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.

unit.go 8.2KB

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