feat: add stats page
This commit is contained in:
@@ -50,6 +50,8 @@ type Server struct {
|
||||
bookmarkH *handler.BookmarkHandler
|
||||
collectionH *handler.CollectionHandler
|
||||
profileH *handler.ProfileHandler
|
||||
feedbackH *handler.FeedbackHandler
|
||||
statsH *handler.StatsHandler
|
||||
|
||||
// Auth state (nil when Postgres is unavailable — /auth and /users return 503)
|
||||
authIssuer *auth.Issuer
|
||||
@@ -164,6 +166,14 @@ func (s *Server) initAuth(cfg *config.Config, logger *zap.Logger) {
|
||||
s.bookmarkH = handler.NewBookmarkHandler(bookmarkSvc)
|
||||
s.collectionH = handler.NewCollectionHandler(collectionSvc, postRepo, issuer, userRepo)
|
||||
s.profileH = handler.NewProfileHandler(userRepo, postRepo, collectionRepo)
|
||||
|
||||
// Feedback + stats — share Postgres with the rest of /api/v1 and
|
||||
// the existing mailer instance.
|
||||
feedbackRepo := repository.NewFeedbackRepo(s.pg)
|
||||
statsRepo := repository.NewStatsRepo(s.pg)
|
||||
feedbackSvc := service.NewFeedbackService(feedbackRepo, mail, cfg.FeedbackAdminEmails, logger)
|
||||
s.feedbackH = handler.NewFeedbackHandler(feedbackSvc)
|
||||
s.statsH = handler.NewStatsHandler(statsRepo, feedbackRepo)
|
||||
}
|
||||
|
||||
// initShortener wires Postgres + Redis + the shorturl handler/workers.
|
||||
@@ -276,6 +286,14 @@ func (s *Server) setupRouter() {
|
||||
w.Write([]byte(`{"status":"ok"}`))
|
||||
})
|
||||
|
||||
// Public ops snapshot — aggregate counts + recent feedback rendered
|
||||
// as HTML. Lives outside /api/v1 because it returns HTML, not JSON.
|
||||
// Currently unauthenticated by product decision; gate here if that
|
||||
// ever needs to change.
|
||||
if s.statsH != nil {
|
||||
r.Get("/stats", s.statsH.Render)
|
||||
}
|
||||
|
||||
// API v1
|
||||
r.Route("/api/v1", func(r chi.Router) {
|
||||
// Books
|
||||
@@ -601,6 +619,20 @@ func (s *Server) setupRouter() {
|
||||
}
|
||||
})
|
||||
|
||||
// --- Feedback ---
|
||||
// OptionalAuth so authed callers' user_id is captured
|
||||
// automatically (handler reads middleware.UserID), and
|
||||
// anonymous callers are still accepted (they supply
|
||||
// contact_email instead).
|
||||
r.Group(func(r chi.Router) {
|
||||
if s.feedbackH == nil {
|
||||
r.HandleFunc("/feedback", s.authUnavailable)
|
||||
return
|
||||
}
|
||||
r.Use(middleware.OptionalAuth(s.authIssuer, s.userRepo))
|
||||
r.Post("/feedback", s.feedbackH.Submit)
|
||||
})
|
||||
|
||||
// Push Notifications
|
||||
r.Route("/notifications", func(r chi.Router) {
|
||||
// TODO: register push notification handlers
|
||||
|
||||
Reference in New Issue
Block a user