add: wikiPages

This commit is contained in:
hang 2021-11-16 11:13:39 +08:00
parent c7d8181a70
commit 4884fe093f
7 changed files with 231 additions and 6 deletions

View File

@ -200,6 +200,19 @@ func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) {
return CommitsCountFiles(repo.Path, []string{revision}, []string{file}) return CommitsCountFiles(repo.Path, []string{revision}, []string{file})
} }
// GetFirstAndLastCommitByPath returns the first commit and the last commit of relative path.
func (repo *Repository) GetFirstAndLastCommitByPath(revision, relpath string) (*Commit, *Commit, error) {
stdout, err := NewCommand("log", revision, prettyLogFormat, "--", relpath).RunInDirBytes(repo.Path)
if err != nil {
return nil, nil, err
}
commits, err := repo.parsePrettyFormatLogToList(stdout)
if err != nil {
return nil, nil, err
}
return commits.Front().Value.(*Commit), commits.Back().Value.(*Commit), nil
}
// CommitsByFileAndRange return the commits according revision file and the page // CommitsByFileAndRange return the commits according revision file and the page
func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (*list.List, error) { func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (*list.List, error) {
skip := (page - 1) * setting.Git.CommitsRangeSize skip := (page - 1) * setting.Git.CommitsRangeSize

44
modules/structs/wiki.go Normal file
View File

@ -0,0 +1,44 @@
package structs
type WikiesResponse struct {
WikiMeta
WikiCloneLink CloneLink `json:"wiki_clone_link"`
}
type WikiMeta struct {
Name string `json:"name"`
Commit WikiCommit `json:"commit"`
FirstCommit WikiCommit `json:"-"`
//WikiCloneLink CloneLink `json:"wiki_clone_link"`
}
type WikiCommit struct {
ID string `json:"id"`
Message string `json:"message"`
Author WikiUser `json:"author"`
Commiter WikiUser `json:"-"`
}
type WikiUser struct {
Name string `json:"name"`
Email string `json:"email"`
When int64 `json:"when"`
}
type WikiResponse struct {
WikiMeta
CommitCounts int64 `json:"commit_counts"`
MdContent string `json:"md_content"`
SimpleContent string `json:"simple_content"`
WikiCloneLink CloneLink `json:"wiki_clone_link"`
}
type WikiOption struct {
Name string `json:"name"`
Content string `json:"content"`
CommitMessage string `json:"commit_message"`
}
type CloneLink struct {
SSH string `json:"ssh"`
HTTPS string `json:"https"`
}

View File

@ -782,6 +782,15 @@ func Routes() *web.Route {
m.Delete("", repo.DeleteBranchProtection) m.Delete("", repo.DeleteBranchProtection)
}) })
}, reqToken(), reqAdmin()) }, reqToken(), reqAdmin())
m.Group("/wikies", func() {
m.Combo("").Get(repo.ListWikiPages)
// Post(bind(api.WikiOption{}), repo.CreateWiki)
// m.Group("/:page", func() {
// m.Combo("").Get(repo.GetWiki).
// Patch(bind(api.WikiOption{}), repo.EditWiki).
// Delete(repo.DeleteWiki)
// })
})
m.Group("/tags", func() { m.Group("/tags", func() {
m.Get("", repo.ListTags) m.Get("", repo.ListTags)
m.Get("/*", repo.GetTag) m.Get("/*", repo.GetTag)

121
routers/api/v1/repo/wiki.go Normal file
View File

@ -0,0 +1,121 @@
package repo
import (
"net/http"
"sort"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
webWiki "code.gitea.io/gitea/routers/web/repo"
wiki_service "code.gitea.io/gitea/services/wiki"
)
func ListWikiPages(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/wikies repository repoWikiList
// ---
// summary: List the wikies in a repository
// 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
// responses:
// "200":
// "$ref": "#/responses/WikiList"
if !ctx.Repo.Repository.HasWiki() {
return
}
wikiCloneWiki := ctx.Repo.Repository.WikiCloneLink()
wikiRepo, commit, err := webWiki.FindWikiRepoCommit(ctx.Context)
if err != nil {
if wikiRepo != nil {
wikiRepo.Close()
}
return
}
defer func() {
if wikiRepo != nil {
wikiRepo.Close()
}
}()
entries, err := commit.ListEntries()
if err != nil {
ctx.ServerError("entries", err)
return
}
pages := make([]api.WikiesResponse, 0, len(entries))
for _, entry := range entries {
if !entry.IsRegular() {
continue
}
lastCommit, firstCommit, _ := wikiRepo.GetFirstAndLastCommitByPath("master", entry.Name())
if err != nil {
ctx.ServerError("GetCommitByPath", err)
return
}
wikiName, err := wiki_service.FilenameToName(entry.Name())
if err != nil {
if models.IsErrWikiInvalidFileName(err) {
continue
}
ctx.ServerError("FilenameToName", err)
return
}
pages = append(pages, api.WikiesResponse{
WikiCloneLink: api.CloneLink{
HTTPS: wikiCloneWiki.HTTPS,
SSH: wikiCloneWiki.SSH,
},
WikiMeta: api.WikiMeta{
Name: wikiName,
Commit: api.WikiCommit{
Author: api.WikiUser{
Name: lastCommit.Author.Name,
Email: lastCommit.Author.Email,
When: lastCommit.Author.When.Unix(),
},
Commiter: api.WikiUser{
Name: lastCommit.Committer.Name,
Email: lastCommit.Committer.Email,
When: lastCommit.Author.When.Unix(),
},
ID: lastCommit.ID.String(),
Message: lastCommit.Message(),
},
FirstCommit: api.WikiCommit{
Author: api.WikiUser{
Name: firstCommit.Author.Name,
Email: firstCommit.Author.Email,
When: firstCommit.Author.When.Unix(),
},
Commiter: api.WikiUser{
Name: firstCommit.Committer.Name,
Email: firstCommit.Committer.Email,
When: firstCommit.Author.When.Unix(),
},
ID: firstCommit.ID.String(),
Message: firstCommit.Message(),
},
},
})
}
//sort by time
sort.Slice(pages, func(i, j int) bool {
return pages[i].FirstCommit.Author.When > pages[j].FirstCommit.Author.When
})
ctx.JSON(http.StatusOK, pages)
}

View File

@ -50,6 +50,11 @@ type swaggerResponseBranchProtectionList struct {
Body []api.BranchProtection `json:"body"` Body []api.BranchProtection `json:"body"`
} }
type swaggerResponseWikiList struct {
// in:body
Body api.WikiesResponse `json:"body"`
}
// TagList // TagList
// swagger:response TagList // swagger:response TagList
type swaggerResponseTagList struct { type swaggerResponseTagList struct {

View File

@ -87,7 +87,7 @@ func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error)
return commit.GetTreeEntryByPath(unescapedTarget) return commit.GetTreeEntryByPath(unescapedTarget)
} }
func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) { func FindWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) {
wikiRepo, err := git.OpenRepository(ctx.Repo.Repository.WikiPath()) wikiRepo, err := git.OpenRepository(ctx.Repo.Repository.WikiPath())
if err != nil { if err != nil {
ctx.ServerError("OpenRepository", err) ctx.ServerError("OpenRepository", err)
@ -133,7 +133,7 @@ func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName strin
} }
func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
wikiRepo, commit, err := findWikiRepoCommit(ctx) wikiRepo, commit, err := FindWikiRepoCommit(ctx)
if err != nil { if err != nil {
if wikiRepo != nil { if wikiRepo != nil {
wikiRepo.Close() wikiRepo.Close()
@ -263,7 +263,7 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
} }
func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
wikiRepo, commit, err := findWikiRepoCommit(ctx) wikiRepo, commit, err := FindWikiRepoCommit(ctx)
if err != nil { if err != nil {
if wikiRepo != nil { if wikiRepo != nil {
wikiRepo.Close() wikiRepo.Close()
@ -337,7 +337,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
} }
func renderEditPage(ctx *context.Context) { func renderEditPage(ctx *context.Context) {
wikiRepo, commit, err := findWikiRepoCommit(ctx) wikiRepo, commit, err := FindWikiRepoCommit(ctx)
if err != nil { if err != nil {
if wikiRepo != nil { if wikiRepo != nil {
wikiRepo.Close() wikiRepo.Close()
@ -472,7 +472,7 @@ func WikiPages(ctx *context.Context) {
ctx.Data["PageIsWiki"] = true ctx.Data["PageIsWiki"] = true
ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(models.UnitTypeWiki) && !ctx.Repo.Repository.IsArchived ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(models.UnitTypeWiki) && !ctx.Repo.Repository.IsArchived
wikiRepo, commit, err := findWikiRepoCommit(ctx) wikiRepo, commit, err := FindWikiRepoCommit(ctx)
if err != nil { if err != nil {
if wikiRepo != nil { if wikiRepo != nil {
wikiRepo.Close() wikiRepo.Close()
@ -521,7 +521,7 @@ func WikiPages(ctx *context.Context) {
// WikiRaw outputs raw blob requested by user (image for example) // WikiRaw outputs raw blob requested by user (image for example)
func WikiRaw(ctx *context.Context) { func WikiRaw(ctx *context.Context) {
wikiRepo, commit, err := findWikiRepoCommit(ctx) wikiRepo, commit, err := FindWikiRepoCommit(ctx)
defer func() { defer func() {
if wikiRepo != nil { if wikiRepo != nil {
wikiRepo.Close() wikiRepo.Close()

View File

@ -9777,6 +9777,39 @@
} }
} }
}, },
"/repos/{owner}/{repo}/wikies": {
"get": {
"produces": [
"application/json"
],
"tags": [
"repository"
],
"summary": "List the wikies in a repository",
"operationId": "repoWikiList",
"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
}
],
"responses": {
"200": {
"$ref": "#/responses/WikiList"
}
}
}
},
"/repos/{template_owner}/{template_repo}/generate": { "/repos/{template_owner}/{template_repo}/generate": {
"post": { "post": {
"consumes": [ "consumes": [