chore: update admin apis
This commit is contained in:
@@ -1,14 +1,11 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/prabhupadasays/spsays-bff/internal/repository"
|
||||
"github.com/prabhupadasays/spsays-bff/internal/service"
|
||||
)
|
||||
|
||||
// StatsHandler renders a single-page HTML snapshot of the system —
|
||||
@@ -17,17 +14,15 @@ import (
|
||||
// public per current product call. If that ever needs to change, wrap
|
||||
// the route in middleware in server.go.
|
||||
//
|
||||
// It also handles the "Mark resolved" form POST per feedback row, which
|
||||
// stamps resolved_at (one-way) and fires the author thank-you email via
|
||||
// the feedback service.
|
||||
// It is READ-ONLY: feedback acknowledge/resolve actions live in the
|
||||
// authenticated admin panel, never on this public page.
|
||||
type StatsHandler struct {
|
||||
stats *repository.StatsRepo
|
||||
feedback *repository.FeedbackRepo
|
||||
svc *service.FeedbackService
|
||||
}
|
||||
|
||||
func NewStatsHandler(stats *repository.StatsRepo, feedback *repository.FeedbackRepo, svc *service.FeedbackService) *StatsHandler {
|
||||
return &StatsHandler{stats: stats, feedback: feedback, svc: svc}
|
||||
func NewStatsHandler(stats *repository.StatsRepo, feedback *repository.FeedbackRepo) *StatsHandler {
|
||||
return &StatsHandler{stats: stats, feedback: feedback}
|
||||
}
|
||||
|
||||
func (h *StatsHandler) Render(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -55,33 +50,6 @@ func (h *StatsHandler) Render(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// AcknowledgeFeedback handles the per-row "Acknowledge" form POST. Marks
|
||||
// the row acknowledged (one-way) and emails the author that we've seen
|
||||
// it and started work, then 303-redirects back to /stats. Already-
|
||||
// acknowledged or unknown ids redirect silently.
|
||||
func (h *StatsHandler) AcknowledgeFeedback(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
if err := h.svc.Acknowledge(r.Context(), id); err != nil && !errors.Is(err, service.ErrAlreadyAcknowledged) {
|
||||
http.Error(w, "acknowledge failed: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/stats", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// ResolveFeedback handles the per-row "Mark resolved" form POST. It marks
|
||||
// the row resolved (one-way) and fires the author thank-you email, then
|
||||
// 303-redirects back to /stats so a refresh doesn't re-submit. Already-
|
||||
// resolved or unknown ids redirect silently — the desired end state is
|
||||
// already true.
|
||||
func (h *StatsHandler) ResolveFeedback(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
if err := h.svc.Resolve(r.Context(), id); err != nil && !errors.Is(err, service.ErrAlreadyResolved) {
|
||||
http.Error(w, "resolve failed: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/stats", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
var statsTpl = template.Must(template.New("stats").Funcs(template.FuncMap{
|
||||
"fmtTime": func(t time.Time) string { return t.Format("2006-01-02 15:04") },
|
||||
}).Parse(statsHTML))
|
||||
@@ -115,6 +83,7 @@ h2 { font-size: 1.05rem; margin-top: 2rem; margin-bottom: 0.5rem; border-bottom:
|
||||
.fb .foot { display: flex; justify-content: flex-end; align-items: center; gap: 0.6rem; margin-top: 0.6rem }
|
||||
.resolved-badge { display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.78rem; font-weight: 600; color: #1e7a4a }
|
||||
.acked-badge { display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.78rem; font-weight: 600; color: #9a6b2f }
|
||||
.pending-badge { display: inline-flex; align-items: center; font-size: 0.78rem; font-weight: 600; color: #999 }
|
||||
.resolve-btn { font: inherit; font-size: 0.8rem; font-weight: 600; color: #fff; background: #1e7a4a; border: 0; border-radius: 6px; padding: 0.4rem 0.85rem; cursor: pointer }
|
||||
.resolve-btn:hover { background: #196b40 }
|
||||
.ack-btn { font: inherit; font-size: 0.8rem; font-weight: 600; color: #9a6b2f; background: #fff; border: 1px solid #d6b27a; border-radius: 6px; padding: 0.4rem 0.85rem; cursor: pointer }
|
||||
@@ -168,17 +137,10 @@ code { background: #f4f4f4; padding: 0.05em 0.3em; border-radius: 3px; font-size
|
||||
{{if .ResolvedAt}}
|
||||
{{if .AcknowledgedAt}}<span class="acked-badge">✓ Acknowledged {{fmtTime .AcknowledgedAt}}</span>{{end}}
|
||||
<span class="resolved-badge">✓ Resolved {{fmtTime .ResolvedAt}}</span>
|
||||
{{else if .AcknowledgedAt}}
|
||||
<span class="acked-badge">✓ Acknowledged {{fmtTime .AcknowledgedAt}}</span>
|
||||
{{else}}
|
||||
{{if .AcknowledgedAt}}
|
||||
<span class="acked-badge">✓ Acknowledged {{fmtTime .AcknowledgedAt}}</span>
|
||||
{{else}}
|
||||
<form method="post" action="/stats/feedback/{{.ID}}/acknowledge" onsubmit="return confirm('Acknowledge this feedback? The author will be emailed that we have seen it and started work. This cannot be undone.');">
|
||||
<button type="submit" class="ack-btn">Acknowledge</button>
|
||||
</form>
|
||||
{{end}}
|
||||
<form method="post" action="/stats/feedback/{{.ID}}/resolve" onsubmit="return confirm('Mark this feedback as resolved? This cannot be undone, and the author will be emailed.');">
|
||||
<button type="submit" class="resolve-btn">Mark resolved</button>
|
||||
</form>
|
||||
<span class="pending-badge">Pending</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user