Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bot/button/handlers/exitsurveysubmit.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,5 +182,5 @@ func addViewFeedbackButton(ctx context.Context, cmd *cmdcontext.ModalContext, ti
return fmt.Errorf("exit survey was completed, but no rating was found (%d:%d)", ticket.GuildId, ticket.Id)
}

return logic.EditGuildArchiveMessageIfExists(ctx, cmd.Worker(), ticket, settings, true, closedBy, reason, &rating)
return logic.EditGuildArchiveMessageIfExists(ctx, cmd, cmd.Worker(), ticket, settings, true, closedBy, reason, &rating)
}
2 changes: 1 addition & 1 deletion bot/button/handlers/rate.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func (h *RateHandler) Execute(ctx *cmdcontext.ButtonContext) {
return
}

if err := logic.EditGuildArchiveMessageIfExists(ctx, ctx.Worker(), ticket, settings, hasFeedback, closedBy, reason, &rating); err != nil {
if err := logic.EditGuildArchiveMessageIfExists(ctx, ctx, ctx.Worker(), ticket, settings, hasFeedback, closedBy, reason, &rating); err != nil {
ctx.HandleError(err)
}
}
45 changes: 19 additions & 26 deletions bot/logic/close.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/TicketsBot-cloud/common/sentry"
"github.com/TicketsBot-cloud/database"
"github.com/TicketsBot-cloud/gdl/objects/channel/message"
"github.com/TicketsBot-cloud/gdl/objects/interaction/component"
"github.com/TicketsBot-cloud/gdl/objects/member"
"github.com/TicketsBot-cloud/gdl/rest"
"github.com/TicketsBot-cloud/gdl/rest/request"
Expand Down Expand Up @@ -231,10 +232,10 @@ func CloseTicket(ctx context.Context, cmd registry.CommandContext, reason *strin
}
}

sendCloseEmbed(ctx, cmd, errorContext, member, settings, ticket, reason)
sendCloseContainer(ctx, cmd, errorContext, member, settings, ticket, reason)
}

func sendCloseEmbed(ctx context.Context, cmd registry.CommandContext, errorContext sentry.ErrorContext, member member.Member, settings database.Settings, ticket database.Ticket, reason *string) {
func sendCloseContainer(ctx context.Context, cmd registry.CommandContext, errorContext sentry.ErrorContext, member member.Member, settings database.Settings, ticket database.Ticket, reason *string) {
// Send logs to archive channel
archiveChannelId, err := dbclient.Client.ArchiveChannel.Get(ctx, ticket.GuildId)
if err != nil {
Expand All @@ -249,14 +250,7 @@ func sendCloseEmbed(ctx context.Context, cmd registry.CommandContext, errorConte
}

if archiveChannelExists && archiveChannelId != nil {
componentBuilders := [][]CloseEmbedElement{
{
TranscriptLinkElement(settings.StoreTranscripts),
ThreadLinkElement(ticket.IsThread && ticket.ChannelId != nil),
},
}

closeContainer := BuildCloseContainer(ctx, cmd, cmd.Worker(), ticket, member.User.Id, reason, nil, componentBuilders)
closeContainer := BuildCloseContainer(ctx, cmd, cmd.Worker(), ticket, nil, member.User.Id, reason, nil, false)

data := rest.CreateMessageData{
Flags: uint(message.FlagComponentsV2),
Expand Down Expand Up @@ -321,33 +315,32 @@ func sendCloseEmbed(ctx context.Context, cmd registry.CommandContext, errorConte

statsd.Client.IncrementKey(statsd.KeyDirectMessage)

componentBuilders := [][]CloseEmbedElement{
{
TranscriptLinkElement(settings.StoreTranscripts),
ThreadLinkElement(ticket.IsThread && ticket.ChannelId != nil),
},
{
FeedbackRowElement(feedbackEnabled && hasSentMessage && permLevel == permission.Everyone),
},
}

closeEmbed, closeComponents := BuildCloseEmbed(ctx, cmd.Worker(), ticket, member.User.Id, reason, nil, componentBuilders)
closeEmbed.SetAuthor(guild.Name, "", fmt.Sprintf("https://cdn.discordapp.com/icons/%d/%s.png", guild.Id, guild.Icon))

// Use message content to tell users why they can't rate a ticket
var content string
var viewFeedbackButton = true
if feedbackEnabled {
if permLevel > permission.Everyone {
content = "-# " + cmd.GetMessage(i18n.MessageCloseCantRateStaff, guild.Name)
viewFeedbackButton = false
} else if !hasSentMessage {
content = "-# " + cmd.GetMessage(i18n.MessageCloseCantRateEmpty)
viewFeedbackButton = false
}
}

closeContainer := BuildCloseContainer(ctx, cmd, cmd.Worker(), ticket, &guild, member.User.Id, reason, nil, viewFeedbackButton)

components := []component.Component{*closeContainer}
if content != "" {
components = []component.Component{
component.BuildTextDisplay(component.TextDisplay{Content: content}),
*closeContainer,
}
}

data := rest.CreateMessageData{
Content: content,
Embeds: utils.Slice(closeEmbed),
Components: closeComponents,
Flags: uint(message.FlagComponentsV2),
Components: components,
}

if _, err := cmd.Worker().CreateMessageComplex(dmChannel, data); err != nil {
Expand Down
175 changes: 65 additions & 110 deletions bot/logic/closeembed.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"github.com/TicketsBot-cloud/common/premium"
"github.com/TicketsBot-cloud/common/sentry"
"github.com/TicketsBot-cloud/database"
"github.com/TicketsBot-cloud/gdl/objects/channel/embed"
"github.com/TicketsBot-cloud/gdl/objects/channel/message"
"github.com/TicketsBot-cloud/gdl/objects/guild"
"github.com/TicketsBot-cloud/gdl/objects/guild/emoji"
"github.com/TicketsBot-cloud/gdl/objects/interaction/component"
"github.com/TicketsBot-cloud/gdl/rest"
Expand All @@ -22,15 +22,15 @@ import (
"github.com/TicketsBot-cloud/worker/config"
)

type CloseEmbedElement func(worker *worker.Context, ticket database.Ticket) []component.Component
type CloseContainerElement func(worker *worker.Context, ticket database.Ticket) []component.Component

func NoopElement() CloseEmbedElement {
func NoopElement() CloseContainerElement {
return func(worker *worker.Context, ticket database.Ticket) []component.Component {
return nil
}
}

func TranscriptLinkElement(condition bool) CloseEmbedElement {
func TranscriptLinkElement(condition bool) CloseContainerElement {
if !condition {
return NoopElement()
}
Expand All @@ -52,7 +52,7 @@ func TranscriptLinkElement(condition bool) CloseEmbedElement {
}
}

func ThreadLinkElement(condition bool) CloseEmbedElement {
func ThreadLinkElement(condition bool) CloseContainerElement {
if !condition {
return NoopElement()
}
Expand All @@ -74,7 +74,7 @@ func ThreadLinkElement(condition bool) CloseEmbedElement {
}
}

func ViewFeedbackElement(condition bool) CloseEmbedElement {
func ViewFeedbackElement(condition bool) CloseContainerElement {
if !condition {
return NoopElement()
}
Expand All @@ -91,7 +91,7 @@ func ViewFeedbackElement(condition bool) CloseEmbedElement {
}
}

func FeedbackRowElement(condition bool) CloseEmbedElement {
func FeedbackRowElement(condition bool) CloseContainerElement {
if !condition {
return NoopElement()
}
Expand Down Expand Up @@ -123,96 +123,19 @@ func FeedbackRowElement(condition bool) CloseEmbedElement {
}
}

func BuildCloseEmbed(
ctx context.Context,
worker *worker.Context,
ticket database.Ticket,
closedBy uint64,
reason *string,
rating *uint8,
components [][]CloseEmbedElement,
) (*embed.Embed, []component.Component) {
var formattedReason string
if reason == nil {
formattedReason = "No reason specified"
} else {
formattedReason = *reason
if len(formattedReason) > 1024 {
formattedReason = formattedReason[:1024]
}
}

var claimedBy string
{
claimUserId, err := dbclient.Client.TicketClaims.Get(ctx, ticket.GuildId, ticket.Id)
if err != nil {
sentry.Error(err)
}

if claimUserId == 0 {
claimedBy = "Not claimed"
} else {
claimedBy = fmt.Sprintf("<@%d>", claimUserId)
}
}

colour, err := utils.GetColourForGuild(ctx, worker, customisation.Green, ticket.GuildId)
if err != nil {
sentry.Error(err)
colour = customisation.Green.Default()
}

// TODO: Translate titles
closeEmbed := embed.NewEmbed().
SetTitle("Ticket Closed").
SetColor(colour).
AddField(formatTitle("Ticket ID", customisation.EmojiId, worker.IsWhitelabel), strconv.Itoa(ticket.Id), true).
AddField(formatTitle("Opened By", customisation.EmojiOpen, worker.IsWhitelabel), fmt.Sprintf("<@%d>", ticket.UserId), true).
AddField(formatTitle("Closed By", customisation.EmojiClose, worker.IsWhitelabel), fmt.Sprintf("<@%d>", closedBy), true).
AddField(formatTitle("Open Time", customisation.EmojiOpenTime, worker.IsWhitelabel), message.BuildTimestamp(ticket.OpenTime, message.TimestampStyleShortDateTime), true).
AddField(formatTitle("Claimed By", customisation.EmojiClaim, worker.IsWhitelabel), claimedBy, true)

if ticket.CloseTime != nil {
closeEmbed.SetTimestamp(*ticket.CloseTime)
}

if rating == nil {
closeEmbed = closeEmbed.AddBlankField(true)
} else {
closeEmbed = closeEmbed.AddField(formatTitle("Rating", customisation.EmojiRating, worker.IsWhitelabel), fmt.Sprintf("%d ⭐", *rating), true)
}

closeEmbed = closeEmbed.AddField(formatTitle("Reason", customisation.EmojiReason, worker.IsWhitelabel), formattedReason, false)

var rows []component.Component
for _, row := range components {
var rowElements []component.Component
for _, element := range row {
rowElements = append(rowElements, element(worker, ticket)...)
}

if len(rowElements) > 0 {
rows = append(rows, component.BuildActionRow(rowElements...))
}
}

return closeEmbed, rows
}

func BuildCloseContainer(
ctx context.Context,
cmd registry.CommandContext,
worker *worker.Context,
ticket database.Ticket,
guild *guild.Guild,
closedBy uint64,
reason *string,
rating *uint8,
components [][]CloseEmbedElement,
viewFeedbackButton bool,
) *component.Component {
var formattedReason string
if reason == nil {
formattedReason = "No reason specified"
} else {
var formattedReason = "No reason specified"
if reason != nil {
formattedReason = *reason
if len(formattedReason) > 1024 {
formattedReason = formattedReason[:1024]
Expand All @@ -225,24 +148,35 @@ func BuildCloseContainer(
}

var claimedBy string
{
claimUserId, err := dbclient.Client.TicketClaims.Get(ctx, ticket.GuildId, ticket.Id)
claimUserId, err := dbclient.Client.TicketClaims.Get(ctx, ticket.GuildId, ticket.Id)
if err != nil {
sentry.Error(err)
} else if claimUserId > 0 {
claimedBy = fmt.Sprintf("<@%d>", claimUserId)
}

var panelName string
if ticket.PanelId != nil {
p, err := dbclient.Client.Panel.GetById(ctx, *ticket.PanelId)
if err != nil {
sentry.Error(err)
}

if claimUserId == 0 {
claimedBy = ""
} else {
claimedBy = fmt.Sprintf("<@%d>", claimUserId)
} else if p.Title != "" {
panelName = p.Title
}
}

section1Text := []string{
formatRow("Ticket ID", strconv.Itoa(ticket.Id)),
section1Text := []string{}
if guild != nil {
section1Text = append(section1Text, formatRow("Server", guild.Name))
}
section1Text = append(section1Text, formatRow("Ticket ID", strconv.Itoa(ticket.Id)))
if panelName != "" {
section1Text = append(section1Text, formatRow("Panel", panelName))
}
section1Text = append(section1Text,
formatRow("Opened By", fmt.Sprintf("<@%d>", ticket.UserId)),
formatRow("Closed By", fmt.Sprintf("<@%d>", closedBy)),
}
)

section2Text := []string{
formatRow("Open Time", message.BuildTimestamp(ticket.OpenTime, message.TimestampStyleShortDateTime)),
Expand Down Expand Up @@ -277,12 +211,39 @@ func BuildCloseContainer(
Content: "## Ticket Closed",
})),
}),
component.BuildTextDisplay(component.TextDisplay{Content: strings.Join(section1Text, "\n")}),
}

sectionContent := component.BuildTextDisplay(component.TextDisplay{
Content: strings.Join(section1Text, "\n"),
})

if guild != nil && guild.Icon != "" {
section := component.Section{
Components: utils.Slice(sectionContent),
Accessory: component.BuildThumbnail(component.Thumbnail{
Media: component.UnfurledMediaItem{
Url: fmt.Sprintf("https://cdn.discordapp.com/icons/%d/%s.png", guild.Id, guild.Icon),
},
}),
}
innerComponents = append(innerComponents, component.BuildSection(section))
} else {
innerComponents = append(innerComponents, sectionContent)
}

innerComponents = append(innerComponents,
component.BuildSeparator(component.Separator{}),
component.BuildTextDisplay(component.TextDisplay{Content: strings.Join(section2Text, "\n")}),
)

if viewFeedbackButton {
innerComponents = append(innerComponents, component.BuildActionRow(
FeedbackRowElement(viewFeedbackButton)(worker, ticket)...,
))
}

if cmd.PremiumTier() == premium.None {
innerComponents = append(innerComponents, component.BuildSeparator(component.Separator{}))
innerComponents = utils.AddPremiumFooter(innerComponents)
}

Expand All @@ -308,6 +269,7 @@ func formatTitle(s string, emoji customisation.CustomEmoji, isWhitelabel bool) s

func EditGuildArchiveMessageIfExists(
ctx context.Context,
cmd registry.CommandContext,
worker *worker.Context,
ticket database.Ticket,
settings database.Settings,
Expand All @@ -325,18 +287,11 @@ func EditGuildArchiveMessageIfExists(
return nil
}

componentBuilders := [][]CloseEmbedElement{
{
TranscriptLinkElement(settings.StoreTranscripts),
ThreadLinkElement(ticket.IsThread && ticket.ChannelId != nil),
ViewFeedbackElement(viewFeedbackButton),
},
}
closeContainer := BuildCloseContainer(ctx, cmd, worker, ticket, nil, closedBy, reason, rating, viewFeedbackButton)

embed, components := BuildCloseEmbed(ctx, worker, ticket, closedBy, reason, rating, componentBuilders)
_, err = worker.EditMessage(archiveMessage.ChannelId, archiveMessage.MessageId, rest.EditMessageData{
Embeds: utils.Slice(embed),
Components: components,
Flags: uint(message.FlagComponentsV2),
Components: utils.Slice(*closeContainer),
})

return err
Expand Down