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