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.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. // ColorFormat provides a basic color format for a Team
  82. func (t *Team) ColorFormat(s fmt.State) {
  83. if t == nil {
  84. log.ColorFprintf(s, "%d:%s (OrgID: %d) %-v",
  85. log.NewColoredIDValue(0),
  86. "<nil>",
  87. log.NewColoredIDValue(0),
  88. 0)
  89. return
  90. }
  91. log.ColorFprintf(s, "%d:%s (OrgID: %d) %-v",
  92. log.NewColoredIDValue(t.ID),
  93. t.Name,
  94. log.NewColoredIDValue(t.OrgID),
  95. t.AccessMode)
  96. }
  97. // GetUnits return a list of available units for a team
  98. func (t *Team) GetUnits() error {
  99. return t.getUnits(db.DefaultContext)
  100. }
  101. func (t *Team) getUnits(ctx context.Context) (err error) {
  102. if t.Units != nil {
  103. return nil
  104. }
  105. t.Units, err = getUnitsByTeamID(ctx, t.ID)
  106. return err
  107. }
  108. // GetUnitNames returns the team units names
  109. func (t *Team) GetUnitNames() (res []string) {
  110. if t.AccessMode >= perm.AccessModeAdmin {
  111. return unit.AllUnitKeyNames()
  112. }
  113. for _, u := range t.Units {
  114. res = append(res, unit.Units[u.Type].NameKey)
  115. }
  116. return res
  117. }
  118. // GetUnitsMap returns the team units permissions
  119. func (t *Team) GetUnitsMap() map[string]string {
  120. m := make(map[string]string)
  121. if t.AccessMode >= perm.AccessModeAdmin {
  122. for _, u := range unit.Units {
  123. m[u.NameKey] = t.AccessMode.String()
  124. }
  125. } else {
  126. for _, u := range t.Units {
  127. m[u.Unit().NameKey] = u.AccessMode.String()
  128. }
  129. }
  130. return m
  131. }
  132. // IsOwnerTeam returns true if team is owner team.
  133. func (t *Team) IsOwnerTeam() bool {
  134. return t.Name == OwnerTeamName
  135. }
  136. // IsMember returns true if given user is a member of team.
  137. func (t *Team) IsMember(userID int64) bool {
  138. isMember, err := IsTeamMember(db.DefaultContext, t.OrgID, t.ID, userID)
  139. if err != nil {
  140. log.Error("IsMember: %v", err)
  141. return false
  142. }
  143. return isMember
  144. }
  145. // LoadRepositories returns paginated repositories in team of organization.
  146. func (t *Team) LoadRepositories(ctx context.Context) (err error) {
  147. if t.Repos != nil {
  148. return nil
  149. }
  150. t.Repos, err = GetTeamRepositories(ctx, &SearchTeamRepoOptions{
  151. TeamID: t.ID,
  152. })
  153. return err
  154. }
  155. // LoadMembers returns paginated members in team of organization.
  156. func (t *Team) LoadMembers(ctx context.Context) (err error) {
  157. t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{
  158. TeamID: t.ID,
  159. })
  160. return err
  161. }
  162. // UnitEnabled returns if the team has the given unit type enabled
  163. func (t *Team) UnitEnabled(ctx context.Context, tp unit.Type) bool {
  164. return t.UnitAccessMode(ctx, tp) > perm.AccessModeNone
  165. }
  166. // UnitAccessMode returns if the team has the given unit type enabled
  167. func (t *Team) UnitAccessMode(ctx context.Context, tp unit.Type) perm.AccessMode {
  168. if err := t.getUnits(ctx); err != nil {
  169. log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error())
  170. }
  171. for _, unit := range t.Units {
  172. if unit.Type == tp {
  173. return unit.AccessMode
  174. }
  175. }
  176. return perm.AccessModeNone
  177. }
  178. // IsUsableTeamName tests if a name could be as team name
  179. func IsUsableTeamName(name string) error {
  180. switch name {
  181. case "new":
  182. return db.ErrNameReserved{Name: name}
  183. default:
  184. return nil
  185. }
  186. }
  187. // GetTeam returns team by given team name and organization.
  188. func GetTeam(ctx context.Context, orgID int64, name string) (*Team, error) {
  189. t := &Team{
  190. OrgID: orgID,
  191. LowerName: strings.ToLower(name),
  192. }
  193. has, err := db.GetByBean(ctx, t)
  194. if err != nil {
  195. return nil, err
  196. } else if !has {
  197. return nil, ErrTeamNotExist{orgID, 0, name}
  198. }
  199. return t, nil
  200. }
  201. // GetTeamIDsByNames returns a slice of team ids corresponds to names.
  202. func GetTeamIDsByNames(orgID int64, names []string, ignoreNonExistent bool) ([]int64, error) {
  203. ids := make([]int64, 0, len(names))
  204. for _, name := range names {
  205. u, err := GetTeam(db.DefaultContext, orgID, name)
  206. if err != nil {
  207. if ignoreNonExistent {
  208. continue
  209. } else {
  210. return nil, err
  211. }
  212. }
  213. ids = append(ids, u.ID)
  214. }
  215. return ids, nil
  216. }
  217. // GetOwnerTeam returns team by given team name and organization.
  218. func GetOwnerTeam(ctx context.Context, orgID int64) (*Team, error) {
  219. return GetTeam(ctx, orgID, OwnerTeamName)
  220. }
  221. // GetTeamByID returns team by given ID.
  222. func GetTeamByID(ctx context.Context, teamID int64) (*Team, error) {
  223. t := new(Team)
  224. has, err := db.GetEngine(ctx).ID(teamID).Get(t)
  225. if err != nil {
  226. return nil, err
  227. } else if !has {
  228. return nil, ErrTeamNotExist{0, teamID, ""}
  229. }
  230. return t, nil
  231. }
  232. // GetTeamNamesByID returns team's lower name from a list of team ids.
  233. func GetTeamNamesByID(teamIDs []int64) ([]string, error) {
  234. if len(teamIDs) == 0 {
  235. return []string{}, nil
  236. }
  237. var teamNames []string
  238. err := db.GetEngine(db.DefaultContext).Table("team").
  239. Select("lower_name").
  240. In("id", teamIDs).
  241. Asc("name").
  242. Find(&teamNames)
  243. return teamNames, err
  244. }
  245. // IncrTeamRepoNum increases the number of repos for the given team by 1
  246. func IncrTeamRepoNum(ctx context.Context, teamID int64) error {
  247. _, err := db.GetEngine(ctx).Incr("num_repos").ID(teamID).Update(new(Team))
  248. return err
  249. }