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

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