2021-10-25 05:43:40 +02:00
|
|
|
// Copyright 2021 The Gitea Authors. All rights reserved.
|
[GITEA] Allow changing the repo Wiki branch to main
Previously, the repo wiki was hardcoded to use `master` as its branch,
this change makes it possible to use `main` (or something else, governed
by `[repository].DEFAULT_BRANCH`, a setting that already exists and
defaults to `main`).
The way it is done is that a new column is added to the `repository`
table: `wiki_branch`. The migration will make existing repositories
default to `master`, for compatibility's sake, even if they don't have a
Wiki (because it's easier to do that). Newly created repositories will
default to `[repository].DEFAULT_BRANCH` instead.
The Wiki service was updated to use the branch name stored in the
database, and fall back to the default if it is empty.
Old repositories with Wikis using the older `master` branch will have
the option to do a one-time transition to `main`, available via the
repository settings in the "Danger Zone". This option will only be
available for repositories that have the internal wiki enabled, it is
not empty, and the wiki branch is not `[repository].DEFAULT_BRANCH`.
When migrating a repository with a Wiki, Forgejo will use the same
branch name for the wiki as the source repository did. If that's not the
same as the default, the option to normalize it will be available after
the migration's done.
Additionally, the `/api/v1/{owner}/{repo}` endpoint was updated: it will
now include the wiki branch name in `GET` requests, and allow changing
the wiki branch via `PATCH`.
Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
(cherry picked from commit d87c526d2a313fa45093ab49b78bb30322b33298)
2024-01-30 12:18:53 +01:00
|
|
|
// Copyright 2024 The Forgejo Authors c/o Codeberg e.V.. All rights reserved.
|
2022-11-27 19:20:29 +01:00
|
|
|
// SPDX-License-Identifier: MIT
|
2021-10-25 05:43:40 +02:00
|
|
|
|
2022-09-02 21:18:23 +02:00
|
|
|
package integration
|
2021-10-25 05:43:40 +02:00
|
|
|
|
|
|
|
import (
|
2023-12-20 21:44:55 +01:00
|
|
|
"context"
|
2021-10-25 05:43:40 +02:00
|
|
|
"encoding/base64"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
2024-11-14 02:13:22 +01:00
|
|
|
"net/url"
|
2021-10-25 05:43:40 +02:00
|
|
|
"testing"
|
|
|
|
|
2023-01-17 22:46:03 +01:00
|
|
|
auth_model "code.gitea.io/gitea/models/auth"
|
2023-12-20 21:44:55 +01:00
|
|
|
repo_model "code.gitea.io/gitea/models/repo"
|
|
|
|
unit_model "code.gitea.io/gitea/models/unit"
|
|
|
|
"code.gitea.io/gitea/models/unittest"
|
2024-04-16 22:51:36 +02:00
|
|
|
user_model "code.gitea.io/gitea/models/user"
|
2024-04-25 00:17:53 +02:00
|
|
|
"code.gitea.io/gitea/modules/optional"
|
2021-10-25 05:43:40 +02:00
|
|
|
api "code.gitea.io/gitea/modules/structs"
|
2023-12-20 21:44:55 +01:00
|
|
|
repo_service "code.gitea.io/gitea/services/repository"
|
2022-09-02 21:18:23 +02:00
|
|
|
"code.gitea.io/gitea/tests"
|
2021-10-25 05:43:40 +02:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2024-07-30 21:41:10 +02:00
|
|
|
"github.com/stretchr/testify/require"
|
2021-10-25 05:43:40 +02:00
|
|
|
)
|
|
|
|
|
[GITEA] Allow changing the repo Wiki branch to main
Previously, the repo wiki was hardcoded to use `master` as its branch,
this change makes it possible to use `main` (or something else, governed
by `[repository].DEFAULT_BRANCH`, a setting that already exists and
defaults to `main`).
The way it is done is that a new column is added to the `repository`
table: `wiki_branch`. The migration will make existing repositories
default to `master`, for compatibility's sake, even if they don't have a
Wiki (because it's easier to do that). Newly created repositories will
default to `[repository].DEFAULT_BRANCH` instead.
The Wiki service was updated to use the branch name stored in the
database, and fall back to the default if it is empty.
Old repositories with Wikis using the older `master` branch will have
the option to do a one-time transition to `main`, available via the
repository settings in the "Danger Zone". This option will only be
available for repositories that have the internal wiki enabled, it is
not empty, and the wiki branch is not `[repository].DEFAULT_BRANCH`.
When migrating a repository with a Wiki, Forgejo will use the same
branch name for the wiki as the source repository did. If that's not the
same as the default, the option to normalize it will be available after
the migration's done.
Additionally, the `/api/v1/{owner}/{repo}` endpoint was updated: it will
now include the wiki branch name in `GET` requests, and allow changing
the wiki branch via `PATCH`.
Signed-off-by: Gergely Nagy <forgejo@gergo.csillger.hu>
(cherry picked from commit d87c526d2a313fa45093ab49b78bb30322b33298)
2024-01-30 12:18:53 +01:00
|
|
|
func TestAPIRenameWikiBranch(t *testing.T) {
|
|
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
|
|
|
|
username := "user2"
|
|
|
|
session := loginUser(t, username)
|
|
|
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
|
|
|
|
|
|
|
repoURLStr := fmt.Sprintf("/api/v1/repos/%s/%s", username, "repo1")
|
|
|
|
wikiBranch := "wiki"
|
|
|
|
req := NewRequestWithJSON(t, "PATCH", repoURLStr, &api.EditRepoOption{
|
|
|
|
WikiBranch: &wikiBranch,
|
|
|
|
}).AddTokenAuth(token)
|
|
|
|
MakeRequest(t, req, http.StatusOK)
|
|
|
|
|
|
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
|
|
|
assert.Equal(t, "wiki", repo.WikiBranch)
|
|
|
|
|
|
|
|
req = NewRequest(t, "GET", repoURLStr)
|
|
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
|
|
var repoData *api.Repository
|
|
|
|
DecodeJSON(t, resp, &repoData)
|
|
|
|
assert.Equal(t, "wiki", repoData.WikiBranch)
|
|
|
|
}
|
|
|
|
|
2021-10-25 05:43:40 +02:00
|
|
|
func TestAPIGetWikiPage(t *testing.T) {
|
2022-09-02 21:18:23 +02:00
|
|
|
defer tests.PrepareTestEnv(t)()
|
2021-10-25 05:43:40 +02:00
|
|
|
|
|
|
|
username := "user2"
|
|
|
|
|
|
|
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/page/Home", username, "repo1")
|
|
|
|
|
|
|
|
req := NewRequest(t, "GET", urlStr)
|
2022-12-02 04:39:42 +01:00
|
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
2021-10-25 05:43:40 +02:00
|
|
|
var page *api.WikiPage
|
|
|
|
DecodeJSON(t, resp, &page)
|
|
|
|
|
|
|
|
assert.Equal(t, &api.WikiPage{
|
|
|
|
WikiPageMetaData: &api.WikiPageMetaData{
|
|
|
|
Title: "Home",
|
|
|
|
HTMLURL: page.HTMLURL,
|
|
|
|
SubURL: "Home",
|
|
|
|
LastCommit: &api.WikiCommit{
|
|
|
|
ID: "2c54faec6c45d31c1abfaecdab471eac6633738a",
|
|
|
|
Author: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Ethan Koenig",
|
|
|
|
Email: "ethantkoenig@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2017-11-27T04:31:18Z",
|
|
|
|
},
|
|
|
|
Committer: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Ethan Koenig",
|
|
|
|
Email: "ethantkoenig@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2017-11-27T04:31:18Z",
|
|
|
|
},
|
|
|
|
Message: "Add Home.md\n",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ContentBase64: base64.RawStdEncoding.EncodeToString(
|
|
|
|
[]byte("# Home page\n\nThis is the home page!\n"),
|
|
|
|
),
|
|
|
|
CommitCount: 1,
|
|
|
|
Sidebar: "",
|
|
|
|
Footer: "",
|
|
|
|
}, page)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPIListWikiPages(t *testing.T) {
|
2022-09-02 21:18:23 +02:00
|
|
|
defer tests.PrepareTestEnv(t)()
|
2021-10-25 05:43:40 +02:00
|
|
|
|
|
|
|
username := "user2"
|
|
|
|
|
|
|
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/pages", username, "repo1")
|
|
|
|
|
|
|
|
req := NewRequest(t, "GET", urlStr)
|
2022-12-02 04:39:42 +01:00
|
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
2021-10-25 05:43:40 +02:00
|
|
|
|
|
|
|
var meta []*api.WikiPageMetaData
|
|
|
|
DecodeJSON(t, resp, &meta)
|
|
|
|
|
|
|
|
dummymeta := []*api.WikiPageMetaData{
|
|
|
|
{
|
|
|
|
Title: "Home",
|
|
|
|
HTMLURL: meta[0].HTMLURL,
|
|
|
|
SubURL: "Home",
|
|
|
|
LastCommit: &api.WikiCommit{
|
|
|
|
ID: "2c54faec6c45d31c1abfaecdab471eac6633738a",
|
|
|
|
Author: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Ethan Koenig",
|
|
|
|
Email: "ethantkoenig@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2017-11-27T04:31:18Z",
|
|
|
|
},
|
|
|
|
Committer: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Ethan Koenig",
|
|
|
|
Email: "ethantkoenig@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2017-11-27T04:31:18Z",
|
|
|
|
},
|
|
|
|
Message: "Add Home.md\n",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2024-11-24 16:41:09 +01:00
|
|
|
Title: "Long Page",
|
2021-10-25 05:43:40 +02:00
|
|
|
HTMLURL: meta[1].HTMLURL,
|
2024-11-24 16:41:09 +01:00
|
|
|
SubURL: "Long-Page",
|
|
|
|
LastCommit: &api.WikiCommit{
|
|
|
|
ID: "d49ac742d44063dcf69d4e0afe725813b777dd89",
|
|
|
|
Author: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Oto Šťáva",
|
|
|
|
Email: "oto.stava@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2024-11-23T11:16:51Z",
|
|
|
|
},
|
|
|
|
Committer: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Oto Šťáva",
|
|
|
|
Email: "oto.stava@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2024-11-23T11:16:51Z",
|
|
|
|
},
|
|
|
|
Message: "add long page\n",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Title: "Page With Image",
|
|
|
|
HTMLURL: meta[2].HTMLURL,
|
2021-10-25 05:43:40 +02:00
|
|
|
SubURL: "Page-With-Image",
|
|
|
|
LastCommit: &api.WikiCommit{
|
|
|
|
ID: "0cf15c3f66ec8384480ed9c3cf87c9e97fbb0ec3",
|
|
|
|
Author: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Gabriel Silva Simões",
|
|
|
|
Email: "simoes.sgabriel@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2019-01-25T01:41:55Z",
|
|
|
|
},
|
|
|
|
Committer: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Gabriel Silva Simões",
|
|
|
|
Email: "simoes.sgabriel@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2019-01-25T01:41:55Z",
|
|
|
|
},
|
|
|
|
Message: "Add jpeg.jpg and page with image\n",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Title: "Page With Spaced Name",
|
2024-11-24 16:41:09 +01:00
|
|
|
HTMLURL: meta[3].HTMLURL,
|
2021-10-25 05:43:40 +02:00
|
|
|
SubURL: "Page-With-Spaced-Name",
|
|
|
|
LastCommit: &api.WikiCommit{
|
|
|
|
ID: "c10d10b7e655b3dab1f53176db57c8219a5488d6",
|
|
|
|
Author: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Gabriel Silva Simões",
|
|
|
|
Email: "simoes.sgabriel@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2019-01-25T01:39:51Z",
|
|
|
|
},
|
|
|
|
Committer: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Gabriel Silva Simões",
|
|
|
|
Email: "simoes.sgabriel@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2019-01-25T01:39:51Z",
|
|
|
|
},
|
|
|
|
Message: "Add page with spaced name\n",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Title: "Unescaped File",
|
2024-11-24 16:41:09 +01:00
|
|
|
HTMLURL: meta[4].HTMLURL,
|
2021-10-25 05:43:40 +02:00
|
|
|
SubURL: "Unescaped-File",
|
|
|
|
LastCommit: &api.WikiCommit{
|
|
|
|
ID: "0dca5bd9b5d7ef937710e056f575e86c0184ba85",
|
|
|
|
Author: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "6543",
|
|
|
|
Email: "6543@obermui.de",
|
|
|
|
},
|
|
|
|
Date: "2021-07-19T16:42:46Z",
|
|
|
|
},
|
|
|
|
Committer: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "6543",
|
|
|
|
Email: "6543@obermui.de",
|
|
|
|
},
|
|
|
|
Date: "2021-07-19T16:42:46Z",
|
|
|
|
},
|
|
|
|
Message: "add unescaped file\n",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, dummymeta, meta)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPINewWikiPage(t *testing.T) {
|
2024-11-14 02:13:22 +01:00
|
|
|
defer tests.PrepareTestEnv(t)()
|
2021-10-25 05:43:40 +02:00
|
|
|
for _, title := range []string{
|
|
|
|
"New page",
|
|
|
|
"&&&&",
|
|
|
|
} {
|
|
|
|
username := "user2"
|
|
|
|
session := loginUser(t, username)
|
Redesign Scoped Access Tokens (#24767)
## Changes
- Adds the following high level access scopes, each with `read` and
`write` levels:
- `activitypub`
- `admin` (hidden if user is not a site admin)
- `misc`
- `notification`
- `organization`
- `package`
- `issue`
- `repository`
- `user`
- Adds new middleware function `tokenRequiresScopes()` in addition to
`reqToken()`
- `tokenRequiresScopes()` is used for each high-level api section
- _if_ a scoped token is present, checks that the required scope is
included based on the section and HTTP method
- `reqToken()` is used for individual routes
- checks that required authentication is present (but does not check
scope levels as this will already have been handled by
`tokenRequiresScopes()`
- Adds migration to convert old scoped access tokens to the new set of
scopes
- Updates the user interface for scope selection
### User interface example
<img width="903" alt="Screen Shot 2023-05-31 at 1 56 55 PM"
src="https://github.com/go-gitea/gitea/assets/23248839/654766ec-2143-4f59-9037-3b51600e32f3">
<img width="917" alt="Screen Shot 2023-05-31 at 1 56 43 PM"
src="https://github.com/go-gitea/gitea/assets/23248839/1ad64081-012c-4a73-b393-66b30352654c">
## tokenRequiresScopes Design Decision
- `tokenRequiresScopes()` was added to more reliably cover api routes.
For an incoming request, this function uses the given scope category
(say `AccessTokenScopeCategoryOrganization`) and the HTTP method (say
`DELETE`) and verifies that any scoped tokens in use include
`delete:organization`.
- `reqToken()` is used to enforce auth for individual routes that
require it. If a scoped token is not present for a request,
`tokenRequiresScopes()` will not return an error
## TODO
- [x] Alphabetize scope categories
- [x] Change 'public repos only' to a radio button (private vs public).
Also expand this to organizations
- [X] Disable token creation if no scopes selected. Alternatively, show
warning
- [x] `reqToken()` is missing from many `POST/DELETE` routes in the api.
`tokenRequiresScopes()` only checks that a given token has the correct
scope, `reqToken()` must be used to check that a token (or some other
auth) is present.
- _This should be addressed in this PR_
- [x] The migration should be reviewed very carefully in order to
minimize access changes to existing user tokens.
- _This should be addressed in this PR_
- [x] Link to api to swagger documentation, clarify what
read/write/delete levels correspond to
- [x] Review cases where more than one scope is needed as this directly
deviates from the api definition.
- _This should be addressed in this PR_
- For example:
```go
m.Group("/users/{username}/orgs", func() {
m.Get("", reqToken(), org.ListUserOrgs)
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser,
auth_model.AccessTokenScopeCategoryOrganization),
context_service.UserAssignmentAPI())
```
## Future improvements
- [ ] Add required scopes to swagger documentation
- [ ] Redesign `reqToken()` to be opt-out rather than opt-in
- [ ] Subdivide scopes like `repository`
- [ ] Once a token is created, if it has no scopes, we should display
text instead of an empty bullet point
- [ ] If the 'public repos only' option is selected, should read
categories be selected by default
Closes #24501
Closes #24799
Co-authored-by: Jonathan Tran <jon@allspice.io>
Co-authored-by: Kyle D <kdumontnu@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2023-06-04 20:57:16 +02:00
|
|
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
2021-10-25 05:43:40 +02:00
|
|
|
|
2023-12-22 00:59:59 +01:00
|
|
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/new", username, "repo1")
|
2021-10-25 05:43:40 +02:00
|
|
|
|
|
|
|
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateWikiPageOptions{
|
|
|
|
Title: title,
|
|
|
|
ContentBase64: base64.StdEncoding.EncodeToString([]byte("Wiki page content for API unit tests")),
|
|
|
|
Message: "",
|
2023-12-22 00:59:59 +01:00
|
|
|
}).AddTokenAuth(token)
|
2022-12-02 04:39:42 +01:00
|
|
|
MakeRequest(t, req, http.StatusCreated)
|
2021-10-25 05:43:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPIEditWikiPage(t *testing.T) {
|
2022-09-02 21:18:23 +02:00
|
|
|
defer tests.PrepareTestEnv(t)()
|
2021-10-25 05:43:40 +02:00
|
|
|
username := "user2"
|
|
|
|
session := loginUser(t, username)
|
Redesign Scoped Access Tokens (#24767)
## Changes
- Adds the following high level access scopes, each with `read` and
`write` levels:
- `activitypub`
- `admin` (hidden if user is not a site admin)
- `misc`
- `notification`
- `organization`
- `package`
- `issue`
- `repository`
- `user`
- Adds new middleware function `tokenRequiresScopes()` in addition to
`reqToken()`
- `tokenRequiresScopes()` is used for each high-level api section
- _if_ a scoped token is present, checks that the required scope is
included based on the section and HTTP method
- `reqToken()` is used for individual routes
- checks that required authentication is present (but does not check
scope levels as this will already have been handled by
`tokenRequiresScopes()`
- Adds migration to convert old scoped access tokens to the new set of
scopes
- Updates the user interface for scope selection
### User interface example
<img width="903" alt="Screen Shot 2023-05-31 at 1 56 55 PM"
src="https://github.com/go-gitea/gitea/assets/23248839/654766ec-2143-4f59-9037-3b51600e32f3">
<img width="917" alt="Screen Shot 2023-05-31 at 1 56 43 PM"
src="https://github.com/go-gitea/gitea/assets/23248839/1ad64081-012c-4a73-b393-66b30352654c">
## tokenRequiresScopes Design Decision
- `tokenRequiresScopes()` was added to more reliably cover api routes.
For an incoming request, this function uses the given scope category
(say `AccessTokenScopeCategoryOrganization`) and the HTTP method (say
`DELETE`) and verifies that any scoped tokens in use include
`delete:organization`.
- `reqToken()` is used to enforce auth for individual routes that
require it. If a scoped token is not present for a request,
`tokenRequiresScopes()` will not return an error
## TODO
- [x] Alphabetize scope categories
- [x] Change 'public repos only' to a radio button (private vs public).
Also expand this to organizations
- [X] Disable token creation if no scopes selected. Alternatively, show
warning
- [x] `reqToken()` is missing from many `POST/DELETE` routes in the api.
`tokenRequiresScopes()` only checks that a given token has the correct
scope, `reqToken()` must be used to check that a token (or some other
auth) is present.
- _This should be addressed in this PR_
- [x] The migration should be reviewed very carefully in order to
minimize access changes to existing user tokens.
- _This should be addressed in this PR_
- [x] Link to api to swagger documentation, clarify what
read/write/delete levels correspond to
- [x] Review cases where more than one scope is needed as this directly
deviates from the api definition.
- _This should be addressed in this PR_
- For example:
```go
m.Group("/users/{username}/orgs", func() {
m.Get("", reqToken(), org.ListUserOrgs)
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser,
auth_model.AccessTokenScopeCategoryOrganization),
context_service.UserAssignmentAPI())
```
## Future improvements
- [ ] Add required scopes to swagger documentation
- [ ] Redesign `reqToken()` to be opt-out rather than opt-in
- [ ] Subdivide scopes like `repository`
- [ ] Once a token is created, if it has no scopes, we should display
text instead of an empty bullet point
- [ ] If the 'public repos only' option is selected, should read
categories be selected by default
Closes #24501
Closes #24799
Co-authored-by: Jonathan Tran <jon@allspice.io>
Co-authored-by: Kyle D <kdumontnu@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
2023-06-04 20:57:16 +02:00
|
|
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
2021-10-25 05:43:40 +02:00
|
|
|
|
2023-12-22 00:59:59 +01:00
|
|
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/page/Page-With-Spaced-Name", username, "repo1")
|
2021-10-25 05:43:40 +02:00
|
|
|
|
|
|
|
req := NewRequestWithJSON(t, "PATCH", urlStr, &api.CreateWikiPageOptions{
|
|
|
|
Title: "edited title",
|
|
|
|
ContentBase64: base64.StdEncoding.EncodeToString([]byte("Edited wiki page content for API unit tests")),
|
|
|
|
Message: "",
|
2023-12-22 00:59:59 +01:00
|
|
|
}).AddTokenAuth(token)
|
2022-12-02 04:39:42 +01:00
|
|
|
MakeRequest(t, req, http.StatusOK)
|
2021-10-25 05:43:40 +02:00
|
|
|
}
|
|
|
|
|
2023-12-20 21:44:55 +01:00
|
|
|
func TestAPIEditOtherWikiPage(t *testing.T) {
|
|
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
|
|
|
|
// (drive-by-user) user, session, and token for a drive-by wiki editor
|
|
|
|
username := "drive-by-user"
|
|
|
|
req := NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
|
|
|
|
"user_name": username,
|
|
|
|
"email": "drive-by@example.com",
|
|
|
|
"password": "examplePassword!1",
|
|
|
|
"retype": "examplePassword!1",
|
|
|
|
})
|
|
|
|
MakeRequest(t, req, http.StatusSeeOther)
|
|
|
|
session := loginUserWithPassword(t, username, "examplePassword!1")
|
|
|
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
|
|
|
|
|
|
|
|
// (user2) user for the user whose wiki we're going to edit (as drive-by-user)
|
|
|
|
otherUsername := "user2"
|
|
|
|
|
|
|
|
// Creating a new Wiki page on user2's repo as user1 fails
|
|
|
|
testCreateWiki := func(expectedStatusCode int) {
|
|
|
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/new", otherUsername, "repo1")
|
|
|
|
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateWikiPageOptions{
|
|
|
|
Title: "Globally Edited Page",
|
|
|
|
ContentBase64: base64.StdEncoding.EncodeToString([]byte("Wiki page content for API unit tests")),
|
|
|
|
Message: "",
|
|
|
|
}).AddTokenAuth(token)
|
|
|
|
session.MakeRequest(t, req, expectedStatusCode)
|
|
|
|
}
|
|
|
|
testCreateWiki(http.StatusForbidden)
|
|
|
|
|
|
|
|
// Update the repo settings for user2's repo to enable globally writeable wiki
|
|
|
|
ctx := context.Background()
|
|
|
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
|
|
|
var units []repo_model.RepoUnit
|
|
|
|
units = append(units, repo_model.RepoUnit{
|
|
|
|
RepoID: repo.ID,
|
|
|
|
Type: unit_model.TypeWiki,
|
|
|
|
Config: new(repo_model.UnitConfig),
|
|
|
|
DefaultPermissions: repo_model.UnitAccessModeWrite,
|
|
|
|
})
|
|
|
|
err := repo_service.UpdateRepositoryUnits(ctx, repo, units, nil)
|
2024-07-30 21:41:10 +02:00
|
|
|
require.NoError(t, err)
|
2023-12-20 21:44:55 +01:00
|
|
|
|
|
|
|
// Creating a new Wiki page on user2's repo works now
|
|
|
|
testCreateWiki(http.StatusCreated)
|
|
|
|
}
|
|
|
|
|
2024-04-16 22:51:36 +02:00
|
|
|
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
|
2024-08-25 02:47:35 +02:00
|
|
|
repo, _, f := tests.CreateDeclarativeRepo(t, user, "", []unit_model.Type{
|
2024-04-16 22:51:36 +02:00
|
|
|
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)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-10-25 05:43:40 +02:00
|
|
|
func TestAPIListPageRevisions(t *testing.T) {
|
2022-09-02 21:18:23 +02:00
|
|
|
defer tests.PrepareTestEnv(t)()
|
2021-10-25 05:43:40 +02:00
|
|
|
username := "user2"
|
|
|
|
|
|
|
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/revisions/Home", username, "repo1")
|
|
|
|
|
|
|
|
req := NewRequest(t, "GET", urlStr)
|
2022-12-02 04:39:42 +01:00
|
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
2021-10-25 05:43:40 +02:00
|
|
|
|
|
|
|
var revisions *api.WikiCommitList
|
|
|
|
DecodeJSON(t, resp, &revisions)
|
|
|
|
|
|
|
|
dummyrevisions := &api.WikiCommitList{
|
|
|
|
WikiCommits: []*api.WikiCommit{
|
|
|
|
{
|
|
|
|
ID: "2c54faec6c45d31c1abfaecdab471eac6633738a",
|
|
|
|
Author: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Ethan Koenig",
|
|
|
|
Email: "ethantkoenig@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2017-11-27T04:31:18Z",
|
|
|
|
},
|
|
|
|
Committer: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: "Ethan Koenig",
|
|
|
|
Email: "ethantkoenig@gmail.com",
|
|
|
|
},
|
|
|
|
Date: "2017-11-27T04:31:18Z",
|
|
|
|
},
|
|
|
|
Message: "Add Home.md\n",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Count: 1,
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, dummyrevisions, revisions)
|
|
|
|
}
|
2024-04-25 00:17:53 +02:00
|
|
|
|
|
|
|
func TestAPIWikiNonMasterBranch(t *testing.T) {
|
2024-11-14 02:13:22 +01:00
|
|
|
onGiteaRun(t, func(t *testing.T, _ *url.URL) {
|
|
|
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
|
|
|
repo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{
|
|
|
|
WikiBranch: optional.Some("main"),
|
2024-04-25 00:17:53 +02:00
|
|
|
})
|
2024-11-14 02:13:22 +01:00
|
|
|
defer f()
|
|
|
|
|
|
|
|
uris := []string{
|
|
|
|
"revisions/Home",
|
|
|
|
"pages",
|
|
|
|
"page/Home",
|
|
|
|
}
|
|
|
|
baseURL := fmt.Sprintf("/api/v1/repos/%s/wiki", repo.FullName())
|
|
|
|
for _, uri := range uris {
|
|
|
|
t.Run(uri, func(t *testing.T) {
|
|
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
|
|
|
|
req := NewRequestf(t, "GET", "%s/%s", baseURL, uri)
|
|
|
|
MakeRequest(t, req, http.StatusOK)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
2024-04-25 00:17:53 +02:00
|
|
|
}
|