|
|
|
|
@ -7,14 +7,72 @@ import (
|
|
|
|
|
"log"
|
|
|
|
|
"net/http"
|
|
|
|
|
"os"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
BaseApiUrl = "https://jds.projectinsight.net/api/"
|
|
|
|
|
|
|
|
|
|
insightTokenFile = "insight.token"
|
|
|
|
|
|
|
|
|
|
projectEndpoint = ""
|
|
|
|
|
projectListEndpoint = "project/list?ids="
|
|
|
|
|
timeEntryForUserInRangeEndpoint = "time-entry/user-date-range?startDate=2020-01-01&endDate=%s&userId=%s"
|
|
|
|
|
userEndpoint = "user/list-active?modelProperties=Id,FirstName,LastName,EmailAddress"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type (
|
|
|
|
|
IClient struct {
|
|
|
|
|
client *http.Client
|
|
|
|
|
tokens *map[string]string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Project struct {
|
|
|
|
|
BillableExpenseVarianceEarnedValueBillableVsWorkBillableTotalPercent float64 `json:"BillableExpense_VarianceEarnedValueBillableVsWorkBillableTotalPercent,omitempty"`
|
|
|
|
|
CompanyDefaultId string `json:"CompanyDefault_Id,omitempty"`
|
|
|
|
|
CustomFieldValueId string `json:"CustomFieldValue_Id,omitempty"`
|
|
|
|
|
DepartmentId string `json:"Department_Id,omitempty"`
|
|
|
|
|
DurationSeconds int64
|
|
|
|
|
DurationString string
|
|
|
|
|
EndDateTimeUTC string
|
|
|
|
|
EstimateAtCompletionToTargetTotalVariance float64 `json:"EstimateAtCompletionToTargetTotal_Variance,omitempty"`
|
|
|
|
|
EstimateAtCompletionToTargetTotalPercentVariance float64 `json:"EstimateAtCompletionToTargetTotalPercent_Variance,omitempty"`
|
|
|
|
|
IsActive bool
|
|
|
|
|
IsOpen bool
|
|
|
|
|
LocationDefaultId string `json:"LocationDefault_Id,omitempty"`
|
|
|
|
|
Name string
|
|
|
|
|
ProfitSalesOrderActual float64
|
|
|
|
|
ProjectPriorityId string `json:"ProjectPriority_Id,omitempty"`
|
|
|
|
|
ProjectState int64 `json:"project_state,omitempty"`
|
|
|
|
|
ProjectStatusId string `json:"ProjectStatus_Id,omitempty"`
|
|
|
|
|
ProjectTypeId string `json:"ProjectType_Id,omitempty"`
|
|
|
|
|
ScheduleStartDate string
|
|
|
|
|
StartDateTimeUTC string
|
|
|
|
|
UrlFull string
|
|
|
|
|
VarSalesOrderExpenseVsBillableExpense float64
|
|
|
|
|
VarSalesOrderExpenseVsBillableExpensePercent float64
|
|
|
|
|
VarSalesOrderExpenseVsInvoiceExpense float64
|
|
|
|
|
VarSalesOrderExpenseVsInvoiceExpensePercent float64
|
|
|
|
|
VarSalesOrderHoursVsBillableHours float64
|
|
|
|
|
VarSalesOrderHoursVsBillableHoursPercent float64
|
|
|
|
|
VarSalesOrderHoursVsInvoiceHours float64
|
|
|
|
|
VarSalesOrderHoursVsInvoiceHoursPercent float64
|
|
|
|
|
VarSalesOrderRateVsBillableRate float64
|
|
|
|
|
VarSalesOrderRateVsBillableRatePercent float64
|
|
|
|
|
VarSalesOrderRateVsInvoiceRate float64
|
|
|
|
|
VarSalesOrderRateVsInvoiceRatePercent float64
|
|
|
|
|
VarSalesOrderTimeVsBillableTime float64
|
|
|
|
|
VarSalesOrderTimeVsBillableTimePercent float64
|
|
|
|
|
VarSalesOrderTimeVsInvoiceTime float64
|
|
|
|
|
VarSalesOrderTimeVsInvoiceTimePercent float64
|
|
|
|
|
VarSalesOrderTotalVsBillableTotal float64
|
|
|
|
|
VarSalesOrderTotalVsBillableTotalPercent float64
|
|
|
|
|
VarSalesOrderTotalVsInvoiceTotal float64
|
|
|
|
|
VarSalesOrderTotalVsInvoiceTotalPercent float64
|
|
|
|
|
WorkPercentComplete float64
|
|
|
|
|
WorkSeconds int64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TimeEntry struct {
|
|
|
|
|
ActualHours float64
|
|
|
|
|
ActualHoursFormattedString string
|
|
|
|
|
@ -33,54 +91,117 @@ type (
|
|
|
|
|
TimeSheetId string `json:"TimeSheet_Id,omitempty"`
|
|
|
|
|
UserId string `json:"User_Id,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func Get(urlEndpoint string) {
|
|
|
|
|
client := http.Client{}
|
|
|
|
|
reqUrl := BaseApiUrl + urlEndpoint
|
|
|
|
|
token := getToken("insight.token")
|
|
|
|
|
deserializeContainer := make([]TimeEntry, 0, 20000)
|
|
|
|
|
User struct {
|
|
|
|
|
Id string
|
|
|
|
|
FirstName string
|
|
|
|
|
LastName string
|
|
|
|
|
EmailAddress string
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
request, err := http.NewRequest("GET", reqUrl, nil)
|
|
|
|
|
func (iClient *IClient) GetTimeAllTimeEntriesForUserThroughDate(userId string, endDate string) *[]TimeEntry {
|
|
|
|
|
urlString := fmt.Sprintf(timeEntryForUserInRangeEndpoint, endDate, userId)
|
|
|
|
|
log.Println(urlString)
|
|
|
|
|
req := iClient.createRequest(urlString, insightTokenFile)
|
|
|
|
|
rawBytes := iClient.doGet(req)
|
|
|
|
|
container := make([]TimeEntry, 0, 1000) //do we want to make the default result size parametric?
|
|
|
|
|
log.Println(string(*rawBytes))
|
|
|
|
|
err := json.Unmarshal(*rawBytes, &container)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
return &container
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
request.Header.Add("api-token", token)
|
|
|
|
|
func (iClient *IClient) GetProjectsInList(projectIds []string) *[]Project {
|
|
|
|
|
ids := strings.Join(projectIds, ",")
|
|
|
|
|
req := iClient.createRequest(projectListEndpoint+ids, insightTokenFile)
|
|
|
|
|
rawBytes := iClient.doGet(req)
|
|
|
|
|
container := make([]Project, 0, 1000) //do we want to make the default result size parametric?
|
|
|
|
|
|
|
|
|
|
resp, err := client.Do(request)
|
|
|
|
|
err := json.Unmarshal(*rawBytes, &container)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bodyBytes, err := ioutil.ReadAll(resp.Body)
|
|
|
|
|
return &container
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (iClient *IClient) GetUsers() *[]User {
|
|
|
|
|
users := iClient.getRawUsers()
|
|
|
|
|
for idx, user := range *users {
|
|
|
|
|
user.EmailAddress = strings.ToLower(user.EmailAddress)
|
|
|
|
|
user.EmailAddress = strings.ReplaceAll(user.EmailAddress, "jdsdesignonline.com", "jdsconsulting.net")
|
|
|
|
|
user.EmailAddress = strings.ReplaceAll(user.EmailAddress, "jdsfaulkner.com", "jdsconsulting.net")
|
|
|
|
|
(*users)[idx] = user
|
|
|
|
|
}
|
|
|
|
|
return users
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (iClient *IClient) getRawUsers() *[]User {
|
|
|
|
|
req := iClient.createRequest(userEndpoint, insightTokenFile)
|
|
|
|
|
rawBytes := iClient.doGet(req)
|
|
|
|
|
container := make([]User, 0, 150) //do we want to make the default result size parametric?
|
|
|
|
|
|
|
|
|
|
err := json.Unmarshal(*rawBytes, &container)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = json.Unmarshal(bodyBytes, &deserializeContainer)
|
|
|
|
|
return &container
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewIClient() *IClient {
|
|
|
|
|
c := IClient{
|
|
|
|
|
client: &http.Client{},
|
|
|
|
|
tokens: cacheTokens(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &c
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func cacheTokens() *map[string]string {
|
|
|
|
|
files, err := os.ReadDir("./tokens/")
|
|
|
|
|
ret := make(map[string]string)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
for _, file := range files {
|
|
|
|
|
subPath := fmt.Sprintf("./tokens/%s", file.Name())
|
|
|
|
|
fileContents, err := os.ReadFile(subPath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, entry := range deserializeContainer {
|
|
|
|
|
log.Printf("%#v\n", entry)
|
|
|
|
|
ret[file.Name()] = string(fileContents)
|
|
|
|
|
}
|
|
|
|
|
log.Println("Received Entries (qty): " + strconv.Itoa(len(deserializeContainer)))
|
|
|
|
|
return &ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getToken(tokenName string) string {
|
|
|
|
|
filePath := fmt.Sprintf("./tokens/%s", tokenName)
|
|
|
|
|
file, err := os.OpenFile(filePath, os.O_RDONLY, 0755)
|
|
|
|
|
func (iClient *IClient) doGet(req *http.Request) *[]byte {
|
|
|
|
|
resp, err := iClient.client.Do(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
|
|
rawBytes, err := ioutil.ReadAll(file)
|
|
|
|
|
bodyBytes, err := ioutil.ReadAll(resp.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string(rawBytes)
|
|
|
|
|
return &bodyBytes
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (iClient *IClient) createRequest(urlEndpoint string, tokenFile string) *http.Request {
|
|
|
|
|
reqUrl := BaseApiUrl + urlEndpoint
|
|
|
|
|
token := (*iClient.tokens)[tokenFile]
|
|
|
|
|
request, err := http.NewRequest("GET", reqUrl, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
request.Header.Add("api-token", token)
|
|
|
|
|
|
|
|
|
|
return request
|
|
|
|
|
}
|
|
|
|
|
|