mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
83 lines
2.8 KiB
Go
83 lines
2.8 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package pull
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/hanzoai/git/models/db"
|
|
"github.com/hanzoai/git/models/organization"
|
|
"github.com/hanzoai/git/models/perm"
|
|
repo_model "github.com/hanzoai/git/models/repo"
|
|
"github.com/hanzoai/git/models/unit"
|
|
user_model "github.com/hanzoai/git/models/user"
|
|
"github.com/hanzoai/git/modules/container"
|
|
|
|
"github.com/hanzoai/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, err := organization.GetTeamUserIDsWithAccessToAnyRepoUnit(ctx, repo.OwnerID, repo.ID, perm.AccessModeRead, unit.TypePullRequests)
|
|
if 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.GetTeamsWithAccessToAnyRepoUnit(ctx, repo.OwnerID, repo.ID, perm.AccessModeRead, unit.TypePullRequests)
|
|
}
|