Add API to get/edit wiki (#17278)
* Add API to get/edit wiki
* Add swagger docs, various improvements
* fmt
* Fix lint and rm comment
* Add page parameter
* Add pagination to pages
* Add tests
* fmt
* Update func names
* Update error handling
* Update type name
* Fix lint
* Don't delete Home
* Update func name
* Update routers/api/v1/repo/wiki.go
Co-authored-by: delvh <dev.lh@web.de>
* Remove unnecessary check
* Fix lint
* Use English strings
* Update integrations/api_wiki_test.go
Co-authored-by: delvh <dev.lh@web.de>
* Update func and test names
* Remove unsed check and avoid duplicated error reports
* Improve error handling
* Return after error
* Document 404 error
* Update swagger
* Fix lint
* Apply suggestions from code review
Co-authored-by: delvh <dev.lh@web.de>
* Document file encoding
* fmt
* Apply suggestions
* Use convert
* Fix integration test
* simplify permissions
* unify duplicate key Title/Name
* improve types & return UTC timestamps
* improve types pt.2
- add WikiPageMetaData.LastCommit
- add WikiPageMetaData.HTMLURL
- replace WikiPageMetaData.Updated with .LastCommit.Committer.Created
also delete convert.ToWikiPage(), as it received too many arguments and
only had one callsite anyway. sorry for bad advice earlier 🙃
* WikiPage.Content is base64 encoded
* simplify error handling in wikiContentsByName()
* update swagger
* fix & DRY findWikiRepoCommit() error handling
ListWikiPages() previously wrote error twice when repo wiki didn't exist
* rename Content -> ContentBase64
* Fix test
* Fix tests
* Update var name
* suburl -> sub_url
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
			
			
This commit is contained in:
		
							parent
							
								
									843bc9deeb
								
							
						
					
					
						commit
						3676fafdac
					
				|  | @ -0,0 +1,251 @@ | |||
| // Copyright 2021 The Gitea Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a MIT-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package integrations | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	api "code.gitea.io/gitea/modules/structs" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
| 
 | ||||
| func TestAPIGetWikiPage(t *testing.T) { | ||||
| 	defer prepareTestEnv(t)() | ||||
| 
 | ||||
| 	username := "user2" | ||||
| 	session := loginUser(t, username) | ||||
| 
 | ||||
| 	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/page/Home", username, "repo1") | ||||
| 
 | ||||
| 	req := NewRequest(t, "GET", urlStr) | ||||
| 	resp := session.MakeRequest(t, req, http.StatusOK) | ||||
| 	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) { | ||||
| 	defer prepareTestEnv(t)() | ||||
| 
 | ||||
| 	username := "user2" | ||||
| 	session := loginUser(t, username) | ||||
| 
 | ||||
| 	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/pages", username, "repo1") | ||||
| 
 | ||||
| 	req := NewRequest(t, "GET", urlStr) | ||||
| 	resp := session.MakeRequest(t, req, http.StatusOK) | ||||
| 
 | ||||
| 	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", | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			Title:   "Page With Image", | ||||
| 			HTMLURL: meta[1].HTMLURL, | ||||
| 			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", | ||||
| 			HTMLURL: meta[2].HTMLURL, | ||||
| 			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", | ||||
| 			HTMLURL: meta[3].HTMLURL, | ||||
| 			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) { | ||||
| 	for _, title := range []string{ | ||||
| 		"New page", | ||||
| 		"&&&&", | ||||
| 	} { | ||||
| 		defer prepareTestEnv(t)() | ||||
| 		username := "user2" | ||||
| 		session := loginUser(t, username) | ||||
| 		token := getTokenForLoggedInUser(t, session) | ||||
| 
 | ||||
| 		urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/new?token=%s", username, "repo1", token) | ||||
| 
 | ||||
| 		req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateWikiPageOptions{ | ||||
| 			Title:         title, | ||||
| 			ContentBase64: base64.StdEncoding.EncodeToString([]byte("Wiki page content for API unit tests")), | ||||
| 			Message:       "", | ||||
| 		}) | ||||
| 		session.MakeRequest(t, req, http.StatusCreated) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestAPIEditWikiPage(t *testing.T) { | ||||
| 	defer prepareTestEnv(t)() | ||||
| 	username := "user2" | ||||
| 	session := loginUser(t, username) | ||||
| 	token := getTokenForLoggedInUser(t, session) | ||||
| 
 | ||||
| 	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/page/Page-With-Spaced-Name?token=%s", username, "repo1", token) | ||||
| 
 | ||||
| 	req := NewRequestWithJSON(t, "PATCH", urlStr, &api.CreateWikiPageOptions{ | ||||
| 		Title:         "edited title", | ||||
| 		ContentBase64: base64.StdEncoding.EncodeToString([]byte("Edited wiki page content for API unit tests")), | ||||
| 		Message:       "", | ||||
| 	}) | ||||
| 	session.MakeRequest(t, req, http.StatusOK) | ||||
| } | ||||
| 
 | ||||
| func TestAPIListPageRevisions(t *testing.T) { | ||||
| 	defer prepareTestEnv(t)() | ||||
| 	username := "user2" | ||||
| 	session := loginUser(t, username) | ||||
| 
 | ||||
| 	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/wiki/revisions/Home", username, "repo1") | ||||
| 
 | ||||
| 	req := NewRequest(t, "GET", urlStr) | ||||
| 	resp := session.MakeRequest(t, req, http.StatusOK) | ||||
| 
 | ||||
| 	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) | ||||
| } | ||||
|  | @ -0,0 +1,60 @@ | |||
| // Copyright 2021 The Gitea Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a MIT-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package convert | ||||
| 
 | ||||
| import ( | ||||
| 	"time" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/modules/git" | ||||
| 	api "code.gitea.io/gitea/modules/structs" | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
| 	wiki_service "code.gitea.io/gitea/services/wiki" | ||||
| ) | ||||
| 
 | ||||
| // ToWikiCommit convert a git commit into a WikiCommit
 | ||||
| func ToWikiCommit(commit *git.Commit) *api.WikiCommit { | ||||
| 	return &api.WikiCommit{ | ||||
| 		ID: commit.ID.String(), | ||||
| 		Author: &api.CommitUser{ | ||||
| 			Identity: api.Identity{ | ||||
| 				Name:  commit.Author.Name, | ||||
| 				Email: commit.Author.Email, | ||||
| 			}, | ||||
| 			Date: commit.Author.When.UTC().Format(time.RFC3339), | ||||
| 		}, | ||||
| 		Committer: &api.CommitUser{ | ||||
| 			Identity: api.Identity{ | ||||
| 				Name:  commit.Committer.Name, | ||||
| 				Email: commit.Committer.Email, | ||||
| 			}, | ||||
| 			Date: commit.Committer.When.UTC().Format(time.RFC3339), | ||||
| 		}, | ||||
| 		Message: commit.CommitMessage, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ToWikiCommitList convert a list of git commits into a WikiCommitList
 | ||||
| func ToWikiCommitList(commits []*git.Commit, total int64) *api.WikiCommitList { | ||||
| 	result := make([]*api.WikiCommit, len(commits)) | ||||
| 	for i := range commits { | ||||
| 		result[i] = ToWikiCommit(commits[i]) | ||||
| 	} | ||||
| 	return &api.WikiCommitList{ | ||||
| 		WikiCommits: result, | ||||
| 		Count:       total, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ToWikiPageMetaData converts meta information to a WikiPageMetaData
 | ||||
| func ToWikiPageMetaData(title string, lastCommit *git.Commit, repo *models.Repository) *api.WikiPageMetaData { | ||||
| 	suburl := wiki_service.NameToSubURL(title) | ||||
| 	return &api.WikiPageMetaData{ | ||||
| 		Title:      title, | ||||
| 		HTMLURL:    util.URLJoin(repo.HTMLURL(), "wiki", suburl), | ||||
| 		SubURL:     suburl, | ||||
| 		LastCommit: ToWikiCommit(lastCommit), | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,47 @@ | |||
| // Copyright 2021 The Gitea Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a MIT-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package structs | ||||
| 
 | ||||
| // WikiCommit page commit/revision
 | ||||
| type WikiCommit struct { | ||||
| 	ID        string      `json:"sha"` | ||||
| 	Author    *CommitUser `json:"author"` | ||||
| 	Committer *CommitUser `json:"commiter"` | ||||
| 	Message   string      `json:"message"` | ||||
| } | ||||
| 
 | ||||
| // WikiPage a wiki page
 | ||||
| type WikiPage struct { | ||||
| 	*WikiPageMetaData | ||||
| 	// Page content, base64 encoded
 | ||||
| 	ContentBase64 string `json:"content_base64"` | ||||
| 	CommitCount   int64  `json:"commit_count"` | ||||
| 	Sidebar       string `json:"sidebar"` | ||||
| 	Footer        string `json:"footer"` | ||||
| } | ||||
| 
 | ||||
| // WikiPageMetaData wiki page meta information
 | ||||
| type WikiPageMetaData struct { | ||||
| 	Title      string      `json:"title"` | ||||
| 	HTMLURL    string      `json:"html_url"` | ||||
| 	SubURL     string      `json:"sub_url"` | ||||
| 	LastCommit *WikiCommit `json:"last_commit"` | ||||
| } | ||||
| 
 | ||||
| // CreateWikiPageOptions form for creating wiki
 | ||||
| type CreateWikiPageOptions struct { | ||||
| 	// page title. leave empty to keep unchanged
 | ||||
| 	Title string `json:"title"` | ||||
| 	// content must be base64 encoded
 | ||||
| 	ContentBase64 string `json:"content_base64"` | ||||
| 	// optional commit message summarizing the change
 | ||||
| 	Message string `json:"message"` | ||||
| } | ||||
| 
 | ||||
| // WikiCommitList commit/revision list
 | ||||
| type WikiCommitList struct { | ||||
| 	WikiCommits []*WikiCommit `json:"commits"` | ||||
| 	Count       int64         `json:"count"` | ||||
| } | ||||
|  | @ -521,6 +521,13 @@ func mustEnableIssuesOrPulls(ctx *context.APIContext) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func mustEnableWiki(ctx *context.APIContext) { | ||||
| 	if !(ctx.Repo.CanRead(models.UnitTypeWiki)) { | ||||
| 		ctx.NotFound() | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func mustNotBeArchived(ctx *context.APIContext) { | ||||
| 	if ctx.Repo.Repository.IsArchived { | ||||
| 		ctx.NotFound() | ||||
|  | @ -791,6 +798,15 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route { | |||
| 					m.Combo("").Get(repo.ListTrackedTimesByRepository) | ||||
| 					m.Combo("/{timetrackingusername}").Get(repo.ListTrackedTimesByUser) | ||||
| 				}, mustEnableIssues, reqToken()) | ||||
| 				m.Group("/wiki", func() { | ||||
| 					m.Combo("/page/{pageName}"). | ||||
| 						Get(repo.GetWikiPage). | ||||
| 						Patch(mustNotBeArchived, reqRepoWriter(models.UnitTypeWiki), bind(api.CreateWikiPageOptions{}), repo.EditWikiPage). | ||||
| 						Delete(mustNotBeArchived, reqRepoWriter(models.UnitTypeWiki), repo.DeleteWikiPage) | ||||
| 					m.Get("/revisions/{pageName}", repo.ListPageRevisions) | ||||
| 					m.Post("/new", mustNotBeArchived, reqRepoWriter(models.UnitTypeWiki), bind(api.CreateWikiPageOptions{}), repo.NewWikiPage) | ||||
| 					m.Get("/pages", repo.ListWikiPages) | ||||
| 				}, mustEnableWiki) | ||||
| 				m.Group("/issues", func() { | ||||
| 					m.Combo("").Get(repo.ListIssues). | ||||
| 						Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueOption{}), repo.CreateIssue) | ||||
|  |  | |||
|  | @ -0,0 +1,514 @@ | |||
| // Copyright 2021 The Gitea Authors. All rights reserved.
 | ||||
| // Use of this source code is governed by a MIT-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package repo | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/modules/context" | ||||
| 	"code.gitea.io/gitea/modules/convert" | ||||
| 	"code.gitea.io/gitea/modules/git" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	api "code.gitea.io/gitea/modules/structs" | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
| 	"code.gitea.io/gitea/modules/web" | ||||
| 	wiki_service "code.gitea.io/gitea/services/wiki" | ||||
| ) | ||||
| 
 | ||||
| // NewWikiPage response for wiki create request
 | ||||
| func NewWikiPage(ctx *context.APIContext) { | ||||
| 	// swagger:operation POST /repos/{owner}/{repo}/wiki/new repository repoCreateWikiPage
 | ||||
| 	// ---
 | ||||
| 	// summary: Create a wiki page
 | ||||
| 	// consumes:
 | ||||
| 	// - application/json
 | ||||
| 	// parameters:
 | ||||
| 	// - name: owner
 | ||||
| 	//   in: path
 | ||||
| 	//   description: owner of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: repo
 | ||||
| 	//   in: path
 | ||||
| 	//   description: name of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: body
 | ||||
| 	//   in: body
 | ||||
| 	//   schema:
 | ||||
| 	//     "$ref": "#/definitions/CreateWikiPageOptions"
 | ||||
| 	// responses:
 | ||||
| 	//   "201":
 | ||||
| 	//     "$ref": "#/responses/WikiPage"
 | ||||
| 	//   "400":
 | ||||
| 	//     "$ref": "#/responses/error"
 | ||||
| 	//   "403":
 | ||||
| 	//     "$ref": "#/responses/forbidden"
 | ||||
| 
 | ||||
| 	form := web.GetForm(ctx).(*api.CreateWikiPageOptions) | ||||
| 
 | ||||
| 	if util.IsEmptyString(form.Title) { | ||||
| 		ctx.Error(http.StatusBadRequest, "emptyTitle", nil) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	wikiName := wiki_service.NormalizeWikiName(form.Title) | ||||
| 
 | ||||
| 	if len(form.Message) == 0 { | ||||
| 		form.Message = fmt.Sprintf("Add '%s'", form.Title) | ||||
| 	} | ||||
| 
 | ||||
| 	content, err := base64.StdEncoding.DecodeString(form.ContentBase64) | ||||
| 	if err != nil { | ||||
| 		ctx.Error(http.StatusBadRequest, "invalid base64 encoding of content", err) | ||||
| 		return | ||||
| 	} | ||||
| 	form.ContentBase64 = string(content) | ||||
| 
 | ||||
| 	if err := wiki_service.AddWikiPage(ctx.User, ctx.Repo.Repository, wikiName, form.ContentBase64, form.Message); err != nil { | ||||
| 		if models.IsErrWikiReservedName(err) { | ||||
| 			ctx.Error(http.StatusBadRequest, "IsErrWikiReservedName", err) | ||||
| 		} else if models.IsErrWikiAlreadyExist(err) { | ||||
| 			ctx.Error(http.StatusBadRequest, "IsErrWikiAlreadyExists", err) | ||||
| 		} else { | ||||
| 			ctx.Error(http.StatusInternalServerError, "AddWikiPage", err) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	wikiPage := getWikiPage(ctx, wikiName) | ||||
| 
 | ||||
| 	if !ctx.Written() { | ||||
| 		ctx.JSON(http.StatusCreated, wikiPage) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // EditWikiPage response for wiki modify request
 | ||||
| func EditWikiPage(ctx *context.APIContext) { | ||||
| 	// swagger:operation PATCH /repos/{owner}/{repo}/wiki/page/{pageName} repository repoEditWikiPage
 | ||||
| 	// ---
 | ||||
| 	// summary: Edit a wiki page
 | ||||
| 	// consumes:
 | ||||
| 	// - application/json
 | ||||
| 	// parameters:
 | ||||
| 	// - name: owner
 | ||||
| 	//   in: path
 | ||||
| 	//   description: owner of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: repo
 | ||||
| 	//   in: path
 | ||||
| 	//   description: name of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: pageName
 | ||||
| 	//   in: path
 | ||||
| 	//   description: name of the page
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: body
 | ||||
| 	//   in: body
 | ||||
| 	//   schema:
 | ||||
| 	//     "$ref": "#/definitions/CreateWikiPageOptions"
 | ||||
| 	// responses:
 | ||||
| 	//   "200":
 | ||||
| 	//     "$ref": "#/responses/WikiPage"
 | ||||
| 	//   "400":
 | ||||
| 	//     "$ref": "#/responses/error"
 | ||||
| 	//   "403":
 | ||||
| 	//     "$ref": "#/responses/forbidden"
 | ||||
| 
 | ||||
| 	form := web.GetForm(ctx).(*api.CreateWikiPageOptions) | ||||
| 
 | ||||
| 	oldWikiName := wiki_service.NormalizeWikiName(ctx.Params(":pageName")) | ||||
| 	newWikiName := wiki_service.NormalizeWikiName(form.Title) | ||||
| 
 | ||||
| 	if len(newWikiName) == 0 { | ||||
| 		newWikiName = oldWikiName | ||||
| 	} | ||||
| 
 | ||||
| 	if len(form.Message) == 0 { | ||||
| 		form.Message = fmt.Sprintf("Update '%s'", newWikiName) | ||||
| 	} | ||||
| 
 | ||||
| 	content, err := base64.StdEncoding.DecodeString(form.ContentBase64) | ||||
| 	if err != nil { | ||||
| 		ctx.Error(http.StatusBadRequest, "invalid base64 encoding of content", err) | ||||
| 		return | ||||
| 	} | ||||
| 	form.ContentBase64 = string(content) | ||||
| 
 | ||||
| 	if err := wiki_service.EditWikiPage(ctx.User, ctx.Repo.Repository, oldWikiName, newWikiName, form.ContentBase64, form.Message); err != nil { | ||||
| 		ctx.Error(http.StatusInternalServerError, "EditWikiPage", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	wikiPage := getWikiPage(ctx, newWikiName) | ||||
| 
 | ||||
| 	if !ctx.Written() { | ||||
| 		ctx.JSON(http.StatusOK, wikiPage) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func getWikiPage(ctx *context.APIContext, title string) *api.WikiPage { | ||||
| 	title = wiki_service.NormalizeWikiName(title) | ||||
| 
 | ||||
| 	wikiRepo, commit := findWikiRepoCommit(ctx) | ||||
| 	if wikiRepo != nil { | ||||
| 		defer wikiRepo.Close() | ||||
| 	} | ||||
| 	if ctx.Written() { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	//lookup filename in wiki - get filecontent, real filename
 | ||||
| 	content, pageFilename := wikiContentsByName(ctx, commit, title, false) | ||||
| 	if ctx.Written() { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	sidebarContent, _ := wikiContentsByName(ctx, commit, "_Sidebar", true) | ||||
| 	if ctx.Written() { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	footerContent, _ := wikiContentsByName(ctx, commit, "_Footer", true) | ||||
| 	if ctx.Written() { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// get commit count - wiki revisions
 | ||||
| 	commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename) | ||||
| 
 | ||||
| 	// Get last change information.
 | ||||
| 	lastCommit, err := wikiRepo.GetCommitByPath(pageFilename) | ||||
| 	if err != nil { | ||||
| 		ctx.Error(http.StatusInternalServerError, "GetCommitByPath", err) | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	return &api.WikiPage{ | ||||
| 		WikiPageMetaData: convert.ToWikiPageMetaData(title, lastCommit, ctx.Repo.Repository), | ||||
| 		ContentBase64:    content, | ||||
| 		CommitCount:      commitsCount, | ||||
| 		Sidebar:          sidebarContent, | ||||
| 		Footer:           footerContent, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeleteWikiPage delete wiki page
 | ||||
| func DeleteWikiPage(ctx *context.APIContext) { | ||||
| 	// swagger:operation DELETE /repos/{owner}/{repo}/wiki/page/{pageName} repository repoDeleteWikiPage
 | ||||
| 	// ---
 | ||||
| 	// summary: Delete a wiki page
 | ||||
| 	// parameters:
 | ||||
| 	// - name: owner
 | ||||
| 	//   in: path
 | ||||
| 	//   description: owner of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: repo
 | ||||
| 	//   in: path
 | ||||
| 	//   description: name of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: pageName
 | ||||
| 	//   in: path
 | ||||
| 	//   description: name of the page
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// responses:
 | ||||
| 	//   "204":
 | ||||
| 	//     "$ref": "#/responses/empty"
 | ||||
| 	//   "403":
 | ||||
| 	//     "$ref": "#/responses/forbidden"
 | ||||
| 	//   "404":
 | ||||
| 	//     "$ref": "#/responses/notFound"
 | ||||
| 
 | ||||
| 	wikiName := wiki_service.NormalizeWikiName(ctx.Params(":pageName")) | ||||
| 
 | ||||
| 	if err := wiki_service.DeleteWikiPage(ctx.User, ctx.Repo.Repository, wikiName); err != nil { | ||||
| 		if err.Error() == "file does not exist" { | ||||
| 			ctx.NotFound(err) | ||||
| 			return | ||||
| 		} | ||||
| 		ctx.Error(http.StatusInternalServerError, "DeleteWikiPage", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Status(http.StatusNoContent) | ||||
| } | ||||
| 
 | ||||
| // ListWikiPages get wiki pages list
 | ||||
| func ListWikiPages(ctx *context.APIContext) { | ||||
| 	// swagger:operation GET /repos/{owner}/{repo}/wiki/pages repository repoGetWikiPages
 | ||||
| 	// ---
 | ||||
| 	// summary: Get all wiki pages
 | ||||
| 	// produces:
 | ||||
| 	// - application/json
 | ||||
| 	// parameters:
 | ||||
| 	// - name: owner
 | ||||
| 	//   in: path
 | ||||
| 	//   description: owner of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: repo
 | ||||
| 	//   in: path
 | ||||
| 	//   description: name of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: page
 | ||||
| 	//   in: query
 | ||||
| 	//   description: page number of results to return (1-based)
 | ||||
| 	//   type: integer
 | ||||
| 	// - name: limit
 | ||||
| 	//   in: query
 | ||||
| 	//   description: page size of results
 | ||||
| 	//   type: integer
 | ||||
| 	// responses:
 | ||||
| 	//   "200":
 | ||||
| 	//     "$ref": "#/responses/WikiPageList"
 | ||||
| 	//   "404":
 | ||||
| 	//     "$ref": "#/responses/notFound"
 | ||||
| 
 | ||||
| 	wikiRepo, commit := findWikiRepoCommit(ctx) | ||||
| 	if wikiRepo != nil { | ||||
| 		defer wikiRepo.Close() | ||||
| 	} | ||||
| 	if ctx.Written() { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	page := ctx.FormInt("page") | ||||
| 	if page <= 1 { | ||||
| 		page = 1 | ||||
| 	} | ||||
| 	limit := ctx.FormInt("limit") | ||||
| 	if limit <= 1 { | ||||
| 		limit = setting.API.DefaultPagingNum | ||||
| 	} | ||||
| 
 | ||||
| 	skip := (page - 1) * limit | ||||
| 	max := page * limit | ||||
| 
 | ||||
| 	entries, err := commit.ListEntries() | ||||
| 	if err != nil { | ||||
| 		ctx.ServerError("ListEntries", err) | ||||
| 		return | ||||
| 	} | ||||
| 	pages := make([]*api.WikiPageMetaData, 0, len(entries)) | ||||
| 	for i, entry := range entries { | ||||
| 		if i < skip || i >= max || !entry.IsRegular() { | ||||
| 			continue | ||||
| 		} | ||||
| 		c, err := wikiRepo.GetCommitByPath(entry.Name()) | ||||
| 		if err != nil { | ||||
| 			ctx.Error(http.StatusInternalServerError, "GetCommit", err) | ||||
| 			return | ||||
| 		} | ||||
| 		wikiName, err := wiki_service.FilenameToName(entry.Name()) | ||||
| 		if err != nil { | ||||
| 			if models.IsErrWikiInvalidFileName(err) { | ||||
| 				continue | ||||
| 			} | ||||
| 			ctx.Error(http.StatusInternalServerError, "WikiFilenameToName", err) | ||||
| 			return | ||||
| 		} | ||||
| 		pages = append(pages, convert.ToWikiPageMetaData(wikiName, c, ctx.Repo.Repository)) | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.JSON(http.StatusOK, pages) | ||||
| } | ||||
| 
 | ||||
| // GetWikiPage get single wiki page
 | ||||
| func GetWikiPage(ctx *context.APIContext) { | ||||
| 	// swagger:operation GET /repos/{owner}/{repo}/wiki/page/{pageName} repository repoGetWikiPage
 | ||||
| 	// ---
 | ||||
| 	// summary: Get a wiki page
 | ||||
| 	// produces:
 | ||||
| 	// - application/json
 | ||||
| 	// parameters:
 | ||||
| 	// - name: owner
 | ||||
| 	//   in: path
 | ||||
| 	//   description: owner of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: repo
 | ||||
| 	//   in: path
 | ||||
| 	//   description: name of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: pageName
 | ||||
| 	//   in: path
 | ||||
| 	//   description: name of the page
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// responses:
 | ||||
| 	//   "200":
 | ||||
| 	//     "$ref": "#/responses/WikiPage"
 | ||||
| 	//   "404":
 | ||||
| 	//     "$ref": "#/responses/notFound"
 | ||||
| 
 | ||||
| 	// get requested pagename
 | ||||
| 	pageName := wiki_service.NormalizeWikiName(ctx.Params(":pageName")) | ||||
| 
 | ||||
| 	wikiPage := getWikiPage(ctx, pageName) | ||||
| 	if !ctx.Written() { | ||||
| 		ctx.JSON(http.StatusOK, wikiPage) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ListPageRevisions renders file revision list of wiki page
 | ||||
| func ListPageRevisions(ctx *context.APIContext) { | ||||
| 	// swagger:operation GET /repos/{owner}/{repo}/wiki/revisions/{pageName} repository repoGetWikiPageRevisions
 | ||||
| 	// ---
 | ||||
| 	// summary: Get revisions of a wiki page
 | ||||
| 	// produces:
 | ||||
| 	// - application/json
 | ||||
| 	// parameters:
 | ||||
| 	// - name: owner
 | ||||
| 	//   in: path
 | ||||
| 	//   description: owner of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: repo
 | ||||
| 	//   in: path
 | ||||
| 	//   description: name of the repo
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: pageName
 | ||||
| 	//   in: path
 | ||||
| 	//   description: name of the page
 | ||||
| 	//   type: string
 | ||||
| 	//   required: true
 | ||||
| 	// - name: page
 | ||||
| 	//   in: query
 | ||||
| 	//   description: page number of results to return (1-based)
 | ||||
| 	//   type: integer
 | ||||
| 	// responses:
 | ||||
| 	//   "200":
 | ||||
| 	//     "$ref": "#/responses/WikiCommitList"
 | ||||
| 	//   "404":
 | ||||
| 	//     "$ref": "#/responses/notFound"
 | ||||
| 
 | ||||
| 	wikiRepo, commit := findWikiRepoCommit(ctx) | ||||
| 	if wikiRepo != nil { | ||||
| 		defer wikiRepo.Close() | ||||
| 	} | ||||
| 	if ctx.Written() { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// get requested pagename
 | ||||
| 	pageName := wiki_service.NormalizeWikiName(ctx.Params(":pageName")) | ||||
| 	if len(pageName) == 0 { | ||||
| 		pageName = "Home" | ||||
| 	} | ||||
| 
 | ||||
| 	//lookup filename in wiki - get filecontent, gitTree entry , real filename
 | ||||
| 	_, pageFilename := wikiContentsByName(ctx, commit, pageName, false) | ||||
| 	if ctx.Written() { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// get commit count - wiki revisions
 | ||||
| 	commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename) | ||||
| 
 | ||||
| 	page := ctx.FormInt("page") | ||||
| 	if page <= 1 { | ||||
| 		page = 1 | ||||
| 	} | ||||
| 
 | ||||
| 	// get Commit Count
 | ||||
| 	commitsHistory, err := wikiRepo.CommitsByFileAndRangeNoFollow("master", pageFilename, page) | ||||
| 	if err != nil { | ||||
| 		ctx.Error(http.StatusInternalServerError, "CommitsByFileAndRangeNoFollow", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.JSON(http.StatusOK, convert.ToWikiCommitList(commitsHistory, commitsCount)) | ||||
| } | ||||
| 
 | ||||
| // findEntryForFile finds the tree entry for a target filepath.
 | ||||
| func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) { | ||||
| 	entry, err := commit.GetTreeEntryByPath(target) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if entry != nil { | ||||
| 		return entry, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Then the unescaped, shortest alternative
 | ||||
| 	var unescapedTarget string | ||||
| 	if unescapedTarget, err = url.QueryUnescape(target); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return commit.GetTreeEntryByPath(unescapedTarget) | ||||
| } | ||||
| 
 | ||||
| // findWikiRepoCommit opens the wiki repo and returns the latest commit, writing to context on error.
 | ||||
| // The caller is responsible for closing the returned repo again
 | ||||
| func findWikiRepoCommit(ctx *context.APIContext) (*git.Repository, *git.Commit) { | ||||
| 	wikiRepo, err := git.OpenRepository(ctx.Repo.Repository.WikiPath()) | ||||
| 	if err != nil { | ||||
| 
 | ||||
| 		if git.IsErrNotExist(err) || err.Error() == "no such file or directory" { | ||||
| 			ctx.NotFound(err) | ||||
| 		} else { | ||||
| 			ctx.Error(http.StatusInternalServerError, "OpenRepository", err) | ||||
| 		} | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 
 | ||||
| 	commit, err := wikiRepo.GetBranchCommit("master") | ||||
| 	if err != nil { | ||||
| 		if git.IsErrNotExist(err) { | ||||
| 			ctx.NotFound(err) | ||||
| 		} else { | ||||
| 			ctx.Error(http.StatusInternalServerError, "GetBranchCommit", err) | ||||
| 		} | ||||
| 		return wikiRepo, nil | ||||
| 	} | ||||
| 	return wikiRepo, commit | ||||
| } | ||||
| 
 | ||||
| // wikiContentsByEntry returns the contents of the wiki page referenced by the
 | ||||
| // given tree entry, encoded with base64. Writes to ctx if an error occurs.
 | ||||
| func wikiContentsByEntry(ctx *context.APIContext, entry *git.TreeEntry) string { | ||||
| 	blob := entry.Blob() | ||||
| 	if blob.Size() > setting.API.DefaultMaxBlobSize { | ||||
| 		return "" | ||||
| 	} | ||||
| 	content, err := blob.GetBlobContentBase64() | ||||
| 	if err != nil { | ||||
| 		ctx.Error(http.StatusInternalServerError, "GetBlobContentBase64", err) | ||||
| 		return "" | ||||
| 	} | ||||
| 	return content | ||||
| } | ||||
| 
 | ||||
| // wikiContentsByName returns the contents of a wiki page, along with a boolean
 | ||||
| // indicating whether the page exists. Writes to ctx if an error occurs.
 | ||||
| func wikiContentsByName(ctx *context.APIContext, commit *git.Commit, wikiName string, isSidebarOrFooter bool) (string, string) { | ||||
| 	pageFilename := wiki_service.NameToFilename(wikiName) | ||||
| 	entry, err := findEntryForFile(commit, pageFilename) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		if git.IsErrNotExist(err) { | ||||
| 			if !isSidebarOrFooter { | ||||
| 				ctx.NotFound() | ||||
| 			} | ||||
| 		} else { | ||||
| 			ctx.ServerError("findEntryForFile", err) | ||||
| 		} | ||||
| 		return "", "" | ||||
| 	} | ||||
| 	return wikiContentsByEntry(ctx, entry), pageFilename | ||||
| } | ||||
|  | @ -169,4 +169,7 @@ type swaggerParameterBodies struct { | |||
| 
 | ||||
| 	// in:body
 | ||||
| 	UserSettingsOptions api.UserSettingsOptions | ||||
| 
 | ||||
| 	// in:body
 | ||||
| 	CreateWikiPageOptions api.CreateWikiPageOptions | ||||
| } | ||||
|  |  | |||
|  | @ -323,3 +323,24 @@ type swaggerCombinedStatus struct { | |||
| 	// in: body
 | ||||
| 	Body api.CombinedStatus `json:"body"` | ||||
| } | ||||
| 
 | ||||
| // WikiPageList
 | ||||
| // swagger:response WikiPageList
 | ||||
| type swaggerWikiPageList struct { | ||||
| 	// in:body
 | ||||
| 	Body []api.WikiPageMetaData `json:"body"` | ||||
| } | ||||
| 
 | ||||
| // WikiPage
 | ||||
| // swagger:response WikiPage
 | ||||
| type swaggerWikiPage struct { | ||||
| 	// in:body
 | ||||
| 	Body api.WikiPage `json:"body"` | ||||
| } | ||||
| 
 | ||||
| // WikiCommitList
 | ||||
| // swagger:response WikiCommitList
 | ||||
| type swaggerWikiCommitList struct { | ||||
| 	// in:body
 | ||||
| 	Body api.WikiCommitList `json:"body"` | ||||
| } | ||||
|  |  | |||
|  | @ -9889,6 +9889,284 @@ | |||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "/repos/{owner}/{repo}/wiki/new": { | ||||
|       "post": { | ||||
|         "consumes": [ | ||||
|           "application/json" | ||||
|         ], | ||||
|         "tags": [ | ||||
|           "repository" | ||||
|         ], | ||||
|         "summary": "Create a wiki page", | ||||
|         "operationId": "repoCreateWikiPage", | ||||
|         "parameters": [ | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "owner of the repo", | ||||
|             "name": "owner", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "name of the repo", | ||||
|             "name": "repo", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "name": "body", | ||||
|             "in": "body", | ||||
|             "schema": { | ||||
|               "$ref": "#/definitions/CreateWikiPageOptions" | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         "responses": { | ||||
|           "201": { | ||||
|             "$ref": "#/responses/WikiPage" | ||||
|           }, | ||||
|           "400": { | ||||
|             "$ref": "#/responses/error" | ||||
|           }, | ||||
|           "403": { | ||||
|             "$ref": "#/responses/forbidden" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "/repos/{owner}/{repo}/wiki/page/{pageName}": { | ||||
|       "get": { | ||||
|         "produces": [ | ||||
|           "application/json" | ||||
|         ], | ||||
|         "tags": [ | ||||
|           "repository" | ||||
|         ], | ||||
|         "summary": "Get a wiki page", | ||||
|         "operationId": "repoGetWikiPage", | ||||
|         "parameters": [ | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "owner of the repo", | ||||
|             "name": "owner", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "name of the repo", | ||||
|             "name": "repo", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "name of the page", | ||||
|             "name": "pageName", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           } | ||||
|         ], | ||||
|         "responses": { | ||||
|           "200": { | ||||
|             "$ref": "#/responses/WikiPage" | ||||
|           }, | ||||
|           "404": { | ||||
|             "$ref": "#/responses/notFound" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "delete": { | ||||
|         "tags": [ | ||||
|           "repository" | ||||
|         ], | ||||
|         "summary": "Delete a wiki page", | ||||
|         "operationId": "repoDeleteWikiPage", | ||||
|         "parameters": [ | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "owner of the repo", | ||||
|             "name": "owner", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "name of the repo", | ||||
|             "name": "repo", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "name of the page", | ||||
|             "name": "pageName", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           } | ||||
|         ], | ||||
|         "responses": { | ||||
|           "204": { | ||||
|             "$ref": "#/responses/empty" | ||||
|           }, | ||||
|           "403": { | ||||
|             "$ref": "#/responses/forbidden" | ||||
|           }, | ||||
|           "404": { | ||||
|             "$ref": "#/responses/notFound" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "patch": { | ||||
|         "consumes": [ | ||||
|           "application/json" | ||||
|         ], | ||||
|         "tags": [ | ||||
|           "repository" | ||||
|         ], | ||||
|         "summary": "Edit a wiki page", | ||||
|         "operationId": "repoEditWikiPage", | ||||
|         "parameters": [ | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "owner of the repo", | ||||
|             "name": "owner", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "name of the repo", | ||||
|             "name": "repo", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "name of the page", | ||||
|             "name": "pageName", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "name": "body", | ||||
|             "in": "body", | ||||
|             "schema": { | ||||
|               "$ref": "#/definitions/CreateWikiPageOptions" | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         "responses": { | ||||
|           "200": { | ||||
|             "$ref": "#/responses/WikiPage" | ||||
|           }, | ||||
|           "400": { | ||||
|             "$ref": "#/responses/error" | ||||
|           }, | ||||
|           "403": { | ||||
|             "$ref": "#/responses/forbidden" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "/repos/{owner}/{repo}/wiki/pages": { | ||||
|       "get": { | ||||
|         "produces": [ | ||||
|           "application/json" | ||||
|         ], | ||||
|         "tags": [ | ||||
|           "repository" | ||||
|         ], | ||||
|         "summary": "Get all wiki pages", | ||||
|         "operationId": "repoGetWikiPages", | ||||
|         "parameters": [ | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "owner of the repo", | ||||
|             "name": "owner", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "name of the repo", | ||||
|             "name": "repo", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "integer", | ||||
|             "description": "page number of results to return (1-based)", | ||||
|             "name": "page", | ||||
|             "in": "query" | ||||
|           }, | ||||
|           { | ||||
|             "type": "integer", | ||||
|             "description": "page size of results", | ||||
|             "name": "limit", | ||||
|             "in": "query" | ||||
|           } | ||||
|         ], | ||||
|         "responses": { | ||||
|           "200": { | ||||
|             "$ref": "#/responses/WikiPageList" | ||||
|           }, | ||||
|           "404": { | ||||
|             "$ref": "#/responses/notFound" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "/repos/{owner}/{repo}/wiki/revisions/{pageName}": { | ||||
|       "get": { | ||||
|         "produces": [ | ||||
|           "application/json" | ||||
|         ], | ||||
|         "tags": [ | ||||
|           "repository" | ||||
|         ], | ||||
|         "summary": "Get revisions of a wiki page", | ||||
|         "operationId": "repoGetWikiPageRevisions", | ||||
|         "parameters": [ | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "owner of the repo", | ||||
|             "name": "owner", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "name of the repo", | ||||
|             "name": "repo", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "string", | ||||
|             "description": "name of the page", | ||||
|             "name": "pageName", | ||||
|             "in": "path", | ||||
|             "required": true | ||||
|           }, | ||||
|           { | ||||
|             "type": "integer", | ||||
|             "description": "page number of results to return (1-based)", | ||||
|             "name": "page", | ||||
|             "in": "query" | ||||
|           } | ||||
|         ], | ||||
|         "responses": { | ||||
|           "200": { | ||||
|             "$ref": "#/responses/WikiCommitList" | ||||
|           }, | ||||
|           "404": { | ||||
|             "$ref": "#/responses/notFound" | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "/repos/{template_owner}/{template_repo}/generate": { | ||||
|       "post": { | ||||
|         "consumes": [ | ||||
|  | @ -13666,6 +13944,28 @@ | |||
|       }, | ||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||
|     }, | ||||
|     "CreateWikiPageOptions": { | ||||
|       "description": "CreateWikiPageOptions form for creating wiki", | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "content_base64": { | ||||
|           "description": "content must be base64 encoded", | ||||
|           "type": "string", | ||||
|           "x-go-name": "ContentBase64" | ||||
|         }, | ||||
|         "message": { | ||||
|           "description": "optional commit message summarizing the change", | ||||
|           "type": "string", | ||||
|           "x-go-name": "Message" | ||||
|         }, | ||||
|         "title": { | ||||
|           "description": "page title. leave empty to keep unchanged", | ||||
|           "type": "string", | ||||
|           "x-go-name": "Title" | ||||
|         } | ||||
|       }, | ||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||
|     }, | ||||
|     "Cron": { | ||||
|       "description": "Cron represents a Cron task", | ||||
|       "type": "object", | ||||
|  | @ -17376,6 +17676,108 @@ | |||
|         } | ||||
|       }, | ||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||
|     }, | ||||
|     "WikiCommit": { | ||||
|       "description": "WikiCommit page commit/revision", | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "author": { | ||||
|           "$ref": "#/definitions/CommitUser" | ||||
|         }, | ||||
|         "commiter": { | ||||
|           "$ref": "#/definitions/CommitUser" | ||||
|         }, | ||||
|         "message": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "Message" | ||||
|         }, | ||||
|         "sha": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "ID" | ||||
|         } | ||||
|       }, | ||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||
|     }, | ||||
|     "WikiCommitList": { | ||||
|       "description": "WikiCommitList commit/revision list", | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "commits": { | ||||
|           "type": "array", | ||||
|           "items": { | ||||
|             "$ref": "#/definitions/WikiCommit" | ||||
|           }, | ||||
|           "x-go-name": "WikiCommits" | ||||
|         }, | ||||
|         "count": { | ||||
|           "type": "integer", | ||||
|           "format": "int64", | ||||
|           "x-go-name": "Count" | ||||
|         } | ||||
|       }, | ||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||
|     }, | ||||
|     "WikiPage": { | ||||
|       "description": "WikiPage a wiki page", | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "commit_count": { | ||||
|           "type": "integer", | ||||
|           "format": "int64", | ||||
|           "x-go-name": "CommitCount" | ||||
|         }, | ||||
|         "content_base64": { | ||||
|           "description": "Page content, base64 encoded", | ||||
|           "type": "string", | ||||
|           "x-go-name": "ContentBase64" | ||||
|         }, | ||||
|         "footer": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "Footer" | ||||
|         }, | ||||
|         "html_url": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "HTMLURL" | ||||
|         }, | ||||
|         "last_commit": { | ||||
|           "$ref": "#/definitions/WikiCommit" | ||||
|         }, | ||||
|         "sidebar": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "Sidebar" | ||||
|         }, | ||||
|         "sub_url": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "SubURL" | ||||
|         }, | ||||
|         "title": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "Title" | ||||
|         } | ||||
|       }, | ||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||
|     }, | ||||
|     "WikiPageMetaData": { | ||||
|       "description": "WikiPageMetaData wiki page meta information", | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "html_url": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "HTMLURL" | ||||
|         }, | ||||
|         "last_commit": { | ||||
|           "$ref": "#/definitions/WikiCommit" | ||||
|         }, | ||||
|         "sub_url": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "SubURL" | ||||
|         }, | ||||
|         "title": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "Title" | ||||
|         } | ||||
|       }, | ||||
|       "x-go-package": "code.gitea.io/gitea/modules/structs" | ||||
|     } | ||||
|   }, | ||||
|   "responses": { | ||||
|  | @ -18069,6 +18471,27 @@ | |||
|         "$ref": "#/definitions/WatchInfo" | ||||
|       } | ||||
|     }, | ||||
|     "WikiCommitList": { | ||||
|       "description": "WikiCommitList", | ||||
|       "schema": { | ||||
|         "$ref": "#/definitions/WikiCommitList" | ||||
|       } | ||||
|     }, | ||||
|     "WikiPage": { | ||||
|       "description": "WikiPage", | ||||
|       "schema": { | ||||
|         "$ref": "#/definitions/WikiPage" | ||||
|       } | ||||
|     }, | ||||
|     "WikiPageList": { | ||||
|       "description": "WikiPageList", | ||||
|       "schema": { | ||||
|         "type": "array", | ||||
|         "items": { | ||||
|           "$ref": "#/definitions/WikiPageMetaData" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "conflict": { | ||||
|       "description": "APIConflict is a conflict empty response" | ||||
|     }, | ||||
|  | @ -18117,7 +18540,7 @@ | |||
|     "parameterBodies": { | ||||
|       "description": "parameterBodies", | ||||
|       "schema": { | ||||
|         "$ref": "#/definitions/UserSettingsOptions" | ||||
|         "$ref": "#/definitions/CreateWikiPageOptions" | ||||
|       } | ||||
|     }, | ||||
|     "redirect": { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue