mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 21:28:11 +09:00 
			
		
		
		
	Add setting to set default and global disabled repository units. (#8788)
* Add possibility to global disable repo units. * Add Default Repo Unit app.ini setting. * Hide units * Hide disabled repo units * Minor fixes * Indicate disabled units in team settings. Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: zeripath <art27@cantab.net>
This commit is contained in:
		
				
					committed by
					
						 Lauris BH
						Lauris BH
					
				
			
			
				
	
			
			
			
						parent
						
							36943e56d6
						
					
				
				
					commit
					3c07d03c03
				
			| @@ -42,6 +42,13 @@ DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH = false | ||||
| ; Allow users to push local repositories to Gitea and have them automatically created for a user or an org | ||||
| ENABLE_PUSH_CREATE_USER = false | ||||
| ENABLE_PUSH_CREATE_ORG = false | ||||
| ; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki | ||||
| DISABLED_REPO_UNITS =  | ||||
| ; Comma separated list of default repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki. | ||||
| ; Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility. | ||||
| ; External wiki and issue tracker can't be enabled by default as it requires additional settings. | ||||
| ; Disabled repo units will not be added to new repositories regardless if it is in the default list. | ||||
| DEFAULT_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki | ||||
|  | ||||
| [repository.editor] | ||||
| ; List of file extensions for which lines should be wrapped in the CodeMirror editor | ||||
|   | ||||
| @@ -128,6 +128,7 @@ func loadRepoConfig() { | ||||
| // NewRepoContext creates a new repository context | ||||
| func NewRepoContext() { | ||||
| 	loadRepoConfig() | ||||
| 	loadUnitConfig() | ||||
|  | ||||
| 	RemoveAllWithNotice("Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp")) | ||||
| } | ||||
| @@ -393,6 +394,7 @@ func (repo *Repository) getUnits(e Engine) (err error) { | ||||
| 	} | ||||
|  | ||||
| 	repo.Units, err = getUnitsByRepoID(e, repo.ID) | ||||
| 	log.Trace("repo.Units: %-+v", repo.Units) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| @@ -1442,14 +1444,19 @@ func UpdateRepositoryUpdatedTime(repoID int64, updateTime time.Time) error { | ||||
| } | ||||
|  | ||||
| // UpdateRepositoryUnits updates a repository's units | ||||
| func UpdateRepositoryUnits(repo *Repository, units []RepoUnit) (err error) { | ||||
| func UpdateRepositoryUnits(repo *Repository, units []RepoUnit, deleteUnitTypes []UnitType) (err error) { | ||||
| 	sess := x.NewSession() | ||||
| 	defer sess.Close() | ||||
| 	if err = sess.Begin(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if _, err = sess.Where("repo_id = ?", repo.ID).Delete(new(RepoUnit)); err != nil { | ||||
| 	// Delete existing settings of units before adding again | ||||
| 	for _, u := range units { | ||||
| 		deleteUnitTypes = append(deleteUnitTypes, u.Type) | ||||
| 	} | ||||
|  | ||||
| 	if _, err = sess.Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(RepoUnit)); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -170,5 +170,16 @@ func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig { | ||||
| } | ||||
|  | ||||
| func getUnitsByRepoID(e Engine, repoID int64) (units []*RepoUnit, err error) { | ||||
| 	return units, e.Where("repo_id = ?", repoID).Find(&units) | ||||
| 	var tmpUnits []*RepoUnit | ||||
| 	if err := e.Where("repo_id = ?", repoID).Find(&tmpUnits); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	for _, u := range tmpUnits { | ||||
| 		if !u.Type.UnitGlobalDisabled() { | ||||
| 			units = append(units, u) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return units, nil | ||||
| } | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| ) | ||||
|  | ||||
| // UnitType is Unit's Type | ||||
| @@ -78,13 +79,89 @@ var ( | ||||
| 		UnitTypeWiki, | ||||
| 	} | ||||
|  | ||||
| 	// NotAllowedDefaultRepoUnits contains units that can't be default | ||||
| 	NotAllowedDefaultRepoUnits = []UnitType{ | ||||
| 		UnitTypeExternalWiki, | ||||
| 		UnitTypeExternalTracker, | ||||
| 	} | ||||
|  | ||||
| 	// MustRepoUnits contains the units could not be disabled currently | ||||
| 	MustRepoUnits = []UnitType{ | ||||
| 		UnitTypeCode, | ||||
| 		UnitTypeReleases, | ||||
| 	} | ||||
|  | ||||
| 	// DisabledRepoUnits contains the units that have been globally disabled | ||||
| 	DisabledRepoUnits = []UnitType{} | ||||
| ) | ||||
|  | ||||
| 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)) | ||||
| 		copy(DefaultRepoUnits, MustRepoUnits) | ||||
| 		for _, defaultU := range setDefaultRepoUnits { | ||||
| 			if !defaultU.CanBeDefault() { | ||||
| 				log.Warn("Not allowed as default unit: %s", defaultU.String()) | ||||
| 				continue | ||||
| 			} | ||||
| 			// MustRepoUnits already added | ||||
| 			if defaultU.CanDisable() { | ||||
| 				DefaultRepoUnits = append(DefaultRepoUnits, defaultU) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	DisabledRepoUnits = FindUnitTypes(setting.Repository.DisabledRepoUnits...) | ||||
| 	// Check that must units are not disabled | ||||
| 	for i, disabledU := range DisabledRepoUnits { | ||||
| 		if !disabledU.CanDisable() { | ||||
| 			log.Warn("Not allowed to global disable unit %s", disabledU.String()) | ||||
| 			DisabledRepoUnits = append(DisabledRepoUnits[:i], DisabledRepoUnits[i+1:]...) | ||||
| 		} | ||||
| 	} | ||||
| 	// Remove disabled units from default units | ||||
| 	for _, disabledU := range DisabledRepoUnits { | ||||
| 		for i, defaultU := range DefaultRepoUnits { | ||||
| 			if defaultU == disabledU { | ||||
| 				DefaultRepoUnits = append(DefaultRepoUnits[:i], DefaultRepoUnits[i+1:]...) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // UnitGlobalDisabled checks if unit type is global disabled | ||||
| func (u UnitType) UnitGlobalDisabled() bool { | ||||
| 	for _, ud := range DisabledRepoUnits { | ||||
| 		if u == ud { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // CanDisable checks if this unit type can be disabled. | ||||
| func (u *UnitType) CanDisable() bool { | ||||
| 	for _, mu := range MustRepoUnits { | ||||
| 		if *u == mu { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // CanBeDefault checks if the unit type can be a default repo unit | ||||
| func (u *UnitType) CanBeDefault() bool { | ||||
| 	for _, nadU := range NotAllowedDefaultRepoUnits { | ||||
| 		if *u == nadU { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // Unit is a section of one repository | ||||
| type Unit struct { | ||||
| 	Type    UnitType | ||||
| @@ -96,7 +173,7 @@ type Unit struct { | ||||
|  | ||||
| // CanDisable returns if this unit could be disabled. | ||||
| func (u *Unit) CanDisable() bool { | ||||
| 	return true | ||||
| 	return u.Type.CanDisable() | ||||
| } | ||||
|  | ||||
| // IsLessThan compares order of two units | ||||
|   | ||||
| @@ -622,6 +622,7 @@ func (u *User) GetRepositories(page, pageSize int) (err error) { | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	var ids []int64 | ||||
|  | ||||
| @@ -636,6 +637,7 @@ func (u *User) GetRepositoryIDs(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) { | ||||
| 	var ids []int64 | ||||
|  | ||||
| @@ -656,6 +658,7 @@ func (u *User) GetOrgRepositoryIDs(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) { | ||||
| 	ids, err := u.GetRepositoryIDs(units...) | ||||
| 	if err != nil { | ||||
|   | ||||
| @@ -37,6 +37,8 @@ var ( | ||||
| 		DefaultCloseIssuesViaCommitsInAnyBranch bool | ||||
| 		EnablePushCreateUser                    bool | ||||
| 		EnablePushCreateOrg                     bool | ||||
| 		DisabledRepoUnits                       []string | ||||
| 		DefaultRepoUnits                        []string | ||||
|  | ||||
| 		// Repository editor settings | ||||
| 		Editor struct { | ||||
| @@ -98,6 +100,8 @@ var ( | ||||
| 		DefaultCloseIssuesViaCommitsInAnyBranch: false, | ||||
| 		EnablePushCreateUser:                    false, | ||||
| 		EnablePushCreateOrg:                     false, | ||||
| 		DisabledRepoUnits:                       []string{}, | ||||
| 		DefaultRepoUnits:                        []string{}, | ||||
|  | ||||
| 		// Repository editor settings | ||||
| 		Editor: struct { | ||||
|   | ||||
| @@ -636,6 +636,7 @@ stargazers = Stargazers | ||||
| forks = Forks | ||||
| pick_reaction = Pick your reaction | ||||
| reactions_more = and %d more | ||||
| unit_disabled = The site administrator has disabled this repository section. | ||||
|  | ||||
| template.items = Template Items | ||||
| template.git_content = Git Content (Default Branch) | ||||
| @@ -1613,6 +1614,7 @@ team_desc_helper = Describe the purpose or role of the team. | ||||
| team_access_desc = Repository access | ||||
| team_permission_desc = Permission | ||||
| team_unit_desc = Allow Access to Repository Sections | ||||
| team_unit_disabled = (Disabled) | ||||
|  | ||||
| form.name_reserved = The organization name '%s' is reserved. | ||||
| form.name_pattern_not_allowed = The pattern '%s' is not allowed in an organization name. | ||||
|   | ||||
| @@ -757,25 +757,10 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { | ||||
| 	repo := ctx.Repo.Repository | ||||
|  | ||||
| 	var units []models.RepoUnit | ||||
| 	var deleteUnitTypes []models.UnitType | ||||
|  | ||||
| 	for _, tp := range models.MustRepoUnits { | ||||
| 		units = append(units, models.RepoUnit{ | ||||
| 			RepoID: repo.ID, | ||||
| 			Type:   tp, | ||||
| 			Config: new(models.UnitConfig), | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| 	if opts.HasIssues == nil { | ||||
| 		// If HasIssues setting not touched, rewrite existing repo unit | ||||
| 		if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil { | ||||
| 			units = append(units, *unit) | ||||
| 		} else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil { | ||||
| 			units = append(units, *unit) | ||||
| 		} | ||||
| 	} else if *opts.HasIssues { | ||||
| 		if opts.ExternalTracker != nil { | ||||
|  | ||||
| 	if opts.HasIssues != nil { | ||||
| 		if *opts.HasIssues && opts.ExternalTracker != nil && !models.UnitTypeExternalTracker.UnitGlobalDisabled() { | ||||
| 			// Check that values are valid | ||||
| 			if !validation.IsValidExternalURL(opts.ExternalTracker.ExternalTrackerURL) { | ||||
| 				err := fmt.Errorf("External tracker URL not valid") | ||||
| @@ -797,7 +782,8 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { | ||||
| 					ExternalTrackerStyle:  opts.ExternalTracker.ExternalTrackerStyle, | ||||
| 				}, | ||||
| 			}) | ||||
| 		} else { | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues) | ||||
| 		} else if *opts.HasIssues && opts.ExternalTracker == nil && !models.UnitTypeIssues.UnitGlobalDisabled() { | ||||
| 			// Default to built-in tracker | ||||
| 			var config *models.IssuesConfig | ||||
|  | ||||
| @@ -823,19 +809,19 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { | ||||
| 				Type:   models.UnitTypeIssues, | ||||
| 				Config: config, | ||||
| 			}) | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker) | ||||
| 		} else if !*opts.HasIssues { | ||||
| 			if !models.UnitTypeExternalTracker.UnitGlobalDisabled() { | ||||
| 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker) | ||||
| 			} | ||||
| 			if !models.UnitTypeIssues.UnitGlobalDisabled() { | ||||
| 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if opts.HasWiki == nil { | ||||
| 		// If HasWiki setting not touched, rewrite existing repo unit | ||||
| 		if unit, err := repo.GetUnit(models.UnitTypeWiki); err == nil { | ||||
| 			units = append(units, *unit) | ||||
| 		} else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil { | ||||
| 			units = append(units, *unit) | ||||
| 		} | ||||
| 	} else if *opts.HasWiki { | ||||
| 		if opts.ExternalWiki != nil { | ||||
|  | ||||
| 	if opts.HasWiki != nil { | ||||
| 		if *opts.HasWiki && opts.ExternalWiki != nil && !models.UnitTypeExternalWiki.UnitGlobalDisabled() { | ||||
| 			// Check that values are valid | ||||
| 			if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) { | ||||
| 				err := fmt.Errorf("External wiki URL not valid") | ||||
| @@ -850,22 +836,27 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { | ||||
| 					ExternalWikiURL: opts.ExternalWiki.ExternalWikiURL, | ||||
| 				}, | ||||
| 			}) | ||||
| 		} else { | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki) | ||||
| 		} else if *opts.HasWiki && opts.ExternalWiki == nil && !models.UnitTypeWiki.UnitGlobalDisabled() { | ||||
| 			config := &models.UnitConfig{} | ||||
| 			units = append(units, models.RepoUnit{ | ||||
| 				RepoID: repo.ID, | ||||
| 				Type:   models.UnitTypeWiki, | ||||
| 				Config: config, | ||||
| 			}) | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki) | ||||
| 		} else if !*opts.HasWiki { | ||||
| 			if !models.UnitTypeExternalWiki.UnitGlobalDisabled() { | ||||
| 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki) | ||||
| 			} | ||||
| 			if !models.UnitTypeWiki.UnitGlobalDisabled() { | ||||
| 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if opts.HasPullRequests == nil { | ||||
| 		// If HasPullRequest setting not touched, rewrite existing repo unit | ||||
| 		if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil { | ||||
| 			units = append(units, *unit) | ||||
| 		} | ||||
| 	} else if *opts.HasPullRequests { | ||||
| 	if opts.HasPullRequests != nil { | ||||
| 		if *opts.HasPullRequests && !models.UnitTypePullRequests.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. | ||||
| @@ -905,9 +896,12 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { | ||||
| 				Type:   models.UnitTypePullRequests, | ||||
| 				Config: config, | ||||
| 			}) | ||||
| 		} else if !*opts.HasPullRequests && !models.UnitTypePullRequests.UnitGlobalDisabled() { | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypePullRequests) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := models.UpdateRepositoryUnits(repo, units); err != nil { | ||||
| 	if err := models.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil { | ||||
| 		ctx.Error(http.StatusInternalServerError, "UpdateRepositoryUnits", err) | ||||
| 		return err | ||||
| 	} | ||||
|   | ||||
| @@ -205,21 +205,13 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { | ||||
|  | ||||
| 	case "advanced": | ||||
| 		var units []models.RepoUnit | ||||
| 		var deleteUnitTypes []models.UnitType | ||||
|  | ||||
| 		// 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 | ||||
| 		ctx.Data["Err_RepoName"] = nil | ||||
|  | ||||
| 		for _, tp := range models.MustRepoUnits { | ||||
| 			units = append(units, models.RepoUnit{ | ||||
| 				RepoID: repo.ID, | ||||
| 				Type:   tp, | ||||
| 				Config: new(models.UnitConfig), | ||||
| 			}) | ||||
| 		} | ||||
|  | ||||
| 		if form.EnableWiki { | ||||
| 			if form.EnableExternalWiki { | ||||
| 		if form.EnableWiki && form.EnableExternalWiki && !models.UnitTypeExternalWiki.UnitGlobalDisabled() { | ||||
| 			if !validation.IsValidExternalURL(form.ExternalWikiURL) { | ||||
| 				ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error")) | ||||
| 				ctx.Redirect(repo.Link() + "/settings") | ||||
| @@ -233,17 +225,24 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { | ||||
| 					ExternalWikiURL: form.ExternalWikiURL, | ||||
| 				}, | ||||
| 			}) | ||||
| 			} else { | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki) | ||||
| 		} else if form.EnableWiki && !form.EnableExternalWiki && !models.UnitTypeWiki.UnitGlobalDisabled() { | ||||
| 			units = append(units, models.RepoUnit{ | ||||
| 				RepoID: repo.ID, | ||||
| 				Type:   models.UnitTypeWiki, | ||||
| 				Config: new(models.UnitConfig), | ||||
| 			}) | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki) | ||||
| 		} else { | ||||
| 			if !models.UnitTypeExternalWiki.UnitGlobalDisabled() { | ||||
| 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalWiki) | ||||
| 			} | ||||
| 			if !models.UnitTypeWiki.UnitGlobalDisabled() { | ||||
| 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeWiki) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if form.EnableIssues { | ||||
| 			if form.EnableExternalTracker { | ||||
| 		if form.EnableIssues && form.EnableExternalTracker && !models.UnitTypeExternalTracker.UnitGlobalDisabled() { | ||||
| 			if !validation.IsValidExternalURL(form.ExternalTrackerURL) { | ||||
| 				ctx.Flash.Error(ctx.Tr("repo.settings.external_tracker_url_error")) | ||||
| 				ctx.Redirect(repo.Link() + "/settings") | ||||
| @@ -263,7 +262,8 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { | ||||
| 					ExternalTrackerStyle:  form.TrackerIssueStyle, | ||||
| 				}, | ||||
| 			}) | ||||
| 			} else { | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues) | ||||
| 		} else if form.EnableIssues && !form.EnableExternalTracker && !models.UnitTypeIssues.UnitGlobalDisabled() { | ||||
| 			units = append(units, models.RepoUnit{ | ||||
| 				RepoID: repo.ID, | ||||
| 				Type:   models.UnitTypeIssues, | ||||
| @@ -273,10 +273,17 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { | ||||
| 					EnableDependencies:               form.EnableIssueDependencies, | ||||
| 				}, | ||||
| 			}) | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker) | ||||
| 		} else { | ||||
| 			if !models.UnitTypeExternalTracker.UnitGlobalDisabled() { | ||||
| 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeExternalTracker) | ||||
| 			} | ||||
| 			if !models.UnitTypeIssues.UnitGlobalDisabled() { | ||||
| 				deleteUnitTypes = append(deleteUnitTypes, models.UnitTypeIssues) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if form.EnablePulls { | ||||
| 		if form.EnablePulls && !models.UnitTypePullRequests.UnitGlobalDisabled() { | ||||
| 			units = append(units, models.RepoUnit{ | ||||
| 				RepoID: repo.ID, | ||||
| 				Type:   models.UnitTypePullRequests, | ||||
| @@ -288,9 +295,11 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) { | ||||
| 					AllowSquash:               form.PullsAllowSquash, | ||||
| 				}, | ||||
| 			}) | ||||
| 		} else if !models.UnitTypePullRequests.UnitGlobalDisabled() { | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, models.UnitTypePullRequests) | ||||
| 		} | ||||
|  | ||||
| 		if err := models.UpdateRepositoryUnits(repo, units); err != nil { | ||||
| 		if err := models.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil { | ||||
| 			ctx.ServerError("UpdateRepositoryUnits", err) | ||||
| 			return | ||||
| 		} | ||||
|   | ||||
| @@ -261,6 +261,11 @@ func RegisterRoutes(m *macaron.Macaron) { | ||||
| 	} | ||||
|  | ||||
| 	m.Use(user.GetNotificationCount) | ||||
| 	m.Use(func(ctx *context.Context) { | ||||
| 		ctx.Data["UnitWikiGlobalDisabled"] = models.UnitTypeWiki.UnitGlobalDisabled() | ||||
| 		ctx.Data["UnitIssuesGlobalDisabled"] = models.UnitTypeIssues.UnitGlobalDisabled() | ||||
| 		ctx.Data["UnitPullsGlobalDisabled"] = models.UnitTypePullRequests.UnitGlobalDisabled() | ||||
| 	}) | ||||
|  | ||||
| 	// FIXME: not all routes need go through same middlewares. | ||||
| 	// Especially some AJAX requests, we can reduce middleware number to improve performance. | ||||
|   | ||||
| @@ -158,6 +158,12 @@ func Dashboard(ctx *context.Context) { | ||||
|  | ||||
| // Milestones render the user milestones page | ||||
| func Milestones(ctx *context.Context) { | ||||
| 	if models.UnitTypeIssues.UnitGlobalDisabled() && models.UnitTypePullRequests.UnitGlobalDisabled() { | ||||
| 		log.Debug("Milestones overview page not available as both issues and pull requests are globally disabled") | ||||
| 		ctx.Status(404) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ctx.Data["Title"] = ctx.Tr("milestones") | ||||
| 	ctx.Data["PageIsMilestonesDashboard"] = true | ||||
|  | ||||
| @@ -335,10 +341,22 @@ func Issues(ctx *context.Context) { | ||||
| 	isPullList := ctx.Params(":type") == "pulls" | ||||
| 	unitType := models.UnitTypeIssues | ||||
| 	if isPullList { | ||||
| 		if models.UnitTypePullRequests.UnitGlobalDisabled() { | ||||
| 			log.Debug("Pull request overview page not available as it is globally disabled.") | ||||
| 			ctx.Status(404) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		ctx.Data["Title"] = ctx.Tr("pull_requests") | ||||
| 		ctx.Data["PageIsPulls"] = true | ||||
| 		unitType = models.UnitTypePullRequests | ||||
| 	} else { | ||||
| 		if models.UnitTypeIssues.UnitGlobalDisabled() { | ||||
| 			log.Debug("Issues overview page not available as it is globally disabled.") | ||||
| 			ctx.Status(404) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		ctx.Data["Title"] = ctx.Tr("issues") | ||||
| 		ctx.Data["PageIsIssues"] = true | ||||
| 	} | ||||
|   | ||||
| @@ -10,9 +10,15 @@ | ||||
|  | ||||
| 	{{if .IsSigned}} | ||||
| 		<a class="item {{if .PageIsDashboard}}active{{end}}" href="{{AppSubUrl}}/">{{.i18n.Tr "dashboard"}}</a> | ||||
| 		{{if not .UnitIssuesGlobalDisabled}} | ||||
| 		<a class="item {{if .PageIsIssues}}active{{end}}" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | ||||
| 		{{end}} | ||||
| 		{{if not .UnitPullsGlobalDisabled}} | ||||
| 		<a class="item {{if .PageIsPulls}}active{{end}}" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | ||||
| 		{{end}} | ||||
| 		{{if not (and .UnitIssuesGlobalDisabled .UnitPullsGlobalDisabled)}} | ||||
| 		{{if .ShowMilestonesDashboardPage}}<a class="item {{if .PageIsMilestonesDashboard}}active{{end}}" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a>{{end}} | ||||
| 		{{end}} | ||||
| 		<a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "explore"}}</a> | ||||
| 	{{else if .IsLandingPageHome}} | ||||
| 		<a class="item {{if .PageIsHome}}active{{end}}" href="{{AppSubUrl}}/">{{.i18n.Tr "home"}}</a> | ||||
|   | ||||
| @@ -81,10 +81,14 @@ | ||||
| 							<label>{{.i18n.Tr "org.team_unit_desc"}}</label> | ||||
| 							<br> | ||||
| 							{{range $t, $unit := $.Units}} | ||||
| 							{{if $unit.Type.UnitGlobalDisabled}} | ||||
| 							<div class="field poping up" data-content="{{$.i18n.Tr "repo.unit_disabled"}}"> | ||||
| 							{{else}} | ||||
| 							<div class="field"> | ||||
| 							{{end}} | ||||
| 								<div class="ui toggle checkbox"> | ||||
| 									<input type="checkbox" class="hidden" name="units" value="{{$unit.Type.Value}}"{{if or (eq $.Team.ID 0) ($.Team.UnitEnabled $unit.Type)}} checked{{end}}> | ||||
| 									<label>{{$.i18n.Tr $unit.NameKey}}</label> | ||||
| 									<label>{{$.i18n.Tr $unit.NameKey}}{{if $unit.Type.UnitGlobalDisabled}} {{$.i18n.Tr "org.team_unit_disabled"}}{{end}}</label> | ||||
| 									<span class="help">{{$.i18n.Tr $unit.DescKey}}</span> | ||||
| 								</div> | ||||
| 							</div> | ||||
|   | ||||
| @@ -144,20 +144,32 @@ | ||||
| 				{{$isWikiEnabled := or (.Repository.UnitEnabled $.UnitTypeWiki) (.Repository.UnitEnabled $.UnitTypeExternalWiki)}} | ||||
| 				<div class="inline field"> | ||||
| 					<label>{{.i18n.Tr "repo.wiki"}}</label> | ||||
| 					{{if and (.UnitTypeWiki.UnitGlobalDisabled) (.UnitTypeExternalWiki.UnitGlobalDisabled)}} | ||||
| 					<div class="ui checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||
| 					{{else}} | ||||
| 					<div class="ui checkbox"> | ||||
| 					{{end}} | ||||
| 						<input class="enable-system" name="enable_wiki" type="checkbox" data-target="#wiki_box" {{if $isWikiEnabled}}checked{{end}}> | ||||
| 						<label>{{.i18n.Tr "repo.settings.wiki_desc"}}</label> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 				<div class="field {{if not $isWikiEnabled}}disabled{{end}}" id="wiki_box"> | ||||
| 					<div class="field"> | ||||
| 						{{if .UnitTypeWiki.UnitGlobalDisabled}} | ||||
| 						<div class="ui radio checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||
| 						{{else}} | ||||
| 						<div class="ui radio checkbox"> | ||||
| 						{{end}} | ||||
| 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="false" data-target="#external_wiki_box" {{if not (.Repository.UnitEnabled $.UnitTypeExternalWiki)}}checked{{end}}/> | ||||
| 							<label>{{.i18n.Tr "repo.settings.use_internal_wiki"}}</label> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 					<div class="field"> | ||||
| 						{{if .UnitTypeExternalWiki.UnitGlobalDisabled}} | ||||
| 						<div class="ui radio checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||
| 						{{else}} | ||||
| 						<div class="ui radio checkbox"> | ||||
| 						{{end}} | ||||
| 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="true" data-target="#external_wiki_box" {{if .Repository.UnitEnabled $.UnitTypeExternalWiki}}checked{{end}}/> | ||||
| 							<label>{{.i18n.Tr "repo.settings.use_external_wiki"}}</label> | ||||
| 						</div> | ||||
| @@ -174,14 +186,22 @@ | ||||
| 				{{$isIssuesEnabled := or (.Repository.UnitEnabled $.UnitTypeIssues) (.Repository.UnitEnabled $.UnitTypeExternalTracker)}} | ||||
| 				<div class="inline field"> | ||||
| 					<label>{{.i18n.Tr "repo.issues"}}</label> | ||||
| 					{{if and (.UnitTypeIssues.UnitGlobalDisabled) (.UnitTypeExternalTracker.UnitGlobalDisabled)}} | ||||
| 					<div class="ui checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||
| 					{{else}} | ||||
| 					<div class="ui checkbox"> | ||||
| 					{{end}} | ||||
| 						<input class="enable-system" name="enable_issues" type="checkbox" data-target="#issue_box" {{if $isIssuesEnabled}}checked{{end}}> | ||||
| 						<label>{{.i18n.Tr "repo.settings.issues_desc"}}</label> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 				<div class="field {{if not $isIssuesEnabled}}disabled{{end}}" id="issue_box"> | ||||
| 					<div class="field"> | ||||
| 						{{if .UnitTypeIssues.UnitGlobalDisabled}} | ||||
| 						<div class="ui radio checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||
| 						{{else}} | ||||
| 						<div class="ui radio checkbox"> | ||||
| 						{{end}} | ||||
| 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="false" data-context="#internal_issue_box" data-target="#external_issue_box" {{if not (.Repository.UnitEnabled $.UnitTypeExternalTracker)}}checked{{end}}/> | ||||
| 							<label>{{.i18n.Tr "repo.settings.use_internal_issue_tracker"}}</label> | ||||
| 						</div> | ||||
| @@ -209,7 +229,11 @@ | ||||
| 							</div> | ||||
| 					</div> | ||||
| 					<div class="field"> | ||||
| 						{{if .UnitTypeExternalTracker.UnitGlobalDisabled}} | ||||
| 						<div class="ui radio checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||
| 						{{else}} | ||||
| 						<div class="ui radio checkbox"> | ||||
| 						{{end}} | ||||
| 							<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="true" data-context="#internal_issue_box" data-target="#external_issue_box" {{if .Repository.UnitEnabled $.UnitTypeExternalTracker}}checked{{end}}/> | ||||
| 							<label>{{.i18n.Tr "repo.settings.use_external_issue_tracker"}}</label> | ||||
| 						</div> | ||||
| @@ -251,7 +275,11 @@ | ||||
| 					{{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}} | ||||
| 					<div class="inline field"> | ||||
| 						<label>{{.i18n.Tr "repo.pulls"}}</label> | ||||
| 						{{if .UnitTypePullRequests.UnitGlobalDisabled}} | ||||
| 						<div class="ui checkbox poping up disabled" data-content="{{.i18n.Tr "repo.unit_disabled"}}"> | ||||
| 						{{else}} | ||||
| 						<div class="ui checkbox"> | ||||
| 						{{end}} | ||||
| 							<input class="enable-system" name="enable_pulls" type="checkbox" data-target="#pull_box" {{if $pullRequestEnabled}}checked{{end}}> | ||||
| 							<label>{{.i18n.Tr "repo.settings.pulls_desc"}}</label> | ||||
| 						</div> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user