wiki.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. package repo
  2. import (
  3. "strings"
  4. "time"
  5. "github.com/gogs/git-module"
  6. "gogs.io/gogs/internal/context"
  7. "gogs.io/gogs/internal/database"
  8. "gogs.io/gogs/internal/form"
  9. "gogs.io/gogs/internal/gitutil"
  10. "gogs.io/gogs/internal/markup"
  11. )
  12. const (
  13. tmplRepoWikiStart = "repo/wiki/start"
  14. tmplRepoWikiView = "repo/wiki/view"
  15. tmplRepoWikiNew = "repo/wiki/new"
  16. tmplRepoWikiPages = "repo/wiki/pages"
  17. )
  18. func MustEnableWiki(c *context.Context) {
  19. if !c.Repo.Repository.EnableWiki {
  20. c.NotFound()
  21. return
  22. }
  23. if c.Repo.Repository.EnableExternalWiki {
  24. c.Redirect(c.Repo.Repository.ExternalWikiURL)
  25. return
  26. }
  27. }
  28. type PageMeta struct {
  29. Name string
  30. URL string
  31. Updated time.Time
  32. }
  33. func renderWikiPage(c *context.Context, isViewPage bool) (*git.Repository, string) {
  34. wikiPath := c.Repo.Repository.WikiPath()
  35. wikiRepo, err := git.Open(wikiPath)
  36. if err != nil {
  37. c.Error(err, "open repository")
  38. return nil, ""
  39. }
  40. commit, err := wikiRepo.BranchCommit(database.WikiBranch(wikiPath))
  41. if err != nil {
  42. c.Error(err, "get branch commit")
  43. return nil, ""
  44. }
  45. // Get page list.
  46. if isViewPage {
  47. entries, err := commit.Entries(git.LsTreeOptions{Verbatim: true})
  48. if err != nil {
  49. c.Error(err, "list entries")
  50. return nil, ""
  51. }
  52. pages := make([]PageMeta, 0, len(entries))
  53. for i := range entries {
  54. if entries[i].Type() == git.ObjectBlob && strings.HasSuffix(entries[i].Name(), ".md") {
  55. name := strings.TrimSuffix(entries[i].Name(), ".md")
  56. pages = append(pages, PageMeta{
  57. Name: name,
  58. URL: database.ToWikiPageURL(name),
  59. })
  60. }
  61. }
  62. c.Data["Pages"] = pages
  63. }
  64. pageURL := c.Params(":page")
  65. if pageURL == "" {
  66. pageURL = "Home"
  67. }
  68. c.Data["PageURL"] = pageURL
  69. pageName := database.ToWikiPageName(pageURL)
  70. c.Data["old_title"] = pageName
  71. c.Data["Title"] = pageName
  72. c.Data["title"] = pageName
  73. c.Data["RequireHighlightJS"] = true
  74. blob, err := commit.Blob(pageName + ".md")
  75. if err != nil {
  76. if gitutil.IsErrRevisionNotExist(err) {
  77. c.Redirect(c.Repo.RepoLink + "/wiki/_pages")
  78. } else {
  79. c.Error(err, "get blob")
  80. }
  81. return nil, ""
  82. }
  83. p, err := blob.Bytes()
  84. if err != nil {
  85. c.Error(err, "read blob")
  86. return nil, ""
  87. }
  88. if isViewPage {
  89. c.Data["content"] = string(markup.Markdown(p, c.Repo.RepoLink, c.Repo.Repository.ComposeMetas()))
  90. } else {
  91. c.Data["content"] = string(p)
  92. }
  93. return wikiRepo, pageName
  94. }
  95. func Wiki(c *context.Context) {
  96. c.Data["PageIsWiki"] = true
  97. if !c.Repo.Repository.HasWiki() {
  98. c.Data["Title"] = c.Tr("repo.wiki")
  99. c.Success(tmplRepoWikiStart)
  100. return
  101. }
  102. wikiRepo, pageName := renderWikiPage(c, true)
  103. if c.Written() {
  104. return
  105. }
  106. // Get last change information.
  107. branch := database.WikiBranch(c.Repo.Repository.WikiPath())
  108. commits, err := wikiRepo.Log(git.RefsHeads+branch, git.LogOptions{Path: pageName + ".md"})
  109. if err != nil {
  110. c.Error(err, "get commits by path")
  111. return
  112. }
  113. c.Data["Author"] = commits[0].Author
  114. c.Success(tmplRepoWikiView)
  115. }
  116. func WikiPages(c *context.Context) {
  117. c.Data["Title"] = c.Tr("repo.wiki.pages")
  118. c.Data["PageIsWiki"] = true
  119. if !c.Repo.Repository.HasWiki() {
  120. c.Redirect(c.Repo.RepoLink + "/wiki")
  121. return
  122. }
  123. wikiPath := c.Repo.Repository.WikiPath()
  124. wikiRepo, err := git.Open(wikiPath)
  125. if err != nil {
  126. c.Error(err, "open repository")
  127. return
  128. }
  129. branch := database.WikiBranch(wikiPath)
  130. commit, err := wikiRepo.BranchCommit(branch)
  131. if err != nil {
  132. c.Error(err, "get branch commit")
  133. return
  134. }
  135. entries, err := commit.Entries(git.LsTreeOptions{Verbatim: true})
  136. if err != nil {
  137. c.Error(err, "list entries")
  138. return
  139. }
  140. pages := make([]PageMeta, 0, len(entries))
  141. for i := range entries {
  142. if entries[i].Type() == git.ObjectBlob && strings.HasSuffix(entries[i].Name(), ".md") {
  143. commits, err := wikiRepo.Log(git.RefsHeads+branch, git.LogOptions{Path: entries[i].Name()})
  144. if err != nil {
  145. c.Error(err, "get commits by path")
  146. return
  147. }
  148. name := strings.TrimSuffix(entries[i].Name(), ".md")
  149. pages = append(pages, PageMeta{
  150. Name: name,
  151. URL: database.ToWikiPageURL(name),
  152. Updated: commits[0].Author.When,
  153. })
  154. }
  155. }
  156. c.Data["Pages"] = pages
  157. c.Success(tmplRepoWikiPages)
  158. }
  159. func NewWiki(c *context.Context) {
  160. c.Data["Title"] = c.Tr("repo.wiki.new_page")
  161. c.Data["PageIsWiki"] = true
  162. c.Data["RequireSimpleMDE"] = true
  163. if !c.Repo.Repository.HasWiki() {
  164. c.Data["title"] = "Home"
  165. }
  166. c.Success(tmplRepoWikiNew)
  167. }
  168. func NewWikiPost(c *context.Context, f form.NewWiki) {
  169. c.Data["Title"] = c.Tr("repo.wiki.new_page")
  170. c.Data["PageIsWiki"] = true
  171. c.Data["RequireSimpleMDE"] = true
  172. if c.HasError() {
  173. c.Success(tmplRepoWikiNew)
  174. return
  175. }
  176. if err := c.Repo.Repository.AddWikiPage(c.User, f.Title, f.Content, f.Message); err != nil {
  177. if database.IsErrWikiAlreadyExist(err) {
  178. c.Data["Err_Title"] = true
  179. c.RenderWithErr(c.Tr("repo.wiki.page_already_exists"), tmplRepoWikiNew, &f)
  180. } else {
  181. c.Error(err, "add wiki page")
  182. }
  183. return
  184. }
  185. c.Redirect(c.Repo.RepoLink + "/wiki/" + database.ToWikiPageURL(database.ToWikiPageName(f.Title)))
  186. }
  187. func EditWiki(c *context.Context) {
  188. c.Data["PageIsWiki"] = true
  189. c.Data["PageIsWikiEdit"] = true
  190. c.Data["RequireSimpleMDE"] = true
  191. if !c.Repo.Repository.HasWiki() {
  192. c.Redirect(c.Repo.RepoLink + "/wiki")
  193. return
  194. }
  195. renderWikiPage(c, false)
  196. if c.Written() {
  197. return
  198. }
  199. c.Success(tmplRepoWikiNew)
  200. }
  201. func EditWikiPost(c *context.Context, f form.NewWiki) {
  202. c.Data["Title"] = c.Tr("repo.wiki.new_page")
  203. c.Data["PageIsWiki"] = true
  204. c.Data["RequireSimpleMDE"] = true
  205. if c.HasError() {
  206. c.Success(tmplRepoWikiNew)
  207. return
  208. }
  209. if err := c.Repo.Repository.EditWikiPage(c.User, f.OldTitle, f.Title, f.Content, f.Message); err != nil {
  210. c.Error(err, "edit wiki page")
  211. return
  212. }
  213. c.Redirect(c.Repo.RepoLink + "/wiki/" + database.ToWikiPageURL(database.ToWikiPageName(f.Title)))
  214. }
  215. func DeleteWikiPagePost(c *context.Context) {
  216. pageURL := c.Params(":page")
  217. if pageURL == "" {
  218. pageURL = "Home"
  219. }
  220. pageName := database.ToWikiPageName(pageURL)
  221. if err := c.Repo.Repository.DeleteWikiPage(c.User, pageName); err != nil {
  222. c.Error(err, "delete wiki page")
  223. return
  224. }
  225. c.JSONSuccess(map[string]any{
  226. "redirect": c.Repo.RepoLink + "/wiki/",
  227. })
  228. }