You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

team.go 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // Copyright 2018 The Gitea Authors. All rights reserved.
  2. // Copyright 2016 The Gogs Authors. All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. package organization
  5. import (
  6. "context"
  7. "fmt"
  8. "strings"
  9. "code.gitea.io/gitea/models/db"
  10. "code.gitea.io/gitea/models/perm"
  11. repo_model "code.gitea.io/gitea/models/repo"
  12. "code.gitea.io/gitea/models/unit"
  13. user_model "code.gitea.io/gitea/models/user"
  14. "code.gitea.io/gitea/modules/log"
  15. "code.gitea.io/gitea/modules/util"
  16. )
  17. // ___________
  18. // \__ ___/___ _____ _____
  19. // | |_/ __ \\__ \ / \
  20. // | |\ ___/ / __ \| Y Y \
  21. // |____| \___ >____ /__|_| /
  22. // \/ \/ \/
  23. // ErrTeamAlreadyExist represents a "TeamAlreadyExist" kind of error.
  24. type ErrTeamAlreadyExist struct {
  25. OrgID int64
  26. Name string
  27. }
  28. // IsErrTeamAlreadyExist checks if an error is a ErrTeamAlreadyExist.
  29. func IsErrTeamAlreadyExist(err error) bool {
  30. _, ok := err.(ErrTeamAlreadyExist)
  31. return ok
  32. }
  33. func (err ErrTeamAlreadyExist) Error() string {
  34. return fmt.Sprintf("team already exists [org_id: %d, name: %s]", err.OrgID, err.Name)
  35. }
  36. func (err ErrTeamAlreadyExist) Unwrap() error {
  37. return util.ErrAlreadyExist
  38. }
  39. // ErrTeamNotExist represents a "TeamNotExist" error
  40. type ErrTeamNotExist struct {
  41. OrgID int64
  42. TeamID int64
  43. Name string
  44. }
  45. // IsErrTeamNotExist checks if an error is a ErrTeamNotExist.
  46. func IsErrTeamNotExist(err error) bool {
  47. _, ok := err.(ErrTeamNotExist)
  48. return ok
  49. }
  50. func (err ErrTeamNotExist) Error() string {
  51. return fmt.Sprintf("team does not exist [org_id %d, team_id %d, name: %s]", err.OrgID, err.TeamID, err.Name)
  52. }
  53. func (err ErrTeamNotExist) Unwrap() error {
  54. return util.ErrNotExist
  55. }
  56. // OwnerTeamName return the owner team name
  57. const OwnerTeamName = "Owners"
  58. // Team represents a organization team.
  59. type Team struct {
  60. ID int64 `xorm:"pk autoincr"`
  61. OrgID int64 `xorm:"INDEX"`
  62. LowerName string
  63. Name string
  64. Description string
  65. AccessMode perm.AccessMode `xorm:"'authorize'"`
  66. Repos []*repo_model.Repository `xorm:"-"`
  67. Members []*user_model.User `xorm:"-"`
  68. NumRepos int
  69. NumMembers int
  70. Units []*TeamUnit `xorm:"-"`
  71. IncludesAllRepositories bool `xorm:"NOT NULL DEFAULT false"`
  72. CanCreateOrgRepo bool `xorm:"NOT NULL DEFAULT false"`
  73. }
  74. func init() {
  75. db.RegisterModel(new(Team))
  76. db.RegisterModel(new(TeamUser))
  77. db.RegisterModel(new(TeamRepo))
  78. db.RegisterModel(new(TeamUnit))
  79. db.RegisterModel(new(TeamInvite))
  80. }
  81. func (t *Team) LogString() string {
  82. if t == nil {
  83. return "<Team nil>"
  84. }
  85. return fmt.Sprintf("<Team %d:%s OrgID=%d AccessMode=%s>", t.ID, t.Name, t.OrgID, t.AccessMode.LogString())
  86. }
  87. // LoadUnits load a list of available units for a team
  88. func (t *Team) LoadUnits(ctx context.Context) (err error) {
  89. if t.Units != nil {
  90. return nil
  91. }
  92. t.Units, err = getUnitsByTeamID(ctx, t.ID)
  93. return err
  94. }
  95. // GetUnitNames returns the team units names
  96. func (t *Team) GetUnitNames() (res []string) {
  97. if t.AccessMode >= perm.AccessModeAdmin {
  98. return unit.AllUnitKeyNames()
  99. }
  100. for _, u := range t.Units {
  101. res = append(res, unit.Units[u.Type].NameKey)
  102. }
  103. return res
  104. }
  105. // GetUnitsMap returns the team units permissions
  106. func (t *Team) GetUnitsMap() map[string]string {
  107. m := make(map[string]string)
  108. if t.AccessMode >= perm.AccessModeAdmin {
  109. for _, u := range unit.Units {
  110. m[u.NameKey] = t.AccessMode.String()
  111. }
  112. } else {
  113. for _, u := range t.Units {
  114. m[u.Unit().NameKey] = u.AccessMode.String()
  115. }
  116. }
  117. return m
  118. }
  119. // IsOwnerTeam returns true if team is owner team.
  120. func (t *Team) IsOwnerTeam() bool {
  121. return t.Name == OwnerTeamName
  122. }
  123. // IsMember returns true if given user is a member of team.
  124. func (t *Team) IsMember(userID int64) bool {
  125. isMember, err := IsTeamMember(db.DefaultContext, t.OrgID, t.ID, userID)
  126. if err != nil {
  127. log.Error("IsMember: %v", err)
  128. return false
  129. }
  130. return isMember
  131. }
  132. // LoadRepositories returns paginated repositories in team of organization.
  133. func (t *Team) LoadRepositories(ctx context.Context) (err error) {
  134. if t.Repos != nil {
  135. return nil
  136. }
  137. t.Repos, err = GetTeamRepositories(ctx, &SearchTeamRepoOptions{
  138. TeamID: t.ID,
  139. })
  140. return err
  141. }
  142. // LoadMembers returns paginated members in team of organization.
  143. func (t *Team) LoadMembers(ctx context.Context) (err error) {
  144. t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{
  145. TeamID: t.ID,
  146. })
  147. return err
  148. }
  149. // UnitEnabled returns if the team has the given unit type enabled
  150. func (t *Team) UnitEnabled(ctx context.Context, tp unit.Type) bool {
  151. return t.UnitAccessMode(ctx, tp) > perm.AccessModeNone
  152. }
  153. // UnitAccessMode returns if the team has the given unit type enabled
  154. func (t *Team) UnitAccessMode(ctx context.Context, tp unit.Type) perm.AccessMode {
  155. if err := t.LoadUnits(ctx); err != nil {
  156. log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error())
  157. }
  158. for _, unit := range t.Units {
  159. if unit.Type == tp {
  160. return unit.AccessMode
  161. }
  162. }
  163. return perm.AccessModeNone
  164. }
  165. // IsUsableTeamName tests if a name could be as team name
  166. func IsUsableTeamName(name string) error {
  167. switch name {
  168. case "new":
  169. return db.ErrNameReserved{Name: name}
  170. default:
  171. return nil
  172. }
  173. }
  174. // GetTeam returns team by given team name and organization.
  175. func GetTeam(ctx context.Context, orgID int64, name string) (*Team, error) {
  176. t := &Team{
  177. OrgID: orgID,
  178. LowerName: strings.ToLower(name),
  179. }
  180. has, err := db.GetByBean(ctx, t)
  181. if err != nil {
  182. return nil, err
  183. } else if !has {
  184. return nil, ErrTeamNotExist{orgID, 0, name}
  185. }
  186. return t, nil
  187. }
  188. // GetTeamIDsByNames returns a slice of team ids corresponds to names.
  189. func GetTeamIDsByNames(orgID int64, names []string, ignoreNonExistent bool) ([]int64, error) {
  190. ids := make([]int64, 0, len(names))
  191. for _, name := range names {
  192. u, err := GetTeam(db.DefaultContext, orgID, name)
  193. if err != nil {
  194. if ignoreNonExistent {
  195. continue
  196. } else {
  197. return nil, err
  198. }
  199. }
  200. ids = append(ids, u.ID)
  201. }
  202. return ids, nil
  203. }
  204. // GetOwnerTeam returns team by given team name and organization.
  205. func GetOwnerTeam(ctx context.Context, orgID int64) (*Team, error) {
  206. return GetTeam(ctx, orgID, OwnerTeamName)
  207. }
  208. // GetTeamByID returns team by given ID.
  209. func GetTeamByID(ctx context.Context, teamID int64) (*Team, error) {
  210. t := new(Team)
  211. has, err := db.GetEngine(ctx).ID(teamID).Get(t)
  212. if err != nil {
  213. return nil, err
  214. } else if !has {
  215. return nil, ErrTeamNotExist{0, teamID, ""}
  216. }
  217. return t, nil
  218. }
  219. // GetTeamNamesByID returns team's lower name from a list of team ids.
  220. func GetTeamNamesByID(teamIDs []int64) ([]string, error) {
  221. if len(teamIDs) == 0 {
  222. return []string{}, nil
  223. }
  224. var teamNames []string
  225. err := db.GetEngine(db.DefaultContext).Table("team").
  226. Select("lower_name").
  227. In("id", teamIDs).
  228. Asc("name").
  229. Find(&teamNames)
  230. return teamNames, err
  231. }
  232. // IncrTeamRepoNum increases the number of repos for the given team by 1
  233. func IncrTeamRepoNum(ctx context.Context, teamID int64) error {
  234. _, err := db.GetEngine(ctx).Incr("num_repos").ID(teamID).Update(new(Team))
  235. return err
  236. }