Skip to content

Commit

Permalink
Added time entries
Browse files Browse the repository at this point in the history
  • Loading branch information
Matija Pevec committed Jan 12, 2020
1 parent 17b6ec7 commit 5fdf1a5
Show file tree
Hide file tree
Showing 9 changed files with 578 additions and 41 deletions.
50 changes: 50 additions & 0 deletions client/activity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package client

type Activity struct {
Id int64 `json:"id"`
Name string `json:"name"`
}

type Activities []Activity

type ActivitiesResponse struct {
Activities Activities `json:"time_entry_activities"`
}

func (c *Client) GetActivities() (Activities, error) {
req, err := c.getRequest("/enumerations/time_entry_activities.json", "")
if err != nil {
return nil, err
}

var response ActivitiesResponse
_, err = c.Do(req, &response)
if err != nil {
return nil, err
}

return response.Activities, nil
}

func (acts Activities) Valid(name string) (int64, bool) {
theMap := make(map[string]int64)
for _, activity := range acts {
theMap[activity.Name] = activity.Id
}

activityId, exists := theMap[name]
if !exists {
return activityId, false
}

return activityId, true
}

func (acts Activities) Names() []string {
theActs := make([]string, 0, len(acts))
for _, activity := range acts {
theActs = append(theActs, activity.Name)
}

return theActs
}
92 changes: 61 additions & 31 deletions client/client.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package client

import (
"bytes"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -40,37 +41,57 @@ func (c *Client) getRequest(path string, queryParams string) (*http.Request, err
return req, nil
}

// TODO: Uncomment when post request will be used.
//func (c *Client) postRequest(path string, body interface{}) (*http.Request, error) {
// hostname, apiKey := getCredentials()
// u := url.URL{
// Scheme: "https",
// Host: hostname,
// Path: path,
// }
//
// var buf io.ReadWriter
// if body != nil {
// buf = new(bytes.Buffer)
// err := json.NewEncoder(buf).Encode(body)
// if err != nil {
// return nil, err
// }
// }
//
// req, err := http.NewRequest("POST", u.String(), buf)
// if err != nil {
// return nil, err
// }
// if body != nil {
// req.Header.Set("Content-Type", "application/json")
// }
// req.Header.Set("Accept", "application/json")
// req.Header.Set("User-Agent", c.UserAgent)
// req.Header.Set("X-Redmine-API-Key", apiKey)
//
// return req, nil
//}
func (c *Client) postRequest(path string, body interface{}) (*http.Request, error) {
hostname, apiKey := getCredentials()
u := url.URL{
Scheme: "https",
Host: hostname,
Path: path,
}

var buf io.ReadWriter
if body != nil {
buf = new(bytes.Buffer)
err := json.NewEncoder(buf).Encode(body)
if err != nil {
return nil, err
}
}

req, err := http.NewRequest("POST", u.String(), buf)
if err != nil {
return nil, err
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", c.UserAgent)
req.Header.Set("X-Redmine-API-Key", apiKey)

return req, nil
}

func (c *Client) deleteRequest(path string) (*http.Request, error) {
hostname, apiKey := getCredentials()
u := url.URL{
Scheme: "https",
Host: hostname,
Path: path,
}

var buf io.ReadWriter
req, err := http.NewRequest("DELETE", u.String(), buf)
if err != nil {
return nil, err
}

req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", c.UserAgent)
req.Header.Set("X-Redmine-API-Key", apiKey)

return req, nil
}

func (c *Client) Do(req *http.Request, v interface{}) (*http.Response, error) {
resp, err := c.HttpClient.Do(req)
Expand Down Expand Up @@ -98,3 +119,12 @@ func getCredentials() (hostname, apiKey string) {

return
}

type Entity struct {
Id int64 `json:"id"`
Name string `json:"name"`
}

type EntityId struct {
Id int64 `json:"id"`
}
5 changes: 0 additions & 5 deletions client/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ type ProjectResponse struct {
Project Project `json:"project"`
}

type Entity struct {
Id int64 `json:"id"`
Name string `json:"name"`
}

func (c *Client) GetProject(id int64) (*Project, error) {
req, err := c.getRequest(fmt.Sprintf("/projects/%v.json", id), "")
if err != nil {
Expand Down
131 changes: 131 additions & 0 deletions client/timeentry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package client

import (
"errors"
"fmt"
"net/http"
"time"
)

type TimeEntry struct {
Id int64 `json:"id"`
Project Entity `json:"project"`
Issue EntityId `json:"issue"`
User Entity `json:"user"`
Activity Entity `json:"activity"`
Hours float64 `json:"hours"`
Comments string `json:"comments"`
SpentOn DateTime `json:"spent_on"`
CreatedOn time.Time `json:"created_on"`
UpdatedOn time.Time `json:"updated_on"`
}

type TimeEntriesResponse struct {
TimeEntries []TimeEntry `json:"time_entries"`
}

type TimeEntryResponse struct {
TimeEntry TimeEntry `json:"time_entry"`
}

func (c *Client) GetTimeEntries(queryParams string) ([]TimeEntry, error) {
req, err := c.getRequest("/time_entries.json", queryParams)
if err != nil {
return nil, err
}

var response TimeEntriesResponse
_, err = c.Do(req, &response)
if err != nil {
return nil, err
}

return response.TimeEntries, nil
}

type TimeEntryBody struct {
TimeEntry TimeEntryPost `json:"time_entry"`
}

type TimeEntryPost struct {
IssueId int `json:"issue_id,omitempty"`
ProjectId int `json:"project_id,omitempty"`
SpentOn DateTime `json:"spent_on"`
Hours float32 `json:"hours"`
ActivityId int `json:"activity_id"`
Comments string `json:"comments"`
}

func (c *Client) AddTimeEntry(entry TimeEntryPost) (*TimeEntry, error) {
req, err := c.postRequest("/time_entries.json", TimeEntryBody{TimeEntry: entry})
if err != nil {
return nil, err
}

var response TimeEntryResponse
_, err = c.Do(req, &response)
if err != nil {
return nil, err
}

return &response.TimeEntry, nil
}

func (c *Client) DeleteTimeEntry(id int) error {
req, err := c.deleteRequest(fmt.Sprintf("/time_entries/%v.json", id))
if err != nil {
return err
}

resp, err := c.HttpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()

switch resp.StatusCode {
case http.StatusOK:
return nil
case http.StatusNotFound:
return fmt.Errorf("there is no time entry with id %v", id)
default:
return fmt.Errorf("status code %v", resp.StatusCode)
}
}

type DateTime struct {
time.Time
}

func NewDateTime(time time.Time) *DateTime {
return &DateTime{Time: time}
}

const DateTimeFormat = "2006-01-02"

func (t *DateTime) UnmarshalJSON(data []byte) error {
if string(data) == "null" {
return nil
}

parsedTime, err := time.Parse(`"`+DateTimeFormat+`"`, string(data))
if err != nil {
return err
}

*t = DateTime{parsedTime}

return nil
}

func (t DateTime) MarshalJSON() ([]byte, error) {
if y := t.Year(); y < 0 || y >= 10000 {
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
}

b := make([]byte, 0, len(DateTimeFormat)+2)
b = append(b, '"')
b = t.AppendFormat(b, DateTimeFormat)
b = append(b, '"')
return b, nil
}
Loading

0 comments on commit 5fdf1a5

Please sign in to comment.