func Comment(ctx *middleware.Context) { send := func(status int, data interface{}, err error) { if err != nil { log.Error(4, "issue.Comment(?): %s", err) ctx.JSON(status, map[string]interface{}{ "ok": false, "status": status, "error": err.Error(), }) } else { ctx.JSON(status, map[string]interface{}{ "ok": true, "status": status, "data": data, }) } } index := com.StrTo(ctx.Query("issueIndex")).MustInt64() if index == 0 { ctx.Error(404) return } issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index) if err != nil { if err == models.ErrIssueNotExist { send(404, nil, err) } else { send(200, nil, err) } return } // Check if issue owner changes the status of issue. var newStatus string if ctx.Repo.IsOwner() || issue.PosterId == ctx.User.Id { newStatus = ctx.Query("change_status") } if len(newStatus) > 0 { if (strings.Contains(newStatus, "Reopen") && issue.IsClosed) || (strings.Contains(newStatus, "Close") && !issue.IsClosed) { issue.IsClosed = !issue.IsClosed if err = models.UpdateIssue(issue); err != nil { send(500, nil, err) return } else if err = models.UpdateIssueUserPairsByStatus(issue.ID, issue.IsClosed); err != nil { send(500, nil, err) return } if err = issue.GetLabels(); err != nil { send(500, nil, err) return } for _, label := range issue.Labels { if issue.IsClosed { label.NumClosedIssues++ } else { label.NumClosedIssues-- } if err = models.UpdateLabel(label); err != nil { send(500, nil, err) return } } // Change open/closed issue counter for the associated milestone if issue.MilestoneId > 0 { if err = models.ChangeMilestoneIssueStats(issue); err != nil { send(500, nil, err) } } cmtType := models.COMMENT_TYPE_CLOSE if !issue.IsClosed { cmtType = models.COMMENT_TYPE_REOPEN } if _, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.ID, 0, 0, cmtType, "", nil); err != nil { send(200, nil, err) return } log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.ID, !issue.IsClosed) } } var comment *models.Comment var ms []string content := ctx.Query("content") // Fix #321. Allow empty comments, as long as we have attachments. if len(content) > 0 || len(ctx.Req.MultipartForm.File["attachments"]) > 0 { switch ctx.Params(":action") { case "new": if comment, err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.ID, 0, 0, models.COMMENT_TYPE_COMMENT, content, nil); err != nil { send(500, nil, err) return } // Update mentions. ms = base.MentionPattern.FindAllString(issue.Content, -1) if len(ms) > 0 { for i := range ms { ms[i] = ms[i][1:] } if err := models.UpdateMentions(ms, issue.ID); err != nil { send(500, nil, err) return } } log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.ID) default: ctx.Handle(404, "issue.Comment", err) return } } if comment != nil { uploadFiles(ctx, issue.ID, comment.Id) } // Notify watchers. act := &models.Action{ ActUserID: ctx.User.Id, ActUserName: ctx.User.LowerName, ActEmail: ctx.User.Email, OpType: models.COMMENT_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]), RepoID: ctx.Repo.Repository.Id, RepoUserName: ctx.Repo.Owner.LowerName, RepoName: ctx.Repo.Repository.LowerName, IsPrivate: ctx.Repo.Repository.IsPrivate, } if err = models.NotifyWatchers(act); err != nil { send(500, nil, err) return } // Mail watchers and mentions. if setting.Service.EnableNotifyMail { issue.Content = content tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue) if err != nil { send(500, nil, err) return } tos = append(tos, ctx.User.LowerName) newTos := make([]string, 0, len(ms)) for _, m := range ms { if com.IsSliceContainsStr(tos, m) { continue } newTos = append(newTos, m) } if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil { send(500, nil, err) return } } send(200, fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, index), nil) }
func Comment(ctx *middleware.Context, params martini.Params) { index, err := base.StrTo(ctx.Query("issueIndex")).Int64() if err != nil { ctx.Handle(404, "issue.Comment(get index)", err) return } issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index) if err != nil { if err == models.ErrIssueNotExist { ctx.Handle(404, "issue.Comment", err) } else { ctx.Handle(200, "issue.Comment(get issue)", err) } return } // TODO: check collaborators // Check if issue owner changes the status of issue. var newStatus string if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id { newStatus = ctx.Query("change_status") } if len(newStatus) > 0 { if (strings.Contains(newStatus, "Reopen") && issue.IsClosed) || (strings.Contains(newStatus, "Close") && !issue.IsClosed) { issue.IsClosed = !issue.IsClosed if err = models.UpdateIssue(issue); err != nil { ctx.Handle(200, "issue.Comment(update issue status)", err) return } cmtType := models.IT_CLOSE if !issue.IsClosed { cmtType = models.IT_REOPEN } if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, ""); err != nil { ctx.Handle(200, "issue.Comment(create status change comment)", err) return } log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.Id, !issue.IsClosed) } } content := ctx.Query("content") if len(content) > 0 { switch params["action"] { case "new": if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.IT_PLAIN, content); err != nil { ctx.Handle(500, "issue.Comment(create comment)", err) return } log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id) default: ctx.Handle(404, "issue.Comment", err) return } } ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, index)) }
func Comment(ctx *middleware.Context, params martini.Params) { index, err := base.StrTo(ctx.Query("issueIndex")).Int64() if err != nil { ctx.Handle(404, "issue.Comment(get index)", err) return } issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index) if err != nil { if err == models.ErrIssueNotExist { ctx.Handle(404, "issue.Comment", err) } else { ctx.Handle(200, "issue.Comment(get issue)", err) } return } // Check if issue owner changes the status of issue. var newStatus string if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id { newStatus = ctx.Query("change_status") } if len(newStatus) > 0 { if (strings.Contains(newStatus, "Reopen") && issue.IsClosed) || (strings.Contains(newStatus, "Close") && !issue.IsClosed) { issue.IsClosed = !issue.IsClosed if err = models.UpdateIssue(issue); err != nil { ctx.Handle(500, "issue.Comment(UpdateIssue)", err) return } else if err = models.UpdateIssueUserPairsByStatus(issue.Id, issue.IsClosed); err != nil { ctx.Handle(500, "issue.Comment(UpdateIssueUserPairsByStatus)", err) return } cmtType := models.IT_CLOSE if !issue.IsClosed { cmtType = models.IT_REOPEN } if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, ""); err != nil { ctx.Handle(200, "issue.Comment(create status change comment)", err) return } log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.Id, !issue.IsClosed) } } var ms []string content := ctx.Query("content") if len(content) > 0 { switch params["action"] { case "new": if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.IT_PLAIN, content); err != nil { ctx.Handle(500, "issue.Comment(create comment)", err) return } // Update mentions. ms = base.MentionPattern.FindAllString(issue.Content, -1) if len(ms) > 0 { for i := range ms { ms[i] = ms[i][1:] } ids := models.GetUserIdsByNames(ms) if err := models.UpdateIssueUserPairsByMentions(ids, issue.Id); err != nil { ctx.Handle(500, "issue.CreateIssue(UpdateIssueUserPairsByMentions)", err) return } } log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id) default: ctx.Handle(404, "issue.Comment", err) return } } // Notify watchers. act := &models.Action{ ActUserId: ctx.User.Id, ActUserName: ctx.User.LowerName, ActEmail: ctx.User.Email, OpType: models.OP_COMMENT_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, strings.Split(content, "\n")[0]), RepoId: ctx.Repo.Repository.Id, RepoUserName: ctx.Repo.Owner.LowerName, RepoName: ctx.Repo.Repository.LowerName, } if err = models.NotifyWatchers(act); err != nil { ctx.Handle(500, "issue.CreateIssue(NotifyWatchers)", err) return } // Mail watchers and mentions. if setting.Service.EnableNotifyMail { issue.Content = content tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue) if err != nil { ctx.Handle(500, "issue.Comment(SendIssueNotifyMail)", err) return } tos = append(tos, ctx.User.LowerName) newTos := make([]string, 0, len(ms)) for _, m := range ms { if com.IsSliceContainsStr(tos, m) { continue } newTos = append(newTos, m) } if err = mailer.SendIssueMentionMail(ctx.Render, ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue, models.GetUserEmailsByNames(newTos)); err != nil { ctx.Handle(500, "issue.Comment(SendIssueMentionMail)", err) return } } ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, index)) }