gitea源码

reviewer.go 3.1KB

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