A clean, Markdown-based publishing platform made for writers. Write together, and build a community. https://writefreely.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

194 lines
5.6 KiB

  1. /*
  2. * Copyright © 2018-2021 Musing Studio LLC.
  3. *
  4. * This file is part of WriteFreely.
  5. *
  6. * WriteFreely is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License, included
  8. * in the LICENSE file in this source code package.
  9. */
  10. package writefreely
  11. import (
  12. "net/http"
  13. "strings"
  14. "github.com/gorilla/mux"
  15. "github.com/writeas/impart"
  16. "github.com/writeas/web-core/log"
  17. "github.com/writefreely/writefreely/page"
  18. )
  19. func handleViewPad(app *App, w http.ResponseWriter, r *http.Request) error {
  20. vars := mux.Vars(r)
  21. action := vars["action"]
  22. slug := vars["slug"]
  23. collAlias := vars["collection"]
  24. if app.cfg.App.SingleUser {
  25. // TODO: refactor all of this, especially for single-user blogs
  26. c, err := app.db.GetCollectionByID(1)
  27. if err != nil {
  28. return err
  29. }
  30. collAlias = c.Alias
  31. }
  32. appData := &struct {
  33. page.StaticPage
  34. Post *RawPost
  35. User *User
  36. Blogs *[]Collection
  37. Silenced bool
  38. Editing bool // True if we're modifying an existing post
  39. EditCollection *Collection // Collection of the post we're editing, if any
  40. }{
  41. StaticPage: pageForReq(app, r),
  42. Post: &RawPost{Font: "norm"},
  43. User: getUserSession(app, r),
  44. }
  45. var err error
  46. if appData.User != nil {
  47. appData.Blogs, err = app.db.GetPublishableCollections(appData.User, app.cfg.App.Host)
  48. if err != nil {
  49. log.Error("Unable to get user's blogs for Pad: %v", err)
  50. }
  51. appData.Silenced, err = app.db.IsUserSilenced(appData.User.ID)
  52. if err != nil {
  53. if err == ErrUserNotFound {
  54. return err
  55. }
  56. log.Error("Unable to get user status for Pad: %v", err)
  57. }
  58. }
  59. padTmpl := app.cfg.App.Editor
  60. if templates[padTmpl] == nil {
  61. if padTmpl != "" {
  62. log.Info("No template '%s' found. Falling back to default 'pad' template.", padTmpl)
  63. }
  64. padTmpl = "pad"
  65. }
  66. if action == "" && slug == "" {
  67. // Not editing any post; simply render the Pad
  68. if err = templates[padTmpl].ExecuteTemplate(w, "pad", appData); err != nil {
  69. log.Error("Unable to execute template: %v", err)
  70. }
  71. return nil
  72. }
  73. // Retrieve post information for editing
  74. appData.Editing = true
  75. // Make sure this isn't cached, so user doesn't accidentally lose data
  76. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  77. w.Header().Set("Expires", "Thu, 04 Oct 1990 20:00:00 GMT")
  78. if slug != "" {
  79. // TODO: refactor all of this, especially for single-user blogs
  80. appData.Post = getRawCollectionPost(app, slug, collAlias)
  81. if appData.Post.OwnerID != appData.User.ID {
  82. // TODO: add ErrForbiddenEditPost message to flashes
  83. return impart.HTTPError{http.StatusFound, r.URL.Path[:strings.LastIndex(r.URL.Path, "/edit")]}
  84. }
  85. appData.EditCollection, err = app.db.GetCollectionForPad(collAlias)
  86. if err != nil {
  87. log.Error("Unable to GetCollectionForPad: %s", err)
  88. return err
  89. }
  90. appData.EditCollection.hostName = app.cfg.App.Host
  91. } else {
  92. // Editing a floating article
  93. appData.Post = getRawPost(app, action)
  94. appData.Post.Id = action
  95. }
  96. if appData.Post.Gone {
  97. return ErrPostUnpublished
  98. } else if appData.Post.Found && (appData.Post.Title != "" || appData.Post.Content != "") {
  99. // Got the post
  100. } else if appData.Post.Found {
  101. log.Error("Found post, but other conditions failed.")
  102. return ErrPostFetchError
  103. } else {
  104. return ErrPostNotFound
  105. }
  106. if err = templates[padTmpl].ExecuteTemplate(w, "pad", appData); err != nil {
  107. log.Error("Unable to execute template: %v", err)
  108. }
  109. return nil
  110. }
  111. func handleViewMeta(app *App, w http.ResponseWriter, r *http.Request) error {
  112. vars := mux.Vars(r)
  113. action := vars["action"]
  114. slug := vars["slug"]
  115. collAlias := vars["collection"]
  116. appData := &struct {
  117. page.StaticPage
  118. Post *RawPost
  119. User *User
  120. EditCollection *Collection // Collection of the post we're editing, if any
  121. Flashes []string
  122. NeedsToken bool
  123. Silenced bool
  124. }{
  125. StaticPage: pageForReq(app, r),
  126. Post: &RawPost{Font: "norm"},
  127. User: getUserSession(app, r),
  128. }
  129. var err error
  130. appData.Silenced, err = app.db.IsUserSilenced(appData.User.ID)
  131. if err != nil {
  132. log.Error("view meta: get user status: %v", err)
  133. return ErrInternalGeneral
  134. }
  135. if action == "" && slug == "" {
  136. return ErrPostNotFound
  137. }
  138. // Make sure this isn't cached, so user doesn't accidentally lose data
  139. w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
  140. w.Header().Set("Expires", "Thu, 28 Jul 1989 12:00:00 GMT")
  141. if slug != "" {
  142. appData.Post = getRawCollectionPost(app, slug, collAlias)
  143. if appData.Post.OwnerID != appData.User.ID {
  144. // TODO: add ErrForbiddenEditPost message to flashes
  145. return impart.HTTPError{http.StatusFound, r.URL.Path[:strings.LastIndex(r.URL.Path, "/meta")]}
  146. }
  147. if app.cfg.App.SingleUser {
  148. // TODO: optimize this query just like we do in GetCollectionForPad (?)
  149. appData.EditCollection, err = app.db.GetCollectionByID(1)
  150. } else {
  151. appData.EditCollection, err = app.db.GetCollectionForPad(collAlias)
  152. }
  153. if err != nil {
  154. return err
  155. }
  156. appData.EditCollection.hostName = app.cfg.App.Host
  157. } else {
  158. // Editing a floating article
  159. appData.Post = getRawPost(app, action)
  160. appData.Post.Id = action
  161. }
  162. appData.NeedsToken = appData.User == nil || appData.User.ID != appData.Post.OwnerID
  163. if appData.Post.Gone {
  164. return ErrPostUnpublished
  165. } else if appData.Post.Found && appData.Post.Content != "" {
  166. // Got the post
  167. } else if appData.Post.Found {
  168. return ErrPostFetchError
  169. } else {
  170. return ErrPostNotFound
  171. }
  172. appData.Flashes, _ = getSessionFlashes(app, w, r, nil)
  173. if err = templates["edit-meta"].ExecuteTemplate(w, "edit-meta", appData); err != nil {
  174. log.Error("Unable to execute template: %v", err)
  175. }
  176. return nil
  177. }