新增:新建wiki接口

This commit is contained in:
yystopf 2022-10-31 16:00:26 +08:00
parent 1eeb49801f
commit 905811e11e
2 changed files with 150 additions and 1 deletions

View File

@ -1,9 +1,14 @@
package hat
import (
"fmt"
"net/http"
"reflect"
"strings"
hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
"gitea.com/go-chi/binding"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
@ -54,7 +59,8 @@ func Routers() *web.Route {
m.Get("/tag_name_set", context.ReferencesGitRepo(), repo.TagNameSet)
m.Group("/wikies", func() {
m.Combo("").Get(repo.ListWikiPages)
m.Combo("").Get(repo.ListWikiPages).
Post(bind(hat_api.WikiOption{}), repo.CreateWiki)
})
}, repoAssignment())
})
@ -153,3 +159,20 @@ func repoAssignment() func(ctx *context.APIContext) {
}
}
}
// bind binding an obj to a func(ctx *context.APIContext)
func bind(obj interface{}) http.HandlerFunc {
tp := reflect.TypeOf(obj)
for tp.Kind() == reflect.Ptr {
tp = tp.Elem()
}
return web.Wrap(func(ctx *context.APIContext) {
theObj := reflect.New(tp).Interface() // create a new form obj for every request but not use obj directly
errs := binding.Bind(ctx.Req, theObj)
if len(errs) > 0 {
ctx.Error(http.StatusUnprocessableEntity, "validationError", fmt.Sprintf("%s: %s", errs[0].FieldNames, errs[0].Error()))
return
}
web.SetForm(ctx, theObj)
})
}

View File

@ -1,12 +1,19 @@
package repo
import (
"bytes"
"io"
"net/http"
"net/url"
"sort"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/web"
wiki_service "code.gitea.io/gitea/services/wiki"
hat_git "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/git"
hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
@ -112,3 +119,122 @@ func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, err
}
return wikiRepo, commit, nil
}
func CreateWiki(ctx *context.Context) {
form := web.GetForm(ctx).(*hat_api.WikiOption)
wikiName := wiki_service.NormalizeWikiName(form.Name)
wikiCloneLink := ctx.Repo.Repository.WikiCloneLink()
if err := wiki_service.AddWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName, form.Content, form.CommitMessage); err != nil {
if models.IsErrWikiReservedName(err) {
ctx.Error(http.StatusInternalServerError, "WikiNameIsReservedPage", "wiki名称是被保留的.")
} else if models.IsErrWikiAlreadyExist(err) {
ctx.Error(http.StatusConflict, "WikiNameAlreadyExist", "wiki名称已存在")
} else {
ctx.Error(http.StatusInternalServerError, "AddWikiPage", err.Error())
}
return
}
wikiRepo, commit, _ := findWikiRepoCommit(ctx)
data, entry, pageFilename := wikiContentsByName(ctx, commit, wikiName)
metas := ctx.Repo.Repository.ComposeDocumentMetas()
var rctx = &markup.RenderContext{
URLPrefix: ctx.Repo.RepoLink,
Metas: metas,
IsWiki: true,
}
var buf strings.Builder
if err := markdown.Render(rctx, bytes.NewReader(data), &buf); err != nil {
if wikiRepo != nil {
wikiRepo.Close()
}
ctx.ServerError("Render", err)
return
}
commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename)
c, err := wikiRepo.GetCommitByPath(entry.Name())
if err != nil {
if models.IsErrWikiInvalidFileName(err) {
return
}
}
wiki := hat_api.WikiResponse{
WikiCloneLink: hat_api.CloneLink{
HTTPS: wikiCloneLink.HTTPS,
SSH: wikiCloneLink.SSH,
},
WikiMeta: hat_api.WikiMeta{
Name: form.Name,
Commit: hat_api.WikiCommit{
Author: hat_api.WikiUser{
Name: c.Author.Name,
Email: c.Author.Email,
When: c.Author.When.Unix(),
},
Commiter: hat_api.WikiUser{
Name: c.Committer.Name,
Email: c.Committer.Email,
When: c.Author.When.Unix(),
},
ID: c.ID.String(),
Message: c.Message(),
},
},
CommitCounts: commitsCount,
MdContent: string(data),
SimpleContent: buf.String(),
}
ctx.JSON(http.StatusOK, wiki)
}
func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte {
reader, err := entry.Blob().DataAsync()
if err != nil {
ctx.ServerError("Blob.Data", err)
return nil
}
defer reader.Close()
content, err := io.ReadAll(reader)
if err != nil {
ctx.ServerError("ReadAll", err)
return nil
}
return content
}
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)
}
// 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.Context, commit *git.Commit, wikiName string) ([]byte, *git.TreeEntry, string) {
pageFilename := wiki_service.NameToFilename(wikiName)
entry, err := findEntryForFile(commit, pageFilename)
if err != nil {
if git.IsErrNotExist(err) {
} else {
ctx.ServerError("findEntryForFile", err)
}
return nil, nil, ""
}
return wikiContentsByEntry(ctx, entry), entry, pageFilename
}