1// Copyright 2013 The go-github AUTHORS. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file.
5
6package github
7
8import (
9	"context"
10	"fmt"
11	"time"
12)
13
14// RepositoryComment represents a comment for a commit, file, or line in a repository.
15type RepositoryComment struct {
16	HTMLURL   *string    `json:"html_url,omitempty"`
17	URL       *string    `json:"url,omitempty"`
18	ID        *int64     `json:"id,omitempty"`
19	NodeID    *string    `json:"node_id,omitempty"`
20	CommitID  *string    `json:"commit_id,omitempty"`
21	User      *User      `json:"user,omitempty"`
22	Reactions *Reactions `json:"reactions,omitempty"`
23	CreatedAt *time.Time `json:"created_at,omitempty"`
24	UpdatedAt *time.Time `json:"updated_at,omitempty"`
25
26	// User-mutable fields
27	Body *string `json:"body"`
28	// User-initialized fields
29	Path     *string `json:"path,omitempty"`
30	Position *int    `json:"position,omitempty"`
31}
32
33func (r RepositoryComment) String() string {
34	return Stringify(r)
35}
36
37// ListComments lists all the comments for the repository.
38//
39// GitHub API docs: https://developer.github.com/v3/repos/comments/#list-commit-comments-for-a-repository
40func (s *RepositoriesService) ListComments(ctx context.Context, owner, repo string, opt *ListOptions) ([]*RepositoryComment, *Response, error) {
41	u := fmt.Sprintf("repos/%v/%v/comments", owner, repo)
42	u, err := addOptions(u, opt)
43	if err != nil {
44		return nil, nil, err
45	}
46
47	req, err := s.client.NewRequest("GET", u, nil)
48	if err != nil {
49		return nil, nil, err
50	}
51
52	// TODO: remove custom Accept header when this API fully launches.
53	req.Header.Set("Accept", mediaTypeReactionsPreview)
54
55	var comments []*RepositoryComment
56	resp, err := s.client.Do(ctx, req, &comments)
57	if err != nil {
58		return nil, resp, err
59	}
60
61	return comments, resp, nil
62}
63
64// ListCommitComments lists all the comments for a given commit SHA.
65//
66// GitHub API docs: https://developer.github.com/v3/repos/comments/#list-comments-for-a-single-commit
67func (s *RepositoriesService) ListCommitComments(ctx context.Context, owner, repo, sha string, opt *ListOptions) ([]*RepositoryComment, *Response, error) {
68	u := fmt.Sprintf("repos/%v/%v/commits/%v/comments", owner, repo, sha)
69	u, err := addOptions(u, opt)
70	if err != nil {
71		return nil, nil, err
72	}
73
74	req, err := s.client.NewRequest("GET", u, nil)
75	if err != nil {
76		return nil, nil, err
77	}
78
79	// TODO: remove custom Accept header when this API fully launches.
80	req.Header.Set("Accept", mediaTypeReactionsPreview)
81
82	var comments []*RepositoryComment
83	resp, err := s.client.Do(ctx, req, &comments)
84	if err != nil {
85		return nil, resp, err
86	}
87
88	return comments, resp, nil
89}
90
91// CreateComment creates a comment for the given commit.
92// Note: GitHub allows for comments to be created for non-existing files and positions.
93//
94// GitHub API docs: https://developer.github.com/v3/repos/comments/#create-a-commit-comment
95func (s *RepositoriesService) CreateComment(ctx context.Context, owner, repo, sha string, comment *RepositoryComment) (*RepositoryComment, *Response, error) {
96	u := fmt.Sprintf("repos/%v/%v/commits/%v/comments", owner, repo, sha)
97	req, err := s.client.NewRequest("POST", u, comment)
98	if err != nil {
99		return nil, nil, err
100	}
101
102	c := new(RepositoryComment)
103	resp, err := s.client.Do(ctx, req, c)
104	if err != nil {
105		return nil, resp, err
106	}
107
108	return c, resp, nil
109}
110
111// GetComment gets a single comment from a repository.
112//
113// GitHub API docs: https://developer.github.com/v3/repos/comments/#get-a-single-commit-comment
114func (s *RepositoriesService) GetComment(ctx context.Context, owner, repo string, id int64) (*RepositoryComment, *Response, error) {
115	u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id)
116	req, err := s.client.NewRequest("GET", u, nil)
117	if err != nil {
118		return nil, nil, err
119	}
120
121	// TODO: remove custom Accept header when this API fully launches.
122	req.Header.Set("Accept", mediaTypeReactionsPreview)
123
124	c := new(RepositoryComment)
125	resp, err := s.client.Do(ctx, req, c)
126	if err != nil {
127		return nil, resp, err
128	}
129
130	return c, resp, nil
131}
132
133// UpdateComment updates the body of a single comment.
134//
135// GitHub API docs: https://developer.github.com/v3/repos/comments/#update-a-commit-comment
136func (s *RepositoriesService) UpdateComment(ctx context.Context, owner, repo string, id int64, comment *RepositoryComment) (*RepositoryComment, *Response, error) {
137	u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id)
138	req, err := s.client.NewRequest("PATCH", u, comment)
139	if err != nil {
140		return nil, nil, err
141	}
142
143	c := new(RepositoryComment)
144	resp, err := s.client.Do(ctx, req, c)
145	if err != nil {
146		return nil, resp, err
147	}
148
149	return c, resp, nil
150}
151
152// DeleteComment deletes a single comment from a repository.
153//
154// GitHub API docs: https://developer.github.com/v3/repos/comments/#delete-a-commit-comment
155func (s *RepositoriesService) DeleteComment(ctx context.Context, owner, repo string, id int64) (*Response, error) {
156	u := fmt.Sprintf("repos/%v/%v/comments/%v", owner, repo, id)
157	req, err := s.client.NewRequest("DELETE", u, nil)
158	if err != nil {
159		return nil, err
160	}
161	return s.client.Do(ctx, req, nil)
162}
163