| 
 | 1 | +// Copyright 2024 The Gitea Authors. All rights reserved.  | 
 | 2 | +// SPDX-License-Identifier: MIT  | 
 | 3 | + | 
 | 4 | +package pull  | 
 | 5 | + | 
 | 6 | +import (  | 
 | 7 | +	"context"  | 
 | 8 | + | 
 | 9 | +	"code.gitea.io/gitea/models/db"  | 
 | 10 | +	"code.gitea.io/gitea/models/organization"  | 
 | 11 | +	"code.gitea.io/gitea/models/perm"  | 
 | 12 | +	repo_model "code.gitea.io/gitea/models/repo"  | 
 | 13 | +	"code.gitea.io/gitea/models/unit"  | 
 | 14 | +	user_model "code.gitea.io/gitea/models/user"  | 
 | 15 | +	"code.gitea.io/gitea/modules/container"  | 
 | 16 | + | 
 | 17 | +	"xorm.io/builder"  | 
 | 18 | +)  | 
 | 19 | + | 
 | 20 | +// GetReviewers get all users can be requested to review:  | 
 | 21 | +// - Poster should not be listed  | 
 | 22 | +// - For collaborator, all users that have read access or higher to the repository.  | 
 | 23 | +// - For repository under organization, users under the teams which have read permission or higher of pull request unit  | 
 | 24 | +// - Owner will be listed if it's not an organization, not the poster and not in the list of reviewers  | 
 | 25 | +func GetReviewers(ctx context.Context, repo *repo_model.Repository, doerID, posterID int64) ([]*user_model.User, error) {  | 
 | 26 | +	if err := repo.LoadOwner(ctx); err != nil {  | 
 | 27 | +		return nil, err  | 
 | 28 | +	}  | 
 | 29 | + | 
 | 30 | +	e := db.GetEngine(ctx)  | 
 | 31 | +	uniqueUserIDs := make(container.Set[int64])  | 
 | 32 | + | 
 | 33 | +	collaboratorIDs := make([]int64, 0, 10)  | 
 | 34 | +	if err := e.Table("collaboration").Where("repo_id=?", repo.ID).  | 
 | 35 | +		And("mode >= ?", perm.AccessModeRead).  | 
 | 36 | +		Select("user_id").  | 
 | 37 | +		Find(&collaboratorIDs); err != nil {  | 
 | 38 | +		return nil, err  | 
 | 39 | +	}  | 
 | 40 | +	uniqueUserIDs.AddMultiple(collaboratorIDs...)  | 
 | 41 | + | 
 | 42 | +	if repo.Owner.IsOrganization() {  | 
 | 43 | +		additionalUserIDs := make([]int64, 0, 10)  | 
 | 44 | +		if err := e.Table("team_user").  | 
 | 45 | +			Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id").  | 
 | 46 | +			Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id").  | 
 | 47 | +			Where("`team_repo`.repo_id = ? AND (`team_unit`.access_mode >= ? AND `team_unit`.`type` = ?)",  | 
 | 48 | +				repo.ID, perm.AccessModeRead, unit.TypePullRequests).  | 
 | 49 | +			Distinct("`team_user`.uid").  | 
 | 50 | +			Select("`team_user`.uid").  | 
 | 51 | +			Find(&additionalUserIDs); err != nil {  | 
 | 52 | +			return nil, err  | 
 | 53 | +		}  | 
 | 54 | +		uniqueUserIDs.AddMultiple(additionalUserIDs...)  | 
 | 55 | +	}  | 
 | 56 | + | 
 | 57 | +	uniqueUserIDs.Remove(posterID) // posterID should not be in the list of reviewers  | 
 | 58 | + | 
 | 59 | +	// Leave a seat for owner itself to append later, but if owner is an organization  | 
 | 60 | +	// and just waste 1 unit is cheaper than re-allocate memory once.  | 
 | 61 | +	users := make([]*user_model.User, 0, len(uniqueUserIDs)+1)  | 
 | 62 | +	if len(uniqueUserIDs) > 0 {  | 
 | 63 | +		if err := e.In("id", uniqueUserIDs.Values()).  | 
 | 64 | +			Where(builder.Eq{"`user`.is_active": true}).  | 
 | 65 | +			OrderBy(user_model.GetOrderByName()).  | 
 | 66 | +			Find(&users); err != nil {  | 
 | 67 | +			return nil, err  | 
 | 68 | +		}  | 
 | 69 | +	}  | 
 | 70 | + | 
 | 71 | +	// add owner after all users are loaded because we can avoid load owner twice  | 
 | 72 | +	if repo.OwnerID != posterID && !repo.Owner.IsOrganization() && !uniqueUserIDs.Contains(repo.OwnerID) {  | 
 | 73 | +		users = append(users, repo.Owner)  | 
 | 74 | +	}  | 
 | 75 | + | 
 | 76 | +	return users, nil  | 
 | 77 | +}  | 
 | 78 | + | 
 | 79 | +// GetReviewerTeams get all teams can be requested to review  | 
 | 80 | +func GetReviewerTeams(ctx context.Context, repo *repo_model.Repository) ([]*organization.Team, error) {  | 
 | 81 | +	if err := repo.LoadOwner(ctx); err != nil {  | 
 | 82 | +		return nil, err  | 
 | 83 | +	}  | 
 | 84 | +	if !repo.Owner.IsOrganization() {  | 
 | 85 | +		return nil, nil  | 
 | 86 | +	}  | 
 | 87 | + | 
 | 88 | +	return organization.GetTeamsWithAccessToRepoUnit(ctx, repo.OwnerID, repo.ID, perm.AccessModeRead, unit.TypePullRequests)  | 
 | 89 | +}  | 
0 commit comments