feed.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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 storage
  5. import (
  6. "database/sql"
  7. "errors"
  8. "fmt"
  9. "time"
  10. "github.com/miniflux/miniflux2/helper"
  11. "github.com/miniflux/miniflux2/model"
  12. )
  13. func (s *Storage) FeedExists(userID, feedID int64) bool {
  14. defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:FeedExists] userID=%d, feedID=%d", userID, feedID))
  15. var result int
  16. query := `SELECT count(*) as c FROM feeds WHERE user_id=$1 AND id=$2`
  17. s.db.QueryRow(query, userID, feedID).Scan(&result)
  18. return result >= 1
  19. }
  20. func (s *Storage) FeedURLExists(userID int64, feedURL string) bool {
  21. defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:FeedURLExists] userID=%d, feedURL=%s", userID, feedURL))
  22. var result int
  23. query := `SELECT count(*) as c FROM feeds WHERE user_id=$1 AND feed_url=$2`
  24. s.db.QueryRow(query, userID, feedURL).Scan(&result)
  25. return result >= 1
  26. }
  27. // CountFeeds returns the number of feeds that belongs to the given user.
  28. func (s *Storage) CountFeeds(userID int64) int {
  29. var result int
  30. err := s.db.QueryRow(`SELECT count(*) FROM feeds WHERE user_id=$1`, userID).Scan(&result)
  31. if err != nil {
  32. return 0
  33. }
  34. return result
  35. }
  36. func (s *Storage) GetFeeds(userID int64) (model.Feeds, error) {
  37. defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetFeeds] userID=%d", userID))
  38. feeds := make(model.Feeds, 0)
  39. query := `SELECT
  40. f.id, f.feed_url, f.site_url, f.title, f.etag_header, f.last_modified_header,
  41. f.user_id, f.checked_at, f.parsing_error_count, f.parsing_error_msg,
  42. f.category_id, c.title as category_title,
  43. fi.icon_id
  44. FROM feeds f
  45. LEFT JOIN categories c ON c.id=f.category_id
  46. LEFT JOIN feed_icons fi ON fi.feed_id=f.id
  47. WHERE f.user_id=$1
  48. ORDER BY f.id ASC`
  49. rows, err := s.db.Query(query, userID)
  50. if err != nil {
  51. return nil, fmt.Errorf("Unable to fetch feeds: %v", err)
  52. }
  53. defer rows.Close()
  54. for rows.Next() {
  55. var feed model.Feed
  56. var iconID, errorMsg interface{}
  57. feed.Category = &model.Category{UserID: userID}
  58. feed.Icon = &model.FeedIcon{}
  59. err := rows.Scan(
  60. &feed.ID,
  61. &feed.FeedURL,
  62. &feed.SiteURL,
  63. &feed.Title,
  64. &feed.EtagHeader,
  65. &feed.LastModifiedHeader,
  66. &feed.UserID,
  67. &feed.CheckedAt,
  68. &feed.ParsingErrorCount,
  69. &errorMsg,
  70. &feed.Category.ID,
  71. &feed.Category.Title,
  72. &iconID,
  73. )
  74. if err != nil {
  75. return nil, fmt.Errorf("Unable to fetch feeds row: %v", err)
  76. }
  77. if iconID == nil {
  78. feed.Icon.IconID = 0
  79. } else {
  80. feed.Icon.IconID = iconID.(int64)
  81. }
  82. if errorMsg == nil {
  83. feed.ParsingErrorMsg = ""
  84. } else {
  85. feed.ParsingErrorMsg = errorMsg.(string)
  86. }
  87. feed.Icon.FeedID = feed.ID
  88. feeds = append(feeds, &feed)
  89. }
  90. return feeds, nil
  91. }
  92. func (s *Storage) GetFeedById(userID, feedID int64) (*model.Feed, error) {
  93. defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetFeedById] feedID=%d", feedID))
  94. var feed model.Feed
  95. feed.Category = &model.Category{UserID: userID}
  96. query := `
  97. SELECT
  98. f.id, f.feed_url, f.site_url, f.title, f.etag_header, f.last_modified_header,
  99. f.user_id, f.checked_at, f.parsing_error_count, f.parsing_error_msg,
  100. f.category_id, c.title as category_title
  101. FROM feeds f
  102. LEFT JOIN categories c ON c.id=f.category_id
  103. WHERE f.user_id=$1 AND f.id=$2`
  104. err := s.db.QueryRow(query, userID, feedID).Scan(
  105. &feed.ID,
  106. &feed.FeedURL,
  107. &feed.SiteURL,
  108. &feed.Title,
  109. &feed.EtagHeader,
  110. &feed.LastModifiedHeader,
  111. &feed.UserID,
  112. &feed.CheckedAt,
  113. &feed.ParsingErrorCount,
  114. &feed.ParsingErrorMsg,
  115. &feed.Category.ID,
  116. &feed.Category.Title,
  117. )
  118. switch {
  119. case err == sql.ErrNoRows:
  120. return nil, nil
  121. case err != nil:
  122. return nil, fmt.Errorf("unable to fetch feed: %v", err)
  123. }
  124. return &feed, nil
  125. }
  126. func (s *Storage) CreateFeed(feed *model.Feed) error {
  127. defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CreateFeed] feedURL=%s", feed.FeedURL))
  128. sql := `
  129. INSERT INTO feeds
  130. (feed_url, site_url, title, category_id, user_id, etag_header, last_modified_header)
  131. VALUES ($1, $2, $3, $4, $5, $6, $7)
  132. RETURNING id
  133. `
  134. err := s.db.QueryRow(
  135. sql,
  136. feed.FeedURL,
  137. feed.SiteURL,
  138. feed.Title,
  139. feed.Category.ID,
  140. feed.UserID,
  141. feed.EtagHeader,
  142. feed.LastModifiedHeader,
  143. ).Scan(&feed.ID)
  144. if err != nil {
  145. return fmt.Errorf("unable to create feed: %v", err)
  146. }
  147. for i := 0; i < len(feed.Entries); i++ {
  148. feed.Entries[i].FeedID = feed.ID
  149. feed.Entries[i].UserID = feed.UserID
  150. err := s.CreateEntry(feed.Entries[i])
  151. if err != nil {
  152. return err
  153. }
  154. }
  155. return nil
  156. }
  157. func (s *Storage) UpdateFeed(feed *model.Feed) (err error) {
  158. defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UpdateFeed] feedURL=%s", feed.FeedURL))
  159. query := `UPDATE feeds SET
  160. feed_url=$1, site_url=$2, title=$3, category_id=$4, etag_header=$5, last_modified_header=$6, checked_at=$7,
  161. parsing_error_msg=$8, parsing_error_count=$9
  162. WHERE id=$10 AND user_id=$11`
  163. _, err = s.db.Exec(query,
  164. feed.FeedURL,
  165. feed.SiteURL,
  166. feed.Title,
  167. feed.Category.ID,
  168. feed.EtagHeader,
  169. feed.LastModifiedHeader,
  170. feed.CheckedAt,
  171. feed.ParsingErrorMsg,
  172. feed.ParsingErrorCount,
  173. feed.ID,
  174. feed.UserID,
  175. )
  176. if err != nil {
  177. return fmt.Errorf("Unable to update feed: %v", err)
  178. }
  179. return nil
  180. }
  181. func (s *Storage) RemoveFeed(userID, feedID int64) error {
  182. defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:RemoveFeed] userID=%d, feedID=%d", userID, feedID))
  183. result, err := s.db.Exec("DELETE FROM feeds WHERE id = $1 AND user_id = $2", feedID, userID)
  184. if err != nil {
  185. return fmt.Errorf("Unable to remove this feed: %v", err)
  186. }
  187. count, err := result.RowsAffected()
  188. if err != nil {
  189. return fmt.Errorf("Unable to remove this feed: %v", err)
  190. }
  191. if count == 0 {
  192. return errors.New("no feed has been removed")
  193. }
  194. return nil
  195. }