2023-07-20 15:18:52 +08:00
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package issues
import (
"context"
"code.gitea.io/gitea/models/db"
2024-08-05 18:59:53 +08:00
organization_model "code.gitea.io/gitea/models/organization"
2023-07-20 15:18:52 +08:00
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
2024-03-02 23:42:31 +08:00
"code.gitea.io/gitea/modules/optional"
2023-07-20 15:18:52 +08:00
"xorm.io/builder"
)
type ReviewList [ ] * Review
// LoadReviewers loads reviewers
func ( reviews ReviewList ) LoadReviewers ( ctx context . Context ) error {
2024-02-15 02:19:57 +08:00
reviewerIDs := make ( [ ] int64 , len ( reviews ) )
2023-07-20 15:18:52 +08:00
for i := 0 ; i < len ( reviews ) ; i ++ {
2024-02-15 02:19:57 +08:00
reviewerIDs [ i ] = reviews [ i ] . ReviewerID
2023-07-20 15:18:52 +08:00
}
2024-02-15 02:19:57 +08:00
reviewers , err := user_model . GetPossibleUserByIDs ( ctx , reviewerIDs )
2023-07-20 15:18:52 +08:00
if err != nil {
return err
}
userMap := make ( map [ int64 ] * user_model . User , len ( reviewers ) )
for _ , reviewer := range reviewers {
userMap [ reviewer . ID ] = reviewer
}
for _ , review := range reviews {
review . Reviewer = userMap [ review . ReviewerID ]
}
return nil
}
2024-08-05 18:59:53 +08:00
// LoadReviewersTeams loads reviewers teams
func ( reviews ReviewList ) LoadReviewersTeams ( ctx context . Context ) error {
reviewersTeamsIDs := make ( [ ] int64 , 0 )
for _ , review := range reviews {
if review . ReviewerTeamID != 0 {
reviewersTeamsIDs = append ( reviewersTeamsIDs , review . ReviewerTeamID )
}
}
teamsMap := make ( map [ int64 ] * organization_model . Team , 0 )
for _ , teamID := range reviewersTeamsIDs {
team , err := organization_model . GetTeamByID ( ctx , teamID )
if err != nil {
return err
}
teamsMap [ teamID ] = team
}
for _ , review := range reviews {
if review . ReviewerTeamID != 0 {
review . ReviewerTeam = teamsMap [ review . ReviewerTeamID ]
}
}
return nil
}
2023-07-20 15:18:52 +08:00
func ( reviews ReviewList ) LoadIssues ( ctx context . Context ) error {
2024-04-09 20:27:30 +08:00
issueIDs := container . FilterSlice ( reviews , func ( review * Review ) ( int64 , bool ) {
return review . IssueID , true
} )
2023-07-20 15:18:52 +08:00
2024-04-09 20:27:30 +08:00
issues , err := GetIssuesByIDs ( ctx , issueIDs )
2023-07-20 15:18:52 +08:00
if err != nil {
return err
}
if _ , err := issues . LoadRepositories ( ctx ) ; err != nil {
return err
}
issueMap := make ( map [ int64 ] * Issue , len ( issues ) )
for _ , issue := range issues {
issueMap [ issue . ID ] = issue
}
for _ , review := range reviews {
review . Issue = issueMap [ review . IssueID ]
}
return nil
}
// FindReviewOptions represent possible filters to find reviews
type FindReviewOptions struct {
db . ListOptions
2024-10-01 09:58:55 +08:00
Types [ ] ReviewType
2023-07-20 15:18:52 +08:00
IssueID int64
ReviewerID int64
OfficialOnly bool
2024-03-02 23:42:31 +08:00
Dismissed optional . Option [ bool ]
2023-07-20 15:18:52 +08:00
}
func ( opts * FindReviewOptions ) toCond ( ) builder . Cond {
cond := builder . NewCond ( )
if opts . IssueID > 0 {
cond = cond . And ( builder . Eq { "issue_id" : opts . IssueID } )
}
if opts . ReviewerID > 0 {
cond = cond . And ( builder . Eq { "reviewer_id" : opts . ReviewerID } )
}
2024-10-01 09:58:55 +08:00
if len ( opts . Types ) > 0 {
cond = cond . And ( builder . In ( "type" , opts . Types ) )
2023-07-20 15:18:52 +08:00
}
if opts . OfficialOnly {
cond = cond . And ( builder . Eq { "official" : true } )
}
2024-03-02 23:42:31 +08:00
if opts . Dismissed . Has ( ) {
cond = cond . And ( builder . Eq { "dismissed" : opts . Dismissed . Value ( ) } )
2023-07-20 15:18:52 +08:00
}
return cond
}
// FindReviews returns reviews passing FindReviewOptions
func FindReviews ( ctx context . Context , opts FindReviewOptions ) ( ReviewList , error ) {
reviews := make ( [ ] * Review , 0 , 10 )
sess := db . GetEngine ( ctx ) . Where ( opts . toCond ( ) )
if opts . Page > 0 && ! opts . IsListAll ( ) {
sess = db . SetSessionPagination ( sess , & opts )
}
return reviews , sess .
Asc ( "created_unix" ) .
Asc ( "id" ) .
Find ( & reviews )
}
// FindLatestReviews returns only latest reviews per user, passing FindReviewOptions
func FindLatestReviews ( ctx context . Context , opts FindReviewOptions ) ( ReviewList , error ) {
reviews := make ( [ ] * Review , 0 , 10 )
cond := opts . toCond ( )
sess := db . GetEngine ( ctx ) . Where ( cond )
if opts . Page > 0 {
sess = db . SetSessionPagination ( sess , & opts )
}
sess . In ( "id" , builder .
2023-07-29 03:18:12 +08:00
Select ( "max(id)" ) .
2023-07-20 15:18:52 +08:00
From ( "review" ) .
Where ( cond ) .
GroupBy ( "reviewer_id" ) )
return reviews , sess .
Asc ( "created_unix" ) .
Asc ( "id" ) .
Find ( & reviews )
}
// CountReviews returns count of reviews passing FindReviewOptions
2023-09-25 21:17:37 +08:00
func CountReviews ( ctx context . Context , opts FindReviewOptions ) ( int64 , error ) {
return db . GetEngine ( ctx ) . Where ( opts . toCond ( ) ) . Count ( & Review { } )
2023-07-20 15:18:52 +08:00
}
// GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request
2023-09-25 21:17:37 +08:00
func GetReviewersFromOriginalAuthorsByIssueID ( ctx context . Context , issueID int64 ) ( ReviewList , error ) {
2023-07-20 15:18:52 +08:00
reviews := make ( [ ] * Review , 0 , 10 )
// Get latest review of each reviewer, sorted in order they were made
2023-09-25 21:17:37 +08:00
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" ,
2023-07-20 15:18:52 +08:00
issueID , ReviewTypeApprove , ReviewTypeReject , ReviewTypeRequest ) .
Find ( & reviews ) ; err != nil {
return nil , err
}
return reviews , nil
}
// GetReviewsByIssueID gets the latest review of each reviewer for a pull request
2023-09-25 21:17:37 +08:00
func GetReviewsByIssueID ( ctx context . Context , issueID int64 ) ( ReviewList , error ) {
2023-07-20 15:18:52 +08:00
reviews := make ( [ ] * Review , 0 , 10 )
2023-09-25 21:17:37 +08:00
sess := db . GetEngine ( ctx )
2023-07-20 15:18:52 +08:00
// Get latest review of each reviewer, sorted in order they were made
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" ,
issueID , ReviewTypeApprove , ReviewTypeReject , ReviewTypeRequest , false ) .
Find ( & reviews ) ; err != nil {
return nil , err
}
teamReviewRequests := make ( [ ] * Review , 0 , 5 )
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" ,
issueID ) .
Find ( & teamReviewRequests ) ; err != nil {
return nil , err
}
if len ( teamReviewRequests ) > 0 {
reviews = append ( reviews , teamReviewRequests ... )
}
return reviews , nil
}