aboutsummaryrefslogtreecommitdiffhomepage
path: root/backend/api/handler_feeds.go
diff options
context:
space:
mode:
Diffstat (limited to 'backend/api/handler_feeds.go')
-rw-r--r--backend/api/handler_feeds.go185
1 files changed, 185 insertions, 0 deletions
diff --git a/backend/api/handler_feeds.go b/backend/api/handler_feeds.go
new file mode 100644
index 0000000..f0a8785
--- /dev/null
+++ b/backend/api/handler_feeds.go
@@ -0,0 +1,185 @@
+package api
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "strconv"
+ "time"
+
+ appcontext "undef.ninja/x/feedaka/context"
+ "undef.ninja/x/feedaka/db"
+ "undef.ninja/x/feedaka/feed"
+)
+
+func (h *Handler) FeedsListFeeds(ctx context.Context, _ FeedsListFeedsRequestObject) (FeedsListFeedsResponseObject, error) {
+ userID, ok := appcontext.GetUserID(ctx)
+ if !ok {
+ return nil, fmt.Errorf("authentication required")
+ }
+
+ dbFeeds, err := h.Queries.GetFeeds(ctx, userID)
+ if err != nil {
+ return nil, err
+ }
+
+ unreadCounts, err := h.Queries.GetFeedUnreadCounts(ctx, userID)
+ if err != nil {
+ return nil, err
+ }
+ countMap := make(map[int64]int64, len(unreadCounts))
+ for _, uc := range unreadCounts {
+ countMap[uc.FeedID] = uc.UnreadCount
+ }
+
+ feeds := make(FeedsListFeeds200JSONResponse, 0, len(dbFeeds))
+ for _, f := range dbFeeds {
+ feeds = append(feeds, dbFeedToAPI(f, countMap[f.ID]))
+ }
+
+ return feeds, nil
+}
+
+func (h *Handler) FeedsAddFeed(ctx context.Context, request FeedsAddFeedRequestObject) (FeedsAddFeedResponseObject, error) {
+ userID, ok := appcontext.GetUserID(ctx)
+ if !ok {
+ return nil, fmt.Errorf("authentication required")
+ }
+
+ f, err := feed.Fetch(ctx, request.Body.Url)
+ if err != nil {
+ return FeedsAddFeed400JSONResponse{Message: fmt.Sprintf("failed to parse feed: %v", err)}, nil
+ }
+
+ dbFeed, err := h.Queries.CreateFeed(ctx, db.CreateFeedParams{
+ Url: request.Body.Url,
+ Title: f.Title,
+ FetchedAt: time.Now().UTC().Format(time.RFC3339),
+ UserID: userID,
+ })
+ if err != nil {
+ return FeedsAddFeed400JSONResponse{Message: fmt.Sprintf("failed to insert feed: %v", err)}, nil
+ }
+
+ if err := feed.Sync(ctx, h.Queries, dbFeed.ID, f); err != nil {
+ return FeedsAddFeed400JSONResponse{Message: fmt.Sprintf("failed to sync articles: %v", err)}, nil
+ }
+
+ return FeedsAddFeed201JSONResponse(dbFeedToAPI(dbFeed, 0)), nil
+}
+
+func (h *Handler) FeedsGetFeed(ctx context.Context, request FeedsGetFeedRequestObject) (FeedsGetFeedResponseObject, error) {
+ userID, ok := appcontext.GetUserID(ctx)
+ if !ok {
+ return nil, fmt.Errorf("authentication required")
+ }
+
+ feedID, err := strconv.ParseInt(request.FeedId, 10, 64)
+ if err != nil {
+ return FeedsGetFeed404JSONResponse{Message: "invalid feed ID"}, nil
+ }
+
+ dbFeed, err := h.Queries.GetFeed(ctx, feedID)
+ if err != nil {
+ if err == sql.ErrNoRows {
+ return FeedsGetFeed404JSONResponse{Message: "feed not found"}, nil
+ }
+ return nil, err
+ }
+
+ if dbFeed.UserID != userID {
+ return FeedsGetFeed404JSONResponse{Message: "feed not found"}, nil
+ }
+
+ return FeedsGetFeed200JSONResponse(dbFeedToAPI(dbFeed, 0)), nil
+}
+
+func (h *Handler) FeedsUnsubscribeFeed(ctx context.Context, request FeedsUnsubscribeFeedRequestObject) (FeedsUnsubscribeFeedResponseObject, error) {
+ userID, ok := appcontext.GetUserID(ctx)
+ if !ok {
+ return nil, fmt.Errorf("authentication required")
+ }
+
+ feedID, err := strconv.ParseInt(request.FeedId, 10, 64)
+ if err != nil {
+ return FeedsUnsubscribeFeed404JSONResponse{Message: "invalid feed ID"}, nil
+ }
+
+ dbFeed, err := h.Queries.GetFeed(ctx, feedID)
+ if err != nil {
+ if err == sql.ErrNoRows {
+ return FeedsUnsubscribeFeed404JSONResponse{Message: "feed not found"}, nil
+ }
+ return nil, err
+ }
+
+ if dbFeed.UserID != userID {
+ return FeedsUnsubscribeFeed404JSONResponse{Message: "feed not found"}, nil
+ }
+
+ if err := h.Queries.UnsubscribeFeed(ctx, feedID); err != nil {
+ return nil, err
+ }
+
+ return FeedsUnsubscribeFeed204Response{}, nil
+}
+
+func (h *Handler) FeedsMarkFeedRead(ctx context.Context, request FeedsMarkFeedReadRequestObject) (FeedsMarkFeedReadResponseObject, error) {
+ userID, ok := appcontext.GetUserID(ctx)
+ if !ok {
+ return nil, fmt.Errorf("authentication required")
+ }
+
+ feedID, err := strconv.ParseInt(request.FeedId, 10, 64)
+ if err != nil {
+ return FeedsMarkFeedRead404JSONResponse{Message: "invalid feed ID"}, nil
+ }
+
+ dbFeed, err := h.Queries.GetFeed(ctx, feedID)
+ if err != nil {
+ if err == sql.ErrNoRows {
+ return FeedsMarkFeedRead404JSONResponse{Message: "feed not found"}, nil
+ }
+ return nil, err
+ }
+
+ if dbFeed.UserID != userID {
+ return FeedsMarkFeedRead404JSONResponse{Message: "feed not found"}, nil
+ }
+
+ if err := h.Queries.MarkFeedArticlesRead(ctx, feedID); err != nil {
+ return nil, err
+ }
+
+ return FeedsMarkFeedRead200JSONResponse(dbFeedToAPI(dbFeed, 0)), nil
+}
+
+func (h *Handler) FeedsMarkFeedUnread(ctx context.Context, request FeedsMarkFeedUnreadRequestObject) (FeedsMarkFeedUnreadResponseObject, error) {
+ userID, ok := appcontext.GetUserID(ctx)
+ if !ok {
+ return nil, fmt.Errorf("authentication required")
+ }
+
+ feedID, err := strconv.ParseInt(request.FeedId, 10, 64)
+ if err != nil {
+ return FeedsMarkFeedUnread404JSONResponse{Message: "invalid feed ID"}, nil
+ }
+
+ dbFeed, err := h.Queries.GetFeed(ctx, feedID)
+ if err != nil {
+ if err == sql.ErrNoRows {
+ return FeedsMarkFeedUnread404JSONResponse{Message: "feed not found"}, nil
+ }
+ return nil, err
+ }
+
+ if dbFeed.UserID != userID {
+ return FeedsMarkFeedUnread404JSONResponse{Message: "feed not found"}, nil
+ }
+
+ if err := h.Queries.MarkFeedArticlesUnread(ctx, feedID); err != nil {
+ return nil, err
+ }
+
+ return FeedsMarkFeedUnread200JSONResponse(dbFeedToAPI(dbFeed, 0)), nil
+}