code.gitea.io/gitea@v1.22.3/tests/integration/api_comment_test.go (about)

     1  // Copyright 2017 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package integration
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  	"net/url"
    10  	"testing"
    11  
    12  	auth_model "code.gitea.io/gitea/models/auth"
    13  	"code.gitea.io/gitea/models/db"
    14  	issues_model "code.gitea.io/gitea/models/issues"
    15  	repo_model "code.gitea.io/gitea/models/repo"
    16  	"code.gitea.io/gitea/models/unittest"
    17  	user_model "code.gitea.io/gitea/models/user"
    18  	api "code.gitea.io/gitea/modules/structs"
    19  	"code.gitea.io/gitea/services/convert"
    20  	"code.gitea.io/gitea/tests"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  )
    24  
    25  func TestAPIListRepoComments(t *testing.T) {
    26  	defer tests.PrepareTestEnv(t)()
    27  
    28  	comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
    29  		unittest.Cond("type = ?", issues_model.CommentTypeComment))
    30  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
    31  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
    32  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
    33  
    34  	link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments", repoOwner.Name, repo.Name))
    35  	req := NewRequest(t, "GET", link.String())
    36  	resp := MakeRequest(t, req, http.StatusOK)
    37  
    38  	var apiComments []*api.Comment
    39  	DecodeJSON(t, resp, &apiComments)
    40  	assert.Len(t, apiComments, 2)
    41  	for _, apiComment := range apiComments {
    42  		c := &issues_model.Comment{ID: apiComment.ID}
    43  		unittest.AssertExistsAndLoadBean(t, c,
    44  			unittest.Cond("type = ?", issues_model.CommentTypeComment))
    45  		unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: c.IssueID, RepoID: repo.ID})
    46  	}
    47  
    48  	// test before and since filters
    49  	query := url.Values{}
    50  	before := "2000-01-01T00:00:11+00:00" // unix: 946684811
    51  	since := "2000-01-01T00:00:12+00:00"  // unix: 946684812
    52  	query.Add("before", before)
    53  	link.RawQuery = query.Encode()
    54  	req = NewRequest(t, "GET", link.String())
    55  	resp = MakeRequest(t, req, http.StatusOK)
    56  	DecodeJSON(t, resp, &apiComments)
    57  	assert.Len(t, apiComments, 1)
    58  	assert.EqualValues(t, 2, apiComments[0].ID)
    59  
    60  	query.Del("before")
    61  	query.Add("since", since)
    62  	link.RawQuery = query.Encode()
    63  	req = NewRequest(t, "GET", link.String())
    64  	resp = MakeRequest(t, req, http.StatusOK)
    65  	DecodeJSON(t, resp, &apiComments)
    66  	assert.Len(t, apiComments, 1)
    67  	assert.EqualValues(t, 3, apiComments[0].ID)
    68  }
    69  
    70  func TestAPIListIssueComments(t *testing.T) {
    71  	defer tests.PrepareTestEnv(t)()
    72  
    73  	comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
    74  		unittest.Cond("type = ?", issues_model.CommentTypeComment))
    75  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
    76  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
    77  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
    78  
    79  	token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeReadIssue)
    80  	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/comments", repoOwner.Name, repo.Name, issue.Index).
    81  		AddTokenAuth(token)
    82  	resp := MakeRequest(t, req, http.StatusOK)
    83  
    84  	var comments []*api.Comment
    85  	DecodeJSON(t, resp, &comments)
    86  	expectedCount := unittest.GetCount(t, &issues_model.Comment{IssueID: issue.ID},
    87  		unittest.Cond("type = ?", issues_model.CommentTypeComment))
    88  	assert.Len(t, comments, expectedCount)
    89  }
    90  
    91  func TestAPICreateComment(t *testing.T) {
    92  	defer tests.PrepareTestEnv(t)()
    93  	const commentBody = "Comment body"
    94  
    95  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{})
    96  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
    97  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
    98  
    99  	token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
   100  	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments",
   101  		repoOwner.Name, repo.Name, issue.Index)
   102  	req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
   103  		"body": commentBody,
   104  	}).AddTokenAuth(token)
   105  	resp := MakeRequest(t, req, http.StatusCreated)
   106  
   107  	var updatedComment api.Comment
   108  	DecodeJSON(t, resp, &updatedComment)
   109  	assert.EqualValues(t, commentBody, updatedComment.Body)
   110  	unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: updatedComment.ID, IssueID: issue.ID, Content: commentBody})
   111  
   112  	t.Run("BlockedByRepoOwner", func(t *testing.T) {
   113  		defer tests.PrintCurrentTest(t)()
   114  
   115  		user34 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 34})
   116  		issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
   117  		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
   118  
   119  		req := NewRequestWithValues(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments", repo.OwnerName, repo.Name, issue.Index), map[string]string{
   120  			"body": commentBody,
   121  		}).AddTokenAuth(getUserToken(t, user34.Name, auth_model.AccessTokenScopeWriteRepository))
   122  		MakeRequest(t, req, http.StatusForbidden)
   123  	})
   124  
   125  	t.Run("BlockedByIssuePoster", func(t *testing.T) {
   126  		defer tests.PrintCurrentTest(t)()
   127  
   128  		user34 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 34})
   129  		issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 13})
   130  		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
   131  
   132  		req := NewRequestWithValues(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments", repo.OwnerName, repo.Name, issue.Index), map[string]string{
   133  			"body": commentBody,
   134  		}).AddTokenAuth(getUserToken(t, user34.Name, auth_model.AccessTokenScopeWriteRepository))
   135  		MakeRequest(t, req, http.StatusForbidden)
   136  	})
   137  }
   138  
   139  func TestAPIGetComment(t *testing.T) {
   140  	defer tests.PrepareTestEnv(t)()
   141  
   142  	comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2})
   143  	assert.NoError(t, comment.LoadIssue(db.DefaultContext))
   144  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID})
   145  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   146  
   147  	token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeReadIssue)
   148  	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d", repoOwner.Name, repo.Name, comment.ID)
   149  	MakeRequest(t, req, http.StatusOK)
   150  	req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d", repoOwner.Name, repo.Name, comment.ID).
   151  		AddTokenAuth(token)
   152  	resp := MakeRequest(t, req, http.StatusOK)
   153  
   154  	var apiComment api.Comment
   155  	DecodeJSON(t, resp, &apiComment)
   156  
   157  	assert.NoError(t, comment.LoadPoster(db.DefaultContext))
   158  	expect := convert.ToAPIComment(db.DefaultContext, repo, comment)
   159  
   160  	assert.Equal(t, expect.ID, apiComment.ID)
   161  	assert.Equal(t, expect.Poster.FullName, apiComment.Poster.FullName)
   162  	assert.Equal(t, expect.Body, apiComment.Body)
   163  	assert.Equal(t, expect.Created.Unix(), apiComment.Created.Unix())
   164  }
   165  
   166  func TestAPIGetSystemUserComment(t *testing.T) {
   167  	defer tests.PrepareTestEnv(t)()
   168  
   169  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{})
   170  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
   171  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   172  
   173  	for _, systemUser := range []*user_model.User{
   174  		user_model.NewGhostUser(),
   175  		user_model.NewActionsUser(),
   176  	} {
   177  		body := fmt.Sprintf("Hello %s", systemUser.Name)
   178  		comment, err := issues_model.CreateComment(db.DefaultContext, &issues_model.CreateCommentOptions{
   179  			Type:    issues_model.CommentTypeComment,
   180  			Doer:    systemUser,
   181  			Repo:    repo,
   182  			Issue:   issue,
   183  			Content: body,
   184  		})
   185  		assert.NoError(t, err)
   186  
   187  		req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d", repoOwner.Name, repo.Name, comment.ID)
   188  		resp := MakeRequest(t, req, http.StatusOK)
   189  
   190  		var apiComment api.Comment
   191  		DecodeJSON(t, resp, &apiComment)
   192  
   193  		if assert.NotNil(t, apiComment.Poster) {
   194  			if assert.Equal(t, systemUser.ID, apiComment.Poster.ID) {
   195  				assert.NoError(t, comment.LoadPoster(db.DefaultContext))
   196  				assert.Equal(t, systemUser.Name, apiComment.Poster.UserName)
   197  			}
   198  		}
   199  		assert.Equal(t, body, apiComment.Body)
   200  	}
   201  }
   202  
   203  func TestAPIEditComment(t *testing.T) {
   204  	defer tests.PrepareTestEnv(t)()
   205  	const newCommentBody = "This is the new comment body"
   206  
   207  	comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 8},
   208  		unittest.Cond("type = ?", issues_model.CommentTypeComment))
   209  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
   210  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
   211  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   212  
   213  	t.Run("UnrelatedCommentID", func(t *testing.T) {
   214  		// Using the ID of a comment that does not belong to the repository must fail
   215  		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
   216  		repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   217  		token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
   218  		urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d",
   219  			repoOwner.Name, repo.Name, comment.ID)
   220  		req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
   221  			"body": newCommentBody,
   222  		}).AddTokenAuth(token)
   223  		MakeRequest(t, req, http.StatusNotFound)
   224  	})
   225  
   226  	token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
   227  	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d",
   228  		repoOwner.Name, repo.Name, comment.ID)
   229  	req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
   230  		"body": newCommentBody,
   231  	}).AddTokenAuth(token)
   232  	resp := MakeRequest(t, req, http.StatusOK)
   233  
   234  	var updatedComment api.Comment
   235  	DecodeJSON(t, resp, &updatedComment)
   236  	assert.EqualValues(t, comment.ID, updatedComment.ID)
   237  	assert.EqualValues(t, newCommentBody, updatedComment.Body)
   238  	unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: comment.ID, IssueID: issue.ID, Content: newCommentBody})
   239  }
   240  
   241  func TestAPIDeleteComment(t *testing.T) {
   242  	defer tests.PrepareTestEnv(t)()
   243  
   244  	comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 8},
   245  		unittest.Cond("type = ?", issues_model.CommentTypeComment))
   246  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
   247  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
   248  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   249  
   250  	t.Run("UnrelatedCommentID", func(t *testing.T) {
   251  		// Using the ID of a comment that does not belong to the repository must fail
   252  		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
   253  		repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   254  		token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
   255  		req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d", repoOwner.Name, repo.Name, comment.ID).
   256  			AddTokenAuth(token)
   257  		MakeRequest(t, req, http.StatusNotFound)
   258  	})
   259  
   260  	token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
   261  	req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d", repoOwner.Name, repo.Name, comment.ID).
   262  		AddTokenAuth(token)
   263  	MakeRequest(t, req, http.StatusNoContent)
   264  
   265  	unittest.AssertNotExistsBean(t, &issues_model.Comment{ID: comment.ID})
   266  }
   267  
   268  func TestAPIListIssueTimeline(t *testing.T) {
   269  	defer tests.PrepareTestEnv(t)()
   270  
   271  	// load comment
   272  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
   273  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
   274  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   275  
   276  	// make request
   277  	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/timeline", repoOwner.Name, repo.Name, issue.Index)
   278  	resp := MakeRequest(t, req, http.StatusOK)
   279  
   280  	// check if lens of list returned by API and
   281  	// lists extracted directly from DB are the same
   282  	var comments []*api.TimelineComment
   283  	DecodeJSON(t, resp, &comments)
   284  	expectedCount := unittest.GetCount(t, &issues_model.Comment{IssueID: issue.ID})
   285  	assert.Len(t, comments, expectedCount)
   286  }