Refactor APIClient, start to add support for time trackers

This commit is contained in:
Justin Hawkins 2025-06-20 16:12:48 +02:00
parent 163e7abf47
commit 34a94fa269

View File

@ -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 {