Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update comment ID type and Time Tracking 2.0 #58

Merged
merged 4 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clickup/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type Client struct {
Tasks *TasksService
TaskTemplates *TaskTemplatesService
Teams *TeamsService
TimeTrackings *TimeTrackingsService
SharedHierarchy *SharedHierarchyService
Spaces *SpacesService
Folders *FoldersService
Expand Down Expand Up @@ -138,6 +139,7 @@ func NewClient(httpClient *http.Client, APIKey string) *Client {
c.Tasks = (*TasksService)(&c.common)
c.TaskTemplates = (*TaskTemplatesService)(&c.common)
c.Teams = (*TeamsService)(&c.common)
c.TimeTrackings = (*TimeTrackingsService)(&c.common)
c.SharedHierarchy = (*SharedHierarchyService)(&c.common)
c.Spaces = (*SpacesService)(&c.common)
c.Folders = (*FoldersService)(&c.common)
Expand Down
4 changes: 2 additions & 2 deletions clickup/comments.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type UpdateCommentRequest struct {
}

type CreateCommentResponse struct {
ID string `json:"id"`
ID int `json:"id"`
HistId string `json:"hist_id"`
Date *Date `json:"date"`
}
Expand All @@ -35,7 +35,7 @@ type TaskCommentOptions struct {
}

type Comment struct {
ID string `json:"id"`
ID int `json:"id"`
Comment []CommentInComment `json:"comment"`
CommentText string `json:"comment_text"`
User User `json:"user"`
Expand Down
8 changes: 4 additions & 4 deletions clickup/comments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestCommentsService_CreateTaskComment(t *testing.T) {

fmt.Fprint(w,
`{
"id": "458",
"id": 458,
"hist_id": "26508",
"date": 1568036964079
}`,
Expand All @@ -44,7 +44,7 @@ func TestCommentsService_CreateTaskComment(t *testing.T) {
t.Errorf("Actions.ListArtifacts returned error: %v", err)
}

want := &CreateCommentResponse{ID: "458", HistId: "26508", Date: NewDateWithUnixTime(1568036964079)}
want := &CreateCommentResponse{ID: 458, HistId: "26508", Date: NewDateWithUnixTime(1568036964079)}
if !cmp.Equal(artifacts, want) {
t.Errorf("Actions.ListArtifacts returned %+v, want %+v", artifacts, want)
}
Expand All @@ -60,7 +60,7 @@ func TestCommentsService_GetTaskComments(t *testing.T) {
`{
"comments": [
{
"id": "458",
"id": 458,
"comment": [
{
"text": "Task comment content"
Expand Down Expand Up @@ -115,7 +115,7 @@ func TestCommentsService_GetTaskComments(t *testing.T) {
ProfilePicture: "https://attachments-public.clickup.com/profilePictures/183_abc.jpg",
}
comment := Comment{
ID: "458",
ID: 458,
Comment: []CommentInComment{{Text: "Task comment content"}},
CommentText: "Task comment content",
User: user,
Expand Down
28 changes: 27 additions & 1 deletion clickup/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,31 @@ type TaskRequest struct {
CustomItemId int `json:"custom_item_id,omitempty"` // To create a task that doesn't use a custom task type, either don't include this field in the request body, or send 'null'. To create this task as a Milestone, send a value of 1. To use a custom task type, send the custom task type ID as defined in your Workspace, such as 2.
}

type TaskUpdateRequest struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Assignees TaskAssigneeUpdateRequest `json:"assignees,omitempty"`
Tags []string `json:"tags,omitempty"`
Status string `json:"status,omitempty"`
Priority int `json:"priority,omitempty"`
DueDate *Date `json:"due_date,omitempty"`
DueDateTime bool `json:"due_date_time,omitempty"`
TimeEstimate int `json:"time_estimate,omitempty"`
StartDate *Date `json:"start_date,omitempty"`
StartDateTime bool `json:"start_date_time,omitempty"`
NotifyAll bool `json:"notify_all,omitempty"`
Parent string `json:"parent,omitempty"`
LinksTo string `json:"links_to,omitempty"`
CheckRequiredCustomFields bool `json:"check_required_custom_fields,omitempty"`
CustomFields []CustomFieldInTaskRequest `json:"custom_fields,omitempty"`
CustomItemId int `json:"custom_item_id,omitempty"` // To create a task that doesn't use a custom task type, either don't include this field in the request body, or send 'null'. To create this task as a Milestone, send a value of 1. To use a custom task type, send the custom task type ID as defined in your Workspace, such as 2.
}

type TaskAssigneeUpdateRequest struct {
Add []int `json:"add,omitempty"`
Rem []int `json:"rem,omitempty"`
}

type CustomFieldInTaskRequest struct {
ID string `json:"id"`
Value interface{} `json:"value"`
Expand Down Expand Up @@ -129,6 +154,7 @@ type TasksInStatus struct {
}

type TaskStatus struct {
ID string `json:"id"`
Status string `json:"status"`
Color string `json:"color"`
Type string `json:"type"`
Expand Down Expand Up @@ -282,7 +308,7 @@ func (s *TasksService) CreateTask(ctx context.Context, listID string, tr *TaskRe
}

// FIXME: assignees add/rem
func (s *TasksService) UpdateTask(ctx context.Context, taskID string, opts *GetTaskOptions, tr *TaskRequest) (*Task, *Response, error) {
func (s *TasksService) UpdateTask(ctx context.Context, taskID string, opts *GetTaskOptions, tr *TaskUpdateRequest) (*Task, *Response, error) {
u := fmt.Sprintf("task/%v/", taskID)
u, err := addOptions(u, opts)
if err != nil {
Expand Down
110 changes: 110 additions & 0 deletions clickup/time_tracking.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package clickup

import (
"context"
"fmt"
)

type TimeTrackingsService service

type GetTimeTrackingResponse struct {
Data TimeTrackingData `json:"data"`
}

type CreateTimeTrackingResponse struct {
Data TimeTrackingData `json:"data"`
}

// See https://clickup.com/api/clickupreference/operation/Createatimeentry/
type TimeTrackingRequest struct {
Description string `json:"description,omitempty"`
Tags []TimeTrackingTag `json:"tags,omitempty"`
Start int64 `json:"start"`
End int64 `json:"end,omitempty"`
Stop int64 `json:"stop,omitempty"`
Billable bool `json:"billable,omitempty"`
Duration int32 `json:"duration"`
Assignee int `json:"assignee,omitempty"`
Tid string `json:"tid,omitempty"`
}

type TimeTrackingTag struct {
Name string `json:"name"`
TagBg string `json:"tag_bg"`
TagFg string `json:"tag_fg"`
Creator int `json:"creator"`
}

type TimeTrackingData struct {
ID string `json:"id"`
Wid string `json:"wid"`
User User `json:"user"`
Billable bool `json:"billable"`
Start int `json:"start"`
End string `json:"end"`
Duration int `json:"duration"`
Description string `json:"description"`
Source string `json:"source"`
At int `json:"at"`
IsLocked bool `json:"is_locked"`
TaskLocation TaskLocation `json:"task_location"`
Task Task `json:"task"`
Tags []TimeTrackingTag `json:"tags"`
TaskURL string `json:"task_url"`
}

type TaskLocation struct {
ListID int `json:"list_id"`
FolderID int `json:"folder_id"`
SpaceID int `json:"space_id"`
ListName string `json:"list_name"`
FolderName string `json:"folder_name"`
SpaceName string `json:"space_name"`
}

type CreateTimeTrackingOptions struct {
CustomTaskIDs bool `url:"custom_task_ids,omitempty"`
TeamID int `url:"team_id,omitempty"`
}

func (s *TimeTrackingsService) CreateTimeTracking(ctx context.Context, teamID string, opts *CreateTimeTrackingOptions, ttr *TimeTrackingRequest) (*CreateTimeTrackingResponse, *Response, error) {
u := fmt.Sprintf("team/%s/time_entries", teamID)
u, err := addOptions(u, opts)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest("POST", u, ttr)
if err != nil {
return nil, nil, err
}

timeTracking := new(CreateTimeTrackingResponse)
resp, err := s.client.Do(ctx, req, timeTracking)
if err != nil {
return nil, resp, err
}

return timeTracking, resp, nil
}

func (s *TimeTrackingsService) GetTimeTracking(ctx context.Context, teamID string, timerID string, opts *CreateTimeTrackingOptions, ttr *TimeTrackingRequest) (*GetTimeTrackingResponse, *Response, error) {
u := fmt.Sprintf("team/%s/time_entries/%s", teamID, timerID)
u, err := addOptions(u, opts)
if err != nil {
return nil, nil, err
}

req, err := s.client.NewRequest("GET", u, ttr)
if err != nil {
return nil, nil, err
}

getTimeTrackingResponse := new(GetTimeTrackingResponse)
resp, err := s.client.Do(ctx, req, getTimeTrackingResponse)
if err != nil {
return nil, resp, err
}

return getTimeTrackingResponse, resp, nil
}
98 changes: 98 additions & 0 deletions clickup/time_tracking_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package clickup

import (
"context"
"encoding/json"
"fmt"
"net/http"
"testing"

"github.com/google/go-cmp/cmp"
)

func TestTimeTrackingService_CreateTimeTracking(t *testing.T) {
client, mux, _, teardown := setup()
defer teardown()

input := &TimeTrackingRequest{
Description: "description",
Start: 1719595398,
Duration: 120000,
Assignee: 99999999,
Tid: "9hz",
Billable: true,
}

mux.HandleFunc("/team/123/time_entries", func(w http.ResponseWriter, r *http.Request) {
v := new(TimeTrackingRequest)
json.NewDecoder(r.Body).Decode(v)

testMethod(t, r, "POST")
if !cmp.Equal(v, input) {
t.Errorf("Request body = %+v, want %+v", v, input)
}

fmt.Fprint(w,
`{
"data": {
"id": "4090130922962924695",
"task": {
"id": "9hz",
"name": "Test",
"status": {
"status": "in progress",
"id": "p99999999999_99asdhAS",
"color": "#5f55ee",
"type": "custom",
"orderindex": 1
}
},
"wid": "9999999999",
"user": {
"id": 99999999,
"username": "John",
"email": "[email protected]",
"color": "#afb42b",
"initials": "J",
"profilePicture": "https://attachments.clickup.com/profilePictures/99999999_tX9.jpg"
},
"billable": true,
"start": 1719595398,
"end": "1719715398",
"duration": 120000,
"description": "description",
"tags": [],
"at": 1719586940375,
"is_locked": false,
"task_location": {}
}
}`,
)
})

ctx := context.Background()
artifacts, _, err := client.TimeTrackings.CreateTimeTracking(ctx, "123", nil, input)
if err != nil {
t.Errorf("Actions.ListArtifacts returned error: %v", err)
}

want := &CreateTimeTrackingResponse{Data: TimeTrackingData{
ID: "4090130922962924695",
Wid: "9999999999",
User: User{ID: 99999999, Username: "John", Email: "[email protected]", Color: "#afb42b", Initials: "J", ProfilePicture: "https://attachments.clickup.com/profilePictures/99999999_tX9.jpg"},
Billable: true,
Start: 1719595398,
End: "1719715398",
Duration: 120000,
Description: "description",
Tags: []TimeTrackingTag{},
At: 1719586940375,
IsLocked: false,
TaskLocation: TaskLocation{},
Task: Task{ID: "9hz", Name: "Test", Status: TaskStatus{ID: "p99999999999_99asdhAS", Status: "in progress", Color: "#5f55ee", Type: "custom", Orderindex: json.Number("1")}},
}}
if !cmp.Equal(artifacts, want) {
t.Errorf("Actions.ListArtifacts returned %+v, want %+v", artifacts, want)
}

}
8 changes: 4 additions & 4 deletions example/update-duedate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ func main() {
getTask(ctx, client, taskId)

fmt.Println("\nUpdate due date of the task to 2122/01/02 03:04:05:06")
updateTask(ctx, client, taskId, &clickup.TaskRequest{
updateTask(ctx, client, taskId, &clickup.TaskUpdateRequest{
DueDate: clickup.NewDate(
time.Date(2122, 1, 2, 3, 4, 5, 6, time.Now().Location()),
),
})

fmt.Println("\nUpdate the task with empty TaskRequest")
updateTask(ctx, client, taskId, &clickup.TaskRequest{})
updateTask(ctx, client, taskId, &clickup.TaskUpdateRequest{})

fmt.Println("\nRemove task due date with NullDate()")
updateTask(ctx, client, taskId, &clickup.TaskRequest{
updateTask(ctx, client, taskId, &clickup.TaskUpdateRequest{
DueDate: clickup.NullDate(),
})
}
Expand All @@ -50,7 +50,7 @@ func getTask(ctx context.Context, client *clickup.Client, taskID string) {
fmt.Println(task.Name, task.DueDate)
}

func updateTask(ctx context.Context, client *clickup.Client, taskID string, tr *clickup.TaskRequest) {
func updateTask(ctx context.Context, client *clickup.Client, taskID string, tr *clickup.TaskUpdateRequest) {
task, _, err := client.Tasks.UpdateTask(ctx, taskID, &clickup.GetTaskOptions{}, tr)
if err != nil {
log.Fatalln(err)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/raksul/go-clickup

go 1.21.1
go 1.22.3

require (
github.com/google/go-cmp v0.5.8
Expand Down
Loading