Fix comment permissions (#28213)
This PR will fix some missed checks for private repositories' data on web routes and API routes.
This commit is contained in:
parent
80217cacfc
commit
882e502327
34 changed files with 417 additions and 105 deletions
|
@ -92,10 +92,9 @@ func CountUserGPGKeys(ctx context.Context, userID int64) (int64, error) {
|
||||||
return db.GetEngine(ctx).Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{})
|
return db.GetEngine(ctx).Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGPGKeyByID returns public key by given ID.
|
func GetGPGKeyForUserByID(ctx context.Context, ownerID, keyID int64) (*GPGKey, error) {
|
||||||
func GetGPGKeyByID(ctx context.Context, keyID int64) (*GPGKey, error) {
|
|
||||||
key := new(GPGKey)
|
key := new(GPGKey)
|
||||||
has, err := db.GetEngine(ctx).ID(keyID).Get(key)
|
has, err := db.GetEngine(ctx).Where("id=? AND owner_id=?", keyID, ownerID).Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
|
@ -225,7 +224,7 @@ func deleteGPGKey(ctx context.Context, keyID string) (int64, error) {
|
||||||
|
|
||||||
// DeleteGPGKey deletes GPG key information in database.
|
// DeleteGPGKey deletes GPG key information in database.
|
||||||
func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err error) {
|
func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err error) {
|
||||||
key, err := GetGPGKeyByID(ctx, id)
|
key, err := GetGPGKeyForUserByID(ctx, doer.ID, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if IsErrGPGKeyNotExist(err) {
|
if IsErrGPGKeyNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -233,11 +232,6 @@ func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err err
|
||||||
return fmt.Errorf("GetPublicKeyByID: %w", err)
|
return fmt.Errorf("GetPublicKeyByID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user has access to delete this key.
|
|
||||||
if !doer.IsAdmin && doer.ID != key.OwnerID {
|
|
||||||
return ErrGPGKeyAccessDenied{doer.ID, key.ID}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(ctx)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -66,3 +66,12 @@
|
||||||
tree_path: "README.md"
|
tree_path: "README.md"
|
||||||
created_unix: 946684812
|
created_unix: 946684812
|
||||||
invalidated: true
|
invalidated: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 8
|
||||||
|
type: 0 # comment
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 4 # in repo_id 2
|
||||||
|
content: "comment in private pository"
|
||||||
|
created_unix: 946684811
|
||||||
|
updated_unix: 946684811
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
priority: 0
|
priority: 0
|
||||||
is_closed: true
|
is_closed: true
|
||||||
is_pull: false
|
is_pull: false
|
||||||
num_comments: 0
|
num_comments: 1
|
||||||
created_unix: 946684830
|
created_unix: 946684830
|
||||||
updated_unix: 978307200
|
updated_unix: 978307200
|
||||||
is_locked: false
|
is_locked: false
|
||||||
|
|
|
@ -1024,6 +1024,7 @@ type FindCommentsOptions struct {
|
||||||
Type CommentType
|
Type CommentType
|
||||||
IssueIDs []int64
|
IssueIDs []int64
|
||||||
Invalidated util.OptionalBool
|
Invalidated util.OptionalBool
|
||||||
|
IsPull util.OptionalBool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToConds implements FindOptions interface
|
// ToConds implements FindOptions interface
|
||||||
|
@ -1058,6 +1059,9 @@ func (opts FindCommentsOptions) ToConds() builder.Cond {
|
||||||
if !opts.Invalidated.IsNone() {
|
if !opts.Invalidated.IsNone() {
|
||||||
cond = cond.And(builder.Eq{"comment.invalidated": opts.Invalidated.IsTrue()})
|
cond = cond.And(builder.Eq{"comment.invalidated": opts.Invalidated.IsTrue()})
|
||||||
}
|
}
|
||||||
|
if opts.IsPull != util.OptionalBoolNone {
|
||||||
|
cond = cond.And(builder.Eq{"issue.is_pull": opts.IsPull.IsTrue()})
|
||||||
|
}
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1065,7 +1069,7 @@ func (opts FindCommentsOptions) ToConds() builder.Cond {
|
||||||
func FindComments(ctx context.Context, opts *FindCommentsOptions) (CommentList, error) {
|
func FindComments(ctx context.Context, opts *FindCommentsOptions) (CommentList, error) {
|
||||||
comments := make([]*Comment, 0, 10)
|
comments := make([]*Comment, 0, 10)
|
||||||
sess := db.GetEngine(ctx).Where(opts.ToConds())
|
sess := db.GetEngine(ctx).Where(opts.ToConds())
|
||||||
if opts.RepoID > 0 {
|
if opts.RepoID > 0 || opts.IsPull != util.OptionalBoolNone {
|
||||||
sess.Join("INNER", "issue", "issue.id = comment.issue_id")
|
sess.Join("INNER", "issue", "issue.id = comment.issue_id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -218,9 +218,9 @@ func GetIssueContentHistoryByID(dbCtx context.Context, id int64) (*ContentHistor
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssueContentHistoryAndPrev get a history and the previous non-deleted history (to compare)
|
// GetIssueContentHistoryAndPrev get a history and the previous non-deleted history (to compare)
|
||||||
func GetIssueContentHistoryAndPrev(dbCtx context.Context, id int64) (history, prevHistory *ContentHistory, err error) {
|
func GetIssueContentHistoryAndPrev(dbCtx context.Context, issueID, id int64) (history, prevHistory *ContentHistory, err error) {
|
||||||
history = &ContentHistory{}
|
history = &ContentHistory{}
|
||||||
has, err := db.GetEngine(dbCtx).ID(id).Get(history)
|
has, err := db.GetEngine(dbCtx).Where("id=? AND issue_id=?", id, issueID).Get(history)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to get issue content history %v. err=%v", id, err)
|
log.Error("failed to get issue content history %v. err=%v", id, err)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
|
@ -58,13 +58,13 @@ func TestContentHistory(t *testing.T) {
|
||||||
hasHistory2, _ := issues_model.HasIssueContentHistory(dbCtx, 10, 1)
|
hasHistory2, _ := issues_model.HasIssueContentHistory(dbCtx, 10, 1)
|
||||||
assert.False(t, hasHistory2)
|
assert.False(t, hasHistory2)
|
||||||
|
|
||||||
h6, h6Prev, _ := issues_model.GetIssueContentHistoryAndPrev(dbCtx, 6)
|
h6, h6Prev, _ := issues_model.GetIssueContentHistoryAndPrev(dbCtx, 10, 6)
|
||||||
assert.EqualValues(t, 6, h6.ID)
|
assert.EqualValues(t, 6, h6.ID)
|
||||||
assert.EqualValues(t, 5, h6Prev.ID)
|
assert.EqualValues(t, 5, h6Prev.ID)
|
||||||
|
|
||||||
// soft-delete
|
// soft-delete
|
||||||
_ = issues_model.SoftDeleteIssueContentHistory(dbCtx, 5)
|
_ = issues_model.SoftDeleteIssueContentHistory(dbCtx, 5)
|
||||||
h6, h6Prev, _ = issues_model.GetIssueContentHistoryAndPrev(dbCtx, 6)
|
h6, h6Prev, _ = issues_model.GetIssueContentHistoryAndPrev(dbCtx, 10, 6)
|
||||||
assert.EqualValues(t, 6, h6.ID)
|
assert.EqualValues(t, 6, h6.ID)
|
||||||
assert.EqualValues(t, 4, h6Prev.ID)
|
assert.EqualValues(t, 4, h6Prev.ID)
|
||||||
|
|
||||||
|
|
|
@ -294,6 +294,18 @@ func GetProjectByID(ctx context.Context, id int64) (*Project, error) {
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetProjectForRepoByID returns the projects in a repository
|
||||||
|
func GetProjectForRepoByID(ctx context.Context, repoID, id int64) (*Project, error) {
|
||||||
|
p := new(Project)
|
||||||
|
has, err := db.GetEngine(ctx).Where("id=? AND repo_id=?", id, repoID).Get(p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, ErrProjectNotExist{ID: id}
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateProject updates project properties
|
// UpdateProject updates project properties
|
||||||
func UpdateProject(ctx context.Context, p *Project) error {
|
func UpdateProject(ctx context.Context, p *Project) error {
|
||||||
if !IsCardTypeValid(p.CardType) {
|
if !IsCardTypeValid(p.CardType) {
|
||||||
|
|
|
@ -207,6 +207,21 @@ func GetReleaseByID(ctx context.Context, id int64) (*Release, error) {
|
||||||
return rel, nil
|
return rel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetReleaseForRepoByID returns release with given ID.
|
||||||
|
func GetReleaseForRepoByID(ctx context.Context, repoID, id int64) (*Release, error) {
|
||||||
|
rel := new(Release)
|
||||||
|
has, err := db.GetEngine(ctx).
|
||||||
|
Where("id=? AND repo_id=?", id, repoID).
|
||||||
|
Get(rel)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, ErrReleaseNotExist{id, ""}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rel, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FindReleasesOptions describes the conditions to Find releases
|
// FindReleasesOptions describes the conditions to Find releases
|
||||||
type FindReleasesOptions struct {
|
type FindReleasesOptions struct {
|
||||||
db.ListOptions
|
db.ListOptions
|
||||||
|
|
|
@ -392,39 +392,40 @@ func CreateWebhooks(ctx context.Context, ws []*Webhook) error {
|
||||||
return db.Insert(ctx, ws)
|
return db.Insert(ctx, ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getWebhook uses argument bean as query condition,
|
// GetWebhookByID returns webhook of repository by given ID.
|
||||||
// ID must be specified and do not assign unnecessary fields.
|
func GetWebhookByID(ctx context.Context, id int64) (*Webhook, error) {
|
||||||
func getWebhook(ctx context.Context, bean *Webhook) (*Webhook, error) {
|
bean := new(Webhook)
|
||||||
has, err := db.GetEngine(ctx).Get(bean)
|
has, err := db.GetEngine(ctx).ID(id).Get(bean)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return nil, ErrWebhookNotExist{ID: bean.ID}
|
return nil, ErrWebhookNotExist{ID: id}
|
||||||
}
|
}
|
||||||
return bean, nil
|
return bean, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhookByID returns webhook of repository by given ID.
|
|
||||||
func GetWebhookByID(ctx context.Context, id int64) (*Webhook, error) {
|
|
||||||
return getWebhook(ctx, &Webhook{
|
|
||||||
ID: id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWebhookByRepoID returns webhook of repository by given ID.
|
// GetWebhookByRepoID returns webhook of repository by given ID.
|
||||||
func GetWebhookByRepoID(ctx context.Context, repoID, id int64) (*Webhook, error) {
|
func GetWebhookByRepoID(ctx context.Context, repoID, id int64) (*Webhook, error) {
|
||||||
return getWebhook(ctx, &Webhook{
|
webhook := new(Webhook)
|
||||||
ID: id,
|
has, err := db.GetEngine(ctx).Where("id=? AND repo_id=?", id, repoID).Get(webhook)
|
||||||
RepoID: repoID,
|
if err != nil {
|
||||||
})
|
return nil, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, ErrWebhookNotExist{ID: id}
|
||||||
|
}
|
||||||
|
return webhook, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebhookByOwnerID returns webhook of a user or organization by given ID.
|
// GetWebhookByOwnerID returns webhook of a user or organization by given ID.
|
||||||
func GetWebhookByOwnerID(ctx context.Context, ownerID, id int64) (*Webhook, error) {
|
func GetWebhookByOwnerID(ctx context.Context, ownerID, id int64) (*Webhook, error) {
|
||||||
return getWebhook(ctx, &Webhook{
|
webhook := new(Webhook)
|
||||||
ID: id,
|
has, err := db.GetEngine(ctx).Where("id=? AND owner_id=?", id, ownerID).Get(webhook)
|
||||||
OwnerID: ownerID,
|
if err != nil {
|
||||||
})
|
return nil, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, ErrWebhookNotExist{ID: id}
|
||||||
|
}
|
||||||
|
return webhook, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListWebhookOptions are options to filter webhooks on ListWebhooksByOpts
|
// ListWebhookOptions are options to filter webhooks on ListWebhooksByOpts
|
||||||
|
@ -461,20 +462,20 @@ func UpdateWebhookLastStatus(ctx context.Context, w *Webhook) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteWebhook uses argument bean as query condition,
|
// DeleteWebhookByID uses argument bean as query condition,
|
||||||
// ID must be specified and do not assign unnecessary fields.
|
// ID must be specified and do not assign unnecessary fields.
|
||||||
func deleteWebhook(ctx context.Context, bean *Webhook) (err error) {
|
func DeleteWebhookByID(ctx context.Context, id int64) (err error) {
|
||||||
ctx, committer, err := db.TxContext(ctx)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
if count, err := db.DeleteByBean(ctx, bean); err != nil {
|
if count, err := db.DeleteByID(ctx, id, new(Webhook)); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if count == 0 {
|
} else if count == 0 {
|
||||||
return ErrWebhookNotExist{ID: bean.ID}
|
return ErrWebhookNotExist{ID: id}
|
||||||
} else if _, err = db.DeleteByBean(ctx, &HookTask{HookID: bean.ID}); err != nil {
|
} else if _, err = db.DeleteByBean(ctx, &HookTask{HookID: id}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,16 +484,16 @@ func deleteWebhook(ctx context.Context, bean *Webhook) (err error) {
|
||||||
|
|
||||||
// DeleteWebhookByRepoID deletes webhook of repository by given ID.
|
// DeleteWebhookByRepoID deletes webhook of repository by given ID.
|
||||||
func DeleteWebhookByRepoID(ctx context.Context, repoID, id int64) error {
|
func DeleteWebhookByRepoID(ctx context.Context, repoID, id int64) error {
|
||||||
return deleteWebhook(ctx, &Webhook{
|
if _, err := GetWebhookByRepoID(ctx, repoID, id); err != nil {
|
||||||
ID: id,
|
return err
|
||||||
RepoID: repoID,
|
}
|
||||||
})
|
return DeleteWebhookByID(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteWebhookByOwnerID deletes webhook of a user or organization by given ID.
|
// DeleteWebhookByOwnerID deletes webhook of a user or organization by given ID.
|
||||||
func DeleteWebhookByOwnerID(ctx context.Context, ownerID, id int64) error {
|
func DeleteWebhookByOwnerID(ctx context.Context, ownerID, id int64) error {
|
||||||
return deleteWebhook(ctx, &Webhook{
|
if _, err := GetWebhookByOwnerID(ctx, ownerID, id); err != nil {
|
||||||
ID: id,
|
return err
|
||||||
OwnerID: ownerID,
|
}
|
||||||
})
|
return DeleteWebhookByID(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1259,8 +1259,8 @@ func Routes() *web.Route {
|
||||||
m.Group("/{username}/{reponame}", func() {
|
m.Group("/{username}/{reponame}", func() {
|
||||||
m.Group("/issues", func() {
|
m.Group("/issues", func() {
|
||||||
m.Combo("").Get(repo.ListIssues).
|
m.Combo("").Get(repo.ListIssues).
|
||||||
Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueOption{}), repo.CreateIssue)
|
Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueOption{}), reqRepoReader(unit.TypeIssues), repo.CreateIssue)
|
||||||
m.Get("/pinned", repo.ListPinnedIssues)
|
m.Get("/pinned", reqRepoReader(unit.TypeIssues), repo.ListPinnedIssues)
|
||||||
m.Group("/comments", func() {
|
m.Group("/comments", func() {
|
||||||
m.Get("", repo.ListRepoIssueComments)
|
m.Get("", repo.ListRepoIssueComments)
|
||||||
m.Group("/{id}", func() {
|
m.Group("/{id}", func() {
|
||||||
|
|
|
@ -462,6 +462,24 @@ func ListIssues(ctx *context.APIContext) {
|
||||||
isPull = util.OptionalBoolNone
|
isPull = util.OptionalBoolNone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isPull != util.OptionalBoolNone && !ctx.Repo.CanReadIssuesOrPulls(isPull.IsTrue()) {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isPull == util.OptionalBoolNone {
|
||||||
|
canReadIssues := ctx.Repo.CanRead(unit.TypeIssues)
|
||||||
|
canReadPulls := ctx.Repo.CanRead(unit.TypePullRequests)
|
||||||
|
if !canReadIssues && !canReadPulls {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
} else if !canReadIssues {
|
||||||
|
isPull = util.OptionalBoolTrue
|
||||||
|
} else if !canReadPulls {
|
||||||
|
isPull = util.OptionalBoolFalse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: we should be more efficient here
|
// FIXME: we should be more efficient here
|
||||||
createdByID := getUserIDForFilter(ctx, "created_by")
|
createdByID := getUserIDForFilter(ctx, "created_by")
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
|
@ -593,6 +611,10 @@ func GetIssue(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull) {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue))
|
ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,11 @@ import (
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
access_model "code.gitea.io/gitea/models/perm/access"
|
access_model "code.gitea.io/gitea/models/perm/access"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
|
@ -71,6 +73,11 @@ func ListIssueComments(ctx *context.APIContext) {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetRawIssueByIndex", err)
|
ctx.Error(http.StatusInternalServerError, "GetRawIssueByIndex", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull) {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
issue.Repo = ctx.Repo.Repository
|
issue.Repo = ctx.Repo.Repository
|
||||||
|
|
||||||
opts := &issues_model.FindCommentsOptions{
|
opts := &issues_model.FindCommentsOptions{
|
||||||
|
@ -271,12 +278,27 @@ func ListRepoIssueComments(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isPull util.OptionalBool
|
||||||
|
canReadIssue := ctx.Repo.CanRead(unit.TypeIssues)
|
||||||
|
canReadPull := ctx.Repo.CanRead(unit.TypePullRequests)
|
||||||
|
if canReadIssue && canReadPull {
|
||||||
|
isPull = util.OptionalBoolNone
|
||||||
|
} else if canReadIssue {
|
||||||
|
isPull = util.OptionalBoolFalse
|
||||||
|
} else if canReadPull {
|
||||||
|
isPull = util.OptionalBoolTrue
|
||||||
|
} else {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
opts := &issues_model.FindCommentsOptions{
|
opts := &issues_model.FindCommentsOptions{
|
||||||
ListOptions: utils.GetListOptions(ctx),
|
ListOptions: utils.GetListOptions(ctx),
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
Type: issues_model.CommentTypeComment,
|
Type: issues_model.CommentTypeComment,
|
||||||
Since: since,
|
Since: since,
|
||||||
Before: before,
|
Before: before,
|
||||||
|
IsPull: isPull,
|
||||||
}
|
}
|
||||||
|
|
||||||
comments, err := issues_model.FindComments(ctx, opts)
|
comments, err := issues_model.FindComments(ctx, opts)
|
||||||
|
@ -367,6 +389,11 @@ func CreateIssueComment(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull) {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.Doer.IsAdmin {
|
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.Doer.IsAdmin {
|
||||||
ctx.Error(http.StatusForbidden, "CreateIssueComment", errors.New(ctx.Tr("repo.issues.comment_on_locked")))
|
ctx.Error(http.StatusForbidden, "CreateIssueComment", errors.New(ctx.Tr("repo.issues.comment_on_locked")))
|
||||||
return
|
return
|
||||||
|
@ -436,6 +463,11 @@ func GetIssueComment(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if comment.Type != issues_model.CommentTypeComment {
|
if comment.Type != issues_model.CommentTypeComment {
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
return
|
return
|
||||||
|
@ -555,7 +587,17 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.IsAdmin()) {
|
if err := comment.LoadIssue(ctx); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if comment.Issue.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
ctx.Status(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
|
||||||
ctx.Status(http.StatusForbidden)
|
ctx.Status(http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -658,7 +700,17 @@ func deleteIssueComment(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.IsAdmin()) {
|
if err := comment.LoadIssue(ctx); err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if comment.Issue.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
ctx.Status(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
|
||||||
ctx.Status(http.StatusForbidden)
|
ctx.Status(http.StatusForbidden)
|
||||||
return
|
return
|
||||||
} else if comment.Type != issues_model.CommentTypeComment {
|
} else if comment.Type != issues_model.CommentTypeComment {
|
||||||
|
|
|
@ -329,6 +329,10 @@ func getIssueCommentSafe(ctx *context.APIContext) *issues_model.Comment {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
comment.Issue.Repo = ctx.Repo.Repository
|
comment.Issue.Repo = ctx.Repo.Repository
|
||||||
|
|
||||||
return comment
|
return comment
|
||||||
|
|
|
@ -61,6 +61,12 @@ func GetIssueCommentReactions(ctx *context.APIContext) {
|
||||||
|
|
||||||
if err := comment.LoadIssue(ctx); err != nil {
|
if err := comment.LoadIssue(ctx); err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue", err)
|
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if comment.Issue.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
|
if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
|
||||||
|
@ -190,9 +196,19 @@ func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOp
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = comment.LoadIssue(ctx)
|
if err = comment.LoadIssue(ctx); err != nil {
|
||||||
if err != nil {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue() failed", err)
|
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue() failed", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if comment.Issue.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if comment.Issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull) {
|
if comment.Issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull) {
|
||||||
|
|
|
@ -153,6 +153,12 @@ func GetDeployKey(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this check make it more consistent
|
||||||
|
if key.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err = key.GetContent(ctx); err != nil {
|
if err = key.GetContent(ctx); err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetContent", err)
|
ctx.Error(http.StatusInternalServerError, "GetContent", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -49,13 +49,12 @@ func GetRelease(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
id := ctx.ParamsInt64(":id")
|
id := ctx.ParamsInt64(":id")
|
||||||
release, err := repo_model.GetReleaseByID(ctx, id)
|
release, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id)
|
||||||
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
|
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
|
ctx.Error(http.StatusInternalServerError, "GetReleaseForRepoByID", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil && repo_model.IsErrReleaseNotExist(err) ||
|
if err != nil && repo_model.IsErrReleaseNotExist(err) || release.IsTag {
|
||||||
release.IsTag || release.RepoID != ctx.Repo.Repository.ID {
|
|
||||||
ctx.NotFound()
|
ctx.NotFound()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -315,13 +314,12 @@ func EditRelease(ctx *context.APIContext) {
|
||||||
|
|
||||||
form := web.GetForm(ctx).(*api.EditReleaseOption)
|
form := web.GetForm(ctx).(*api.EditReleaseOption)
|
||||||
id := ctx.ParamsInt64(":id")
|
id := ctx.ParamsInt64(":id")
|
||||||
rel, err := repo_model.GetReleaseByID(ctx, id)
|
rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id)
|
||||||
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
|
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
|
ctx.Error(http.StatusInternalServerError, "GetReleaseForRepoByID", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil && repo_model.IsErrReleaseNotExist(err) ||
|
if err != nil && repo_model.IsErrReleaseNotExist(err) || rel.IsTag {
|
||||||
rel.IsTag || rel.RepoID != ctx.Repo.Repository.ID {
|
|
||||||
ctx.NotFound()
|
ctx.NotFound()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -393,17 +391,16 @@ func DeleteRelease(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
|
|
||||||
id := ctx.ParamsInt64(":id")
|
id := ctx.ParamsInt64(":id")
|
||||||
rel, err := repo_model.GetReleaseByID(ctx, id)
|
rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id)
|
||||||
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
|
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
|
ctx.Error(http.StatusInternalServerError, "GetReleaseForRepoByID", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil && repo_model.IsErrReleaseNotExist(err) ||
|
if err != nil && repo_model.IsErrReleaseNotExist(err) || rel.IsTag {
|
||||||
rel.IsTag || rel.RepoID != ctx.Repo.Repository.ID {
|
|
||||||
ctx.NotFound()
|
ctx.NotFound()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := release_service.DeleteReleaseByID(ctx, id, ctx.Doer, false); err != nil {
|
if err := release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, false); err != nil {
|
||||||
if models.IsErrProtectedTagName(err) {
|
if models.IsErrProtectedTagName(err) {
|
||||||
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
|
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
|
||||||
return
|
return
|
||||||
|
|
|
@ -17,6 +17,23 @@ import (
|
||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func checkReleaseMatchRepo(ctx *context.APIContext, releaseID int64) bool {
|
||||||
|
release, err := repo_model.GetReleaseByID(ctx, releaseID)
|
||||||
|
if err != nil {
|
||||||
|
if repo_model.IsErrReleaseNotExist(err) {
|
||||||
|
ctx.NotFound()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if release.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
ctx.NotFound()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// GetReleaseAttachment gets a single attachment of the release
|
// GetReleaseAttachment gets a single attachment of the release
|
||||||
func GetReleaseAttachment(ctx *context.APIContext) {
|
func GetReleaseAttachment(ctx *context.APIContext) {
|
||||||
// swagger:operation GET /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id} repository repoGetReleaseAttachment
|
// swagger:operation GET /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id} repository repoGetReleaseAttachment
|
||||||
|
@ -54,6 +71,10 @@ func GetReleaseAttachment(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
releaseID := ctx.ParamsInt64(":id")
|
releaseID := ctx.ParamsInt64(":id")
|
||||||
|
if !checkReleaseMatchRepo(ctx, releaseID) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
attachID := ctx.ParamsInt64(":attachment_id")
|
attachID := ctx.ParamsInt64(":attachment_id")
|
||||||
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -176,13 +197,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
|
||||||
|
|
||||||
// Check if release exists an load release
|
// Check if release exists an load release
|
||||||
releaseID := ctx.ParamsInt64(":id")
|
releaseID := ctx.ParamsInt64(":id")
|
||||||
release, err := repo_model.GetReleaseByID(ctx, releaseID)
|
if !checkReleaseMatchRepo(ctx, releaseID) {
|
||||||
if err != nil {
|
|
||||||
if repo_model.IsErrReleaseNotExist(err) {
|
|
||||||
ctx.NotFound()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +218,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
|
||||||
attach, err := attachment.UploadAttachment(ctx, file, setting.Repository.Release.AllowedTypes, header.Size, &repo_model.Attachment{
|
attach, err := attachment.UploadAttachment(ctx, file, setting.Repository.Release.AllowedTypes, header.Size, &repo_model.Attachment{
|
||||||
Name: filename,
|
Name: filename,
|
||||||
UploaderID: ctx.Doer.ID,
|
UploaderID: ctx.Doer.ID,
|
||||||
RepoID: release.RepoID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
ReleaseID: releaseID,
|
ReleaseID: releaseID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -264,6 +279,10 @@ func EditReleaseAttachment(ctx *context.APIContext) {
|
||||||
|
|
||||||
// Check if release exists an load release
|
// Check if release exists an load release
|
||||||
releaseID := ctx.ParamsInt64(":id")
|
releaseID := ctx.ParamsInt64(":id")
|
||||||
|
if !checkReleaseMatchRepo(ctx, releaseID) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
attachID := ctx.ParamsInt64(":attachment_id")
|
attachID := ctx.ParamsInt64(":attachment_id")
|
||||||
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -328,6 +347,10 @@ func DeleteReleaseAttachment(ctx *context.APIContext) {
|
||||||
|
|
||||||
// Check if release exists an load release
|
// Check if release exists an load release
|
||||||
releaseID := ctx.ParamsInt64(":id")
|
releaseID := ctx.ParamsInt64(":id")
|
||||||
|
if !checkReleaseMatchRepo(ctx, releaseID) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
attachID := ctx.ParamsInt64(":attachment_id")
|
attachID := ctx.ParamsInt64(":attachment_id")
|
||||||
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -112,7 +112,7 @@ func DeleteReleaseByTag(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = releaseservice.DeleteReleaseByID(ctx, release.ID, ctx.Doer, false); err != nil {
|
if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, release, ctx.Doer, false); err != nil {
|
||||||
if models.IsErrProtectedTagName(err) {
|
if models.IsErrProtectedTagName(err) {
|
||||||
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
|
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
|
||||||
return
|
return
|
||||||
|
|
|
@ -272,7 +272,7 @@ func DeleteTag(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = releaseservice.DeleteReleaseByID(ctx, tag.ID, ctx.Doer, true); err != nil {
|
if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, tag, ctx.Doer, true); err != nil {
|
||||||
if models.IsErrProtectedTagName(err) {
|
if models.IsErrProtectedTagName(err) {
|
||||||
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
|
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
|
||||||
return
|
return
|
||||||
|
|
|
@ -342,6 +342,10 @@ func GetOauth2Application(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if app.UID != ctx.Doer.ID {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
app.ClientSecret = ""
|
app.ClientSecret = ""
|
||||||
|
|
||||||
|
|
|
@ -112,7 +112,7 @@ func GetGPGKey(ctx *context.APIContext) {
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
key, err := asymkey_model.GetGPGKeyByID(ctx, ctx.ParamsInt64(":id"))
|
key, err := asymkey_model.GetGPGKeyForUserByID(ctx, ctx.Doer.ID, ctx.ParamsInt64(":id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if asymkey_model.IsErrGPGKeyNotExist(err) {
|
if asymkey_model.IsErrGPGKeyNotExist(err) {
|
||||||
ctx.NotFound()
|
ctx.NotFound()
|
||||||
|
|
|
@ -62,6 +62,11 @@ func GetHook(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !ctx.Doer.IsAdmin && hook.OwnerID != ctx.Doer.ID {
|
||||||
|
ctx.NotFound()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
apiHook, err := webhook_service.ToHook(ctx.Doer.HomeLink(), hook)
|
apiHook, err := webhook_service.ToHook(ctx.Doer.HomeLink(), hook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
|
|
|
@ -3106,6 +3106,11 @@ func UpdateCommentContent(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if comment.Issue.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
|
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
|
||||||
ctx.Error(http.StatusForbidden)
|
ctx.Error(http.StatusForbidden)
|
||||||
return
|
return
|
||||||
|
@ -3172,6 +3177,11 @@ func DeleteComment(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if comment.Issue.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
|
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
|
||||||
ctx.Error(http.StatusForbidden)
|
ctx.Error(http.StatusForbidden)
|
||||||
return
|
return
|
||||||
|
@ -3298,6 +3308,11 @@ func ChangeCommentReaction(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if comment.Issue.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull)) {
|
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull)) {
|
||||||
if log.IsTrace() {
|
if log.IsTrace() {
|
||||||
if ctx.IsSigned {
|
if ctx.IsSigned {
|
||||||
|
@ -3441,6 +3456,21 @@ func GetCommentAttachments(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := comment.LoadIssue(ctx); err != nil {
|
||||||
|
ctx.NotFoundOrServerError("LoadIssue", issues_model.IsErrIssueNotExist, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if comment.Issue.RepoID != ctx.Repo.Repository.ID {
|
||||||
|
ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.Repo.Permission.CanReadIssuesOrPulls(comment.Issue.IsPull) {
|
||||||
|
ctx.NotFound("CanReadIssuesOrPulls", issues_model.ErrCommentNotExist{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !comment.Type.HasAttachmentSupport() {
|
if !comment.Type.HasAttachmentSupport() {
|
||||||
ctx.ServerError("GetCommentAttachments", fmt.Errorf("comment type %v does not support attachments", comment.Type))
|
ctx.ServerError("GetCommentAttachments", fmt.Errorf("comment type %v does not support attachments", comment.Type))
|
||||||
return
|
return
|
||||||
|
|
|
@ -122,7 +122,7 @@ func GetContentHistoryDetail(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
historyID := ctx.FormInt64("history_id")
|
historyID := ctx.FormInt64("history_id")
|
||||||
history, prevHistory, err := issues_model.GetIssueContentHistoryAndPrev(ctx, historyID)
|
history, prevHistory, err := issues_model.GetIssueContentHistoryAndPrev(ctx, issue.ID, historyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.JSON(http.StatusNotFound, map[string]any{
|
ctx.JSON(http.StatusNotFound, map[string]any{
|
||||||
"message": "Can not find the content history",
|
"message": "Can not find the content history",
|
||||||
|
|
|
@ -468,7 +468,7 @@ func AddBoardToProjectPost(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id"))
|
project, err := project_model.GetProjectForRepoByID(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if project_model.IsErrProjectNotExist(err) {
|
if project_model.IsErrProjectNotExist(err) {
|
||||||
ctx.NotFound("", nil)
|
ctx.NotFound("", nil)
|
||||||
|
|
|
@ -616,7 +616,27 @@ func DeleteTag(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteReleaseOrTag(ctx *context.Context, isDelTag bool) {
|
func deleteReleaseOrTag(ctx *context.Context, isDelTag bool) {
|
||||||
if err := releaseservice.DeleteReleaseByID(ctx, ctx.FormInt64("id"), ctx.Doer, isDelTag); err != nil {
|
redirect := func() {
|
||||||
|
if isDelTag {
|
||||||
|
ctx.JSONRedirect(ctx.Repo.RepoLink + "/tags")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSONRedirect(ctx.Repo.RepoLink + "/releases")
|
||||||
|
}
|
||||||
|
|
||||||
|
rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, ctx.FormInt64("id"))
|
||||||
|
if err != nil {
|
||||||
|
if repo_model.IsErrReleaseNotExist(err) {
|
||||||
|
ctx.NotFound("GetReleaseForRepoByID", err)
|
||||||
|
} else {
|
||||||
|
ctx.Flash.Error("DeleteReleaseByID: " + err.Error())
|
||||||
|
redirect()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, isDelTag); err != nil {
|
||||||
if models.IsErrProtectedTagName(err) {
|
if models.IsErrProtectedTagName(err) {
|
||||||
ctx.Flash.Error(ctx.Tr("repo.release.tag_name_protected"))
|
ctx.Flash.Error(ctx.Tr("repo.release.tag_name_protected"))
|
||||||
} else {
|
} else {
|
||||||
|
@ -630,10 +650,5 @@ func deleteReleaseOrTag(ctx *context.Context, isDelTag bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if isDelTag {
|
redirect()
|
||||||
ctx.JSONRedirect(ctx.Repo.RepoLink + "/tags")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.JSONRedirect(ctx.Repo.RepoLink + "/releases")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -301,17 +301,7 @@ func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repo
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteReleaseByID deletes a release and corresponding Git tag by given ID.
|
// DeleteReleaseByID deletes a release and corresponding Git tag by given ID.
|
||||||
func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, delTag bool) error {
|
func DeleteReleaseByID(ctx context.Context, repo *repo_model.Repository, rel *repo_model.Release, doer *user_model.User, delTag bool) error {
|
||||||
rel, err := repo_model.GetReleaseByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("GetReleaseByID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
repo, err := repo_model.GetRepositoryByID(ctx, rel.RepoID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("GetRepositoryByID: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if delTag {
|
if delTag {
|
||||||
protectedTags, err := git_model.GetProtectedTags(ctx, rel.RepoID)
|
protectedTags, err := git_model.GetProtectedTags(ctx, rel.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -344,19 +334,19 @@ func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, del
|
||||||
}, repository.NewPushCommits())
|
}, repository.NewPushCommits())
|
||||||
notify_service.DeleteRef(ctx, doer, repo, refName)
|
notify_service.DeleteRef(ctx, doer, repo, refName)
|
||||||
|
|
||||||
if err := repo_model.DeleteReleaseByID(ctx, id); err != nil {
|
if err := repo_model.DeleteReleaseByID(ctx, rel.ID); err != nil {
|
||||||
return fmt.Errorf("DeleteReleaseByID: %w", err)
|
return fmt.Errorf("DeleteReleaseByID: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rel.IsTag = true
|
rel.IsTag = true
|
||||||
|
|
||||||
if err = repo_model.UpdateRelease(ctx, rel); err != nil {
|
if err := repo_model.UpdateRelease(ctx, rel); err != nil {
|
||||||
return fmt.Errorf("Update: %w", err)
|
return fmt.Errorf("Update: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rel.Repo = repo
|
rel.Repo = repo
|
||||||
if err = rel.LoadAttributes(ctx); err != nil {
|
if err := rel.LoadAttributes(ctx); err != nil {
|
||||||
return fmt.Errorf("LoadAttributes: %w", err)
|
return fmt.Errorf("LoadAttributes: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,14 @@ func TestAPIGetCommentAttachment(t *testing.T) {
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID})
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID})
|
||||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
t.Run("UnrelatedCommentID", func(t *testing.T) {
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||||
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
|
||||||
|
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d/assets/%d?token=%s", repoOwner.Name, repo.Name, comment.ID, attachment.ID, token)
|
||||||
|
MakeRequest(t, req, http.StatusNotFound)
|
||||||
|
})
|
||||||
|
|
||||||
session := loginUser(t, repoOwner.Name)
|
session := loginUser(t, repoOwner.Name)
|
||||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadIssue)
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadIssue)
|
||||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d/assets/%d?token=%s", repoOwner.Name, repo.Name, comment.ID, attachment.ID, token)
|
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d/assets/%d?token=%s", repoOwner.Name, repo.Name, comment.ID, attachment.ID, token)
|
||||||
|
|
|
@ -177,12 +177,25 @@ func TestAPIEditComment(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
const newCommentBody = "This is the new comment body"
|
const newCommentBody = "This is the new comment body"
|
||||||
|
|
||||||
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 8},
|
||||||
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
t.Run("UnrelatedCommentID", func(t *testing.T) {
|
||||||
|
// Using the ID of a comment that does not belong to the repository must fail
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
MakeRequest(t, req, http.StatusNotFound)
|
||||||
|
})
|
||||||
|
|
||||||
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
|
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
|
||||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
||||||
repoOwner.Name, repo.Name, comment.ID, token)
|
repoOwner.Name, repo.Name, comment.ID, token)
|
||||||
|
@ -201,12 +214,22 @@ func TestAPIEditComment(t *testing.T) {
|
||||||
func TestAPIDeleteComment(t *testing.T) {
|
func TestAPIDeleteComment(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 8},
|
||||||
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
unittest.Cond("type = ?", issues_model.CommentTypeComment))
|
||||||
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
|
||||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
|
||||||
|
|
||||||
|
t.Run("UnrelatedCommentID", func(t *testing.T) {
|
||||||
|
// Using the ID of a comment that does not belong to the repository must fail
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||||
|
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.StatusNotFound)
|
||||||
|
})
|
||||||
|
|
||||||
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
|
token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
|
||||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
||||||
repoOwner.Name, repo.Name, comment.ID, token)
|
repoOwner.Name, repo.Name, comment.ID, token)
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
@ -107,6 +108,26 @@ func TestAPICommentReactions(t *testing.T) {
|
||||||
})
|
})
|
||||||
MakeRequest(t, req, http.StatusOK)
|
MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
t.Run("UnrelatedCommentID", func(t *testing.T) {
|
||||||
|
// Using the ID of a comment that does not belong to the repository must fail
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||||
|
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/reactions?token=%s",
|
||||||
|
repoOwner.Name, repo.Name, comment.ID, token)
|
||||||
|
req = NewRequestWithJSON(t, "POST", urlStr, &api.EditReactionOption{
|
||||||
|
Reaction: "+1",
|
||||||
|
})
|
||||||
|
MakeRequest(t, req, http.StatusNotFound)
|
||||||
|
req = NewRequestWithJSON(t, "DELETE", urlStr, &api.EditReactionOption{
|
||||||
|
Reaction: "+1",
|
||||||
|
})
|
||||||
|
MakeRequest(t, req, http.StatusNotFound)
|
||||||
|
|
||||||
|
req = NewRequestf(t, "GET", urlStr)
|
||||||
|
MakeRequest(t, req, http.StatusNotFound)
|
||||||
|
})
|
||||||
|
|
||||||
// Add allowed reaction
|
// Add allowed reaction
|
||||||
req = NewRequestWithJSON(t, "POST", urlStr, &api.EditReactionOption{
|
req = NewRequestWithJSON(t, "POST", urlStr, &api.EditReactionOption{
|
||||||
Reaction: "+1",
|
Reaction: "+1",
|
||||||
|
|
|
@ -72,6 +72,17 @@ func TestCreateReadOnlyDeployKey(t *testing.T) {
|
||||||
Content: rawKeyBody.Key,
|
Content: rawKeyBody.Key,
|
||||||
Mode: perm.AccessModeRead,
|
Mode: perm.AccessModeRead,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Using the ID of a key that does not belong to the repository must fail
|
||||||
|
{
|
||||||
|
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/keys/%d?token=%s", repoOwner.Name, repo.Name, newDeployKey.ID, token))
|
||||||
|
MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
session5 := loginUser(t, "user5")
|
||||||
|
token5 := getTokenForLoggedInUser(t, session5, auth_model.AccessTokenScopeWriteRepository)
|
||||||
|
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/user5/repo4/keys/%d?token=%s", newDeployKey.ID, token5))
|
||||||
|
MakeRequest(t, req, http.StatusNotFound)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateReadWriteDeployKey(t *testing.T) {
|
func TestCreateReadWriteDeployKey(t *testing.T) {
|
||||||
|
|
|
@ -34,6 +34,6 @@ func TestNodeinfo(t *testing.T) {
|
||||||
assert.Equal(t, "gitea", nodeinfo.Software.Name)
|
assert.Equal(t, "gitea", nodeinfo.Software.Name)
|
||||||
assert.Equal(t, 25, nodeinfo.Usage.Users.Total)
|
assert.Equal(t, 25, nodeinfo.Usage.Users.Total)
|
||||||
assert.Equal(t, 20, nodeinfo.Usage.LocalPosts)
|
assert.Equal(t, 20, nodeinfo.Usage.LocalPosts)
|
||||||
assert.Equal(t, 2, nodeinfo.Usage.LocalComments)
|
assert.Equal(t, 3, nodeinfo.Usage.LocalComments)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,6 +206,56 @@ func TestIssueCommentClose(t *testing.T) {
|
||||||
assert.Equal(t, "Description", val)
|
assert.Equal(t, "Description", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIssueCommentDelete(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
issueURL := testNewIssue(t, session, "user2", "repo1", "Title", "Description")
|
||||||
|
comment1 := "Test comment 1"
|
||||||
|
commentID := testIssueAddComment(t, session, issueURL, comment1, "")
|
||||||
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: commentID})
|
||||||
|
assert.Equal(t, comment1, comment.Content)
|
||||||
|
|
||||||
|
// Using the ID of a comment that does not belong to the repository must fail
|
||||||
|
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d/delete", "user5", "repo4", commentID), map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, issueURL),
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusNotFound)
|
||||||
|
req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d/delete", "user2", "repo1", commentID), map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, issueURL),
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
unittest.AssertNotExistsBean(t, &issues_model.Comment{ID: commentID})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIssueCommentUpdate(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
issueURL := testNewIssue(t, session, "user2", "repo1", "Title", "Description")
|
||||||
|
comment1 := "Test comment 1"
|
||||||
|
commentID := testIssueAddComment(t, session, issueURL, comment1, "")
|
||||||
|
|
||||||
|
comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: commentID})
|
||||||
|
assert.Equal(t, comment1, comment.Content)
|
||||||
|
|
||||||
|
modifiedContent := comment.Content + "MODIFIED"
|
||||||
|
|
||||||
|
// Using the ID of a comment that does not belong to the repository must fail
|
||||||
|
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user5", "repo4", commentID), map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, issueURL),
|
||||||
|
"content": modifiedContent,
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusNotFound)
|
||||||
|
|
||||||
|
req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{
|
||||||
|
"_csrf": GetCSRF(t, session, issueURL),
|
||||||
|
"content": modifiedContent,
|
||||||
|
})
|
||||||
|
session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
comment = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: commentID})
|
||||||
|
assert.Equal(t, modifiedContent, comment.Content)
|
||||||
|
}
|
||||||
|
|
||||||
func TestIssueReaction(t *testing.T) {
|
func TestIssueReaction(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user2")
|
||||||
|
|
|
@ -88,7 +88,7 @@ func TestMirrorPull(t *testing.T) {
|
||||||
|
|
||||||
release, err := repo_model.GetRelease(db.DefaultContext, repo.ID, "v0.2")
|
release, err := repo_model.GetRelease(db.DefaultContext, repo.ID, "v0.2")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, release_service.DeleteReleaseByID(ctx, release.ID, user, true))
|
assert.NoError(t, release_service.DeleteReleaseByID(ctx, repo, release, user, true))
|
||||||
|
|
||||||
ok = mirror_service.SyncPullMirror(ctx, mirror.ID)
|
ok = mirror_service.SyncPullMirror(ctx, mirror.ID)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
|
|
Loading…
Add table
Reference in a new issue