From 058c517b3b61cb9d1902599947bd7889ce1fe932 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 5 May 2024 13:17:28 +0200 Subject: [PATCH] Parse rss headers before saving to db --- api/cmd/feeds.go | 13 ++++++- api/feeds.go | 79 +++++++++++++++++++++++++++++------------- docker-compose.dev.yml | 2 ++ shell.nix | 1 + 4 files changed, 69 insertions(+), 26 deletions(-) diff --git a/api/cmd/feeds.go b/api/cmd/feeds.go index 9db4800..ed9e7bb 100644 --- a/api/cmd/feeds.go +++ b/api/cmd/feeds.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "log" "net/http" @@ -35,7 +36,17 @@ func (h *Handler) AddFeed(c echo.Context) error { return err } - feed, err := h.feeds.AddFeed(req.Link, req.Tags, user) + feeds, err := h.feeds.GetFeedData(req.Link) + if err != nil { + return echo.NewHTTPError(400, fmt.Sprintf("Invalid feed link: %v", err)) + } + if len(feeds) != 1 { + return c.JSON(409, feeds) + } + feed := feeds[0] + feed.SubmitterId = user + feed.Tags = req.Tags + feed, err = h.feeds.AddFeed(feed) if err != nil { log.Printf("Add feed error: %v", err) return echo.NewHTTPError(500, "internal server error") diff --git a/api/feeds.go b/api/feeds.go index d21edb9..3724a62 100644 --- a/api/feeds.go +++ b/api/feeds.go @@ -1,6 +1,8 @@ package vex import ( + "fmt" + "net/http" "time" "github.com/google/uuid" @@ -15,26 +17,41 @@ type Feed struct { FaviconUrl string `json:"faviconUrl"` Tags []string `json:"tags"` SubmitterId uuid.UUID `json:"submitterId"` - Submitter User `json:"submitter,omitempty"` + Submitter *User `json:"submitter,omitempty"` AddedDate time.Time `json:"addedDate"` } type FeedDao struct { - Id uuid.UUID - Name string - Link string - FaviconUrl string `db:"favicon_url"` - Tags pq.StringArray - SubmitterId uuid.UUID `db:"submitter_id"` - Submitter User `db:"submitter"` - AddedDate time.Time `db:"added_date"` + Id uuid.UUID + Name string + Link string + FaviconUrl string `db:"favicon_url"` + Tags pq.StringArray + SubmitterId uuid.UUID `db:"submitter_id"` + Submitter *User `db:"submitter"` + AddedDate time.Time `db:"added_date"` + Etag string + LastFetchDate *time.Time `db:"last_fetch_date"` } func (f *FeedDao) ToFeed() Feed { return Feed{ Id: f.Id, Name: f.Name, - Link: f.Name, + Link: f.Link, + FaviconUrl: f.FaviconUrl, + Tags: f.Tags, + SubmitterId: f.SubmitterId, + Submitter: f.Submitter, + AddedDate: f.AddedDate, + } +} + +func (f *Feed) ToDao() FeedDao { + return FeedDao{ + Id: f.Id, + Name: f.Name, + Link: f.Link, FaviconUrl: f.FaviconUrl, Tags: f.Tags, SubmitterId: f.SubmitterId, @@ -45,39 +62,51 @@ func (f *FeedDao) ToFeed() Feed { type FeedService struct { database *sqlx.DB + reader Reader } func NewFeedService(db *sqlx.DB) FeedService { - return FeedService{database: db} + return FeedService{ + database: db, + reader: NewRssReader(http.DefaultClient), + } } -func (s FeedService) AddFeed(link string, tags []string, submitter uuid.UUID) (Feed, error) { - feed := FeedDao{ - Id: uuid.New(), - Name: link, - Link: link, - FaviconUrl: link, - Tags: tags, - SubmitterId: submitter, +func (s FeedService) GetFeedData(link string) ([]Feed, error) { + parsed, err := s.reader.ReadFeed(link, "", nil) + if err != nil { + return nil, err } + return []Feed{ + { + Id: uuid.New(), + Name: parsed.Title, + Link: link, + FaviconUrl: fmt.Sprintf("%s/favicon.ico", parsed.Link), + AddedDate: time.Now(), + }, + }, nil +} +func (s FeedService) AddFeed(feed Feed) (Feed, error) { _, err := s.database.NamedExec( - `insert into feeds (id, name, link, favicon_url, tags, submitter_id, added_date) - values (:id, :name, :link, :favicon_url, :tags, :submitter_id, :added_date)`, - feed, + `insert into feeds (id, name, link, favicon_url, tags, submitter_id, added_date, etag, last_fetch_date) + values (:id, :name, :link, :favicon_url, :tags, :submitter_id, :added_date, :etag, :last_fetch_date)`, + feed.ToDao(), ) if err != nil { return Feed{}, err } - return feed.ToFeed(), nil + return feed, nil } func (s FeedService) ListFeeds() ([]Feed, error) { ret := []FeedDao{} err := s.database.Select( &ret, - `select f.*, u.id as "submitter.id", u.name as "submitter.name", u.email as "submitter.email", u.password as "submitter.password" from feeds - as f left join users as u on u.id = f.submitter_id + `select f.*, u.id as "submitter.id", u.name as "submitter.name", u.email as "submitter.email", u.password as "submitter.password" + from feeds as f left + join users as u on u.id = f.submitter_id order by added_date`, ) if err != nil { diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 1e38f4d..124215d 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -19,6 +19,8 @@ services: restart: on-failure env_file: - ./.env + ports: + - "5432:5432" volumes: - db:/var/lib/postgresql/data - ./sql/create.sql:/docker-entrypoint-initdb.d/init.sql diff --git a/shell.nix b/shell.nix index 85e1042..380f1cc 100644 --- a/shell.nix +++ b/shell.nix @@ -4,5 +4,6 @@ go wgo pgformatter + postgresql ]; }