code.gitea.io/gitea@v1.22.3/models/issues/review_list.go (about)

     1  // Copyright 2023 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package issues
     5  
     6  import (
     7  	"context"
     8  
     9  	"code.gitea.io/gitea/models/db"
    10  	user_model "code.gitea.io/gitea/models/user"
    11  	"code.gitea.io/gitea/modules/container"
    12  	"code.gitea.io/gitea/modules/optional"
    13  
    14  	"xorm.io/builder"
    15  )
    16  
    17  type ReviewList []*Review
    18  
    19  // LoadReviewers loads reviewers
    20  func (reviews ReviewList) LoadReviewers(ctx context.Context) error {
    21  	reviewerIDs := make([]int64, len(reviews))
    22  	for i := 0; i < len(reviews); i++ {
    23  		reviewerIDs[i] = reviews[i].ReviewerID
    24  	}
    25  	reviewers, err := user_model.GetPossibleUserByIDs(ctx, reviewerIDs)
    26  	if err != nil {
    27  		return err
    28  	}
    29  
    30  	userMap := make(map[int64]*user_model.User, len(reviewers))
    31  	for _, reviewer := range reviewers {
    32  		userMap[reviewer.ID] = reviewer
    33  	}
    34  	for _, review := range reviews {
    35  		review.Reviewer = userMap[review.ReviewerID]
    36  	}
    37  	return nil
    38  }
    39  
    40  func (reviews ReviewList) LoadIssues(ctx context.Context) error {
    41  	issueIDs := container.FilterSlice(reviews, func(review *Review) (int64, bool) {
    42  		return review.IssueID, true
    43  	})
    44  
    45  	issues, err := GetIssuesByIDs(ctx, issueIDs)
    46  	if err != nil {
    47  		return err
    48  	}
    49  	if _, err := issues.LoadRepositories(ctx); err != nil {
    50  		return err
    51  	}
    52  	issueMap := make(map[int64]*Issue, len(issues))
    53  	for _, issue := range issues {
    54  		issueMap[issue.ID] = issue
    55  	}
    56  
    57  	for _, review := range reviews {
    58  		review.Issue = issueMap[review.IssueID]
    59  	}
    60  	return nil
    61  }
    62  
    63  // FindReviewOptions represent possible filters to find reviews
    64  type FindReviewOptions struct {
    65  	db.ListOptions
    66  	Types        []ReviewType
    67  	IssueID      int64
    68  	ReviewerID   int64
    69  	OfficialOnly bool
    70  	Dismissed    optional.Option[bool]
    71  }
    72  
    73  func (opts *FindReviewOptions) toCond() builder.Cond {
    74  	cond := builder.NewCond()
    75  	if opts.IssueID > 0 {
    76  		cond = cond.And(builder.Eq{"issue_id": opts.IssueID})
    77  	}
    78  	if opts.ReviewerID > 0 {
    79  		cond = cond.And(builder.Eq{"reviewer_id": opts.ReviewerID})
    80  	}
    81  	if len(opts.Types) > 0 {
    82  		cond = cond.And(builder.In("type", opts.Types))
    83  	}
    84  	if opts.OfficialOnly {
    85  		cond = cond.And(builder.Eq{"official": true})
    86  	}
    87  	if opts.Dismissed.Has() {
    88  		cond = cond.And(builder.Eq{"dismissed": opts.Dismissed.Value()})
    89  	}
    90  	return cond
    91  }
    92  
    93  // FindReviews returns reviews passing FindReviewOptions
    94  func FindReviews(ctx context.Context, opts FindReviewOptions) (ReviewList, error) {
    95  	reviews := make([]*Review, 0, 10)
    96  	sess := db.GetEngine(ctx).Where(opts.toCond())
    97  	if opts.Page > 0 && !opts.IsListAll() {
    98  		sess = db.SetSessionPagination(sess, &opts)
    99  	}
   100  	return reviews, sess.
   101  		Asc("created_unix").
   102  		Asc("id").
   103  		Find(&reviews)
   104  }
   105  
   106  // FindLatestReviews returns only latest reviews per user, passing FindReviewOptions
   107  func FindLatestReviews(ctx context.Context, opts FindReviewOptions) (ReviewList, error) {
   108  	reviews := make([]*Review, 0, 10)
   109  	cond := opts.toCond()
   110  	sess := db.GetEngine(ctx).Where(cond)
   111  	if opts.Page > 0 {
   112  		sess = db.SetSessionPagination(sess, &opts)
   113  	}
   114  
   115  	sess.In("id", builder.
   116  		Select("max(id)").
   117  		From("review").
   118  		Where(cond).
   119  		GroupBy("reviewer_id"))
   120  
   121  	return reviews, sess.
   122  		Asc("created_unix").
   123  		Asc("id").
   124  		Find(&reviews)
   125  }
   126  
   127  // CountReviews returns count of reviews passing FindReviewOptions
   128  func CountReviews(ctx context.Context, opts FindReviewOptions) (int64, error) {
   129  	return db.GetEngine(ctx).Where(opts.toCond()).Count(&Review{})
   130  }
   131  
   132  // GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request
   133  func GetReviewersFromOriginalAuthorsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) {
   134  	reviews := make([]*Review, 0, 10)
   135  
   136  	// Get latest review of each reviewer, sorted in order they were made
   137  	if err := db.GetEngine(ctx).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND original_author_id <> 0 GROUP BY issue_id, original_author_id) ORDER BY review.updated_unix ASC",
   138  		issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest).
   139  		Find(&reviews); err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	return reviews, nil
   144  }
   145  
   146  // GetReviewsByIssueID gets the latest review of each reviewer for a pull request
   147  func GetReviewsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) {
   148  	reviews := make([]*Review, 0, 10)
   149  
   150  	sess := db.GetEngine(ctx)
   151  
   152  	// Get latest review of each reviewer, sorted in order they were made
   153  	if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND dismissed = ? AND original_author_id = 0 GROUP BY issue_id, reviewer_id) ORDER BY review.updated_unix ASC",
   154  		issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, false).
   155  		Find(&reviews); err != nil {
   156  		return nil, err
   157  	}
   158  
   159  	teamReviewRequests := make([]*Review, 0, 5)
   160  	if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id <> 0 AND original_author_id = 0 GROUP BY issue_id, reviewer_team_id) ORDER BY review.updated_unix ASC",
   161  		issueID).
   162  		Find(&teamReviewRequests); err != nil {
   163  		return nil, err
   164  	}
   165  
   166  	if len(teamReviewRequests) > 0 {
   167  		reviews = append(reviews, teamReviewRequests...)
   168  	}
   169  
   170  	return reviews, nil
   171  }