forked from
tangled.org/core
Monorepo for Tangled — https://tangled.org
1package notifications
2
3import (
4 "log"
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}
21
22func New(database *db.DB, oauthHandler *oauth.OAuth, pagesHandler *pages.Pages) *Notifications {
23 return &Notifications{
24 db: database,
25 oauth: oauthHandler,
26 pages: pagesHandler,
27 }
28}
29
30func (n *Notifications) Router(mw *middleware.Middleware) http.Handler {
31 r := chi.NewRouter()
32
33 r.Get("/count", n.getUnreadCount)
34
35 r.Group(func(r chi.Router) {
36 r.Use(middleware.AuthMiddleware(n.oauth))
37 r.With(middleware.Paginate).Get("/", n.notificationsPage)
38 r.Post("/{id}/read", n.markRead)
39 r.Post("/read-all", n.markAllRead)
40 r.Delete("/{id}", n.deleteNotification)
41 })
42
43 return r
44}
45
46func (n *Notifications) notificationsPage(w http.ResponseWriter, r *http.Request) {
47 user := n.oauth.GetUser(r)
48
49 page, ok := r.Context().Value("page").(pagination.Page)
50 if !ok {
51 log.Println("failed to get page")
52 page = pagination.FirstPage()
53 }
54
55 total, err := db.CountNotifications(
56 n.db,
57 db.FilterEq("recipient_did", user.Did),
58 )
59 if err != nil {
60 log.Println("failed to get total notifications:", err)
61 n.pages.Error500(w)
62 return
63 }
64
65 notifications, err := db.GetNotificationsWithEntities(
66 n.db,
67 page,
68 db.FilterEq("recipient_did", user.Did),
69 )
70 if err != nil {
71 log.Println("failed to get notifications:", err)
72 n.pages.Error500(w)
73 return
74 }
75
76 err = n.db.MarkAllNotificationsRead(r.Context(), user.Did)
77 if err != nil {
78 log.Println("failed to mark notifications as read:", 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 db.FilterEq("recipient_did", user.Did),
101 db.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 = n.db.MarkNotificationRead(r.Context(), 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 := n.db.MarkAllNotificationsRead(r.Context(), 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 = n.db.DeleteNotification(r.Context(), 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}