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