mirror of
https://github.com/go-gitea/gitea
synced 2024-11-05 12:07:00 +01:00
37a4b233a0
1. There are already global "unit consts", no need to use context data, which is fragile 2. Remove the "String()" method from "unit", it would only cause rendering problems in templates --------- Co-authored-by: silverwind <me@silverwind.io>
360 lines
8.3 KiB
Go
360 lines
8.3 KiB
Go
// Copyright 2017 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package unit
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"sync/atomic"
|
|
|
|
"code.gitea.io/gitea/models/perm"
|
|
"code.gitea.io/gitea/modules/container"
|
|
"code.gitea.io/gitea/modules/log"
|
|
"code.gitea.io/gitea/modules/setting"
|
|
)
|
|
|
|
// Type is Unit's Type
|
|
type Type int
|
|
|
|
// Enumerate all the unit types
|
|
const (
|
|
TypeInvalid Type = iota // 0 invalid
|
|
TypeCode // 1 code
|
|
TypeIssues // 2 issues
|
|
TypePullRequests // 3 PRs
|
|
TypeReleases // 4 Releases
|
|
TypeWiki // 5 Wiki
|
|
TypeExternalWiki // 6 ExternalWiki
|
|
TypeExternalTracker // 7 ExternalTracker
|
|
TypeProjects // 8 Projects
|
|
TypePackages // 9 Packages
|
|
TypeActions // 10 Actions
|
|
)
|
|
|
|
// Value returns integer value for unit type (used by template)
|
|
func (u Type) Value() int {
|
|
return int(u)
|
|
}
|
|
|
|
func (u Type) LogString() string {
|
|
unit, ok := Units[u]
|
|
unitName := "unknown"
|
|
if ok {
|
|
unitName = unit.NameKey
|
|
}
|
|
return fmt.Sprintf("<UnitType:%d:%s>", u, unitName)
|
|
}
|
|
|
|
var (
|
|
// AllRepoUnitTypes contains all the unit types
|
|
AllRepoUnitTypes = []Type{
|
|
TypeCode,
|
|
TypeIssues,
|
|
TypePullRequests,
|
|
TypeReleases,
|
|
TypeWiki,
|
|
TypeExternalWiki,
|
|
TypeExternalTracker,
|
|
TypeProjects,
|
|
TypePackages,
|
|
TypeActions,
|
|
}
|
|
|
|
// DefaultRepoUnits contains the default unit types
|
|
DefaultRepoUnits = []Type{
|
|
TypeCode,
|
|
TypeIssues,
|
|
TypePullRequests,
|
|
TypeReleases,
|
|
TypeWiki,
|
|
TypeProjects,
|
|
TypePackages,
|
|
TypeActions,
|
|
}
|
|
|
|
// ForkRepoUnits contains the default unit types for forks
|
|
DefaultForkRepoUnits = []Type{
|
|
TypeCode,
|
|
TypePullRequests,
|
|
}
|
|
|
|
// NotAllowedDefaultRepoUnits contains units that can't be default
|
|
NotAllowedDefaultRepoUnits = []Type{
|
|
TypeExternalWiki,
|
|
TypeExternalTracker,
|
|
}
|
|
|
|
disabledRepoUnitsAtomic atomic.Pointer[[]Type] // the units that have been globally disabled
|
|
)
|
|
|
|
// DisabledRepoUnitsGet returns the globally disabled units, it is a quick patch to fix data-race during testing.
|
|
// Because the queue worker might read when a test is mocking the value. FIXME: refactor to a clear solution later.
|
|
func DisabledRepoUnitsGet() []Type {
|
|
v := disabledRepoUnitsAtomic.Load()
|
|
if v == nil {
|
|
return nil
|
|
}
|
|
return *v
|
|
}
|
|
|
|
func DisabledRepoUnitsSet(v []Type) {
|
|
disabledRepoUnitsAtomic.Store(&v)
|
|
}
|
|
|
|
// Get valid set of default repository units from settings
|
|
func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
|
|
units := defaultUnits
|
|
|
|
// Use setting if not empty
|
|
if len(settingDefaultUnits) > 0 {
|
|
units = make([]Type, 0, len(settingDefaultUnits))
|
|
for _, settingUnit := range settingDefaultUnits {
|
|
if !settingUnit.CanBeDefault() {
|
|
log.Warn("Not allowed as default unit: %s", settingUnit.LogString())
|
|
continue
|
|
}
|
|
units = append(units, settingUnit)
|
|
}
|
|
}
|
|
|
|
// Remove disabled units
|
|
for _, disabledUnit := range DisabledRepoUnitsGet() {
|
|
for i, unit := range units {
|
|
if unit == disabledUnit {
|
|
units = append(units[:i], units[i+1:]...)
|
|
}
|
|
}
|
|
}
|
|
|
|
return units
|
|
}
|
|
|
|
// LoadUnitConfig load units from settings
|
|
func LoadUnitConfig() error {
|
|
disabledRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DisabledRepoUnits...)
|
|
if len(invalidKeys) > 0 {
|
|
log.Warn("Invalid keys in disabled repo units: %s", strings.Join(invalidKeys, ", "))
|
|
}
|
|
DisabledRepoUnitsSet(disabledRepoUnits)
|
|
|
|
setDefaultRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultRepoUnits...)
|
|
if len(invalidKeys) > 0 {
|
|
log.Warn("Invalid keys in default repo units: %s", strings.Join(invalidKeys, ", "))
|
|
}
|
|
DefaultRepoUnits = validateDefaultRepoUnits(DefaultRepoUnits, setDefaultRepoUnits)
|
|
if len(DefaultRepoUnits) == 0 {
|
|
return errors.New("no default repository units found")
|
|
}
|
|
setDefaultForkRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultForkRepoUnits...)
|
|
if len(invalidKeys) > 0 {
|
|
log.Warn("Invalid keys in default fork repo units: %s", strings.Join(invalidKeys, ", "))
|
|
}
|
|
DefaultForkRepoUnits = validateDefaultRepoUnits(DefaultForkRepoUnits, setDefaultForkRepoUnits)
|
|
if len(DefaultForkRepoUnits) == 0 {
|
|
return errors.New("no default fork repository units found")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UnitGlobalDisabled checks if unit type is global disabled
|
|
func (u Type) UnitGlobalDisabled() bool {
|
|
for _, ud := range DisabledRepoUnitsGet() {
|
|
if u == ud {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// CanBeDefault checks if the unit type can be a default repo unit
|
|
func (u *Type) CanBeDefault() bool {
|
|
for _, nadU := range NotAllowedDefaultRepoUnits {
|
|
if *u == nadU {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Unit is a section of one repository
|
|
type Unit struct {
|
|
Type Type
|
|
NameKey string
|
|
URI string
|
|
DescKey string
|
|
Priority int
|
|
MaxAccessMode perm.AccessMode // The max access mode of the unit. i.e. Read means this unit can only be read.
|
|
}
|
|
|
|
// IsLessThan compares order of two units
|
|
func (u Unit) IsLessThan(unit Unit) bool {
|
|
return u.Priority < unit.Priority
|
|
}
|
|
|
|
// MaxPerm returns the max perms of this unit
|
|
func (u Unit) MaxPerm() perm.AccessMode {
|
|
if u.Type == TypeExternalTracker || u.Type == TypeExternalWiki {
|
|
return perm.AccessModeRead
|
|
}
|
|
return perm.AccessModeAdmin
|
|
}
|
|
|
|
// Enumerate all the units
|
|
var (
|
|
UnitCode = Unit{
|
|
TypeCode,
|
|
"repo.code",
|
|
"/",
|
|
"repo.code.desc",
|
|
0,
|
|
perm.AccessModeOwner,
|
|
}
|
|
|
|
UnitIssues = Unit{
|
|
TypeIssues,
|
|
"repo.issues",
|
|
"/issues",
|
|
"repo.issues.desc",
|
|
1,
|
|
perm.AccessModeOwner,
|
|
}
|
|
|
|
UnitExternalTracker = Unit{
|
|
TypeExternalTracker,
|
|
"repo.ext_issues",
|
|
"/issues",
|
|
"repo.ext_issues.desc",
|
|
101,
|
|
perm.AccessModeRead,
|
|
}
|
|
|
|
UnitPullRequests = Unit{
|
|
TypePullRequests,
|
|
"repo.pulls",
|
|
"/pulls",
|
|
"repo.pulls.desc",
|
|
2,
|
|
perm.AccessModeOwner,
|
|
}
|
|
|
|
UnitReleases = Unit{
|
|
TypeReleases,
|
|
"repo.releases",
|
|
"/releases",
|
|
"repo.releases.desc",
|
|
3,
|
|
perm.AccessModeOwner,
|
|
}
|
|
|
|
UnitWiki = Unit{
|
|
TypeWiki,
|
|
"repo.wiki",
|
|
"/wiki",
|
|
"repo.wiki.desc",
|
|
4,
|
|
perm.AccessModeOwner,
|
|
}
|
|
|
|
UnitExternalWiki = Unit{
|
|
TypeExternalWiki,
|
|
"repo.ext_wiki",
|
|
"/wiki",
|
|
"repo.ext_wiki.desc",
|
|
102,
|
|
perm.AccessModeRead,
|
|
}
|
|
|
|
UnitProjects = Unit{
|
|
TypeProjects,
|
|
"repo.projects",
|
|
"/projects",
|
|
"repo.projects.desc",
|
|
5,
|
|
perm.AccessModeOwner,
|
|
}
|
|
|
|
UnitPackages = Unit{
|
|
TypePackages,
|
|
"repo.packages",
|
|
"/packages",
|
|
"packages.desc",
|
|
6,
|
|
perm.AccessModeRead,
|
|
}
|
|
|
|
UnitActions = Unit{
|
|
TypeActions,
|
|
"repo.actions",
|
|
"/actions",
|
|
"actions.unit.desc",
|
|
7,
|
|
perm.AccessModeOwner,
|
|
}
|
|
|
|
// Units contains all the units
|
|
Units = map[Type]Unit{
|
|
TypeCode: UnitCode,
|
|
TypeIssues: UnitIssues,
|
|
TypeExternalTracker: UnitExternalTracker,
|
|
TypePullRequests: UnitPullRequests,
|
|
TypeReleases: UnitReleases,
|
|
TypeWiki: UnitWiki,
|
|
TypeExternalWiki: UnitExternalWiki,
|
|
TypeProjects: UnitProjects,
|
|
TypePackages: UnitPackages,
|
|
TypeActions: UnitActions,
|
|
}
|
|
)
|
|
|
|
// FindUnitTypes give the unit key names and return valid unique units and invalid keys
|
|
func FindUnitTypes(nameKeys ...string) (res []Type, invalidKeys []string) {
|
|
m := make(container.Set[Type])
|
|
for _, key := range nameKeys {
|
|
t := TypeFromKey(key)
|
|
if t == TypeInvalid {
|
|
invalidKeys = append(invalidKeys, key)
|
|
} else if m.Add(t) {
|
|
res = append(res, t)
|
|
}
|
|
}
|
|
return res, invalidKeys
|
|
}
|
|
|
|
// TypeFromKey give the unit key name and return unit
|
|
func TypeFromKey(nameKey string) Type {
|
|
for t, u := range Units {
|
|
if strings.EqualFold(nameKey, u.NameKey) {
|
|
return t
|
|
}
|
|
}
|
|
return TypeInvalid
|
|
}
|
|
|
|
// AllUnitKeyNames returns all unit key names
|
|
func AllUnitKeyNames() []string {
|
|
res := make([]string, 0, len(Units))
|
|
for _, u := range Units {
|
|
res = append(res, u.NameKey)
|
|
}
|
|
return res
|
|
}
|
|
|
|
// MinUnitAccessMode returns the minial permission of the permission map
|
|
func MinUnitAccessMode(unitsMap map[Type]perm.AccessMode) perm.AccessMode {
|
|
res := perm.AccessModeNone
|
|
for t, mode := range unitsMap {
|
|
// Don't allow `TypeExternal{Tracker,Wiki}` to influence this as they can only be set to READ perms.
|
|
if t == TypeExternalTracker || t == TypeExternalWiki {
|
|
continue
|
|
}
|
|
|
|
// get the minial permission great than AccessModeNone except all are AccessModeNone
|
|
if mode > perm.AccessModeNone && (res == perm.AccessModeNone || mode < res) {
|
|
res = mode
|
|
}
|
|
}
|
|
return res
|
|
}
|