code.gitea.io/gitea@v1.21.7/models/unit/unit.go (about) 1 // Copyright 2017 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package unit 5 6 import ( 7 "errors" 8 "fmt" 9 "strings" 10 11 "code.gitea.io/gitea/models/perm" 12 "code.gitea.io/gitea/modules/container" 13 "code.gitea.io/gitea/modules/log" 14 "code.gitea.io/gitea/modules/setting" 15 ) 16 17 // Type is Unit's Type 18 type Type int 19 20 // Enumerate all the unit types 21 const ( 22 TypeInvalid Type = iota // 0 invalid 23 TypeCode // 1 code 24 TypeIssues // 2 issues 25 TypePullRequests // 3 PRs 26 TypeReleases // 4 Releases 27 TypeWiki // 5 Wiki 28 TypeExternalWiki // 6 ExternalWiki 29 TypeExternalTracker // 7 ExternalTracker 30 TypeProjects // 8 Kanban board 31 TypePackages // 9 Packages 32 TypeActions // 10 Actions 33 ) 34 35 // Value returns integer value for unit type 36 func (u Type) Value() int { 37 return int(u) 38 } 39 40 func (u Type) String() string { 41 switch u { 42 case TypeCode: 43 return "TypeCode" 44 case TypeIssues: 45 return "TypeIssues" 46 case TypePullRequests: 47 return "TypePullRequests" 48 case TypeReleases: 49 return "TypeReleases" 50 case TypeWiki: 51 return "TypeWiki" 52 case TypeExternalWiki: 53 return "TypeExternalWiki" 54 case TypeExternalTracker: 55 return "TypeExternalTracker" 56 case TypeProjects: 57 return "TypeProjects" 58 case TypePackages: 59 return "TypePackages" 60 case TypeActions: 61 return "TypeActions" 62 } 63 return fmt.Sprintf("Unknown Type %d", u) 64 } 65 66 func (u Type) LogString() string { 67 return fmt.Sprintf("<UnitType:%d:%s>", u, u.String()) 68 } 69 70 var ( 71 // AllRepoUnitTypes contains all the unit types 72 AllRepoUnitTypes = []Type{ 73 TypeCode, 74 TypeIssues, 75 TypePullRequests, 76 TypeReleases, 77 TypeWiki, 78 TypeExternalWiki, 79 TypeExternalTracker, 80 TypeProjects, 81 TypePackages, 82 TypeActions, 83 } 84 85 // DefaultRepoUnits contains the default unit types 86 DefaultRepoUnits = []Type{ 87 TypeCode, 88 TypeIssues, 89 TypePullRequests, 90 TypeReleases, 91 TypeWiki, 92 TypeProjects, 93 TypePackages, 94 } 95 96 // ForkRepoUnits contains the default unit types for forks 97 DefaultForkRepoUnits = []Type{ 98 TypeCode, 99 TypePullRequests, 100 } 101 102 // NotAllowedDefaultRepoUnits contains units that can't be default 103 NotAllowedDefaultRepoUnits = []Type{ 104 TypeExternalWiki, 105 TypeExternalTracker, 106 } 107 108 // DisabledRepoUnits contains the units that have been globally disabled 109 DisabledRepoUnits = []Type{} 110 ) 111 112 // Get valid set of default repository units from settings 113 func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type { 114 units := defaultUnits 115 116 // Use setting if not empty 117 if len(settingDefaultUnits) > 0 { 118 units = make([]Type, 0, len(settingDefaultUnits)) 119 for _, settingUnit := range settingDefaultUnits { 120 if !settingUnit.CanBeDefault() { 121 log.Warn("Not allowed as default unit: %s", settingUnit.String()) 122 continue 123 } 124 units = append(units, settingUnit) 125 } 126 } 127 128 // Remove disabled units 129 for _, disabledUnit := range DisabledRepoUnits { 130 for i, unit := range units { 131 if unit == disabledUnit { 132 units = append(units[:i], units[i+1:]...) 133 } 134 } 135 } 136 137 return units 138 } 139 140 // LoadUnitConfig load units from settings 141 func LoadUnitConfig() error { 142 var invalidKeys []string 143 DisabledRepoUnits, invalidKeys = FindUnitTypes(setting.Repository.DisabledRepoUnits...) 144 if len(invalidKeys) > 0 { 145 log.Warn("Invalid keys in disabled repo units: %s", strings.Join(invalidKeys, ", ")) 146 } 147 148 setDefaultRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultRepoUnits...) 149 if len(invalidKeys) > 0 { 150 log.Warn("Invalid keys in default repo units: %s", strings.Join(invalidKeys, ", ")) 151 } 152 DefaultRepoUnits = validateDefaultRepoUnits(DefaultRepoUnits, setDefaultRepoUnits) 153 if len(DefaultRepoUnits) == 0 { 154 return errors.New("no default repository units found") 155 } 156 setDefaultForkRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultForkRepoUnits...) 157 if len(invalidKeys) > 0 { 158 log.Warn("Invalid keys in default fork repo units: %s", strings.Join(invalidKeys, ", ")) 159 } 160 DefaultForkRepoUnits = validateDefaultRepoUnits(DefaultForkRepoUnits, setDefaultForkRepoUnits) 161 if len(DefaultForkRepoUnits) == 0 { 162 return errors.New("no default fork repository units found") 163 } 164 return nil 165 } 166 167 // UnitGlobalDisabled checks if unit type is global disabled 168 func (u Type) UnitGlobalDisabled() bool { 169 for _, ud := range DisabledRepoUnits { 170 if u == ud { 171 return true 172 } 173 } 174 return false 175 } 176 177 // CanBeDefault checks if the unit type can be a default repo unit 178 func (u *Type) CanBeDefault() bool { 179 for _, nadU := range NotAllowedDefaultRepoUnits { 180 if *u == nadU { 181 return false 182 } 183 } 184 return true 185 } 186 187 // Unit is a section of one repository 188 type Unit struct { 189 Type Type 190 NameKey string 191 URI string 192 DescKey string 193 Idx int 194 MaxAccessMode perm.AccessMode // The max access mode of the unit. i.e. Read means this unit can only be read. 195 } 196 197 // IsLessThan compares order of two units 198 func (u Unit) IsLessThan(unit Unit) bool { 199 if (u.Type == TypeExternalTracker || u.Type == TypeExternalWiki) && unit.Type != TypeExternalTracker && unit.Type != TypeExternalWiki { 200 return false 201 } 202 return u.Idx < unit.Idx 203 } 204 205 // MaxPerm returns the max perms of this unit 206 func (u Unit) MaxPerm() perm.AccessMode { 207 if u.Type == TypeExternalTracker || u.Type == TypeExternalWiki { 208 return perm.AccessModeRead 209 } 210 return perm.AccessModeAdmin 211 } 212 213 // Enumerate all the units 214 var ( 215 UnitCode = Unit{ 216 TypeCode, 217 "repo.code", 218 "/", 219 "repo.code.desc", 220 0, 221 perm.AccessModeOwner, 222 } 223 224 UnitIssues = Unit{ 225 TypeIssues, 226 "repo.issues", 227 "/issues", 228 "repo.issues.desc", 229 1, 230 perm.AccessModeOwner, 231 } 232 233 UnitExternalTracker = Unit{ 234 TypeExternalTracker, 235 "repo.ext_issues", 236 "/issues", 237 "repo.ext_issues.desc", 238 1, 239 perm.AccessModeRead, 240 } 241 242 UnitPullRequests = Unit{ 243 TypePullRequests, 244 "repo.pulls", 245 "/pulls", 246 "repo.pulls.desc", 247 2, 248 perm.AccessModeOwner, 249 } 250 251 UnitReleases = Unit{ 252 TypeReleases, 253 "repo.releases", 254 "/releases", 255 "repo.releases.desc", 256 3, 257 perm.AccessModeOwner, 258 } 259 260 UnitWiki = Unit{ 261 TypeWiki, 262 "repo.wiki", 263 "/wiki", 264 "repo.wiki.desc", 265 4, 266 perm.AccessModeOwner, 267 } 268 269 UnitExternalWiki = Unit{ 270 TypeExternalWiki, 271 "repo.ext_wiki", 272 "/wiki", 273 "repo.ext_wiki.desc", 274 4, 275 perm.AccessModeRead, 276 } 277 278 UnitProjects = Unit{ 279 TypeProjects, 280 "repo.projects", 281 "/projects", 282 "repo.projects.desc", 283 5, 284 perm.AccessModeOwner, 285 } 286 287 UnitPackages = Unit{ 288 TypePackages, 289 "repo.packages", 290 "/packages", 291 "packages.desc", 292 6, 293 perm.AccessModeRead, 294 } 295 296 UnitActions = Unit{ 297 TypeActions, 298 "repo.actions", 299 "/actions", 300 "actions.unit.desc", 301 7, 302 perm.AccessModeOwner, 303 } 304 305 // Units contains all the units 306 Units = map[Type]Unit{ 307 TypeCode: UnitCode, 308 TypeIssues: UnitIssues, 309 TypeExternalTracker: UnitExternalTracker, 310 TypePullRequests: UnitPullRequests, 311 TypeReleases: UnitReleases, 312 TypeWiki: UnitWiki, 313 TypeExternalWiki: UnitExternalWiki, 314 TypeProjects: UnitProjects, 315 TypePackages: UnitPackages, 316 TypeActions: UnitActions, 317 } 318 ) 319 320 // FindUnitTypes give the unit key names and return valid unique units and invalid keys 321 func FindUnitTypes(nameKeys ...string) (res []Type, invalidKeys []string) { 322 m := make(container.Set[Type]) 323 for _, key := range nameKeys { 324 t := TypeFromKey(key) 325 if t == TypeInvalid { 326 invalidKeys = append(invalidKeys, key) 327 } else if m.Add(t) { 328 res = append(res, t) 329 } 330 } 331 return res, invalidKeys 332 } 333 334 // TypeFromKey give the unit key name and return unit 335 func TypeFromKey(nameKey string) Type { 336 for t, u := range Units { 337 if strings.EqualFold(nameKey, u.NameKey) { 338 return t 339 } 340 } 341 return TypeInvalid 342 } 343 344 // AllUnitKeyNames returns all unit key names 345 func AllUnitKeyNames() []string { 346 res := make([]string, 0, len(Units)) 347 for _, u := range Units { 348 res = append(res, u.NameKey) 349 } 350 return res 351 } 352 353 // MinUnitAccessMode returns the minial permission of the permission map 354 func MinUnitAccessMode(unitsMap map[Type]perm.AccessMode) perm.AccessMode { 355 res := perm.AccessModeNone 356 for t, mode := range unitsMap { 357 // Don't allow `TypeExternal{Tracker,Wiki}` to influence this as they can only be set to READ perms. 358 if t == TypeExternalTracker || t == TypeExternalWiki { 359 continue 360 } 361 362 // get the minial permission great than AccessModeNone except all are AccessModeNone 363 if mode > perm.AccessModeNone && (res == perm.AccessModeNone || mode < res) { 364 res = mode 365 } 366 } 367 return res 368 }