gitea源码

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