Yōten: A social tracker for your language learning journey built on the atproto.

feat: add notification count middleware

This middleware retrieves the unread notification count to be displayed
in the header for the notification bell

brookjeynes.dev 4221c9eb 11daa1aa

verified
+35 -5
+6 -2
internal/clients/bsky/bsky.go
··· 6 6 "net/http" 7 7 "net/url" 8 8 9 + "yoten.app/internal/server/middleware" 9 10 "yoten.app/internal/server/oauth" 10 11 "yoten.app/internal/types" 11 12 ) ··· 72 73 return nil, fmt.Errorf("failed to get bsky profile:, %w", err) 73 74 } 74 75 76 + unreadNotificationCount, _ := r.Context().Value(middleware.UnreadNotificationCountCtxKey).(int) 77 + 75 78 return &types.User{ 76 - OauthUser: *oauth, 77 - BskyProfile: bskyProfile, 79 + OauthUser: *oauth, 80 + BskyProfile: bskyProfile, 81 + UnreadNotificationCount: unreadNotificationCount, 78 82 }, nil 79 83 }
+3 -2
internal/server/handlers/router.go
··· 43 43 44 44 func (h *Handler) StandardRouter(mw *middleware.Middleware) http.Handler { 45 45 r := chi.NewRouter() 46 + r.Use(middleware.LoadUnreadNotificationCount(h.Oauth)) 46 47 48 + r.Mount("/", h.OAuthRouter()) 47 49 r.Handle("/static/*", h.HandleStatic()) 48 50 r.Get("/", h.HandleIndexPage) 49 51 r.Get("/feed", h.HandleStudySessionFeed) 50 - 51 - r.Mount("/", h.OAuthRouter()) 52 52 53 53 r.Route("/friends", func(r chi.Router) { 54 54 r.Use(middleware.AuthMiddleware(h.Oauth)) ··· 122 122 r := chi.NewRouter() 123 123 124 124 r.Use(middleware.StripLeadingAt) 125 + r.Use(middleware.LoadUnreadNotificationCount(h.Oauth)) 125 126 126 127 r.Group(func(r chi.Router) { 127 128 r.Use(mw.ResolveIdent())
+24
internal/server/middleware/middleware.go
··· 15 15 "yoten.app/internal/server/views" 16 16 ) 17 17 18 + type CtxKey string 19 + 20 + const UnreadNotificationCountCtxKey CtxKey = "unreadNotificationCount" 21 + 18 22 type Middleware struct { 19 23 oauth *oauth.OAuth 20 24 db *db.DB ··· 96 100 next.ServeHTTP(w, req) 97 101 }) 98 102 } 103 + 104 + func LoadUnreadNotificationCount(o *oauth.OAuth) middlewareFunc { 105 + return func(next http.Handler) http.Handler { 106 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 107 + user := o.GetUser(r) 108 + if user == nil { 109 + next.ServeHTTP(w, r) 110 + return 111 + } 112 + 113 + count, err := db.GetUnreadNotificationCount(o.Db, user.Did) 114 + if err != nil { 115 + log.Println("failed to get notification count:", err) 116 + } 117 + 118 + ctx := context.WithValue(r.Context(), UnreadNotificationCountCtxKey, count) 119 + next.ServeHTTP(w, r.WithContext(ctx)) 120 + }) 121 + } 122 + }
+2 -1
internal/types/types.go
··· 8 8 9 9 type User struct { 10 10 OauthUser 11 - BskyProfile BskyProfile 11 + BskyProfile BskyProfile 12 + UnreadNotificationCount int 12 13 } 13 14 14 15 type BskyProfile struct {