feed.go 5.5 KB

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