From 34a94fa2694458e9350aa01ef9cb3aa188490561 Mon Sep 17 00:00:00 2001 From: Justin Hawkins Date: Fri, 20 Jun 2025 16:12:48 +0200 Subject: [PATCH] Refactor APIClient, start to add support for time trackers --- mite/mite.go | 65 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/mite/mite.go b/mite/mite.go index 3ad792c..4cf8af6 100644 --- a/mite/mite.go +++ b/mite/mite.go @@ -3,6 +3,7 @@ package mite import ( "bytes" "encoding/json" + "errors" "fmt" "net/http" "time" @@ -56,7 +57,7 @@ func (p Project) GetName() string { return p.Name + " (" + p.CustomerName + ")" func (a APIClient) GetProjects() (Projects, error) { // GET /projects.json p := APIProjects{} - err := get(a.domain, a.apiKey, "/projects.json", &p) + err := a.get("/projects.json", &p) if err != nil { return nil, err } @@ -98,7 +99,7 @@ func (c Customer) GetName() string { return c.Name } func (a APIClient) GetCustomers() (Customers, error) { // GET /customers.json p := apiCustomers{} - err := get(a.domain, a.apiKey, "/customers.json", &p) + err := a.get("/customers.json", &p) if err != nil { return nil, err } @@ -142,7 +143,7 @@ func (s Service) GetName() string { func (a APIClient) GetServices() (Services, error) { // GET /services.json p := apiServices{} - err := get(a.domain, a.apiKey, "/services.json", &p) + err := a.get("/services.json", &p) if err != nil { return nil, err } @@ -215,7 +216,7 @@ func (a APIClient) GetTimeEntries(from, to time.Time) (TimeEntries, error) { p := apiTimeEntry{} u := fmt.Sprintf("/time_entries.json?from=%s&to=%s", from.Format(time.DateOnly), to.Format(time.DateOnly)) - err := get(a.domain, a.apiKey, u, &p) + err := a.get(u, &p) if err != nil { return nil, err } @@ -253,23 +254,62 @@ func (a APIClient) AddTimeEntry(date string, minutes int, notes string, projectI req.RequestTimeEntryHolder.ProjectID = projectId req.RequestTimeEntryHolder.ServiceID = serviceId - err := post(a.domain, a.apiKey, "/time_entries.json", req) + err := a.post("/time_entries.json", req) return err - } -func post(domain, apiKey, path string, data any) error { +type apiTimeTrackerEntry struct { + TimeTrackerHolder timeTrackerHolder `json:"tracker"` +} + +type timeTrackerHolder struct { + TrackingTimeEntry *TrackingTimeEntry `json:"tracking_time_entry"` +} + +type TrackingTimeEntry struct { + ID int `json:"id"` + Minutes int `json:"minutes"` + Since time.Time `json:"since"` +} + +// { +// "tracker": { +// "tracking_time_entry": { +// "id": 36135321, +// "minutes": 247, +// "since": "2015-10-15T17:05:04+02:00" +// } +// } +// } + +var ErrNoTracker = errors.New("no time tracker running") + +// GetTimeTracker gets the current running time tracker. If no tracker is +// running, the error returned will be ErrNoTracker +func (a APIClient) GetTimeTracker() (TrackingTimeEntry, error) { + r := apiTimeTrackerEntry{} + err := a.get("/tracker.json", &r) + if err != nil { + return TrackingTimeEntry{}, err + } + if r.TimeTrackerHolder.TrackingTimeEntry == nil { + return TrackingTimeEntry{}, ErrNoTracker + } + return *r.TimeTrackerHolder.TrackingTimeEntry, nil +} + +func (a APIClient) post(path string, data any) error { b, err := json.Marshal(data) if err != nil { return err } - req, err := http.NewRequest("POST", baseurl(domain, path), bytes.NewBuffer(b)) + req, err := http.NewRequest("POST", baseurl(a.domain, path), bytes.NewBuffer(b)) if err != nil { return err } - req.Header.Add("X-MiteApiKey", apiKey) + req.Header.Add("X-MiteApiKey", a.apiKey) req.Header.Add("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) @@ -285,12 +325,12 @@ func post(domain, apiKey, path string, data any) error { } -func get(domain, apiKey, path string, data any) error { - req, err := http.NewRequest("GET", baseurl(domain, path), nil) +func (a APIClient) get(path string, data any) error { + req, err := http.NewRequest("GET", baseurl(a.domain, path), nil) if err != nil { return err } - req.Header.Add("X-MiteApiKey", apiKey) + req.Header.Add("X-MiteApiKey", a.apiKey) resp, err := http.DefaultClient.Do(req) if err != nil { @@ -305,7 +345,6 @@ func get(domain, apiKey, path string, data any) error { return err } return nil - } func baseurl(domain, path string) string {