oups
This commit is contained in:
@@ -0,0 +1,252 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/leolionad58/ticketbot/internal/db"
|
||||
panelauth "github.com/leolionad58/ticketbot/internal/panel/auth"
|
||||
)
|
||||
|
||||
// ConvocBotService is the subset of BotService needed for convocation operations.
|
||||
type ConvocBotService interface {
|
||||
CreateConvocation(guildID, staffDiscordID, targetDiscordID, reason string) (channelID string, err error)
|
||||
SendConvocPanel(guildID string) error
|
||||
SendConvocPanelByID(panelID int64) error
|
||||
}
|
||||
|
||||
// ConvocDiscordInfo is the subset of DiscordInfo for guild selection in convocations.
|
||||
type ConvocDiscordInfo interface {
|
||||
GetGuildList() []GuildInfo
|
||||
}
|
||||
|
||||
// ConvocationsHandler serves /convocations.
|
||||
type ConvocationsHandler struct {
|
||||
TicketRepo *db.TicketRepo
|
||||
ConvocRepo *db.ConvocationConfigRepo
|
||||
ConvocPanelRepo *db.ConvocationPanelRepo
|
||||
GuildID string
|
||||
BotService ConvocBotService
|
||||
DiscordInfo ConvocDiscordInfo
|
||||
Renderer *Renderer
|
||||
}
|
||||
|
||||
type convocationsData struct {
|
||||
baseData
|
||||
Config *db.ConvocationConfig
|
||||
ConvocPanels []*db.ConvocationPanel
|
||||
Tickets []*db.Ticket
|
||||
Total int
|
||||
Page int
|
||||
Pages int
|
||||
Guilds []GuildInfo
|
||||
}
|
||||
|
||||
// HandleGET serves GET /convocations.
|
||||
func (h *ConvocationsHandler) HandleGET(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
base := h.Renderer.base(r, "convocations")
|
||||
sess := panelauth.SessionFromContext(ctx)
|
||||
if sess != nil {
|
||||
base.CSRFToken = sess.CSRFToken
|
||||
}
|
||||
|
||||
cfg, err := h.ConvocRepo.Get(ctx, h.GuildID)
|
||||
if err != nil {
|
||||
http.Error(w, "db error: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var convocPanels []*db.ConvocationPanel
|
||||
if h.ConvocPanelRepo != nil {
|
||||
convocPanels, _ = h.ConvocPanelRepo.List(ctx, h.GuildID)
|
||||
}
|
||||
|
||||
page := 1
|
||||
tickets, total, err := h.TicketRepo.ListFiltered(ctx, db.TicketFilter{
|
||||
Type: "convocation",
|
||||
Page: page,
|
||||
PageSize: 20,
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, "db error: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
pages := total / 20
|
||||
if total%20 != 0 {
|
||||
pages++
|
||||
}
|
||||
if pages < 1 {
|
||||
pages = 1
|
||||
}
|
||||
|
||||
var guilds []GuildInfo
|
||||
if h.DiscordInfo != nil {
|
||||
guilds = h.DiscordInfo.GetGuildList()
|
||||
}
|
||||
|
||||
h.Renderer.Page(w, "convocations", convocationsData{
|
||||
baseData: base,
|
||||
Config: cfg,
|
||||
ConvocPanels: convocPanels,
|
||||
Tickets: tickets,
|
||||
Total: total,
|
||||
Page: page,
|
||||
Pages: pages,
|
||||
Guilds: guilds,
|
||||
})
|
||||
}
|
||||
|
||||
// HandlePOST serves POST /convocations — saves the convocation config.
|
||||
func (h *ConvocationsHandler) HandlePOST(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Load existing config to preserve panel_message_id (not sent by form)
|
||||
existing, _ := h.ConvocRepo.Get(ctx, h.GuildID)
|
||||
panelMsgID := ""
|
||||
panelChannelID := strings.TrimSpace(r.FormValue("panel_channel_id"))
|
||||
if existing != nil {
|
||||
panelMsgID = existing.PanelMessageID
|
||||
// If channel changed, clear stored message ID so SendConvocPanel sends a new message
|
||||
if existing.PanelChannelID != panelChannelID {
|
||||
panelMsgID = ""
|
||||
}
|
||||
}
|
||||
|
||||
embedColor := strings.TrimSpace(r.FormValue("panel_embed_color"))
|
||||
if embedColor == "" {
|
||||
embedColor = "#5865f2"
|
||||
}
|
||||
|
||||
cfg := &db.ConvocationConfig{
|
||||
GuildID: h.GuildID,
|
||||
CategoryID: strings.TrimSpace(r.FormValue("category_id")),
|
||||
LogChannelID: strings.TrimSpace(r.FormValue("log_channel_id")),
|
||||
ModalEnabled: r.FormValue("modal_enabled") == "1",
|
||||
PanelChannelID: panelChannelID,
|
||||
PanelMessageID: panelMsgID,
|
||||
PanelEmbedTitle: strings.TrimSpace(r.FormValue("panel_embed_title")),
|
||||
PanelEmbedDescription: strings.TrimSpace(r.FormValue("panel_embed_description")),
|
||||
PanelEmbedColor: embedColor,
|
||||
}
|
||||
|
||||
if err := h.ConvocRepo.Upsert(ctx, cfg); err != nil {
|
||||
http.Error(w, "db error: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/convocations?flash=Configuration+sauvegardée", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// HandleCreatePanel serves POST /convocations/panels/new — creates a new convocation panel entry.
|
||||
func (h *ConvocationsHandler) HandleCreatePanel(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if h.ConvocPanelRepo == nil {
|
||||
http.Redirect(w, r, "/convocations?error=Non+configuré", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
color := strings.TrimSpace(r.FormValue("embed_color"))
|
||||
if color == "" {
|
||||
color = "#5865f2"
|
||||
}
|
||||
p := &db.ConvocationPanel{
|
||||
GuildID: h.GuildID,
|
||||
EmbedTitle: strings.TrimSpace(r.FormValue("embed_title")),
|
||||
EmbedDesc: strings.TrimSpace(r.FormValue("embed_description")),
|
||||
EmbedColor: color,
|
||||
ChannelID: strings.TrimSpace(r.FormValue("channel_id")),
|
||||
}
|
||||
if err := h.ConvocPanelRepo.Create(ctx, p); err != nil {
|
||||
http.Redirect(w, r, "/convocations?error="+urlEncode(err.Error()), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/convocations?flash=Panel+créé", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// HandleDeletePanel serves POST /convocations/panels/{id}/delete.
|
||||
func (h *ConvocationsHandler) HandleDeletePanel(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
idStr := chi.URLParam(r, "id")
|
||||
var id int64
|
||||
fmt.Sscanf(idStr, "%d", &id)
|
||||
if h.ConvocPanelRepo != nil {
|
||||
h.ConvocPanelRepo.Delete(ctx, id) //nolint
|
||||
}
|
||||
http.Redirect(w, r, "/convocations?flash=Panel+supprimé", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// HandleSendPanel serves POST /convocations/panels/{id}/send.
|
||||
func (h *ConvocationsHandler) HandleSendPanel(w http.ResponseWriter, r *http.Request) {
|
||||
idStr := chi.URLParam(r, "id")
|
||||
var id int64
|
||||
fmt.Sscanf(idStr, "%d", &id)
|
||||
if h.BotService == nil {
|
||||
http.Redirect(w, r, "/convocations?error=Bot+non+disponible", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
if err := h.BotService.SendConvocPanelByID(id); err != nil {
|
||||
http.Redirect(w, r, "/convocations?error="+urlEncode(err.Error()), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/convocations?flash=Panel+envoyé+sur+Discord", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// HandleCreate serves POST /convocations/create — creates a convocation via Discord.
|
||||
func (h *ConvocationsHandler) HandleCreate(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if h.BotService == nil {
|
||||
http.Error(w, "bot non disponible", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
|
||||
guildID := strings.TrimSpace(r.FormValue("guild_id"))
|
||||
if guildID == "" {
|
||||
guildID = h.GuildID
|
||||
}
|
||||
targetID := strings.TrimSpace(r.FormValue("target_id"))
|
||||
reason := strings.TrimSpace(r.FormValue("reason"))
|
||||
|
||||
if targetID == "" || reason == "" {
|
||||
http.Redirect(w, r, "/convocations?error=ID+utilisateur+et+raison+requis", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
admin := panelauth.AdminFromContext(r.Context())
|
||||
staffDiscordID := ""
|
||||
if admin != nil {
|
||||
staffDiscordID = admin.DiscordID
|
||||
}
|
||||
|
||||
channelID, err := h.BotService.CreateConvocation(guildID, staffDiscordID, targetID, reason)
|
||||
if err != nil {
|
||||
http.Redirect(w, r, "/convocations?error="+urlEncode(err.Error()), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/convocations?flash=Convocation+créée+dans+<#"+channelID+">", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func urlEncode(s string) string {
|
||||
var out strings.Builder
|
||||
for _, r := range s {
|
||||
switch {
|
||||
case r >= 'a' && r <= 'z', r >= 'A' && r <= 'Z', r >= '0' && r <= '9':
|
||||
out.WriteRune(r)
|
||||
case r == '-' || r == '_' || r == '.' || r == '~':
|
||||
out.WriteRune(r)
|
||||
default:
|
||||
out.WriteString("+" + strings.ReplaceAll(string(r), " ", "+"))
|
||||
}
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
Reference in New Issue
Block a user