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, } 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 CreateIssuePost(ctx *middleware.Context, form auth.CreateIssueForm) { send := func(status int, data interface{}, err error) { if err != nil { log.Error(4, "issue.CreateIssuePost(?): %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, }) } } var err error // Get all milestones. _, err = models.GetMilestones(ctx.Repo.Repository.Id, false) if err != nil { send(500, nil, err) return } _, err = models.GetMilestones(ctx.Repo.Repository.Id, true) if err != nil { send(500, nil, err) return } _, err = ctx.Repo.Repository.GetCollaborators() if err != nil { send(500, nil, err) return } if ctx.HasError() { send(400, nil, errors.New(ctx.Flash.ErrorMsg)) return } // Only collaborators can assign. if !ctx.Repo.IsOwner() { form.AssigneeId = 0 } issue := &models.Issue{ RepoId: ctx.Repo.Repository.Id, Index: int64(ctx.Repo.Repository.NumIssues) + 1, Name: form.IssueName, PosterId: ctx.User.Id, MilestoneId: form.MilestoneId, AssigneeId: form.AssigneeId, LabelIds: form.Labels, Content: form.Content, } if err := models.NewIssue(issue); err != nil { send(500, nil, err) return } else if err := models.NewIssueUserPairs(ctx.Repo.Repository, issue.Id, ctx.Repo.Owner.Id, ctx.User.Id, form.AssigneeId); err != nil { send(500, nil, err) return } if setting.AttachmentEnabled { uploadFiles(ctx, issue.Id, 0) } // 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 } } act := &models.Action{ ActUserID: ctx.User.Id, ActUserName: ctx.User.Name, ActEmail: ctx.User.Email, OpType: models.CREATE_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name), RepoID: ctx.Repo.Repository.Id, RepoUserName: ctx.Repo.Owner.Name, RepoName: ctx.Repo.Repository.Name, RefName: ctx.Repo.BranchName, IsPrivate: ctx.Repo.Repository.IsPrivate, } // Notify watchers. if err := models.NotifyWatchers(act); err != nil { send(500, nil, err) return } // Mail watchers and mentions. if setting.Service.EnableNotifyMail { 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 } } log.Trace("%d Issue created: %d", ctx.Repo.Repository.Id, issue.Id) send(200, fmt.Sprintf("%s/%s/%s/issues/%d", setting.AppSubUrl, ctx.Params(":username"), ctx.Params(":reponame"), issue.Index), nil) }