forked from tangled.org/core
Monorepo for Tangled — https://tangled.org
at master 4.0 kB view raw
1package notifications 2 3import ( 4 "log/slog" 5 "net/http" 6 "strconv" 7 8 "github.com/go-chi/chi/v5" 9 "tangled.org/core/appview/db" 10 "tangled.org/core/appview/middleware" 11 "tangled.org/core/appview/oauth" 12 "tangled.org/core/appview/pages" 13 "tangled.org/core/appview/pagination" 14 "tangled.org/core/orm" 15) 16 17type Notifications struct { 18 db *db.DB 19 oauth *oauth.OAuth 20 pages *pages.Pages 21 logger *slog.Logger 22} 23 24func New(database *db.DB, oauthHandler *oauth.OAuth, pagesHandler *pages.Pages, logger *slog.Logger) *Notifications { 25 return &Notifications{ 26 db: database, 27 oauth: oauthHandler, 28 pages: pagesHandler, 29 logger: logger, 30 } 31} 32 33func (n *Notifications) Router(mw *middleware.Middleware) http.Handler { 34 r := chi.NewRouter() 35 36 r.Get("/count", n.getUnreadCount) 37 38 r.Group(func(r chi.Router) { 39 r.Use(middleware.AuthMiddleware(n.oauth)) 40 r.With(middleware.Paginate).Get("/", n.notificationsPage) 41 r.Post("/{id}/read", n.markRead) 42 r.Post("/read-all", n.markAllRead) 43 r.Delete("/{id}", n.deleteNotification) 44 }) 45 46 return r 47} 48 49func (n *Notifications) notificationsPage(w http.ResponseWriter, r *http.Request) { 50 l := n.logger.With("handler", "notificationsPage") 51 user := n.oauth.GetUser(r) 52 53 page := pagination.FromContext(r.Context()) 54 55 total, err := db.CountNotifications( 56 n.db, 57 orm.FilterEq("recipient_did", user.Did), 58 ) 59 if err != nil { 60 l.Error("failed to get total notifications", "err", err) 61 n.pages.Error500(w) 62 return 63 } 64 65 notifications, err := db.GetNotificationsWithEntities( 66 n.db, 67 page, 68 orm.FilterEq("recipient_did", user.Did), 69 ) 70 if err != nil { 71 l.Error("failed to get notifications", "err", err) 72 n.pages.Error500(w) 73 return 74 } 75 76 err = db.MarkAllNotificationsRead(n.db, user.Did) 77 if err != nil { 78 l.Error("failed to mark notifications as read", "err", err) 79 } 80 81 unreadCount := 0 82 83 n.pages.Notifications(w, pages.NotificationsParams{ 84 LoggedInUser: user, 85 Notifications: notifications, 86 UnreadCount: unreadCount, 87 Page: page, 88 Total: total, 89 }) 90} 91 92func (n *Notifications) getUnreadCount(w http.ResponseWriter, r *http.Request) { 93 user := n.oauth.GetUser(r) 94 if user == nil { 95 return 96 } 97 98 count, err := db.CountNotifications( 99 n.db, 100 orm.FilterEq("recipient_did", user.Did), 101 orm.FilterEq("read", 0), 102 ) 103 if err != nil { 104 http.Error(w, "Failed to get unread count", http.StatusInternalServerError) 105 return 106 } 107 108 params := pages.NotificationCountParams{ 109 Count: count, 110 } 111 err = n.pages.NotificationCount(w, params) 112 if err != nil { 113 http.Error(w, "Failed to render count", http.StatusInternalServerError) 114 return 115 } 116} 117 118func (n *Notifications) markRead(w http.ResponseWriter, r *http.Request) { 119 userDid := n.oauth.GetDid(r) 120 121 idStr := chi.URLParam(r, "id") 122 notificationID, err := strconv.ParseInt(idStr, 10, 64) 123 if err != nil { 124 http.Error(w, "Invalid notification ID", http.StatusBadRequest) 125 return 126 } 127 128 err = db.MarkNotificationRead(n.db, notificationID, userDid) 129 if err != nil { 130 http.Error(w, "Failed to mark notification as read", http.StatusInternalServerError) 131 return 132 } 133 134 w.WriteHeader(http.StatusNoContent) 135} 136 137func (n *Notifications) markAllRead(w http.ResponseWriter, r *http.Request) { 138 userDid := n.oauth.GetDid(r) 139 140 err := db.MarkAllNotificationsRead(n.db, userDid) 141 if err != nil { 142 http.Error(w, "Failed to mark all notifications as read", http.StatusInternalServerError) 143 return 144 } 145 146 http.Redirect(w, r, "/notifications", http.StatusSeeOther) 147} 148 149func (n *Notifications) deleteNotification(w http.ResponseWriter, r *http.Request) { 150 userDid := n.oauth.GetDid(r) 151 152 idStr := chi.URLParam(r, "id") 153 notificationID, err := strconv.ParseInt(idStr, 10, 64) 154 if err != nil { 155 http.Error(w, "Invalid notification ID", http.StatusBadRequest) 156 return 157 } 158 159 err = db.DeleteNotification(n.db, notificationID, userDid) 160 if err != nil { 161 http.Error(w, "Failed to delete notification", http.StatusInternalServerError) 162 return 163 } 164 165 w.WriteHeader(http.StatusOK) 166}