Files
bot_ticket_r6_elite/internal/panel/handlers/sessions.go
T
2026-05-10 18:07:51 +02:00

132 lines
3.2 KiB
Go

package handlers
import (
"database/sql"
"net/http"
"strconv"
"github.com/go-chi/chi/v5"
"github.com/leolionad58/ticketbot/internal/db"
panelauth "github.com/leolionad58/ticketbot/internal/panel/auth"
)
// SessionsHandler serves /sessions routes (superadmin only).
type SessionsHandler struct {
SessionRepo *db.PanelSessionRepo
AdminRepo *db.PanelAdminRepo
AuditLog *db.AuditLogRepo
Renderer *Renderer
}
// sessionWithAdmin joins a PanelSession with the admin's username.
type sessionWithAdmin struct {
*db.PanelSession
DiscordUsername string
IsCurrent bool
}
type sessionsData struct {
baseData
Sessions []*sessionWithAdmin
}
// HandleList serves GET /sessions.
func (h *SessionsHandler) HandleList(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
base := h.Renderer.base(r, "sessions")
currentSess := panelauth.SessionFromContext(ctx)
currentToken := ""
if currentSess != nil {
currentToken = currentSess.Token
}
sessions, err := h.SessionRepo.List(ctx)
if err != nil {
http.Error(w, "db error: "+err.Error(), http.StatusInternalServerError)
return
}
var enriched []*sessionWithAdmin
for _, s := range sessions {
swa := &sessionWithAdmin{
PanelSession: s,
IsCurrent: s.Token == currentToken,
}
if admin, err := h.AdminRepo.GetByID(ctx, s.AdminID); err == nil && admin != nil {
swa.DiscordUsername = admin.DiscordUsername
}
enriched = append(enriched, swa)
}
h.Renderer.Page(w, "sessions", sessionsData{
baseData: base,
Sessions: enriched,
})
}
// HandleRevoke serves POST /sessions/{id}/revoke.
func (h *SessionsHandler) HandleRevoke(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
id, err := strconv.ParseInt(chi.URLParam(r, "id"), 10, 64)
if err != nil {
http.Error(w, "invalid id", http.StatusBadRequest)
return
}
if err := h.SessionRepo.DeleteByID(ctx, id); err != nil {
http.Error(w, "db error: "+err.Error(), http.StatusInternalServerError)
return
}
// Audit log
if h.AuditLog != nil {
admin := panelauth.AdminFromContext(ctx)
if admin != nil {
_ = h.AuditLog.Insert(ctx, &db.AuditLogEntry{
AdminID: admin.ID,
Action: db.AuditRevokeSession,
EntityType: "panel_session",
EntityID: sql.NullInt64{Int64: id, Valid: true},
IPAddress: clientIP(r),
})
}
}
http.Redirect(w, r, "/sessions?flash=Session+révoquée", http.StatusSeeOther)
}
// HandleRevokeAll serves POST /sessions/revoke-all.
func (h *SessionsHandler) HandleRevokeAll(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
admin := panelauth.AdminFromContext(ctx)
if admin == nil {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
currentSess := panelauth.SessionFromContext(ctx)
currentToken := ""
if currentSess != nil {
currentToken = currentSess.Token
}
if err := h.SessionRepo.DeleteAllExcept(ctx, admin.ID, currentToken); err != nil {
http.Error(w, "db error: "+err.Error(), http.StatusInternalServerError)
return
}
// Audit log
if h.AuditLog != nil {
_ = h.AuditLog.Insert(ctx, &db.AuditLogEntry{
AdminID: admin.ID,
Action: db.AuditRevokeAllSess,
EntityType: "panel_session",
IPAddress: clientIP(r),
})
}
http.Redirect(w, r, "/sessions?flash=Toutes+les+sessions+révoquées", http.StatusSeeOther)
}