wip: Add user entries status

This commit is contained in:
2024-05-05 18:43:00 +02:00
parent ac5e85da12
commit 88a859a88b
4 changed files with 142 additions and 22 deletions

View File

@@ -1,11 +1,57 @@
package main
import (
"net/http"
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"github.com/zoriya/vex"
)
type ChangeEntryStatusDto struct {
Id uuid.UUID `json:"id" validate:"required"`
IsRead bool `json:"isRead"`
IsBookmarked bool `json:"isBookmarked"`
IsReadLater bool `json:"isReadLater"`
IsIgnored bool `json:"isIgnored"`
}
func (h *Handler) GetEntries(c echo.Context) error {
ret, err := h.entries.ListEntries()
user, err := GetCurrentUserId(c)
if err != nil {
return err
}
ret, err := h.entries.ListEntries(user)
if err != nil {
return err
}
return c.JSON(200, ret)
}
func (h *Handler) ChangeUserStatus(c echo.Context) error {
user, err := GetCurrentUserId(c)
if err != nil {
return err
}
var req ChangeEntryStatusDto
err = c.Bind(&req)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
if err = c.Validate(&req); err != nil {
return err
}
h.entries.ChangeStatus(vex.ChangeStatusDao{
Id: req.Id,
User: user,
IsRead: req.IsRead,
IsBookmarked: req.IsBookmarked,
IsReadLater: req.IsReadLater,
IsIgnored: req.IsIgnored,
})
ret, err := h.entries.GetEntry(req.Id, user)
if err != nil {
return err
}
@@ -13,5 +59,6 @@ func (h *Handler) GetEntries(c echo.Context) error {
}
func (h *Handler) RegisterEntriesRoutes(e *echo.Echo, r *echo.Group) {
e.GET("/entries", h.GetEntries)
r.GET("/entries", h.GetEntries)
r.PATCH("/entries", h.ChangeUserStatus)
}

View File

@@ -9,14 +9,18 @@ import (
)
type Entry struct {
Id uuid.UUID `json:"id"`
Title string `json:"title"`
Link string `json:"link"`
Date time.Time `json:"date"`
Content string `json:"content"`
Authors []string `json:"authors"`
FeedId uuid.UUID `json:"feedId"`
Feed Feed `json:"feed,omitempty"`
Id uuid.UUID `json:"id"`
Title string `json:"title"`
Link string `json:"link"`
Date time.Time `json:"date"`
Content string `json:"content"`
Authors []string `json:"authors"`
FeedId uuid.UUID `json:"feedId"`
Feed Feed `json:"feed,omitempty"`
IsRead bool `json:"isRead"`
IsBookmarked bool `json:"isBookmarked"`
IsReadLater bool `json:"isReadLater"`
IsIgnored bool `json:"isIgnored"`
}
type EntryDao struct {
@@ -28,18 +32,37 @@ type EntryDao struct {
Authors pq.StringArray
FeedId uuid.UUID `db:"feed_id"`
Feed FeedDao `db:"feed"`
EntryId *uuid.UUID `db:"entry_id"`
UserId *uuid.UUID `db:"user_id"`
IsRead *bool `db:"is_read"`
IsBookmarked *bool `db:"is_bookmarked"`
IsReadLater *bool `db:"is_read_later"`
IsIgnored *bool `db:"is_ignored"`
}
func OrDefault[T any](val *T) T {
if val != nil {
return *val
}
var ret T
return ret
}
func (e *EntryDao) ToEntry() Entry {
return Entry{
Id: e.Id,
Title: e.Title,
Link: e.Link,
Date: e.Date,
Content: e.Content,
Authors: e.Authors,
FeedId: e.FeedId,
Feed: e.Feed.ToFeed(),
Id: e.Id,
Title: e.Title,
Link: e.Link,
Date: e.Date,
Content: e.Content,
Authors: e.Authors,
FeedId: e.FeedId,
Feed: e.Feed.ToFeed(),
IsRead: OrDefault(e.IsRead),
IsBookmarked: OrDefault(e.IsBookmarked),
IsReadLater: OrDefault(e.IsReadLater),
IsIgnored: OrDefault(e.IsIgnored),
}
}
@@ -60,18 +83,60 @@ func (s EntryService) Add(entries []EntryDao) error {
return err
}
func (s EntryService) ListEntries() ([]Entry, error) {
func (s EntryService) GetEntry(id uuid.UUID, userId uuid.UUID) (Entry, error) {
var ret EntryDao
err := s.database.Select(
&ret,
`select e.*, s.*,
f.id as "feed.id", f.name as "feed.name", f.link as "feed.link", f.favicon_url as "feed.favicon_url",
f.tags as "feed.tags", f.submitter_id as "feed.submitter_id", f.added_date as "feed.added_date"
from entries as e
left join entries_users as s on s.entry_id = e.id and s.user_id = $1
left join feeds as f on f.id = e.feed_id
where e.id = $2`,
userId,
id,
)
if err != nil {
return Entry{}, err
}
return ret.ToEntry(), nil
}
func (s EntryService) ListEntries(userId uuid.UUID) ([]Entry, error) {
ret := []EntryDao{}
err := s.database.Select(
&ret,
`select e.*, f.id as "feed.id", f.name as "feed.name", f.link as "feed.link", f.favicon_url as "feed.favicon_url",
`select e.*, s.*,
f.id as "feed.id", f.name as "feed.name", f.link as "feed.link", f.favicon_url as "feed.favicon_url",
f.tags as "feed.tags", f.submitter_id as "feed.submitter_id", f.added_date as "feed.added_date"
from entries as e
left join entries_users as s on s.entry_id = e.id and s.user_id = $1
left join feeds as f on f.id = e.feed_id
order by e.date`,
order by e.date desc`,
userId,
)
if err != nil {
return nil, err
}
return Map(ret, func(e EntryDao, _ int) Entry { return e.ToEntry() }), nil
}
type ChangeStatusDao struct {
Id uuid.UUID
User uuid.UUID
IsRead bool `db:"is_read"`
IsBookmarked bool `db:"is_bookmarked"`
IsReadLater bool `db:"is_read_later"`
IsIgnored bool `db:"is_ignored"`
}
func (s EntryService) ChangeStatus(status ChangeStatusDao) error {
_, err := s.database.NamedExec(
`insert into entries_users (entry_id, user_id, is_read, is_bookmared, is_read_later, is_ignored)
values (:id, :user, :is_read, :is_bookmared, :is_read_later, :is_ignored)
on conflict(entry_id, user_id) do update set is_read = :is_read, is_bookmarked = :is_bookmarked, is_read_later = :is_read_later, is_ignored = :is_ignored`,
status,
)
return err
}

View File

@@ -104,6 +104,7 @@ func (s FeedService) AddFeed(feed Feed) (Feed, error) {
if err != nil {
return Feed{}, err
}
return feed, nil
}

View File

@@ -30,11 +30,18 @@ create table if not exists entries(
create table if not exists entries_users(
user_id uuid not null references users(id),
feed_id uuid not null references feeds(id),
entry_id uuid not null references entries(id),
is_read bool not null,
is_bookmarked bool not null,
is_read_later bool not null,
is_ignored bool not null,
constraint entries_users_pk primary key (user_id, entry_id)
);
create table if not exists feeds_users(
user_id uuid not null references users(id),
feed_id uuid not null references feeds(id),
is_ignored bool not null,
constraint entries_users_pk primary key (user_id, feed_id)
);