Files

469 lines
12 KiB
Go
Raw Permalink Normal View History

2019-12-07 23:04:19 +01:00
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
2019-12-07 23:04:19 +01:00
package repo
import (
"errors"
2019-12-20 18:07:12 +01:00
"net/http"
2019-12-07 23:04:19 +01:00
2022-03-31 17:20:39 +08:00
issues_model "code.gitea.io/gitea/models/issues"
2024-03-04 09:16:03 +01:00
user_model "code.gitea.io/gitea/models/user"
2019-12-07 23:04:19 +01:00
api "code.gitea.io/gitea/modules/structs"
2021-01-26 23:36:53 +08:00
"code.gitea.io/gitea/modules/web"
2020-01-24 19:00:29 +00:00
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/context"
2022-12-29 03:57:15 +01:00
"code.gitea.io/gitea/services/convert"
2024-03-04 09:16:03 +01:00
issue_service "code.gitea.io/gitea/services/issue"
2019-12-07 23:04:19 +01:00
)
// GetIssueCommentReactions list reactions of a comment from an issue
2019-12-07 23:04:19 +01:00
func GetIssueCommentReactions(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/issues/comments/{id}/reactions issue issueGetCommentReactions
// ---
// summary: Get a list of reactions from a comment of an issue
2019-12-07 23:04:19 +01:00
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the comment to edit
// type: integer
// format: int64
// required: true
// responses:
// "200":
// "$ref": "#/responses/ReactionList"
2019-12-20 18:07:12 +01:00
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
2024-12-24 21:47:45 +08:00
comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id"))
2019-12-07 23:04:19 +01:00
if err != nil {
if issues_model.IsErrCommentNotExist(err) {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound(err)
2019-12-07 23:04:19 +01:00
} else {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
}
return
}
if err := comment.LoadIssue(ctx); err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2023-11-26 01:21:21 +08:00
return
}
if comment.Issue.RepoID != ctx.Repo.Repository.ID {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound()
2023-11-26 01:21:21 +08:00
return
}
if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
2025-02-17 14:13:17 +08:00
ctx.APIError(http.StatusForbidden, errors.New("no permission to get reactions"))
2019-12-07 23:04:19 +01:00
return
}
reactions, _, err := issues_model.FindCommentReactions(ctx, comment.IssueID, comment.ID)
2019-12-07 23:04:19 +01:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
return
}
2022-03-31 17:20:39 +08:00
_, err = reactions.LoadUsers(ctx, ctx.Repo.Repository)
2019-12-07 23:04:19 +01:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
return
}
var result []api.Reaction
2019-12-07 23:04:19 +01:00
for _, r := range reactions {
result = append(result, api.Reaction{
User: convert.ToUser(ctx, r.User, ctx.Doer),
2019-12-07 23:04:19 +01:00
Reaction: r.Type,
Created: r.CreatedUnix.AsTime(),
})
}
2019-12-20 18:07:12 +01:00
ctx.JSON(http.StatusOK, result)
2019-12-07 23:04:19 +01:00
}
// PostIssueCommentReaction add a reaction to a comment of an issue
2021-01-26 23:36:53 +08:00
func PostIssueCommentReaction(ctx *context.APIContext) {
2019-12-07 23:04:19 +01:00
// swagger:operation POST /repos/{owner}/{repo}/issues/comments/{id}/reactions issue issuePostCommentReaction
// ---
// summary: Add a reaction to a comment of an issue
2019-12-07 23:04:19 +01:00
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the comment to edit
// type: integer
// format: int64
// required: true
// - name: content
// in: body
// schema:
// "$ref": "#/definitions/EditReactionOption"
// responses:
// "200":
// "$ref": "#/responses/Reaction"
2019-12-07 23:04:19 +01:00
// "201":
// "$ref": "#/responses/Reaction"
2019-12-20 18:07:12 +01:00
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
2021-01-26 23:36:53 +08:00
form := web.GetForm(ctx).(*api.EditReactionOption)
changeIssueCommentReaction(ctx, *form, true)
2019-12-07 23:04:19 +01:00
}
// DeleteIssueCommentReaction remove a reaction from a comment of an issue
2021-01-26 23:36:53 +08:00
func DeleteIssueCommentReaction(ctx *context.APIContext) {
2019-12-07 23:04:19 +01:00
// swagger:operation DELETE /repos/{owner}/{repo}/issues/comments/{id}/reactions issue issueDeleteCommentReaction
// ---
// summary: Remove a reaction from a comment of an issue
2019-12-07 23:04:19 +01:00
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: id
// in: path
// description: id of the comment to edit
// type: integer
// format: int64
// required: true
// - name: content
// in: body
// schema:
// "$ref": "#/definitions/EditReactionOption"
// responses:
// "204":
2019-12-07 23:04:19 +01:00
// "$ref": "#/responses/empty"
2019-12-20 18:07:12 +01:00
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
2021-01-26 23:36:53 +08:00
form := web.GetForm(ctx).(*api.EditReactionOption)
changeIssueCommentReaction(ctx, *form, false)
2019-12-07 23:04:19 +01:00
}
func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOption, isCreateType bool) {
2024-12-24 21:47:45 +08:00
comment, err := issues_model.GetCommentByID(ctx, ctx.PathParamInt64("id"))
2019-12-07 23:04:19 +01:00
if err != nil {
if issues_model.IsErrCommentNotExist(err) {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound(err)
2019-12-07 23:04:19 +01:00
} else {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
}
return
}
2023-11-26 01:21:21 +08:00
if err = comment.LoadIssue(ctx); err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2023-11-26 01:21:21 +08:00
return
}
if comment.Issue.RepoID != ctx.Repo.Repository.ID {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound()
2023-11-26 01:21:21 +08:00
return
}
if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound()
2023-11-26 01:21:21 +08:00
return
2019-12-07 23:04:19 +01:00
}
if comment.Issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull) {
2025-02-17 14:13:17 +08:00
ctx.APIError(http.StatusForbidden, errors.New("no permission to change reaction"))
2019-12-07 23:04:19 +01:00
return
}
if isCreateType {
// PostIssueCommentReaction part
2024-03-04 09:16:03 +01:00
reaction, err := issue_service.CreateCommentReaction(ctx, ctx.Doer, comment, form.Reaction)
2019-12-07 23:04:19 +01:00
if err != nil {
2024-03-04 09:16:03 +01:00
if issues_model.IsErrForbiddenIssueReaction(err) || errors.Is(err, user_model.ErrBlockedUser) {
2025-02-17 14:13:17 +08:00
ctx.APIError(http.StatusForbidden, err)
2022-03-31 17:20:39 +08:00
} else if issues_model.IsErrReactionAlreadyExist(err) {
ctx.JSON(http.StatusOK, api.Reaction{
User: convert.ToUser(ctx, ctx.Doer, ctx.Doer),
Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(),
})
2019-12-07 23:04:19 +01:00
} else {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
}
return
}
ctx.JSON(http.StatusCreated, api.Reaction{
User: convert.ToUser(ctx, ctx.Doer, ctx.Doer),
2019-12-07 23:04:19 +01:00
Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(),
})
} else {
// DeleteIssueCommentReaction part
err = issues_model.DeleteCommentReaction(ctx, ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Reaction)
2019-12-07 23:04:19 +01:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
return
}
ctx.Status(http.StatusNoContent)
2019-12-07 23:04:19 +01:00
}
}
// GetIssueReactions list reactions of an issue
2019-12-07 23:04:19 +01:00
func GetIssueReactions(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/reactions issue issueGetIssueReactions
// ---
// summary: Get a list reactions of an issue
2019-12-07 23:04:19 +01:00
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: index
// in: path
// description: index of the issue
// type: integer
// format: int64
// required: true
2020-01-24 19:00:29 +00:00
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
// description: page size of results
2020-01-24 19:00:29 +00:00
// type: integer
2019-12-07 23:04:19 +01:00
// responses:
// "200":
// "$ref": "#/responses/ReactionList"
2019-12-20 18:07:12 +01:00
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
2024-12-24 21:47:45 +08:00
issue, err := issues_model.GetIssueWithAttrsByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
2019-12-07 23:04:19 +01:00
if err != nil {
if issues_model.IsErrIssueNotExist(err) {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound()
2019-12-07 23:04:19 +01:00
} else {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
}
return
}
if !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull) {
2025-02-17 14:13:17 +08:00
ctx.APIError(http.StatusForbidden, errors.New("no permission to get reactions"))
2019-12-07 23:04:19 +01:00
return
}
reactions, count, err := issues_model.FindIssueReactions(ctx, issue.ID, utils.GetListOptions(ctx))
2019-12-07 23:04:19 +01:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
return
}
2022-03-31 17:20:39 +08:00
_, err = reactions.LoadUsers(ctx, ctx.Repo.Repository)
2019-12-07 23:04:19 +01:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
return
}
var result []api.Reaction
2019-12-07 23:04:19 +01:00
for _, r := range reactions {
result = append(result, api.Reaction{
User: convert.ToUser(ctx, r.User, ctx.Doer),
2019-12-07 23:04:19 +01:00
Reaction: r.Type,
Created: r.CreatedUnix.AsTime(),
})
}
ctx.SetTotalCountHeader(count)
2019-12-20 18:07:12 +01:00
ctx.JSON(http.StatusOK, result)
2019-12-07 23:04:19 +01:00
}
// PostIssueReaction add a reaction to an issue
2021-01-26 23:36:53 +08:00
func PostIssueReaction(ctx *context.APIContext) {
2019-12-07 23:04:19 +01:00
// swagger:operation POST /repos/{owner}/{repo}/issues/{index}/reactions issue issuePostIssueReaction
// ---
// summary: Add a reaction to an issue
2019-12-07 23:04:19 +01:00
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: index
// in: path
// description: index of the issue
// type: integer
// format: int64
// required: true
// - name: content
// in: body
// schema:
// "$ref": "#/definitions/EditReactionOption"
// responses:
// "200":
// "$ref": "#/responses/Reaction"
2019-12-07 23:04:19 +01:00
// "201":
// "$ref": "#/responses/Reaction"
2019-12-20 18:07:12 +01:00
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
2021-01-26 23:36:53 +08:00
form := web.GetForm(ctx).(*api.EditReactionOption)
changeIssueReaction(ctx, *form, true)
2019-12-07 23:04:19 +01:00
}
// DeleteIssueReaction remove a reaction from an issue
2021-01-26 23:36:53 +08:00
func DeleteIssueReaction(ctx *context.APIContext) {
2019-12-07 23:04:19 +01:00
// swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/reactions issue issueDeleteIssueReaction
// ---
// summary: Remove a reaction from an issue
2019-12-07 23:04:19 +01:00
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: owner
// in: path
// description: owner of the repo
// type: string
// required: true
// - name: repo
// in: path
// description: name of the repo
// type: string
// required: true
// - name: index
// in: path
// description: index of the issue
// type: integer
// format: int64
// required: true
// - name: content
// in: body
// schema:
// "$ref": "#/definitions/EditReactionOption"
// responses:
// "204":
2019-12-07 23:04:19 +01:00
// "$ref": "#/responses/empty"
2019-12-20 18:07:12 +01:00
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
2021-01-26 23:36:53 +08:00
form := web.GetForm(ctx).(*api.EditReactionOption)
changeIssueReaction(ctx, *form, false)
2019-12-07 23:04:19 +01:00
}
func changeIssueReaction(ctx *context.APIContext, form api.EditReactionOption, isCreateType bool) {
2024-12-24 21:47:45 +08:00
issue, err := issues_model.GetIssueWithAttrsByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index"))
2019-12-07 23:04:19 +01:00
if err != nil {
if issues_model.IsErrIssueNotExist(err) {
2025-02-17 14:13:17 +08:00
ctx.APIErrorNotFound()
2019-12-07 23:04:19 +01:00
} else {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
}
return
}
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
2025-02-17 14:13:17 +08:00
ctx.APIError(http.StatusForbidden, errors.New("no permission to change reaction"))
2019-12-07 23:04:19 +01:00
return
}
if isCreateType {
// PostIssueReaction part
2024-03-04 09:16:03 +01:00
reaction, err := issue_service.CreateIssueReaction(ctx, ctx.Doer, issue, form.Reaction)
2019-12-07 23:04:19 +01:00
if err != nil {
2024-03-04 09:16:03 +01:00
if issues_model.IsErrForbiddenIssueReaction(err) || errors.Is(err, user_model.ErrBlockedUser) {
2025-02-17 14:13:17 +08:00
ctx.APIError(http.StatusForbidden, err)
2022-03-31 17:20:39 +08:00
} else if issues_model.IsErrReactionAlreadyExist(err) {
ctx.JSON(http.StatusOK, api.Reaction{
User: convert.ToUser(ctx, ctx.Doer, ctx.Doer),
Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(),
})
2019-12-07 23:04:19 +01:00
} else {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
}
return
}
ctx.JSON(http.StatusCreated, api.Reaction{
User: convert.ToUser(ctx, ctx.Doer, ctx.Doer),
2019-12-07 23:04:19 +01:00
Reaction: reaction.Type,
Created: reaction.CreatedUnix.AsTime(),
})
} else {
// DeleteIssueReaction part
err = issues_model.DeleteIssueReaction(ctx, ctx.Doer.ID, issue.ID, form.Reaction)
2019-12-07 23:04:19 +01:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx.APIErrorInternal(err)
2019-12-07 23:04:19 +01:00
return
}
ctx.Status(http.StatusNoContent)
2019-12-07 23:04:19 +01:00
}
}