Complete time tracker API access
All checks were successful
CI / test (push) Successful in 38s

This commit is contained in:
Justin Hawkins 2025-06-20 16:40:28 +02:00
parent 9a318d3cff
commit e1df2dea3b
2 changed files with 150 additions and 14 deletions

View File

@ -264,6 +264,7 @@ type apiTimeTrackerEntry struct {
type timeTrackerHolder struct { type timeTrackerHolder struct {
TrackingTimeEntry *TrackingTimeEntry `json:"tracking_time_entry"` TrackingTimeEntry *TrackingTimeEntry `json:"tracking_time_entry"`
StoppedTimeEntry *StoppedTimeEntry `json:"stopped_time_entry"`
} }
type TrackingTimeEntry struct { type TrackingTimeEntry struct {
@ -272,6 +273,25 @@ type TrackingTimeEntry struct {
Since time.Time `json:"since"` Since time.Time `json:"since"`
} }
type StoppedTimeEntry struct {
ID int `json:"id"`
Minutes int `json:"minutes"`
}
// {
// "tracker": {
// "tracking_time_entry": {
// "id": 36135322,
// "minutes": 0,
// "since": "2015-10-15T17:33:52+02:00"
// },
// "stopped_time_entry": {
// "id": 36134329,
// "minutes": 46
// }
// }
// }
// { // {
// "tracker": { // "tracker": {
// "tracking_time_entry": { // "tracking_time_entry": {
@ -298,6 +318,86 @@ func (a APIClient) GetTimeTracker() (TrackingTimeEntry, error) {
return *r.TimeTrackerHolder.TrackingTimeEntry, nil return *r.TimeTrackerHolder.TrackingTimeEntry, nil
} }
func (a APIClient) StartTimeTracker(id int) (TrackingTimeEntry, *StoppedTimeEntry, error) {
url := fmt.Sprintf("/tracker/%d.json", id)
r := apiTimeTrackerEntry{}
err := a.patch(url, &r)
if err != nil {
return TrackingTimeEntry{}, nil, err
}
if r.TimeTrackerHolder.TrackingTimeEntry == nil {
// I don't think this should happen, the patch should have been a 404?
panic(fmt.Sprintf("unexpected failure to find a tracking entry in a successful PATCH\n%#v", r.TimeTrackerHolder))
}
return *r.TimeTrackerHolder.TrackingTimeEntry, r.TimeTrackerHolder.StoppedTimeEntry, nil
}
func (a APIClient) StopTimeTracker(id int) (StoppedTimeEntry, error) {
url := fmt.Sprintf("/tracker/%d.json", id)
r := apiTimeTrackerEntry{}
err := a.delete(url, &r)
if err != nil {
return StoppedTimeEntry{}, err
}
if r.TimeTrackerHolder.StoppedTimeEntry == nil {
// I don't think this should happen, the patch should have been a 404?
panic(fmt.Sprintf("unexpected failure to find a tracking entry in a successful DELETE\n%#v", r.TimeTrackerHolder))
}
return *r.TimeTrackerHolder.StoppedTimeEntry, nil
}
func (a APIClient) delete(path string, data any) error {
req, err := http.NewRequest("DELETE", baseurl(a.domain, path), nil)
if err != nil {
return err
}
req.Header.Add("X-MiteApiKey", a.apiKey)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
return fmt.Errorf("expected 2XX, got %d", resp.StatusCode)
}
err = json.NewDecoder(resp.Body).Decode(&data)
if err != nil {
return err
}
return nil
}
func (a APIClient) patch(path string, data any) error {
req, err := http.NewRequest("PATCH", baseurl(a.domain, path), nil)
if err != nil {
return err
}
req.Header.Add("X-MiteApiKey", a.apiKey)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
return fmt.Errorf("expected 2XX, got %d", resp.StatusCode)
}
err = json.NewDecoder(resp.Body).Decode(&data)
if err != nil {
return err
}
return nil
}
func (a APIClient) post(path string, data any) error { func (a APIClient) post(path string, data any) error {
b, err := json.Marshal(data) b, err := json.Marshal(data)

View File

@ -6,19 +6,10 @@ import (
) )
func TestUnmarshalTimeTracking(t *testing.T) { func TestUnmarshalTimeTracking(t *testing.T) {
trackerOn := []byte(`
{
"tracker": {
"tracking_time_entry": {
"id": 36135321,
"minutes": 247,
"since": "2015-10-15T17:05:04+02:00"
}
}
}`)
trackerOff := []byte(`{ trackerOff := []byte(`{
"tracker": {} "tracker": {}
}`) }`)
off := apiTimeTrackerEntry{} off := apiTimeTrackerEntry{}
err := json.Unmarshal(trackerOff, &off) err := json.Unmarshal(trackerOff, &off)
if err != nil { if err != nil {
@ -28,14 +19,23 @@ func TestUnmarshalTimeTracking(t *testing.T) {
t.Error("expected nil, but is not") t.Error("expected nil, but is not")
} }
} }
trackerOn := []byte(`
{
"tracker": {
"tracking_time_entry": {
"id": 36135321,
"minutes": 247,
"since": "2015-10-15T17:05:04+02:00"
}
}
}`)
on := apiTimeTrackerEntry{} on := apiTimeTrackerEntry{}
err = json.Unmarshal(trackerOn, &on) err = json.Unmarshal(trackerOn, &on)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} else { } else {
if on.TimeTrackerHolder.TrackingTimeEntry == nil { if on.TimeTrackerHolder.TrackingTimeEntry == nil {
t.Error("expected note nil, but is not") t.Error("expected not nil, but is not")
} else { } else {
if on.TimeTrackerHolder.TrackingTimeEntry.ID != 36135321 { if on.TimeTrackerHolder.TrackingTimeEntry.ID != 36135321 {
t.Error("bad unmarshal?") t.Error("bad unmarshal?")
@ -43,4 +43,40 @@ func TestUnmarshalTimeTracking(t *testing.T) {
} }
} }
trackerStart := []byte(`{
"tracker": {
"tracking_time_entry": {
"id": 36135322,
"minutes": 0,
"since": "2015-10-15T17:33:52+02:00"
},
"stopped_time_entry": {
"id": 36134329,
"minutes": 46
}
}
}`)
start := apiTimeTrackerEntry{}
err = json.Unmarshal(trackerStart, &start)
if err != nil {
t.Error(err)
} else {
if start.TimeTrackerHolder.TrackingTimeEntry == nil {
t.Error("expected not nil, but is not")
} else {
if start.TimeTrackerHolder.TrackingTimeEntry.ID != 36135322 {
t.Error("bad unmarshal?")
}
}
if start.TimeTrackerHolder.StoppedTimeEntry == nil {
t.Error("expected not nil, but is nil")
} else {
if start.TimeTrackerHolder.StoppedTimeEntry.ID != 36134329 {
t.Error("bad unmarshal")
}
}
}
} }