mirror of
https://github.com/go-gitea/gitea.git
synced 2024-12-04 16:23:49 +08:00
fe49cb0243
This PR rewrites `GetReviewer` function and move it to service layer. Reviewers should not be watchers, so that this PR removed all watchers from reviewers. When the repository is under an organization, the pull request unit read permission will be checked to resolve the bug of #32394 Fix #32394
90 lines
3.1 KiB
Go
90 lines
3.1 KiB
Go
// Copyright 2024 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package pull
|
|
|
|
import (
|
|
"context"
|
|
|
|
"code.gitea.io/gitea/models/db"
|
|
"code.gitea.io/gitea/models/organization"
|
|
"code.gitea.io/gitea/models/perm"
|
|
repo_model "code.gitea.io/gitea/models/repo"
|
|
"code.gitea.io/gitea/models/unit"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
"code.gitea.io/gitea/modules/container"
|
|
|
|
"xorm.io/builder"
|
|
)
|
|
|
|
// GetReviewers get all users can be requested to review:
|
|
// - Poster should not be listed
|
|
// - For collaborator, all users that have read access or higher to the repository.
|
|
// - For repository under organization, users under the teams which have read permission or higher of pull request unit
|
|
// - Owner will be listed if it's not an organization, not the poster and not in the list of reviewers
|
|
func GetReviewers(ctx context.Context, repo *repo_model.Repository, doerID, posterID int64) ([]*user_model.User, error) {
|
|
if err := repo.LoadOwner(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
e := db.GetEngine(ctx)
|
|
uniqueUserIDs := make(container.Set[int64])
|
|
|
|
collaboratorIDs := make([]int64, 0, 10)
|
|
if err := e.Table("collaboration").Where("repo_id=?", repo.ID).
|
|
And("mode >= ?", perm.AccessModeRead).
|
|
Select("user_id").
|
|
Find(&collaboratorIDs); err != nil {
|
|
return nil, err
|
|
}
|
|
uniqueUserIDs.AddMultiple(collaboratorIDs...)
|
|
|
|
if repo.Owner.IsOrganization() {
|
|
additionalUserIDs := make([]int64, 0, 10)
|
|
if err := e.Table("team_user").
|
|
Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id").
|
|
Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id").
|
|
Where("`team_repo`.repo_id = ? AND (`team_unit`.access_mode >= ? AND `team_unit`.`type` = ?)",
|
|
repo.ID, perm.AccessModeRead, unit.TypePullRequests).
|
|
Distinct("`team_user`.uid").
|
|
Select("`team_user`.uid").
|
|
Find(&additionalUserIDs); err != nil {
|
|
return nil, err
|
|
}
|
|
uniqueUserIDs.AddMultiple(additionalUserIDs...)
|
|
}
|
|
|
|
uniqueUserIDs.Remove(posterID) // posterID should not be in the list of reviewers
|
|
|
|
// Leave a seat for owner itself to append later, but if owner is an organization
|
|
// and just waste 1 unit is cheaper than re-allocate memory once.
|
|
users := make([]*user_model.User, 0, len(uniqueUserIDs)+1)
|
|
if len(uniqueUserIDs) > 0 {
|
|
if err := e.In("id", uniqueUserIDs.Values()).
|
|
Where(builder.Eq{"`user`.is_active": true}).
|
|
OrderBy(user_model.GetOrderByName()).
|
|
Find(&users); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// add owner after all users are loaded because we can avoid load owner twice
|
|
if repo.OwnerID != posterID && !repo.Owner.IsOrganization() && !uniqueUserIDs.Contains(repo.OwnerID) {
|
|
users = append(users, repo.Owner)
|
|
}
|
|
|
|
return users, nil
|
|
}
|
|
|
|
// GetReviewerTeams get all teams can be requested to review
|
|
func GetReviewerTeams(ctx context.Context, repo *repo_model.Repository) ([]*organization.Team, error) {
|
|
if err := repo.LoadOwner(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
if !repo.Owner.IsOrganization() {
|
|
return nil, nil
|
|
}
|
|
|
|
return organization.GetTeamsWithAccessToRepoUnit(ctx, repo.OwnerID, repo.ID, perm.AccessModeRead, unit.TypePullRequests)
|
|
}
|