diff --git a/integrations/api_repo_edit_test.go b/integrations/api_repo_edit_test.go
index e980357a0f..f8e21a495b 100644
--- a/integrations/api_repo_edit_test.go
+++ b/integrations/api_repo_edit_test.go
@@ -12,6 +12,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
+	unit_model "code.gitea.io/gitea/models/unit"
 	api "code.gitea.io/gitea/modules/structs"
 
 	"github.com/stretchr/testify/assert"
@@ -26,7 +27,7 @@ func getRepoEditOptionFromRepo(repo *models.Repository) *api.EditRepoOption {
 	hasIssues := false
 	var internalTracker *api.InternalTracker
 	var externalTracker *api.ExternalTracker
-	if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil {
+	if unit, err := repo.GetUnit(unit_model.TypeIssues); err == nil {
 		config := unit.IssuesConfig()
 		hasIssues = true
 		internalTracker = &api.InternalTracker{
@@ -34,7 +35,7 @@ func getRepoEditOptionFromRepo(repo *models.Repository) *api.EditRepoOption {
 			AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime,
 			EnableIssueDependencies:          config.EnableDependencies,
 		}
-	} else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil {
+	} else if unit, err := repo.GetUnit(unit_model.TypeExternalTracker); err == nil {
 		config := unit.ExternalTrackerConfig()
 		hasIssues = true
 		externalTracker = &api.ExternalTracker{
@@ -45,9 +46,9 @@ func getRepoEditOptionFromRepo(repo *models.Repository) *api.EditRepoOption {
 	}
 	hasWiki := false
 	var externalWiki *api.ExternalWiki
-	if _, err := repo.GetUnit(models.UnitTypeWiki); err == nil {
+	if _, err := repo.GetUnit(unit_model.TypeWiki); err == nil {
 		hasWiki = true
-	} else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil {
+	} else if unit, err := repo.GetUnit(unit_model.TypeExternalWiki); err == nil {
 		hasWiki = true
 		config := unit.ExternalWikiConfig()
 		externalWiki = &api.ExternalWiki{
@@ -61,7 +62,7 @@ func getRepoEditOptionFromRepo(repo *models.Repository) *api.EditRepoOption {
 	allowRebase := false
 	allowRebaseMerge := false
 	allowSquash := false
-	if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil {
+	if unit, err := repo.GetUnit(unit_model.TypePullRequests); err == nil {
 		config := unit.PullRequestsConfig()
 		hasPullRequests = true
 		ignoreWhitespaceConflicts = config.IgnoreWhitespaceConflicts
diff --git a/models/attachment.go b/models/attachment.go
index f06b389dc6..ed82aaf483 100644
--- a/models/attachment.go
+++ b/models/attachment.go
@@ -10,6 +10,7 @@ import (
 	"path"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/storage"
 	"code.gitea.io/gitea/modules/timeutil"
@@ -62,25 +63,25 @@ func (a *Attachment) DownloadURL() string {
 }
 
 // LinkedRepository returns the linked repo if any
-func (a *Attachment) LinkedRepository() (*Repository, UnitType, error) {
+func (a *Attachment) LinkedRepository() (*Repository, unit.Type, error) {
 	if a.IssueID != 0 {
 		iss, err := GetIssueByID(a.IssueID)
 		if err != nil {
-			return nil, UnitTypeIssues, err
+			return nil, unit.TypeIssues, err
 		}
 		repo, err := GetRepositoryByID(iss.RepoID)
-		unitType := UnitTypeIssues
+		unitType := unit.TypeIssues
 		if iss.IsPull {
-			unitType = UnitTypePullRequests
+			unitType = unit.TypePullRequests
 		}
 		return repo, unitType, err
 	} else if a.ReleaseID != 0 {
 		rel, err := GetReleaseByID(a.ReleaseID)
 		if err != nil {
-			return nil, UnitTypeReleases, err
+			return nil, unit.TypeReleases, err
 		}
 		repo, err := GetRepositoryByID(rel.RepoID)
-		return repo, UnitTypeReleases, err
+		return repo, unit.TypeReleases, err
 	}
 	return nil, -1, nil
 }
diff --git a/models/attachment_test.go b/models/attachment_test.go
index 725d5a40c0..c7f456341c 100644
--- a/models/attachment_test.go
+++ b/models/attachment_test.go
@@ -8,6 +8,7 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -107,11 +108,11 @@ func TestLinkedRepository(t *testing.T) {
 		name             string
 		attachID         int64
 		expectedRepo     *Repository
-		expectedUnitType UnitType
+		expectedUnitType unit.Type
 	}{
-		{"LinkedIssue", 1, &Repository{ID: 1}, UnitTypeIssues},
-		{"LinkedComment", 3, &Repository{ID: 1}, UnitTypePullRequests},
-		{"LinkedRelease", 9, &Repository{ID: 1}, UnitTypeReleases},
+		{"LinkedIssue", 1, &Repository{ID: 1}, unit.TypeIssues},
+		{"LinkedComment", 3, &Repository{ID: 1}, unit.TypePullRequests},
+		{"LinkedRelease", 9, &Repository{ID: 1}, unit.TypeReleases},
 		{"Notlinked", 10, nil, -1},
 	}
 	for _, tc := range testCases {
diff --git a/models/branches.go b/models/branches.go
index caca9e23fe..50de52a277 100644
--- a/models/branches.go
+++ b/models/branches.go
@@ -11,6 +11,7 @@ import (
 	"time"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/timeutil"
@@ -74,7 +75,7 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool {
 		} else if repo, err := GetRepositoryByID(protectBranch.RepoID); err != nil {
 			log.Error("GetRepositoryByID: %v", err)
 			return false
-		} else if writeAccess, err := HasAccessUnit(user, repo, UnitTypeCode, AccessModeWrite); err != nil {
+		} else if writeAccess, err := HasAccessUnit(user, repo, unit.TypeCode, AccessModeWrite); err != nil {
 			log.Error("HasAccessUnit: %v", err)
 			return false
 		} else {
@@ -102,7 +103,7 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool {
 func (protectBranch *ProtectedBranch) IsUserMergeWhitelisted(userID int64, permissionInRepo Permission) bool {
 	if !protectBranch.EnableMergeWhitelist {
 		// Then we need to fall back on whether the user has write permission
-		return permissionInRepo.CanWrite(UnitTypeCode)
+		return permissionInRepo.CanWrite(unit.TypeCode)
 	}
 
 	if base.Int64sContains(protectBranch.MergeWhitelistUserIDs, userID) {
@@ -134,7 +135,7 @@ func (protectBranch *ProtectedBranch) isUserOfficialReviewer(e db.Engine, user *
 
 	if !protectBranch.EnableApprovalsWhitelist {
 		// Anyone with write access is considered official reviewer
-		writeAccess, err := hasAccessUnit(e, user, repo, UnitTypeCode, AccessModeWrite)
+		writeAccess, err := hasAccessUnit(e, user, repo, unit.TypeCode, AccessModeWrite)
 		if err != nil {
 			return false, err
 		}
@@ -454,7 +455,7 @@ func updateUserWhitelist(repo *Repository, currentWhitelist, newWhitelist []int6
 			return nil, fmt.Errorf("GetUserRepoPermission [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err)
 		}
 
-		if !perm.CanWrite(UnitTypeCode) {
+		if !perm.CanWrite(unit.TypeCode) {
 			continue // Drop invalid user ID
 		}
 
diff --git a/models/issue.go b/models/issue.go
index 75aafe51b7..f36267c945 100644
--- a/models/issue.go
+++ b/models/issue.go
@@ -15,6 +15,7 @@ import (
 
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/issues"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/references"
@@ -2031,9 +2032,9 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx context.Context, doer *User,
 		}
 		if len(teams) != 0 {
 			checked := make([]int64, 0, len(teams))
-			unittype := UnitTypeIssues
+			unittype := unit.TypeIssues
 			if issue.IsPull {
-				unittype = UnitTypePullRequests
+				unittype = unit.TypePullRequests
 			}
 			for _, team := range teams {
 				if team.Authorize >= AccessModeOwner {
diff --git a/models/issue_dependency.go b/models/issue_dependency.go
index 0dfb99ca01..f58bb3da0a 100644
--- a/models/issue_dependency.go
+++ b/models/issue_dependency.go
@@ -6,6 +6,7 @@ package models
 
 import (
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/timeutil"
@@ -141,7 +142,7 @@ func (repo *Repository) IsDependenciesEnabled() bool {
 func (repo *Repository) isDependenciesEnabled(e db.Engine) bool {
 	var u *RepoUnit
 	var err error
-	if u, err = repo.getUnit(e, UnitTypeIssues); err != nil {
+	if u, err = repo.getUnit(e, unit.TypeIssues); err != nil {
 		log.Trace("%s", err)
 		return setting.Service.DefaultEnableDependencies
 	}
diff --git a/models/lfs_lock.go b/models/lfs_lock.go
index ca49ab8a6a..247444a66d 100644
--- a/models/lfs_lock.go
+++ b/models/lfs_lock.go
@@ -11,6 +11,7 @@ import (
 	"time"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 
 	"xorm.io/xorm"
@@ -152,7 +153,7 @@ func CheckLFSAccessForRepo(u *User, repo *Repository, mode AccessMode) error {
 	if err != nil {
 		return err
 	}
-	if !perm.CanAccess(mode, UnitTypeCode) {
+	if !perm.CanAccess(mode, unit.TypeCode) {
 		return ErrLFSUnauthorizedAction{repo.ID, u.DisplayName(), mode}
 	}
 	return nil
diff --git a/models/migrations/v111.go b/models/migrations/v111.go
index 95f0ec22dd..02624da66a 100644
--- a/models/migrations/v111.go
+++ b/models/migrations/v111.go
@@ -56,7 +56,7 @@ func addBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
 		// VisibleTypePrivate Visible only for organization's members
 		VisibleTypePrivate int = 2
 
-		// UnitTypeCode is unit type code
+		// unit.UnitTypeCode is unit type code
 		UnitTypeCode int = 1
 
 		// AccessModeNone no access
diff --git a/models/notification.go b/models/notification.go
index bcbe8b0988..ce656f4355 100644
--- a/models/notification.go
+++ b/models/notification.go
@@ -9,6 +9,7 @@ import (
 	"strconv"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/timeutil"
@@ -262,10 +263,10 @@ func createOrUpdateIssueNotifications(e db.Engine, issueID, commentID, notificat
 
 			return err
 		}
-		if issue.IsPull && !issue.Repo.checkUnitUser(e, user, UnitTypePullRequests) {
+		if issue.IsPull && !issue.Repo.checkUnitUser(e, user, unit.TypePullRequests) {
 			continue
 		}
-		if !issue.IsPull && !issue.Repo.checkUnitUser(e, user, UnitTypeIssues) {
+		if !issue.IsPull && !issue.Repo.checkUnitUser(e, user, unit.TypeIssues) {
 			continue
 		}
 
diff --git a/models/org.go b/models/org.go
index d2801a30ce..c6d2562f15 100644
--- a/models/org.go
+++ b/models/org.go
@@ -10,6 +10,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/storage"
@@ -202,8 +203,8 @@ func CreateOrganization(org, owner *User) (err error) {
 	}
 
 	// insert units for team
-	units := make([]TeamUnit, 0, len(AllRepoUnitTypes))
-	for _, tp := range AllRepoUnitTypes {
+	units := make([]TeamUnit, 0, len(unit.AllRepoUnitTypes))
+	for _, tp := range unit.AllRepoUnitTypes {
 		units = append(units, TeamUnit{
 			OrgID:  org.ID,
 			TeamID: t.ID,
diff --git a/models/org_team.go b/models/org_team.go
index fc6a5f2c3b..10178ec88a 100644
--- a/models/org_team.go
+++ b/models/org_team.go
@@ -12,6 +12,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 
@@ -135,7 +136,7 @@ func (t *Team) getUnits(e db.Engine) (err error) {
 // GetUnitNames returns the team units names
 func (t *Team) GetUnitNames() (res []string) {
 	for _, u := range t.Units {
-		res = append(res, Units[u.Type].NameKey)
+		res = append(res, unit.Units[u.Type].NameKey)
 	}
 	return
 }
@@ -435,11 +436,11 @@ func (t *Team) RemoveRepository(repoID int64) error {
 }
 
 // UnitEnabled returns if the team has the given unit type enabled
-func (t *Team) UnitEnabled(tp UnitType) bool {
+func (t *Team) UnitEnabled(tp unit.Type) bool {
 	return t.unitEnabled(db.GetEngine(db.DefaultContext), tp)
 }
 
-func (t *Team) unitEnabled(e db.Engine, tp UnitType) bool {
+func (t *Team) unitEnabled(e db.Engine, tp unit.Type) bool {
 	if err := t.getUnits(e); err != nil {
 		log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error())
 	}
@@ -1029,15 +1030,15 @@ func GetTeamsWithAccessToRepo(orgID, repoID int64, mode AccessMode) ([]*Team, er
 
 // TeamUnit describes all units of a repository
 type TeamUnit struct {
-	ID     int64    `xorm:"pk autoincr"`
-	OrgID  int64    `xorm:"INDEX"`
-	TeamID int64    `xorm:"UNIQUE(s)"`
-	Type   UnitType `xorm:"UNIQUE(s)"`
+	ID     int64     `xorm:"pk autoincr"`
+	OrgID  int64     `xorm:"INDEX"`
+	TeamID int64     `xorm:"UNIQUE(s)"`
+	Type   unit.Type `xorm:"UNIQUE(s)"`
 }
 
 // Unit returns Unit
-func (t *TeamUnit) Unit() Unit {
-	return Units[t.Type]
+func (t *TeamUnit) Unit() unit.Unit {
+	return unit.Units[t.Type]
 }
 
 func getUnitsByTeamID(e db.Engine, teamID int64) (units []*TeamUnit, err error) {
diff --git a/models/pull.go b/models/pull.go
index 38f2c1b8ce..6bcc30e901 100644
--- a/models/pull.go
+++ b/models/pull.go
@@ -11,6 +11,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/timeutil"
@@ -236,7 +237,7 @@ func (pr *PullRequest) GetDefaultMergeMessage() string {
 	}
 
 	issueReference := "#"
-	if pr.BaseRepo.UnitEnabled(UnitTypeExternalTracker) {
+	if pr.BaseRepo.UnitEnabled(unit.TypeExternalTracker) {
 		issueReference = "!"
 	}
 
@@ -338,7 +339,7 @@ func (pr *PullRequest) GetDefaultSquashMessage() string {
 		log.Error("LoadBaseRepo: %v", err)
 		return ""
 	}
-	if pr.BaseRepo.UnitEnabled(UnitTypeExternalTracker) {
+	if pr.BaseRepo.UnitEnabled(unit.TypeExternalTracker) {
 		return fmt.Sprintf("%s (!%d)", pr.Issue.Title, pr.Issue.Index)
 	}
 	return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index)
diff --git a/models/pull_test.go b/models/pull_test.go
index 173977aafe..e6855240db 100644
--- a/models/pull_test.go
+++ b/models/pull_test.go
@@ -8,6 +8,7 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -255,7 +256,7 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) {
 	assert.NoError(t, db.PrepareTestDatabase())
 
 	externalTracker := RepoUnit{
-		Type: UnitTypeExternalTracker,
+		Type: unit.TypeExternalTracker,
 		Config: &ExternalTrackerConfig{
 			ExternalTrackerFormat: "https://someurl.com/{user}/{repo}/{issue}",
 		},
diff --git a/models/repo.go b/models/repo.go
index 25b1e65206..10dc8d9b09 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -23,6 +23,7 @@ import (
 	"unicode/utf8"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/lfs"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/markup"
@@ -128,7 +129,7 @@ func loadRepoConfig() {
 // NewRepoContext creates a new repository context
 func NewRepoContext() {
 	loadRepoConfig()
-	loadUnitConfig()
+	unit.LoadUnitConfig()
 
 	RemoveAllWithNotice("Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp"))
 }
@@ -353,11 +354,11 @@ func (repo *Repository) getUnits(e db.Engine) (err error) {
 }
 
 // CheckUnitUser check whether user could visit the unit of this repository
-func (repo *Repository) CheckUnitUser(user *User, unitType UnitType) bool {
+func (repo *Repository) CheckUnitUser(user *User, unitType unit.Type) bool {
 	return repo.checkUnitUser(db.GetEngine(db.DefaultContext), user, unitType)
 }
 
-func (repo *Repository) checkUnitUser(e db.Engine, user *User, unitType UnitType) bool {
+func (repo *Repository) checkUnitUser(e db.Engine, user *User, unitType unit.Type) bool {
 	if user.IsAdmin {
 		return true
 	}
@@ -371,7 +372,7 @@ func (repo *Repository) checkUnitUser(e db.Engine, user *User, unitType UnitType
 }
 
 // UnitEnabled if this repository has the given unit enabled
-func (repo *Repository) UnitEnabled(tp UnitType) bool {
+func (repo *Repository) UnitEnabled(tp unit.Type) bool {
 	if err := repo.getUnits(db.GetEngine(db.DefaultContext)); err != nil {
 		log.Warn("Error loading repository (ID: %d) units: %s", repo.ID, err.Error())
 	}
@@ -385,7 +386,7 @@ func (repo *Repository) UnitEnabled(tp UnitType) bool {
 
 // ErrUnitTypeNotExist represents a "UnitTypeNotExist" kind of error.
 type ErrUnitTypeNotExist struct {
-	UT UnitType
+	UT unit.Type
 }
 
 // IsErrUnitTypeNotExist checks if an error is a ErrUnitNotExist.
@@ -399,28 +400,28 @@ func (err ErrUnitTypeNotExist) Error() string {
 }
 
 // MustGetUnit always returns a RepoUnit object
-func (repo *Repository) MustGetUnit(tp UnitType) *RepoUnit {
+func (repo *Repository) MustGetUnit(tp unit.Type) *RepoUnit {
 	ru, err := repo.GetUnit(tp)
 	if err == nil {
 		return ru
 	}
 
-	if tp == UnitTypeExternalWiki {
+	if tp == unit.TypeExternalWiki {
 		return &RepoUnit{
 			Type:   tp,
 			Config: new(ExternalWikiConfig),
 		}
-	} else if tp == UnitTypeExternalTracker {
+	} else if tp == unit.TypeExternalTracker {
 		return &RepoUnit{
 			Type:   tp,
 			Config: new(ExternalTrackerConfig),
 		}
-	} else if tp == UnitTypePullRequests {
+	} else if tp == unit.TypePullRequests {
 		return &RepoUnit{
 			Type:   tp,
 			Config: new(PullRequestsConfig),
 		}
-	} else if tp == UnitTypeIssues {
+	} else if tp == unit.TypeIssues {
 		return &RepoUnit{
 			Type:   tp,
 			Config: new(IssuesConfig),
@@ -433,11 +434,11 @@ func (repo *Repository) MustGetUnit(tp UnitType) *RepoUnit {
 }
 
 // GetUnit returns a RepoUnit object
-func (repo *Repository) GetUnit(tp UnitType) (*RepoUnit, error) {
+func (repo *Repository) GetUnit(tp unit.Type) (*RepoUnit, error) {
 	return repo.getUnit(db.GetEngine(db.DefaultContext), tp)
 }
 
-func (repo *Repository) getUnit(e db.Engine, tp UnitType) (*RepoUnit, error) {
+func (repo *Repository) getUnit(e db.Engine, tp unit.Type) (*RepoUnit, error) {
 	if err := repo.getUnits(e); err != nil {
 		return nil, err
 	}
@@ -484,7 +485,7 @@ func (repo *Repository) ComposeMetas() map[string]string {
 			"mode":     "comment",
 		}
 
-		unit, err := repo.GetUnit(UnitTypeExternalTracker)
+		unit, err := repo.GetUnit(unit.TypeExternalTracker)
 		if err == nil {
 			metas["format"] = unit.ExternalTrackerConfig().ExternalTrackerFormat
 			switch unit.ExternalTrackerConfig().ExternalTrackerStyle {
@@ -802,7 +803,7 @@ func (repo *Repository) CanEnablePulls() bool {
 
 // AllowsPulls returns true if repository meets the requirements of accepting pulls and has them enabled.
 func (repo *Repository) AllowsPulls() bool {
-	return repo.CanEnablePulls() && repo.UnitEnabled(UnitTypePullRequests)
+	return repo.CanEnablePulls() && repo.UnitEnabled(unit.TypePullRequests)
 }
 
 // CanEnableEditor returns true if repository meets the requirements of web editor.
@@ -1076,9 +1077,9 @@ func CreateRepository(ctx context.Context, doer, u *User, repo *Repository, over
 	}
 
 	// insert units for repo
-	units := make([]RepoUnit, 0, len(DefaultRepoUnits))
-	for _, tp := range DefaultRepoUnits {
-		if tp == UnitTypeIssues {
+	units := make([]RepoUnit, 0, len(unit.DefaultRepoUnits))
+	for _, tp := range unit.DefaultRepoUnits {
+		if tp == unit.TypeIssues {
 			units = append(units, RepoUnit{
 				RepoID: repo.ID,
 				Type:   tp,
@@ -1088,7 +1089,7 @@ func CreateRepository(ctx context.Context, doer, u *User, repo *Repository, over
 					EnableDependencies:               setting.Service.DefaultEnableDependencies,
 				},
 			})
-		} else if tp == UnitTypePullRequests {
+		} else if tp == unit.TypePullRequests {
 			units = append(units, RepoUnit{
 				RepoID: repo.ID,
 				Type:   tp,
@@ -1406,7 +1407,7 @@ func UpdateRepositoryUpdatedTime(repoID int64, updateTime time.Time) error {
 }
 
 // UpdateRepositoryUnits updates a repository's units
-func UpdateRepositoryUnits(repo *Repository, units []RepoUnit, deleteUnitTypes []UnitType) (err error) {
+func UpdateRepositoryUnits(repo *Repository, units []RepoUnit, deleteUnitTypes []unit.Type) (err error) {
 	sess := db.NewSession(db.DefaultContext)
 	defer sess.Close()
 	if err = sess.Begin(); err != nil {
diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go
index bc9d0100ef..dd362406cf 100644
--- a/models/repo_collaboration.go
+++ b/models/repo_collaboration.go
@@ -9,6 +9,7 @@ import (
 	"fmt"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/timeutil"
 
@@ -276,7 +277,7 @@ func (repo *Repository) IsOwnerMemberCollaborator(userID int64) (bool, error) {
 	teamMember, err := db.GetEngine(db.DefaultContext).Join("INNER", "team_repo", "team_repo.team_id = team_user.team_id").
 		Join("INNER", "team_unit", "team_unit.team_id = team_user.team_id").
 		Where("team_repo.repo_id = ?", repo.ID).
-		And("team_unit.`type` = ?", UnitTypeCode).
+		And("team_unit.`type` = ?", unit.TypeCode).
 		And("team_user.uid = ?", userID).Table("team_user").Exist(&TeamUser{})
 	if err != nil {
 		return false, err
diff --git a/models/repo_issue.go b/models/repo_issue.go
index 433d0e39bd..32bfdc15b6 100644
--- a/models/repo_issue.go
+++ b/models/repo_issue.go
@@ -4,7 +4,10 @@
 
 package models
 
-import "code.gitea.io/gitea/modules/setting"
+import (
+	"code.gitea.io/gitea/models/unit"
+	"code.gitea.io/gitea/modules/setting"
+)
 
 // ___________.__             ___________                     __
 // \__    ___/|__| _____   ___\__    ___/___________    ____ |  | __ ___________
@@ -27,7 +30,7 @@ func (repo *Repository) IsTimetrackerEnabled() bool {
 
 	var u *RepoUnit
 	var err error
-	if u, err = repo.GetUnit(UnitTypeIssues); err != nil {
+	if u, err = repo.GetUnit(unit.TypeIssues); err != nil {
 		return setting.Service.DefaultEnableTimetracking
 	}
 	return u.IssuesConfig().EnableTimetracker
@@ -37,7 +40,7 @@ func (repo *Repository) IsTimetrackerEnabled() bool {
 func (repo *Repository) AllowOnlyContributorsToTrackTime() bool {
 	var u *RepoUnit
 	var err error
-	if u, err = repo.GetUnit(UnitTypeIssues); err != nil {
+	if u, err = repo.GetUnit(unit.TypeIssues); err != nil {
 		return setting.Service.DefaultAllowOnlyContributorsToTrackTime
 	}
 	return u.IssuesConfig().AllowOnlyContributorsToTrackTime
diff --git a/models/repo_permission.go b/models/repo_permission.go
index 5ec933aa0f..3db7200470 100644
--- a/models/repo_permission.go
+++ b/models/repo_permission.go
@@ -8,6 +8,7 @@ import (
 	"fmt"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 )
 
@@ -15,7 +16,7 @@ import (
 type Permission struct {
 	AccessMode AccessMode
 	Units      []*RepoUnit
-	UnitsMode  map[UnitType]AccessMode
+	UnitsMode  map[unit.Type]AccessMode
 }
 
 // IsOwner returns true if current user is the owner of repository.
@@ -37,7 +38,7 @@ func (p *Permission) HasAccess() bool {
 }
 
 // UnitAccessMode returns current user accessmode to the specify unit of the repository
-func (p *Permission) UnitAccessMode(unitType UnitType) AccessMode {
+func (p *Permission) UnitAccessMode(unitType unit.Type) AccessMode {
 	if p.UnitsMode == nil {
 		for _, u := range p.Units {
 			if u.Type == unitType {
@@ -50,12 +51,12 @@ func (p *Permission) UnitAccessMode(unitType UnitType) AccessMode {
 }
 
 // CanAccess returns true if user has mode access to the unit of the repository
-func (p *Permission) CanAccess(mode AccessMode, unitType UnitType) bool {
+func (p *Permission) CanAccess(mode AccessMode, unitType unit.Type) bool {
 	return p.UnitAccessMode(unitType) >= mode
 }
 
 // CanAccessAny returns true if user has mode access to any of the units of the repository
-func (p *Permission) CanAccessAny(mode AccessMode, unitTypes ...UnitType) bool {
+func (p *Permission) CanAccessAny(mode AccessMode, unitTypes ...unit.Type) bool {
 	for _, u := range unitTypes {
 		if p.CanAccess(mode, u) {
 			return true
@@ -65,12 +66,12 @@ func (p *Permission) CanAccessAny(mode AccessMode, unitTypes ...UnitType) bool {
 }
 
 // CanRead returns true if user could read to this unit
-func (p *Permission) CanRead(unitType UnitType) bool {
+func (p *Permission) CanRead(unitType unit.Type) bool {
 	return p.CanAccess(AccessModeRead, unitType)
 }
 
 // CanReadAny returns true if user has read access to any of the units of the repository
-func (p *Permission) CanReadAny(unitTypes ...UnitType) bool {
+func (p *Permission) CanReadAny(unitTypes ...unit.Type) bool {
 	return p.CanAccessAny(AccessModeRead, unitTypes...)
 }
 
@@ -78,13 +79,13 @@ func (p *Permission) CanReadAny(unitTypes ...UnitType) bool {
 // returns true if isPull is false and user could read to issues
 func (p *Permission) CanReadIssuesOrPulls(isPull bool) bool {
 	if isPull {
-		return p.CanRead(UnitTypePullRequests)
+		return p.CanRead(unit.TypePullRequests)
 	}
-	return p.CanRead(UnitTypeIssues)
+	return p.CanRead(unit.TypeIssues)
 }
 
 // CanWrite returns true if user could write to this unit
-func (p *Permission) CanWrite(unitType UnitType) bool {
+func (p *Permission) CanWrite(unitType unit.Type) bool {
 	return p.CanAccess(AccessModeWrite, unitType)
 }
 
@@ -92,9 +93,9 @@ func (p *Permission) CanWrite(unitType UnitType) bool {
 // returns true if isPull is false and user could write to issues
 func (p *Permission) CanWriteIssuesOrPulls(isPull bool) bool {
 	if isPull {
-		return p.CanWrite(UnitTypePullRequests)
+		return p.CanWrite(unit.TypePullRequests)
 	}
-	return p.CanWrite(UnitTypeIssues)
+	return p.CanWrite(unit.TypeIssues)
 }
 
 // ColorFormat writes a colored string for these Permissions
@@ -215,7 +216,7 @@ func getUserRepoPermission(e db.Engine, repo *Repository, user *User) (perm Perm
 		return
 	}
 
-	perm.UnitsMode = make(map[UnitType]AccessMode)
+	perm.UnitsMode = make(map[unit.Type]AccessMode)
 
 	// Collaborators on organization
 	if isCollaborator {
@@ -330,16 +331,16 @@ func isUserRepoAdmin(e db.Engine, repo *Repository, user *User) (bool, error) {
 // AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the
 // user does not have access.
 func AccessLevel(user *User, repo *Repository) (AccessMode, error) {
-	return accessLevelUnit(db.GetEngine(db.DefaultContext), user, repo, UnitTypeCode)
+	return accessLevelUnit(db.GetEngine(db.DefaultContext), user, repo, unit.TypeCode)
 }
 
 // AccessLevelUnit returns the Access a user has to a repository's. Will return NoneAccess if the
 // user does not have access.
-func AccessLevelUnit(user *User, repo *Repository, unitType UnitType) (AccessMode, error) {
+func AccessLevelUnit(user *User, repo *Repository, unitType unit.Type) (AccessMode, error) {
 	return accessLevelUnit(db.GetEngine(db.DefaultContext), user, repo, unitType)
 }
 
-func accessLevelUnit(e db.Engine, user *User, repo *Repository, unitType UnitType) (AccessMode, error) {
+func accessLevelUnit(e db.Engine, user *User, repo *Repository, unitType unit.Type) (AccessMode, error) {
 	perm, err := getUserRepoPermission(e, repo, user)
 	if err != nil {
 		return AccessModeNone, err
@@ -347,13 +348,13 @@ func accessLevelUnit(e db.Engine, user *User, repo *Repository, unitType UnitTyp
 	return perm.UnitAccessMode(unitType), nil
 }
 
-func hasAccessUnit(e db.Engine, user *User, repo *Repository, unitType UnitType, testMode AccessMode) (bool, error) {
+func hasAccessUnit(e db.Engine, user *User, repo *Repository, unitType unit.Type, testMode AccessMode) (bool, error) {
 	mode, err := accessLevelUnit(e, user, repo, unitType)
 	return testMode <= mode, err
 }
 
 // HasAccessUnit returns true if user has testMode to the unit of the repository
-func HasAccessUnit(user *User, repo *Repository, unitType UnitType, testMode AccessMode) (bool, error) {
+func HasAccessUnit(user *User, repo *Repository, unitType unit.Type, testMode AccessMode) (bool, error) {
 	return hasAccessUnit(db.GetEngine(db.DefaultContext), user, repo, unitType, testMode)
 }
 
@@ -372,7 +373,7 @@ func canBeAssigned(e db.Engine, user *User, repo *Repository, _ bool) (bool, err
 	if err != nil {
 		return false, err
 	}
-	return perm.CanAccessAny(AccessModeWrite, UnitTypeCode, UnitTypeIssues, UnitTypePullRequests), nil
+	return perm.CanAccessAny(AccessModeWrite, unit.TypeCode, unit.TypeIssues, unit.TypePullRequests), nil
 }
 
 func hasAccess(e db.Engine, userID int64, repo *Repository) (bool, error) {
@@ -397,7 +398,7 @@ func HasAccess(userID int64, repo *Repository) (bool, error) {
 }
 
 // FilterOutRepoIdsWithoutUnitAccess filter out repos where user has no access to repositories
-func FilterOutRepoIdsWithoutUnitAccess(u *User, repoIDs []int64, units ...UnitType) ([]int64, error) {
+func FilterOutRepoIdsWithoutUnitAccess(u *User, repoIDs []int64, units ...unit.Type) ([]int64, error) {
 	i := 0
 	for _, rID := range repoIDs {
 		repo, err := GetRepositoryByID(rID)
diff --git a/models/repo_permission_test.go b/models/repo_permission_test.go
index 1fbf1b9f8f..5e43937776 100644
--- a/models/repo_permission_test.go
+++ b/models/repo_permission_test.go
@@ -8,6 +8,7 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -165,8 +166,8 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) {
 	for _, unit := range repo.Units {
 		assert.True(t, perm.CanRead(unit.Type))
 	}
-	assert.True(t, perm.CanWrite(UnitTypeIssues))
-	assert.False(t, perm.CanWrite(UnitTypeCode))
+	assert.True(t, perm.CanWrite(unit.TypeIssues))
+	assert.False(t, perm.CanWrite(unit.TypeCode))
 
 	// admin
 	admin := db.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
@@ -235,17 +236,17 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
 	tester := db.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
 	perm, err = GetUserRepoPermission(repo, tester)
 	assert.NoError(t, err)
-	assert.True(t, perm.CanWrite(UnitTypeIssues))
-	assert.False(t, perm.CanWrite(UnitTypeCode))
-	assert.False(t, perm.CanRead(UnitTypeCode))
+	assert.True(t, perm.CanWrite(unit.TypeIssues))
+	assert.False(t, perm.CanWrite(unit.TypeCode))
+	assert.False(t, perm.CanRead(unit.TypeCode))
 
 	// org member team reviewer
 	reviewer := db.AssertExistsAndLoadBean(t, &User{ID: 20}).(*User)
 	perm, err = GetUserRepoPermission(repo, reviewer)
 	assert.NoError(t, err)
-	assert.False(t, perm.CanRead(UnitTypeIssues))
-	assert.False(t, perm.CanWrite(UnitTypeCode))
-	assert.True(t, perm.CanRead(UnitTypeCode))
+	assert.False(t, perm.CanRead(unit.TypeIssues))
+	assert.False(t, perm.CanWrite(unit.TypeCode))
+	assert.True(t, perm.CanRead(unit.TypeCode))
 
 	// admin
 	admin := db.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
diff --git a/models/repo_test.go b/models/repo_test.go
index 8073a9cd2f..425e8c0191 100644
--- a/models/repo_test.go
+++ b/models/repo_test.go
@@ -13,6 +13,7 @@ import (
 	"testing"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/markup"
 
 	"github.com/stretchr/testify/assert"
@@ -32,7 +33,7 @@ func TestMetas(t *testing.T) {
 	assert.Equal(t, "testOwner", metas["user"])
 
 	externalTracker := RepoUnit{
-		Type: UnitTypeExternalTracker,
+		Type: unit.TypeExternalTracker,
 		Config: &ExternalTrackerConfig{
 			ExternalTrackerFormat: "https://someurl.com/{user}/{repo}/{issue}",
 		},
diff --git a/models/repo_unit.go b/models/repo_unit.go
index 474f65bf03..4dac15366b 100644
--- a/models/repo_unit.go
+++ b/models/repo_unit.go
@@ -9,6 +9,7 @@ import (
 
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/login"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/json"
 	"code.gitea.io/gitea/modules/timeutil"
 
@@ -20,7 +21,7 @@ import (
 type RepoUnit struct {
 	ID          int64
 	RepoID      int64              `xorm:"INDEX(s)"`
-	Type        UnitType           `xorm:"INDEX(s)"`
+	Type        unit.Type          `xorm:"INDEX(s)"`
 	Config      convert.Conversion `xorm:"TEXT"`
 	CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
 }
@@ -154,16 +155,16 @@ func (cfg *PullRequestsConfig) AllowedMergeStyleCount() int {
 func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) {
 	switch colName {
 	case "type":
-		switch UnitType(login.Cell2Int64(val)) {
-		case UnitTypeCode, UnitTypeReleases, UnitTypeWiki, UnitTypeProjects:
+		switch unit.Type(login.Cell2Int64(val)) {
+		case unit.TypeCode, unit.TypeReleases, unit.TypeWiki, unit.TypeProjects:
 			r.Config = new(UnitConfig)
-		case UnitTypeExternalWiki:
+		case unit.TypeExternalWiki:
 			r.Config = new(ExternalWikiConfig)
-		case UnitTypeExternalTracker:
+		case unit.TypeExternalTracker:
 			r.Config = new(ExternalTrackerConfig)
-		case UnitTypePullRequests:
+		case unit.TypePullRequests:
 			r.Config = new(PullRequestsConfig)
-		case UnitTypeIssues:
+		case unit.TypeIssues:
 			r.Config = new(IssuesConfig)
 		default:
 			panic(fmt.Sprintf("unrecognized repo unit type: %v", *val))
@@ -172,36 +173,36 @@ func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) {
 }
 
 // Unit returns Unit
-func (r *RepoUnit) Unit() Unit {
-	return Units[r.Type]
+func (r *RepoUnit) Unit() unit.Unit {
+	return unit.Units[r.Type]
 }
 
-// CodeConfig returns config for UnitTypeCode
+// CodeConfig returns config for unit.TypeCode
 func (r *RepoUnit) CodeConfig() *UnitConfig {
 	return r.Config.(*UnitConfig)
 }
 
-// PullRequestsConfig returns config for UnitTypePullRequests
+// PullRequestsConfig returns config for unit.TypePullRequests
 func (r *RepoUnit) PullRequestsConfig() *PullRequestsConfig {
 	return r.Config.(*PullRequestsConfig)
 }
 
-// ReleasesConfig returns config for UnitTypeReleases
+// ReleasesConfig returns config for unit.TypeReleases
 func (r *RepoUnit) ReleasesConfig() *UnitConfig {
 	return r.Config.(*UnitConfig)
 }
 
-// ExternalWikiConfig returns config for UnitTypeExternalWiki
+// ExternalWikiConfig returns config for unit.TypeExternalWiki
 func (r *RepoUnit) ExternalWikiConfig() *ExternalWikiConfig {
 	return r.Config.(*ExternalWikiConfig)
 }
 
-// IssuesConfig returns config for UnitTypeIssues
+// IssuesConfig returns config for unit.TypeIssues
 func (r *RepoUnit) IssuesConfig() *IssuesConfig {
 	return r.Config.(*IssuesConfig)
 }
 
-// ExternalTrackerConfig returns config for UnitTypeExternalTracker
+// ExternalTrackerConfig returns config for unit.TypeExternalTracker
 func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig {
 	return r.Config.(*ExternalTrackerConfig)
 }
diff --git a/models/repo_watch.go b/models/repo_watch.go
index b37d47874e..55fb08a426 100644
--- a/models/repo_watch.go
+++ b/models/repo_watch.go
@@ -8,6 +8,7 @@ import (
 	"fmt"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/setting"
 	"code.gitea.io/gitea/modules/timeutil"
 )
@@ -245,9 +246,9 @@ func notifyWatchers(e db.Engine, actions ...*Action) error {
 					permPR[i] = false
 					continue
 				}
-				permCode[i] = perm.CanRead(UnitTypeCode)
-				permIssue[i] = perm.CanRead(UnitTypeIssues)
-				permPR[i] = perm.CanRead(UnitTypePullRequests)
+				permCode[i] = perm.CanRead(unit.TypeCode)
+				permIssue[i] = perm.CanRead(unit.TypeIssues)
+				permPR[i] = perm.CanRead(unit.TypePullRequests)
 			}
 		}
 
diff --git a/models/review.go b/models/review.go
index d456383d9c..ab275ecb26 100644
--- a/models/review.go
+++ b/models/review.go
@@ -9,6 +9,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/timeutil"
 
@@ -897,7 +898,7 @@ func CanMarkConversation(issue *Issue, doer *User) (permResult bool, err error)
 			return false, err
 		}
 
-		permResult = perm.CanAccess(AccessModeWrite, UnitTypePullRequests)
+		permResult = perm.CanAccess(AccessModeWrite, unit.TypePullRequests)
 		if !permResult {
 			if permResult, err = IsOfficialReviewer(issue, doer); err != nil {
 				return false, err
diff --git a/models/unit.go b/models/unit/unit.go
similarity index 58%
rename from models/unit.go
rename to models/unit/unit.go
index 939deba574..0af4640b7a 100644
--- a/models/unit.go
+++ b/models/unit/unit.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a MIT-style
 // license that can be found in the LICENSE file.
 
-package models
+package unit
 
 import (
 	"fmt"
@@ -12,50 +12,50 @@ import (
 	"code.gitea.io/gitea/modules/setting"
 )
 
-// UnitType is Unit's Type
-type UnitType int
+// Type is Unit's Type
+type Type int
 
 // Enumerate all the unit types
 const (
-	UnitTypeCode            UnitType = iota + 1 // 1 code
-	UnitTypeIssues                              // 2 issues
-	UnitTypePullRequests                        // 3 PRs
-	UnitTypeReleases                            // 4 Releases
-	UnitTypeWiki                                // 5 Wiki
-	UnitTypeExternalWiki                        // 6 ExternalWiki
-	UnitTypeExternalTracker                     // 7 ExternalTracker
-	UnitTypeProjects                            // 8 Kanban board
+	TypeCode            Type = iota + 1 // 1 code
+	TypeIssues                          // 2 issues
+	TypePullRequests                    // 3 PRs
+	TypeReleases                        // 4 Releases
+	TypeWiki                            // 5 Wiki
+	TypeExternalWiki                    // 6 ExternalWiki
+	TypeExternalTracker                 // 7 ExternalTracker
+	TypeProjects                        // 8 Kanban board
 )
 
 // Value returns integer value for unit type
-func (u UnitType) Value() int {
+func (u Type) Value() int {
 	return int(u)
 }
 
-func (u UnitType) String() string {
+func (u Type) String() string {
 	switch u {
-	case UnitTypeCode:
-		return "UnitTypeCode"
-	case UnitTypeIssues:
-		return "UnitTypeIssues"
-	case UnitTypePullRequests:
-		return "UnitTypePullRequests"
-	case UnitTypeReleases:
-		return "UnitTypeReleases"
-	case UnitTypeWiki:
-		return "UnitTypeWiki"
-	case UnitTypeExternalWiki:
-		return "UnitTypeExternalWiki"
-	case UnitTypeExternalTracker:
-		return "UnitTypeExternalTracker"
-	case UnitTypeProjects:
-		return "UnitTypeProjects"
+	case TypeCode:
+		return "TypeCode"
+	case TypeIssues:
+		return "TypeIssues"
+	case TypePullRequests:
+		return "TypePullRequests"
+	case TypeReleases:
+		return "TypeReleases"
+	case TypeWiki:
+		return "TypeWiki"
+	case TypeExternalWiki:
+		return "TypeExternalWiki"
+	case TypeExternalTracker:
+		return "TypeExternalTracker"
+	case TypeProjects:
+		return "TypeProjects"
 	}
-	return fmt.Sprintf("Unknown UnitType %d", u)
+	return fmt.Sprintf("Unknown Type %d", u)
 }
 
-// ColorFormat provides a ColorFormatted version of this UnitType
-func (u UnitType) ColorFormat(s fmt.State) {
+// ColorFormat provides a ColorFormatted version of this Type
+func (u Type) ColorFormat(s fmt.State) {
 	log.ColorFprintf(s, "%d:%s",
 		log.NewColoredIDValue(u),
 		u)
@@ -63,49 +63,50 @@ func (u UnitType) ColorFormat(s fmt.State) {
 
 var (
 	// AllRepoUnitTypes contains all the unit types
-	AllRepoUnitTypes = []UnitType{
-		UnitTypeCode,
-		UnitTypeIssues,
-		UnitTypePullRequests,
-		UnitTypeReleases,
-		UnitTypeWiki,
-		UnitTypeExternalWiki,
-		UnitTypeExternalTracker,
-		UnitTypeProjects,
+	AllRepoUnitTypes = []Type{
+		TypeCode,
+		TypeIssues,
+		TypePullRequests,
+		TypeReleases,
+		TypeWiki,
+		TypeExternalWiki,
+		TypeExternalTracker,
+		TypeProjects,
 	}
 
 	// DefaultRepoUnits contains the default unit types
-	DefaultRepoUnits = []UnitType{
-		UnitTypeCode,
-		UnitTypeIssues,
-		UnitTypePullRequests,
-		UnitTypeReleases,
-		UnitTypeWiki,
-		UnitTypeProjects,
+	DefaultRepoUnits = []Type{
+		TypeCode,
+		TypeIssues,
+		TypePullRequests,
+		TypeReleases,
+		TypeWiki,
+		TypeProjects,
 	}
 
 	// NotAllowedDefaultRepoUnits contains units that can't be default
-	NotAllowedDefaultRepoUnits = []UnitType{
-		UnitTypeExternalWiki,
-		UnitTypeExternalTracker,
+	NotAllowedDefaultRepoUnits = []Type{
+		TypeExternalWiki,
+		TypeExternalTracker,
 	}
 
 	// MustRepoUnits contains the units could not be disabled currently
-	MustRepoUnits = []UnitType{
-		UnitTypeCode,
-		UnitTypeReleases,
+	MustRepoUnits = []Type{
+		TypeCode,
+		TypeReleases,
 	}
 
 	// DisabledRepoUnits contains the units that have been globally disabled
-	DisabledRepoUnits = []UnitType{}
+	DisabledRepoUnits = []Type{}
 )
 
-func loadUnitConfig() {
+// LoadUnitConfig load units from settings
+func LoadUnitConfig() {
 	setDefaultRepoUnits := FindUnitTypes(setting.Repository.DefaultRepoUnits...)
 	// Default repo units set if setting is not empty
 	if len(setDefaultRepoUnits) > 0 {
 		// MustRepoUnits required as default
-		DefaultRepoUnits = make([]UnitType, len(MustRepoUnits))
+		DefaultRepoUnits = make([]Type, len(MustRepoUnits))
 		copy(DefaultRepoUnits, MustRepoUnits)
 		for _, defaultU := range setDefaultRepoUnits {
 			if !defaultU.CanBeDefault() {
@@ -138,7 +139,7 @@ func loadUnitConfig() {
 }
 
 // UnitGlobalDisabled checks if unit type is global disabled
-func (u UnitType) UnitGlobalDisabled() bool {
+func (u Type) UnitGlobalDisabled() bool {
 	for _, ud := range DisabledRepoUnits {
 		if u == ud {
 			return true
@@ -148,7 +149,7 @@ func (u UnitType) UnitGlobalDisabled() bool {
 }
 
 // CanDisable checks if this unit type can be disabled.
-func (u *UnitType) CanDisable() bool {
+func (u *Type) CanDisable() bool {
 	for _, mu := range MustRepoUnits {
 		if *u == mu {
 			return false
@@ -158,7 +159,7 @@ func (u *UnitType) CanDisable() bool {
 }
 
 // CanBeDefault checks if the unit type can be a default repo unit
-func (u *UnitType) CanBeDefault() bool {
+func (u *Type) CanBeDefault() bool {
 	for _, nadU := range NotAllowedDefaultRepoUnits {
 		if *u == nadU {
 			return false
@@ -169,7 +170,7 @@ func (u *UnitType) CanBeDefault() bool {
 
 // Unit is a section of one repository
 type Unit struct {
-	Type    UnitType
+	Type    Type
 	NameKey string
 	URI     string
 	DescKey string
@@ -183,7 +184,7 @@ func (u *Unit) CanDisable() bool {
 
 // IsLessThan compares order of two units
 func (u Unit) IsLessThan(unit Unit) bool {
-	if (u.Type == UnitTypeExternalTracker || u.Type == UnitTypeExternalWiki) && unit.Type != UnitTypeExternalTracker && unit.Type != UnitTypeExternalWiki {
+	if (u.Type == TypeExternalTracker || u.Type == TypeExternalWiki) && unit.Type != TypeExternalTracker && unit.Type != TypeExternalWiki {
 		return false
 	}
 	return u.Idx < unit.Idx
@@ -192,7 +193,7 @@ func (u Unit) IsLessThan(unit Unit) bool {
 // Enumerate all the units
 var (
 	UnitCode = Unit{
-		UnitTypeCode,
+		TypeCode,
 		"repo.code",
 		"/",
 		"repo.code.desc",
@@ -200,7 +201,7 @@ var (
 	}
 
 	UnitIssues = Unit{
-		UnitTypeIssues,
+		TypeIssues,
 		"repo.issues",
 		"/issues",
 		"repo.issues.desc",
@@ -208,7 +209,7 @@ var (
 	}
 
 	UnitExternalTracker = Unit{
-		UnitTypeExternalTracker,
+		TypeExternalTracker,
 		"repo.ext_issues",
 		"/issues",
 		"repo.ext_issues.desc",
@@ -216,7 +217,7 @@ var (
 	}
 
 	UnitPullRequests = Unit{
-		UnitTypePullRequests,
+		TypePullRequests,
 		"repo.pulls",
 		"/pulls",
 		"repo.pulls.desc",
@@ -224,7 +225,7 @@ var (
 	}
 
 	UnitReleases = Unit{
-		UnitTypeReleases,
+		TypeReleases,
 		"repo.releases",
 		"/releases",
 		"repo.releases.desc",
@@ -232,7 +233,7 @@ var (
 	}
 
 	UnitWiki = Unit{
-		UnitTypeWiki,
+		TypeWiki,
 		"repo.wiki",
 		"/wiki",
 		"repo.wiki.desc",
@@ -240,7 +241,7 @@ var (
 	}
 
 	UnitExternalWiki = Unit{
-		UnitTypeExternalWiki,
+		TypeExternalWiki,
 		"repo.ext_wiki",
 		"/wiki",
 		"repo.ext_wiki.desc",
@@ -248,7 +249,7 @@ var (
 	}
 
 	UnitProjects = Unit{
-		UnitTypeProjects,
+		TypeProjects,
 		"repo.projects",
 		"/projects",
 		"repo.projects.desc",
@@ -256,20 +257,20 @@ var (
 	}
 
 	// Units contains all the units
-	Units = map[UnitType]Unit{
-		UnitTypeCode:            UnitCode,
-		UnitTypeIssues:          UnitIssues,
-		UnitTypeExternalTracker: UnitExternalTracker,
-		UnitTypePullRequests:    UnitPullRequests,
-		UnitTypeReleases:        UnitReleases,
-		UnitTypeWiki:            UnitWiki,
-		UnitTypeExternalWiki:    UnitExternalWiki,
-		UnitTypeProjects:        UnitProjects,
+	Units = map[Type]Unit{
+		TypeCode:            UnitCode,
+		TypeIssues:          UnitIssues,
+		TypeExternalTracker: UnitExternalTracker,
+		TypePullRequests:    UnitPullRequests,
+		TypeReleases:        UnitReleases,
+		TypeWiki:            UnitWiki,
+		TypeExternalWiki:    UnitExternalWiki,
+		TypeProjects:        UnitProjects,
 	}
 )
 
 // FindUnitTypes give the unit key name and return unit
-func FindUnitTypes(nameKeys ...string) (res []UnitType) {
+func FindUnitTypes(nameKeys ...string) (res []Type) {
 	for _, key := range nameKeys {
 		for t, u := range Units {
 			if strings.EqualFold(key, u.NameKey) {
diff --git a/models/user.go b/models/user.go
index dde5d0e180..bf4444802f 100644
--- a/models/user.go
+++ b/models/user.go
@@ -22,6 +22,7 @@ import (
 
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/models/login"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
@@ -559,7 +560,7 @@ func (u *User) GetRepositories(listOpts db.ListOptions, names ...string) (err er
 
 // GetRepositoryIDs returns repositories IDs where user owned and has unittypes
 // Caller shall check that units is not globally disabled
-func (u *User) GetRepositoryIDs(units ...UnitType) ([]int64, error) {
+func (u *User) GetRepositoryIDs(units ...unit.Type) ([]int64, error) {
 	var ids []int64
 
 	sess := db.GetEngine(db.DefaultContext).Table("repository").Cols("repository.id")
@@ -574,7 +575,7 @@ func (u *User) GetRepositoryIDs(units ...UnitType) ([]int64, error) {
 
 // GetActiveRepositoryIDs returns non-archived repositories IDs where user owned and has unittypes
 // Caller shall check that units is not globally disabled
-func (u *User) GetActiveRepositoryIDs(units ...UnitType) ([]int64, error) {
+func (u *User) GetActiveRepositoryIDs(units ...unit.Type) ([]int64, error) {
 	var ids []int64
 
 	sess := db.GetEngine(db.DefaultContext).Table("repository").Cols("repository.id")
@@ -591,7 +592,7 @@ func (u *User) GetActiveRepositoryIDs(units ...UnitType) ([]int64, error) {
 
 // GetOrgRepositoryIDs returns repositories IDs where user's team owned and has unittypes
 // Caller shall check that units is not globally disabled
-func (u *User) GetOrgRepositoryIDs(units ...UnitType) ([]int64, error) {
+func (u *User) GetOrgRepositoryIDs(units ...unit.Type) ([]int64, error) {
 	var ids []int64
 
 	if err := db.GetEngine(db.DefaultContext).Table("repository").
@@ -612,7 +613,7 @@ func (u *User) GetOrgRepositoryIDs(units ...UnitType) ([]int64, error) {
 
 // GetActiveOrgRepositoryIDs returns non-archived repositories IDs where user's team owned and has unittypes
 // Caller shall check that units is not globally disabled
-func (u *User) GetActiveOrgRepositoryIDs(units ...UnitType) ([]int64, error) {
+func (u *User) GetActiveOrgRepositoryIDs(units ...unit.Type) ([]int64, error) {
 	var ids []int64
 
 	if err := db.GetEngine(db.DefaultContext).Table("repository").
@@ -634,7 +635,7 @@ func (u *User) GetActiveOrgRepositoryIDs(units ...UnitType) ([]int64, error) {
 
 // GetAccessRepoIDs returns all repositories IDs where user's or user is a team member organizations
 // Caller shall check that units is not globally disabled
-func (u *User) GetAccessRepoIDs(units ...UnitType) ([]int64, error) {
+func (u *User) GetAccessRepoIDs(units ...unit.Type) ([]int64, error) {
 	ids, err := u.GetRepositoryIDs(units...)
 	if err != nil {
 		return nil, err
@@ -648,7 +649,7 @@ func (u *User) GetAccessRepoIDs(units ...UnitType) ([]int64, error) {
 
 // GetActiveAccessRepoIDs returns all non-archived repositories IDs where user's or user is a team member organizations
 // Caller shall check that units is not globally disabled
-func (u *User) GetActiveAccessRepoIDs(units ...UnitType) ([]int64, error) {
+func (u *User) GetActiveAccessRepoIDs(units ...unit.Type) ([]int64, error) {
 	ids, err := u.GetActiveRepositoryIDs(units...)
 	if err != nil {
 		return nil, err
diff --git a/modules/context/context.go b/modules/context/context.go
index f652d3845a..cb7131907e 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -21,6 +21,7 @@ import (
 	"time"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	mc "code.gitea.io/gitea/modules/cache"
 	"code.gitea.io/gitea/modules/json"
@@ -90,7 +91,7 @@ func (ctx *Context) IsUserRepoAdmin() bool {
 }
 
 // IsUserRepoWriter returns true if current user has write privilege in current repo
-func (ctx *Context) IsUserRepoWriter(unitTypes []models.UnitType) bool {
+func (ctx *Context) IsUserRepoWriter(unitTypes []unit.Type) bool {
 	for _, unitType := range unitTypes {
 		if ctx.Repo.CanWrite(unitType) {
 			return true
@@ -101,7 +102,7 @@ func (ctx *Context) IsUserRepoWriter(unitTypes []models.UnitType) bool {
 }
 
 // IsUserRepoReaderSpecific returns true if current user can read current repo's specific part
-func (ctx *Context) IsUserRepoReaderSpecific(unitType models.UnitType) bool {
+func (ctx *Context) IsUserRepoReaderSpecific(unitType unit.Type) bool {
 	return ctx.Repo.CanRead(unitType)
 }
 
@@ -733,10 +734,10 @@ func Contexter() func(next http.Handler) http.Handler {
 
 			ctx.Data["ManifestData"] = setting.ManifestData
 
-			ctx.Data["UnitWikiGlobalDisabled"] = models.UnitTypeWiki.UnitGlobalDisabled()
-			ctx.Data["UnitIssuesGlobalDisabled"] = models.UnitTypeIssues.UnitGlobalDisabled()
-			ctx.Data["UnitPullsGlobalDisabled"] = models.UnitTypePullRequests.UnitGlobalDisabled()
-			ctx.Data["UnitProjectsGlobalDisabled"] = models.UnitTypeProjects.UnitGlobalDisabled()
+			ctx.Data["UnitWikiGlobalDisabled"] = unit.TypeWiki.UnitGlobalDisabled()
+			ctx.Data["UnitIssuesGlobalDisabled"] = unit.TypeIssues.UnitGlobalDisabled()
+			ctx.Data["UnitPullsGlobalDisabled"] = unit.TypePullRequests.UnitGlobalDisabled()
+			ctx.Data["UnitProjectsGlobalDisabled"] = unit.TypeProjects.UnitGlobalDisabled()
 
 			ctx.Data["i18n"] = locale
 			ctx.Data["Tr"] = i18n.Tr
diff --git a/modules/context/permission.go b/modules/context/permission.go
index b9cdf93de2..2b87aa4591 100644
--- a/modules/context/permission.go
+++ b/modules/context/permission.go
@@ -5,7 +5,7 @@
 package context
 
 import (
-	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 )
 
@@ -20,7 +20,7 @@ func RequireRepoAdmin() func(ctx *Context) {
 }
 
 // RequireRepoWriter returns a middleware for requiring repository write to the specify unitType
-func RequireRepoWriter(unitType models.UnitType) func(ctx *Context) {
+func RequireRepoWriter(unitType unit.Type) func(ctx *Context) {
 	return func(ctx *Context) {
 		if !ctx.Repo.CanWrite(unitType) {
 			ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
@@ -30,7 +30,7 @@ func RequireRepoWriter(unitType models.UnitType) func(ctx *Context) {
 }
 
 // RequireRepoWriterOr returns a middleware for requiring repository write to one of the unit permission
-func RequireRepoWriterOr(unitTypes ...models.UnitType) func(ctx *Context) {
+func RequireRepoWriterOr(unitTypes ...unit.Type) func(ctx *Context) {
 	return func(ctx *Context) {
 		for _, unitType := range unitTypes {
 			if ctx.Repo.CanWrite(unitType) {
@@ -42,7 +42,7 @@ func RequireRepoWriterOr(unitTypes ...models.UnitType) func(ctx *Context) {
 }
 
 // RequireRepoReader returns a middleware for requiring repository read to the specify unitType
-func RequireRepoReader(unitType models.UnitType) func(ctx *Context) {
+func RequireRepoReader(unitType unit.Type) func(ctx *Context) {
 	return func(ctx *Context) {
 		if !ctx.Repo.CanRead(unitType) {
 			if log.IsTrace() {
@@ -68,7 +68,7 @@ func RequireRepoReader(unitType models.UnitType) func(ctx *Context) {
 }
 
 // RequireRepoReaderOr returns a middleware for requiring repository write to one of the unit permission
-func RequireRepoReaderOr(unitTypes ...models.UnitType) func(ctx *Context) {
+func RequireRepoReaderOr(unitTypes ...unit.Type) func(ctx *Context) {
 	return func(ctx *Context) {
 		for _, unitType := range unitTypes {
 			if ctx.Repo.CanRead(unitType) {
diff --git a/modules/context/repo.go b/modules/context/repo.go
index 88f4d27658..d5763c78a3 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -14,6 +14,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	unit_model "code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/cache"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
@@ -72,12 +73,12 @@ type Repository struct {
 
 // CanEnableEditor returns true if repository is editable and user has proper access level.
 func (r *Repository) CanEnableEditor() bool {
-	return r.Permission.CanWrite(models.UnitTypeCode) && r.Repository.CanEnableEditor() && r.IsViewBranch && !r.Repository.IsArchived
+	return r.Permission.CanWrite(unit_model.TypeCode) && r.Repository.CanEnableEditor() && r.IsViewBranch && !r.Repository.IsArchived
 }
 
 // CanCreateBranch returns true if repository is editable and user has proper access level.
 func (r *Repository) CanCreateBranch() bool {
-	return r.Permission.CanWrite(models.UnitTypeCode) && r.Repository.CanCreateBranch()
+	return r.Permission.CanWrite(unit_model.TypeCode) && r.Repository.CanCreateBranch()
 }
 
 // RepoMustNotBeArchived checks if a repo is archived
@@ -276,7 +277,7 @@ func RetrieveTemplateRepo(ctx *Context, repo *models.Repository) {
 		return
 	}
 
-	if !perm.CanRead(models.UnitTypeCode) {
+	if !perm.CanRead(unit_model.TypeCode) {
 		repo.TemplateID = 0
 	}
 }
@@ -461,7 +462,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
 	ctx.Data["RepoLink"] = ctx.Repo.RepoLink
 	ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
 
-	unit, err := ctx.Repo.Repository.GetUnit(models.UnitTypeExternalTracker)
+	unit, err := ctx.Repo.Repository.GetUnit(unit_model.TypeExternalTracker)
 	if err == nil {
 		ctx.Data["RepoExternalIssuesLink"] = unit.ExternalTrackerConfig().ExternalTrackerURL
 	}
@@ -485,9 +486,9 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
 	ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
 	ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
 	ctx.Data["RepoOwnerIsOrganization"] = repo.Owner.IsOrganization()
-	ctx.Data["CanWriteCode"] = ctx.Repo.CanWrite(models.UnitTypeCode)
-	ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(models.UnitTypeIssues)
-	ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(models.UnitTypePullRequests)
+	ctx.Data["CanWriteCode"] = ctx.Repo.CanWrite(unit_model.TypeCode)
+	ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(unit_model.TypeIssues)
+	ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(unit_model.TypePullRequests)
 
 	if ctx.Data["CanSignedUserFork"], err = ctx.Repo.Repository.CanUserFork(ctx.User); err != nil {
 		ctx.ServerError("CanUserFork", err)
@@ -577,7 +578,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
 	ctx.Data["CommitID"] = ctx.Repo.CommitID
 
 	// People who have push access or have forked repository can propose a new pull request.
-	canPush := ctx.Repo.CanWrite(models.UnitTypeCode) || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID))
+	canPush := ctx.Repo.CanWrite(unit_model.TypeCode) || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID))
 	canCompare := false
 
 	// Pull request is allowed if this is a fork repository
@@ -897,14 +898,14 @@ func GitHookService() func(ctx *Context) {
 // UnitTypes returns a middleware to set unit types to context variables.
 func UnitTypes() func(ctx *Context) {
 	return func(ctx *Context) {
-		ctx.Data["UnitTypeCode"] = models.UnitTypeCode
-		ctx.Data["UnitTypeIssues"] = models.UnitTypeIssues
-		ctx.Data["UnitTypePullRequests"] = models.UnitTypePullRequests
-		ctx.Data["UnitTypeReleases"] = models.UnitTypeReleases
-		ctx.Data["UnitTypeWiki"] = models.UnitTypeWiki
-		ctx.Data["UnitTypeExternalWiki"] = models.UnitTypeExternalWiki
-		ctx.Data["UnitTypeExternalTracker"] = models.UnitTypeExternalTracker
-		ctx.Data["UnitTypeProjects"] = models.UnitTypeProjects
+		ctx.Data["UnitTypeCode"] = unit_model.TypeCode
+		ctx.Data["UnitTypeIssues"] = unit_model.TypeIssues
+		ctx.Data["UnitTypePullRequests"] = unit_model.TypePullRequests
+		ctx.Data["UnitTypeReleases"] = unit_model.TypeReleases
+		ctx.Data["UnitTypeWiki"] = unit_model.TypeWiki
+		ctx.Data["UnitTypeExternalWiki"] = unit_model.TypeExternalWiki
+		ctx.Data["UnitTypeExternalTracker"] = unit_model.TypeExternalTracker
+		ctx.Data["UnitTypeProjects"] = unit_model.TypeProjects
 	}
 }
 
diff --git a/modules/convert/convert.go b/modules/convert/convert.go
index 2960f7741a..9c5e2037c5 100644
--- a/modules/convert/convert.go
+++ b/modules/convert/convert.go
@@ -13,6 +13,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/login"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	api "code.gitea.io/gitea/modules/structs"
@@ -35,7 +36,7 @@ func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit, bp *models.
 		var hasPerm bool
 		var err error
 		if user != nil {
-			hasPerm, err = models.HasAccessUnit(user, repo, models.UnitTypeCode, models.AccessModeWrite)
+			hasPerm, err = models.HasAccessUnit(user, repo, unit.TypeCode, models.AccessModeWrite)
 			if err != nil {
 				return nil, err
 			}
diff --git a/modules/convert/repository.go b/modules/convert/repository.go
index 7f3d67137f..bb8217908d 100644
--- a/modules/convert/repository.go
+++ b/modules/convert/repository.go
@@ -6,6 +6,7 @@ package convert
 
 import (
 	"code.gitea.io/gitea/models"
+	unit_model "code.gitea.io/gitea/models/unit"
 	api "code.gitea.io/gitea/modules/structs"
 )
 
@@ -37,7 +38,7 @@ func innerToRepo(repo *models.Repository, mode models.AccessMode, isParent bool)
 	hasIssues := false
 	var externalTracker *api.ExternalTracker
 	var internalTracker *api.InternalTracker
-	if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil {
+	if unit, err := repo.GetUnit(unit_model.TypeIssues); err == nil {
 		config := unit.IssuesConfig()
 		hasIssues = true
 		internalTracker = &api.InternalTracker{
@@ -45,7 +46,7 @@ func innerToRepo(repo *models.Repository, mode models.AccessMode, isParent bool)
 			AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime,
 			EnableIssueDependencies:          config.EnableDependencies,
 		}
-	} else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil {
+	} else if unit, err := repo.GetUnit(unit_model.TypeExternalTracker); err == nil {
 		config := unit.ExternalTrackerConfig()
 		hasIssues = true
 		externalTracker = &api.ExternalTracker{
@@ -56,9 +57,9 @@ func innerToRepo(repo *models.Repository, mode models.AccessMode, isParent bool)
 	}
 	hasWiki := false
 	var externalWiki *api.ExternalWiki
-	if _, err := repo.GetUnit(models.UnitTypeWiki); err == nil {
+	if _, err := repo.GetUnit(unit_model.TypeWiki); err == nil {
 		hasWiki = true
-	} else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil {
+	} else if unit, err := repo.GetUnit(unit_model.TypeExternalWiki); err == nil {
 		hasWiki = true
 		config := unit.ExternalWikiConfig()
 		externalWiki = &api.ExternalWiki{
@@ -72,7 +73,7 @@ func innerToRepo(repo *models.Repository, mode models.AccessMode, isParent bool)
 	allowRebaseMerge := false
 	allowSquash := false
 	defaultMergeStyle := models.MergeStyleMerge
-	if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil {
+	if unit, err := repo.GetUnit(unit_model.TypePullRequests); err == nil {
 		config := unit.PullRequestsConfig()
 		hasPullRequests = true
 		ignoreWhitespaceConflicts = config.IgnoreWhitespaceConflicts
@@ -83,7 +84,7 @@ func innerToRepo(repo *models.Repository, mode models.AccessMode, isParent bool)
 		defaultMergeStyle = config.GetDefaultMergeStyle()
 	}
 	hasProjects := false
-	if _, err := repo.GetUnit(models.UnitTypeProjects); err == nil {
+	if _, err := repo.GetUnit(unit_model.TypeProjects); err == nil {
 		hasProjects = true
 	}
 
diff --git a/modules/doctor/fix16961.go b/modules/doctor/fix16961.go
index 60cc5ffe2f..e0e44b414b 100644
--- a/modules/doctor/fix16961.go
+++ b/modules/doctor/fix16961.go
@@ -10,6 +10,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/timeutil"
 	"xorm.io/builder"
@@ -212,34 +213,34 @@ func fixBrokenRepoUnit16961(repoUnit *models.RepoUnit, bs []byte) (fixed bool, e
 		return false, nil
 	}
 
-	switch models.UnitType(repoUnit.Type) {
-	case models.UnitTypeCode, models.UnitTypeReleases, models.UnitTypeWiki, models.UnitTypeProjects:
+	switch unit.Type(repoUnit.Type) {
+	case unit.TypeCode, unit.TypeReleases, unit.TypeWiki, unit.TypeProjects:
 		cfg := &models.UnitConfig{}
 		repoUnit.Config = cfg
 		if fixed, err := fixUnitConfig16961(bs, cfg); !fixed {
 			return false, err
 		}
-	case models.UnitTypeExternalWiki:
+	case unit.TypeExternalWiki:
 		cfg := &models.ExternalWikiConfig{}
 		repoUnit.Config = cfg
 
 		if fixed, err := fixExternalWikiConfig16961(bs, cfg); !fixed {
 			return false, err
 		}
-	case models.UnitTypeExternalTracker:
+	case unit.TypeExternalTracker:
 		cfg := &models.ExternalTrackerConfig{}
 		repoUnit.Config = cfg
 		if fixed, err := fixExternalTrackerConfig16961(bs, cfg); !fixed {
 			return false, err
 		}
-	case models.UnitTypePullRequests:
+	case unit.TypePullRequests:
 		cfg := &models.PullRequestsConfig{}
 		repoUnit.Config = cfg
 
 		if fixed, err := fixPullRequestsConfig16961(bs, cfg); !fixed {
 			return false, err
 		}
-	case models.UnitTypeIssues:
+	case unit.TypeIssues:
 		cfg := &models.IssuesConfig{}
 		repoUnit.Config = cfg
 		if fixed, err := fixIssuesConfig16961(bs, cfg); !fixed {
@@ -256,7 +257,7 @@ func fixBrokenRepoUnits16961(logger log.Logger, autofix bool) error {
 	type RepoUnit struct {
 		ID          int64
 		RepoID      int64
-		Type        models.UnitType
+		Type        unit.Type
 		Config      []byte
 		CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
 	}
diff --git a/modules/notification/webhook/webhook.go b/modules/notification/webhook/webhook.go
index c767acf134..35f0cdc596 100644
--- a/modules/notification/webhook/webhook.go
+++ b/modules/notification/webhook/webhook.go
@@ -6,6 +6,7 @@ package webhook
 
 import (
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/convert"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
@@ -136,7 +137,7 @@ func (m *webhookNotifier) NotifyMigrateRepository(doer *models.User, u *models.U
 
 func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *models.User, issue *models.Issue, assignee *models.User, removed bool, comment *models.Comment) {
 	if issue.IsPull {
-		mode, _ := models.AccessLevelUnit(doer, issue.Repo, models.UnitTypePullRequests)
+		mode, _ := models.AccessLevelUnit(doer, issue.Repo, unit.TypePullRequests)
 
 		if err := issue.LoadPullRequest(); err != nil {
 			log.Error("LoadPullRequest failed: %v", err)
@@ -160,7 +161,7 @@ func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *models.User, issue *mo
 			return
 		}
 	} else {
-		mode, _ := models.AccessLevelUnit(doer, issue.Repo, models.UnitTypeIssues)
+		mode, _ := models.AccessLevelUnit(doer, issue.Repo, unit.TypeIssues)
 		apiIssue := &api.IssuePayload{
 			Index:      issue.Index,
 			Issue:      convert.ToAPIIssue(issue),
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 70d7cb40f8..8f852a96ce 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -70,6 +70,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
@@ -253,7 +254,7 @@ func reqAdmin() func(ctx *context.APIContext) {
 }
 
 // reqRepoWriter user should have a permission to write to a repo, or be a site admin
-func reqRepoWriter(unitTypes ...models.UnitType) func(ctx *context.APIContext) {
+func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) {
 	return func(ctx *context.APIContext) {
 		if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
 			ctx.Error(http.StatusForbidden, "reqRepoWriter", "user should have a permission to write to a repo")
@@ -263,7 +264,7 @@ func reqRepoWriter(unitTypes ...models.UnitType) func(ctx *context.APIContext) {
 }
 
 // reqRepoReader user should have specific read permission or be a repo admin or a site admin
-func reqRepoReader(unitType models.UnitType) func(ctx *context.APIContext) {
+func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) {
 	return func(ctx *context.APIContext) {
 		if !ctx.IsUserRepoReaderSpecific(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
 			ctx.Error(http.StatusForbidden, "reqRepoReader", "user should have specific read permission or be a repo admin or a site admin")
@@ -450,19 +451,19 @@ func orgAssignment(args ...bool) func(ctx *context.APIContext) {
 }
 
 func mustEnableIssues(ctx *context.APIContext) {
-	if !ctx.Repo.CanRead(models.UnitTypeIssues) {
+	if !ctx.Repo.CanRead(unit.TypeIssues) {
 		if log.IsTrace() {
 			if ctx.IsSigned {
 				log.Trace("Permission Denied: User %-v cannot read %-v in Repo %-v\n"+
 					"User in Repo has Permissions: %-+v",
 					ctx.User,
-					models.UnitTypeIssues,
+					unit.TypeIssues,
 					ctx.Repo.Repository,
 					ctx.Repo.Permission)
 			} else {
 				log.Trace("Permission Denied: Anonymous user cannot read %-v in Repo %-v\n"+
 					"Anonymous user in Repo has Permissions: %-+v",
-					models.UnitTypeIssues,
+					unit.TypeIssues,
 					ctx.Repo.Repository,
 					ctx.Repo.Permission)
 			}
@@ -473,19 +474,19 @@ func mustEnableIssues(ctx *context.APIContext) {
 }
 
 func mustAllowPulls(ctx *context.APIContext) {
-	if !(ctx.Repo.Repository.CanEnablePulls() && ctx.Repo.CanRead(models.UnitTypePullRequests)) {
+	if !(ctx.Repo.Repository.CanEnablePulls() && ctx.Repo.CanRead(unit.TypePullRequests)) {
 		if ctx.Repo.Repository.CanEnablePulls() && log.IsTrace() {
 			if ctx.IsSigned {
 				log.Trace("Permission Denied: User %-v cannot read %-v in Repo %-v\n"+
 					"User in Repo has Permissions: %-+v",
 					ctx.User,
-					models.UnitTypePullRequests,
+					unit.TypePullRequests,
 					ctx.Repo.Repository,
 					ctx.Repo.Permission)
 			} else {
 				log.Trace("Permission Denied: Anonymous user cannot read %-v in Repo %-v\n"+
 					"Anonymous user in Repo has Permissions: %-+v",
-					models.UnitTypePullRequests,
+					unit.TypePullRequests,
 					ctx.Repo.Repository,
 					ctx.Repo.Permission)
 			}
@@ -496,22 +497,22 @@ func mustAllowPulls(ctx *context.APIContext) {
 }
 
 func mustEnableIssuesOrPulls(ctx *context.APIContext) {
-	if !ctx.Repo.CanRead(models.UnitTypeIssues) &&
-		!(ctx.Repo.Repository.CanEnablePulls() && ctx.Repo.CanRead(models.UnitTypePullRequests)) {
+	if !ctx.Repo.CanRead(unit.TypeIssues) &&
+		!(ctx.Repo.Repository.CanEnablePulls() && ctx.Repo.CanRead(unit.TypePullRequests)) {
 		if ctx.Repo.Repository.CanEnablePulls() && log.IsTrace() {
 			if ctx.IsSigned {
 				log.Trace("Permission Denied: User %-v cannot read %-v and %-v in Repo %-v\n"+
 					"User in Repo has Permissions: %-+v",
 					ctx.User,
-					models.UnitTypeIssues,
-					models.UnitTypePullRequests,
+					unit.TypeIssues,
+					unit.TypePullRequests,
 					ctx.Repo.Repository,
 					ctx.Repo.Permission)
 			} else {
 				log.Trace("Permission Denied: Anonymous user cannot read %-v and %-v in Repo %-v\n"+
 					"Anonymous user in Repo has Permissions: %-+v",
-					models.UnitTypeIssues,
-					models.UnitTypePullRequests,
+					unit.TypeIssues,
+					unit.TypePullRequests,
 					ctx.Repo.Repository,
 					ctx.Repo.Permission)
 			}
@@ -522,7 +523,7 @@ func mustEnableIssuesOrPulls(ctx *context.APIContext) {
 }
 
 func mustEnableWiki(ctx *context.APIContext) {
-	if !(ctx.Repo.CanRead(models.UnitTypeWiki)) {
+	if !(ctx.Repo.CanRead(unit.TypeWiki)) {
 		ctx.NotFound()
 		return
 	}
@@ -726,7 +727,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
 				m.Combo("").Get(reqAnyRepoReader(), repo.Get).
 					Delete(reqToken(), reqOwner(), repo.Delete).
 					Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), repo.Edit)
-				m.Post("/generate", reqToken(), reqRepoReader(models.UnitTypeCode), bind(api.GenerateRepoOption{}), repo.Generate)
+				m.Post("/generate", reqToken(), reqRepoReader(unit.TypeCode), bind(api.GenerateRepoOption{}), repo.Generate)
 				m.Post("/transfer", reqOwner(), bind(api.TransferRepoOption{}), repo.Transfer)
 				m.Combo("/notifications").
 					Get(reqToken(), notify.ListRepoNotifications).
@@ -763,16 +764,16 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
 						Put(reqAdmin(), repo.AddTeam).
 						Delete(reqAdmin(), repo.DeleteTeam)
 				}, reqToken())
-				m.Get("/raw/*", context.RepoRefForAPI, reqRepoReader(models.UnitTypeCode), repo.GetRawFile)
-				m.Get("/archive/*", reqRepoReader(models.UnitTypeCode), repo.GetArchive)
+				m.Get("/raw/*", context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetRawFile)
+				m.Get("/archive/*", reqRepoReader(unit.TypeCode), repo.GetArchive)
 				m.Combo("/forks").Get(repo.ListForks).
-					Post(reqToken(), reqRepoReader(models.UnitTypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
+					Post(reqToken(), reqRepoReader(unit.TypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
 				m.Group("/branches", func() {
 					m.Get("", repo.ListBranches)
 					m.Get("/*", repo.GetBranch)
-					m.Delete("/*", context.ReferencesGitRepo(false), reqRepoWriter(models.UnitTypeCode), repo.DeleteBranch)
-					m.Post("", reqRepoWriter(models.UnitTypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
-				}, reqRepoReader(models.UnitTypeCode))
+					m.Delete("/*", context.ReferencesGitRepo(false), reqRepoWriter(unit.TypeCode), repo.DeleteBranch)
+					m.Post("", reqRepoWriter(unit.TypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
+				}, reqRepoReader(unit.TypeCode))
 				m.Group("/branch_protections", func() {
 					m.Get("", repo.ListBranchProtections)
 					m.Post("", bind(api.CreateBranchProtectionOption{}), repo.CreateBranchProtection)
@@ -785,9 +786,9 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
 				m.Group("/tags", func() {
 					m.Get("", repo.ListTags)
 					m.Get("/*", repo.GetTag)
-					m.Post("", reqRepoWriter(models.UnitTypeCode), bind(api.CreateTagOption{}), repo.CreateTag)
+					m.Post("", reqRepoWriter(unit.TypeCode), bind(api.CreateTagOption{}), repo.CreateTag)
 					m.Delete("/*", repo.DeleteTag)
-				}, reqRepoReader(models.UnitTypeCode), context.ReferencesGitRepo(true))
+				}, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(true))
 				m.Group("/keys", func() {
 					m.Combo("").Get(repo.ListDeployKeys).
 						Post(bind(api.CreateKeyOption{}), repo.CreateDeployKey)
@@ -801,10 +802,10 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
 				m.Group("/wiki", func() {
 					m.Combo("/page/{pageName}").
 						Get(repo.GetWikiPage).
-						Patch(mustNotBeArchived, reqRepoWriter(models.UnitTypeWiki), bind(api.CreateWikiPageOptions{}), repo.EditWikiPage).
-						Delete(mustNotBeArchived, reqRepoWriter(models.UnitTypeWiki), repo.DeleteWikiPage)
+						Patch(mustNotBeArchived, reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), repo.EditWikiPage).
+						Delete(mustNotBeArchived, reqRepoWriter(unit.TypeWiki), repo.DeleteWikiPage)
 					m.Get("/revisions/{pageName}", repo.ListPageRevisions)
-					m.Post("/new", mustNotBeArchived, reqRepoWriter(models.UnitTypeWiki), bind(api.CreateWikiPageOptions{}), repo.NewWikiPage)
+					m.Post("/new", mustNotBeArchived, reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), repo.NewWikiPage)
 					m.Get("/pages", repo.ListWikiPages)
 				}, mustEnableWiki)
 				m.Group("/issues", func() {
@@ -866,19 +867,19 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
 				}, mustEnableIssuesOrPulls)
 				m.Group("/labels", func() {
 					m.Combo("").Get(repo.ListLabels).
-						Post(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), bind(api.CreateLabelOption{}), repo.CreateLabel)
+						Post(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.CreateLabelOption{}), repo.CreateLabel)
 					m.Combo("/{id}").Get(repo.GetLabel).
-						Patch(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), bind(api.EditLabelOption{}), repo.EditLabel).
-						Delete(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), repo.DeleteLabel)
+						Patch(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.EditLabelOption{}), repo.EditLabel).
+						Delete(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), repo.DeleteLabel)
 				})
 				m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown)
 				m.Post("/markdown/raw", misc.MarkdownRaw)
 				m.Group("/milestones", func() {
 					m.Combo("").Get(repo.ListMilestones).
-						Post(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), bind(api.CreateMilestoneOption{}), repo.CreateMilestone)
+						Post(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.CreateMilestoneOption{}), repo.CreateMilestone)
 					m.Combo("/{id}").Get(repo.GetMilestone).
-						Patch(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), bind(api.EditMilestoneOption{}), repo.EditMilestone).
-						Delete(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), repo.DeleteMilestone)
+						Patch(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.EditMilestoneOption{}), repo.EditMilestone).
+						Delete(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), repo.DeleteMilestone)
 				})
 				m.Get("/stargazers", repo.ListStargazers)
 				m.Get("/subscribers", repo.ListSubscribers)
@@ -889,27 +890,27 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
 				})
 				m.Group("/releases", func() {
 					m.Combo("").Get(repo.ListReleases).
-						Post(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(false), bind(api.CreateReleaseOption{}), repo.CreateRelease)
+						Post(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(false), bind(api.CreateReleaseOption{}), repo.CreateRelease)
 					m.Group("/{id}", func() {
 						m.Combo("").Get(repo.GetRelease).
-							Patch(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(false), bind(api.EditReleaseOption{}), repo.EditRelease).
-							Delete(reqToken(), reqRepoWriter(models.UnitTypeReleases), repo.DeleteRelease)
+							Patch(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(false), bind(api.EditReleaseOption{}), repo.EditRelease).
+							Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteRelease)
 						m.Group("/assets", func() {
 							m.Combo("").Get(repo.ListReleaseAttachments).
-								Post(reqToken(), reqRepoWriter(models.UnitTypeReleases), repo.CreateReleaseAttachment)
+								Post(reqToken(), reqRepoWriter(unit.TypeReleases), repo.CreateReleaseAttachment)
 							m.Combo("/{asset}").Get(repo.GetReleaseAttachment).
-								Patch(reqToken(), reqRepoWriter(models.UnitTypeReleases), bind(api.EditAttachmentOptions{}), repo.EditReleaseAttachment).
-								Delete(reqToken(), reqRepoWriter(models.UnitTypeReleases), repo.DeleteReleaseAttachment)
+								Patch(reqToken(), reqRepoWriter(unit.TypeReleases), bind(api.EditAttachmentOptions{}), repo.EditReleaseAttachment).
+								Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteReleaseAttachment)
 						})
 					})
 					m.Group("/tags", func() {
 						m.Combo("/{tag}").
 							Get(repo.GetReleaseByTag).
-							Delete(reqToken(), reqRepoWriter(models.UnitTypeReleases), repo.DeleteReleaseByTag)
+							Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteReleaseByTag)
 					})
-				}, reqRepoReader(models.UnitTypeReleases))
-				m.Post("/mirror-sync", reqToken(), reqRepoWriter(models.UnitTypeCode), repo.MirrorSync)
-				m.Get("/editorconfig/{filename}", context.RepoRefForAPI, reqRepoReader(models.UnitTypeCode), repo.GetEditorconfig)
+				}, reqRepoReader(unit.TypeReleases))
+				m.Post("/mirror-sync", reqToken(), reqRepoWriter(unit.TypeCode), repo.MirrorSync)
+				m.Get("/editorconfig/{filename}", context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetEditorconfig)
 				m.Group("/pulls", func() {
 					m.Combo("").Get(repo.ListPullRequests).
 						Post(reqToken(), mustNotBeArchived, bind(api.CreatePullRequestOption{}), repo.CreatePullRequest)
@@ -940,18 +941,18 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
 							Delete(reqToken(), bind(api.PullReviewRequestOptions{}), repo.DeleteReviewRequests).
 							Post(reqToken(), bind(api.PullReviewRequestOptions{}), repo.CreateReviewRequests)
 					})
-				}, mustAllowPulls, reqRepoReader(models.UnitTypeCode), context.ReferencesGitRepo(false))
+				}, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(false))
 				m.Group("/statuses", func() {
 					m.Combo("/{sha}").Get(repo.GetCommitStatuses).
 						Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus)
-				}, reqRepoReader(models.UnitTypeCode))
+				}, reqRepoReader(unit.TypeCode))
 				m.Group("/commits", func() {
 					m.Get("", repo.GetAllCommits)
 					m.Group("/{ref}", func() {
 						m.Get("/status", repo.GetCombinedCommitStatusByRef)
 						m.Get("/statuses", repo.GetCommitStatusesByRef)
 					})
-				}, reqRepoReader(models.UnitTypeCode))
+				}, reqRepoReader(unit.TypeCode))
 				m.Group("/git", func() {
 					m.Group("/commits", func() {
 						m.Get("/{sha}", repo.GetSingleCommit)
@@ -963,7 +964,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
 					m.Get("/blobs/{sha}", context.RepoRefForAPI, repo.GetBlob)
 					m.Get("/tags/{sha}", context.RepoRefForAPI, repo.GetAnnotatedTag)
 					m.Get("/notes/{sha}", repo.GetNote)
-				}, reqRepoReader(models.UnitTypeCode))
+				}, reqRepoReader(unit.TypeCode))
 				m.Group("/contents", func() {
 					m.Get("", repo.GetContentsList)
 					m.Get("/*", repo.GetContents)
@@ -971,8 +972,8 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
 						m.Post("", bind(api.CreateFileOptions{}), repo.CreateFile)
 						m.Put("", bind(api.UpdateFileOptions{}), repo.UpdateFile)
 						m.Delete("", bind(api.DeleteFileOptions{}), repo.DeleteFile)
-					}, reqRepoWriter(models.UnitTypeCode), reqToken())
-				}, reqRepoReader(models.UnitTypeCode))
+					}, reqRepoWriter(unit.TypeCode), reqToken())
+				}, reqRepoReader(unit.TypeCode))
 				m.Get("/signing-key.gpg", misc.SigningKey)
 				m.Group("/topics", func() {
 					m.Combo("").Get(repo.ListTopics).
@@ -983,7 +984,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
 					}, reqAdmin())
 				}, reqAnyRepoReader())
 				m.Get("/issue_templates", context.ReferencesGitRepo(false), repo.GetIssueTemplates)
-				m.Get("/languages", reqRepoReader(models.UnitTypeCode), repo.GetLanguages)
+				m.Get("/languages", reqRepoReader(unit.TypeCode), repo.GetLanguages)
 			}, repoAssignment())
 		})
 
diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go
index a84763d6f6..0dc1b68aee 100644
--- a/routers/api/v1/org/team.go
+++ b/routers/api/v1/org/team.go
@@ -9,6 +9,7 @@ import (
 	"net/http"
 
 	"code.gitea.io/gitea/models"
+	unit_model "code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
 	"code.gitea.io/gitea/modules/log"
@@ -172,7 +173,7 @@ func CreateTeam(ctx *context.APIContext) {
 		Authorize:               models.ParseAccessMode(form.Permission),
 	}
 
-	unitTypes := models.FindUnitTypes(form.Units...)
+	unitTypes := unit_model.FindUnitTypes(form.Units...)
 
 	if team.Authorize < models.AccessModeOwner {
 		var units = make([]*models.TeamUnit, 0, len(form.Units))
@@ -260,7 +261,7 @@ func EditTeam(ctx *context.APIContext) {
 	if team.Authorize < models.AccessModeOwner {
 		if len(form.Units) > 0 {
 			var units = make([]*models.TeamUnit, 0, len(form.Units))
-			unitTypes := models.FindUnitTypes(form.Units...)
+			unitTypes := unit_model.FindUnitTypes(form.Units...)
 			for _, tp := range unitTypes {
 				units = append(units, &models.TeamUnit{
 					OrgID: ctx.Org.Team.OrgID,
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go
index d9451b8090..009b8a26d6 100644
--- a/routers/api/v1/repo/file.go
+++ b/routers/api/v1/repo/file.go
@@ -12,6 +12,7 @@ import (
 	"time"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/repofiles"
@@ -182,12 +183,12 @@ func GetEditorconfig(ctx *context.APIContext) {
 
 // canWriteFiles returns true if repository is editable and user has proper access level.
 func canWriteFiles(r *context.Repository) bool {
-	return r.Permission.CanWrite(models.UnitTypeCode) && !r.Repository.IsMirror && !r.Repository.IsArchived
+	return r.Permission.CanWrite(unit.TypeCode) && !r.Repository.IsMirror && !r.Repository.IsArchived
 }
 
 // canReadFiles returns true if repository is readable and user has proper access level.
 func canReadFiles(r *context.Repository) bool {
-	return r.Permission.CanRead(models.UnitTypeCode)
+	return r.Permission.CanRead(unit.TypeCode)
 }
 
 // CreateFile handles API call for creating a file
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index 17a3becd5b..a2454b8618 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -14,6 +14,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
 	issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
@@ -582,7 +583,7 @@ func CreateIssue(ctx *context.APIContext) {
 	//     "$ref": "#/responses/validationError"
 	form := web.GetForm(ctx).(*api.CreateIssueOption)
 	var deadlineUnix timeutil.TimeStamp
-	if form.Deadline != nil && ctx.Repo.CanWrite(models.UnitTypeIssues) {
+	if form.Deadline != nil && ctx.Repo.CanWrite(unit.TypeIssues) {
 		deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
 	}
 
@@ -599,7 +600,7 @@ func CreateIssue(ctx *context.APIContext) {
 
 	var assigneeIDs = make([]int64, 0)
 	var err error
-	if ctx.Repo.CanWrite(models.UnitTypeIssues) {
+	if ctx.Repo.CanWrite(unit.TypeIssues) {
 		issue.MilestoneID = form.Milestone
 		assigneeIDs, err = models.MakeIDsFromAPIAssigneesToAdd(form.Assignee, form.Assignees)
 		if err != nil {
diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go
index e9d8fbab26..f73e63547b 100644
--- a/routers/api/v1/repo/issue_tracked_time.go
+++ b/routers/api/v1/repo/issue_tracked_time.go
@@ -10,6 +10,7 @@ import (
 	"time"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
 	api "code.gitea.io/gitea/modules/structs"
@@ -108,7 +109,7 @@ func ListTrackedTimes(ctx *context.APIContext) {
 
 	cantSetUser := !ctx.User.IsAdmin &&
 		opts.UserID != ctx.User.ID &&
-		!ctx.IsUserRepoWriter([]models.UnitType{models.UnitTypeIssues})
+		!ctx.IsUserRepoWriter([]unit.Type{unit.TypeIssues})
 
 	if cantSetUser {
 		if opts.UserID == 0 {
@@ -527,7 +528,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) {
 
 	cantSetUser := !ctx.User.IsAdmin &&
 		opts.UserID != ctx.User.ID &&
-		!ctx.IsUserRepoWriter([]models.UnitType{models.UnitTypeIssues})
+		!ctx.IsUserRepoWriter([]unit.Type{unit.TypeIssues})
 
 	if cantSetUser {
 		if opts.UserID == 0 {
diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go
index 67d0c7ee1c..c9ac3e8292 100644
--- a/routers/api/v1/repo/mirror.go
+++ b/routers/api/v1/repo/mirror.go
@@ -7,7 +7,7 @@ package repo
 import (
 	"net/http"
 
-	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/setting"
 	mirror_service "code.gitea.io/gitea/services/mirror"
@@ -39,7 +39,7 @@ func MirrorSync(ctx *context.APIContext) {
 
 	repo := ctx.Repo.Repository
 
-	if !ctx.Repo.CanWrite(models.UnitTypeCode) {
+	if !ctx.Repo.CanWrite(unit.TypeCode) {
 		ctx.Error(http.StatusForbidden, "MirrorSync", "Must have write access")
 	}
 
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index f2a1d7fe63..7f377edc3f 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -14,6 +14,7 @@ import (
 	"time"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
 	"code.gitea.io/gitea/modules/git"
@@ -481,7 +482,7 @@ func EditPullRequest(ctx *context.APIContext) {
 	issue := pr.Issue
 	issue.Repo = ctx.Repo.Repository
 
-	if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWrite(models.UnitTypePullRequests) {
+	if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWrite(unit.TypePullRequests) {
 		ctx.Status(http.StatusForbidden)
 		return
 	}
@@ -518,7 +519,7 @@ func EditPullRequest(ctx *context.APIContext) {
 	// Pass one or more user logins to replace the set of assignees on this Issue.
 	// Send an empty array ([]) to clear all assignees from the Issue.
 
-	if ctx.Repo.CanWrite(models.UnitTypePullRequests) && (form.Assignees != nil || len(form.Assignee) > 0) {
+	if ctx.Repo.CanWrite(unit.TypePullRequests) && (form.Assignees != nil || len(form.Assignee) > 0) {
 		err = issue_service.UpdateAssignees(issue, form.Assignee, form.Assignees, ctx.User)
 		if err != nil {
 			if models.IsErrUserNotExist(err) {
@@ -530,7 +531,7 @@ func EditPullRequest(ctx *context.APIContext) {
 		}
 	}
 
-	if ctx.Repo.CanWrite(models.UnitTypePullRequests) && form.Milestone != 0 &&
+	if ctx.Repo.CanWrite(unit.TypePullRequests) && form.Milestone != 0 &&
 		issue.MilestoneID != form.Milestone {
 		oldMilestoneID := issue.MilestoneID
 		issue.MilestoneID = form.Milestone
@@ -540,7 +541,7 @@ func EditPullRequest(ctx *context.APIContext) {
 		}
 	}
 
-	if ctx.Repo.CanWrite(models.UnitTypePullRequests) && form.Labels != nil {
+	if ctx.Repo.CanWrite(unit.TypePullRequests) && form.Labels != nil {
 		labels, err := models.GetLabelsInRepoByIDs(ctx.Repo.Repository.ID, form.Labels)
 		if err != nil {
 			ctx.Error(http.StatusInternalServerError, "GetLabelsInRepoByIDsError", err)
@@ -978,7 +979,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
 		ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
 		return nil, nil, nil, nil, "", ""
 	}
-	if !permBase.CanReadIssuesOrPulls(true) || !permBase.CanRead(models.UnitTypeCode) {
+	if !permBase.CanReadIssuesOrPulls(true) || !permBase.CanRead(unit.TypeCode) {
 		if log.IsTrace() {
 			log.Trace("Permission Denied: User %-v cannot create/read pull requests or cannot read code in Repo %-v\nUser in baseRepo has Permissions: %-+v",
 				ctx.User,
@@ -997,7 +998,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
 		ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
 		return nil, nil, nil, nil, "", ""
 	}
-	if !permHead.CanRead(models.UnitTypeCode) {
+	if !permHead.CanRead(unit.TypeCode) {
 		if log.IsTrace() {
 			log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v",
 				ctx.User,
diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go
index a600a1e33f..08ebde4e0c 100644
--- a/routers/api/v1/repo/release.go
+++ b/routers/api/v1/repo/release.go
@@ -8,6 +8,7 @@ import (
 	"net/http"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
 	api "code.gitea.io/gitea/modules/structs"
@@ -114,7 +115,7 @@ func ListReleases(ctx *context.APIContext) {
 
 	opts := models.FindReleasesOptions{
 		ListOptions:   listOptions,
-		IncludeDrafts: ctx.Repo.AccessMode >= models.AccessModeWrite || ctx.Repo.UnitAccessMode(models.UnitTypeReleases) >= models.AccessModeWrite,
+		IncludeDrafts: ctx.Repo.AccessMode >= models.AccessModeWrite || ctx.Repo.UnitAccessMode(unit.TypeReleases) >= models.AccessModeWrite,
 		IncludeTags:   false,
 		IsDraft:       ctx.FormOptionalBool("draft"),
 		IsPreRelease:  ctx.FormOptionalBool("pre-release"),
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index 0f85d917d1..22f9da614d 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -12,6 +12,7 @@ import (
 	"time"
 
 	"code.gitea.io/gitea/models"
+	unit_model "code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
 	"code.gitea.io/gitea/modules/git"
@@ -735,10 +736,10 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
 	repo := ctx.Repo.Repository
 
 	var units []models.RepoUnit
-	var deleteUnitTypes []models.UnitType
+	var deleteUnitTypes []unit_model.Type
 
 	if opts.HasIssues != nil {
-		if *opts.HasIssues && opts.ExternalTracker != nil && !models.UnitTypeExternalTracker.UnitGlobalDisabled() {
+		if *opts.HasIssues && opts.ExternalTracker != nil && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
 			// Check that values are valid
 			if !validation.IsValidExternalURL(opts.ExternalTracker.ExternalTrackerURL) {
 				err := fmt.Errorf("External tracker URL not valid")
@@ -753,15 +754,15 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
 
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypeExternalTracker,
+				Type:   unit_model.TypeExternalTracker,
 				Config: &models.ExternalTrackerConfig{
 					ExternalTrackerURL:    opts.ExternalTracker.ExternalTrackerURL,
 					ExternalTrackerFormat: opts.ExternalTracker.ExternalTrackerFormat,
 					ExternalTrackerStyle:  opts.ExternalTracker.ExternalTrackerStyle,
 				},
 			})
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues)
-		} else if *opts.HasIssues && opts.ExternalTracker == nil && !models.UnitTypeIssues.UnitGlobalDisabled() {
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
+		} else if *opts.HasIssues && opts.ExternalTracker == nil && !unit_model.TypeIssues.UnitGlobalDisabled() {
 			// Default to built-in tracker
 			var config *models.IssuesConfig
 
@@ -771,7 +772,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
 					AllowOnlyContributorsToTrackTime: opts.InternalTracker.AllowOnlyContributorsToTrackTime,
 					EnableDependencies:               opts.InternalTracker.EnableIssueDependencies,
 				}
-			} else if unit, err := repo.GetUnit(models.UnitTypeIssues); err != nil {
+			} else if unit, err := repo.GetUnit(unit_model.TypeIssues); err != nil {
 				// Unit type doesn't exist so we make a new config file with default values
 				config = &models.IssuesConfig{
 					EnableTimetracker:                true,
@@ -784,22 +785,22 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
 
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypeIssues,
+				Type:   unit_model.TypeIssues,
 				Config: config,
 			})
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker)
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
 		} else if !*opts.HasIssues {
-			if !models.UnitTypeExternalTracker.UnitGlobalDisabled() {
-				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker)
+			if !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
+				deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
 			}
-			if !models.UnitTypeIssues.UnitGlobalDisabled() {
-				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues)
+			if !unit_model.TypeIssues.UnitGlobalDisabled() {
+				deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
 			}
 		}
 	}
 
 	if opts.HasWiki != nil {
-		if *opts.HasWiki && opts.ExternalWiki != nil && !models.UnitTypeExternalWiki.UnitGlobalDisabled() {
+		if *opts.HasWiki && opts.ExternalWiki != nil && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
 			// Check that values are valid
 			if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) {
 				err := fmt.Errorf("External wiki URL not valid")
@@ -809,36 +810,36 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
 
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypeExternalWiki,
+				Type:   unit_model.TypeExternalWiki,
 				Config: &models.ExternalWikiConfig{
 					ExternalWikiURL: opts.ExternalWiki.ExternalWikiURL,
 				},
 			})
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki)
-		} else if *opts.HasWiki && opts.ExternalWiki == nil && !models.UnitTypeWiki.UnitGlobalDisabled() {
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
+		} else if *opts.HasWiki && opts.ExternalWiki == nil && !unit_model.TypeWiki.UnitGlobalDisabled() {
 			config := &models.UnitConfig{}
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypeWiki,
+				Type:   unit_model.TypeWiki,
 				Config: config,
 			})
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki)
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
 		} else if !*opts.HasWiki {
-			if !models.UnitTypeExternalWiki.UnitGlobalDisabled() {
-				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki)
+			if !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
+				deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
 			}
-			if !models.UnitTypeWiki.UnitGlobalDisabled() {
-				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki)
+			if !unit_model.TypeWiki.UnitGlobalDisabled() {
+				deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
 			}
 		}
 	}
 
 	if opts.HasPullRequests != nil {
-		if *opts.HasPullRequests && !models.UnitTypePullRequests.UnitGlobalDisabled() {
+		if *opts.HasPullRequests && !unit_model.TypePullRequests.UnitGlobalDisabled() {
 			// We do allow setting individual PR settings through the API, so
 			// we get the config settings and then set them
 			// if those settings were provided in the opts.
-			unit, err := repo.GetUnit(models.UnitTypePullRequests)
+			unit, err := repo.GetUnit(unit_model.TypePullRequests)
 			var config *models.PullRequestsConfig
 			if err != nil {
 				// Unit type doesn't exist so we make a new config file with default values
@@ -887,22 +888,22 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
 
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypePullRequests,
+				Type:   unit_model.TypePullRequests,
 				Config: config,
 			})
-		} else if !*opts.HasPullRequests && !models.UnitTypePullRequests.UnitGlobalDisabled() {
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypePullRequests)
+		} else if !*opts.HasPullRequests && !unit_model.TypePullRequests.UnitGlobalDisabled() {
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
 		}
 	}
 
-	if opts.HasProjects != nil && !models.UnitTypeProjects.UnitGlobalDisabled() {
+	if opts.HasProjects != nil && !unit_model.TypeProjects.UnitGlobalDisabled() {
 		if *opts.HasProjects {
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypeProjects,
+				Type:   unit_model.TypeProjects,
 			})
 		} else {
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeProjects)
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeProjects)
 		}
 	}
 
diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go
index 3e4995376c..04c334b38f 100644
--- a/routers/private/hook_pre_receive.go
+++ b/routers/private/hook_pre_receive.go
@@ -12,6 +12,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	gitea_context "code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
@@ -58,7 +59,7 @@ func (ctx *preReceiveContext) Perm() *models.Permission {
 // CanWriteCode returns true if can write code
 func (ctx *preReceiveContext) CanWriteCode() bool {
 	if !ctx.checkedCanWriteCode {
-		ctx.canWriteCode = ctx.Perm().CanWrite(models.UnitTypeCode)
+		ctx.canWriteCode = ctx.Perm().CanWrite(unit.TypeCode)
 		ctx.checkedCanWriteCode = true
 	}
 	return ctx.canWriteCode
@@ -81,7 +82,7 @@ func (ctx *preReceiveContext) AssertCanWriteCode() bool {
 // CanCreatePullRequest returns true if can create pull requests
 func (ctx *preReceiveContext) CanCreatePullRequest() bool {
 	if !ctx.checkedCanCreatePullRequest {
-		ctx.canCreatePullRequest = ctx.Perm().CanRead(models.UnitTypePullRequests)
+		ctx.canCreatePullRequest = ctx.Perm().CanRead(unit.TypePullRequests)
 		ctx.checkedCanCreatePullRequest = true
 	}
 	return ctx.canCreatePullRequest
diff --git a/routers/private/serv.go b/routers/private/serv.go
index b3edd7fc24..a7ef980d2d 100644
--- a/routers/private/serv.go
+++ b/routers/private/serv.go
@@ -11,6 +11,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
@@ -93,12 +94,12 @@ func ServCommand(ctx *context.PrivateContext) {
 	}
 
 	// The default unit we're trying to look at is code
-	unitType := models.UnitTypeCode
+	unitType := unit.TypeCode
 
 	// Unless we're a wiki...
 	if strings.HasSuffix(repoName, ".wiki") {
 		// in which case we need to look at the wiki
-		unitType = models.UnitTypeWiki
+		unitType = unit.TypeWiki
 		// And we'd better munge the reponame and tell downstream we're looking at a wiki
 		results.IsWiki = true
 		results.RepoName = repoName[:len(repoName)-5]
@@ -295,7 +296,7 @@ func ServCommand(ctx *context.PrivateContext) {
 			}
 		} else {
 			// Because of the special ref "refs/for" we will need to delay write permission check
-			if git.SupportProcReceive && unitType == models.UnitTypeCode {
+			if git.SupportProcReceive && unitType == unit.TypeCode {
 				mode = models.AccessModeRead
 			}
 
@@ -362,7 +363,7 @@ func ServCommand(ctx *context.PrivateContext) {
 
 	if results.IsWiki {
 		// Ensure the wiki is enabled before we allow access to it
-		if _, err := repo.GetUnit(models.UnitTypeWiki); err != nil {
+		if _, err := repo.GetUnit(unit.TypeWiki); err != nil {
 			if models.IsErrUnitTypeNotExist(err) {
 				ctx.JSON(http.StatusForbidden, private.ErrServCommand{
 					Results: results,
diff --git a/routers/web/explore/code.go b/routers/web/explore/code.go
index a9b159468d..6ff48be0f8 100644
--- a/routers/web/explore/code.go
+++ b/routers/web/explore/code.go
@@ -8,6 +8,7 @@ import (
 	"net/http"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	code_indexer "code.gitea.io/gitea/modules/indexer/code"
@@ -77,7 +78,7 @@ func Code(ctx *context.Context) {
 		var rightRepoMap = make(map[int64]*models.Repository, len(repoMaps))
 		repoIDs = make([]int64, 0, len(repoMaps))
 		for id, repo := range repoMaps {
-			if repo.CheckUnitUser(ctx.User, models.UnitTypeCode) {
+			if repo.CheckUnitUser(ctx.User, unit.TypeCode) {
 				rightRepoMap[id] = repo
 				repoIDs = append(repoIDs, id)
 			}
diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go
index c93fcd062b..3fe97142ae 100644
--- a/routers/web/org/teams.go
+++ b/routers/web/org/teams.go
@@ -11,6 +11,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	unit_model "code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/log"
@@ -216,7 +217,7 @@ func NewTeam(ctx *context.Context) {
 	ctx.Data["PageIsOrgTeams"] = true
 	ctx.Data["PageIsOrgTeamsNew"] = true
 	ctx.Data["Team"] = &models.Team{}
-	ctx.Data["Units"] = models.Units
+	ctx.Data["Units"] = unit_model.Units
 	ctx.HTML(http.StatusOK, tplTeamNew)
 }
 
@@ -226,7 +227,7 @@ func NewTeamPost(ctx *context.Context) {
 	ctx.Data["Title"] = ctx.Org.Organization.FullName
 	ctx.Data["PageIsOrgTeams"] = true
 	ctx.Data["PageIsOrgTeamsNew"] = true
-	ctx.Data["Units"] = models.Units
+	ctx.Data["Units"] = unit_model.Units
 	var includesAllRepositories = form.RepoAccess == "all"
 
 	t := &models.Team{
@@ -305,7 +306,7 @@ func EditTeam(ctx *context.Context) {
 	ctx.Data["PageIsOrgTeams"] = true
 	ctx.Data["team_name"] = ctx.Org.Team.Name
 	ctx.Data["desc"] = ctx.Org.Team.Description
-	ctx.Data["Units"] = models.Units
+	ctx.Data["Units"] = unit_model.Units
 	ctx.HTML(http.StatusOK, tplTeamNew)
 }
 
@@ -316,7 +317,7 @@ func EditTeamPost(ctx *context.Context) {
 	ctx.Data["Title"] = ctx.Org.Organization.FullName
 	ctx.Data["PageIsOrgTeams"] = true
 	ctx.Data["Team"] = t
-	ctx.Data["Units"] = models.Units
+	ctx.Data["Units"] = unit_model.Units
 
 	isAuthChanged := false
 	isIncludeAllChanged := false
diff --git a/routers/web/repo/activity.go b/routers/web/repo/activity.go
index f9d248b06e..ae37b51403 100644
--- a/routers/web/repo/activity.go
+++ b/routers/web/repo/activity.go
@@ -9,6 +9,7 @@ import (
 	"time"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 )
@@ -52,10 +53,10 @@ func Activity(ctx *context.Context) {
 
 	var err error
 	if ctx.Data["Activity"], err = models.GetActivityStats(ctx.Repo.Repository, timeFrom,
-		ctx.Repo.CanRead(models.UnitTypeReleases),
-		ctx.Repo.CanRead(models.UnitTypeIssues),
-		ctx.Repo.CanRead(models.UnitTypePullRequests),
-		ctx.Repo.CanRead(models.UnitTypeCode)); err != nil {
+		ctx.Repo.CanRead(unit.TypeReleases),
+		ctx.Repo.CanRead(unit.TypeIssues),
+		ctx.Repo.CanRead(unit.TypePullRequests),
+		ctx.Repo.CanRead(unit.TypeCode)); err != nil {
 		ctx.ServerError("GetActivityStats", err)
 		return
 	}
diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go
index 32cfc2adff..991beeace2 100644
--- a/routers/web/repo/branch.go
+++ b/routers/web/repo/branch.go
@@ -12,6 +12,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/git"
@@ -51,9 +52,9 @@ func Branches(ctx *context.Context) {
 	ctx.Data["IsRepoToolbarBranches"] = true
 	ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
 	ctx.Data["AllowsPulls"] = ctx.Repo.Repository.AllowsPulls()
-	ctx.Data["IsWriter"] = ctx.Repo.CanWrite(models.UnitTypeCode)
+	ctx.Data["IsWriter"] = ctx.Repo.CanWrite(unit.TypeCode)
 	ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
-	ctx.Data["CanPull"] = ctx.Repo.CanWrite(models.UnitTypeCode) || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID))
+	ctx.Data["CanPull"] = ctx.Repo.CanWrite(unit.TypeCode) || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID))
 	ctx.Data["PageIsViewCode"] = true
 	ctx.Data["PageIsBranches"] = true
 
@@ -208,7 +209,7 @@ func loadBranches(ctx *context.Context, skip, limit int) ([]*Branch, int) {
 	log.Debug("loadOneBranch: load default: '%s'", defaultBranch.Name)
 	branches = append(branches, loadOneBranch(ctx, defaultBranch, protectedBranches, repoIDToRepo, repoIDToGitRepo))
 
-	if ctx.Repo.CanWrite(models.UnitTypeCode) {
+	if ctx.Repo.CanWrite(unit.TypeCode) {
 		deletedBranches, err := getDeletedBranches(ctx)
 		if err != nil {
 			ctx.ServerError("getDeletedBranches", err)
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index 555abc1c8b..86ecc2bab1 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -17,6 +17,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/charset"
 	"code.gitea.io/gitea/modules/context"
@@ -384,7 +385,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
 		ctx.ServerError("GetUserRepoPermission", err)
 		return nil
 	}
-	if !permBase.CanRead(models.UnitTypeCode) {
+	if !permBase.CanRead(unit.TypeCode) {
 		if log.IsTrace() {
 			log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in baseRepo has Permissions: %-+v",
 				ctx.User,
@@ -403,7 +404,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
 			ctx.ServerError("GetUserRepoPermission", err)
 			return nil
 		}
-		if !permHead.CanRead(models.UnitTypeCode) {
+		if !permHead.CanRead(unit.TypeCode) {
 			if log.IsTrace() {
 				log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v",
 					ctx.User,
@@ -422,7 +423,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
 	if rootRepo != nil &&
 		rootRepo.ID != ci.HeadRepo.ID &&
 		rootRepo.ID != baseRepo.ID {
-		canRead := rootRepo.CheckUnitUser(ctx.User, models.UnitTypeCode)
+		canRead := rootRepo.CheckUnitUser(ctx.User, unit.TypeCode)
 		if canRead {
 			ctx.Data["RootRepo"] = rootRepo
 			if !fileOnly {
@@ -447,7 +448,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
 		ownForkRepo.ID != ci.HeadRepo.ID &&
 		ownForkRepo.ID != baseRepo.ID &&
 		(rootRepo == nil || ownForkRepo.ID != rootRepo.ID) {
-		canRead := ownForkRepo.CheckUnitUser(ctx.User, models.UnitTypeCode)
+		canRead := ownForkRepo.CheckUnitUser(ctx.User, unit.TypeCode)
 		if canRead {
 			ctx.Data["OwnForkRepo"] = ownForkRepo
 			if !fileOnly {
@@ -542,7 +543,7 @@ func PrepareCompareDiff(
 	if (headCommitID == ci.CompareInfo.MergeBase && !ci.DirectComparison) ||
 		headCommitID == ci.CompareInfo.BaseCommitID {
 		ctx.Data["IsNothingToCompare"] = true
-		if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil {
+		if unit, err := repo.GetUnit(unit.TypePullRequests); err == nil {
 			config := unit.PullRequestsConfig()
 
 			if !config.AutodetectManualMerge {
@@ -736,7 +737,7 @@ func CompareDiff(ctx *context.Context) {
 	ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
 	upload.AddUploadContext(ctx, "comment")
 
-	ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(models.UnitTypePullRequests)
+	ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(unit.TypePullRequests)
 
 	ctx.HTML(http.StatusOK, tplCompare)
 }
diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go
index f272583499..d9f8c20092 100644
--- a/routers/web/repo/editor.go
+++ b/routers/web/repo/editor.go
@@ -12,6 +12,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/charset"
 	"code.gitea.io/gitea/modules/context"
@@ -331,7 +332,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
 		}
 	}
 
-	if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) {
+	if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) {
 		ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
 	} else {
 		ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
@@ -517,7 +518,7 @@ func DeleteFilePost(ctx *context.Context) {
 	}
 
 	ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
-	if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) {
+	if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) {
 		ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
 	} else {
 		treePath := path.Dir(ctx.Repo.TreePath)
@@ -722,7 +723,7 @@ func UploadFilePost(ctx *context.Context) {
 		return
 	}
 
-	if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) {
+	if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) {
 		ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName))
 	} else {
 		ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
diff --git a/routers/web/repo/http.go b/routers/web/repo/http.go
index 162338a959..7c5dcd42be 100644
--- a/routers/web/repo/http.go
+++ b/routers/web/repo/http.go
@@ -22,6 +22,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/login"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
@@ -99,11 +100,11 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
 	}
 
 	isWiki := false
-	var unitType = models.UnitTypeCode
+	var unitType = unit.TypeCode
 	var wikiRepoName string
 	if strings.HasSuffix(reponame, ".wiki") {
 		isWiki = true
-		unitType = models.UnitTypeWiki
+		unitType = unit.TypeWiki
 		wikiRepoName = reponame
 		reponame = reponame[:len(reponame)-5]
 	}
@@ -270,7 +271,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
 
 	if isWiki {
 		// Ensure the wiki is enabled before we allow access to it
-		if _, err := repo.GetUnit(models.UnitTypeWiki); err != nil {
+		if _, err := repo.GetUnit(unit.TypeWiki); err != nil {
 			if models.IsErrUnitTypeNotExist(err) {
 				ctx.HandleText(http.StatusForbidden, "repository wiki is disabled")
 				return
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index 2782e8d629..93b6b7a305 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -17,6 +17,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/convert"
@@ -82,13 +83,13 @@ func MustAllowUserComment(ctx *context.Context) {
 
 // MustEnableIssues check if repository enable internal issues
 func MustEnableIssues(ctx *context.Context) {
-	if !ctx.Repo.CanRead(models.UnitTypeIssues) &&
-		!ctx.Repo.CanRead(models.UnitTypeExternalTracker) {
+	if !ctx.Repo.CanRead(unit.TypeIssues) &&
+		!ctx.Repo.CanRead(unit.TypeExternalTracker) {
 		ctx.NotFound("MustEnableIssues", nil)
 		return
 	}
 
-	unit, err := ctx.Repo.Repository.GetUnit(models.UnitTypeExternalTracker)
+	unit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalTracker)
 	if err == nil {
 		ctx.Redirect(unit.ExternalTrackerConfig().ExternalTrackerURL)
 		return
@@ -97,7 +98,7 @@ func MustEnableIssues(ctx *context.Context) {
 
 // MustAllowPulls check if repository enable pull requests and user have right to do that
 func MustAllowPulls(ctx *context.Context) {
-	if !ctx.Repo.Repository.CanEnablePulls() || !ctx.Repo.CanRead(models.UnitTypePullRequests) {
+	if !ctx.Repo.Repository.CanEnablePulls() || !ctx.Repo.CanRead(unit.TypePullRequests) {
 		ctx.NotFound("MustAllowPulls", nil)
 		return
 	}
@@ -790,7 +791,7 @@ func NewIssue(ctx *context.Context) {
 	body := ctx.FormString("body")
 	ctx.Data["BodyQuery"] = body
 
-	ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanRead(models.UnitTypeProjects)
+	ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanRead(unit.TypeProjects)
 	ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
 	upload.AddUploadContext(ctx, "comment")
 
@@ -828,7 +829,7 @@ func NewIssue(ctx *context.Context) {
 		return
 	}
 
-	ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(models.UnitTypeIssues)
+	ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(unit.TypeIssues)
 
 	ctx.HTML(http.StatusOK, tplIssueNew)
 }
@@ -1065,7 +1066,7 @@ func getBranchData(ctx *context.Context, issue *models.Issue) {
 func ViewIssue(ctx *context.Context) {
 	if ctx.Params(":type") == "issues" {
 		// If issue was requested we check if repo has external tracker and redirect
-		extIssueUnit, err := ctx.Repo.Repository.GetUnit(models.UnitTypeExternalTracker)
+		extIssueUnit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalTracker)
 		if err == nil && extIssueUnit != nil {
 			if extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == markup.IssueNameStyleNumeric || extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == "" {
 				metas := ctx.Repo.Repository.ComposeMetas()
@@ -1114,9 +1115,9 @@ func ViewIssue(ctx *context.Context) {
 		ctx.Data["NewIssueChooseTemplate"] = len(ctx.IssueTemplatesFromDefaultBranch()) > 0
 	}
 
-	if issue.IsPull && !ctx.Repo.CanRead(models.UnitTypeIssues) {
+	if issue.IsPull && !ctx.Repo.CanRead(unit.TypeIssues) {
 		ctx.Data["IssueType"] = "pulls"
-	} else if !issue.IsPull && !ctx.Repo.CanRead(models.UnitTypePullRequests) {
+	} else if !issue.IsPull && !ctx.Repo.CanRead(unit.TypePullRequests) {
 		ctx.Data["IssueType"] = "issues"
 	} else {
 		ctx.Data["IssueType"] = "all"
@@ -1125,7 +1126,7 @@ func ViewIssue(ctx *context.Context) {
 	ctx.Data["RequireHighlightJS"] = true
 	ctx.Data["RequireTribute"] = true
 	ctx.Data["RequireSimpleMDE"] = true
-	ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanRead(models.UnitTypeProjects)
+	ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanRead(unit.TypeProjects)
 	ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
 	upload.AddUploadContext(ctx, "comment")
 
@@ -1224,7 +1225,7 @@ func ViewIssue(ctx *context.Context) {
 	}
 
 	if issue.IsPull {
-		canChooseReviewer := ctx.Repo.CanWrite(models.UnitTypePullRequests)
+		canChooseReviewer := ctx.Repo.CanWrite(unit.TypePullRequests)
 		if !canChooseReviewer && ctx.User != nil && ctx.IsSigned {
 			canChooseReviewer, err = models.IsOfficialReviewer(issue, ctx.User)
 			if err != nil {
@@ -1481,7 +1482,7 @@ func ViewIssue(ctx *context.Context) {
 					ctx.ServerError("GetUserRepoPermission", err)
 					return
 				}
-				if perm.CanWrite(models.UnitTypeCode) {
+				if perm.CanWrite(unit.TypeCode) {
 					// Check if branch is not protected
 					if protected, err := pull.HeadRepo.IsProtectedBranch(pull.HeadBranch); err != nil {
 						log.Error("IsProtectedBranch: %v", err)
@@ -1512,7 +1513,7 @@ func ViewIssue(ctx *context.Context) {
 			}
 		}
 
-		prUnit, err := repo.GetUnit(models.UnitTypePullRequests)
+		prUnit, err := repo.GetUnit(unit.TypePullRequests)
 		if err != nil {
 			ctx.ServerError("GetUnit", err)
 			return
@@ -1618,7 +1619,7 @@ func ViewIssue(ctx *context.Context) {
 	ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login?redirect_to=" + ctx.Data["Link"].(string)
 	ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
 	ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
-	ctx.Data["HasProjectsWritePermission"] = ctx.Repo.CanWrite(models.UnitTypeProjects)
+	ctx.Data["HasProjectsWritePermission"] = ctx.Repo.CanWrite(unit.TypeProjects)
 	ctx.Data["IsRepoAdmin"] = ctx.IsSigned && (ctx.Repo.IsAdmin() || ctx.User.IsAdmin)
 	ctx.Data["LockReasons"] = setting.Repository.Issue.LockReasons
 	ctx.Data["RefEndName"] = git.RefEndName(issue.Ref)
@@ -1645,8 +1646,8 @@ func GetActionIssue(ctx *context.Context) *models.Issue {
 }
 
 func checkIssueRights(ctx *context.Context, issue *models.Issue) {
-	if issue.IsPull && !ctx.Repo.CanRead(models.UnitTypePullRequests) ||
-		!issue.IsPull && !ctx.Repo.CanRead(models.UnitTypeIssues) {
+	if issue.IsPull && !ctx.Repo.CanRead(unit.TypePullRequests) ||
+		!issue.IsPull && !ctx.Repo.CanRead(unit.TypeIssues) {
 		ctx.NotFound("IssueOrPullRequestUnitNotAllowed", nil)
 	}
 }
@@ -1671,8 +1672,8 @@ func getActionIssues(ctx *context.Context) []*models.Issue {
 		return nil
 	}
 	// Check access rights for all issues
-	issueUnitEnabled := ctx.Repo.CanRead(models.UnitTypeIssues)
-	prUnitEnabled := ctx.Repo.CanRead(models.UnitTypePullRequests)
+	issueUnitEnabled := ctx.Repo.CanRead(unit.TypeIssues)
+	prUnitEnabled := ctx.Repo.CanRead(unit.TypePullRequests)
 	for _, issue := range issues {
 		if issue.IsPull && !prUnitEnabled || !issue.IsPull && !issueUnitEnabled {
 			ctx.NotFound("IssueOrPullRequestUnitNotAllowed", nil)
diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go
index dc647b8809..08eb98acb8 100644
--- a/routers/web/repo/issue_content_history.go
+++ b/routers/web/repo/issue_content_history.go
@@ -13,6 +13,7 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
 	issuesModel "code.gitea.io/gitea/models/issues"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/timeutil"
@@ -87,7 +88,7 @@ func canSoftDeleteContentHistory(ctx *context.Context, issue *models.Issue, comm
 	canSoftDelete := false
 	if ctx.Repo.IsOwner() {
 		canSoftDelete = true
-	} else if ctx.Repo.CanWrite(models.UnitTypeIssues) {
+	} else if ctx.Repo.CanWrite(unit.TypeIssues) {
 		if comment == nil {
 			// the issue poster or the history poster can soft-delete
 			canSoftDelete = ctx.User.ID == issue.PosterID || ctx.User.ID == history.PosterID
diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go
index e98d189c1a..08b285df0a 100644
--- a/routers/web/repo/projects.go
+++ b/routers/web/repo/projects.go
@@ -10,6 +10,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/markup"
@@ -29,13 +30,13 @@ const (
 
 // MustEnableProjects check if projects are enabled in settings
 func MustEnableProjects(ctx *context.Context) {
-	if models.UnitTypeProjects.UnitGlobalDisabled() {
+	if unit.TypeProjects.UnitGlobalDisabled() {
 		ctx.NotFound("EnableKanbanBoard", nil)
 		return
 	}
 
 	if ctx.Repo.Repository != nil {
-		if !ctx.Repo.CanRead(models.UnitTypeProjects) {
+		if !ctx.Repo.CanRead(unit.TypeProjects) {
 			ctx.NotFound("MustEnableProjects", nil)
 			return
 		}
@@ -107,7 +108,7 @@ func Projects(ctx *context.Context) {
 	pager.AddParam(ctx, "state", "State")
 	ctx.Data["Page"] = pager
 
-	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
+	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
 	ctx.Data["IsShowClosed"] = isShowClosed
 	ctx.Data["IsProjectsPage"] = true
 	ctx.Data["SortType"] = sortType
@@ -119,7 +120,7 @@ func Projects(ctx *context.Context) {
 func NewProject(ctx *context.Context) {
 	ctx.Data["Title"] = ctx.Tr("repo.projects.new")
 	ctx.Data["ProjectTypes"] = models.GetProjectsConfig()
-	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
+	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
 	ctx.HTML(http.StatusOK, tplProjectsNew)
 }
 
@@ -129,7 +130,7 @@ func NewProjectPost(ctx *context.Context) {
 	ctx.Data["Title"] = ctx.Tr("repo.projects.new")
 
 	if ctx.HasError() {
-		ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
+		ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
 		ctx.Data["ProjectTypes"] = models.GetProjectsConfig()
 		ctx.HTML(http.StatusOK, tplProjectsNew)
 		return
@@ -206,7 +207,7 @@ func DeleteProject(ctx *context.Context) {
 func EditProject(ctx *context.Context) {
 	ctx.Data["Title"] = ctx.Tr("repo.projects.edit")
 	ctx.Data["PageIsEditProjects"] = true
-	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
+	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
 
 	p, err := models.GetProjectByID(ctx.ParamsInt64(":id"))
 	if err != nil {
@@ -233,7 +234,7 @@ func EditProjectPost(ctx *context.Context) {
 	form := web.GetForm(ctx).(*forms.CreateProjectForm)
 	ctx.Data["Title"] = ctx.Tr("repo.projects.edit")
 	ctx.Data["PageIsEditProjects"] = true
-	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
+	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
 
 	if ctx.HasError() {
 		ctx.HTML(http.StatusOK, tplProjectsNew)
@@ -330,7 +331,7 @@ func ViewProject(ctx *context.Context) {
 		return
 	}
 
-	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
+	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
 	ctx.Data["Project"] = project
 	ctx.Data["Boards"] = boards
 
@@ -371,7 +372,7 @@ func DeleteProjectBoard(ctx *context.Context) {
 		return
 	}
 
-	if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, models.UnitTypeProjects) {
+	if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, unit.TypeProjects) {
 		ctx.JSON(http.StatusForbidden, map[string]string{
 			"message": "Only authorized users are allowed to perform this action.",
 		})
@@ -420,7 +421,7 @@ func DeleteProjectBoard(ctx *context.Context) {
 // AddBoardToProjectPost allows a new board to be added to a project.
 func AddBoardToProjectPost(ctx *context.Context) {
 	form := web.GetForm(ctx).(*forms.EditProjectBoardForm)
-	if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, models.UnitTypeProjects) {
+	if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, unit.TypeProjects) {
 		ctx.JSON(http.StatusForbidden, map[string]string{
 			"message": "Only authorized users are allowed to perform this action.",
 		})
@@ -460,7 +461,7 @@ func checkProjectBoardChangePermissions(ctx *context.Context) (*models.Project,
 		return nil, nil
 	}
 
-	if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, models.UnitTypeProjects) {
+	if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, unit.TypeProjects) {
 		ctx.JSON(http.StatusForbidden, map[string]string{
 			"message": "Only authorized users are allowed to perform this action.",
 		})
@@ -554,7 +555,7 @@ func MoveIssueAcrossBoards(ctx *context.Context) {
 		return
 	}
 
-	if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, models.UnitTypeProjects) {
+	if !ctx.Repo.IsOwner() && !ctx.Repo.IsAdmin() && !ctx.Repo.CanAccess(models.AccessModeWrite, unit.TypeProjects) {
 		ctx.JSON(http.StatusForbidden, map[string]string{
 			"message": "Only authorized users are allowed to perform this action.",
 		})
@@ -626,7 +627,7 @@ func MoveIssueAcrossBoards(ctx *context.Context) {
 func CreateProject(ctx *context.Context) {
 	ctx.Data["Title"] = ctx.Tr("repo.projects.new")
 	ctx.Data["ProjectTypes"] = models.GetProjectsConfig()
-	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
+	ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
 
 	ctx.HTML(http.StatusOK, tplGenericProjectsNew)
 }
@@ -642,7 +643,7 @@ func CreateProjectPost(ctx *context.Context, form forms.UserCreateProjectForm) {
 	ctx.Data["ContextUser"] = user
 
 	if ctx.HasError() {
-		ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
+		ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects)
 		ctx.HTML(http.StatusOK, tplGenericProjectsNew)
 		return
 	}
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index 153ebc306f..0ac05a7609 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -17,6 +17,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/git"
@@ -73,11 +74,11 @@ func getRepository(ctx *context.Context, repoID int64) *models.Repository {
 		return nil
 	}
 
-	if !perm.CanRead(models.UnitTypeCode) {
+	if !perm.CanRead(unit.TypeCode) {
 		log.Trace("Permission Denied: User %-v cannot read %-v of repo %-v\n"+
 			"User in repo has Permissions: %-+v",
 			ctx.User,
-			models.UnitTypeCode,
+			unit.TypeCode,
 			ctx.Repo,
 			perm)
 		ctx.NotFound("getRepository", nil)
@@ -1034,7 +1035,7 @@ func CompareAndPullRequestPost(ctx *context.Context) {
 	ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
 	ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
 	upload.AddUploadContext(ctx, "comment")
-	ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(models.UnitTypePullRequests)
+	ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(unit.TypePullRequests)
 
 	var (
 		repo        = ctx.Repo.Repository
@@ -1221,7 +1222,7 @@ func CleanUpPullRequest(ctx *context.Context) {
 		ctx.ServerError("GetUserRepoPermission", err)
 		return
 	}
-	if !perm.CanWrite(models.UnitTypeCode) {
+	if !perm.CanWrite(unit.TypeCode) {
 		ctx.NotFound("CleanUpPullRequest", nil)
 		return
 	}
diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go
index df1fd745d8..20f6ddd2a5 100644
--- a/routers/web/repo/release.go
+++ b/routers/web/repo/release.go
@@ -12,6 +12,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/log"
@@ -102,7 +103,7 @@ func releasesOrTags(ctx *context.Context, isTagList bool) {
 	}
 	ctx.Data["Tags"] = tags
 
-	writeAccess := ctx.Repo.CanWrite(models.UnitTypeReleases)
+	writeAccess := ctx.Repo.CanWrite(unit.TypeReleases)
 	ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived
 
 	opts := models.FindReleasesOptions{
@@ -186,7 +187,7 @@ func SingleRelease(ctx *context.Context) {
 	ctx.Data["Title"] = ctx.Tr("repo.release.releases")
 	ctx.Data["PageIsReleaseList"] = true
 
-	writeAccess := ctx.Repo.CanWrite(models.UnitTypeReleases)
+	writeAccess := ctx.Repo.CanWrite(unit.TypeReleases)
 	ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived
 
 	release, err := models.GetRelease(ctx.Repo.Repository.ID, ctx.Params("*"))
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index 735bf4fe9f..c70dec6481 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -14,6 +14,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/graceful"
@@ -144,7 +145,7 @@ func Create(ctx *context.Context) {
 	templateID := ctx.FormInt64("template_id")
 	if templateID > 0 {
 		templateRepo, err := models.GetRepositoryByID(templateID)
-		if err == nil && templateRepo.CheckUnitUser(ctxUser, models.UnitTypeCode) {
+		if err == nil && templateRepo.CheckUnitUser(ctxUser, unit.TypeCode) {
 			ctx.Data["repo_template"] = templateID
 			ctx.Data["repo_template_name"] = templateRepo.Name
 		}
diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go
index e71a5bf482..b104ede005 100644
--- a/routers/web/repo/setting.go
+++ b/routers/web/repo/setting.go
@@ -16,6 +16,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
+	unit_model "code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/git"
@@ -337,7 +338,7 @@ func SettingsPost(ctx *context.Context) {
 	case "advanced":
 		var repoChanged bool
 		var units []models.RepoUnit
-		var deleteUnitTypes []models.UnitType
+		var deleteUnitTypes []unit_model.Type
 
 		// This section doesn't require repo_name/RepoName to be set in the form, don't show it
 		// as an error on the UI for this action
@@ -348,7 +349,7 @@ func SettingsPost(ctx *context.Context) {
 			repoChanged = true
 		}
 
-		if form.EnableWiki && form.EnableExternalWiki && !models.UnitTypeExternalWiki.UnitGlobalDisabled() {
+		if form.EnableWiki && form.EnableExternalWiki && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
 			if !validation.IsValidExternalURL(form.ExternalWikiURL) {
 				ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error"))
 				ctx.Redirect(repo.Link() + "/settings")
@@ -357,29 +358,29 @@ func SettingsPost(ctx *context.Context) {
 
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypeExternalWiki,
+				Type:   unit_model.TypeExternalWiki,
 				Config: &models.ExternalWikiConfig{
 					ExternalWikiURL: form.ExternalWikiURL,
 				},
 			})
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki)
-		} else if form.EnableWiki && !form.EnableExternalWiki && !models.UnitTypeWiki.UnitGlobalDisabled() {
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
+		} else if form.EnableWiki && !form.EnableExternalWiki && !unit_model.TypeWiki.UnitGlobalDisabled() {
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypeWiki,
+				Type:   unit_model.TypeWiki,
 				Config: new(models.UnitConfig),
 			})
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki)
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
 		} else {
-			if !models.UnitTypeExternalWiki.UnitGlobalDisabled() {
-				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki)
+			if !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
+				deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
 			}
-			if !models.UnitTypeWiki.UnitGlobalDisabled() {
-				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki)
+			if !unit_model.TypeWiki.UnitGlobalDisabled() {
+				deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
 			}
 		}
 
-		if form.EnableIssues && form.EnableExternalTracker && !models.UnitTypeExternalTracker.UnitGlobalDisabled() {
+		if form.EnableIssues && form.EnableExternalTracker && !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
 			if !validation.IsValidExternalURL(form.ExternalTrackerURL) {
 				ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error"))
 				ctx.Redirect(repo.Link() + "/settings")
@@ -392,47 +393,47 @@ func SettingsPost(ctx *context.Context) {
 			}
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypeExternalTracker,
+				Type:   unit_model.TypeExternalTracker,
 				Config: &models.ExternalTrackerConfig{
 					ExternalTrackerURL:    form.ExternalTrackerURL,
 					ExternalTrackerFormat: form.TrackerURLFormat,
 					ExternalTrackerStyle:  form.TrackerIssueStyle,
 				},
 			})
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues)
-		} else if form.EnableIssues && !form.EnableExternalTracker && !models.UnitTypeIssues.UnitGlobalDisabled() {
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
+		} else if form.EnableIssues && !form.EnableExternalTracker && !unit_model.TypeIssues.UnitGlobalDisabled() {
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypeIssues,
+				Type:   unit_model.TypeIssues,
 				Config: &models.IssuesConfig{
 					EnableTimetracker:                form.EnableTimetracker,
 					AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
 					EnableDependencies:               form.EnableIssueDependencies,
 				},
 			})
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker)
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
 		} else {
-			if !models.UnitTypeExternalTracker.UnitGlobalDisabled() {
-				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker)
+			if !unit_model.TypeExternalTracker.UnitGlobalDisabled() {
+				deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
 			}
-			if !models.UnitTypeIssues.UnitGlobalDisabled() {
-				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues)
+			if !unit_model.TypeIssues.UnitGlobalDisabled() {
+				deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeIssues)
 			}
 		}
 
-		if form.EnableProjects && !models.UnitTypeProjects.UnitGlobalDisabled() {
+		if form.EnableProjects && !unit_model.TypeProjects.UnitGlobalDisabled() {
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypeProjects,
+				Type:   unit_model.TypeProjects,
 			})
-		} else if !models.UnitTypeProjects.UnitGlobalDisabled() {
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeProjects)
+		} else if !unit_model.TypeProjects.UnitGlobalDisabled() {
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeProjects)
 		}
 
-		if form.EnablePulls && !models.UnitTypePullRequests.UnitGlobalDisabled() {
+		if form.EnablePulls && !unit_model.TypePullRequests.UnitGlobalDisabled() {
 			units = append(units, models.RepoUnit{
 				RepoID: repo.ID,
-				Type:   models.UnitTypePullRequests,
+				Type:   unit_model.TypePullRequests,
 				Config: &models.PullRequestsConfig{
 					IgnoreWhitespaceConflicts:     form.PullsIgnoreWhitespace,
 					AllowMerge:                    form.PullsAllowMerge,
@@ -445,8 +446,8 @@ func SettingsPost(ctx *context.Context) {
 					DefaultMergeStyle:             models.MergeStyle(form.PullsDefaultMergeStyle),
 				},
 			})
-		} else if !models.UnitTypePullRequests.UnitGlobalDisabled() {
-			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypePullRequests)
+		} else if !unit_model.TypePullRequests.UnitGlobalDisabled() {
+			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
 		}
 
 		if err := models.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil {
@@ -786,7 +787,7 @@ func Collaboration(ctx *context.Context) {
 	ctx.Data["OrgID"] = ctx.Repo.Repository.OwnerID
 	ctx.Data["OrgName"] = ctx.Repo.Repository.OwnerName
 	ctx.Data["Org"] = ctx.Repo.Repository.Owner
-	ctx.Data["Units"] = models.Units
+	ctx.Data["Units"] = unit_model.Units
 
 	ctx.HTML(http.StatusOK, tplCollaboration)
 }
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 90be631c73..72f12e9bf2 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -21,6 +21,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
+	unit_model "code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/cache"
 	"code.gitea.io/gitea/modules/charset"
@@ -353,7 +354,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
 	}
 
 	// Check permission to add or upload new file.
-	if ctx.Repo.CanWrite(models.UnitTypeCode) && ctx.Repo.IsViewBranch {
+	if ctx.Repo.CanWrite(unit_model.TypeCode) && ctx.Repo.IsViewBranch {
 		ctx.Data["CanAddFile"] = !ctx.Repo.Repository.IsArchived
 		ctx.Data["CanUploadFile"] = setting.Repository.Upload.Enabled && !ctx.Repo.Repository.IsArchived
 	}
@@ -514,7 +515,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
 				}
 			} else if !ctx.Repo.IsViewBranch {
 				ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.must_be_on_a_branch")
-			} else if !ctx.Repo.CanWrite(models.UnitTypeCode) {
+			} else if !ctx.Repo.CanWrite(unit_model.TypeCode) {
 				ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.fork_before_edit")
 			}
 		}
@@ -563,7 +564,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
 		}
 	} else if !ctx.Repo.IsViewBranch {
 		ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.must_be_on_a_branch")
-	} else if !ctx.Repo.CanWrite(models.UnitTypeCode) {
+	} else if !ctx.Repo.CanWrite(unit_model.TypeCode) {
 		ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.must_have_write_access")
 	}
 }
@@ -607,13 +608,13 @@ func checkHomeCodeViewable(ctx *context.Context) {
 			}
 		}
 
-		var firstUnit *models.Unit
+		var firstUnit *unit_model.Unit
 		for _, repoUnit := range ctx.Repo.Units {
-			if repoUnit.Type == models.UnitTypeCode {
+			if repoUnit.Type == unit_model.TypeCode {
 				return
 			}
 
-			unit, ok := models.Units[repoUnit.Type]
+			unit, ok := unit_model.Units[repoUnit.Type]
 			if ok && (firstUnit == nil || !firstUnit.IsLessThan(unit)) {
 				firstUnit = &unit
 			}
diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go
index a571c46fd7..16927de2e9 100644
--- a/routers/web/repo/wiki.go
+++ b/routers/web/repo/wiki.go
@@ -15,6 +15,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/git"
@@ -40,14 +41,14 @@ const (
 
 // MustEnableWiki check if wiki is enabled, if external then redirect
 func MustEnableWiki(ctx *context.Context) {
-	if !ctx.Repo.CanRead(models.UnitTypeWiki) &&
-		!ctx.Repo.CanRead(models.UnitTypeExternalWiki) {
+	if !ctx.Repo.CanRead(unit.TypeWiki) &&
+		!ctx.Repo.CanRead(unit.TypeExternalWiki) {
 		if log.IsTrace() {
 			log.Trace("Permission Denied: User %-v cannot read %-v or %-v of repo %-v\n"+
 				"User in repo has Permissions: %-+v",
 				ctx.User,
-				models.UnitTypeWiki,
-				models.UnitTypeExternalWiki,
+				unit.TypeWiki,
+				unit.TypeExternalWiki,
 				ctx.Repo.Repository,
 				ctx.Repo.Permission)
 		}
@@ -55,7 +56,7 @@ func MustEnableWiki(ctx *context.Context) {
 		return
 	}
 
-	unit, err := ctx.Repo.Repository.GetUnit(models.UnitTypeExternalWiki)
+	unit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalWiki)
 	if err == nil {
 		ctx.Redirect(unit.ExternalWikiConfig().ExternalWikiURL)
 		return
@@ -380,7 +381,7 @@ func renderEditPage(ctx *context.Context) {
 // Wiki renders single wiki page
 func Wiki(ctx *context.Context) {
 	ctx.Data["PageIsWiki"] = true
-	ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(models.UnitTypeWiki) && !ctx.Repo.Repository.IsArchived
+	ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived
 
 	if !ctx.Repo.Repository.HasWiki() {
 		ctx.Data["Title"] = ctx.Tr("repo.wiki")
@@ -422,7 +423,7 @@ func Wiki(ctx *context.Context) {
 // WikiRevision renders file revision list of wiki page
 func WikiRevision(ctx *context.Context) {
 	ctx.Data["PageIsWiki"] = true
-	ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(models.UnitTypeWiki) && !ctx.Repo.Repository.IsArchived
+	ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived
 
 	if !ctx.Repo.Repository.HasWiki() {
 		ctx.Data["Title"] = ctx.Tr("repo.wiki")
@@ -467,7 +468,7 @@ func WikiPages(ctx *context.Context) {
 
 	ctx.Data["Title"] = ctx.Tr("repo.wiki.pages")
 	ctx.Data["PageIsWiki"] = true
-	ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(models.UnitTypeWiki) && !ctx.Repo.Repository.IsArchived
+	ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived
 
 	wikiRepo, commit, err := findWikiRepoCommit(ctx)
 	if err != nil {
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index af5750e616..1305b0095a 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -16,6 +16,7 @@ import (
 
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/models/db"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/base"
 	"code.gitea.io/gitea/modules/context"
 	issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
@@ -144,7 +145,7 @@ func Dashboard(ctx *context.Context) {
 
 // Milestones render the user milestones page
 func Milestones(ctx *context.Context) {
-	if models.UnitTypeIssues.UnitGlobalDisabled() && models.UnitTypePullRequests.UnitGlobalDisabled() {
+	if unit.TypeIssues.UnitGlobalDisabled() && unit.TypePullRequests.UnitGlobalDisabled() {
 		log.Debug("Milestones overview page not available as both issues and pull requests are globally disabled")
 		ctx.Status(404)
 		return
@@ -316,7 +317,7 @@ func Milestones(ctx *context.Context) {
 
 // Pulls renders the user's pull request overview page
 func Pulls(ctx *context.Context) {
-	if models.UnitTypePullRequests.UnitGlobalDisabled() {
+	if unit.TypePullRequests.UnitGlobalDisabled() {
 		log.Debug("Pull request overview page not available as it is globally disabled.")
 		ctx.Status(404)
 		return
@@ -324,12 +325,12 @@ func Pulls(ctx *context.Context) {
 
 	ctx.Data["Title"] = ctx.Tr("pull_requests")
 	ctx.Data["PageIsPulls"] = true
-	buildIssueOverview(ctx, models.UnitTypePullRequests)
+	buildIssueOverview(ctx, unit.TypePullRequests)
 }
 
 // Issues renders the user's issues overview page
 func Issues(ctx *context.Context) {
-	if models.UnitTypeIssues.UnitGlobalDisabled() {
+	if unit.TypeIssues.UnitGlobalDisabled() {
 		log.Debug("Issues overview page not available as it is globally disabled.")
 		ctx.Status(404)
 		return
@@ -337,13 +338,13 @@ func Issues(ctx *context.Context) {
 
 	ctx.Data["Title"] = ctx.Tr("issues")
 	ctx.Data["PageIsIssues"] = true
-	buildIssueOverview(ctx, models.UnitTypeIssues)
+	buildIssueOverview(ctx, unit.TypeIssues)
 }
 
 // Regexp for repos query
 var issueReposQueryPattern = regexp.MustCompile(`^\[\d+(,\d+)*,?\]$`)
 
-func buildIssueOverview(ctx *context.Context, unitType models.UnitType) {
+func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
 
 	// ----------------------------------------------------
 	// Determine user; can be either user or organization.
@@ -397,7 +398,7 @@ func buildIssueOverview(ctx *context.Context, unitType models.UnitType) {
 	//       - Count Issues by repo
 	// --------------------------------------------------------------------------
 
-	isPullList := unitType == models.UnitTypePullRequests
+	isPullList := unitType == unit.TypePullRequests
 	opts := &models.IssuesOptions{
 		IsPull:     util.OptionalBoolOf(isPullList),
 		SortType:   sortType,
@@ -724,7 +725,7 @@ func getRepoIDs(reposQuery string) []int64 {
 	return repoIDs
 }
 
-func getActiveUserRepoIDs(ctxUser *models.User, team *models.Team, unitType models.UnitType) ([]int64, error) {
+func getActiveUserRepoIDs(ctxUser *models.User, team *models.Team, unitType unit.Type) ([]int64, error) {
 	var userRepoIDs []int64
 	var err error
 
@@ -749,7 +750,7 @@ func getActiveUserRepoIDs(ctxUser *models.User, team *models.Team, unitType mode
 
 // getActiveTeamOrOrgRepoIds gets RepoIDs for ctxUser as Organization.
 // Should be called if and only if ctxUser.IsOrganization == true.
-func getActiveTeamOrOrgRepoIds(ctxUser *models.User, team *models.Team, unitType models.UnitType) ([]int64, error) {
+func getActiveTeamOrOrgRepoIds(ctxUser *models.User, team *models.Team, unitType unit.Type) ([]int64, error) {
 	var orgRepoIDs []int64
 	var err error
 	var env models.AccessibleReposEnvironment
@@ -791,7 +792,7 @@ func issueIDsFromSearch(ctxUser *models.User, keyword string, opts *models.Issue
 	return issueIDsFromSearch, nil
 }
 
-func repoIDMap(ctxUser *models.User, issueCountByRepo map[int64]int64, unitType models.UnitType) (map[int64]*models.Repository, error) {
+func repoIDMap(ctxUser *models.User, issueCountByRepo map[int64]int64, unitType unit.Type) (map[int64]*models.Repository, error) {
 	repoByID := make(map[int64]*models.Repository, len(issueCountByRepo))
 	for id := range issueCountByRepo {
 		if id <= 0 {
diff --git a/routers/web/web.go b/routers/web/web.go
index c0bb74da2e..69f737c3e1 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -10,7 +10,7 @@ import (
 	"os"
 	"path"
 
-	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/httpcache"
@@ -486,18 +486,18 @@ func RegisterRoutes(m *web.Route) {
 	}
 
 	reqRepoAdmin := context.RequireRepoAdmin()
-	reqRepoCodeWriter := context.RequireRepoWriter(models.UnitTypeCode)
-	reqRepoCodeReader := context.RequireRepoReader(models.UnitTypeCode)
-	reqRepoReleaseWriter := context.RequireRepoWriter(models.UnitTypeReleases)
-	reqRepoReleaseReader := context.RequireRepoReader(models.UnitTypeReleases)
-	reqRepoWikiWriter := context.RequireRepoWriter(models.UnitTypeWiki)
-	reqRepoIssueWriter := context.RequireRepoWriter(models.UnitTypeIssues)
-	reqRepoIssueReader := context.RequireRepoReader(models.UnitTypeIssues)
-	reqRepoPullsReader := context.RequireRepoReader(models.UnitTypePullRequests)
-	reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(models.UnitTypeIssues, models.UnitTypePullRequests)
-	reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(models.UnitTypeIssues, models.UnitTypePullRequests)
-	reqRepoProjectsReader := context.RequireRepoReader(models.UnitTypeProjects)
-	reqRepoProjectsWriter := context.RequireRepoWriter(models.UnitTypeProjects)
+	reqRepoCodeWriter := context.RequireRepoWriter(unit.TypeCode)
+	reqRepoCodeReader := context.RequireRepoReader(unit.TypeCode)
+	reqRepoReleaseWriter := context.RequireRepoWriter(unit.TypeReleases)
+	reqRepoReleaseReader := context.RequireRepoReader(unit.TypeReleases)
+	reqRepoWikiWriter := context.RequireRepoWriter(unit.TypeWiki)
+	reqRepoIssueWriter := context.RequireRepoWriter(unit.TypeIssues)
+	reqRepoIssueReader := context.RequireRepoReader(unit.TypeIssues)
+	reqRepoPullsReader := context.RequireRepoReader(unit.TypePullRequests)
+	reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(unit.TypeIssues, unit.TypePullRequests)
+	reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(unit.TypeIssues, unit.TypePullRequests)
+	reqRepoProjectsReader := context.RequireRepoReader(unit.TypeProjects)
+	reqRepoProjectsWriter := context.RequireRepoWriter(unit.TypeProjects)
 
 	// ***** START: Organization *****
 	m.Group("/org", func() {
@@ -920,12 +920,12 @@ func RegisterRoutes(m *web.Route) {
 		m.Group("/activity", func() {
 			m.Get("", repo.Activity)
 			m.Get("/{period}", repo.Activity)
-		}, context.RepoRef(), repo.MustBeNotEmpty, context.RequireRepoReaderOr(models.UnitTypePullRequests, models.UnitTypeIssues, models.UnitTypeReleases))
+		}, context.RepoRef(), repo.MustBeNotEmpty, context.RequireRepoReaderOr(unit.TypePullRequests, unit.TypeIssues, unit.TypeReleases))
 
 		m.Group("/activity_author_data", func() {
 			m.Get("", repo.ActivityAuthors)
 			m.Get("/{period}", repo.ActivityAuthors)
-		}, context.RepoRef(), repo.MustBeNotEmpty, context.RequireRepoReaderOr(models.UnitTypeCode))
+		}, context.RepoRef(), repo.MustBeNotEmpty, context.RequireRepoReaderOr(unit.TypeCode))
 
 		m.Group("/archive", func() {
 			m.Get("/*", repo.Download)
diff --git a/services/forms/org.go b/services/forms/org.go
index 3b994770fd..7c8f17f95e 100644
--- a/services/forms/org.go
+++ b/services/forms/org.go
@@ -8,7 +8,7 @@ package forms
 import (
 	"net/http"
 
-	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/structs"
 	"code.gitea.io/gitea/modules/web/middleware"
@@ -66,7 +66,7 @@ type CreateTeamForm struct {
 	TeamName         string `binding:"Required;AlphaDashDot;MaxSize(30)"`
 	Description      string `binding:"MaxSize(255)"`
 	Permission       string
-	Units            []models.UnitType
+	Units            []unit.Type
 	RepoAccess       string
 	CanCreateOrgRepo bool
 }
diff --git a/services/issue/assignee.go b/services/issue/assignee.go
index 12addede75..290a0041ff 100644
--- a/services/issue/assignee.go
+++ b/services/issue/assignee.go
@@ -6,6 +6,7 @@ package issue
 
 import (
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/notification"
 )
@@ -109,7 +110,7 @@ func IsValidReviewRequest(reviewer, doer *models.User, isAdd bool, issue *models
 
 	var pemResult bool
 	if isAdd {
-		pemResult = permReviewer.CanAccessAny(models.AccessModeRead, models.UnitTypePullRequests)
+		pemResult = permReviewer.CanAccessAny(models.AccessModeRead, unit.TypePullRequests)
 		if !pemResult {
 			return models.ErrNotValidReviewRequest{
 				Reason: "Reviewer can't read",
@@ -122,7 +123,7 @@ func IsValidReviewRequest(reviewer, doer *models.User, isAdd bool, issue *models
 			return nil
 		}
 
-		pemResult = permDoer.CanAccessAny(models.AccessModeWrite, models.UnitTypePullRequests)
+		pemResult = permDoer.CanAccessAny(models.AccessModeWrite, unit.TypePullRequests)
 		if !pemResult {
 			pemResult, err = models.IsOfficialReviewer(issue, doer)
 			if err != nil {
@@ -199,7 +200,7 @@ func IsValidTeamReviewRequest(reviewer *models.Team, doer *models.User, isAdd bo
 			}
 		}
 
-		doerCanWrite := permission.CanAccessAny(models.AccessModeWrite, models.UnitTypePullRequests)
+		doerCanWrite := permission.CanAccessAny(models.AccessModeWrite, unit.TypePullRequests)
 		if !doerCanWrite {
 			official, err := models.IsOfficialReviewer(issue, doer)
 			if err != nil {
diff --git a/services/lfs/server.go b/services/lfs/server.go
index 946437fb27..5ce2a5498a 100644
--- a/services/lfs/server.go
+++ b/services/lfs/server.go
@@ -18,6 +18,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/context"
 	"code.gitea.io/gitea/modules/json"
 	lfs_module "code.gitea.io/gitea/modules/lfs"
@@ -489,7 +490,7 @@ func authenticate(ctx *context.Context, repository *models.Repository, authoriza
 		return false
 	}
 
-	canRead := perm.CanAccess(accessMode, models.UnitTypeCode)
+	canRead := perm.CanAccess(accessMode, unit.TypeCode)
 	if canRead && (!requireSigned || ctx.IsSigned) {
 		return true
 	}
diff --git a/services/mailer/mail_issue.go b/services/mailer/mail_issue.go
index 6f401e5f92..6e63162713 100644
--- a/services/mailer/mail_issue.go
+++ b/services/mailer/mail_issue.go
@@ -8,6 +8,7 @@ import (
 	"fmt"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/setting"
 )
@@ -114,9 +115,9 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []*models.
 }
 
 func mailIssueCommentBatch(ctx *mailCommentContext, users []*models.User, visited map[int64]bool, fromMention bool) error {
-	checkUnit := models.UnitTypeIssues
+	checkUnit := unit.TypeIssues
 	if ctx.Issue.IsPull {
-		checkUnit = models.UnitTypePullRequests
+		checkUnit = unit.TypePullRequests
 	}
 
 	langMap := make(map[string][]*models.User)
diff --git a/services/pull/check.go b/services/pull/check.go
index c55b177e1c..1fb167ac21 100644
--- a/services/pull/check.go
+++ b/services/pull/check.go
@@ -13,6 +13,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/graceful"
 	"code.gitea.io/gitea/modules/log"
@@ -139,13 +140,13 @@ func manuallyMerged(pr *models.PullRequest) bool {
 		return false
 	}
 
-	if unit, err := pr.BaseRepo.GetUnit(models.UnitTypePullRequests); err == nil {
+	if unit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests); err == nil {
 		config := unit.PullRequestsConfig()
 		if !config.AutodetectManualMerge {
 			return false
 		}
 	} else {
-		log.Error("PullRequest[%d].BaseRepo.GetUnit(models.UnitTypePullRequests): %v", pr.ID, err)
+		log.Error("PullRequest[%d].BaseRepo.GetUnit(unit.TypePullRequests): %v", pr.ID, err)
 		return false
 	}
 
diff --git a/services/pull/merge.go b/services/pull/merge.go
index 4d4a64e984..f59931e1bf 100644
--- a/services/pull/merge.go
+++ b/services/pull/merge.go
@@ -16,6 +16,7 @@ import (
 	"time"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/cache"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
@@ -38,9 +39,9 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
 		return fmt.Errorf("LoadBaseRepo: %v", err)
 	}
 
-	prUnit, err := pr.BaseRepo.GetUnit(models.UnitTypePullRequests)
+	prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests)
 	if err != nil {
-		log.Error("pr.BaseRepo.GetUnit(models.UnitTypePullRequests): %v", err)
+		log.Error("pr.BaseRepo.GetUnit(unit.TypePullRequests): %v", err)
 		return err
 	}
 	prConfig := prUnit.PullRequestsConfig()
@@ -565,7 +566,7 @@ func IsUserAllowedToMerge(pr *models.PullRequest, p models.Permission, user *mod
 		return false, err
 	}
 
-	if (p.CanWrite(models.UnitTypeCode) && pr.ProtectedBranch == nil) || (pr.ProtectedBranch != nil && pr.ProtectedBranch.IsUserMergeWhitelisted(user.ID, p)) {
+	if (p.CanWrite(unit.TypeCode) && pr.ProtectedBranch == nil) || (pr.ProtectedBranch != nil && pr.ProtectedBranch.IsUserMergeWhitelisted(user.ID, p)) {
 		return true, nil
 	}
 
@@ -632,7 +633,7 @@ func CheckPRReadyToMerge(pr *models.PullRequest, skipProtectedFilesCheck bool) (
 
 // MergedManually mark pr as merged manually
 func MergedManually(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repository, commitID string) (err error) {
-	prUnit, err := pr.BaseRepo.GetUnit(models.UnitTypePullRequests)
+	prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests)
 	if err != nil {
 		return
 	}
diff --git a/services/pull/patch.go b/services/pull/patch.go
index 27d7991919..b971eb4bf3 100644
--- a/services/pull/patch.go
+++ b/services/pull/patch.go
@@ -14,6 +14,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/util"
@@ -142,7 +143,7 @@ func checkConflicts(pr *models.PullRequest, gitRepo *git.Repository, tmpBasePath
 	}
 
 	// 4. Now get the pull request configuration to check if we need to ignore whitespace
-	prUnit, err := pr.BaseRepo.GetUnit(models.UnitTypePullRequests)
+	prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests)
 	if err != nil {
 		return false, err
 	}
diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go
index 5acb23ac78..944099de1f 100644
--- a/services/wiki/wiki.go
+++ b/services/wiki/wiki.go
@@ -12,6 +12,7 @@ import (
 	"strings"
 
 	"code.gitea.io/gitea/models"
+	"code.gitea.io/gitea/models/unit"
 	"code.gitea.io/gitea/modules/git"
 	"code.gitea.io/gitea/modules/log"
 	repo_module "code.gitea.io/gitea/modules/repository"
@@ -369,7 +370,7 @@ func DeleteWikiPage(doer *models.User, repo *models.Repository, wikiName string)
 
 // DeleteWiki removes the actual and local copy of repository wiki.
 func DeleteWiki(repo *models.Repository) error {
-	if err := models.UpdateRepositoryUnits(repo, nil, []models.UnitType{models.UnitTypeWiki}); err != nil {
+	if err := models.UpdateRepositoryUnits(repo, nil, []unit.Type{unit.TypeWiki}); err != nil {
 		return err
 	}