Add reactions to issues/PR and comments (#2856)

This commit is contained in:
Lauris BH 2017-12-04 01:14:26 +02:00 committed by GitHub
parent e59adcde65
commit 5dc37b187c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 677 additions and 8 deletions

View file

@ -39,6 +39,8 @@ const (
tplMilestoneNew base.TplName = "repo/issue/milestone_new"
tplMilestoneEdit base.TplName = "repo/issue/milestone_edit"
tplReactions base.TplName = "repo/issue/view_content/reactions"
issueTemplateKey = "IssueTemplate"
)
@ -726,9 +728,8 @@ func GetActionIssue(ctx *context.Context) *models.Issue {
ctx.NotFoundOrServerError("GetIssueByIndex", models.IsErrIssueNotExist, err)
return nil
}
if issue.IsPull && !ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) ||
!issue.IsPull && !ctx.Repo.Repository.UnitEnabled(models.UnitTypeIssues) {
ctx.Handle(404, "IssueOrPullRequestUnitNotAllowed", nil)
checkIssueRights(ctx, issue)
if ctx.Written() {
return nil
}
if err = issue.LoadAttributes(); err != nil {
@ -738,6 +739,13 @@ func GetActionIssue(ctx *context.Context) *models.Issue {
return issue
}
func checkIssueRights(ctx *context.Context, issue *models.Issue) {
if issue.IsPull && !ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) ||
!issue.IsPull && !ctx.Repo.Repository.UnitEnabled(models.UnitTypeIssues) {
ctx.Handle(404, "IssueOrPullRequestUnitNotAllowed", nil)
}
}
func getActionIssues(ctx *context.Context) []*models.Issue {
commaSeparatedIssueIDs := ctx.Query("issue_ids")
if len(commaSeparatedIssueIDs) == 0 {
@ -1259,3 +1267,146 @@ func DeleteMilestone(ctx *context.Context) {
"redirect": ctx.Repo.RepoLink + "/milestones",
})
}
// ChangeIssueReaction create a reaction for issue
func ChangeIssueReaction(ctx *context.Context, form auth.ReactionForm) {
issue := GetActionIssue(ctx)
if ctx.Written() {
return
}
if ctx.HasError() {
ctx.Handle(500, "ChangeIssueReaction", errors.New(ctx.GetErrMsg()))
return
}
switch ctx.Params(":action") {
case "react":
reaction, err := models.CreateIssueReaction(ctx.User, issue, form.Content)
if err != nil {
log.Info("CreateIssueReaction: %s", err)
break
}
// Reload new reactions
issue.Reactions = nil
if err = issue.LoadAttributes(); err != nil {
log.Info("issue.LoadAttributes: %s", err)
break
}
log.Trace("Reaction for issue created: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, reaction.ID)
case "unreact":
if err := models.DeleteIssueReaction(ctx.User, issue, form.Content); err != nil {
ctx.Handle(500, "DeleteIssueReaction", err)
return
}
// Reload new reactions
issue.Reactions = nil
if err := issue.LoadAttributes(); err != nil {
log.Info("issue.LoadAttributes: %s", err)
break
}
log.Trace("Reaction for issue removed: %d/%d", ctx.Repo.Repository.ID, issue.ID)
default:
ctx.Handle(404, fmt.Sprintf("Unknown action %s", ctx.Params(":action")), nil)
return
}
if len(issue.Reactions) == 0 {
ctx.JSON(200, map[string]interface{}{
"empty": true,
"html": "",
})
return
}
html, err := ctx.HTMLString(string(tplReactions), map[string]interface{}{
"ctx": ctx.Data,
"ActionURL": fmt.Sprintf("%s/issues/%d/reactions", ctx.Repo.RepoLink, issue.Index),
"Reactions": issue.Reactions.GroupByType(),
})
if err != nil {
ctx.Handle(500, "ChangeIssueReaction.HTMLString", err)
return
}
ctx.JSON(200, map[string]interface{}{
"html": html,
})
}
// ChangeCommentReaction create a reaction for comment
func ChangeCommentReaction(ctx *context.Context, form auth.ReactionForm) {
comment, err := models.GetCommentByID(ctx.ParamsInt64(":id"))
if err != nil {
ctx.NotFoundOrServerError("GetCommentByID", models.IsErrCommentNotExist, err)
return
}
issue, err := models.GetIssueByID(comment.IssueID)
checkIssueRights(ctx, issue)
if ctx.Written() {
return
}
if ctx.HasError() {
ctx.Handle(500, "ChangeCommentReaction", errors.New(ctx.GetErrMsg()))
return
}
switch ctx.Params(":action") {
case "react":
reaction, err := models.CreateCommentReaction(ctx.User, issue, comment, form.Content)
if err != nil {
log.Info("CreateCommentReaction: %s", err)
break
}
// Reload new reactions
comment.Reactions = nil
if err = comment.LoadReactions(); err != nil {
log.Info("comment.LoadReactions: %s", err)
break
}
log.Trace("Reaction for comment created: %d/%d/%d/%d", ctx.Repo.Repository.ID, issue.ID, comment.ID, reaction.ID)
case "unreact":
if err := models.DeleteCommentReaction(ctx.User, issue, comment, form.Content); err != nil {
ctx.Handle(500, "DeleteCommentReaction", err)
return
}
// Reload new reactions
comment.Reactions = nil
if err = comment.LoadReactions(); err != nil {
log.Info("comment.LoadReactions: %s", err)
break
}
log.Trace("Reaction for comment removed: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, comment.ID)
default:
ctx.Handle(404, fmt.Sprintf("Unknown action %s", ctx.Params(":action")), nil)
return
}
if len(comment.Reactions) == 0 {
ctx.JSON(200, map[string]interface{}{
"empty": true,
"html": "",
})
return
}
html, err := ctx.HTMLString(string(tplReactions), map[string]interface{}{
"ctx": ctx.Data,
"ActionURL": fmt.Sprintf("%s/comments/%d/reactions", ctx.Repo.RepoLink, comment.ID),
"Reactions": comment.Reactions.GroupByType(),
})
if err != nil {
ctx.Handle(500, "ChangeCommentReaction.HTMLString", err)
return
}
ctx.JSON(200, map[string]interface{}{
"html": html,
})
}

View file

@ -495,6 +495,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/cancel", repo.CancelStopwatch)
})
})
m.Post("/reactions/:action", bindIgnErr(auth.ReactionForm{}), repo.ChangeIssueReaction)
})
m.Post("/labels", reqRepoWriter, repo.UpdateIssueLabel)
@ -505,6 +506,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/comments/:id", func() {
m.Post("", repo.UpdateCommentContent)
m.Post("/delete", repo.DeleteComment)
m.Post("/reactions/:action", bindIgnErr(auth.ReactionForm{}), repo.ChangeCommentReaction)
}, context.CheckAnyUnit(models.UnitTypeIssues, models.UnitTypePullRequests))
m.Group("/labels", func() {
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)