mirror of
https://github.com/go-gitea/gitea.git
synced 2026-11-09 17:37:20 -06:00
fix(api): lock and unlock issues as the signed-in user, not the repository owner (#40291)
`PUT/DELETE /repos/{owner}/{repo}/issues/{index}/lock` passed
`ctx.ContextUser` as the doer of `LockIssue` / `UnlockIssue`. In the
repo routes that is the owner of the repository, so on a repository of
an organization the lock and unlock timeline comments were created by
the organization instead of the user who did it. The web handler already
uses the signed-in user; this uses `ctx.Doer` as well.
Adds a subtest `DoerOnOrganizationRepo` to the existing
`TestAPILockIssue`: a member of an organization locks and unlocks an
issue of an organization repository, and the comments must be posted by
that member.
Found while testing audit logging of the issue lock events downstream.
_Authored by Codet (Claude)._
This commit is contained in:
@@ -61,7 +61,7 @@ func LockIssue(ctx *context.APIContext) {
|
||||
|
||||
if !issue.IsLocked {
|
||||
opt := &issues_model.IssueLockOptions{
|
||||
Doer: ctx.ContextUser,
|
||||
Doer: ctx.Doer,
|
||||
Issue: issue,
|
||||
Reason: reason,
|
||||
}
|
||||
@@ -121,7 +121,7 @@ func UnlockIssue(ctx *context.APIContext) {
|
||||
|
||||
if issue.IsLocked {
|
||||
opt := &issues_model.IssueLockOptions{
|
||||
Doer: ctx.ContextUser,
|
||||
Doer: ctx.Doer,
|
||||
Issue: issue,
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"gitea.dev/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAPILockIssue(t *testing.T) {
|
||||
@@ -71,4 +72,26 @@ func TestAPILockIssue(t *testing.T) {
|
||||
req = NewRequest(t, "DELETE", urlStr).AddTokenAuth(token34)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
})
|
||||
|
||||
t.Run("DoerOnOrganizationRepo", func(t *testing.T) {
|
||||
// the lock and unlock comments are posted by the signed-in user, not by the organization owning the repository
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 6})
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||
require.True(t, org.IsOrganization())
|
||||
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"}) // an owner of the organization
|
||||
session := loginUser(t, doer.Name)
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue, auth_model.AccessTokenScopeWriteRepository)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/lock", org.Name, repo.Name, issue.Index)
|
||||
|
||||
req := NewRequestWithJSON(t, "PUT", urlStr, api.LockIssueOption{Reason: "Spam"}).AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
lockComment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: issue.ID, Type: issues_model.CommentTypeLock})
|
||||
assert.Equal(t, doer.ID, lockComment.PosterID)
|
||||
|
||||
req = NewRequest(t, "DELETE", urlStr).AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
unlockComment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: issue.ID, Type: issues_model.CommentTypeUnlock})
|
||||
assert.Equal(t, doer.ID, unlockComment.PosterID)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user