forked from NYANDEV/forgejo
00c8b16b8c
System users (Ghost, ActionsUser, etc) have a negative id and may be
the author of a comment, either because it was created by a now
deleted user or via an action using a transient token.
The GetPossibleUserByID function has special cases related to system
users and will not fail if given a negative id.
Refs: https://codeberg.org/forgejo/forgejo/issues/1425
(cherry picked from commit 97667e06b384d834a04eaa05e8f91563481709b1)
(cherry picked from commit 8ef73a09c9cb08e536aff7df8fc715c8d48c7c4f)
(cherry picked from commit fa8a00d26420ef56497203a5c607b3d336feb813)
(cherry picked from commit 2ada2074b56f3cd981dbacac0a7b1033ff486ffd)
(cherry picked from commit f9a59b940a2ab2c9abac7c346da24b22d15017f1)
(cherry picked from commit cd82834043c14a679cc55eba980c27549b2f87e5)
(cherry picked from commit 7fb032c2400386d6edba769452e1735f32ac3f78)
(cherry picked from commit 64438ff837f411656c0456864bd9be2c47f37311)
(cherry picked from commit 8174592b298eb2f3a34ed67a836739cc9c9e5a42)
(cherry picked from commit 46d36555f9
)
344 lines
14 KiB
Go
344 lines
14 KiB
Go
// Copyright 2017 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package integration
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"testing"
|
|
"time"
|
|
|
|
auth_model "code.gitea.io/gitea/models/auth"
|
|
"code.gitea.io/gitea/models/db"
|
|
issues_model "code.gitea.io/gitea/models/issues"
|
|
repo_model "code.gitea.io/gitea/models/repo"
|
|
"code.gitea.io/gitea/models/unittest"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
api "code.gitea.io/gitea/modules/structs"
|
|
"code.gitea.io/gitea/services/convert"
|
|
"code.gitea.io/gitea/tests"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestAPIListRepoComments(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
|
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
|
|
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments", repoOwner.Name, repo.Name))
|
|
req := NewRequest(t, "GET", link.String())
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
|
|
var apiComments []*api.Comment
|
|
DecodeJSON(t, resp, &apiComments)
|
|
assert.Len(t, apiComments, 2)
|
|
for _, apiComment := range apiComments {
|
|
c := &issues_model.Comment{ID: apiComment.ID}
|
|
unittest.AssertExistsAndLoadBean(t, c,
|
|
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: c.IssueID, RepoID: repo.ID})
|
|
}
|
|
|
|
// test before and since filters
|
|
query := url.Values{}
|
|
before := "2000-01-01T00:00:11+00:00" // unix: 946684811
|
|
since := "2000-01-01T00:00:12+00:00" // unix: 946684812
|
|
query.Add("before", before)
|
|
link.RawQuery = query.Encode()
|
|
req = NewRequest(t, "GET", link.String())
|
|
resp = MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &apiComments)
|
|
assert.Len(t, apiComments, 1)
|
|
assert.EqualValues(t, 2, apiComments[0].ID)
|
|
|
|
query.Del("before")
|
|
query.Add("since", since)
|
|
link.RawQuery = query.Encode()
|
|
req = NewRequest(t, "GET", link.String())
|
|
resp = MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &apiComments)
|
|
assert.Len(t, apiComments, 1)
|
|
assert.EqualValues(t, 3, apiComments[0].ID)
|
|
}
|
|
|
|
func TestAPIListIssueComments(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
|
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
|
|
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeReadIssue)
|
|
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/comments?token=%s",
|
|
repoOwner.Name, repo.Name, issue.Index, token)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
|
|
var comments []*api.Comment
|
|
DecodeJSON(t, resp, &comments)
|
|
expectedCount := unittest.GetCount(t, &issues_model.Comment{IssueID: issue.ID},
|
|
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
|
assert.Len(t, comments, expectedCount)
|
|
}
|
|
|
|
func TestAPICreateComment(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
const commentBody = "Comment body"
|
|
|
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{})
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
|
|
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
|
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments?token=%s",
|
|
repoOwner.Name, repo.Name, issue.Index, token)
|
|
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
|
"body": commentBody,
|
|
})
|
|
resp := MakeRequest(t, req, http.StatusCreated)
|
|
|
|
var updatedComment api.Comment
|
|
DecodeJSON(t, resp, &updatedComment)
|
|
assert.EqualValues(t, commentBody, updatedComment.Body)
|
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: updatedComment.ID, IssueID: issue.ID, Content: commentBody})
|
|
}
|
|
|
|
func TestAPICreateCommentAutoDate(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{})
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
|
|
|
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments?token=%s",
|
|
repoOwner.Name, repo.Name, issue.Index, token)
|
|
const commentBody = "Comment body"
|
|
|
|
t.Run("WithAutoDate", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
|
"body": commentBody,
|
|
})
|
|
resp := MakeRequest(t, req, http.StatusCreated)
|
|
var updatedComment api.Comment
|
|
DecodeJSON(t, resp, &updatedComment)
|
|
|
|
// the execution of the API call supposedly lasted less than one minute
|
|
updatedSince := time.Since(updatedComment.Updated)
|
|
assert.LessOrEqual(t, updatedSince, time.Minute)
|
|
|
|
commentAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: updatedComment.ID, IssueID: issue.ID, Content: commentBody})
|
|
updatedSince = time.Since(commentAfter.UpdatedUnix.AsTime())
|
|
assert.LessOrEqual(t, updatedSince, time.Minute)
|
|
})
|
|
|
|
t.Run("WithUpdateDate", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
updatedAt := time.Now().Add(-time.Hour).Truncate(time.Second)
|
|
|
|
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueCommentOption{
|
|
Body: commentBody,
|
|
Updated: &updatedAt,
|
|
})
|
|
resp := MakeRequest(t, req, http.StatusCreated)
|
|
var updatedComment api.Comment
|
|
DecodeJSON(t, resp, &updatedComment)
|
|
|
|
// dates will be converted into the same tz, in order to compare them
|
|
utcTZ, _ := time.LoadLocation("UTC")
|
|
assert.Equal(t, updatedAt.In(utcTZ), updatedComment.Updated.In(utcTZ))
|
|
commentAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: updatedComment.ID, IssueID: issue.ID, Content: commentBody})
|
|
assert.Equal(t, updatedAt.In(utcTZ), commentAfter.UpdatedUnix.AsTime().In(utcTZ))
|
|
})
|
|
}
|
|
|
|
func TestAPIGetComment(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2})
|
|
assert.NoError(t, comment.LoadIssue(db.DefaultContext))
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID})
|
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
|
|
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeReadIssue)
|
|
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d", repoOwner.Name, repo.Name, comment.ID)
|
|
MakeRequest(t, req, http.StatusOK)
|
|
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s", repoOwner.Name, repo.Name, comment.ID, token)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
|
|
var apiComment api.Comment
|
|
DecodeJSON(t, resp, &apiComment)
|
|
|
|
assert.NoError(t, comment.LoadPoster(db.DefaultContext))
|
|
expect := convert.ToAPIComment(db.DefaultContext, repo, comment)
|
|
|
|
assert.Equal(t, expect.ID, apiComment.ID)
|
|
assert.Equal(t, expect.Poster.FullName, apiComment.Poster.FullName)
|
|
assert.Equal(t, expect.Body, apiComment.Body)
|
|
assert.Equal(t, expect.Created.Unix(), apiComment.Created.Unix())
|
|
}
|
|
|
|
func TestAPIGetSystemUserComment(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{})
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
|
|
for _, systemUser := range []*user_model.User{
|
|
user_model.NewGhostUser(),
|
|
user_model.NewActionsUser(),
|
|
} {
|
|
body := fmt.Sprintf("Hello %s", systemUser.Name)
|
|
comment, err := issues_model.CreateComment(db.DefaultContext, &issues_model.CreateCommentOptions{
|
|
Type: issues_model.CommentTypeComment,
|
|
Doer: systemUser,
|
|
Repo: repo,
|
|
Issue: issue,
|
|
Content: body,
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d", repoOwner.Name, repo.Name, comment.ID)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
|
|
var apiComment api.Comment
|
|
DecodeJSON(t, resp, &apiComment)
|
|
|
|
if assert.NotNil(t, apiComment.Poster) {
|
|
if assert.Equal(t, systemUser.ID, apiComment.Poster.ID) {
|
|
assert.NoError(t, comment.LoadPoster(db.DefaultContext))
|
|
assert.Equal(t, systemUser.Name, apiComment.Poster.UserName)
|
|
}
|
|
}
|
|
assert.Equal(t, body, apiComment.Body)
|
|
}
|
|
}
|
|
|
|
func TestAPIEditComment(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
const newCommentBody = "This is the new comment body"
|
|
|
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
|
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
|
|
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
|
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
|
repoOwner.Name, repo.Name, comment.ID, token)
|
|
req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
|
|
"body": newCommentBody,
|
|
})
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
|
|
var updatedComment api.Comment
|
|
DecodeJSON(t, resp, &updatedComment)
|
|
assert.EqualValues(t, comment.ID, updatedComment.ID)
|
|
assert.EqualValues(t, newCommentBody, updatedComment.Body)
|
|
unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: comment.ID, IssueID: issue.ID, Content: newCommentBody})
|
|
}
|
|
|
|
func TestAPIEditCommentWithDate(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
|
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
|
|
|
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
|
repoOwner.Name, repo.Name, comment.ID, token)
|
|
const newCommentBody = "This is the new comment body"
|
|
|
|
t.Run("WithAutoDate", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
|
|
"body": newCommentBody,
|
|
})
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
var updatedComment api.Comment
|
|
DecodeJSON(t, resp, &updatedComment)
|
|
|
|
// the execution of the API call supposedly lasted less than one minute
|
|
updatedSince := time.Since(updatedComment.Updated)
|
|
assert.LessOrEqual(t, updatedSince, time.Minute)
|
|
|
|
commentAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: comment.ID, IssueID: issue.ID, Content: newCommentBody})
|
|
updatedSince = time.Since(commentAfter.UpdatedUnix.AsTime())
|
|
assert.LessOrEqual(t, updatedSince, time.Minute)
|
|
})
|
|
|
|
t.Run("WithUpdateDate", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
updatedAt := time.Now().Add(-time.Hour).Truncate(time.Second)
|
|
|
|
req := NewRequestWithJSON(t, "PATCH", urlStr, &api.EditIssueCommentOption{
|
|
Body: newCommentBody,
|
|
Updated: &updatedAt,
|
|
})
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
var updatedComment api.Comment
|
|
DecodeJSON(t, resp, &updatedComment)
|
|
|
|
// dates will be converted into the same tz, in order to compare them
|
|
utcTZ, _ := time.LoadLocation("UTC")
|
|
assert.Equal(t, updatedAt.In(utcTZ), updatedComment.Updated.In(utcTZ))
|
|
commentAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: comment.ID, IssueID: issue.ID, Content: newCommentBody})
|
|
assert.Equal(t, updatedAt.In(utcTZ), commentAfter.UpdatedUnix.AsTime().In(utcTZ))
|
|
})
|
|
}
|
|
|
|
func TestAPIDeleteComment(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
|
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
|
|
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
|
|
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
|
repoOwner.Name, repo.Name, comment.ID, token)
|
|
MakeRequest(t, req, http.StatusNoContent)
|
|
|
|
unittest.AssertNotExistsBean(t, &issues_model.Comment{ID: comment.ID})
|
|
}
|
|
|
|
func TestAPIListIssueTimeline(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
// load comment
|
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
|
|
|
// make request
|
|
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/timeline",
|
|
repoOwner.Name, repo.Name, issue.Index)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
|
|
// check if lens of list returned by API and
|
|
// lists extracted directly from DB are the same
|
|
var comments []*api.TimelineComment
|
|
DecodeJSON(t, resp, &comments)
|
|
expectedCount := unittest.GetCount(t, &issues_model.Comment{IssueID: issue.ID})
|
|
assert.Len(t, comments, expectedCount)
|
|
}
|