aboutsummaryrefslogtreecommitdiffhomepage
path: root/storage/feed.go
diff options
context:
space:
mode:
Diffstat (limited to 'storage/feed.go')
-rw-r--r--storage/feed.go223
1 files changed, 223 insertions, 0 deletions
diff --git a/storage/feed.go b/storage/feed.go
new file mode 100644
index 0000000..ec08580
--- /dev/null
+++ b/storage/feed.go
@@ -0,0 +1,223 @@
+// Copyright 2017 Frédéric Guillot. All rights reserved.
+// Use of this source code is governed by the Apache 2.0
+// license that can be found in the LICENSE file.
+
+package storage
+
+import (
+ "database/sql"
+ "errors"
+ "fmt"
+ "github.com/miniflux/miniflux2/helper"
+ "github.com/miniflux/miniflux2/model"
+ "time"
+)
+
+func (s *Storage) FeedExists(userID, feedID int64) bool {
+ defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:FeedExists] userID=%d, feedID=%d", userID, feedID))
+
+ var result int
+ query := `SELECT count(*) as c FROM feeds WHERE user_id=$1 AND id=$2`
+ s.db.QueryRow(query, userID, feedID).Scan(&result)
+ return result >= 1
+}
+
+func (s *Storage) FeedURLExists(userID int64, feedURL string) bool {
+ defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:FeedURLExists] userID=%d, feedURL=%s", userID, feedURL))
+
+ var result int
+ query := `SELECT count(*) as c FROM feeds WHERE user_id=$1 AND feed_url=$2`
+ s.db.QueryRow(query, userID, feedURL).Scan(&result)
+ return result >= 1
+}
+
+func (s *Storage) GetFeeds(userID int64) (model.Feeds, error) {
+ defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetFeeds] userID=%d", userID))
+
+ feeds := make(model.Feeds, 0)
+ query := `SELECT
+ f.id, f.feed_url, f.site_url, f.title, f.etag_header, f.last_modified_header,
+ f.user_id, f.checked_at, f.parsing_error_count, f.parsing_error_msg,
+ f.category_id, c.title as category_title,
+ fi.icon_id
+ FROM feeds f
+ LEFT JOIN categories c ON c.id=f.category_id
+ LEFT JOIN feed_icons fi ON fi.feed_id=f.id
+ WHERE f.user_id=$1
+ ORDER BY f.id ASC`
+
+ rows, err := s.db.Query(query, userID)
+ if err != nil {
+ return nil, fmt.Errorf("Unable to fetch feeds: %v", err)
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var feed model.Feed
+ var iconID, errorMsg interface{}
+ feed.Category = &model.Category{UserID: userID}
+ feed.Icon = &model.FeedIcon{}
+
+ err := rows.Scan(
+ &feed.ID,
+ &feed.FeedURL,
+ &feed.SiteURL,
+ &feed.Title,
+ &feed.EtagHeader,
+ &feed.LastModifiedHeader,
+ &feed.UserID,
+ &feed.CheckedAt,
+ &feed.ParsingErrorCount,
+ &errorMsg,
+ &feed.Category.ID,
+ &feed.Category.Title,
+ &iconID,
+ )
+
+ if err != nil {
+ return nil, fmt.Errorf("Unable to fetch feeds row: %v", err)
+ }
+
+ if iconID == nil {
+ feed.Icon.IconID = 0
+ } else {
+ feed.Icon.IconID = iconID.(int64)
+ }
+
+ if errorMsg == nil {
+ feed.ParsingErrorMsg = ""
+ } else {
+ feed.ParsingErrorMsg = errorMsg.(string)
+ }
+
+ feed.Icon.FeedID = feed.ID
+ feeds = append(feeds, &feed)
+ }
+
+ return feeds, nil
+}
+
+func (s *Storage) GetFeedById(userID, feedID int64) (*model.Feed, error) {
+ defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:GetFeedById] feedID=%d", feedID))
+
+ var feed model.Feed
+ feed.Category = &model.Category{UserID: userID}
+
+ query := `
+ SELECT
+ f.id, f.feed_url, f.site_url, f.title, f.etag_header, f.last_modified_header,
+ f.user_id, f.checked_at, f.parsing_error_count, f.parsing_error_msg,
+ f.category_id, c.title as category_title
+ FROM feeds f
+ LEFT JOIN categories c ON c.id=f.category_id
+ WHERE f.user_id=$1 AND f.id=$2`
+
+ err := s.db.QueryRow(query, userID, feedID).Scan(
+ &feed.ID,
+ &feed.FeedURL,
+ &feed.SiteURL,
+ &feed.Title,
+ &feed.EtagHeader,
+ &feed.LastModifiedHeader,
+ &feed.UserID,
+ &feed.CheckedAt,
+ &feed.ParsingErrorCount,
+ &feed.ParsingErrorMsg,
+ &feed.Category.ID,
+ &feed.Category.Title,
+ )
+
+ switch {
+ case err == sql.ErrNoRows:
+ return nil, nil
+ case err != nil:
+ return nil, fmt.Errorf("Unable to fetch feed: %v", err)
+ }
+
+ return &feed, nil
+}
+
+func (s *Storage) CreateFeed(feed *model.Feed) error {
+ defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:CreateFeed] feedURL=%s", feed.FeedURL))
+ sql := `
+ INSERT INTO feeds
+ (feed_url, site_url, title, category_id, user_id, etag_header, last_modified_header)
+ VALUES ($1, $2, $3, $4, $5, $6, $7)
+ RETURNING id
+ `
+
+ err := s.db.QueryRow(
+ sql,
+ feed.FeedURL,
+ feed.SiteURL,
+ feed.Title,
+ feed.Category.ID,
+ feed.UserID,
+ feed.EtagHeader,
+ feed.LastModifiedHeader,
+ ).Scan(&feed.ID)
+
+ if err != nil {
+ return fmt.Errorf("Unable to create feed: %v", err)
+ }
+
+ for i := 0; i < len(feed.Entries); i++ {
+ feed.Entries[i].FeedID = feed.ID
+ feed.Entries[i].UserID = feed.UserID
+ err := s.CreateEntry(feed.Entries[i])
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (s *Storage) UpdateFeed(feed *model.Feed) (err error) {
+ defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:UpdateFeed] feedURL=%s", feed.FeedURL))
+
+ query := `UPDATE feeds SET
+ feed_url=$1, site_url=$2, title=$3, category_id=$4, etag_header=$5, last_modified_header=$6, checked_at=$7,
+ parsing_error_msg=$8, parsing_error_count=$9
+ WHERE id=$10 AND user_id=$11`
+
+ _, err = s.db.Exec(query,
+ feed.FeedURL,
+ feed.SiteURL,
+ feed.Title,
+ feed.Category.ID,
+ feed.EtagHeader,
+ feed.LastModifiedHeader,
+ feed.CheckedAt,
+ feed.ParsingErrorMsg,
+ feed.ParsingErrorCount,
+ feed.ID,
+ feed.UserID,
+ )
+
+ if err != nil {
+ return fmt.Errorf("Unable to update feed: %v", err)
+ }
+
+ return nil
+}
+
+func (s *Storage) RemoveFeed(userID, feedID int64) error {
+ defer helper.ExecutionTime(time.Now(), fmt.Sprintf("[Storage:RemoveFeed] userID=%d, feedID=%d", userID, feedID))
+
+ result, err := s.db.Exec("DELETE FROM feeds WHERE id = $1 AND user_id = $2", feedID, userID)
+ if err != nil {
+ return fmt.Errorf("Unable to remove this feed: %v", err)
+ }
+
+ count, err := result.RowsAffected()
+ if err != nil {
+ return fmt.Errorf("Unable to remove this feed: %v", err)
+ }
+
+ if count == 0 {
+ return errors.New("no feed has been removed")
+ }
+
+ return nil
+}