Allow changing global wiki editability via the API

The global wiki editability can be set via the web UI, this patch makes
it possible to set the same thing via the API too. This is accomplished
by adjusting the GET and PATCH handlers of the
`/api/v1/repos/{owner}/{repo}` route.

The first will include the property when checking the repo's settings,
the second allows a repo admin to change the setting too.

Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
This commit is contained in:
Gergely Nagy 2024-04-16 22:51:36 +02:00
parent ada8bfa52f
commit df8e58c5cb
No known key found for this signature in database
5 changed files with 97 additions and 4 deletions

View file

@ -89,6 +89,7 @@ type Repository struct {
HasWiki bool `json:"has_wiki"` HasWiki bool `json:"has_wiki"`
ExternalWiki *ExternalWiki `json:"external_wiki,omitempty"` ExternalWiki *ExternalWiki `json:"external_wiki,omitempty"`
WikiBranch string `json:"wiki_branch,omitempty"` WikiBranch string `json:"wiki_branch,omitempty"`
GloballyEditableWiki bool `json:"globally_editable_wiki"`
HasPullRequests bool `json:"has_pull_requests"` HasPullRequests bool `json:"has_pull_requests"`
HasProjects bool `json:"has_projects"` HasProjects bool `json:"has_projects"`
HasReleases bool `json:"has_releases"` HasReleases bool `json:"has_releases"`
@ -185,6 +186,8 @@ type EditRepoOption struct {
HasWiki *bool `json:"has_wiki,omitempty"` HasWiki *bool `json:"has_wiki,omitempty"`
// set this structure to use external wiki instead of internal // set this structure to use external wiki instead of internal
ExternalWiki *ExternalWiki `json:"external_wiki,omitempty"` ExternalWiki *ExternalWiki `json:"external_wiki,omitempty"`
// set the globally editable state of the wiki
GloballyEditableWiki *bool `json:"globally_editable_wiki,omitempty"`
// sets the default branch for this repository. // sets the default branch for this repository.
DefaultBranch *string `json:"default_branch,omitempty"` DefaultBranch *string `json:"default_branch,omitempty"`
// sets the branch used for this repository's wiki. // sets the branch used for this repository's wiki.

View file

@ -845,6 +845,15 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
newHasWiki = *opts.HasWiki newHasWiki = *opts.HasWiki
} }
if currHasWiki || newHasWiki { if currHasWiki || newHasWiki {
wikiPermissions := repo.MustGetUnit(ctx, unit_model.TypeWiki).DefaultPermissions
if opts.GloballyEditableWiki != nil {
if *opts.GloballyEditableWiki {
wikiPermissions = repo_model.UnitAccessModeWrite
} else {
wikiPermissions = repo_model.UnitAccessModeRead
}
}
if newHasWiki && opts.ExternalWiki != nil && !unit_model.TypeExternalWiki.UnitGlobalDisabled() { if newHasWiki && opts.ExternalWiki != nil && !unit_model.TypeExternalWiki.UnitGlobalDisabled() {
// Check that values are valid // Check that values are valid
if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) { if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) {
@ -864,9 +873,10 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
} else if newHasWiki && opts.ExternalWiki == nil && !unit_model.TypeWiki.UnitGlobalDisabled() { } else if newHasWiki && opts.ExternalWiki == nil && !unit_model.TypeWiki.UnitGlobalDisabled() {
config := &repo_model.UnitConfig{} config := &repo_model.UnitConfig{}
units = append(units, repo_model.RepoUnit{ units = append(units, repo_model.RepoUnit{
RepoID: repo.ID, RepoID: repo.ID,
Type: unit_model.TypeWiki, Type: unit_model.TypeWiki,
Config: config, Config: config,
DefaultPermissions: wikiPermissions,
}) })
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki) deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
} else if !newHasWiki { } else if !newHasWiki {
@ -876,6 +886,14 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
if !unit_model.TypeWiki.UnitGlobalDisabled() { if !unit_model.TypeWiki.UnitGlobalDisabled() {
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki) deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
} }
} else if *opts.GloballyEditableWiki {
config := &repo_model.UnitConfig{}
units = append(units, repo_model.RepoUnit{
RepoID: repo.ID,
Type: unit_model.TypeWiki,
Config: config,
DefaultPermissions: wikiPermissions,
})
} }
} }

View file

@ -77,9 +77,13 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
} }
} }
hasWiki := false hasWiki := false
globallyEditableWiki := false
var externalWiki *api.ExternalWiki var externalWiki *api.ExternalWiki
if _, err := repo.GetUnit(ctx, unit_model.TypeWiki); err == nil { if wikiUnit, err := repo.GetUnit(ctx, unit_model.TypeWiki); err == nil {
hasWiki = true hasWiki = true
if wikiUnit.DefaultPermissions == repo_model.UnitAccessModeWrite {
globallyEditableWiki = true
}
} else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalWiki); err == nil { } else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalWiki); err == nil {
hasWiki = true hasWiki = true
config := unit.ExternalWikiConfig() config := unit.ExternalWikiConfig()
@ -211,6 +215,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
InternalTracker: internalTracker, InternalTracker: internalTracker,
HasWiki: hasWiki, HasWiki: hasWiki,
WikiBranch: repo.WikiBranch, WikiBranch: repo.WikiBranch,
GloballyEditableWiki: globallyEditableWiki,
HasProjects: hasProjects, HasProjects: hasProjects,
HasReleases: hasReleases, HasReleases: hasReleases,
HasPackages: hasPackages, HasPackages: hasPackages,

View file

@ -20835,6 +20835,11 @@
"external_wiki": { "external_wiki": {
"$ref": "#/definitions/ExternalWiki" "$ref": "#/definitions/ExternalWiki"
}, },
"globally_editable_wiki": {
"description": "set the globally editable state of the wiki",
"type": "boolean",
"x-go-name": "GloballyEditableWiki"
},
"has_actions": { "has_actions": {
"description": "either `true` to enable actions unit, or `false` to disable them.", "description": "either `true` to enable actions unit, or `false` to disable them.",
"type": "boolean", "type": "boolean",
@ -23749,6 +23754,10 @@
"type": "string", "type": "string",
"x-go-name": "FullName" "x-go-name": "FullName"
}, },
"globally_editable_wiki": {
"type": "boolean",
"x-go-name": "GloballyEditableWiki"
},
"has_actions": { "has_actions": {
"type": "boolean", "type": "boolean",
"x-go-name": "HasActions" "x-go-name": "HasActions"

View file

@ -15,6 +15,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit" unit_model "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
repo_service "code.gitea.io/gitea/services/repository" repo_service "code.gitea.io/gitea/services/repository"
"code.gitea.io/gitea/tests" "code.gitea.io/gitea/tests"
@ -286,6 +287,63 @@ func TestAPIEditOtherWikiPage(t *testing.T) {
testCreateWiki(http.StatusCreated) testCreateWiki(http.StatusCreated)
} }
func TestAPISetWikiGlobalEditability(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
// Create a new repository for testing purposes
repo, _, f := CreateDeclarativeRepo(t, user, "", []unit_model.Type{
unit_model.TypeCode,
unit_model.TypeWiki,
}, nil, nil)
defer f()
urlStr := fmt.Sprintf("/api/v1/repos/%s", repo.FullName())
assertGlobalEditability := func(t *testing.T, editability bool) {
t.Helper()
req := NewRequest(t, "GET", urlStr)
resp := MakeRequest(t, req, http.StatusOK)
var opts api.Repository
DecodeJSON(t, resp, &opts)
assert.Equal(t, opts.GloballyEditableWiki, editability)
}
t.Run("api includes GloballyEditableWiki", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
assertGlobalEditability(t, false)
})
t.Run("api can turn on GloballyEditableWiki", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
globallyEditable := true
req := NewRequestWithJSON(t, "PATCH", urlStr, &api.EditRepoOption{
GloballyEditableWiki: &globallyEditable,
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusOK)
assertGlobalEditability(t, true)
})
t.Run("disabling the wiki disables GloballyEditableWiki", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
hasWiki := false
req := NewRequestWithJSON(t, "PATCH", urlStr, &api.EditRepoOption{
HasWiki: &hasWiki,
}).AddTokenAuth(token)
MakeRequest(t, req, http.StatusOK)
assertGlobalEditability(t, false)
})
}
func TestAPIListPageRevisions(t *testing.T) { func TestAPIListPageRevisions(t *testing.T) {
defer tests.PrepareTestEnv(t)() defer tests.PrepareTestEnv(t)()
username := "user2" username := "user2"