Api: advanced settings for repository (external wiki, issue tracker etc.) (#7756)
* Add API for Repo Advanced Settings of wiki and issue tracker Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Add some integration tests for tracker and wiki settings through API * Should return StatusUnprocessableEntity in case of invalid API values. * Add tests for invalid URLs for external tracker and wiki. * Do not set inital values if they are default of type * Make issue tracker and wiki units separate structures in Repository API structure. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Fix comment of structures Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Rewrite API to use struct for setting tracker and wiki settings. * LetOnlyContributorsTrackTime -> AllowOnlyContributorsToTrackTime
This commit is contained in:
		
					parent
					
						
							
								f8899678d2
							
						
					
				
			
			
				commit
				
					
						90ab3056eb
					
				
			
		
					 5 changed files with 327 additions and 41 deletions
				
			
		| 
						 | 
				
			
			@ -23,12 +23,35 @@ func getRepoEditOptionFromRepo(repo *models.Repository) *api.EditRepoOption {
 | 
			
		|||
	website := repo.Website
 | 
			
		||||
	private := repo.IsPrivate
 | 
			
		||||
	hasIssues := false
 | 
			
		||||
	if _, err := repo.GetUnit(models.UnitTypeIssues); err == nil {
 | 
			
		||||
	var internalTracker *api.InternalTracker
 | 
			
		||||
	var externalTracker *api.ExternalTracker
 | 
			
		||||
	if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil {
 | 
			
		||||
		config := unit.IssuesConfig()
 | 
			
		||||
		hasIssues = true
 | 
			
		||||
		internalTracker = &api.InternalTracker{
 | 
			
		||||
			EnableTimeTracker:                config.EnableTimetracker,
 | 
			
		||||
			AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime,
 | 
			
		||||
			EnableIssueDependencies:          config.EnableDependencies,
 | 
			
		||||
		}
 | 
			
		||||
	} else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil {
 | 
			
		||||
		config := unit.ExternalTrackerConfig()
 | 
			
		||||
		hasIssues = true
 | 
			
		||||
		externalTracker = &api.ExternalTracker{
 | 
			
		||||
			ExternalTrackerURL:    config.ExternalTrackerURL,
 | 
			
		||||
			ExternalTrackerFormat: config.ExternalTrackerFormat,
 | 
			
		||||
			ExternalTrackerStyle:  config.ExternalTrackerStyle,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	hasWiki := false
 | 
			
		||||
	var externalWiki *api.ExternalWiki
 | 
			
		||||
	if _, err := repo.GetUnit(models.UnitTypeWiki); err == nil {
 | 
			
		||||
		hasWiki = true
 | 
			
		||||
	} else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil {
 | 
			
		||||
		hasWiki = true
 | 
			
		||||
		config := unit.ExternalWikiConfig()
 | 
			
		||||
		externalWiki = &api.ExternalWiki{
 | 
			
		||||
			ExternalWikiURL: config.ExternalWikiURL,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	defaultBranch := repo.DefaultBranch
 | 
			
		||||
	hasPullRequests := false
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +76,10 @@ func getRepoEditOptionFromRepo(repo *models.Repository) *api.EditRepoOption {
 | 
			
		|||
		Website:                   &website,
 | 
			
		||||
		Private:                   &private,
 | 
			
		||||
		HasIssues:                 &hasIssues,
 | 
			
		||||
		ExternalTracker:           externalTracker,
 | 
			
		||||
		InternalTracker:           internalTracker,
 | 
			
		||||
		HasWiki:                   &hasWiki,
 | 
			
		||||
		ExternalWiki:              externalWiki,
 | 
			
		||||
		DefaultBranch:             &defaultBranch,
 | 
			
		||||
		HasPullRequests:           &hasPullRequests,
 | 
			
		||||
		IgnoreWhitespaceConflicts: &ignoreWhitespaceConflicts,
 | 
			
		||||
| 
						 | 
				
			
			@ -143,6 +169,84 @@ func TestAPIRepoEdit(t *testing.T) {
 | 
			
		|||
		assert.Equal(t, *repoEditOption.Archived, *repo1editedOption.Archived)
 | 
			
		||||
		assert.Equal(t, *repoEditOption.Private, *repo1editedOption.Private)
 | 
			
		||||
		assert.Equal(t, *repoEditOption.HasWiki, *repo1editedOption.HasWiki)
 | 
			
		||||
 | 
			
		||||
		//Test editing repo1 to use internal issue and wiki (default)
 | 
			
		||||
		*repoEditOption.HasIssues = true
 | 
			
		||||
		repoEditOption.ExternalTracker = nil
 | 
			
		||||
		repoEditOption.InternalTracker = &api.InternalTracker{
 | 
			
		||||
			EnableTimeTracker:                false,
 | 
			
		||||
			AllowOnlyContributorsToTrackTime: false,
 | 
			
		||||
			EnableIssueDependencies:          false,
 | 
			
		||||
		}
 | 
			
		||||
		*repoEditOption.HasWiki = true
 | 
			
		||||
		repoEditOption.ExternalWiki = nil
 | 
			
		||||
		url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2)
 | 
			
		||||
		req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
		DecodeJSON(t, resp, &repo)
 | 
			
		||||
		assert.NotNil(t, repo)
 | 
			
		||||
		// check repo1 was written to database
 | 
			
		||||
		repo1edited = models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
 | 
			
		||||
		repo1editedOption = getRepoEditOptionFromRepo(repo1edited)
 | 
			
		||||
		assert.Equal(t, *repo1editedOption.HasIssues, true)
 | 
			
		||||
		assert.Nil(t, repo1editedOption.ExternalTracker)
 | 
			
		||||
		assert.Equal(t, *repo1editedOption.InternalTracker, *repoEditOption.InternalTracker)
 | 
			
		||||
		assert.Equal(t, *repo1editedOption.HasWiki, true)
 | 
			
		||||
		assert.Nil(t, repo1editedOption.ExternalWiki)
 | 
			
		||||
 | 
			
		||||
		//Test editing repo1 to use external issue and wiki
 | 
			
		||||
		repoEditOption.ExternalTracker = &api.ExternalTracker{
 | 
			
		||||
			ExternalTrackerURL:    "http://www.somewebsite.com",
 | 
			
		||||
			ExternalTrackerFormat: "http://www.somewebsite.com/{user}/{repo}?issue={index}",
 | 
			
		||||
			ExternalTrackerStyle:  "alphanumeric",
 | 
			
		||||
		}
 | 
			
		||||
		repoEditOption.ExternalWiki = &api.ExternalWiki{
 | 
			
		||||
			ExternalWikiURL: "http://www.somewebsite.com",
 | 
			
		||||
		}
 | 
			
		||||
		req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
		DecodeJSON(t, resp, &repo)
 | 
			
		||||
		assert.NotNil(t, repo)
 | 
			
		||||
		// check repo1 was written to database
 | 
			
		||||
		repo1edited = models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
 | 
			
		||||
		repo1editedOption = getRepoEditOptionFromRepo(repo1edited)
 | 
			
		||||
		assert.Equal(t, *repo1editedOption.HasIssues, true)
 | 
			
		||||
		assert.Equal(t, *repo1editedOption.ExternalTracker, *repoEditOption.ExternalTracker)
 | 
			
		||||
		assert.Equal(t, *repo1editedOption.HasWiki, true)
 | 
			
		||||
		assert.Equal(t, *repo1editedOption.ExternalWiki, *repoEditOption.ExternalWiki)
 | 
			
		||||
 | 
			
		||||
		// Do some tests with invalid URL for external tracker and wiki
 | 
			
		||||
		repoEditOption.ExternalTracker.ExternalTrackerURL = "htp://www.somewebsite.com"
 | 
			
		||||
		req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity)
 | 
			
		||||
		repoEditOption.ExternalTracker.ExternalTrackerURL = "http://www.somewebsite.com"
 | 
			
		||||
		repoEditOption.ExternalTracker.ExternalTrackerFormat = "http://www.somewebsite.com/{user/{repo}?issue={index}"
 | 
			
		||||
		req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity)
 | 
			
		||||
		repoEditOption.ExternalTracker.ExternalTrackerFormat = "http://www.somewebsite.com/{user}/{repo}?issue={index}"
 | 
			
		||||
		repoEditOption.ExternalWiki.ExternalWikiURL = "htp://www.somewebsite.com"
 | 
			
		||||
		req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusUnprocessableEntity)
 | 
			
		||||
 | 
			
		||||
		//Test small repo change through API with issue and wiki option not set; They shall not be touched.
 | 
			
		||||
		*repoEditOption.Description = "small change"
 | 
			
		||||
		repoEditOption.HasIssues = nil
 | 
			
		||||
		repoEditOption.ExternalTracker = nil
 | 
			
		||||
		repoEditOption.HasWiki = nil
 | 
			
		||||
		repoEditOption.ExternalWiki = nil
 | 
			
		||||
		req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption)
 | 
			
		||||
		resp = session.MakeRequest(t, req, http.StatusOK)
 | 
			
		||||
		DecodeJSON(t, resp, &repo)
 | 
			
		||||
		assert.NotNil(t, repo)
 | 
			
		||||
		// check repo1 was written to database
 | 
			
		||||
		repo1edited = models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
 | 
			
		||||
		repo1editedOption = getRepoEditOptionFromRepo(repo1edited)
 | 
			
		||||
		assert.Equal(t, *repo1editedOption.Description, *repoEditOption.Description)
 | 
			
		||||
		assert.Equal(t, *repo1editedOption.HasIssues, true)
 | 
			
		||||
		assert.NotNil(t, *repo1editedOption.ExternalTracker)
 | 
			
		||||
		assert.Equal(t, *repo1editedOption.HasWiki, true)
 | 
			
		||||
		assert.NotNil(t, *repo1editedOption.ExternalWiki)
 | 
			
		||||
 | 
			
		||||
		// reset repo in db
 | 
			
		||||
		url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, *repoEditOption.Name, token2)
 | 
			
		||||
		req = NewRequestWithJSON(t, "PATCH", url, &origRepoEditOption)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -275,12 +275,35 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool)
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	hasIssues := false
 | 
			
		||||
	if _, err := repo.getUnit(e, UnitTypeIssues); err == nil {
 | 
			
		||||
	var externalTracker *api.ExternalTracker
 | 
			
		||||
	var internalTracker *api.InternalTracker
 | 
			
		||||
	if unit, err := repo.getUnit(e, UnitTypeIssues); err == nil {
 | 
			
		||||
		config := unit.IssuesConfig()
 | 
			
		||||
		hasIssues = true
 | 
			
		||||
		internalTracker = &api.InternalTracker{
 | 
			
		||||
			EnableTimeTracker:                config.EnableTimetracker,
 | 
			
		||||
			AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime,
 | 
			
		||||
			EnableIssueDependencies:          config.EnableDependencies,
 | 
			
		||||
		}
 | 
			
		||||
	} else if unit, err := repo.getUnit(e, UnitTypeExternalTracker); err == nil {
 | 
			
		||||
		config := unit.ExternalTrackerConfig()
 | 
			
		||||
		hasIssues = true
 | 
			
		||||
		externalTracker = &api.ExternalTracker{
 | 
			
		||||
			ExternalTrackerURL:    config.ExternalTrackerURL,
 | 
			
		||||
			ExternalTrackerFormat: config.ExternalTrackerFormat,
 | 
			
		||||
			ExternalTrackerStyle:  config.ExternalTrackerStyle,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	hasWiki := false
 | 
			
		||||
	var externalWiki *api.ExternalWiki
 | 
			
		||||
	if _, err := repo.getUnit(e, UnitTypeWiki); err == nil {
 | 
			
		||||
		hasWiki = true
 | 
			
		||||
	} else if unit, err := repo.getUnit(e, UnitTypeExternalWiki); err == nil {
 | 
			
		||||
		hasWiki = true
 | 
			
		||||
		config := unit.ExternalWikiConfig()
 | 
			
		||||
		externalWiki = &api.ExternalWiki{
 | 
			
		||||
			ExternalWikiURL: config.ExternalWikiURL,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	hasPullRequests := false
 | 
			
		||||
	ignoreWhitespaceConflicts := false
 | 
			
		||||
| 
						 | 
				
			
			@ -324,7 +347,10 @@ func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool)
 | 
			
		|||
		Updated:                   repo.UpdatedUnix.AsTime(),
 | 
			
		||||
		Permissions:               permission,
 | 
			
		||||
		HasIssues:                 hasIssues,
 | 
			
		||||
		ExternalTracker:           externalTracker,
 | 
			
		||||
		InternalTracker:           internalTracker,
 | 
			
		||||
		HasWiki:                   hasWiki,
 | 
			
		||||
		ExternalWiki:              externalWiki,
 | 
			
		||||
		HasPullRequests:           hasPullRequests,
 | 
			
		||||
		IgnoreWhitespaceConflicts: ignoreWhitespaceConflicts,
 | 
			
		||||
		AllowMerge:                allowMerge,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,35 @@ type Permission struct {
 | 
			
		|||
	Pull  bool `json:"pull"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InternalTracker represents settings for internal tracker
 | 
			
		||||
// swagger:model
 | 
			
		||||
type InternalTracker struct {
 | 
			
		||||
	// Enable time tracking (Built-in issue tracker)
 | 
			
		||||
	EnableTimeTracker bool `json:"enable_time_tracker"`
 | 
			
		||||
	// Let only contributors track time (Built-in issue tracker)
 | 
			
		||||
	AllowOnlyContributorsToTrackTime bool `json:"allow_only_contributors_to_track_time"`
 | 
			
		||||
	// Enable dependencies for issues and pull requests (Built-in issue tracker)
 | 
			
		||||
	EnableIssueDependencies bool `json:"enable_issue_dependencies"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ExternalTracker represents settings for external tracker
 | 
			
		||||
// swagger:model
 | 
			
		||||
type ExternalTracker struct {
 | 
			
		||||
	// URL of external issue tracker.
 | 
			
		||||
	ExternalTrackerURL string `json:"external_tracker_url"`
 | 
			
		||||
	// External Issue Tracker URL Format. Use the placeholders {user}, {repo} and {index} for the username, repository name and issue index.
 | 
			
		||||
	ExternalTrackerFormat string `json:"external_tracker_format"`
 | 
			
		||||
	// External Issue Tracker Number Format, either `numeric` or `alphanumeric`
 | 
			
		||||
	ExternalTrackerStyle string `json:"external_tracker_style"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ExternalWiki represents setting for external wiki
 | 
			
		||||
// swagger:model
 | 
			
		||||
type ExternalWiki struct {
 | 
			
		||||
	// URL of external wiki.
 | 
			
		||||
	ExternalWikiURL string `json:"external_wiki_url"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Repository represents a repository
 | 
			
		||||
type Repository struct {
 | 
			
		||||
	ID            int64       `json:"id"`
 | 
			
		||||
| 
						 | 
				
			
			@ -42,17 +71,20 @@ type Repository struct {
 | 
			
		|||
	// swagger:strfmt date-time
 | 
			
		||||
	Created time.Time `json:"created_at"`
 | 
			
		||||
	// swagger:strfmt date-time
 | 
			
		||||
	Updated                   time.Time   `json:"updated_at"`
 | 
			
		||||
	Permissions               *Permission `json:"permissions,omitempty"`
 | 
			
		||||
	HasIssues                 bool        `json:"has_issues"`
 | 
			
		||||
	HasWiki                   bool        `json:"has_wiki"`
 | 
			
		||||
	HasPullRequests           bool        `json:"has_pull_requests"`
 | 
			
		||||
	IgnoreWhitespaceConflicts bool        `json:"ignore_whitespace_conflicts"`
 | 
			
		||||
	AllowMerge                bool        `json:"allow_merge_commits"`
 | 
			
		||||
	AllowRebase               bool        `json:"allow_rebase"`
 | 
			
		||||
	AllowRebaseMerge          bool        `json:"allow_rebase_explicit"`
 | 
			
		||||
	AllowSquash               bool        `json:"allow_squash_merge"`
 | 
			
		||||
	AvatarURL                 string      `json:"avatar_url"`
 | 
			
		||||
	Updated                   time.Time        `json:"updated_at"`
 | 
			
		||||
	Permissions               *Permission      `json:"permissions,omitempty"`
 | 
			
		||||
	HasIssues                 bool             `json:"has_issues"`
 | 
			
		||||
	InternalTracker           *InternalTracker `json:"internal_tracker,omitempty"`
 | 
			
		||||
	ExternalTracker           *ExternalTracker `json:"external_tracker,omitempty"`
 | 
			
		||||
	HasWiki                   bool             `json:"has_wiki"`
 | 
			
		||||
	ExternalWiki              *ExternalWiki    `json:"external_wiki,omitempty"`
 | 
			
		||||
	HasPullRequests           bool             `json:"has_pull_requests"`
 | 
			
		||||
	IgnoreWhitespaceConflicts bool             `json:"ignore_whitespace_conflicts"`
 | 
			
		||||
	AllowMerge                bool             `json:"allow_merge_commits"`
 | 
			
		||||
	AllowRebase               bool             `json:"allow_rebase"`
 | 
			
		||||
	AllowRebaseMerge          bool             `json:"allow_rebase_explicit"`
 | 
			
		||||
	AllowSquash               bool             `json:"allow_squash_merge"`
 | 
			
		||||
	AvatarURL                 string           `json:"avatar_url"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateRepoOption options when creating repository
 | 
			
		||||
| 
						 | 
				
			
			@ -95,8 +127,14 @@ type EditRepoOption struct {
 | 
			
		|||
	Private *bool `json:"private,omitempty"`
 | 
			
		||||
	// either `true` to enable issues for this repository or `false` to disable them.
 | 
			
		||||
	HasIssues *bool `json:"has_issues,omitempty"`
 | 
			
		||||
	// set this structure to configure internal issue tracker (requires has_issues)
 | 
			
		||||
	InternalTracker *InternalTracker `json:"internal_tracker,omitempty"`
 | 
			
		||||
	// set this structure to use external issue tracker (requires has_issues)
 | 
			
		||||
	ExternalTracker *ExternalTracker `json:"external_tracker,omitempty"`
 | 
			
		||||
	// either `true` to enable the wiki for this repository or `false` to disable it.
 | 
			
		||||
	HasWiki *bool `json:"has_wiki,omitempty"`
 | 
			
		||||
	// set this structure to use external wiki instead of internal (requires has_wiki)
 | 
			
		||||
	ExternalWiki *ExternalWiki `json:"external_wiki,omitempty"`
 | 
			
		||||
	// sets the default branch for this repository.
 | 
			
		||||
	DefaultBranch *string `json:"default_branch,omitempty"`
 | 
			
		||||
	// either `true` to allow pull requests, or `false` to prevent pull request.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ import (
 | 
			
		|||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
	"code.gitea.io/gitea/modules/validation"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/convert"
 | 
			
		||||
	mirror_service "code.gitea.io/gitea/services/mirror"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -669,27 +670,56 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
 | 
			
		|||
			units = append(units, *unit)
 | 
			
		||||
		}
 | 
			
		||||
	} else if *opts.HasIssues {
 | 
			
		||||
		// We don't currently allow setting individual issue settings through the API,
 | 
			
		||||
		// only can enable/disable issues, so when enabling issues,
 | 
			
		||||
		// we either get the existing config which means it was already enabled,
 | 
			
		||||
		// or create a new config since it doesn't exist.
 | 
			
		||||
		unit, err := repo.GetUnit(models.UnitTypeIssues)
 | 
			
		||||
		var config *models.IssuesConfig
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			// Unit type doesn't exist so we make a new config file with default values
 | 
			
		||||
			config = &models.IssuesConfig{
 | 
			
		||||
				EnableTimetracker:                true,
 | 
			
		||||
				AllowOnlyContributorsToTrackTime: true,
 | 
			
		||||
				EnableDependencies:               true,
 | 
			
		||||
		if opts.ExternalTracker != nil {
 | 
			
		||||
 | 
			
		||||
			// Check that values are valid
 | 
			
		||||
			if !validation.IsValidExternalURL(opts.ExternalTracker.ExternalTrackerURL) {
 | 
			
		||||
				err := fmt.Errorf("External tracker URL not valid")
 | 
			
		||||
				ctx.Error(http.StatusUnprocessableEntity, "Invalid external tracker URL", err)
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if len(opts.ExternalTracker.ExternalTrackerFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(opts.ExternalTracker.ExternalTrackerFormat) {
 | 
			
		||||
				err := fmt.Errorf("External tracker URL format not valid")
 | 
			
		||||
				ctx.Error(http.StatusUnprocessableEntity, "Invalid external tracker URL format", err)
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			units = append(units, models.RepoUnit{
 | 
			
		||||
				RepoID: repo.ID,
 | 
			
		||||
				Type:   models.UnitTypeExternalTracker,
 | 
			
		||||
				Config: &models.ExternalTrackerConfig{
 | 
			
		||||
					ExternalTrackerURL:    opts.ExternalTracker.ExternalTrackerURL,
 | 
			
		||||
					ExternalTrackerFormat: opts.ExternalTracker.ExternalTrackerFormat,
 | 
			
		||||
					ExternalTrackerStyle:  opts.ExternalTracker.ExternalTrackerStyle,
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
		} else {
 | 
			
		||||
			config = unit.IssuesConfig()
 | 
			
		||||
			// Default to built-in tracker
 | 
			
		||||
			var config *models.IssuesConfig
 | 
			
		||||
 | 
			
		||||
			if opts.InternalTracker != nil {
 | 
			
		||||
				config = &models.IssuesConfig{
 | 
			
		||||
					EnableTimetracker:                opts.InternalTracker.EnableTimeTracker,
 | 
			
		||||
					AllowOnlyContributorsToTrackTime: opts.InternalTracker.AllowOnlyContributorsToTrackTime,
 | 
			
		||||
					EnableDependencies:               opts.InternalTracker.EnableIssueDependencies,
 | 
			
		||||
				}
 | 
			
		||||
			} else if unit, err := repo.GetUnit(models.UnitTypeIssues); err != nil {
 | 
			
		||||
				// Unit type doesn't exist so we make a new config file with default values
 | 
			
		||||
				config = &models.IssuesConfig{
 | 
			
		||||
					EnableTimetracker:                true,
 | 
			
		||||
					AllowOnlyContributorsToTrackTime: true,
 | 
			
		||||
					EnableDependencies:               true,
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				config = unit.IssuesConfig()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			units = append(units, models.RepoUnit{
 | 
			
		||||
				RepoID: repo.ID,
 | 
			
		||||
				Type:   models.UnitTypeIssues,
 | 
			
		||||
				Config: config,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		units = append(units, models.RepoUnit{
 | 
			
		||||
			RepoID: repo.ID,
 | 
			
		||||
			Type:   models.UnitTypeIssues,
 | 
			
		||||
			Config: config,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.HasWiki == nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -700,16 +730,30 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
 | 
			
		|||
			units = append(units, *unit)
 | 
			
		||||
		}
 | 
			
		||||
	} else if *opts.HasWiki {
 | 
			
		||||
		// We don't currently allow setting individual wiki settings through the API,
 | 
			
		||||
		// only can enable/disable the wiki, so when enabling the wiki,
 | 
			
		||||
		// we either get the existing config which means it was already enabled,
 | 
			
		||||
		// or create a new config since it doesn't exist.
 | 
			
		||||
		config := &models.UnitConfig{}
 | 
			
		||||
		units = append(units, models.RepoUnit{
 | 
			
		||||
			RepoID: repo.ID,
 | 
			
		||||
			Type:   models.UnitTypeWiki,
 | 
			
		||||
			Config: config,
 | 
			
		||||
		})
 | 
			
		||||
		if opts.ExternalWiki != nil {
 | 
			
		||||
 | 
			
		||||
			// Check that values are valid
 | 
			
		||||
			if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) {
 | 
			
		||||
				err := fmt.Errorf("External wiki URL not valid")
 | 
			
		||||
				ctx.Error(http.StatusUnprocessableEntity, "", "Invalid external wiki URL")
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			units = append(units, models.RepoUnit{
 | 
			
		||||
				RepoID: repo.ID,
 | 
			
		||||
				Type:   models.UnitTypeExternalWiki,
 | 
			
		||||
				Config: &models.ExternalWikiConfig{
 | 
			
		||||
					ExternalWikiURL: opts.ExternalWiki.ExternalWikiURL,
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
		} else {
 | 
			
		||||
			config := &models.UnitConfig{}
 | 
			
		||||
			units = append(units, models.RepoUnit{
 | 
			
		||||
				RepoID: repo.ID,
 | 
			
		||||
				Type:   models.UnitTypeWiki,
 | 
			
		||||
				Config: config,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if opts.HasPullRequests == nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8469,6 +8469,12 @@
 | 
			
		|||
          "type": "string",
 | 
			
		||||
          "x-go-name": "Description"
 | 
			
		||||
        },
 | 
			
		||||
        "external_tracker": {
 | 
			
		||||
          "$ref": "#/definitions/ExternalTracker"
 | 
			
		||||
        },
 | 
			
		||||
        "external_wiki": {
 | 
			
		||||
          "$ref": "#/definitions/ExternalWiki"
 | 
			
		||||
        },
 | 
			
		||||
        "has_issues": {
 | 
			
		||||
          "description": "either `true` to enable issues for this repository or `false` to disable them.",
 | 
			
		||||
          "type": "boolean",
 | 
			
		||||
| 
						 | 
				
			
			@ -8489,6 +8495,9 @@
 | 
			
		|||
          "type": "boolean",
 | 
			
		||||
          "x-go-name": "IgnoreWhitespaceConflicts"
 | 
			
		||||
        },
 | 
			
		||||
        "internal_tracker": {
 | 
			
		||||
          "$ref": "#/definitions/InternalTracker"
 | 
			
		||||
        },
 | 
			
		||||
        "name": {
 | 
			
		||||
          "description": "name of the repository",
 | 
			
		||||
          "type": "string",
 | 
			
		||||
| 
						 | 
				
			
			@ -8644,6 +8653,40 @@
 | 
			
		|||
      },
 | 
			
		||||
      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
    },
 | 
			
		||||
    "ExternalTracker": {
 | 
			
		||||
      "description": "ExternalTracker represents settings for external tracker",
 | 
			
		||||
      "type": "object",
 | 
			
		||||
      "properties": {
 | 
			
		||||
        "external_tracker_format": {
 | 
			
		||||
          "description": "External Issue Tracker URL Format. Use the placeholders {user}, {repo} and {index} for the username, repository name and issue index.",
 | 
			
		||||
          "type": "string",
 | 
			
		||||
          "x-go-name": "ExternalTrackerFormat"
 | 
			
		||||
        },
 | 
			
		||||
        "external_tracker_style": {
 | 
			
		||||
          "description": "External Issue Tracker Number Format, either `numeric` or `alphanumeric`",
 | 
			
		||||
          "type": "string",
 | 
			
		||||
          "x-go-name": "ExternalTrackerStyle"
 | 
			
		||||
        },
 | 
			
		||||
        "external_tracker_url": {
 | 
			
		||||
          "description": "URL of external issue tracker.",
 | 
			
		||||
          "type": "string",
 | 
			
		||||
          "x-go-name": "ExternalTrackerURL"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
    },
 | 
			
		||||
    "ExternalWiki": {
 | 
			
		||||
      "description": "ExternalWiki represents setting for external wiki",
 | 
			
		||||
      "type": "object",
 | 
			
		||||
      "properties": {
 | 
			
		||||
        "external_wiki_url": {
 | 
			
		||||
          "description": "URL of external wiki.",
 | 
			
		||||
          "type": "string",
 | 
			
		||||
          "x-go-name": "ExternalWikiURL"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
    },
 | 
			
		||||
    "FileCommitResponse": {
 | 
			
		||||
      "type": "object",
 | 
			
		||||
      "title": "FileCommitResponse contains information generated from a Git commit for a repo's file.",
 | 
			
		||||
| 
						 | 
				
			
			@ -9008,6 +9051,28 @@
 | 
			
		|||
      },
 | 
			
		||||
      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
    },
 | 
			
		||||
    "InternalTracker": {
 | 
			
		||||
      "description": "InternalTracker represents settings for internal tracker",
 | 
			
		||||
      "type": "object",
 | 
			
		||||
      "properties": {
 | 
			
		||||
        "allow_only_contributors_to_track_time": {
 | 
			
		||||
          "description": "Let only contributors track time (Built-in issue tracker)",
 | 
			
		||||
          "type": "boolean",
 | 
			
		||||
          "x-go-name": "AllowOnlyContributorsToTrackTime"
 | 
			
		||||
        },
 | 
			
		||||
        "enable_issue_dependencies": {
 | 
			
		||||
          "description": "Enable dependencies for issues and pull requests (Built-in issue tracker)",
 | 
			
		||||
          "type": "boolean",
 | 
			
		||||
          "x-go-name": "EnableIssueDependencies"
 | 
			
		||||
        },
 | 
			
		||||
        "enable_time_tracker": {
 | 
			
		||||
          "description": "Enable time tracking (Built-in issue tracker)",
 | 
			
		||||
          "type": "boolean",
 | 
			
		||||
          "x-go-name": "EnableTimeTracker"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "x-go-package": "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
    },
 | 
			
		||||
    "Issue": {
 | 
			
		||||
      "description": "Issue represents an issue in a repository",
 | 
			
		||||
      "type": "object",
 | 
			
		||||
| 
						 | 
				
			
			@ -9863,6 +9928,12 @@
 | 
			
		|||
          "type": "boolean",
 | 
			
		||||
          "x-go-name": "Empty"
 | 
			
		||||
        },
 | 
			
		||||
        "external_tracker": {
 | 
			
		||||
          "$ref": "#/definitions/ExternalTracker"
 | 
			
		||||
        },
 | 
			
		||||
        "external_wiki": {
 | 
			
		||||
          "$ref": "#/definitions/ExternalWiki"
 | 
			
		||||
        },
 | 
			
		||||
        "fork": {
 | 
			
		||||
          "type": "boolean",
 | 
			
		||||
          "x-go-name": "Fork"
 | 
			
		||||
| 
						 | 
				
			
			@ -9901,6 +9972,9 @@
 | 
			
		|||
          "type": "boolean",
 | 
			
		||||
          "x-go-name": "IgnoreWhitespaceConflicts"
 | 
			
		||||
        },
 | 
			
		||||
        "internal_tracker": {
 | 
			
		||||
          "$ref": "#/definitions/InternalTracker"
 | 
			
		||||
        },
 | 
			
		||||
        "mirror": {
 | 
			
		||||
          "type": "boolean",
 | 
			
		||||
          "x-go-name": "Mirror"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue