entry.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // Copyright 2017 Frédéric Guillot. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package api
  5. import (
  6. "errors"
  7. "net/http"
  8. "time"
  9. "github.com/miniflux/miniflux/http/context"
  10. "github.com/miniflux/miniflux/http/request"
  11. "github.com/miniflux/miniflux/http/response/json"
  12. "github.com/miniflux/miniflux/model"
  13. "github.com/miniflux/miniflux/storage"
  14. )
  15. // GetFeedEntry is the API handler to get a single feed entry.
  16. func (c *Controller) GetFeedEntry(w http.ResponseWriter, r *http.Request) {
  17. feedID, err := request.IntParam(r, "feedID")
  18. if err != nil {
  19. json.BadRequest(w, err)
  20. return
  21. }
  22. entryID, err := request.IntParam(r, "entryID")
  23. if err != nil {
  24. json.BadRequest(w, err)
  25. return
  26. }
  27. ctx := context.New(r)
  28. userID := ctx.UserID()
  29. builder := c.store.NewEntryQueryBuilder(userID)
  30. builder.WithFeedID(feedID)
  31. builder.WithEntryID(entryID)
  32. entry, err := builder.GetEntry()
  33. if err != nil {
  34. json.ServerError(w, errors.New("Unable to fetch this entry from the database"))
  35. return
  36. }
  37. if entry == nil {
  38. json.NotFound(w, errors.New("Entry not found"))
  39. return
  40. }
  41. json.OK(w, r, entry)
  42. }
  43. // GetEntry is the API handler to get a single entry.
  44. func (c *Controller) GetEntry(w http.ResponseWriter, r *http.Request) {
  45. entryID, err := request.IntParam(r, "entryID")
  46. if err != nil {
  47. json.BadRequest(w, err)
  48. return
  49. }
  50. builder := c.store.NewEntryQueryBuilder(context.New(r).UserID())
  51. builder.WithEntryID(entryID)
  52. entry, err := builder.GetEntry()
  53. if err != nil {
  54. json.ServerError(w, errors.New("Unable to fetch this entry from the database"))
  55. return
  56. }
  57. if entry == nil {
  58. json.NotFound(w, errors.New("Entry not found"))
  59. return
  60. }
  61. json.OK(w, r, entry)
  62. }
  63. // GetFeedEntries is the API handler to get all feed entries.
  64. func (c *Controller) GetFeedEntries(w http.ResponseWriter, r *http.Request) {
  65. feedID, err := request.IntParam(r, "feedID")
  66. if err != nil {
  67. json.BadRequest(w, err)
  68. return
  69. }
  70. status := request.QueryParam(r, "status", "")
  71. if status != "" {
  72. if err := model.ValidateEntryStatus(status); err != nil {
  73. json.BadRequest(w, err)
  74. return
  75. }
  76. }
  77. order := request.QueryParam(r, "order", model.DefaultSortingOrder)
  78. if err := model.ValidateEntryOrder(order); err != nil {
  79. json.BadRequest(w, err)
  80. return
  81. }
  82. direction := request.QueryParam(r, "direction", model.DefaultSortingDirection)
  83. if err := model.ValidateDirection(direction); err != nil {
  84. json.BadRequest(w, err)
  85. return
  86. }
  87. limit := request.QueryIntParam(r, "limit", 100)
  88. offset := request.QueryIntParam(r, "offset", 0)
  89. if err := model.ValidateRange(offset, limit); err != nil {
  90. json.BadRequest(w, err)
  91. return
  92. }
  93. builder := c.store.NewEntryQueryBuilder(context.New(r).UserID())
  94. builder.WithFeedID(feedID)
  95. builder.WithStatus(status)
  96. builder.WithOrder(order)
  97. builder.WithDirection(direction)
  98. builder.WithOffset(offset)
  99. builder.WithLimit(limit)
  100. configureFilters(builder, r)
  101. entries, err := builder.GetEntries()
  102. if err != nil {
  103. json.ServerError(w, errors.New("Unable to fetch the list of entries"))
  104. return
  105. }
  106. count, err := builder.CountEntries()
  107. if err != nil {
  108. json.ServerError(w, errors.New("Unable to count the number of entries"))
  109. return
  110. }
  111. json.OK(w, r, &entriesResponse{Total: count, Entries: entries})
  112. }
  113. // GetEntries is the API handler to fetch entries.
  114. func (c *Controller) GetEntries(w http.ResponseWriter, r *http.Request) {
  115. status := request.QueryParam(r, "status", "")
  116. if status != "" {
  117. if err := model.ValidateEntryStatus(status); err != nil {
  118. json.BadRequest(w, err)
  119. return
  120. }
  121. }
  122. order := request.QueryParam(r, "order", model.DefaultSortingOrder)
  123. if err := model.ValidateEntryOrder(order); err != nil {
  124. json.BadRequest(w, err)
  125. return
  126. }
  127. direction := request.QueryParam(r, "direction", model.DefaultSortingDirection)
  128. if err := model.ValidateDirection(direction); err != nil {
  129. json.BadRequest(w, err)
  130. return
  131. }
  132. limit := request.QueryIntParam(r, "limit", 100)
  133. offset := request.QueryIntParam(r, "offset", 0)
  134. if err := model.ValidateRange(offset, limit); err != nil {
  135. json.BadRequest(w, err)
  136. return
  137. }
  138. builder := c.store.NewEntryQueryBuilder(context.New(r).UserID())
  139. builder.WithStatus(status)
  140. builder.WithOrder(order)
  141. builder.WithDirection(direction)
  142. builder.WithOffset(offset)
  143. builder.WithLimit(limit)
  144. configureFilters(builder, r)
  145. entries, err := builder.GetEntries()
  146. if err != nil {
  147. json.ServerError(w, errors.New("Unable to fetch the list of entries"))
  148. return
  149. }
  150. count, err := builder.CountEntries()
  151. if err != nil {
  152. json.ServerError(w, errors.New("Unable to count the number of entries"))
  153. return
  154. }
  155. json.OK(w, r, &entriesResponse{Total: count, Entries: entries})
  156. }
  157. // SetEntryStatus is the API handler to change the status of entries.
  158. func (c *Controller) SetEntryStatus(w http.ResponseWriter, r *http.Request) {
  159. entryIDs, status, err := decodeEntryStatusPayload(r.Body)
  160. if err != nil {
  161. json.BadRequest(w, errors.New("Invalid JSON payload"))
  162. return
  163. }
  164. if err := model.ValidateEntryStatus(status); err != nil {
  165. json.BadRequest(w, err)
  166. return
  167. }
  168. if err := c.store.SetEntriesStatus(context.New(r).UserID(), entryIDs, status); err != nil {
  169. json.ServerError(w, errors.New("Unable to change entries status"))
  170. return
  171. }
  172. json.NoContent(w)
  173. }
  174. // ToggleBookmark is the API handler to toggle bookmark status.
  175. func (c *Controller) ToggleBookmark(w http.ResponseWriter, r *http.Request) {
  176. entryID, err := request.IntParam(r, "entryID")
  177. if err != nil {
  178. json.BadRequest(w, err)
  179. return
  180. }
  181. if err := c.store.ToggleBookmark(context.New(r).UserID(), entryID); err != nil {
  182. json.ServerError(w, errors.New("Unable to toggle bookmark value"))
  183. return
  184. }
  185. json.NoContent(w)
  186. }
  187. func configureFilters(builder *storage.EntryQueryBuilder, r *http.Request) {
  188. beforeEntryID := request.QueryInt64Param(r, "before_entry_id", 0)
  189. if beforeEntryID != 0 {
  190. builder.BeforeEntryID(beforeEntryID)
  191. }
  192. afterEntryID := request.QueryInt64Param(r, "after_entry_id", 0)
  193. if afterEntryID != 0 {
  194. builder.AfterEntryID(afterEntryID)
  195. }
  196. beforeTimestamp := request.QueryInt64Param(r, "before", 0)
  197. if beforeTimestamp != 0 {
  198. builder.BeforeDate(time.Unix(beforeTimestamp, 0))
  199. }
  200. afterTimestamp := request.QueryInt64Param(r, "after", 0)
  201. if afterTimestamp != 0 {
  202. builder.AfterDate(time.Unix(afterTimestamp, 0))
  203. }
  204. if request.HasQueryParam(r, "starred") {
  205. builder.WithStarred()
  206. }
  207. searchQuery := request.QueryParam(r, "search", "")
  208. if searchQuery != "" {
  209. builder.WithSearchQuery(searchQuery)
  210. }
  211. }