From 0f772d1bf487c372ae90a507cb304537df53f1f7 Mon Sep 17 00:00:00 2001 From: Jonas Franz Date: Thu, 10 May 2018 20:41:31 +0200 Subject: [PATCH] Simplified create and find functions for review Signed-off-by: Jonas Franz --- models/issue_comment.go | 5 ++- models/review.go | 80 +++++++++++++++++++++++++++---------- routers/repo/pull_review.go | 53 ++++++++++++++---------- 3 files changed, 95 insertions(+), 43 deletions(-) diff --git a/models/issue_comment.go b/models/issue_comment.go index 56cdc8c629..6c44e74351 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -360,6 +360,7 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err OldTitle: opts.OldTitle, NewTitle: opts.NewTitle, TreePath: opts.TreePath, + ReviewID: opts.ReviewID, } if _, err = e.Insert(comment); err != nil { return nil, err @@ -579,6 +580,7 @@ type CreateCommentOptions struct { CommitSHA string LineNum int64 TreePath string + ReviewID int64 Content string Attachments []string // UUIDs of attachments } @@ -619,7 +621,7 @@ func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content stri } // CreateCodeComment creates a plain code comment at the specified line / path -func CreateCodeComment(doer *User, repo *Repository, issue *Issue, commitSHA, content, treePath string, line int64) (*Comment, error) { +func CreateCodeComment(doer *User, repo *Repository, issue *Issue, commitSHA, content, treePath string, line, reviewID int64) (*Comment, error) { return CreateComment(&CreateCommentOptions{ Type: CommentTypeCode, Doer: doer, @@ -629,6 +631,7 @@ func CreateCodeComment(doer *User, repo *Repository, issue *Issue, commitSHA, co LineNum: line, TreePath: treePath, CommitSHA: commitSHA, + ReviewID: reviewID, }) } diff --git a/models/review.go b/models/review.go index 14580c078f..c6e223d6d5 100644 --- a/models/review.go +++ b/models/review.go @@ -4,11 +4,17 @@ package models -import "code.gitea.io/gitea/modules/util" +import ( + "code.gitea.io/gitea/modules/util" + "github.com/go-xorm/builder" +) // ReviewType defines the sort of feedback a review gives type ReviewType int +// ReviewTypeUnknown unknown review type +const ReviewTypeUnknown ReviewType = -1 + const ( // ReviewTypeApprove approves changes ReviewTypeApprove ReviewType = iota @@ -88,33 +94,65 @@ func GetReviewByID(id int64) (*Review, error) { return getReviewByID(x, id) } -func getPendingReviewByReviewerID(e Engine, reviewer *User, issue *Issue) (review *Review, err error) { - var exists bool - if exists, err = e.Table("review").Where("reviewer_id = ? and issue_id = ? and type = ?", reviewer.ID, issue.ID, ReviewTypePending). - Get(review); !exists && err == nil { - return nil, nil +// FindReviewOptions represent possible filters to find reviews +type FindReviewOptions struct { + Type ReviewType + IssueID int64 + ReviewerID int64 +} + +func (opts *FindReviewOptions) toCond() builder.Cond { + var cond = builder.NewCond() + if opts.IssueID > 0 { + cond = cond.And(builder.Eq{"issue_id": opts.IssueID}) } - return + if opts.ReviewerID > 0 { + cond = cond.And(builder.Eq{"reviewer_id": opts.ReviewerID}) + } + if opts.Type != ReviewTypeUnknown { + cond = cond.And(builder.Eq{"type": opts.Type}) + } + return cond } -// GetPendingReviewByReviewer returns the latest pending review of reviewer at PR issue -func GetPendingReviewByReviewer(reviewer *User, issue *Issue) (*Review, error) { - return getPendingReviewByReviewerID(x, reviewer, issue) +func findReviews(e Engine, opts FindReviewOptions) ([]*Review, error) { + reviews := make([]*Review, 0, 10) + sess := e.Where(opts.toCond()) + return reviews, sess. + Asc("created_unix"). + Asc("id"). + Find(&reviews) } -func createPendingReview(e Engine, reviewer *User, issue *Issue) (*Review, error) { +// FindReviews returns reviews passing FindReviewOptions +func FindReviews(opts FindReviewOptions) ([]*Review, error) { + return findReviews(x, opts) +} + +// CreateReviewOptions represent the options to create a review. Type, Issue and Reviewer are required. +type CreateReviewOptions struct { + Content string + Type ReviewType + Issue *Issue + Reviewer *User +} + +func createReview(e Engine, opts CreateReviewOptions) (*Review, error) { review := &Review{ - Type: ReviewTypePending, - Issue: issue, - IssueID: issue.ID, - Reviewer: reviewer, - ReviewerID: reviewer.ID, + Type: opts.Type, + Issue: opts.Issue, + IssueID: opts.Issue.ID, + Reviewer: opts.Reviewer, + ReviewerID: opts.Reviewer.ID, + Content: opts.Content, } - _, err := e.Insert(review) - return review, err + if _, err := e.Insert(review); err != nil { + return nil, err + } + return review, nil } -// CreatePendingReview creates an empty pending review -func CreatePendingReview(reviewer *User, issue *Issue) (*Review, error) { - return createPendingReview(x, reviewer, issue) +// CreateReview creates a new review based on opts +func CreateReview(opts CreateReviewOptions) (*Review, error) { + return createReview(x, opts) } diff --git a/routers/repo/pull_review.go b/routers/repo/pull_review.go index 8709e5ea1e..801ec79841 100644 --- a/routers/repo/pull_review.go +++ b/routers/repo/pull_review.go @@ -42,7 +42,35 @@ func CreateCodeComment(ctx *context.Context, form auth.CodeCommentForm) { if form.Side == "previous" { signedLine *= -1 } - //FIXME check if line and treepath exist + + review := new(models.Review) + if form.IsReview { + // Check if the user has already a pending review for this issue + reviews, err := models.FindReviews(models.FindReviewOptions{ + ReviewerID: ctx.User.ID, + IssueID: issue.ID, + Type: models.ReviewTypePending, + }) + if err != nil { + ctx.ServerError("CreateCodeComment", err) + return + } + if len(reviews) == 0 { + // Create a new pending review for this issue & user + if review, err = models.CreateReview(models.CreateReviewOptions{ + Type: models.ReviewTypePending, + Reviewer: ctx.User, + Issue: issue, + }); err != nil { + ctx.ServerError("CreateCodeComment", err) + return + } + } else { + review = reviews[0] + } + } + + //FIXME check if line, commit and treepath exist var err error comment, err = models.CreateCodeComment( ctx.User, @@ -52,31 +80,14 @@ func CreateCodeComment(ctx *context.Context, form auth.CodeCommentForm) { form.Content, form.TreePath, signedLine, + review.ID, ) if err != nil { ctx.ServerError("CreateCodeComment", err) return } - - if form.IsReview { - review, err := models.GetPendingReviewByReviewer(ctx.User, issue) - if err != nil { - ctx.ServerError("CreateCodeComment", err) - return - } - if review == nil { - if review, err = models.CreatePendingReview(ctx.User, issue); err != nil { - ctx.ServerError("CreateCodeComment", err) - return - } - } - comment.Review = review - comment.ReviewID = review.ID - if err = models.UpdateComment(comment); err != nil { - ctx.ServerError("CreateCodeComment", err) - return - } - } else { + // Send no notification if comment is pending + if !form.IsReview { notification.Service.NotifyIssue(issue, ctx.User.ID) }