1//
2// Copyright 2021, Sander van Harmelen
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17package gitlab
18
19import (
20	"fmt"
21	"net/http"
22	"time"
23)
24
25// TodosService handles communication with the todos related methods of
26// the Gitlab API.
27//
28// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html
29type TodosService struct {
30	client *Client
31}
32
33// Todo represents a GitLab todo.
34//
35// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html
36type Todo struct {
37	ID         int            `json:"id"`
38	Project    *BasicProject  `json:"project"`
39	Author     *BasicUser     `json:"author"`
40	ActionName TodoAction     `json:"action_name"`
41	TargetType TodoTargetType `json:"target_type"`
42	Target     *TodoTarget    `json:"target"`
43	TargetURL  string         `json:"target_url"`
44	Body       string         `json:"body"`
45	State      string         `json:"state"`
46	CreatedAt  *time.Time     `json:"created_at"`
47}
48
49func (t Todo) String() string {
50	return Stringify(t)
51}
52
53// TodoTarget represents a todo target of type Issue or MergeRequest
54type TodoTarget struct {
55	Assignees            []*BasicUser           `json:"assignees"`
56	Assignee             *BasicUser             `json:"assignee"`
57	Author               *BasicUser             `json:"author"`
58	CreatedAt            *time.Time             `json:"created_at"`
59	Description          string                 `json:"description"`
60	Downvotes            int                    `json:"downvotes"`
61	ID                   int                    `json:"id"`
62	IID                  int                    `json:"iid"`
63	Labels               []string               `json:"labels"`
64	Milestone            *Milestone             `json:"milestone"`
65	ProjectID            int                    `json:"project_id"`
66	State                string                 `json:"state"`
67	Subscribed           bool                   `json:"subscribed"`
68	TaskCompletionStatus *TasksCompletionStatus `json:"task_completion_status"`
69	Title                string                 `json:"title"`
70	UpdatedAt            *time.Time             `json:"updated_at"`
71	Upvotes              int                    `json:"upvotes"`
72	UserNotesCount       int                    `json:"user_notes_count"`
73	WebURL               string                 `json:"web_url"`
74
75	// Only available for type Issue
76	Confidential bool        `json:"confidential"`
77	DueDate      string      `json:"due_date"`
78	HasTasks     bool        `json:"has_tasks"`
79	Links        *IssueLinks `json:"_links"`
80	MovedToID    int         `json:"moved_to_id"`
81	TimeStats    *TimeStats  `json:"time_stats"`
82	Weight       int         `json:"weight"`
83
84	// Only available for type MergeRequest
85	ApprovalsBeforeMerge      int          `json:"approvals_before_merge"`
86	ForceRemoveSourceBranch   bool         `json:"force_remove_source_branch"`
87	MergeCommitSHA            string       `json:"merge_commit_sha"`
88	MergeWhenPipelineSucceeds bool         `json:"merge_when_pipeline_succeeds"`
89	MergeStatus               string       `json:"merge_status"`
90	Reference                 string       `json:"reference"`
91	Reviewers                 []*BasicUser `json:"reviewers"`
92	SHA                       string       `json:"sha"`
93	ShouldRemoveSourceBranch  bool         `json:"should_remove_source_branch"`
94	SourceBranch              string       `json:"source_branch"`
95	SourceProjectID           int          `json:"source_project_id"`
96	Squash                    bool         `json:"squash"`
97	TargetBranch              string       `json:"target_branch"`
98	TargetProjectID           int          `json:"target_project_id"`
99	WorkInProgress            bool         `json:"work_in_progress"`
100
101	// Only available for type DesignManagement::Design
102	FileName string `json:"filename"`
103	ImageURL string `json:"image_url"`
104}
105
106// ListTodosOptions represents the available ListTodos() options.
107//
108// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#get-a-list-of-todos
109type ListTodosOptions struct {
110	ListOptions
111	Action    *TodoAction `url:"action,omitempty" json:"action,omitempty"`
112	AuthorID  *int        `url:"author_id,omitempty" json:"author_id,omitempty"`
113	ProjectID *int        `url:"project_id,omitempty" json:"project_id,omitempty"`
114	State     *string     `url:"state,omitempty" json:"state,omitempty"`
115	Type      *string     `url:"type,omitempty" json:"type,omitempty"`
116}
117
118// ListTodos lists all todos created by authenticated user.
119// When no filter is applied, it returns all pending todos for the current user.
120//
121// GitLab API docs:
122// https://docs.gitlab.com/ce/api/todos.html#get-a-list-of-todos
123func (s *TodosService) ListTodos(opt *ListTodosOptions, options ...RequestOptionFunc) ([]*Todo, *Response, error) {
124	req, err := s.client.NewRequest(http.MethodGet, "todos", opt, options)
125	if err != nil {
126		return nil, nil, err
127	}
128
129	var t []*Todo
130	resp, err := s.client.Do(req, &t)
131	if err != nil {
132		return nil, resp, err
133	}
134
135	return t, resp, err
136}
137
138// MarkTodoAsDone marks a single pending todo given by its ID for the current user as done.
139//
140// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#mark-a-todo-as-done
141func (s *TodosService) MarkTodoAsDone(id int, options ...RequestOptionFunc) (*Response, error) {
142	u := fmt.Sprintf("todos/%d/mark_as_done", id)
143
144	req, err := s.client.NewRequest(http.MethodPost, u, nil, options)
145	if err != nil {
146		return nil, err
147	}
148
149	return s.client.Do(req, nil)
150}
151
152// MarkAllTodosAsDone marks all pending todos for the current user as done.
153//
154// GitLab API docs: https://docs.gitlab.com/ce/api/todos.html#mark-all-todos-as-done
155func (s *TodosService) MarkAllTodosAsDone(options ...RequestOptionFunc) (*Response, error) {
156	req, err := s.client.NewRequest(http.MethodPost, "todos/mark_as_done", nil, options)
157	if err != nil {
158		return nil, err
159	}
160
161	return s.client.Do(req, nil)
162}
163