···
1
+
package notifications
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"
15
+
type Notifications struct {
21
+
func New(database *db.DB, oauthHandler *oauth.OAuth, pagesHandler *pages.Pages) *Notifications {
22
+
return &Notifications{
24
+
oauth: oauthHandler,
25
+
pages: pagesHandler,
29
+
func (n *Notifications) Router(mw *middleware.Middleware) http.Handler {
30
+
r := chi.NewRouter()
32
+
r.Use(middleware.AuthMiddleware(n.oauth))
34
+
r.Get("/", n.notificationsPage)
36
+
r.Get("/count", n.getUnreadCount)
37
+
r.Post("/{id}/read", n.markRead)
38
+
r.Post("/read-all", n.markAllRead)
39
+
r.Delete("/{id}", n.deleteNotification)
44
+
func (n *Notifications) notificationsPage(w http.ResponseWriter, r *http.Request) {
45
+
userDid := n.oauth.GetDid(r)
47
+
limitStr := r.URL.Query().Get("limit")
48
+
offsetStr := r.URL.Query().Get("offset")
50
+
limit := 20 // default
52
+
if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 100 {
57
+
offset := 0 // default
58
+
if offsetStr != "" {
59
+
if o, err := strconv.Atoi(offsetStr); err == nil && o >= 0 {
64
+
notifications, err := n.db.GetNotificationsWithEntities(r.Context(), userDid, limit+1, offset)
66
+
log.Println("failed to get notifications:", err)
71
+
hasMore := len(notifications) > limit
73
+
notifications = notifications[:limit]
76
+
err = n.db.MarkAllNotificationsRead(r.Context(), userDid)
78
+
log.Println("failed to mark notifications as read:", err)
83
+
user := n.oauth.GetUser(r)
85
+
http.Error(w, "Failed to get user", http.StatusInternalServerError)
89
+
params := pages.NotificationsParams{
91
+
Notifications: notifications,
92
+
UnreadCount: unreadCount,
94
+
NextOffset: offset + limit,
98
+
err = n.pages.Notifications(w, params)
100
+
log.Println("failed to load notifs:", err)
101
+
n.pages.Error500(w)
106
+
func (n *Notifications) getUnreadCount(w http.ResponseWriter, r *http.Request) {
107
+
userDid := n.oauth.GetDid(r)
109
+
count, err := n.db.GetUnreadNotificationCount(r.Context(), userDid)
111
+
http.Error(w, "Failed to get unread count", http.StatusInternalServerError)
115
+
params := pages.NotificationCountParams{
118
+
err = n.pages.NotificationCount(w, params)
120
+
http.Error(w, "Failed to render count", http.StatusInternalServerError)
125
+
func (n *Notifications) markRead(w http.ResponseWriter, r *http.Request) {
126
+
userDid := n.oauth.GetDid(r)
128
+
idStr := chi.URLParam(r, "id")
129
+
notificationID, err := strconv.ParseInt(idStr, 10, 64)
131
+
http.Error(w, "Invalid notification ID", http.StatusBadRequest)
135
+
err = n.db.MarkNotificationRead(r.Context(), notificationID, userDid)
137
+
http.Error(w, "Failed to mark notification as read", http.StatusInternalServerError)
141
+
w.WriteHeader(http.StatusNoContent)
144
+
func (n *Notifications) markAllRead(w http.ResponseWriter, r *http.Request) {
145
+
userDid := n.oauth.GetDid(r)
147
+
err := n.db.MarkAllNotificationsRead(r.Context(), userDid)
149
+
http.Error(w, "Failed to mark all notifications as read", http.StatusInternalServerError)
153
+
http.Redirect(w, r, "/notifications", http.StatusSeeOther)
156
+
func (n *Notifications) deleteNotification(w http.ResponseWriter, r *http.Request) {
157
+
userDid := n.oauth.GetDid(r)
159
+
idStr := chi.URLParam(r, "id")
160
+
notificationID, err := strconv.ParseInt(idStr, 10, 64)
162
+
http.Error(w, "Invalid notification ID", http.StatusBadRequest)
166
+
err = n.db.DeleteNotification(r.Context(), notificationID, userDid)
168
+
http.Error(w, "Failed to delete notification", http.StatusInternalServerError)
172
+
w.WriteHeader(http.StatusOK)