dcbot/internal/discord/command_group.go

1348 lines
42 KiB
Go

package discord
import (
"context"
"strings"
"time"
"gitea.dwysokinski.me/twhelp/dcbot/internal/discord/internal/discordi18n"
"gitea.dwysokinski.me/twhelp/dcbot/internal/domain"
"github.com/bwmarrin/discordgo"
"github.com/nicksnyder/go-i18n/v2/i18n"
"go.uber.org/zap"
)
const (
tribeTagMaxLength = 10
)
type groupCommand struct {
localizer *discordi18n.Localizer
logger *zap.Logger
groupSvc GroupService
choiceSvc *choiceService
}
func (c *groupCommand) name() string {
return "group"
}
func (c *groupCommand) register(s *discordgo.Session) error {
if err := c.create(s); err != nil {
return err
}
s.AddHandler(c.handle)
return nil
}
func (c *groupCommand) create(s *discordgo.Session) error {
var perm int64 = discordgo.PermissionAdministrator
dm := false
subcommandBuilders := []func() (*discordgo.ApplicationCommandOption, error){
c.buildSubcommandCreate,
c.buildSubcommandList,
c.buildSubcommandDetails,
c.buildSubcommandTribe,
c.buildSubcommandSet,
c.buildSubcommandDelete,
}
subcommands := make([]*discordgo.ApplicationCommandOption, 0, len(subcommandBuilders))
for _, f := range subcommandBuilders {
cmd, err := f()
if err != nil {
return err
}
subcommands = append(subcommands, cmd)
}
groupCmdDescriptionDefault, groupCmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.description")
if err != nil {
return err
}
_, err = s.ApplicationCommandCreate(s.State.User.ID, "", &discordgo.ApplicationCommand{
Name: c.name(),
Description: groupCmdDescriptionDefault,
DescriptionLocalizations: &groupCmdDescriptionLocalizations,
DefaultMemberPermissions: &perm,
DMPermission: &dm,
Options: subcommands,
})
if err != nil {
return err
}
return nil
}
func (c *groupCommand) buildSubcommandCreate() (*discordgo.ApplicationCommandOption, error) {
options, err := c.buildSubcommandCreateOptions()
if err != nil {
return nil, err
}
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.create.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "create",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: options,
}, nil
}
func (c *groupCommand) buildSubcommandCreateOptions() ([]*discordgo.ApplicationCommandOption, error) {
versionChoices, err := c.choiceSvc.versions(context.Background())
if err != nil {
return nil, err
}
languageChoices, err := c.choiceSvc.languages()
if err != nil {
return nil, err
}
optionVersionDefault, optionVersionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.create.option.version.description")
if err != nil {
return nil, err
}
optionServerDefault, optionServerLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.create.option.server.description")
if err != nil {
return nil, err
}
optionInternalsDefault, optionInternalsLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.create.option.internals.description")
if err != nil {
return nil, err
}
optionBarbariansDefault, optionBarbariansLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.create.option.barbarians.description")
if err != nil {
return nil, err
}
optionChannelGainsDefault, optionChannelGainsLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.create.option.channel-gains.description")
if err != nil {
return nil, err
}
optionLanguageDefault, optionLanguageLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.create.option.language.description")
if err != nil {
return nil, err
}
optionChannelLossesDefault, optionChannelLossesLocalizations, err := c.localizer.LocalizeDiscord(
"cmd.group.create.option.channel-losses.description",
)
if err != nil {
return nil, err
}
return []*discordgo.ApplicationCommandOption{
{
Name: "version",
Description: optionVersionDefault,
DescriptionLocalizations: optionVersionLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Choices: versionChoices,
Required: true,
},
{
Name: "server",
Description: optionServerDefault,
DescriptionLocalizations: optionServerLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
{
Name: "language",
Description: optionLanguageDefault,
DescriptionLocalizations: optionLanguageLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Choices: languageChoices,
Required: true,
},
{
Name: "internals",
Description: optionInternalsDefault,
DescriptionLocalizations: optionInternalsLocalizations,
Type: discordgo.ApplicationCommandOptionBoolean,
Required: true,
},
{
Name: "barbarians",
Description: optionBarbariansDefault,
DescriptionLocalizations: optionBarbariansLocalizations,
Type: discordgo.ApplicationCommandOptionBoolean,
Required: true,
},
{
Name: "channel-gains",
Description: optionChannelGainsDefault,
DescriptionLocalizations: optionChannelGainsLocalizations,
Type: discordgo.ApplicationCommandOptionChannel,
ChannelTypes: []discordgo.ChannelType{
discordgo.ChannelTypeGuildText,
},
Required: false,
},
{
Name: "channel-losses",
Description: optionChannelLossesDefault,
DescriptionLocalizations: optionChannelLossesLocalizations,
Type: discordgo.ApplicationCommandOptionChannel,
ChannelTypes: []discordgo.ChannelType{
discordgo.ChannelTypeGuildText,
},
Required: false,
},
}, nil
}
func (c *groupCommand) buildSubcommandList() (*discordgo.ApplicationCommandOption, error) {
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.list.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "list",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommand,
}, nil
}
func (c *groupCommand) buildSubcommandDetails() (*discordgo.ApplicationCommandOption, error) {
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.details.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "details",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "group",
Description: "Group ID",
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
},
}, nil
}
func (c *groupCommand) buildSubcommandTribe() (*discordgo.ApplicationCommandOption, error) {
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.tribe.description")
if err != nil {
return nil, err
}
subcommandAdd, err := c.buildSubcommandMonitorAdd()
if err != nil {
return nil, err
}
subcommandRemove, err := c.buildSubcommandMonitorRemove()
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "tribe",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommandGroup,
Options: []*discordgo.ApplicationCommandOption{
subcommandAdd,
subcommandRemove,
},
}, nil
}
func (c *groupCommand) buildSubcommandMonitorAdd() (*discordgo.ApplicationCommandOption, error) {
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.tribe.add.description")
if err != nil {
return nil, err
}
optionGroupDefault, optionGroupLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.tribe.add.option.group.description")
if err != nil {
return nil, err
}
optionTagDefault, optionTagLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.tribe.add.option.tag.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "add",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "group",
Description: optionGroupDefault,
DescriptionLocalizations: optionGroupLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
{
Name: "tag",
Description: optionTagDefault,
DescriptionLocalizations: optionTagLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Required: true,
MaxLength: tribeTagMaxLength,
},
},
}, nil
}
func (c *groupCommand) buildSubcommandMonitorRemove() (*discordgo.ApplicationCommandOption, error) {
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.tribe.remove.description")
if err != nil {
return nil, err
}
optionGroupDefault, optionGroupLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.tribe.remove.option.group.description")
if err != nil {
return nil, err
}
optionTagDefault, optionTagLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.tribe.remove.option.tag.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "remove",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "group",
Description: optionGroupDefault,
DescriptionLocalizations: optionGroupLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
{
Name: "tag",
Description: optionTagDefault,
DescriptionLocalizations: optionTagLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Required: true,
MaxLength: tribeTagMaxLength,
},
},
}, nil
}
func (c *groupCommand) buildSubcommandSet() (*discordgo.ApplicationCommandOption, error) {
subcommandBuilders := []func() (*discordgo.ApplicationCommandOption, error){
c.buildSubcommandSetLanguage,
c.buildSubcommandSetChannelGains,
c.buildSubcommandSetChannelLosses,
c.buildSubcommandSetInternals,
c.buildSubcommandSetBarbarians,
}
subcommands := make([]*discordgo.ApplicationCommandOption, 0, len(subcommandBuilders))
for _, f := range subcommandBuilders {
cmd, err := f()
if err != nil {
return nil, err
}
subcommands = append(subcommands, cmd)
}
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "set",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommandGroup,
Options: subcommands,
}, nil
}
func (c *groupCommand) buildSubcommandSetLanguage() (*discordgo.ApplicationCommandOption, error) {
languageChoices, err := c.choiceSvc.languages()
if err != nil {
return nil, err
}
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.language.description")
if err != nil {
return nil, err
}
optionGroupDefault, optionGroupLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.language.option.group.description")
if err != nil {
return nil, err
}
optionLanguageDefault, optionLanguageLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.language.option.language.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "language",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "group",
Description: optionGroupDefault,
DescriptionLocalizations: optionGroupLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
{
Name: "language",
Description: optionLanguageDefault,
DescriptionLocalizations: optionLanguageLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Choices: languageChoices,
Required: true,
},
},
}, nil
}
func (c *groupCommand) buildSubcommandSetChannelGains() (*discordgo.ApplicationCommandOption, error) {
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.channel-gains.description")
if err != nil {
return nil, err
}
optionGroupDefault, optionGroupLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.channel-gains.option.group.description")
if err != nil {
return nil, err
}
optionChannelDefault, optionChannelLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.channel-gains.option.channel.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "channel-gains",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "group",
Description: optionGroupDefault,
DescriptionLocalizations: optionGroupLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
{
Name: "channel",
Description: optionChannelDefault,
DescriptionLocalizations: optionChannelLocalizations,
Type: discordgo.ApplicationCommandOptionChannel,
ChannelTypes: []discordgo.ChannelType{
discordgo.ChannelTypeGuildText,
},
},
},
}, nil
}
func (c *groupCommand) buildSubcommandSetChannelLosses() (*discordgo.ApplicationCommandOption, error) {
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.channel-losses.description")
if err != nil {
return nil, err
}
optionGroupDefault, optionGroupLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.channel-losses.option.group.description")
if err != nil {
return nil, err
}
optionChannelDefault, optionChannelLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.channel-losses.option.channel.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "channel-losses",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "group",
Description: optionGroupDefault,
DescriptionLocalizations: optionGroupLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
{
Name: "channel",
Description: optionChannelDefault,
DescriptionLocalizations: optionChannelLocalizations,
Type: discordgo.ApplicationCommandOptionChannel,
ChannelTypes: []discordgo.ChannelType{
discordgo.ChannelTypeGuildText,
},
},
},
}, nil
}
func (c *groupCommand) buildSubcommandSetInternals() (*discordgo.ApplicationCommandOption, error) {
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.internals.description")
if err != nil {
return nil, err
}
optionGroupDefault, optionGroupLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.internals.option.group.description")
if err != nil {
return nil, err
}
optionInternalsDefault, optionInternalsLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.internals.option.internals.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "internals",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "group",
Description: optionGroupDefault,
DescriptionLocalizations: optionGroupLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
{
Name: "internals",
Description: optionInternalsDefault,
DescriptionLocalizations: optionInternalsLocalizations,
Type: discordgo.ApplicationCommandOptionBoolean,
Required: true,
},
},
}, nil
}
func (c *groupCommand) buildSubcommandSetBarbarians() (*discordgo.ApplicationCommandOption, error) {
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.barbarians.description")
if err != nil {
return nil, err
}
optionGroupDefault, optionGroupLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.barbarians.option.group.description")
if err != nil {
return nil, err
}
optionBarbariansDefault, optionBarbariansLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.set.barbarians.option.barbarians.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "barbarians",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "group",
Description: optionGroupDefault,
DescriptionLocalizations: optionGroupLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
{
Name: "barbarians",
Description: optionBarbariansDefault,
DescriptionLocalizations: optionBarbariansLocalizations,
Type: discordgo.ApplicationCommandOptionBoolean,
Required: true,
},
},
}, nil
}
func (c *groupCommand) buildSubcommandDelete() (*discordgo.ApplicationCommandOption, error) {
cmdDescriptionDefault, cmdDescriptionLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.delete.description")
if err != nil {
return nil, err
}
optionGroupDefault, optionGroupLocalizations, err := c.localizer.LocalizeDiscord("cmd.group.delete.option.group.description")
if err != nil {
return nil, err
}
return &discordgo.ApplicationCommandOption{
Name: "delete",
Description: cmdDescriptionDefault,
DescriptionLocalizations: cmdDescriptionLocalizations,
Type: discordgo.ApplicationCommandOptionSubCommand,
Options: []*discordgo.ApplicationCommandOption{
{
Name: "group",
Description: optionGroupDefault,
DescriptionLocalizations: optionGroupLocalizations,
Type: discordgo.ApplicationCommandOptionString,
Required: true,
},
},
}, nil
}
func (c *groupCommand) handle(s *discordgo.Session, i *discordgo.InteractionCreate) {
if i.Type != discordgo.InteractionApplicationCommand {
return
}
cmdData := i.ApplicationCommandData()
if cmdData.Name != c.name() {
return
}
ctx := context.Background()
name := cmdData.Options[0].Name
switch name {
case "create":
c.handleCreate(ctx, s, i)
case "list":
c.handleList(ctx, s, i)
case "details":
c.handleDetails(ctx, s, i)
case "set":
c.handleSet(ctx, s, i)
case "tribe":
c.handleTribe(ctx, s, i)
case "delete":
c.handleDelete(ctx, s, i)
default:
c.logger.Error("unknown subcommand", zap.String("command", "group"), zap.String("subcommand", name))
}
}
func (c *groupCommand) handleCreate(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
locale := string(i.Locale)
params, err := c.optionsToCreateGroupParams(s, i.GuildID, i.ApplicationCommandData().Options[0].Options)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
group, err := c.groupSvc.Create(ctx, params)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
successMessageID := "cmd.group.create.success"
successMsg, err := c.localizer.Localize(locale, &i18n.LocalizeConfig{
MessageID: successMessageID,
TemplateData: map[string]any{
"GroupID": group.ID,
},
})
if err != nil {
c.logger.Error("no message with the specified id", zap.String("id", successMessageID), zap.Error(err))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: successMsg,
},
})
}
func (c *groupCommand) optionsToCreateGroupParams(
s *discordgo.Session,
guildID string,
options []*discordgo.ApplicationCommandInteractionDataOption,
) (domain.CreateGroupParams, error) {
version := ""
server := ""
channelGains := ""
channelLosses := ""
internals := false
barbarians := false
languageTag := ""
for _, opt := range options {
switch opt.Name {
case "version":
version = opt.StringValue()
case "server":
server = opt.StringValue()
case "language":
languageTag = opt.StringValue()
case "channel-gains":
channelGains = opt.ChannelValue(s).ID
case "channel-losses":
channelLosses = opt.ChannelValue(s).ID
case "internals":
internals = opt.BoolValue()
case "barbarians":
barbarians = opt.BoolValue()
}
}
return domain.NewCreateGroupParams(
guildID,
version,
server,
languageTag,
channelGains,
channelLosses,
barbarians,
internals,
)
}
func (c *groupCommand) handleList(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
locale := string(i.Locale)
groups, err := c.groupSvc.ListServer(ctx, i.GuildID)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
fieldValueMessageID := "cmd.group.list.embed.field.value"
fields := make([]*discordgo.MessageEmbedField, 0, len(groups))
for _, g := range groups {
channelGains := "-"
if g.ChannelGains != "" {
channelGains = buildChannelMention(g.ChannelGains)
}
channelLosses := "-"
if g.ChannelLosses != "" {
channelLosses = buildChannelMention(g.ChannelLosses)
}
langMessageID := buildLangMessageID(g.LanguageTag)
lang, localizeErr := c.localizer.Localize(locale, &i18n.LocalizeConfig{
MessageID: langMessageID,
})
if localizeErr != nil {
c.logger.Error("no message with the specified id", zap.String("id", langMessageID), zap.Error(localizeErr))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, localizeErr),
},
})
return
}
fieldValue, localizeErr := c.localizer.Localize(locale, &i18n.LocalizeConfig{
MessageID: fieldValueMessageID,
TemplateData: map[string]any{
"ServerKey": g.ServerKey,
"ChannelGains": channelGains,
"ChannelLosses": channelLosses,
"Internals": boolToEmoji(g.Internals),
"Barbarians": boolToEmoji(g.Barbarians),
"NumTribes": len(g.Monitors),
"Language": lang,
},
})
if localizeErr != nil {
c.logger.Error("no message with the specified id", zap.String("id", fieldValueMessageID), zap.Error(localizeErr))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, localizeErr),
},
})
return
}
fields = append(fields, &discordgo.MessageEmbedField{
Name: g.ID,
Value: fieldValue,
Inline: false,
})
}
titleMessageID := "cmd.group.list.embed.title"
title, err := c.localizer.Localize(locale, &i18n.LocalizeConfig{MessageID: titleMessageID})
if err != nil {
c.logger.Error("no message with the specified id", zap.String("id", titleMessageID), zap.Error(err))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Embeds: []*discordgo.MessageEmbed{
{
Type: discordgo.EmbedTypeRich,
Title: title,
Fields: fields,
Color: colorGrey,
Timestamp: formatTimestamp(time.Now()),
},
},
},
})
}
func (c *groupCommand) handleDetails(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
locale := string(i.Locale)
g, err := c.groupSvc.GetWithTribes(ctx, i.ApplicationCommandData().Options[0].Options[0].StringValue(), i.GuildID)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
var builderTribes strings.Builder
for i, m := range g.Monitors {
if i > 0 {
builderTribes.WriteString(" ")
}
builderTribes.WriteString(buildLink(m.Tribe.Tag, m.Tribe.ProfileURL))
}
if builderTribes.Len() == 0 {
builderTribes.WriteString("-")
}
channelGains := "-"
if g.ChannelGains != "" {
channelGains = buildChannelMention(g.ChannelGains)
}
channelLosses := "-"
if g.ChannelLosses != "" {
channelLosses = buildChannelMention(g.ChannelLosses)
}
langMessageID := buildLangMessageID(g.LanguageTag)
lang, localizeErr := c.localizer.Localize(locale, &i18n.LocalizeConfig{
MessageID: langMessageID,
})
if localizeErr != nil {
c.logger.Error("no message with the specified id", zap.String("id", langMessageID), zap.Error(localizeErr))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, localizeErr),
},
})
return
}
descriptionMessageID := "cmd.group.details.embed.description"
description, err := c.localizer.Localize(locale, &i18n.LocalizeConfig{
MessageID: descriptionMessageID,
TemplateData: map[string]any{
"ServerKey": g.ServerKey,
"ChannelGains": channelGains,
"ChannelLosses": channelLosses,
"Internals": boolToEmoji(g.Internals),
"Barbarians": boolToEmoji(g.Barbarians),
"Tribes": builderTribes.String(),
"Language": lang,
},
})
if err != nil {
c.logger.Error("no message with the specified id", zap.String("id", descriptionMessageID), zap.Error(err))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Embeds: []*discordgo.MessageEmbed{
{
Type: discordgo.EmbedTypeRich,
Title: g.ID,
Description: description,
Color: colorGrey,
Timestamp: formatTimestamp(time.Now()),
},
},
},
})
}
func (c *groupCommand) handleSet(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
name := i.ApplicationCommandData().Options[0].Options[0].Name
switch name {
case "language":
c.handleSetLanguage(ctx, s, i)
case "channel-gains":
c.handleSetChannelGains(ctx, s, i)
case "channel-losses":
c.handleSetChannelLosses(ctx, s, i)
case "internals":
c.handleSetInternals(ctx, s, i)
case "barbarians":
c.handleSetBarbarians(ctx, s, i)
default:
c.logger.Error("unknown subcommand", zap.String("command", "group set"), zap.String("subcommand", name))
}
}
func (c *groupCommand) handleSetLanguage(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
locale := string(i.Locale)
group := ""
languageTag := ""
for _, opt := range i.ApplicationCommandData().Options[0].Options[0].Options {
if opt == nil {
continue
}
switch opt.Name {
case "group":
group = opt.StringValue()
case "language":
languageTag = opt.StringValue()
}
}
_, err := c.groupSvc.SetLanguageTag(ctx, group, i.GuildID, languageTag)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
successMessageID := "cmd.group.set.language.success"
successMsg, err := c.localizer.Localize(locale, &i18n.LocalizeConfig{MessageID: successMessageID})
if err != nil {
c.logger.Error("no message with the specified id", zap.String("id", successMessageID), zap.Error(err))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: successMsg,
},
})
}
func (c *groupCommand) handleSetChannelGains(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
locale := string(i.Locale)
group := ""
channel := ""
for _, opt := range i.ApplicationCommandData().Options[0].Options[0].Options {
if opt == nil {
continue
}
switch opt.Name {
case "group":
group = opt.StringValue()
case "channel":
channel = opt.ChannelValue(s).ID
}
}
_, err := c.groupSvc.SetChannelGains(ctx, group, i.GuildID, channel)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
successMessageID := "cmd.group.set.channel-gains.success"
successMsg, err := c.localizer.Localize(locale, &i18n.LocalizeConfig{MessageID: successMessageID})
if err != nil {
c.logger.Error("no message with the specified id", zap.String("id", successMessageID), zap.Error(err))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: successMsg,
},
})
}
func (c *groupCommand) handleSetChannelLosses(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
locale := string(i.Locale)
group := ""
channel := ""
for _, opt := range i.ApplicationCommandData().Options[0].Options[0].Options {
if opt == nil {
continue
}
switch opt.Name {
case "group":
group = opt.StringValue()
case "channel":
channel = opt.ChannelValue(s).ID
}
}
_, err := c.groupSvc.SetChannelLosses(ctx, group, i.GuildID, channel)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
successMessageID := "cmd.group.set.channel-losses.success"
successMsg, err := c.localizer.Localize(locale, &i18n.LocalizeConfig{MessageID: successMessageID})
if err != nil {
c.logger.Error("no message with the specified id", zap.String("id", successMessageID), zap.Error(err))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: successMsg,
},
})
}
func (c *groupCommand) handleSetInternals(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
locale := string(i.Locale)
group := ""
internals := false
for _, opt := range i.ApplicationCommandData().Options[0].Options[0].Options {
if opt == nil {
continue
}
switch opt.Name {
case "group":
group = opt.StringValue()
case "internals":
internals = opt.BoolValue()
}
}
_, err := c.groupSvc.SetInternals(ctx, group, i.GuildID, internals)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
successMessageID := "cmd.group.set.internals.success"
successMsg, err := c.localizer.Localize(locale, &i18n.LocalizeConfig{MessageID: successMessageID})
if err != nil {
c.logger.Error("no message with the specified id", zap.String("id", successMessageID), zap.Error(err))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: successMsg,
},
})
}
func (c *groupCommand) handleSetBarbarians(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
locale := string(i.Locale)
group := ""
barbarians := false
for _, opt := range i.ApplicationCommandData().Options[0].Options[0].Options {
if opt == nil {
continue
}
switch opt.Name {
case "group":
group = opt.StringValue()
case "barbarians":
barbarians = opt.BoolValue()
}
}
_, err := c.groupSvc.SetBarbarians(ctx, group, i.GuildID, barbarians)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
successMessageID := "cmd.group.set.barbarians.success"
successMsg, err := c.localizer.Localize(locale, &i18n.LocalizeConfig{MessageID: successMessageID})
if err != nil {
c.logger.Error("no message with the specified id", zap.String("id", successMessageID), zap.Error(err))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: successMsg,
},
})
}
func (c *groupCommand) handleTribe(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
name := i.ApplicationCommandData().Options[0].Options[0].Name
switch name {
case "add":
c.handleTribeAdd(ctx, s, i)
case "remove":
c.handleTribeRemove(ctx, s, i)
default:
c.logger.Error("unknown subcommand", zap.String("command", "group tribe"), zap.String("subcommand", name))
}
}
func (c *groupCommand) handleTribeAdd(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
locale := string(i.Locale)
group := ""
tag := ""
for _, opt := range i.ApplicationCommandData().Options[0].Options[0].Options {
if opt == nil {
continue
}
switch opt.Name {
case "group":
group = opt.StringValue()
case "tag":
tag = opt.StringValue()
}
}
_, err := c.groupSvc.AddTribe(ctx, group, i.GuildID, tag)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
successMessageID := "cmd.group.tribe.add.success"
successMsg, err := c.localizer.Localize(locale, &i18n.LocalizeConfig{MessageID: successMessageID})
if err != nil {
c.logger.Error("no message with the specified id", zap.String("id", successMessageID), zap.Error(err))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: successMsg,
},
})
}
func (c *groupCommand) handleTribeRemove(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
locale := string(i.Locale)
group := ""
tag := ""
for _, opt := range i.ApplicationCommandData().Options[0].Options[0].Options {
if opt == nil {
continue
}
switch opt.Name {
case "group":
group = opt.StringValue()
case "tag":
tag = opt.StringValue()
}
}
_, err := c.groupSvc.RemoveTribe(ctx, group, i.GuildID, tag)
if err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
successMessageID := "cmd.group.tribe.remove.success"
successMsg, err := c.localizer.Localize(locale, &i18n.LocalizeConfig{MessageID: successMessageID})
if err != nil {
c.logger.Error("no message with the specified id", zap.String("id", successMessageID), zap.Error(err))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: successMsg,
},
})
}
func (c *groupCommand) handleDelete(ctx context.Context, s *discordgo.Session, i *discordgo.InteractionCreate) {
locale := string(i.Locale)
group := i.ApplicationCommandData().Options[0].Options[0].StringValue()
if err := c.groupSvc.Delete(ctx, group, i.GuildID); err != nil {
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
successMessageID := "cmd.group.delete.success"
successMsg, err := c.localizer.Localize(locale, &i18n.LocalizeConfig{MessageID: successMessageID})
if err != nil {
c.logger.Error("no message with the specified id", zap.String("id", successMessageID), zap.Error(err))
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: c.localizer.LocalizeError(locale, err),
},
})
return
}
_ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: successMsg,
},
})
}