From 50af2452b18ed9e67a56abb48be7042420caafbe Mon Sep 17 00:00:00 2001 From: lfirmin Date: Sat, 2 May 2026 03:30:08 +0200 Subject: [PATCH] v0.2.1 --- internal/claim/manager.go | 43 +++++++++++++++++++++++++++ internal/discord/components/panel.go | 36 ++++++++-------------- internal/discord/components/ticket.go | 4 +-- 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/internal/claim/manager.go b/internal/claim/manager.go index b047c71..6ca41f6 100644 --- a/internal/claim/manager.go +++ b/internal/claim/manager.go @@ -70,6 +70,49 @@ func (m *Manager) DeleteClaimMessage(ctx context.Context, s *discordgo.Session, m.claims.Delete(ctx, ticketID) //nolint } +// MarkClaimed edits the claim channel message to show the claimed state (green embed, no button, +// no ping) and removes it from tracking so the close flow leaves it untouched. +func (m *Manager) MarkClaimed(ctx context.Context, s *discordgo.Session, ticket *db.Ticket, staffID string) { + cm, err := m.claims.Get(ctx, ticket.ID) + if err != nil || cm == nil { + m.claims.Delete(ctx, ticket.ID) //nolint + return + } + cfg := m.cfg.Get() + claimChannelID := cfg.Bot.ClaimChannel + if claimChannelID == "" { + m.claims.Delete(ctx, ticket.ID) //nolint + return + } + + claimedEmbed := &discordgo.MessageEmbed{ + Title: "Ticket pris en charge", + Color: 0x57f287, + Fields: []*discordgo.MessageEmbedField{ + {Name: "Numéro", Value: fmt.Sprintf("#%04d", ticket.TicketNumber), Inline: true}, + {Name: "Type", Value: ticket.Type, Inline: true}, + {Name: "Auteur", Value: fmt.Sprintf("<@%s>", ticket.UserID), Inline: true}, + {Name: "Pris par", Value: fmt.Sprintf("<@%s>", staffID), Inline: true}, + {Name: "Salon", Value: fmt.Sprintf("<#%s>", ticket.ChannelID), Inline: true}, + }, + Timestamp: time.Now().UTC().Format(time.RFC3339), + } + + content := "" + emptyComponents := []discordgo.MessageComponent{} + if _, editErr := s.ChannelMessageEditComplex(&discordgo.MessageEdit{ + Channel: claimChannelID, + ID: cm.MessageID, + Content: &content, + Embeds: &[]*discordgo.MessageEmbed{claimedEmbed}, + Components: &emptyComponents, + }); editErr != nil { + slog.Warn("claim: edit message to claimed", "ticket_id", ticket.ID, "err", editErr) + } + + m.claims.Delete(ctx, ticket.ID) //nolint +} + func (m *Manager) startReupLoop(s *discordgo.Session, ticket *db.Ticket, lastReupAt time.Time) { ctx, cancel := context.WithCancel(context.Background()) m.mu.Lock() diff --git a/internal/discord/components/panel.go b/internal/discord/components/panel.go index 9a51350..c97e977 100644 --- a/internal/discord/components/panel.go +++ b/internal/discord/components/panel.go @@ -153,7 +153,7 @@ func (c *PanelComponent) HandleModalSubmit(s *discordgo.Session, i *discordgo.In } // b) Webhook impersonation message - postImpersonationMessage(s, ticket, uID, ticketTitle, ticketDescription, parseColor(embedColor), i.GuildID) + postImpersonationMessage(s, ticket, uID, ticketTitle, ticketDescription, i.GuildID) // c) Claim channel message (includes title + description) c.ClaimMgr.StartTicket(ctx, s, ticket) @@ -164,12 +164,12 @@ func (c *PanelComponent) HandleModalSubmit(s *discordgo.Session, i *discordgo.In } // postImpersonationMessage creates a temporary webhook on the ticket channel and posts -// the user's title+description as if it came from the user themselves. -func postImpersonationMessage(s *discordgo.Session, ticket *db.Ticket, userID, title, description string, color int, guildID string) { +// the user's title+description as plain text, impersonating the user's avatar and display name. +func postImpersonationMessage(s *discordgo.Session, ticket *db.Ticket, userID, title, description string, guildID string) { member, err := s.GuildMember(guildID, userID) if err != nil { slog.Warn("impersonation: get member", "user_id", userID, "err", err) - postImpersonationFallback(s, ticket.ChannelID, userID, title, description, color) + postImpersonationFallback(s, ticket.ChannelID, userID, title, description) return } user := member.User @@ -182,24 +182,22 @@ func postImpersonationMessage(s *discordgo.Session, ticket *db.Ticket, userID, t wh, err := s.WebhookCreate(ticket.ChannelID, "ticket-impersonation", "") if err != nil { slog.Warn("impersonation: create webhook", "channel_id", ticket.ChannelID, "err", err) - postImpersonationFallback(s, ticket.ChannelID, userID, title, description, color) + postImpersonationFallback(s, ticket.ChannelID, userID, title, description) return } + content := fmt.Sprintf("**%s**\n%s", title, description) _, execErr := s.WebhookExecute(wh.ID, wh.Token, true, &discordgo.WebhookParams{ Username: displayName, AvatarURL: avatarURL, - Embeds: []*discordgo.MessageEmbed{ - { - Title: title, - Description: description, - Color: color, - }, + Content: content, + AllowedMentions: &discordgo.MessageAllowedMentions{ + Parse: []discordgo.AllowedMentionType{}, }, }) if execErr != nil { slog.Warn("impersonation: execute webhook", "err", execErr) - postImpersonationFallback(s, ticket.ChannelID, userID, title, description, color) + postImpersonationFallback(s, ticket.ChannelID, userID, title, description) } // Delete webhook — channel delete at close cleans up anyway, but we keep it tidy @@ -208,15 +206,7 @@ func postImpersonationMessage(s *discordgo.Session, ticket *db.Ticket, userID, t } } -func postImpersonationFallback(s *discordgo.Session, channelID, userID, title, description string, color int) { - s.ChannelMessageSendComplex(channelID, &discordgo.MessageSend{ //nolint - Embeds: []*discordgo.MessageEmbed{ - { - Title: title, - Description: description, - Color: color, - Author: &discordgo.MessageEmbedAuthor{Name: fmt.Sprintf("Demande de <@%s>", userID)}, - }, - }, - }) +func postImpersonationFallback(s *discordgo.Session, channelID, userID, title, description string) { + content := fmt.Sprintf("**%s**\n%s\n*(par <@%s>)*", title, description, userID) + s.ChannelMessageSend(channelID, content) //nolint } diff --git a/internal/discord/components/ticket.go b/internal/discord/components/ticket.go index 764dbd7..2c421cf 100644 --- a/internal/discord/components/ticket.go +++ b/internal/discord/components/ticket.go @@ -174,9 +174,9 @@ func (c *TicketComponent) HandleClaim(s *discordgo.Session, i *discordgo.Interac } ticket.Status = "claimed" - // Stop re-up loop and delete claim message + // Stop re-up loop and edit claim message to claimed state c.ClaimMgr.Stop(ticketID) - c.ClaimMgr.DeleteClaimMessage(ctx, s, ticketID) + c.ClaimMgr.MarkClaimed(ctx, s, ticket, staffID) // Add staff to ticket channel if err := c.TicketSvc.AddMember(ctx, ticket.ChannelID, staffID); err != nil {