diff --git a/api/cmd/feeds.go b/api/cmd/feeds.go index d107587..9db4800 100644 --- a/api/cmd/feeds.go +++ b/api/cmd/feeds.go @@ -12,6 +12,14 @@ type AddFeedDto struct { Tags []string `json:"tags" validate:"required"` } +func (h *Handler) GetFeeds(c echo.Context) error { + ret, err := h.feeds.ListFeeds() + if err != nil { + return err + } + return c.JSON(200, ret) +} + func (h *Handler) AddFeed(c echo.Context) error { user, err := GetCurrentUserId(c) if err != nil { @@ -35,6 +43,7 @@ func (h *Handler) AddFeed(c echo.Context) error { return c.JSON(201, feed) } -func (h *Handler) RegisterFeedsRoutes(echo *echo.Echo, r *echo.Group) { +func (h *Handler) RegisterFeedsRoutes(e *echo.Echo, r *echo.Group) { + e.GET("/feeds", h.GetFeeds) r.POST("/feeds", h.AddFeed) } diff --git a/api/cmd/users.go b/api/cmd/users.go index e1a786a..ce555dd 100644 --- a/api/cmd/users.go +++ b/api/cmd/users.go @@ -20,12 +20,6 @@ type RegisterDto struct { Password string `json:"password" validate:"required"` } -type UserDto struct { - Id uuid.UUID `json:"id"` - Name string `json:"name"` - Email string `json:"email"` -} - func (h *Handler) Login(c echo.Context) error { var req LoginDto err := c.Bind(&req) @@ -86,11 +80,7 @@ func (h *Handler) GetMe(c echo.Context) error { if user == nil { return echo.NewHTTPError(500, "Internal server error") } - return c.JSON(200, UserDto{ - Id: user.Id, - Name: user.Name, - Email: user.Email, - }) + return c.JSON(200, user) } func GetCurrentUserId(c echo.Context) (uuid.UUID, error) { diff --git a/api/feeds.go b/api/feeds.go index 399acfa..d21edb9 100644 --- a/api/feeds.go +++ b/api/feeds.go @@ -1,18 +1,46 @@ package vex import ( + "time" + "github.com/google/uuid" "github.com/jmoiron/sqlx" "github.com/lib/pq" ) type Feed struct { + Id uuid.UUID `json:"id"` + Name string `json:"name"` + Link string `json:"link"` + FaviconUrl string `json:"faviconUrl"` + Tags []string `json:"tags"` + SubmitterId uuid.UUID `json:"submitterId"` + 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"` +} + +func (f *FeedDao) ToFeed() Feed { + return Feed{ + Id: f.Id, + Name: f.Name, + Link: f.Name, + FaviconUrl: f.FaviconUrl, + Tags: f.Tags, + SubmitterId: f.SubmitterId, + Submitter: f.Submitter, + AddedDate: f.AddedDate, + } } type FeedService struct { @@ -24,7 +52,7 @@ func NewFeedService(db *sqlx.DB) FeedService { } func (s FeedService) AddFeed(link string, tags []string, submitter uuid.UUID) (Feed, error) { - feed := Feed{ + feed := FeedDao{ Id: uuid.New(), Name: link, Link: link, @@ -34,12 +62,26 @@ func (s FeedService) AddFeed(link string, tags []string, submitter uuid.UUID) (F } _, err := s.database.NamedExec( - `insert into feeds (id, name, link, favicon_url, tags, submitter_id) - values (:id, :name, :link, :favicon_url, :tags, :submitter_id)`, + `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, ) if err != nil { return Feed{}, err } - return feed, nil + return feed.ToFeed(), 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 + order by added_date`, + ) + if err != nil { + return nil, err + } + return Map(ret, func(f FeedDao, _ int) Feed { return f.ToFeed() }), nil } diff --git a/api/go.mod b/api/go.mod index b144c98..8981023 100644 --- a/api/go.mod +++ b/api/go.mod @@ -4,7 +4,7 @@ go 1.22.1 require ( github.com/go-playground/validator/v10 v10.20.0 - github.com/golang-jwt/jwt v3.2.2+incompatible + github.com/golang-jwt/jwt/v5 v5.0.0 github.com/google/uuid v1.6.0 github.com/jmoiron/sqlx v1.4.0 github.com/labstack/echo-jwt/v4 v4.2.0 @@ -17,7 +17,7 @@ require ( github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/golang-jwt/jwt/v5 v5.0.0 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect diff --git a/api/users.go b/api/users.go index 9092ace..5abfa97 100644 --- a/api/users.go +++ b/api/users.go @@ -7,10 +7,10 @@ import ( ) type User struct { - Id uuid.UUID - Name string - Email string - Password []byte + Id uuid.UUID `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Password []byte `json:"-"` } type UserService struct { diff --git a/api/utils.go b/api/utils.go new file mode 100644 index 0000000..11eab00 --- /dev/null +++ b/api/utils.go @@ -0,0 +1,9 @@ +package vex + +func Map[T, U any](ts []T, f func(T, int) U) []U { + us := make([]U, len(ts)) + for i := range ts { + us[i] = f(ts[i], i) + } + return us +} diff --git a/sql/create.sql b/sql/create.sql index eb16519..7385f7f 100644 --- a/sql/create.sql +++ b/sql/create.sql @@ -11,7 +11,8 @@ create table if not exists feeds( link text not null unique, favicon_url text not null, tags text[] not null, - submitter_id uuid not null references users(id) + submitter_id uuid not null references users(id), + added_date timestamp with time zone not null ); create table if not exists entries(