summaryrefslogtreecommitdiffstats
path: root/routers/web/repo/wiki.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel@debian.org>2024-10-18 20:33:49 +0200
committerDaniel Baumann <daniel@debian.org>2024-10-18 20:33:49 +0200
commitdd136858f1ea40ad3c94191d647487fa4f31926c (patch)
tree58fec94a7b2a12510c9664b21793f1ed560c6518 /routers/web/repo/wiki.go
parentInitial commit. (diff)
downloadforgejo-upstream.tar.xz
forgejo-upstream.zip
Adding upstream version 9.0.0.upstream/9.0.0upstreamdebian
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'routers/web/repo/wiki.go')
-rw-r--r--routers/web/repo/wiki.go816
1 files changed, 816 insertions, 0 deletions
diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go
new file mode 100644
index 0000000..1fd0800
--- /dev/null
+++ b/routers/web/repo/wiki.go
@@ -0,0 +1,816 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Copyright 2018 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repo
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path/filepath"
+ "strings"
+
+ git_model "code.gitea.io/gitea/models/git"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/charset"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/markup"
+ "code.gitea.io/gitea/modules/markup/markdown"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/timeutil"
+ "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/web"
+ "code.gitea.io/gitea/routers/common"
+ "code.gitea.io/gitea/services/context"
+ "code.gitea.io/gitea/services/forms"
+ notify_service "code.gitea.io/gitea/services/notify"
+ wiki_service "code.gitea.io/gitea/services/wiki"
+)
+
+const (
+ tplWikiStart base.TplName = "repo/wiki/start"
+ tplWikiView base.TplName = "repo/wiki/view"
+ tplWikiRevision base.TplName = "repo/wiki/revision"
+ tplWikiNew base.TplName = "repo/wiki/new"
+ tplWikiPages base.TplName = "repo/wiki/pages"
+ tplWikiSearch base.TplName = "repo/wiki/search"
+)
+
+// MustEnableWiki check if wiki is enabled, if external then redirect
+func MustEnableWiki(ctx *context.Context) {
+ if !ctx.Repo.CanRead(unit.TypeWiki) &&
+ !ctx.Repo.CanRead(unit.TypeExternalWiki) {
+ if log.IsTrace() {
+ log.Trace("Permission Denied: User %-v cannot read %-v or %-v of repo %-v\n"+
+ "User in repo has Permissions: %-+v",
+ ctx.Doer,
+ unit.TypeWiki,
+ unit.TypeExternalWiki,
+ ctx.Repo.Repository,
+ ctx.Repo.Permission)
+ }
+ ctx.NotFound("MustEnableWiki", nil)
+ return
+ }
+
+ unit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalWiki)
+ if err == nil {
+ ctx.Redirect(unit.ExternalWikiConfig().ExternalWikiURL)
+ return
+ }
+}
+
+// PageMeta wiki page meta information
+type PageMeta struct {
+ Name string
+ SubURL string
+ GitEntryName string
+ UpdatedUnix timeutil.TimeStamp
+}
+
+// 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 && !git.IsErrNotExist(err) {
+ return nil, err
+ }
+ if entry != nil {
+ return entry, nil
+ }
+
+ // Then the unescaped, the shortest alternative
+ var unescapedTarget string
+ if unescapedTarget, err = url.QueryUnescape(target); err != nil {
+ return nil, err
+ }
+ return commit.GetTreeEntryByPath(unescapedTarget)
+}
+
+func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) {
+ wikiRepo, err := gitrepo.OpenWikiRepository(ctx, ctx.Repo.Repository)
+ if err != nil {
+ ctx.ServerError("OpenRepository", err)
+ return nil, nil, err
+ }
+
+ commit, err := wikiRepo.GetBranchCommit(ctx.Repo.Repository.GetWikiBranchName())
+ if err != nil {
+ return wikiRepo, nil, err
+ }
+ return wikiRepo, commit, nil
+}
+
+// wikiContentsByEntry returns the contents of the wiki page referenced by the
+// given tree entry. Writes to ctx if an error occurs.
+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
+}
+
+// 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 wiki_service.WebPath) ([]byte, *git.TreeEntry, string, bool) {
+ gitFilename := wiki_service.WebPathToGitPath(wikiName)
+ entry, err := findEntryForFile(commit, gitFilename)
+ if err != nil && !git.IsErrNotExist(err) {
+ ctx.ServerError("findEntryForFile", err)
+ return nil, nil, "", false
+ } else if entry == nil {
+ return nil, nil, "", true
+ }
+ return wikiContentsByEntry(ctx, entry), entry, gitFilename, false
+}
+
+func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
+ wikiRepo, commit, err := findWikiRepoCommit(ctx)
+ if err != nil {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ if !git.IsErrNotExist(err) {
+ ctx.ServerError("GetBranchCommit", err)
+ }
+ return nil, nil
+ }
+
+ // Get page list.
+ entries, err := commit.ListEntries()
+ if err != nil {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ ctx.ServerError("ListEntries", err)
+ return nil, nil
+ }
+ pages := make([]PageMeta, 0, len(entries))
+ for _, entry := range entries {
+ if !entry.IsRegular() {
+ continue
+ }
+ wikiName, err := wiki_service.GitPathToWebPath(entry.Name())
+ if err != nil {
+ if repo_model.IsErrWikiInvalidFileName(err) {
+ continue
+ }
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ ctx.ServerError("WikiFilenameToName", err)
+ return nil, nil
+ } else if wikiName == "_Sidebar" || wikiName == "_Footer" {
+ continue
+ }
+ _, displayName := wiki_service.WebPathToUserTitle(wikiName)
+ pages = append(pages, PageMeta{
+ Name: displayName,
+ SubURL: wiki_service.WebPathToURLPath(wikiName),
+ GitEntryName: entry.Name(),
+ })
+ }
+ ctx.Data["Pages"] = pages
+
+ // get requested page name
+ pageName := wiki_service.WebPathFromRequest(ctx.PathParamRaw("*"))
+ if len(pageName) == 0 {
+ pageName = "Home"
+ }
+
+ _, displayName := wiki_service.WebPathToUserTitle(pageName)
+ ctx.Data["PageURL"] = wiki_service.WebPathToURLPath(pageName)
+ ctx.Data["old_title"] = displayName
+ ctx.Data["Title"] = displayName
+ ctx.Data["title"] = displayName
+
+ isSideBar := pageName == "_Sidebar"
+ isFooter := pageName == "_Footer"
+
+ // lookup filename in wiki - get filecontent, gitTree entry , real filename
+ data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName)
+ if noEntry {
+ ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
+ }
+ if entry == nil || ctx.Written() {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ return nil, nil
+ }
+
+ var sidebarContent []byte
+ if !isSideBar {
+ sidebarContent, _, _, _ = wikiContentsByName(ctx, commit, "_Sidebar")
+ if ctx.Written() {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ return nil, nil
+ }
+ } else {
+ sidebarContent = data
+ }
+
+ var footerContent []byte
+ if !isFooter {
+ footerContent, _, _, _ = wikiContentsByName(ctx, commit, "_Footer")
+ if ctx.Written() {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ return nil, nil
+ }
+ } else {
+ footerContent = data
+ }
+
+ rctx := &markup.RenderContext{
+ Ctx: ctx,
+ Metas: ctx.Repo.Repository.ComposeDocumentMetas(ctx),
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ },
+ IsWiki: true,
+ }
+ buf := &strings.Builder{}
+
+ renderFn := func(data []byte) (escaped *charset.EscapeStatus, output string, err error) {
+ markupRd, markupWr := io.Pipe()
+ defer markupWr.Close()
+ done := make(chan struct{})
+ go func() {
+ // We allow NBSP here this is rendered
+ escaped, _ = charset.EscapeControlReader(markupRd, buf, ctx.Locale, charset.WikiContext, charset.RuneNBSP)
+ output = buf.String()
+ buf.Reset()
+ close(done)
+ }()
+
+ err = markdown.Render(rctx, bytes.NewReader(data), markupWr)
+ _ = markupWr.CloseWithError(err)
+ <-done
+ return escaped, output, err
+ }
+
+ ctx.Data["EscapeStatus"], ctx.Data["content"], err = renderFn(data)
+ if err != nil {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ ctx.ServerError("Render", err)
+ return nil, nil
+ }
+
+ if rctx.SidebarTocNode != nil {
+ sb := &strings.Builder{}
+ err = markdown.SpecializedMarkdown().Renderer().Render(sb, nil, rctx.SidebarTocNode)
+ if err != nil {
+ log.Error("Failed to render wiki sidebar TOC: %v", err)
+ } else {
+ ctx.Data["sidebarTocContent"] = sb.String()
+ }
+ }
+
+ if !isSideBar {
+ buf.Reset()
+ ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"], err = renderFn(sidebarContent)
+ if err != nil {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ ctx.ServerError("Render", err)
+ return nil, nil
+ }
+ ctx.Data["sidebarPresent"] = sidebarContent != nil
+ } else {
+ ctx.Data["sidebarPresent"] = false
+ }
+
+ if !isFooter {
+ buf.Reset()
+ ctx.Data["footerEscapeStatus"], ctx.Data["footerContent"], err = renderFn(footerContent)
+ if err != nil {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ ctx.ServerError("Render", err)
+ return nil, nil
+ }
+ ctx.Data["footerPresent"] = footerContent != nil
+ } else {
+ ctx.Data["footerPresent"] = false
+ }
+
+ // get commit count - wiki revisions
+ commitsCount, _ := wikiRepo.FileCommitsCount(ctx.Repo.Repository.GetWikiBranchName(), pageFilename)
+ ctx.Data["CommitCount"] = commitsCount
+
+ return wikiRepo, entry
+}
+
+func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
+ wikiRepo, commit, err := findWikiRepoCommit(ctx)
+ if err != nil {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ if !git.IsErrNotExist(err) {
+ ctx.ServerError("GetBranchCommit", err)
+ }
+ return nil, nil
+ }
+
+ // get requested pagename
+ pageName := wiki_service.WebPathFromRequest(ctx.PathParamRaw("*"))
+ if len(pageName) == 0 {
+ pageName = "Home"
+ }
+
+ _, displayName := wiki_service.WebPathToUserTitle(pageName)
+ ctx.Data["PageURL"] = wiki_service.WebPathToURLPath(pageName)
+ ctx.Data["old_title"] = displayName
+ ctx.Data["Title"] = displayName
+ ctx.Data["title"] = displayName
+
+ ctx.Data["Username"] = ctx.Repo.Owner.Name
+ ctx.Data["Reponame"] = ctx.Repo.Repository.Name
+
+ // lookup filename in wiki - get filecontent, gitTree entry , real filename
+ data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName)
+ if noEntry {
+ ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
+ }
+ if entry == nil || ctx.Written() {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ return nil, nil
+ }
+
+ ctx.Data["content"] = string(data)
+ ctx.Data["sidebarPresent"] = false
+ ctx.Data["sidebarContent"] = ""
+ ctx.Data["footerPresent"] = false
+ ctx.Data["footerContent"] = ""
+
+ // get commit count - wiki revisions
+ commitsCount, _ := wikiRepo.FileCommitsCount(ctx.Repo.Repository.GetWikiBranchName(), pageFilename)
+ ctx.Data["CommitCount"] = commitsCount
+
+ // get page
+ page := ctx.FormInt("page")
+ if page <= 1 {
+ page = 1
+ }
+
+ // get Commit Count
+ commitsHistory, err := wikiRepo.CommitsByFileAndRange(
+ git.CommitsByFileAndRangeOptions{
+ Revision: ctx.Repo.Repository.GetWikiBranchName(),
+ File: pageFilename,
+ Page: page,
+ })
+ if err != nil {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ ctx.ServerError("CommitsByFileAndRange", err)
+ return nil, nil
+ }
+ ctx.Data["Commits"] = git_model.ConvertFromGitCommit(ctx, commitsHistory, ctx.Repo.Repository)
+
+ pager := context.NewPagination(int(commitsCount), setting.Git.CommitsRangeSize, page, 5)
+ pager.SetDefaultParams(ctx)
+ pager.AddParamString("action", "_revision")
+ ctx.Data["Page"] = pager
+
+ return wikiRepo, entry
+}
+
+func renderEditPage(ctx *context.Context) {
+ wikiRepo, commit, err := findWikiRepoCommit(ctx)
+ if err != nil {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ if !git.IsErrNotExist(err) {
+ ctx.ServerError("GetBranchCommit", err)
+ }
+ return
+ }
+ defer func() {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ }()
+
+ // get requested pagename
+ pageName := wiki_service.WebPathFromRequest(ctx.PathParamRaw("*"))
+ if len(pageName) == 0 {
+ pageName = "Home"
+ }
+
+ _, displayName := wiki_service.WebPathToUserTitle(pageName)
+ ctx.Data["PageURL"] = wiki_service.WebPathToURLPath(pageName)
+ ctx.Data["old_title"] = displayName
+ ctx.Data["Title"] = displayName
+ ctx.Data["title"] = displayName
+
+ // lookup filename in wiki - get filecontent, gitTree entry , real filename
+ data, entry, _, noEntry := wikiContentsByName(ctx, commit, pageName)
+ if noEntry {
+ ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
+ }
+ if entry == nil || ctx.Written() {
+ return
+ }
+
+ ctx.Data["content"] = string(data)
+ ctx.Data["sidebarPresent"] = false
+ ctx.Data["sidebarContent"] = ""
+ ctx.Data["footerPresent"] = false
+ ctx.Data["footerContent"] = ""
+}
+
+// WikiPost renders post of wiki page
+func WikiPost(ctx *context.Context) {
+ switch ctx.FormString("action") {
+ case "_new":
+ if !ctx.Repo.CanWrite(unit.TypeWiki) {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ NewWikiPost(ctx)
+ return
+ case "_delete":
+ if !ctx.Repo.CanWrite(unit.TypeWiki) {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ DeleteWikiPagePost(ctx)
+ return
+ }
+
+ if !ctx.Repo.CanWrite(unit.TypeWiki) {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ EditWikiPost(ctx)
+}
+
+// Wiki renders single wiki page
+func Wiki(ctx *context.Context) {
+ ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived
+
+ switch ctx.FormString("action") {
+ case "_pages":
+ WikiPages(ctx)
+ return
+ case "_revision":
+ WikiRevision(ctx)
+ return
+ case "_edit":
+ if !ctx.Repo.CanWrite(unit.TypeWiki) {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ EditWiki(ctx)
+ return
+ case "_new":
+ if !ctx.Repo.CanWrite(unit.TypeWiki) {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ NewWiki(ctx)
+ return
+ }
+
+ if !ctx.Repo.Repository.HasWiki() {
+ ctx.Data["Title"] = ctx.Tr("repo.wiki")
+ ctx.HTML(http.StatusOK, tplWikiStart)
+ return
+ }
+
+ wikiRepo, entry := renderViewPage(ctx)
+ defer func() {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ }()
+ if ctx.Written() {
+ return
+ }
+ if entry == nil {
+ ctx.Data["Title"] = ctx.Tr("repo.wiki")
+ ctx.HTML(http.StatusOK, tplWikiStart)
+ return
+ }
+
+ wikiPath := entry.Name()
+ if markup.Type(wikiPath) != markdown.MarkupName {
+ ext := strings.ToUpper(filepath.Ext(wikiPath))
+ ctx.Data["FormatWarning"] = fmt.Sprintf("%s rendering is not supported at the moment. Rendered as Markdown.", ext)
+ }
+ // Get last change information.
+ lastCommit, err := wikiRepo.GetCommitByPath(wikiPath)
+ if err != nil {
+ ctx.ServerError("GetCommitByPath", err)
+ return
+ }
+ ctx.Data["Author"] = lastCommit.Author
+
+ ctx.HTML(http.StatusOK, tplWikiView)
+}
+
+// WikiRevision renders file revision list of wiki page
+func WikiRevision(ctx *context.Context) {
+ ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived
+
+ if !ctx.Repo.Repository.HasWiki() {
+ ctx.Data["Title"] = ctx.Tr("repo.wiki")
+ ctx.HTML(http.StatusOK, tplWikiStart)
+ return
+ }
+
+ wikiRepo, entry := renderRevisionPage(ctx)
+ defer func() {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ }()
+
+ if ctx.Written() {
+ return
+ }
+ if entry == nil {
+ ctx.Data["Title"] = ctx.Tr("repo.wiki")
+ ctx.HTML(http.StatusOK, tplWikiStart)
+ return
+ }
+
+ // Get last change information.
+ wikiPath := entry.Name()
+ lastCommit, err := wikiRepo.GetCommitByPath(wikiPath)
+ if err != nil {
+ ctx.ServerError("GetCommitByPath", err)
+ return
+ }
+ ctx.Data["Author"] = lastCommit.Author
+
+ ctx.HTML(http.StatusOK, tplWikiRevision)
+}
+
+// WikiPages render wiki pages list page
+func WikiPages(ctx *context.Context) {
+ if !ctx.Repo.Repository.HasWiki() {
+ ctx.Redirect(ctx.Repo.RepoLink + "/wiki")
+ return
+ }
+
+ ctx.Data["Title"] = ctx.Tr("repo.wiki.pages")
+ ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(unit.TypeWiki) && !ctx.Repo.Repository.IsArchived
+
+ wikiRepo, commit, err := findWikiRepoCommit(ctx)
+ 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("ListEntries", err)
+ return
+ }
+ pages := make([]PageMeta, 0, len(entries))
+ for _, entry := range entries {
+ if !entry.IsRegular() {
+ continue
+ }
+ c, err := wikiRepo.GetCommitByPath(entry.Name())
+ if err != nil {
+ ctx.ServerError("GetCommit", err)
+ return
+ }
+ wikiName, err := wiki_service.GitPathToWebPath(entry.Name())
+ if err != nil {
+ if repo_model.IsErrWikiInvalidFileName(err) {
+ continue
+ }
+ ctx.ServerError("WikiFilenameToName", err)
+ return
+ }
+ _, displayName := wiki_service.WebPathToUserTitle(wikiName)
+ pages = append(pages, PageMeta{
+ Name: displayName,
+ SubURL: wiki_service.WebPathToURLPath(wikiName),
+ GitEntryName: entry.Name(),
+ UpdatedUnix: timeutil.TimeStamp(c.Author.When.Unix()),
+ })
+ }
+ ctx.Data["Pages"] = pages
+
+ ctx.HTML(http.StatusOK, tplWikiPages)
+}
+
+// WikiRaw outputs raw blob requested by user (image for example)
+func WikiRaw(ctx *context.Context) {
+ wikiRepo, commit, err := findWikiRepoCommit(ctx)
+ defer func() {
+ if wikiRepo != nil {
+ wikiRepo.Close()
+ }
+ }()
+
+ if err != nil {
+ if git.IsErrNotExist(err) {
+ ctx.NotFound("findEntryForFile", nil)
+ return
+ }
+ ctx.ServerError("findEntryForfile", err)
+ return
+ }
+
+ providedWebPath := wiki_service.WebPathFromRequest(ctx.PathParamRaw("*"))
+ providedGitPath := wiki_service.WebPathToGitPath(providedWebPath)
+ var entry *git.TreeEntry
+ if commit != nil {
+ // Try to find a file with that name
+ entry, err = findEntryForFile(commit, providedGitPath)
+ if err != nil && !git.IsErrNotExist(err) {
+ ctx.ServerError("findFile", err)
+ return
+ }
+
+ if entry == nil {
+ // Try to find a wiki page with that name
+ providedGitPath = strings.TrimSuffix(providedGitPath, ".md")
+ entry, err = findEntryForFile(commit, providedGitPath)
+ if err != nil && !git.IsErrNotExist(err) {
+ ctx.ServerError("findFile", err)
+ return
+ }
+ }
+ }
+
+ if entry != nil {
+ if err = common.ServeBlob(ctx.Base, ctx.Repo.TreePath, entry.Blob(), nil); err != nil {
+ ctx.ServerError("ServeBlob", err)
+ }
+ return
+ }
+
+ ctx.NotFound("findEntryForFile", nil)
+}
+
+// NewWiki render wiki create page
+func NewWiki(ctx *context.Context) {
+ ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
+
+ if !ctx.Repo.Repository.HasWiki() {
+ ctx.Data["title"] = "Home"
+ }
+ if ctx.FormString("title") != "" {
+ ctx.Data["title"] = ctx.FormString("title")
+ }
+
+ ctx.HTML(http.StatusOK, tplWikiNew)
+}
+
+// NewWikiPost response for wiki create request
+func NewWikiPost(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.NewWikiForm)
+ ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
+
+ if ctx.HasError() {
+ ctx.HTML(http.StatusOK, tplWikiNew)
+ return
+ }
+
+ if util.IsEmptyString(form.Title) {
+ ctx.RenderWithErr(ctx.Tr("repo.issues.new.title_empty"), tplWikiNew, form)
+ return
+ }
+
+ wikiName := wiki_service.UserTitleToWebPath("", form.Title)
+
+ if len(form.Message) == 0 {
+ form.Message = ctx.Locale.TrString("repo.editor.add", form.Title)
+ }
+
+ if err := wiki_service.AddWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName, form.Content, form.Message); err != nil {
+ if repo_model.IsErrWikiReservedName(err) {
+ ctx.Data["Err_Title"] = true
+ ctx.RenderWithErr(ctx.Tr("repo.wiki.reserved_page", wikiName), tplWikiNew, &form)
+ } else if repo_model.IsErrWikiAlreadyExist(err) {
+ ctx.Data["Err_Title"] = true
+ ctx.RenderWithErr(ctx.Tr("repo.wiki.page_already_exists"), tplWikiNew, &form)
+ } else {
+ ctx.ServerError("AddWikiPage", err)
+ }
+ return
+ }
+
+ notify_service.NewWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(wikiName), form.Message)
+
+ ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + wiki_service.WebPathToURLPath(wikiName))
+}
+
+// EditWiki render wiki modify page
+func EditWiki(ctx *context.Context) {
+ ctx.Data["PageIsWikiEdit"] = true
+
+ if !ctx.Repo.Repository.HasWiki() {
+ ctx.Redirect(ctx.Repo.RepoLink + "/wiki")
+ return
+ }
+
+ renderEditPage(ctx)
+ if ctx.Written() {
+ return
+ }
+
+ ctx.HTML(http.StatusOK, tplWikiNew)
+}
+
+// EditWikiPost response for wiki modify request
+func EditWikiPost(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.NewWikiForm)
+ ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
+
+ if ctx.HasError() {
+ ctx.HTML(http.StatusOK, tplWikiNew)
+ return
+ }
+
+ oldWikiName := wiki_service.WebPathFromRequest(ctx.PathParamRaw("*"))
+ newWikiName := wiki_service.UserTitleToWebPath("", form.Title)
+
+ if len(form.Message) == 0 {
+ form.Message = ctx.Locale.TrString("repo.editor.update", form.Title)
+ }
+
+ if err := wiki_service.EditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, oldWikiName, newWikiName, form.Content, form.Message); err != nil {
+ ctx.ServerError("EditWikiPage", err)
+ return
+ }
+
+ notify_service.EditWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(newWikiName), form.Message)
+
+ ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + wiki_service.WebPathToURLPath(newWikiName))
+}
+
+// DeleteWikiPagePost delete wiki page
+func DeleteWikiPagePost(ctx *context.Context) {
+ wikiName := wiki_service.WebPathFromRequest(ctx.PathParamRaw("*"))
+ if len(wikiName) == 0 {
+ wikiName = "Home"
+ }
+
+ if err := wiki_service.DeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, wikiName); err != nil {
+ ctx.ServerError("DeleteWikiPage", err)
+ return
+ }
+
+ notify_service.DeleteWikiPage(ctx, ctx.Doer, ctx.Repo.Repository, string(wikiName))
+
+ ctx.JSONRedirect(ctx.Repo.RepoLink + "/wiki/")
+}
+
+func WikiSearchContent(ctx *context.Context) {
+ keyword := ctx.FormTrim("q")
+ if keyword == "" {
+ ctx.HTML(http.StatusOK, tplWikiSearch)
+ return
+ }
+
+ res, err := wiki_service.SearchWikiContents(ctx, ctx.Repo.Repository, keyword)
+ if err != nil {
+ ctx.ServerError("SearchWikiContents", err)
+ return
+ }
+
+ ctx.Data["Results"] = res
+ ctx.HTML(http.StatusOK, tplWikiSearch)
+}