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

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