From 077054109f3db6a082f28542713b61fef1d7025f Mon Sep 17 00:00:00 2001 From: vaporvee Date: Mon, 15 Apr 2024 18:17:12 +0200 Subject: [PATCH] finished plugin system base --- build_plugins.py | 15 + cmd/go.sum | 24 - cmd_addemoji.go | 95 ---- cmd_autojoinroles.go | 75 --- cmd_autopublish.go | 49 -- cmd_blockpolls.go | 88 --- cmd_form.go | 474 ---------------- cmd_ping.go | 65 --- cmd_sticky.go | 118 ---- cmd_tag.go | 194 ------- .../example_plugin => example/plugin}/main.go | 19 +- go.mod | 4 +- go.sum | 4 +- handlers.go | 139 +---- main.go | 93 +++- manage_data.go | 514 ----------------- plugin_src/addemoji/main.go | 115 ++++ plugin_src/autojoinroles/data.go | 60 ++ plugin_src/autojoinroles/listener.go | 17 + plugin_src/autojoinroles/main.go | 127 +++++ plugin_src/autopublish/data.go | 34 ++ plugin_src/autopublish/listener.go | 23 + plugin_src/autopublish/main.go | 76 +++ plugin_src/blockpolls/data.go | 93 ++++ plugin_src/blockpolls/listener.go | 27 + plugin_src/blockpolls/main.go | 156 ++++++ plugin_src/forms/data.go | 154 ++++++ plugin_src/forms/main.go | 515 ++++++++++++++++++ plugin_src/forms/tool.go | 15 + plugin_src/info/main.go | 6 +- plugin_src/simplefun/cmd_ask.go | 4 +- plugin_src/simplefun/cmd_cat.go | 4 +- plugin_src/simplefun/cmd_dadjoke.go | 4 +- plugin_src/simplefun/go.mod | 20 - plugin_src/simplefun/main.go | 36 +- plugin_src/simplefun/tool.go | 34 -- plugin_src/stickymessages/data.go | 62 +++ plugin_src/stickymessages/listener.go | 33 ++ plugin_src/stickymessages/main.go | 145 +++++ plugin_src/tags/cmd_tag.go | 217 ++++++++ plugin_src/tags/data.go | 70 +++ .../form_templates}/form_demo.json | 0 .../form_templates}/template_general.json | 0 .../form_templates}/template_ticket.json | 0 .../form_templates}/template_url.json | 0 {cmd => shared}/go.mod | 3 +- {plugin_src/simplefun => shared}/go.sum | 4 - {cmd => shared}/main.go | 8 +- shared/tool.go | 114 ++++ tool.go | 230 -------- web/html/privacy.html | 2 +- 51 files changed, 2218 insertions(+), 2160 deletions(-) create mode 100644 build_plugins.py delete mode 100644 cmd/go.sum delete mode 100644 cmd_addemoji.go delete mode 100644 cmd_autojoinroles.go delete mode 100644 cmd_autopublish.go delete mode 100644 cmd_blockpolls.go delete mode 100644 cmd_form.go delete mode 100644 cmd_ping.go delete mode 100644 cmd_sticky.go delete mode 100644 cmd_tag.go rename {plugin_src/example_plugin => example/plugin}/main.go (58%) delete mode 100644 manage_data.go create mode 100644 plugin_src/addemoji/main.go create mode 100644 plugin_src/autojoinroles/data.go create mode 100644 plugin_src/autojoinroles/listener.go create mode 100644 plugin_src/autojoinroles/main.go create mode 100644 plugin_src/autopublish/data.go create mode 100644 plugin_src/autopublish/listener.go create mode 100644 plugin_src/autopublish/main.go create mode 100644 plugin_src/blockpolls/data.go create mode 100644 plugin_src/blockpolls/listener.go create mode 100644 plugin_src/blockpolls/main.go create mode 100644 plugin_src/forms/data.go create mode 100644 plugin_src/forms/main.go create mode 100644 plugin_src/forms/tool.go delete mode 100644 plugin_src/simplefun/go.mod delete mode 100644 plugin_src/simplefun/tool.go create mode 100644 plugin_src/stickymessages/data.go create mode 100644 plugin_src/stickymessages/listener.go create mode 100644 plugin_src/stickymessages/main.go create mode 100644 plugin_src/tags/cmd_tag.go create mode 100644 plugin_src/tags/data.go rename {form_templates => shared/form_templates}/form_demo.json (100%) rename {form_templates => shared/form_templates}/template_general.json (100%) rename {form_templates => shared/form_templates}/template_ticket.json (100%) rename {form_templates => shared/form_templates}/template_url.json (100%) rename {cmd => shared}/go.mod (82%) rename {plugin_src/simplefun => shared}/go.sum (85%) rename {cmd => shared}/main.go (80%) create mode 100644 shared/tool.go delete mode 100644 tool.go diff --git a/build_plugins.py b/build_plugins.py new file mode 100644 index 0000000..7164b34 --- /dev/null +++ b/build_plugins.py @@ -0,0 +1,15 @@ +import os +import subprocess + +src_dir = './plugin_src' +output_dir = './plugins' + +if not os.path.exists(output_dir): + os.makedirs(output_dir) + +for folder_name in os.listdir(src_dir): + folder_path = os.path.join(src_dir, folder_name) + if os.path.isdir(folder_path): + command = f'go build -buildmode=plugin -o {output_dir}/{folder_name}.so {folder_path}' + subprocess.run(command, shell=True, check=True) + print(f'Built plugin: {folder_name}.so') diff --git a/cmd/go.sum b/cmd/go.sum deleted file mode 100644 index 27287ae..0000000 --- a/cmd/go.sum +++ /dev/null @@ -1,24 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/disgoorg/disgo v0.18.2 h1:pZCvaFamfHcnXrj0XA73qtVofP0R8dYEyQfPNgv8dLE= -github.com/disgoorg/disgo v0.18.2/go.mod h1:gkl6DBdbKUvmOOJayWPSvS52KPN/8uJGJ2f13gCEB1o= -github.com/disgoorg/json v1.1.0 h1:7xigHvomlVA9PQw9bMGO02PHGJJPqvX5AnwlYg/Tnys= -github.com/disgoorg/json v1.1.0/go.mod h1:BHDwdde0rpQFDVsRLKhma6Y7fTbQKub/zdGO5O9NqqA= -github.com/disgoorg/snowflake/v2 v2.0.1 h1:CuUxGLwggUxEswZOmZ+mZ5i0xSumQdXW9tXW7uGqe+0= -github.com/disgoorg/snowflake/v2 v2.0.1/go.mod h1:SPU9c2CNn5DSyb86QcKtdZgix9osEtKrHLW4rMhfLCs= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad h1:qIQkSlF5vAUHxEmTbaqt1hkJ/t6skqEGYiMag343ucI= -github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad/go.mod h1:/pA7k3zsXKdjjAiUhB5CjuKib9KJGCaLvZwtxGC8U0s= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cmd_addemoji.go b/cmd_addemoji.go deleted file mode 100644 index f1548e2..0000000 --- a/cmd_addemoji.go +++ /dev/null @@ -1,95 +0,0 @@ -package main - -import ( - "bytes" - "io" - "net/http" - "regexp" - "strings" - - "github.com/disgoorg/disgo/discord" - "github.com/disgoorg/disgo/events" - "github.com/disgoorg/json" - "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" -) - -var cmd_addemoji cmd.Command = cmd.Command{ - Definition: discord.SlashCommandCreate{ - Name: "add-emoji", - Description: "Add an external emoji directly to the server.", - DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageGuildExpressions), - Options: []discord.ApplicationCommandOption{ - &discord.ApplicationCommandOptionString{ - Name: "emoji", - Description: "The emoji you want to add", - Required: true, - }, - }, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - emojiRegex := regexp.MustCompile(`<(.+):(\d+)>`) - emojistring := emojiRegex.FindString(e.SlashCommandInteractionData().String("emoji")) - emojiArray := strings.Split(emojistring, ":") - var emojiName string - var emojiID string - var emojiFileName string - if len(emojiArray) > 1 { - emojiName = strings.TrimSuffix(emojiArray[1], ">") - emojiID = strings.TrimSuffix(emojiArray[2], ">") - } - imageType, emojiReadBit64 := getEmoji(emojiID) - emojiData, err := discord.NewIcon(imageType, emojiReadBit64) - if err != nil { - logrus.Error(err) - } - _, err = e.Client().Rest().CreateEmoji(*e.GuildID(), discord.EmojiCreate{ - Name: emojiName, - Image: *emojiData, - }) - if err != nil { - if strings.HasPrefix(err.Error(), "50035") { - e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Failed adding emoji. Did you provide a correct one?").SetEphemeral(true).Build()) - return - } - if strings.HasPrefix(err.Error(), "50138") { - e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Failed adding emoji. Unable to resize the emoji image.").SetEphemeral(true).Build()) - return - } - logrus.Error(err) - return - } - if imageType == discord.IconTypeGIF { - emojiFileName = emojiName + ".gif" - } else { - emojiFileName = emojiName + ".png" - } - _, emojiRead := getEmoji(emojiID) // for some reason any []bit variable thats used with NewIcon gets corrupted even when its redeclared in a new variable - err = e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContentf("Emoji %s sucessfully added to this server!", emojiName).SetFiles(discord.NewFile(emojiFileName, "", emojiRead)).SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - }, -} - -func getEmoji(emojiID string) (discord.IconType, io.Reader) { - resp, err := http.Get("https://cdn.discordapp.com/emojis/" + emojiID) - if err != nil { - logrus.Error(err) - return discord.IconTypePNG, nil - } - defer resp.Body.Close() - imageData, err := io.ReadAll(resp.Body) - if err != nil { - logrus.Error(err) - return discord.IconTypePNG, nil - } - isAnimated := isGIFImage(imageData) - if isAnimated { - return discord.IconTypeGIF, bytes.NewReader(imageData) - } else { - return discord.IconTypePNG, bytes.NewReader(imageData) - } -} diff --git a/cmd_autojoinroles.go b/cmd_autojoinroles.go deleted file mode 100644 index 13772c9..0000000 --- a/cmd_autojoinroles.go +++ /dev/null @@ -1,75 +0,0 @@ -package main - -import ( - "github.com/disgoorg/disgo/discord" - "github.com/disgoorg/disgo/events" - "github.com/disgoorg/json" - "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" -) - -var cmd_autojoinroles cmd.Command = cmd.Command{ - Definition: discord.SlashCommandCreate{ - Name: "autojoinroles", - Description: "Give users a role when they join", - DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageRoles), - Contexts: []discord.InteractionContextType{ - discord.InteractionContextTypeGuild, - discord.InteractionContextTypePrivateChannel}, - IntegrationTypes: []discord.ApplicationIntegrationType{ - discord.ApplicationIntegrationTypeGuildInstall}, - Options: []discord.ApplicationCommandOption{ - &discord.ApplicationCommandOptionSubCommand{ - Name: "bot", - Description: "Give bots a role when they join (Leave empty to remove current)", - Options: []discord.ApplicationCommandOption{ - &discord.ApplicationCommandOptionRole{ - Name: "role", - Description: "The role bots should get when they join the server", - }, - }, - }, - &discord.ApplicationCommandOptionSubCommand{ - Name: "user", - Description: "Give users a role when they join (Leave empty to remove current)", - Options: []discord.ApplicationCommandOption{ - &discord.ApplicationCommandOptionRole{ - Name: "role", - Description: "The role users should get when they join the server", - }}, - }, - }, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - var role string - option := *e.SlashCommandInteractionData().SubCommandName - var content string - if len(e.SlashCommandInteractionData().Options) == 1 { - var givenRole discord.Role = e.SlashCommandInteractionData().Role("role") - role = givenRole.ID.String() - botrole, err := getHighestRole(e.GuildID().String(), e.Client()) - if err != nil { - logrus.Error(err) - } - if givenRole.Position >= botrole.Position { - content = "<@&" + role + "> is not below the Bot's current highest role(<@&" + botrole.ID.String() + ">). That makes it unable to manage it." - } else { - if setAutoJoinRole(e.GuildID().String(), option, role) { - content = "Updated auto join role for " + option + "s as <@&" + role + ">" - } else { - content = "Setup auto join role for " + option + "s as <@&" + role + ">" - } - } - } else if setAutoJoinRole(e.GuildID().String(), option, role) { - content = "Deleted auto join role for " + option + "s" - } - if content == "" { - content = "No auto join role set for " + option + "s to delete." - } - err := e.CreateMessage(discord.NewMessageCreateBuilder().SetContent(content).SetEphemeral(true).Build()) - if err != nil { - logrus.Error(err) - } - purgeUnusedAutoJoinRoles(e.GuildID().String()) - }, -} diff --git a/cmd_autopublish.go b/cmd_autopublish.go deleted file mode 100644 index 3f27e4e..0000000 --- a/cmd_autopublish.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "github.com/disgoorg/disgo/discord" - "github.com/disgoorg/disgo/events" - "github.com/disgoorg/json" - "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" -) - -var cmd_autopublish cmd.Command = cmd.Command{ - Definition: discord.SlashCommandCreate{ - Name: "autopublish", - Description: "Toggle automatically publishing every post in a announcement channel", - DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageChannels), - Contexts: []discord.InteractionContextType{ - discord.InteractionContextTypeGuild, - discord.InteractionContextTypePrivateChannel}, - IntegrationTypes: []discord.ApplicationIntegrationType{ - discord.ApplicationIntegrationTypeGuildInstall}, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - channel := e.Channel() - if channel.Type() == discord.ChannelTypeGuildNews { - if toggleAutoPublish(e.GuildID().String(), e.Channel().ID().String()) { - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Autopublishing is now disabled on " + discord.ChannelMention(e.Channel().ID())).SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } else { - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Autopublishing is now enabled on " + discord.ChannelMention(e.Channel().ID())).SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } - } else { - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("This is not an announcement channel!").SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } - }, -} diff --git a/cmd_blockpolls.go b/cmd_blockpolls.go deleted file mode 100644 index 3c5d1d9..0000000 --- a/cmd_blockpolls.go +++ /dev/null @@ -1,88 +0,0 @@ -package main - -import ( - "github.com/disgoorg/disgo/discord" - "github.com/disgoorg/disgo/events" - "github.com/disgoorg/json" - "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" -) - -var cmd_blockpolls cmd.Command = cmd.Command{ - Definition: discord.SlashCommandCreate{ - Name: "block-polls", - Description: "Block polls from beeing posted in this channel.", - DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageChannels), - Contexts: []discord.InteractionContextType{ - discord.InteractionContextTypeGuild, - discord.InteractionContextTypePrivateChannel}, - IntegrationTypes: []discord.ApplicationIntegrationType{ - discord.ApplicationIntegrationTypeGuildInstall}, - Options: []discord.ApplicationCommandOption{ - &discord.ApplicationCommandOptionSubCommand{ - Name: "toggle", - Description: "Toggle blocking polls from beeing posted in this channel.", - Options: []discord.ApplicationCommandOption{ - &discord.ApplicationCommandOptionBool{ - Name: "global", - Description: "If polls are blocked server wide or only in the current channel.", - }, - &discord.ApplicationCommandOptionRole{ - Name: "allowed-role", - Description: "The role that bypasses this block role.", - }, - }, - }, - /*&discord.ApplicationCommandOptionSubCommand{ - Name: "list", - Description: "List the current block polls rules for this server.", - },*/ - }, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - switch *e.SlashCommandInteractionData().SubCommandName { - case "toggle": - isGlobal := isGlobalBlockPolls(e.GuildID().String()) - if isGlobal && !e.SlashCommandInteractionData().Bool("global") { - e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Polls are currently globally blocked. Disable global blocking to enable channel specific blocking.").SetEphemeral(true).Build()) - } else { - exists, isGlobal := toggleBlockPolls(e.GuildID().String(), e.Channel().ID().String(), e.SlashCommandInteractionData().Bool("global"), e.SlashCommandInteractionData().Role("allowed-role").ID.String()) - if exists { - if e.SlashCommandInteractionData().Bool("global") { - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Polls are now globally unblocked.").SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } else { - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Polls are now unblocked in " + discord.ChannelMention(e.Channel().ID())).SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } - } else { - if isGlobal { - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Polls are now globally blocked.").SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } else { - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Polls are now blocked in " + discord.ChannelMention(e.Channel().ID())).SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } - } - } - /*case "list": - list := listBlockPolls(e.GuildID().String())*/ - } - }, -} diff --git a/cmd_form.go b/cmd_form.go deleted file mode 100644 index 0f21678..0000000 --- a/cmd_form.go +++ /dev/null @@ -1,474 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "strings" - - "github.com/disgoorg/disgo/bot" - "github.com/disgoorg/disgo/discord" - "github.com/disgoorg/disgo/events" - "github.com/disgoorg/json" - "github.com/disgoorg/snowflake/v2" - "github.com/google/uuid" - "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" - "github.com/vaporvee/acecore/custom" -) - -var cmd_form cmd.Command = cmd.Command{ - Definition: discord.SlashCommandCreate{ - Name: "form", - DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageChannels), - Description: "Create custom forms right inside Discord", - Contexts: []discord.InteractionContextType{ - discord.InteractionContextTypeGuild, - discord.InteractionContextTypePrivateChannel}, - IntegrationTypes: []discord.ApplicationIntegrationType{ - discord.ApplicationIntegrationTypeGuildInstall}, - Options: []discord.ApplicationCommandOption{ - &discord.ApplicationCommandOptionSubCommand{ - Name: "help", - Description: "Gives you an example file and demo for creating custom forms", - }, - &discord.ApplicationCommandOptionSubCommand{ - Name: "custom", - Description: "Create a new custom form right inside Discord", - Options: []discord.ApplicationCommandOption{ - &discord.ApplicationCommandOptionAttachment{ - Name: "json", - Description: "Your edited form file", - Required: true, - }, - }, - }, - &discord.ApplicationCommandOptionSubCommand{ - Name: "add", - Description: "Adds existing forms to this channel", - Options: []discord.ApplicationCommandOption{ - &discord.ApplicationCommandOptionChannel{ - Name: "result_channel", - Description: "Where the form results should appear", - ChannelTypes: []discord.ChannelType{discord.ChannelTypeGuildText}, - }, - &discord.ApplicationCommandOptionMentionable{ - Name: "moderator", - Description: "Who can interact with moderating buttons.", - }, - &discord.ApplicationCommandOptionString{ - Name: "type", - Description: "Which type of form you want to add", - Autocomplete: true, - }, - &discord.ApplicationCommandOptionString{ - Name: "title", - Description: "The title the form should have", - }, - &discord.ApplicationCommandOptionChannel{ - Name: "approve_channel", - Description: "Channel for results that need to be accepted by a moderator before sending it to the result channel", - ChannelTypes: []discord.ChannelType{discord.ChannelTypeGuildText}, - }, - &discord.ApplicationCommandOptionBool{ - Name: "mods_can_answer", - Description: "Moderators can open a new channel on the form result, which then pings the user who submitted it", - }, - }, - }, - }, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - switch *e.SlashCommandInteractionData().SubCommandName { - case "help": - fileData, err := formTemplates.ReadFile("form_templates/form_demo.json") - if err != nil { - logrus.Error(err) - return - } - fileReader := bytes.NewReader(fileData) - err = e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("NOT SUPPORTED YET!(use `/form add` instead)\n\nGet the example file edit it (make sure to have a unique \"form_type\") and submit it via `/form create`.\nOr use the demo button to get an idea of how the example would look like."). - SetFiles(discord.NewFile("example.json", "json", fileReader)). - SetContainerComponents(discord.ActionRowComponent{discord.NewPrimaryButton("Demo", "form_demo").WithEmoji(discord.ComponentEmoji{Name: "📑"})}).SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - case "custom": - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Feature not available yet use `/form add` instead").SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - case "add": - var title, formID, overwriteTitle, acceptChannelID string - var modsCanAnswer bool - var resultChannelID string - data := e.SlashCommandInteractionData() - if data.Channel("result_channel").ID.String() != "0" { - resultChannelID = data.Channel("result_channel").ID.String() - } - moderator := data.Role("moderator").ID.String() - if moderator == "0" { - moderator = e.User().ID.String() - } - formID = data.String("type") - overwriteTitle = data.String("title") - if overwriteTitle != "" { - title = overwriteTitle - } - if data.Channel("approve_channel").ID.String() != "0" { - acceptChannelID = data.Channel("approve_channel").ID.String() - } - modsCanAnswer = data.Bool("mods_can_answer") - - if formID == "" { - formID = "template_general" - } - if title == "" { - formTitles := map[string]string{ - "template_ticket": "Make a new ticket", - "template_url": "Add your URL", - "template_general": "Form", - } - if val, ok := formTitles[formID]; ok { - title = val - } - } - var exists bool = true - var formManageID uuid.UUID = uuid.New() - for exists { - formManageID = uuid.New() - exists = getFormManageIdExists(formManageID) - } - messagebuild := discord.NewMessageCreateBuilder().SetEmbeds(discord.NewEmbedBuilder(). - SetTitle(title).SetDescription("Press the bottom button to open a form popup.").SetColor(custom.GetColor("primary")). - Build()).SetContainerComponents(discord.ActionRowComponent{ - discord.NewSuccessButton("Submit", "form:"+formManageID.String()).WithEmoji(discord.ComponentEmoji{ - Name: "anim_rocket", - ID: snowflake.MustParse("1215740398706757743"), - Animated: true, - })}). - Build() - message, err := e.Client().Rest().CreateMessage(e.Channel().ID(), messagebuild) - if err != nil { - logrus.Error(err) - } - var category string - if modsCanAnswer { - c, err := e.Client().Rest().CreateGuildChannel(*e.GuildID(), discord.GuildCategoryChannelCreate{Name: title + " mod answers"}) - if err != nil { - logrus.Error(err) - } - category = c.ID().String() - } - - addFormButton(e.GuildID().String(), e.Channel().ID().String(), message.ID.String(), formManageID.String(), formID, resultChannelID, overwriteTitle, acceptChannelID, category, moderator) - err = e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Successfully added form button!").SetEphemeral(true).Build()) - if err != nil { - logrus.Error(err) - } - } - }, - DynamicComponentIDs: func() []string { return getFormButtonIDs() }, - DynamicModalIDs: func() []string { return getFormButtonIDs() }, - ComponentInteract: func(e *events.ComponentInteractionCreate) { - if e.Data.Type() == discord.ComponentTypeButton { - if strings.ContainsAny(e.ButtonInteractionData().CustomID(), ";") { - var form_manage_id string = strings.TrimPrefix(strings.Split(e.ButtonInteractionData().CustomID(), ";")[0], "form:") - switch strings.Split(e.ButtonInteractionData().CustomID(), ";")[1] { - case "decline": - err := e.Client().Rest().DeleteMessage(e.Channel().ID(), e.Message.ID) - if err != nil { - logrus.Error(err) - } - e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Submission declined!").SetEphemeral(true).Build()) - case "approve": - embed := e.Message.Embeds[0] - embed.Description = fmt.Sprintf("This submission was approved by <@%s>.", e.User().ID) - _, err := e.Client().Rest().CreateMessage(snowflake.MustParse(getFormResultValues(form_manage_id).ResultChannelID), discord.NewMessageCreateBuilder(). - SetEmbeds(embed). - Build()) - if err != nil { - logrus.Error(err) - } - e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Submission accepted!").SetEphemeral(true).Build()) - err = e.Client().Rest().DeleteMessage(e.Channel().ID(), e.Message.ID) - if err != nil { - logrus.Error(err) - } - case "comment": - author := strings.TrimSuffix(strings.Split(e.Message.Embeds[0].Fields[len(e.Message.Embeds[0].Fields)-1].Value, "<@")[1], ">") - embed := e.Message.Embeds[0] - moderator := e.User().ID - channel := createFormComment(form_manage_id, snowflake.MustParse(author), moderator, "answer", embed, *e.GuildID(), e.Client()) - e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Created channel " + discord.ChannelMention(channel.ID())).SetEphemeral(true).Build()) - } - } else { - if strings.HasPrefix(e.ButtonInteractionData().CustomID(), "form:") { - var formManageID string = strings.TrimPrefix(e.ButtonInteractionData().CustomID(), "form:") - e.Modal(jsonStringBuildModal(e.User().ID.String(), formManageID, getFormType(formManageID), getFormOverwriteTitle(formManageID))) - } else if e.ButtonInteractionData().CustomID() == "form_demo" { - e.Modal(jsonStringBuildModal(e.User().ID.String(), "form_demo", "form_demo")) - } - } - } - }, - ModalSubmit: func(e *events.ModalSubmitInteractionCreate) { - if !strings.HasPrefix(e.Data.CustomID, "form_demo") { - var form_manage_id string = strings.Split(e.Data.CustomID, ":")[1] - var result FormResult = getFormResultValues(form_manage_id) - var fields []discord.EmbedField - var modal ModalJson = getModalByFormID(getFormType(form_manage_id)) - var overwrite_title string = getFormOverwriteTitle(form_manage_id) - if overwrite_title != "" { - modal.Title = overwrite_title - } - var inline bool - var index int = 0 - for _, component := range e.Data.Components { - var input discord.TextInputComponent = component.(discord.TextInputComponent) - inline = input.Style == discord.TextInputStyleShort - fields = append(fields, discord.EmbedField{ - Name: modal.Form[index].Label, - Value: input.Value, - Inline: &inline, - }) - index++ - } - - fields = append(fields, discord.EmbedField{ - Value: "From <#" + e.Channel().ID().String() + "> by " + e.User().Mention(), - }) - if result.ResultChannelID == "" { - if result.CommentCategoryID != "" { - channel := createFormComment(form_manage_id, e.User().ID, snowflake.MustParse(result.ModeratorID), "answer", discord.NewEmbedBuilder(). - SetAuthorName(*e.User().GlobalName).SetAuthorIcon(*e.User().AvatarURL()).SetTitle("\""+modal.Title+"\"").SetDescription("This is the submitted result"). - SetColor(custom.GetColor("primary")).SetFields(fields...). - Build(), *e.GuildID(), e.Client()) - err := e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Created channel " + discord.ChannelMention(channel.ID())).SetEphemeral(true).Build()) - if err != nil { - logrus.Error(err) - } - } else { - e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("You need to provide either a `result_channel` or enable `mods_can_answer` to create a valid form.").SetEphemeral(true). - Build()) - } - } else { - if result.AcceptChannelID == "" { - _, err := e.Client().Rest().CreateMessage(snowflake.MustParse(result.ResultChannelID), discord.NewMessageCreateBuilder(). - SetEmbeds(discord.NewEmbedBuilder(). - SetAuthorName(*e.User().GlobalName).SetAuthorIcon(*e.User().AvatarURL()).SetTitle("\""+modal.Title+"\"").SetDescription("This is the submitted result"). - SetColor(custom.GetColor("primary")).SetFields(fields...). - Build()). - SetContainerComponents(discord.NewActionRow(discord. - NewButton(discord.ButtonStylePrimary, "Comment", "form:"+form_manage_id+";comment", ""). - WithEmoji(discord.ComponentEmoji{Name: "👥"}))). - Build()) - if err != nil { - logrus.Error(err) - } else { - err = e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Submitted!").SetEphemeral(true).Build()) - if err != nil { - logrus.Error(err) - } - } - } else { - var buttons []discord.InteractiveComponent - if result.CommentCategoryID != "" { - buttons = []discord.InteractiveComponent{discord. - NewButton(discord.ButtonStylePrimary, "Comment", "form:"+form_manage_id+";comment", ""). - WithEmoji(discord.ComponentEmoji{Name: "👥"})} - } - buttons = append(buttons, discord. - NewButton(discord.ButtonStyleDanger, "Decline", "form:"+form_manage_id+";decline", ""). - WithEmoji(discord.ComponentEmoji{Name: "🛑"}), - discord. - NewButton(discord.ButtonStyleSuccess, "Approve", "form:"+form_manage_id+";approve", ""). - WithEmoji(discord.ComponentEmoji{Name: "🎉"})) - _, err := e.Client().Rest().CreateMessage(snowflake.MustParse(result.AcceptChannelID), discord.NewMessageCreateBuilder(). - SetEmbeds(discord.NewEmbedBuilder(). - SetAuthorName(*e.User().GlobalName).SetAuthorIcon(*e.User().AvatarURL()).SetTitle("\""+modal.Title+"\"").SetDescription("**This submission needs approval.**"). - SetColor(custom.GetColor("primary")).SetFields(fields...). - Build()). - SetContainerComponents(discord.NewActionRow(buttons...)). - Build()) - - if err != nil { - logrus.Error(err) - } else { - err = e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Submitted!").SetEphemeral(true).Build()) - if err != nil { - logrus.Error(err) - } - } - } - } - } else { - err := e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("The results would be submited...").SetEphemeral(true).Build()) - if err != nil { - logrus.Error(err) - } - } - - }, - Autocomplete: func(e *events.AutocompleteInteractionCreate) { - err := e.AutocompleteResult([]discord.AutocompleteChoice{ - &discord.AutocompleteChoiceString{ - Name: "Support Ticket", - Value: "template_ticket", - }, - &discord.AutocompleteChoiceString{ - Name: "Submit URL", - Value: "template_url", - }, - &discord.AutocompleteChoiceString{ - Name: "General", - Value: "template_general", - }, - }) - if err != nil { - logrus.Error(err) - } - }, -} - -var cmd_ticket_form cmd.Command = cmd.Command{ - Definition: discord.SlashCommandCreate{ - Name: "ticket", - DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageChannels), - Description: "A quick command to create Ticketpanels. (/form for more)", - Contexts: []discord.InteractionContextType{ - discord.InteractionContextTypeGuild, - discord.InteractionContextTypePrivateChannel}, - Options: []discord.ApplicationCommandOption{ - &discord.ApplicationCommandOptionString{ - Name: "title", - Description: "The title the ticket should have", - }, - &discord.ApplicationCommandOptionMentionable{ - Name: "moderator", - Description: "Who can interact with moderating buttons.", - }, - }, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - var title string = "Ticket" - var moderator string - data := e.SlashCommandInteractionData() - if data.String("title") != "" { - title = data.String("title") - } - moderator = data.Role("moderator").ID.String() - if moderator == "" { - moderator = data.User("moderator").ID.String() - } - var exists bool = true - var formManageID uuid.UUID = uuid.New() - for exists { - formManageID = uuid.New() - exists = getFormManageIdExists(formManageID) - } - messagebuild := discord.NewMessageCreateBuilder().SetEmbeds(discord.NewEmbedBuilder(). - SetTitle(title).SetDescription("Press the bottom button to open a form popup.").SetColor(custom.GetColor("primary")). - Build()).SetContainerComponents(discord.ActionRowComponent{ - discord.NewSuccessButton("Submit", "form:"+formManageID.String()).WithEmoji(discord.ComponentEmoji{ - Name: "anim_rocket", - ID: snowflake.MustParse("1215740398706757743"), - Animated: true, - })}). - Build() - message, err := e.Client().Rest().CreateMessage(e.Channel().ID(), messagebuild) - if err != nil { - logrus.Error(err) - return - } - if title == "" { - title = "Ticket" - } - var category string - c, err := e.Client().Rest().CreateGuildChannel(*e.GuildID(), discord.GuildCategoryChannelCreate{Name: title + " mod answers"}) - if err != nil { - logrus.Error(err) - } - category = c.ID().String() - if title == "Ticket" { - title = "" - } - - addFormButton(e.GuildID().String(), e.Channel().ID().String(), message.ID.String(), formManageID.String(), "template_ticket", "", title, "", category, moderator) - err = e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Successfully added ticket panel!\n(`/form` for more options or custom ticket forms.)").SetEphemeral(true).Build()) - if err != nil { - logrus.Error(err) - } - }, -} - -// moderator can be userID as well as roleID -func createFormComment(form_manage_id string, author snowflake.ID, moderator snowflake.ID, commentName string, embed discord.Embed, guildID snowflake.ID, client bot.Client) discord.Channel { - var category snowflake.ID = snowflake.MustParse(getFormResultValues(form_manage_id).CommentCategoryID) - _, err := client.Rest().GetChannel(category) - if err != nil { - c, err := client.Rest().CreateGuildChannel(guildID, discord.GuildCategoryChannelCreate{Name: strings.Trim(embed.Title, "\"") + " mod " + commentName + "s"}) - if err != nil { - logrus.Error(err) - } - category = c.ID() - updateFormCommentCategory(form_manage_id, category.String()) - } - ch, err := client.Rest().CreateGuildChannel(guildID, discord.GuildTextChannelCreate{ - ParentID: category, - Name: strings.ToLower(embed.Author.Name) + "-" + commentName, - }) - if err != nil { - logrus.Error(err) - } - var permissionOverwrites []discord.PermissionOverwrite = []discord.PermissionOverwrite{ - discord.RolePermissionOverwrite{ - RoleID: guildID, - Deny: discord.PermissionViewChannel, - }} - - if isIDRole(client, guildID, moderator) { - permissionOverwrites = append(permissionOverwrites, discord.RolePermissionOverwrite{ - RoleID: moderator, - Allow: discord.PermissionViewChannel, - }) - } else { - permissionOverwrites = append(permissionOverwrites, discord.MemberPermissionOverwrite{ - UserID: moderator, - Allow: discord.PermissionViewChannel, - }) - } - permissionOverwrites = append(permissionOverwrites, discord.RolePermissionOverwrite{ - RoleID: author, - Allow: discord.PermissionViewChannel, - }) - _, err = client.Rest().UpdateChannel(ch.ID(), discord.GuildTextChannelUpdate{PermissionOverwrites: &permissionOverwrites}) - if err != nil { - logrus.Error(err) - } - modTypeChar := "" - if isIDRole(client, guildID, moderator) { - modTypeChar = "&" - } - embed.Description = "This was submitted" - _, err = client.Rest().CreateMessage(ch.ID(), discord.NewMessageCreateBuilder(). - SetContent("<@"+modTypeChar+moderator.String()+"> <@"+author.String()+">").SetEmbeds(embed). - Build()) - if err != nil { - logrus.Error(err) - } - return ch -} - -func getFormButtonIDs() []string { - var IDs []string = []string{"form_demo"} - var formButtonIDs []string = getFormManageIDs() - for _, buttonID := range formButtonIDs { - IDs = append(IDs, "form:"+buttonID) - } - return IDs -} diff --git a/cmd_ping.go b/cmd_ping.go deleted file mode 100644 index 04ce645..0000000 --- a/cmd_ping.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import ( - "fmt" - "net/http" - "time" - - "github.com/disgoorg/disgo/discord" - "github.com/disgoorg/disgo/events" - "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" - "github.com/vaporvee/acecore/custom" -) - -var cmd_ping cmd.Command = cmd.Command{ - Definition: discord.SlashCommandCreate{ - Name: "ping", - Description: "Returns the ping of the bot", - Contexts: []discord.InteractionContextType{ - discord.InteractionContextTypeGuild, - discord.InteractionContextTypePrivateChannel, - discord.InteractionContextTypeBotDM, - }, - IntegrationTypes: []discord.ApplicationIntegrationType{ - discord.ApplicationIntegrationTypeGuildInstall, - discord.ApplicationIntegrationTypeUserInstall, - }, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - start := time.Now() - - client := http.Client{ - Timeout: 5 * time.Second, - } - - resp, err := client.Get("https://discord.com/api/v9/gateway/bot") - if err != nil { - logrus.Error(err) - return - } - defer resp.Body.Close() - - ping := time.Since(start) - var pingColor string - if ping.Milliseconds() < 200 { - pingColor = "green" - } else if ping.Milliseconds() < 400 { - pingColor = "yellow" - } else { - pingColor = "red" - } - app, err := e.Client().Rest().GetCurrentApplication() - if err != nil { - logrus.Error(err) - } - err = e.CreateMessage(discord.NewMessageCreateBuilder(). - SetEmbeds(discord.NewEmbedBuilder(). - SetTitle(app.Bot.Username + " ping"). - SetDescription(fmt.Sprintf("# %.2fms", ping.Seconds()*1000)). - SetColor(custom.GetColor(pingColor)).Build()).SetEphemeral(true).Build()) - if err != nil { - logrus.Error(err) - } - }, -} diff --git a/cmd_sticky.go b/cmd_sticky.go deleted file mode 100644 index c81e095..0000000 --- a/cmd_sticky.go +++ /dev/null @@ -1,118 +0,0 @@ -package main - -import ( - "github.com/disgoorg/disgo/discord" - "github.com/disgoorg/disgo/events" - "github.com/disgoorg/json" - "github.com/disgoorg/snowflake/v2" - "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" - "github.com/vaporvee/acecore/custom" -) - -var cmd_sticky cmd.Command = cmd.Command{ - Definition: discord.SlashCommandCreate{ - Name: "sticky", - Description: "Stick or unstick messages to the bottom of the current channel", - DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageMessages), - Contexts: []discord.InteractionContextType{ - discord.InteractionContextTypeGuild, - discord.InteractionContextTypePrivateChannel}, - IntegrationTypes: []discord.ApplicationIntegrationType{ - discord.ApplicationIntegrationTypeGuildInstall}, - Options: []discord.ApplicationCommandOption{ - &discord.ApplicationCommandOptionString{ - Name: "message", - Description: "The message you want to stick to the bottom of this channel", - Required: false, - }, - }, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - if len(e.SlashCommandInteractionData().Options) == 0 { - if hasSticky(e.GuildID().String(), e.Channel().ID().String()) { - err := e.Client().Rest().DeleteMessage(e.Channel().ID(), snowflake.MustParse(getStickyMessageID(e.GuildID().String(), e.Channel().ID().String()))) - if err != nil { - logrus.Error(err) - } - removeSticky(e.GuildID().String(), e.Channel().ID().String()) - err = e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("The sticky message was removed from this channel!").SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } else { - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("This channel has no sticky message!").SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } - } else { - inputStickyMessage(e) - } - }, -} - -var context_sticky cmd.Command = cmd.Command{ - Definition: discord.MessageCommandCreate{ - Name: "Stick to channel", - DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageMessages), - Contexts: []discord.InteractionContextType{ - discord.InteractionContextTypeGuild, - discord.InteractionContextTypePrivateChannel}, - IntegrationTypes: []discord.ApplicationIntegrationType{ - discord.ApplicationIntegrationTypeGuildInstall}, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - inputStickyMessage(e) - }, -} - -func inputStickyMessage(e *events.ApplicationCommandInteractionCreate) { - var messageText string - if e.ApplicationCommandInteraction.Data.Type() == discord.ApplicationCommandTypeMessage { - messageText = e.MessageCommandInteractionData().TargetMessage().Content //TODO add more data then just content - } else { - messageText = e.SlashCommandInteractionData().String("message") - } - if messageText == "" { - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Can't add empty sticky messages!").SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } else { - message, err := e.Client().Rest().CreateMessage(e.Channel().ID(), discord.MessageCreate{Embeds: []discord.Embed{ - {Description: messageText, Footer: &discord.EmbedFooter{Text: "📌 Sticky message"}, Color: custom.GetColor("primary")}}}) - if err != nil { - logrus.Error(err) - } - - if hasSticky(e.GuildID().String(), e.Channel().ID().String()) { - err = e.Client().Rest().DeleteMessage(e.Channel().ID(), snowflake.MustParse(getStickyMessageID(e.GuildID().String(), e.Channel().ID().String()))) - if err != nil { - logrus.Error(err, getStickyMessageID(e.GuildID().String(), e.Channel().ID().String())) - } - removeSticky(e.GuildID().String(), e.Channel().ID().String()) - addSticky(e.GuildID().String(), e.Channel().ID().String(), messageText, message.ID.String()) - err = e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Sticky message in this channel was updated!").SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } else { - addSticky(e.GuildID().String(), e.Channel().ID().String(), messageText, message.ID.String()) - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Message sticked to the channel!").SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } - } -} diff --git a/cmd_tag.go b/cmd_tag.go deleted file mode 100644 index 2ae0d05..0000000 --- a/cmd_tag.go +++ /dev/null @@ -1,194 +0,0 @@ -package main - -import ( - "github.com/disgoorg/disgo/discord" - "github.com/disgoorg/disgo/events" - "github.com/disgoorg/json" - "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" -) - -// TODO: make user installable tag command using userIDs instead of guildIDs -var cmd_tag cmd.Command = cmd.Command{ - Definition: discord.SlashCommandCreate{ - Name: "tag", - DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageGuild), - Description: "A command to show and edit saved presaved messages.", - Contexts: []discord.InteractionContextType{ - discord.InteractionContextTypeGuild, - discord.InteractionContextTypePrivateChannel}, - IntegrationTypes: []discord.ApplicationIntegrationType{ - discord.ApplicationIntegrationTypeGuildInstall}, - Options: []discord.ApplicationCommandOption{ - discord.ApplicationCommandOptionSubCommand{ - Name: "get", - Description: "A command to get messages saved to the bot.", - Options: []discord.ApplicationCommandOption{ - discord.ApplicationCommandOptionString{ - Name: "tag", - Description: "Your predefined tag for the saved message", - Required: true, - Autocomplete: true, - }, - }, - }, - discord.ApplicationCommandOptionSubCommand{ - Name: "add", - Description: "A command to add messages saved to the bot.", - }, - discord.ApplicationCommandOptionSubCommand{ - Name: "remove", - Description: "A command to remove messages saved to the bot.", - Options: []discord.ApplicationCommandOption{ - discord.ApplicationCommandOptionString{ - Name: "tag", - Description: "The tag you want to remove", - Required: true, - Autocomplete: true, - }, - }, - }, - }, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - switch *e.SlashCommandInteractionData().SubCommandName { - case "get": - GetTagCommand(e) - case "add": - AddTagCommand(e) - case "remove": - removeTag(e.GuildID().String(), e.SlashCommandInteractionData().String("tag")) - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Tag removed!").SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - } - }, - ModalIDs: []string{"tag_add_modal"}, - ModalSubmit: func(e *events.ModalSubmitInteractionCreate) { - tagName := e.Data.Text("tag_add_modal_name") - tagContent := e.Data.Text("tag_add_modal_content") - addTag(e.GuildID().String(), tagName, tagContent) - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent("Tag \"" + tagName + "\" added!").SetEphemeral(true). - Build()) - if err != nil { - logrus.Error(err) - } - }, - Autocomplete: func(e *events.AutocompleteInteractionCreate) { - AutocompleteTag(e) - }, -} - -var cmd_tag_short cmd.Command = cmd.Command{ - Definition: discord.SlashCommandCreate{ - Name: "g", - Description: "A short command to get presaved messages.", - Contexts: []discord.InteractionContextType{ - discord.InteractionContextTypeGuild, - discord.InteractionContextTypePrivateChannel}, - IntegrationTypes: []discord.ApplicationIntegrationType{ - discord.ApplicationIntegrationTypeGuildInstall}, - Options: []discord.ApplicationCommandOption{ - discord.ApplicationCommandOptionString{ - Name: "tag", - Description: "Your predefined tag for the saved message", - Required: true, - Autocomplete: true, - }, - }, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - GetTagCommand(e) - }, - Autocomplete: func(e *events.AutocompleteInteractionCreate) { - AutocompleteTag(e) - }, -} - -var context_tag cmd.Command = cmd.Command{ - Definition: discord.MessageCommandCreate{ - Name: "Save as tag", - DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageGuild), - Contexts: []discord.InteractionContextType{ - discord.InteractionContextTypeGuild, - discord.InteractionContextTypePrivateChannel}, - IntegrationTypes: []discord.ApplicationIntegrationType{ - discord.ApplicationIntegrationTypeGuildInstall}, - }, - Interact: func(e *events.ApplicationCommandInteractionCreate) { - AddTagCommand(e) - }, -} - -func GetTagCommand(e *events.ApplicationCommandInteractionCreate) { - err := e.CreateMessage(discord.NewMessageCreateBuilder(). - SetContent(getTagContent(e.GuildID().String(), e.SlashCommandInteractionData().String("tag"))). - Build()) - if err != nil { - logrus.Error(err) - } -} - -func AddTagCommand(e *events.ApplicationCommandInteractionCreate) { - var prevalue string - if e.ApplicationCommandInteraction.Data.Type() == discord.ApplicationCommandTypeMessage { - prevalue = e.MessageCommandInteractionData().TargetMessage().Content - } - err := e.Modal(discord.ModalCreate{ - CustomID: "tag_add_modal" + e.User().ID.String(), - Title: "Add a custom tag command", - Components: []discord.ContainerComponent{ - discord.ActionRowComponent{ - discord.TextInputComponent{ - CustomID: "tag_add_modal_name", - Label: "Name", - Style: discord.TextInputStyleShort, - Required: true, - MaxLength: 20, - Value: "", - }, - }, - discord.ActionRowComponent{ - discord.TextInputComponent{ - CustomID: "tag_add_modal_content", - Label: "Content", - Style: discord.TextInputStyleParagraph, - Required: true, - MaxLength: 2000, - Value: prevalue, - }, - }, - }, - }) - if err != nil { - logrus.Error(err) - } -} - -func AutocompleteTag(e *events.AutocompleteInteractionCreate) { - err := e.AutocompleteResult(generateTagChoices(e.GuildID().String())) - if err != nil { - logrus.Error(err) - } -} - -func generateTagChoices(guildID string) []discord.AutocompleteChoice { - choices := []discord.AutocompleteChoice{} - IDs, err := getTagIDs(guildID) - if err != nil { - logrus.Error(err) - return choices - } - for _, id := range IDs { - id_name := getTagName(guildID, id) - choices = append(choices, &discord.AutocompleteChoiceString{ - Name: id_name, - Value: id, - }) - } - return choices -} diff --git a/plugin_src/example_plugin/main.go b/example/plugin/main.go similarity index 58% rename from plugin_src/example_plugin/main.go rename to example/plugin/main.go index 77885c5..9407ce4 100644 --- a/plugin_src/example_plugin/main.go +++ b/example/plugin/main.go @@ -1,23 +1,22 @@ package main import ( + "database/sql" + "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" - "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" + "github.com/vaporvee/acecore/shared" ) -var Plugin = &cmd.Plugin{ +var db *sql.DB + +var Plugin = &shared.Plugin{ Name: "testplugin", - Register: func(e *events.Ready) error { - app, err := e.Client().Rest().GetCurrentApplication() - if err != nil { - return err - } - logrus.Infof("%s has a working plugin called \"testplugin\"", app.Bot.Username) + Init: func(d *sql.DB) error { + db = d return nil }, - Commands: []cmd.Command{ + Commands: []shared.Command{ { Definition: discord.SlashCommandCreate{ Name: "testplugincommand", diff --git a/go.mod b/go.mod index bfc7c71..e20558c 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/joho/godotenv v1.5.1 github.com/lib/pq v1.10.9 github.com/sirupsen/logrus v1.9.3 - github.com/vaporvee/acecore/cmd v0.0.0-20240414204205-9ac9f89071f6 + github.com/vaporvee/acecore/shared v0.0.0-20240414204205-9ac9f89071f6 ) require ( @@ -20,3 +20,5 @@ require ( golang.org/x/net v0.21.0 // indirect golang.org/x/sys v0.17.0 // indirect ) + +replace github.com/vaporvee/acecore/shared => ./shared \ No newline at end of file diff --git a/go.sum b/go.sum index e7c91f4..014935c 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/vaporvee/acecore/cmd v0.0.0-20240414204205-9ac9f89071f6 h1:QyVs7R8dTS5KEnOjUbTV2jFe7VqGyi8q4krdjy8f9j0= -github.com/vaporvee/acecore/cmd v0.0.0-20240414204205-9ac9f89071f6/go.mod h1:03W2NrAPbAqa7gsqAM+2K/wT28stj9BmEhC5NzeGe3A= +github.com/vaporvee/acecore/shared v0.0.0-20240414204205-9ac9f89071f6 h1:QyVs7R8dTS5KEnOjUbTV2jFe7VqGyi8q4krdjy8f9j0= +github.com/vaporvee/acecore/shared v0.0.0-20240414204205-9ac9f89071f6/go.mod h1:03W2NrAPbAqa7gsqAM+2K/wT28stj9BmEhC5NzeGe3A= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= diff --git a/handlers.go b/handlers.go index 19e6b2d..c183e38 100644 --- a/handlers.go +++ b/handlers.go @@ -3,31 +3,22 @@ package main import ( "fmt" "os" - "path/filepath" - "plugin" - "runtime" "slices" "strings" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" - "github.com/disgoorg/snowflake/v2" "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" - "github.com/vaporvee/acecore/custom" + + "github.com/vaporvee/acecore/shared" ) -var commands []cmd.Command = []cmd.Command{cmd_tag, cmd_tag_short, context_tag, cmd_sticky, context_sticky, cmd_ping, cmd_addemoji, cmd_form, cmd_ticket_form, cmd_blockpolls, cmd_autopublish, cmd_autojoinroles} +var commands []shared.Command func ready(e *events.Ready) { logrus.Info("Starting up...") - findAndDeleteUnusedMessages(e.Client()) removeOldCommandFromAllGuilds(e.Client()) - err := loadPlugins("plugins/", e) - if err != nil { - logrus.Warn(err) - } var existingCommandNames []string existingCommands, err := e.Client().Rest().GetGlobalCommands(e.Client().ApplicationID(), false) if err != nil { @@ -56,68 +47,6 @@ func ready(e *events.Ready) { logrus.Info("Successfully started the Bot!") } -func loadPlugins(directory string, e *events.Ready) error { - files, err := os.ReadDir(directory) - if err != nil { - return err - } - - // Determine the appropriate file extension for dynamic libraries - var ext string - switch runtime.GOOS { - case "windows": - ext = ".dll" - case "linux": - ext = ".so" - case "darwin": - ext = ".dylib" - default: - return fmt.Errorf("unsupported operating system: %s", runtime.GOOS) - } - - for _, file := range files { - if filepath.Ext(file.Name()) == ext { - p, err := plugin.Open(filepath.Join(directory, file.Name())) - if err != nil { - return err - } - - symPlugin, err := p.Lookup("Plugin") - if err != nil { - logrus.Errorf("Error looking up symbol 'Plugin' in %s: %v", file.Name(), err) - continue - } - - pluginPtr, ok := symPlugin.(**cmd.Plugin) - if !ok { - logrus.Errorf("Plugin does not match expected type") - continue - } - - plugin := *pluginPtr - if plugin.Name == "" { - logrus.Warn("Plugin is unnamed") - } - if plugin.Commands != nil { - commands = append(commands, plugin.Commands...) - } else { - logrus.Errorf("Plugin %s has no commands set", plugin.Name) - continue - } - if plugin.Register != nil { - err = plugin.Register(e, db) - if err != nil { - logrus.Errorf("Error running plugin register %s function: %v", plugin.Name, err) - continue - } - } - - } - } - - return nil -} - func applicationCommandInteractionCreate(e *events.ApplicationCommandInteractionCreate) { for _, command := range commands { if command.Interact != nil && e.Data.CommandName() == command.Definition.CommandName() { @@ -202,65 +131,3 @@ func removeOldCommandFromAllGuilds(c bot.Client) { } } } - -func messageCreate(e *events.MessageCreate) { - if len(e.Message.Embeds) == 0 || e.Message.Embeds[0].Footer == nil || e.Message.Embeds[0].Footer.Text != "📌 Sticky message" { - if hasSticky(e.Message.GuildID.String(), e.Message.ChannelID.String()) { - stickymessageID := getStickyMessageID(e.Message.GuildID.String(), e.Message.ChannelID.String()) - err := e.Client().Rest().DeleteMessage(e.ChannelID, snowflake.MustParse(stickymessageID)) - stickyMessage, _ := e.Client().Rest().CreateMessage(e.ChannelID, discord.MessageCreate{ - Embeds: []discord.Embed{ - { - Footer: &discord.EmbedFooter{ - Text: "📌 Sticky message", - }, - Color: custom.GetColor("primary"), - Description: getStickyMessageContent(e.Message.GuildID.String(), e.Message.ChannelID.String()), - }, - }, - }) - if err != nil { - logrus.Error(err) - } - updateStickyMessageID(e.Message.GuildID.String(), e.Message.ChannelID.String(), stickyMessage.ID.String()) - } - } - channel, err := e.Client().Rest().GetChannel(e.Message.ChannelID) - if err != nil { - logrus.Error(err) - } - if channel != nil { - isBlockPollsEnabledGlobal := isGlobalBlockPolls(e.GuildID.String()) - isBlockPollsEnabled, allowedRole := getBlockPollsEnabled(e.GuildID.String(), e.Message.ChannelID.String()) - var hasAllowedRole bool - if allowedRole != "" { - hasAllowedRole = slices.Contains(e.Message.Member.RoleIDs, snowflake.MustParse(allowedRole)) - } - if (isBlockPollsEnabledGlobal || isBlockPollsEnabled) && !hasAllowedRole && messageIsPoll(e.Message.ChannelID.String(), e.Message.ID.String(), e.Client()) { - e.Client().Rest().DeleteMessage(e.Message.ChannelID, e.Message.ID) - } - if channel.Type() == discord.ChannelTypeGuildNews { - if isAutopublishEnabled(e.GuildID.String(), e.ChannelID.String()) { - _, err := e.Client().Rest().CrosspostMessage(e.ChannelID, e.MessageID) - if err != nil { - logrus.Error(err) - return - } - } - } - } -} - -func messageDelete(e *events.MessageDelete) { //TODO: also clear on bot start when message doesn't exist - tryDeleteUnusedMessage(e.MessageID.String()) -} - -func guildMemberJoin(e *events.GuildMemberJoin) { - role := getAutoJoinRole(e.GuildID.String(), e.Member.User.Bot) - if role != "" { - err := e.Client().Rest().AddMemberRole(e.GuildID, e.Member.User.ID, snowflake.MustParse(role)) - if err != nil { - logrus.Error(err) - } - } -} diff --git a/main.go b/main.go index fd62121..e415c7c 100644 --- a/main.go +++ b/main.go @@ -3,10 +3,14 @@ package main import ( "context" "database/sql" + "fmt" "io" "net/url" "os" "os/signal" + "path/filepath" + "plugin" + "runtime" "strconv" "syscall" "time" @@ -19,6 +23,7 @@ import ( "github.com/joho/godotenv" "github.com/sirupsen/logrus" "github.com/vaporvee/acecore/log2webhook" + "github.com/vaporvee/acecore/shared" "github.com/vaporvee/acecore/web" ) @@ -26,6 +31,8 @@ var ( db *sql.DB ) +var listeners []func() + func main() { logrusInitFile() var err error @@ -35,8 +42,16 @@ func main() { if err != nil { logrus.Fatal(err) } - initTables() - client, err := disgo.New(os.Getenv("BOT_TOKEN"), + err = loadPlugins("plugins/") + if err != nil { + logrus.Warn(err) + } + shared.BotConfigs = append(shared.BotConfigs, + bot.WithEventListenerFunc(ready), + bot.WithEventListenerFunc(applicationCommandInteractionCreate), + bot.WithEventListenerFunc(autocompleteInteractionCreate), + bot.WithEventListenerFunc(componentInteractionCreate), + bot.WithEventListenerFunc(modalSubmitInteractionCreate), bot.WithGatewayConfigOpts( gateway.WithIntents( gateway.IntentGuilds, @@ -45,15 +60,9 @@ func main() { gateway.IntentGuildMembers, gateway.IntentDirectMessages, ), - ), - bot.WithEventListenerFunc(ready), - bot.WithEventListenerFunc(applicationCommandInteractionCreate), - bot.WithEventListenerFunc(autocompleteInteractionCreate), - bot.WithEventListenerFunc(componentInteractionCreate), - bot.WithEventListenerFunc(modalSubmitInteractionCreate), - bot.WithEventListenerFunc(messageCreate), - bot.WithEventListenerFunc(messageDelete), - bot.WithEventListenerFunc(guildMemberJoin), + )) + client, err := disgo.New(os.Getenv("BOT_TOKEN"), + shared.BotConfigs..., ) if err != nil { logrus.Fatal("error creating Discord session,", err) @@ -102,3 +111,65 @@ func logrusInitFile() { mw := io.MultiWriter(os.Stdout, log, &log2webhook.WebhookWriter{}) logrus.SetOutput(mw) } + +func loadPlugins(directory string) error { + files, err := os.ReadDir(directory) + if err != nil { + return err + } + + // Determine the appropriate file extension for dynamic libraries + var ext string + switch runtime.GOOS { + case "windows": + ext = ".dll" + case "linux": + ext = ".so" + case "darwin": + ext = ".dylib" + default: + return fmt.Errorf("unsupported operating system: %s", runtime.GOOS) + } + + for _, file := range files { + if filepath.Ext(file.Name()) == ext { + p, err := plugin.Open(filepath.Join(directory, file.Name())) + if err != nil { + return err + } + + symPlugin, err := p.Lookup("Plugin") + if err != nil { + logrus.Errorf("Error looking up symbol 'Plugin' in %s: %v", file.Name(), err) + continue + } + + pluginPtr, ok := symPlugin.(**shared.Plugin) + if !ok { + logrus.Errorf("Plugin does not match expected type") + continue + } + + plugin := *pluginPtr + if plugin.Name == "" { + logrus.Warn("Plugin is unnamed") + } + if plugin.Commands != nil { + commands = append(commands, plugin.Commands...) + } else { + logrus.Errorf("Plugin %s has no commands set", plugin.Name) + continue + } + if plugin.Init != nil { + err = plugin.Init(db) + if err != nil { + logrus.Errorf("Error running plugin register %s function: %v", plugin.Name, err) + continue + } + } + + } + } + + return nil +} diff --git a/manage_data.go b/manage_data.go deleted file mode 100644 index b07136d..0000000 --- a/manage_data.go +++ /dev/null @@ -1,514 +0,0 @@ -package main - -import ( - "log" - "os" - "slices" - - "github.com/google/uuid" - "github.com/sirupsen/logrus" -) - -func initTables() { - createTableQuery := `CREATE TABLE IF NOT EXISTS tags ( - tag_id TEXT NOT NULL, - tag_name TEXT NOT NULL, - tag_content TEXT NOT NULL, - guild_id TEXT NOT NULL, - PRIMARY KEY (tag_id, guild_id) - ); - CREATE TABLE IF NOT EXISTS sticky ( - message_id TEXT NOT NULL, - channel_id TEXT NOT NULL, - message_content TEXT NOT NULL, - guild_id TEXT NOT NULL, - PRIMARY KEY (channel_id, guild_id) - ); - CREATE TABLE IF NOT EXISTS custom_forms ( - form_type TEXT NOT NULL, - title TEXT NOT NULL, - json JSON NOT NULL, - guild_id TEXT NOT NULL, - PRIMARY KEY (form_type, guild_id) - ); - CREATE TABLE IF NOT EXISTS form_manage ( - form_manage_id TEXT NOT NULL, - form_type TEXT NOT NULL, - overwrite_title TEXT, - message_id TEXT NOT NULL, - channel_id TEXT NOT NULL, - guild_id TEXT NOT NULL, - result_channel_id TEXT NOT NULL, - accept_channel_id TEXT, - comment_category TEXT, - moderator_id TEXT, - PRIMARY KEY (form_manage_id, form_type) - ); - CREATE TABLE IF NOT EXISTS autojoinroles ( - guild_id TEXT NOT NULL, - bot_role TEXT, - user_role TEXT, - PRIMARY KEY (guild_id) - ); - CREATE TABLE IF NOT EXISTS autopublish ( - guild_id TEXT NOT NULL, - news_channel_id TEXT NOT NULL, - PRIMARY KEY (guild_id, news_channel_id) - ); - CREATE TABLE IF NOT EXISTS blockpolls ( - guild_id TEXT NOT NULL, - channel_id TEXT, - global BOOLEAN, - allowed_role TEXT, - PRIMARY KEY (guild_id) - ) - ` - _, err := db.Exec(createTableQuery) - if err != nil { - log.Fatal(err) - } - if slices.Contains(os.Args, "--form-db-update") { - _, err = db.Exec("ALTER TABLE blockpolls ADD global BOOLEAN;") - if err != nil { - log.Fatal(err) - } - _, err = db.Exec("ALTER TABLE blockpolls ADD allowed_role TEXT;") - if err != nil { - log.Fatal(err) - } - } -} - -type FormResult struct { - OverwriteTitle string - ResultChannelID string - AcceptChannelID string - CommentCategoryID string - ModeratorID string -} - -type BlockPoll struct { - ChannelID string - Global bool - AllowedRole string -} - -func addTag(guildID, tagName, tagContent string) bool { - var exists bool = true - //TODO: add modify command - id := uuid.New() - for exists { - id = uuid.New() - err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM tags WHERE guild_id = $1 AND tag_id = $2)", guildID, id).Scan(&exists) - if err != nil { - logrus.Error(err) - } - } - _, err := db.Exec("INSERT INTO tags (guild_id, tag_name, tag_content, tag_id) VALUES ($1, $2, $3, $4)", guildID, tagName, tagContent, id) - if err != nil { - logrus.Error(err) - } - - return exists -} -func removeTag(guildID string, tagID string) { - var exists bool - err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM tags WHERE guild_id = $1 AND tag_id = $2)", guildID, tagID).Scan(&exists) - if err != nil { - logrus.Error(err) - } - if exists { - _, err = db.Exec("DELETE FROM tags WHERE guild_id = $1 AND tag_id = $2", guildID, tagID) - if err != nil { - logrus.Error(err) - } - } -} -func getTagIDs(guildID string) ([]string, error) { - var IDs []string - rows, err := db.Query("SELECT tag_id FROM tags WHERE guild_id = $1", guildID) - if err != nil { - return nil, err - } - defer rows.Close() - - for rows.Next() { - var id string - if err := rows.Scan(&id); err != nil { - return nil, err - } - IDs = append(IDs, id) - } - - if err := rows.Err(); err != nil { - return nil, err - } - - return IDs, nil -} -func getTagName(guildID string, tagID string) string { - var tagName string - db.QueryRow("SELECT tag_name FROM tags WHERE guild_id = $1 AND tag_id = $2", guildID, tagID).Scan(&tagName) - return tagName -} -func getTagContent(guildID string, tagID string) string { - var tagContent string - db.QueryRow("SELECT tag_content FROM tags WHERE guild_id = $1 AND tag_id = $2", guildID, tagID).Scan(&tagContent) - return tagContent -} - -func addSticky(guildID string, channelID string, messageContent string, messageID string) { - _, err := db.Exec("INSERT INTO sticky (guild_id, channel_id, message_id, message_content) VALUES ($1, $2, $3, $4)", guildID, channelID, messageID, messageContent) - if err != nil { - logrus.Error(err) - } - -} - -func hasSticky(guildID string, channelID string) bool { - var exists bool - err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM sticky WHERE guild_id = $1 AND channel_id = $2)", guildID, channelID).Scan(&exists) - if err != nil { - logrus.Error(err) - } - return exists -} - -func getStickyMessageID(guildID string, channelID string) string { - var messageID string - exists := hasSticky(guildID, channelID) - if exists { - err := db.QueryRow("SELECT message_id FROM sticky WHERE guild_id = $1 AND channel_id = $2", guildID, channelID).Scan(&messageID) - if err != nil { - logrus.Error(err) - } - } - return messageID -} -func getStickyMessageContent(guildID string, channelID string) string { - var messageID string - exists := hasSticky(guildID, channelID) - if exists { - err := db.QueryRow("SELECT message_content FROM sticky WHERE guild_id = $1 AND channel_id = $2", guildID, channelID).Scan(&messageID) - if err != nil { - logrus.Error(err) - } - } - return messageID -} - -func updateStickyMessageID(guildID string, channelID string, messageID string) { - exists := hasSticky(guildID, channelID) - if exists { - _, err := db.Exec("UPDATE sticky SET message_id = $1 WHERE guild_id = $2 AND channel_id = $3", messageID, guildID, channelID) - if err != nil { - logrus.Error(err) - } - } -} - -func removeSticky(guildID string, channelID string) { - _, err := db.Exec("DELETE FROM sticky WHERE guild_id = $1 AND channel_id = $2", guildID, channelID) - if err != nil { - logrus.Error(err) - } -} - -func getFormManageIdExists(id uuid.UUID) bool { - var exists bool - err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM form_manage WHERE form_manage_id = $1)", id).Scan(&exists) - if err != nil { - logrus.Error(err) - } - return exists -} - -func addFormButton(guildID string, channelID string, messageID string, formManageID string, formType string, resultChannelID string, overwriteTitle string, acceptChannelID string, commentCategory string, moderator_id string) { - _, err := db.Exec( - `INSERT INTO form_manage ( - guild_id, - form_manage_id, - channel_id, - message_id, - form_type, - result_channel_id, - overwrite_title, - accept_channel_id, - comment_category, - moderator_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, - guildID, formManageID, channelID, messageID, formType, resultChannelID, overwriteTitle, acceptChannelID, commentCategory, moderator_id) - if err != nil { - logrus.Error(err) - } -} - -func getFormManageIDs() []string { - if db == nil { - return nil - } - var IDs []string - rows, err := db.Query("SELECT form_manage_id FROM form_manage") - if err != nil { - logrus.Error(err) - return nil - } - defer rows.Close() - - for rows.Next() { - var id string - if err := rows.Scan(&id); err != nil { - logrus.Error(err) - return nil - } - IDs = append(IDs, id) - } - - if err := rows.Err(); err != nil { - logrus.Error(err) - return nil - } - return IDs -} - -func getFormType(formManageID string) string { - var formType string - err := db.QueryRow("SELECT form_type FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&formType) - if err != nil { - logrus.Error(err) - } - return formType -} - -func getFormResultValues(formManageID string) FormResult { - var result FormResult - err := db.QueryRow("SELECT overwrite_title FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&result.OverwriteTitle) - if err != nil { - logrus.Error(err) - } - err = db.QueryRow("SELECT result_channel_id FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&result.ResultChannelID) - if err != nil { - logrus.Error(err) - } - err = db.QueryRow("SELECT accept_channel_id FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&result.AcceptChannelID) - if err != nil { - logrus.Error(err) - } - err = db.QueryRow("SELECT comment_category FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&result.CommentCategoryID) - if err != nil { - logrus.Error(err) - } - err = db.QueryRow("SELECT moderator_id FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&result.ModeratorID) - if err != nil { - logrus.Error(err) - } - return result -} - -func getFormOverwriteTitle(formManageID string) string { - var overwriteTitle string - err := db.QueryRow("SELECT overwrite_title FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&overwriteTitle) - if err != nil { - logrus.Error(err) - } - return overwriteTitle -} - -func updateFormCommentCategory(formManageID string, comment_category string) { - _, err := db.Exec("UPDATE form_manage SET comment_category = $1 WHERE form_manage_id = $2", comment_category, formManageID) - if err != nil { - logrus.Error(err) - } -} - -func setAutoJoinRole(guildID string, option string, roleID string) bool { - var role_exists bool - var autojoinroles_exists bool - err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM autojoinroles WHERE guild_id = $1)", guildID).Scan(&autojoinroles_exists) - if err != nil { - logrus.Error(err) - } - err = db.QueryRow("SELECT EXISTS (SELECT 1 FROM autojoinroles WHERE guild_id = $1 AND "+option+"_role IS NOT NULL AND "+option+"_role != '')", guildID).Scan(&role_exists) - if err != nil { - logrus.Error(err) - } - if autojoinroles_exists { - _, err = db.Exec("UPDATE autojoinroles SET "+option+"_role = $1 WHERE guild_id = $2", roleID, guildID) - if err != nil { - logrus.Error(err) - } - } else { - _, err = db.Exec("INSERT INTO autojoinroles (guild_id, "+option+"_role) VALUES ($1, $2)", guildID, roleID) - if err != nil { - logrus.Error(err) - } - } - return role_exists -} - -func purgeUnusedAutoJoinRoles(guildID string) { - _, err := db.Exec("DELETE FROM autojoinroles WHERE guild_id = $1 AND user_role = '' OR user_role IS NULL AND bot_role = '' OR bot_role IS NULL", guildID) - if err != nil { - logrus.Error(err) - } -} - -func getAutoJoinRole(guildID string, isBot bool) string { - var isBotString string - var role string - if isBot { - isBotString = "bot" - } else { - isBotString = "user" - } - var exists bool - err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM autojoinroles WHERE guild_id = $1)", guildID).Scan(&exists) - if err != nil { - logrus.Error(err) - return role - } - if exists { - err = db.QueryRow("SELECT "+isBotString+"_role FROM autojoinroles WHERE guild_id = $1", guildID).Scan(&role) - if err != nil { - logrus.Error(err, guildID) - } - } - return role -} - -func toggleAutoPublish(guildID string, newsChannelID string) bool { - var exists bool - err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM autopublish WHERE guild_id = $1 AND news_channel_id = $2)", guildID, newsChannelID).Scan(&exists) - if err != nil { - logrus.Error(err) - } - if exists { - _, err := db.Exec("DELETE FROM autopublish WHERE guild_id = $1 AND news_channel_id = $2", guildID, newsChannelID) - if err != nil { - logrus.Error(err) - } - } else { - _, err := db.Exec("INSERT INTO autopublish (guild_id, news_channel_id) VALUES ($1, $2)", guildID, newsChannelID) - if err != nil { - logrus.Error(err) - } - } - return exists -} - -func isAutopublishEnabled(guildID string, newsChannelID string) bool { - var enabled bool - err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM autopublish WHERE guild_id = $1 AND news_channel_id = $2)", guildID, newsChannelID).Scan(&enabled) - if err != nil { - logrus.Error(err) - } - return enabled -} - -func isGlobalBlockPolls(guildID string) bool { - var globalexists bool - err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM blockpolls WHERE guild_id = $1 AND global = true)", guildID).Scan(&globalexists) - if err != nil { - logrus.Error(err) - } - return globalexists -} - -func toggleBlockPolls(guildID string, channelID string, global bool, allowedRole string) (e bool, isGlobal bool) { - globalexists := isGlobalBlockPolls(guildID) - var exists bool - err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM blockpolls WHERE guild_id = $1 AND channel_id = $2)", guildID, channelID).Scan(&exists) - if err != nil { - logrus.Error(err) - } - if globalexists { - _, err := db.Exec("DELETE FROM blockpolls WHERE guild_id = $1 AND global = true", guildID) - if err != nil { - logrus.Error(err) - } - return true, true - } else if global { - _, err = db.Exec("DELETE FROM blockpolls WHERE guild_id = $1", guildID) - if err != nil { - logrus.Error(err) - } - _, err := db.Exec("INSERT INTO blockpolls (guild_id, global, channel_id, allowed_role) VALUES ($1, true, $2, $3)", guildID, channelID, allowedRole) - if err != nil { - logrus.Error(err) - } - return false, true - } else if exists && !globalexists { - _, err := db.Exec("DELETE FROM blockpolls WHERE guild_id = $1 AND channel_id = $2", guildID, channelID) - if err != nil { - logrus.Error(err) - } - return true, false - } else if !globalexists { - _, err := db.Exec("INSERT INTO blockpolls (guild_id, channel_id, allowed_role) VALUES ($1, $2, $3)", guildID, channelID, allowedRole) - if err != nil { - logrus.Error(err) - } - return false, false - } else { - return false, false - } -} - -func listBlockPolls(guildID string) []BlockPoll { - var list []BlockPoll - rows, err := db.Query("SELECT channel_id, global, allowed_role FROM blockpolls WHERE guild_id = $1", guildID) - if err != nil { - log.Fatal(err) - } - for rows.Next() { - var bp BlockPoll - err := rows.Scan(&bp.ChannelID, &bp.Global, &bp.AllowedRole) - if err != nil { - log.Fatal(err) - } - list = append(list, bp) - } - return list -} - -func getBlockPollsEnabled(guildID string, channelID string) (isEnabled bool, allowedRole string) { - var enabled bool - var v_allowedRole string - err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM blockpolls WHERE guild_id = $1 AND channel_id = $2)", guildID, channelID).Scan(&enabled) - if err != nil { - logrus.Error(err) - } - err = db.QueryRow("SELECT allowed_role FROM blockpolls WHERE guild_id = $1 AND channel_id = $2", guildID, channelID).Scan(&v_allowedRole) - if err != nil && err.Error() != "sql: no rows in result set" { - logrus.Error(err) - } - return enabled, v_allowedRole -} - -func tryDeleteUnusedMessage(messageID string) { - _, err := db.Exec("DELETE FROM form_manage WHERE message_id = $1", messageID) - if err != nil { - logrus.Error(err) - } -} - -func getAllSavedMessages() []MessageIDs { - var savedMessages []MessageIDs - rows, err := db.Query("SELECT message_id, channel_id FROM form_manage") - if err != nil { - logrus.Error(err) - return nil - } - defer rows.Close() - for rows.Next() { - var messageID, channelID string - if err := rows.Scan(&messageID, &channelID); err != nil { - logrus.Error(err) - continue - } - savedMessages = append(savedMessages, MessageIDs{ID: messageID, ChannelID: channelID}) - } - if err := rows.Err(); err != nil { - logrus.Error(err) - } - return savedMessages -} diff --git a/plugin_src/addemoji/main.go b/plugin_src/addemoji/main.go new file mode 100644 index 0000000..cd06753 --- /dev/null +++ b/plugin_src/addemoji/main.go @@ -0,0 +1,115 @@ +package main + +import ( + "bytes" + "io" + "net/http" + "regexp" + "strings" + + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/json" + "github.com/sirupsen/logrus" + "github.com/vaporvee/acecore/shared" +) + +var Plugin = &shared.Plugin{ + Name: "Add Emoji", + Commands: []shared.Command{ + { + Definition: discord.SlashCommandCreate{ + Name: "add-emoji", + Description: "Add an external emoji directly to the server.", + DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageGuildExpressions), + Options: []discord.ApplicationCommandOption{ + &discord.ApplicationCommandOptionString{ + Name: "emoji", + Description: "The emoji you want to add", + Required: true, + }, + }, + }, + Interact: func(e *events.ApplicationCommandInteractionCreate) { + emojiRegex := regexp.MustCompile(`<(.+):(\d+)>`) + emojistring := emojiRegex.FindString(e.SlashCommandInteractionData().String("emoji")) + emojiArray := strings.Split(emojistring, ":") + var emojiName string + var emojiID string + var emojiFileName string + if len(emojiArray) > 1 { + emojiName = strings.TrimSuffix(emojiArray[1], ">") + emojiID = strings.TrimSuffix(emojiArray[2], ">") + } + imageType, emojiReadBit64 := getEmoji(emojiID) + emojiData, err := discord.NewIcon(imageType, emojiReadBit64) + if err != nil { + logrus.Error(err) + } + _, err = e.Client().Rest().CreateEmoji(*e.GuildID(), discord.EmojiCreate{ + Name: emojiName, + Image: *emojiData, + }) + if err != nil { + if strings.HasPrefix(err.Error(), "50035") { + e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Failed adding emoji. Did you provide a correct one?").SetEphemeral(true).Build()) + return + } + if strings.HasPrefix(err.Error(), "50138") { + e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Failed adding emoji. Unable to resize the emoji image.").SetEphemeral(true).Build()) + return + } + logrus.Error(err) + return + } + if imageType == discord.IconTypeGIF { + emojiFileName = emojiName + ".gif" + } else { + emojiFileName = emojiName + ".png" + } + _, emojiRead := getEmoji(emojiID) // for some reason any []bit variable thats used with NewIcon gets corrupted even when its redeclared in a new variable + err = e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContentf("Emoji %s sucessfully added to this server!", emojiName).SetFiles(discord.NewFile(emojiFileName, "", emojiRead)).SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + }, + }, + }, +} + +func getEmoji(emojiID string) (discord.IconType, io.Reader) { + resp, err := http.Get("https://cdn.discordapp.com/emojis/" + emojiID) + if err != nil { + logrus.Error(err) + return discord.IconTypePNG, nil + } + defer resp.Body.Close() + imageData, err := io.ReadAll(resp.Body) + if err != nil { + logrus.Error(err) + return discord.IconTypePNG, nil + } + isAnimated := isGIFImage(imageData) + if isAnimated { + return discord.IconTypeGIF, bytes.NewReader(imageData) + } else { + return discord.IconTypePNG, bytes.NewReader(imageData) + } +} + +func isGIFImage(imageData []byte) bool { + if len(imageData) < 6 { + return false + } + // Check for the GIF89a header at the beginning of the byte array + if string(imageData[0:6]) == "GIF89a" { + return true + } + // Check for the GIF87a header at the beginning of the byte array + if string(imageData[0:6]) == "GIF87a" { + return true + } + return false +} diff --git a/plugin_src/autojoinroles/data.go b/plugin_src/autojoinroles/data.go new file mode 100644 index 0000000..46684bd --- /dev/null +++ b/plugin_src/autojoinroles/data.go @@ -0,0 +1,60 @@ +package main + +import ( + "github.com/sirupsen/logrus" +) + +func setAutoJoinRole(guildID string, option string, roleID string) bool { + var role_exists bool + var autojoinroles_exists bool + err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM autojoinroles WHERE guild_id = $1)", guildID).Scan(&autojoinroles_exists) + if err != nil { + logrus.Error(err) + } + err = db.QueryRow("SELECT EXISTS (SELECT 1 FROM autojoinroles WHERE guild_id = $1 AND "+option+"_role IS NOT NULL AND "+option+"_role != '')", guildID).Scan(&role_exists) + if err != nil { + logrus.Error(err) + } + if autojoinroles_exists { + _, err = db.Exec("UPDATE autojoinroles SET "+option+"_role = $1 WHERE guild_id = $2", roleID, guildID) + if err != nil { + logrus.Error(err) + } + } else { + _, err = db.Exec("INSERT INTO autojoinroles (guild_id, "+option+"_role) VALUES ($1, $2)", guildID, roleID) + if err != nil { + logrus.Error(err) + } + } + return role_exists +} + +func purgeUnusedAutoJoinRoles(guildID string) { + _, err := db.Exec("DELETE FROM autojoinroles WHERE guild_id = $1 AND user_role = '' OR user_role IS NULL AND bot_role = '' OR bot_role IS NULL", guildID) + if err != nil { + logrus.Error(err) + } +} + +func getAutoJoinRole(guildID string, isBot bool) string { + var isBotString string + var role string + if isBot { + isBotString = "bot" + } else { + isBotString = "user" + } + var exists bool + err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM autojoinroles WHERE guild_id = $1)", guildID).Scan(&exists) + if err != nil { + logrus.Error(err) + return role + } + if exists { + err = db.QueryRow("SELECT "+isBotString+"_role FROM autojoinroles WHERE guild_id = $1", guildID).Scan(&role) + if err != nil { + logrus.Error(err, guildID) + } + } + return role +} diff --git a/plugin_src/autojoinroles/listener.go b/plugin_src/autojoinroles/listener.go new file mode 100644 index 0000000..ba190a0 --- /dev/null +++ b/plugin_src/autojoinroles/listener.go @@ -0,0 +1,17 @@ +package main + +import ( + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/snowflake/v2" + "github.com/sirupsen/logrus" +) + +func guildMemberJoin(e *events.GuildMemberJoin) { + role := getAutoJoinRole(e.GuildID.String(), e.Member.User.Bot) + if role != "" { + err := e.Client().Rest().AddMemberRole(e.GuildID, e.Member.User.ID, snowflake.MustParse(role)) + if err != nil { + logrus.Error(err) + } + } +} diff --git a/plugin_src/autojoinroles/main.go b/plugin_src/autojoinroles/main.go new file mode 100644 index 0000000..d74b5d0 --- /dev/null +++ b/plugin_src/autojoinroles/main.go @@ -0,0 +1,127 @@ +package main + +import ( + "database/sql" + + "github.com/disgoorg/disgo/bot" + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/json" + "github.com/disgoorg/snowflake/v2" + "github.com/sirupsen/logrus" + "github.com/vaporvee/acecore/shared" +) + +var db *sql.DB + +var dbCreateQuery string = ` +CREATE TABLE IF NOT EXISTS autojoinroles ( + guild_id TEXT NOT NULL, + bot_role TEXT, + user_role TEXT, + PRIMARY KEY (guild_id) +); +` + +var Plugin = &shared.Plugin{ + Name: "Auto Join Roles", + Init: func(d *sql.DB) error { + db = d + _, err := d.Exec(dbCreateQuery) + if err != nil { + return err + } + shared.BotConfigs = append(shared.BotConfigs, bot.WithEventListenerFunc(guildMemberJoin)) + return nil + }, + Commands: []shared.Command{ + { + Definition: discord.SlashCommandCreate{ + Name: "autojoinroles", + Description: "Give users a role when they join", + DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageRoles), + Contexts: []discord.InteractionContextType{ + discord.InteractionContextTypeGuild, + discord.InteractionContextTypePrivateChannel}, + IntegrationTypes: []discord.ApplicationIntegrationType{ + discord.ApplicationIntegrationTypeGuildInstall}, + Options: []discord.ApplicationCommandOption{ + &discord.ApplicationCommandOptionSubCommand{ + Name: "bot", + Description: "Give bots a role when they join (Leave empty to remove current)", + Options: []discord.ApplicationCommandOption{ + &discord.ApplicationCommandOptionRole{ + Name: "role", + Description: "The role bots should get when they join the server", + }, + }, + }, + &discord.ApplicationCommandOptionSubCommand{ + Name: "user", + Description: "Give users a role when they join (Leave empty to remove current)", + Options: []discord.ApplicationCommandOption{ + &discord.ApplicationCommandOptionRole{ + Name: "role", + Description: "The role users should get when they join the server", + }}, + }, + }, + }, + Interact: func(e *events.ApplicationCommandInteractionCreate) { + var role string + option := *e.SlashCommandInteractionData().SubCommandName + var content string + if len(e.SlashCommandInteractionData().Options) == 1 { + var givenRole discord.Role = e.SlashCommandInteractionData().Role("role") + role = givenRole.ID.String() + botrole, err := getHighestRole(e.GuildID().String(), e.Client()) + if err != nil { + logrus.Error(err) + } + if givenRole.Position >= botrole.Position { + content = "<@&" + role + "> is not below the Bot's current highest role(<@&" + botrole.ID.String() + ">). That makes it unable to manage it." + } else { + if setAutoJoinRole(e.GuildID().String(), option, role) { + content = "Updated auto join role for " + option + "s as <@&" + role + ">" + } else { + content = "Setup auto join role for " + option + "s as <@&" + role + ">" + } + } + } else if setAutoJoinRole(e.GuildID().String(), option, role) { + content = "Deleted auto join role for " + option + "s" + } + if content == "" { + content = "No auto join role set for " + option + "s to delete." + } + err := e.CreateMessage(discord.NewMessageCreateBuilder().SetContent(content).SetEphemeral(true).Build()) + if err != nil { + logrus.Error(err) + } + purgeUnusedAutoJoinRoles(e.GuildID().String()) + }, + }, + }, +} + +func getHighestRole(guildID string, c bot.Client) (*discord.Role, error) { + botmember, err := c.Rest().GetMember(snowflake.MustParse(guildID), c.ApplicationID()) + if err != nil { + return nil, err + } + roles, err := c.Rest().GetRoles(snowflake.MustParse(guildID)) + if err != nil { + return nil, err + } + var highestRole *discord.Role + for _, roleID := range botmember.RoleIDs { + for _, role := range roles { + if role.ID == roleID { + if highestRole == nil || role.Position > highestRole.Position { + highestRole = &role + } + break + } + } + } + return highestRole, nil +} diff --git a/plugin_src/autopublish/data.go b/plugin_src/autopublish/data.go new file mode 100644 index 0000000..cd11520 --- /dev/null +++ b/plugin_src/autopublish/data.go @@ -0,0 +1,34 @@ +package main + +import ( + "github.com/sirupsen/logrus" +) + +func toggleAutoPublish(guildID string, newsChannelID string) bool { + var exists bool + err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM autopublish WHERE guild_id = $1 AND news_channel_id = $2)", guildID, newsChannelID).Scan(&exists) + if err != nil { + logrus.Error(err) + } + if exists { + _, err := db.Exec("DELETE FROM autopublish WHERE guild_id = $1 AND news_channel_id = $2", guildID, newsChannelID) + if err != nil { + logrus.Error(err) + } + } else { + _, err := db.Exec("INSERT INTO autopublish (guild_id, news_channel_id) VALUES ($1, $2)", guildID, newsChannelID) + if err != nil { + logrus.Error(err) + } + } + return exists +} + +func isAutopublishEnabled(guildID string, newsChannelID string) bool { + var enabled bool + err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM autopublish WHERE guild_id = $1 AND news_channel_id = $2)", guildID, newsChannelID).Scan(&enabled) + if err != nil { + logrus.Error(err) + } + return enabled +} diff --git a/plugin_src/autopublish/listener.go b/plugin_src/autopublish/listener.go new file mode 100644 index 0000000..5cbd4a6 --- /dev/null +++ b/plugin_src/autopublish/listener.go @@ -0,0 +1,23 @@ +package main + +import ( + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" + "github.com/sirupsen/logrus" +) + +func messageCreate(e *events.MessageCreate) { + channel, err := e.Client().Rest().GetChannel(e.Message.ChannelID) + if err != nil { + logrus.Error(err) + } + if channel.Type() == discord.ChannelTypeGuildNews { + if isAutopublishEnabled(e.GuildID.String(), e.ChannelID.String()) { + _, err := e.Client().Rest().CrosspostMessage(e.ChannelID, e.MessageID) + if err != nil { + logrus.Error(err) + return + } + } + } +} diff --git a/plugin_src/autopublish/main.go b/plugin_src/autopublish/main.go new file mode 100644 index 0000000..5b4c456 --- /dev/null +++ b/plugin_src/autopublish/main.go @@ -0,0 +1,76 @@ +package main + +import ( + "database/sql" + + "github.com/disgoorg/disgo/bot" + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/json" + "github.com/sirupsen/logrus" + "github.com/vaporvee/acecore/shared" +) + +var db *sql.DB + +var dbCreateQuery string = ` +CREATE TABLE IF NOT EXISTS autopublish ( + guild_id TEXT NOT NULL, + news_channel_id TEXT NOT NULL, + PRIMARY KEY (guild_id, news_channel_id) + ); +` + +var Plugin = &shared.Plugin{ + Name: "Auto Publish", + Init: func(d *sql.DB) error { + db = d + _, err := d.Exec(dbCreateQuery) + if err != nil { + return err + } + shared.BotConfigs = append(shared.BotConfigs, bot.WithEventListenerFunc(messageCreate)) + return nil + }, + Commands: []shared.Command{ + { + Definition: discord.SlashCommandCreate{ + Name: "autopublish", + Description: "Toggle automatically publishing every post in a announcement channel", + DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageChannels), + Contexts: []discord.InteractionContextType{ + discord.InteractionContextTypeGuild, + discord.InteractionContextTypePrivateChannel}, + IntegrationTypes: []discord.ApplicationIntegrationType{ + discord.ApplicationIntegrationTypeGuildInstall}, + }, + Interact: func(e *events.ApplicationCommandInteractionCreate) { + channel := e.Channel() + if channel.Type() == discord.ChannelTypeGuildNews { + if toggleAutoPublish(e.GuildID().String(), e.Channel().ID().String()) { + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Autopublishing is now disabled on " + discord.ChannelMention(e.Channel().ID())).SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } else { + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Autopublishing is now enabled on " + discord.ChannelMention(e.Channel().ID())).SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } + } else { + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("This is not an announcement channel!").SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } + }, + }, + }, +} diff --git a/plugin_src/blockpolls/data.go b/plugin_src/blockpolls/data.go new file mode 100644 index 0000000..4600c4e --- /dev/null +++ b/plugin_src/blockpolls/data.go @@ -0,0 +1,93 @@ +package main + +import ( + "log" + + "github.com/sirupsen/logrus" +) + +type BlockPoll struct { + ChannelID string + Global bool + AllowedRole string +} + +func isGlobalBlockPolls(guildID string) bool { + var globalexists bool + err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM blockpolls WHERE guild_id = $1 AND global = true)", guildID).Scan(&globalexists) + if err != nil { + logrus.Error(err) + } + return globalexists +} + +func toggleBlockPolls(guildID string, channelID string, global bool, allowedRole string) (e bool, isGlobal bool) { + globalexists := isGlobalBlockPolls(guildID) + var exists bool + err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM blockpolls WHERE guild_id = $1 AND channel_id = $2)", guildID, channelID).Scan(&exists) + if err != nil { + logrus.Error(err) + } + if globalexists { + _, err := db.Exec("DELETE FROM blockpolls WHERE guild_id = $1 AND global = true", guildID) + if err != nil { + logrus.Error(err) + } + return true, true + } else if global { + _, err = db.Exec("DELETE FROM blockpolls WHERE guild_id = $1", guildID) + if err != nil { + logrus.Error(err) + } + _, err := db.Exec("INSERT INTO blockpolls (guild_id, global, channel_id, allowed_role) VALUES ($1, true, $2, $3)", guildID, channelID, allowedRole) + if err != nil { + logrus.Error(err) + } + return false, true + } else if exists && !globalexists { + _, err := db.Exec("DELETE FROM blockpolls WHERE guild_id = $1 AND channel_id = $2", guildID, channelID) + if err != nil { + logrus.Error(err) + } + return true, false + } else if !globalexists { + _, err := db.Exec("INSERT INTO blockpolls (guild_id, channel_id, allowed_role) VALUES ($1, $2, $3)", guildID, channelID, allowedRole) + if err != nil { + logrus.Error(err) + } + return false, false + } else { + return false, false + } +} + +func listBlockPolls(guildID string) []BlockPoll { + var list []BlockPoll + rows, err := db.Query("SELECT channel_id, global, allowed_role FROM blockpolls WHERE guild_id = $1", guildID) + if err != nil { + log.Fatal(err) + } + for rows.Next() { + var bp BlockPoll + err := rows.Scan(&bp.ChannelID, &bp.Global, &bp.AllowedRole) + if err != nil { + log.Fatal(err) + } + list = append(list, bp) + } + return list +} + +func getBlockPollsEnabled(guildID string, channelID string) (isEnabled bool, allowedRole string) { + var enabled bool + var v_allowedRole string + err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM blockpolls WHERE guild_id = $1 AND channel_id = $2)", guildID, channelID).Scan(&enabled) + if err != nil { + logrus.Error(err) + } + err = db.QueryRow("SELECT allowed_role FROM blockpolls WHERE guild_id = $1 AND channel_id = $2", guildID, channelID).Scan(&v_allowedRole) + if err != nil && err.Error() != "sql: no rows in result set" { + logrus.Error(err) + } + return enabled, v_allowedRole +} diff --git a/plugin_src/blockpolls/listener.go b/plugin_src/blockpolls/listener.go new file mode 100644 index 0000000..2ba0bcf --- /dev/null +++ b/plugin_src/blockpolls/listener.go @@ -0,0 +1,27 @@ +package main + +import ( + "slices" + + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/snowflake/v2" + "github.com/sirupsen/logrus" +) + +func messageCreate(e *events.MessageCreate) { + channel, err := e.Client().Rest().GetChannel(e.Message.ChannelID) + if err != nil { + logrus.Error(err) + } + if channel != nil { + isBlockPollsEnabledGlobal := isGlobalBlockPolls(e.GuildID.String()) + isBlockPollsEnabled, allowedRole := getBlockPollsEnabled(e.GuildID.String(), e.Message.ChannelID.String()) + var hasAllowedRole bool + if allowedRole != "" { + hasAllowedRole = slices.Contains(e.Message.Member.RoleIDs, snowflake.MustParse(allowedRole)) + } + if (isBlockPollsEnabledGlobal || isBlockPollsEnabled) && !hasAllowedRole && messageIsPoll(e.Message.ChannelID.String(), e.Message.ID.String(), e.Client()) { + e.Client().Rest().DeleteMessage(e.Message.ChannelID, e.Message.ID) + } + } +} diff --git a/plugin_src/blockpolls/main.go b/plugin_src/blockpolls/main.go new file mode 100644 index 0000000..7ca28bd --- /dev/null +++ b/plugin_src/blockpolls/main.go @@ -0,0 +1,156 @@ +package main + +import ( + "database/sql" + "io" + "net/http" + + "github.com/disgoorg/disgo/bot" + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/disgo/rest" + "github.com/disgoorg/json" + "github.com/sirupsen/logrus" + "github.com/vaporvee/acecore/shared" +) + +var db *sql.DB + +var dbCreateQuery string = ` +CREATE TABLE IF NOT EXISTS blockpolls ( + guild_id TEXT NOT NULL, + channel_id TEXT, + global BOOLEAN, + allowed_role TEXT, + PRIMARY KEY (guild_id) +) +` + +var Plugin = &shared.Plugin{ + Name: "Block Polls", + Init: func(d *sql.DB) error { + db = d + _, err := d.Exec(dbCreateQuery) + if err != nil { + return err + } + shared.BotConfigs = append(shared.BotConfigs, bot.WithEventListenerFunc(messageCreate)) + return nil + }, + Commands: []shared.Command{ + { + Definition: discord.SlashCommandCreate{ + Name: "block-polls", + Description: "Block polls from beeing posted in this channel.", + DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageChannels), + Contexts: []discord.InteractionContextType{ + discord.InteractionContextTypeGuild, + discord.InteractionContextTypePrivateChannel}, + IntegrationTypes: []discord.ApplicationIntegrationType{ + discord.ApplicationIntegrationTypeGuildInstall}, + Options: []discord.ApplicationCommandOption{ + &discord.ApplicationCommandOptionSubCommand{ + Name: "toggle", + Description: "Toggle blocking polls from beeing posted in this channel.", + Options: []discord.ApplicationCommandOption{ + &discord.ApplicationCommandOptionBool{ + Name: "global", + Description: "If polls are blocked server wide or only in the current channel.", + }, + &discord.ApplicationCommandOptionRole{ + Name: "allowed-role", + Description: "The role that bypasses this block role.", + }, + }, + }, + /*&discord.ApplicationCommandOptionSubCommand{ + Name: "list", + Description: "List the current block polls rules for this server.", + },*/ + }, + }, + Interact: func(e *events.ApplicationCommandInteractionCreate) { + switch *e.SlashCommandInteractionData().SubCommandName { + case "toggle": + isGlobal := isGlobalBlockPolls(e.GuildID().String()) + if isGlobal && !e.SlashCommandInteractionData().Bool("global") { + e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Polls are currently globally blocked. Disable global blocking to enable channel specific blocking.").SetEphemeral(true).Build()) + } else { + exists, isGlobal := toggleBlockPolls(e.GuildID().String(), e.Channel().ID().String(), e.SlashCommandInteractionData().Bool("global"), e.SlashCommandInteractionData().Role("allowed-role").ID.String()) + if exists { + if e.SlashCommandInteractionData().Bool("global") { + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Polls are now globally unblocked.").SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } else { + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Polls are now unblocked in " + discord.ChannelMention(e.Channel().ID())).SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } + } else { + if isGlobal { + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Polls are now globally blocked.").SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } else { + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Polls are now blocked in " + discord.ChannelMention(e.Channel().ID())).SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } + } + } + /*case "list": + list := listBlockPolls(e.GuildID().String())*/ + } + }, + }, + }, +} + +func messageIsPoll(channelID string, messageID string, client bot.Client) bool { + url := rest.DefaultConfig().URL + "/channels/" + channelID + "/messages/" + messageID + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + logrus.Error(err) + return false + } + + auth := "Bot " + client.Token() + req.Header.Set("Authorization", auth) + + resp, err := client.Rest().HTTPClient().Do(req) + if err != nil { + logrus.Error(err) + return false + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + logrus.Error(err) + return false + } + + var data map[string]interface{} + err = json.Unmarshal(body, &data) + if err != nil { + logrus.Error(err) + return false + } + + _, ok := data["poll"] + return ok +} diff --git a/plugin_src/forms/data.go b/plugin_src/forms/data.go new file mode 100644 index 0000000..7ae4680 --- /dev/null +++ b/plugin_src/forms/data.go @@ -0,0 +1,154 @@ +package main + +import ( + "github.com/google/uuid" + "github.com/sirupsen/logrus" +) + +type FormResult struct { + OverwriteTitle string + ResultChannelID string + AcceptChannelID string + CommentCategoryID string + ModeratorID string +} + +type MessageIDs struct { + ID string + ChannelID string +} + +func getFormManageIdExists(id uuid.UUID) bool { + var exists bool + err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM form_manage WHERE form_manage_id = $1)", id).Scan(&exists) + if err != nil { + logrus.Error(err) + } + return exists +} + +func addFormButton(guildID string, channelID string, messageID string, formManageID string, formType string, resultChannelID string, overwriteTitle string, acceptChannelID string, commentCategory string, moderator_id string) { + _, err := db.Exec( + `INSERT INTO form_manage ( + guild_id, + form_manage_id, + channel_id, + message_id, + form_type, + result_channel_id, + overwrite_title, + accept_channel_id, + comment_category, + moderator_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, + guildID, formManageID, channelID, messageID, formType, resultChannelID, overwriteTitle, acceptChannelID, commentCategory, moderator_id) + if err != nil { + logrus.Error(err) + } +} + +func getFormManageIDs() []string { + if db == nil { + return nil + } + var IDs []string + rows, err := db.Query("SELECT form_manage_id FROM form_manage") + if err != nil { + logrus.Error(err) + return nil + } + defer rows.Close() + + for rows.Next() { + var id string + if err := rows.Scan(&id); err != nil { + logrus.Error(err) + return nil + } + IDs = append(IDs, id) + } + + if err := rows.Err(); err != nil { + logrus.Error(err) + return nil + } + return IDs +} + +func getFormType(formManageID string) string { + var formType string + err := db.QueryRow("SELECT form_type FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&formType) + if err != nil { + logrus.Error(err) + } + return formType +} + +func getFormResultValues(formManageID string) FormResult { + var result FormResult + err := db.QueryRow("SELECT overwrite_title FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&result.OverwriteTitle) + if err != nil { + logrus.Error(err) + } + err = db.QueryRow("SELECT result_channel_id FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&result.ResultChannelID) + if err != nil { + logrus.Error(err) + } + err = db.QueryRow("SELECT accept_channel_id FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&result.AcceptChannelID) + if err != nil { + logrus.Error(err) + } + err = db.QueryRow("SELECT comment_category FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&result.CommentCategoryID) + if err != nil { + logrus.Error(err) + } + err = db.QueryRow("SELECT moderator_id FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&result.ModeratorID) + if err != nil { + logrus.Error(err) + } + return result +} + +func getFormOverwriteTitle(formManageID string) string { + var overwriteTitle string + err := db.QueryRow("SELECT overwrite_title FROM form_manage WHERE form_manage_id = $1", formManageID).Scan(&overwriteTitle) + if err != nil { + logrus.Error(err) + } + return overwriteTitle +} + +func updateFormCommentCategory(formManageID string, comment_category string) { + _, err := db.Exec("UPDATE form_manage SET comment_category = $1 WHERE form_manage_id = $2", comment_category, formManageID) + if err != nil { + logrus.Error(err) + } +} + +func tryDeleteUnusedMessage(messageID string) { + _, err := db.Exec("DELETE FROM form_manage WHERE message_id = $1", messageID) + if err != nil { + logrus.Error(err) + } +} + +func getAllSavedMessages() []MessageIDs { + var savedMessages []MessageIDs + rows, err := db.Query("SELECT message_id, channel_id FROM form_manage") + if err != nil { + logrus.Error(err) + return nil + } + defer rows.Close() + for rows.Next() { + var messageID, channelID string + if err := rows.Scan(&messageID, &channelID); err != nil { + logrus.Error(err) + continue + } + savedMessages = append(savedMessages, MessageIDs{ID: messageID, ChannelID: channelID}) + } + if err := rows.Err(); err != nil { + logrus.Error(err) + } + return savedMessages +} diff --git a/plugin_src/forms/main.go b/plugin_src/forms/main.go new file mode 100644 index 0000000..39e2d00 --- /dev/null +++ b/plugin_src/forms/main.go @@ -0,0 +1,515 @@ +package main + +import ( + "bytes" + "database/sql" + "fmt" + "strings" + + "github.com/disgoorg/disgo/bot" + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/json" + "github.com/disgoorg/snowflake/v2" + "github.com/google/uuid" + "github.com/sirupsen/logrus" + "github.com/vaporvee/acecore/custom" + "github.com/vaporvee/acecore/shared" +) + +var db *sql.DB + +var dbCreateQuery string = ` +CREATE TABLE IF NOT EXISTS custom_forms ( + form_type TEXT NOT NULL, + title TEXT NOT NULL, + json JSON NOT NULL, + guild_id TEXT NOT NULL, + PRIMARY KEY (form_type, guild_id) + ); + CREATE TABLE IF NOT EXISTS form_manage ( + form_manage_id TEXT NOT NULL, + form_type TEXT NOT NULL, + overwrite_title TEXT, + message_id TEXT NOT NULL, + channel_id TEXT NOT NULL, + guild_id TEXT NOT NULL, + result_channel_id TEXT NOT NULL, + accept_channel_id TEXT, + comment_category TEXT, + moderator_id TEXT, + PRIMARY KEY (form_manage_id, form_type) + ); +` + +var Plugin = &shared.Plugin{ + Name: "Forms", + Init: func(d *sql.DB) error { + db = d + _, err := d.Exec(dbCreateQuery) + if err != nil { + return err + } + shared.BotConfigs = append(shared.BotConfigs, + bot.WithEventListenerFunc(func(e *events.MessageCreate) { tryDeleteUnusedMessage(e.MessageID.String()) }), + bot.WithEventListenerFunc(func(e *events.Ready) { findAndDeleteUnusedMessages(e.Client()) })) + return nil + }, + Commands: []shared.Command{ + { + Definition: discord.SlashCommandCreate{ + Name: "form", + DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageChannels), + Description: "Create custom forms right inside Discord", + Contexts: []discord.InteractionContextType{ + discord.InteractionContextTypeGuild, + discord.InteractionContextTypePrivateChannel}, + IntegrationTypes: []discord.ApplicationIntegrationType{ + discord.ApplicationIntegrationTypeGuildInstall}, + Options: []discord.ApplicationCommandOption{ + &discord.ApplicationCommandOptionSubCommand{ + Name: "help", + Description: "Gives you an example file and demo for creating custom forms", + }, + &discord.ApplicationCommandOptionSubCommand{ + Name: "custom", + Description: "Create a new custom form right inside Discord", + Options: []discord.ApplicationCommandOption{ + &discord.ApplicationCommandOptionAttachment{ + Name: "json", + Description: "Your edited form file", + Required: true, + }, + }, + }, + &discord.ApplicationCommandOptionSubCommand{ + Name: "add", + Description: "Adds existing forms to this channel", + Options: []discord.ApplicationCommandOption{ + &discord.ApplicationCommandOptionChannel{ + Name: "result_channel", + Description: "Where the form results should appear", + ChannelTypes: []discord.ChannelType{discord.ChannelTypeGuildText}, + }, + &discord.ApplicationCommandOptionMentionable{ + Name: "moderator", + Description: "Who can interact with moderating buttons.", + }, + &discord.ApplicationCommandOptionString{ + Name: "type", + Description: "Which type of form you want to add", + Autocomplete: true, + }, + &discord.ApplicationCommandOptionString{ + Name: "title", + Description: "The title the form should have", + }, + &discord.ApplicationCommandOptionChannel{ + Name: "approve_channel", + Description: "Channel for results that need to be accepted by a moderator before sending it to the result channel", + ChannelTypes: []discord.ChannelType{discord.ChannelTypeGuildText}, + }, + &discord.ApplicationCommandOptionBool{ + Name: "mods_can_answer", + Description: "Moderators can open a new channel on the form result, which then pings the user who submitted it", + }, + }, + }, + }, + }, + Interact: func(e *events.ApplicationCommandInteractionCreate) { + switch *e.SlashCommandInteractionData().SubCommandName { + case "help": + fileData, err := shared.FormTemplates.ReadFile("form_templates/form_demo.json") + if err != nil { + logrus.Error(err) + return + } + fileReader := bytes.NewReader(fileData) + err = e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("NOT SUPPORTED YET!(use `/form add` instead)\n\nGet the example file edit it (make sure to have a unique \"form_type\") and submit it via `/form create`.\nOr use the demo button to get an idea of how the example would look like."). + SetFiles(discord.NewFile("example.json", "json", fileReader)). + SetContainerComponents(discord.ActionRowComponent{discord.NewPrimaryButton("Demo", "form_demo").WithEmoji(discord.ComponentEmoji{Name: "📑"})}).SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + case "custom": + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Feature not available yet use `/form add` instead").SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + case "add": + var title, formID, overwriteTitle, acceptChannelID string + var modsCanAnswer bool + var resultChannelID string + data := e.SlashCommandInteractionData() + if data.Channel("result_channel").ID.String() != "0" { + resultChannelID = data.Channel("result_channel").ID.String() + } + moderator := data.Role("moderator").ID.String() + if moderator == "0" { + moderator = e.User().ID.String() + } + formID = data.String("type") + overwriteTitle = data.String("title") + if overwriteTitle != "" { + title = overwriteTitle + } + if data.Channel("approve_channel").ID.String() != "0" { + acceptChannelID = data.Channel("approve_channel").ID.String() + } + modsCanAnswer = data.Bool("mods_can_answer") + + if formID == "" { + formID = "template_general" + } + if title == "" { + formTitles := map[string]string{ + "template_ticket": "Make a new ticket", + "template_url": "Add your URL", + "template_general": "Form", + } + if val, ok := formTitles[formID]; ok { + title = val + } + } + var exists bool = true + var formManageID uuid.UUID = uuid.New() + for exists { + formManageID = uuid.New() + exists = getFormManageIdExists(formManageID) + } + messagebuild := discord.NewMessageCreateBuilder().SetEmbeds(discord.NewEmbedBuilder(). + SetTitle(title).SetDescription("Press the bottom button to open a form popup.").SetColor(custom.GetColor("primary")). + Build()).SetContainerComponents(discord.ActionRowComponent{ + discord.NewSuccessButton("Submit", "form:"+formManageID.String()).WithEmoji(discord.ComponentEmoji{ + Name: "anim_rocket", + ID: snowflake.MustParse("1215740398706757743"), + Animated: true, + })}). + Build() + message, err := e.Client().Rest().CreateMessage(e.Channel().ID(), messagebuild) + if err != nil { + logrus.Error(err) + } + var category string + if modsCanAnswer { + c, err := e.Client().Rest().CreateGuildChannel(*e.GuildID(), discord.GuildCategoryChannelCreate{Name: title + " mod answers"}) + if err != nil { + logrus.Error(err) + } + category = c.ID().String() + } + + addFormButton(e.GuildID().String(), e.Channel().ID().String(), message.ID.String(), formManageID.String(), formID, resultChannelID, overwriteTitle, acceptChannelID, category, moderator) + err = e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Successfully added form button!").SetEphemeral(true).Build()) + if err != nil { + logrus.Error(err) + } + } + }, + DynamicComponentIDs: func() []string { return getFormButtonIDs() }, + DynamicModalIDs: func() []string { return getFormButtonIDs() }, + ComponentInteract: func(e *events.ComponentInteractionCreate) { + if e.Data.Type() == discord.ComponentTypeButton { + if strings.ContainsAny(e.ButtonInteractionData().CustomID(), ";") { + var form_manage_id string = strings.TrimPrefix(strings.Split(e.ButtonInteractionData().CustomID(), ";")[0], "form:") + switch strings.Split(e.ButtonInteractionData().CustomID(), ";")[1] { + case "decline": + err := e.Client().Rest().DeleteMessage(e.Channel().ID(), e.Message.ID) + if err != nil { + logrus.Error(err) + } + e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Submission declined!").SetEphemeral(true).Build()) + case "approve": + embed := e.Message.Embeds[0] + embed.Description = fmt.Sprintf("This submission was approved by <@%s>.", e.User().ID) + _, err := e.Client().Rest().CreateMessage(snowflake.MustParse(getFormResultValues(form_manage_id).ResultChannelID), discord.NewMessageCreateBuilder(). + SetEmbeds(embed). + Build()) + if err != nil { + logrus.Error(err) + } + e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Submission accepted!").SetEphemeral(true).Build()) + err = e.Client().Rest().DeleteMessage(e.Channel().ID(), e.Message.ID) + if err != nil { + logrus.Error(err) + } + case "comment": + author := strings.TrimSuffix(strings.Split(e.Message.Embeds[0].Fields[len(e.Message.Embeds[0].Fields)-1].Value, "<@")[1], ">") + embed := e.Message.Embeds[0] + moderator := e.User().ID + channel := createFormComment(form_manage_id, snowflake.MustParse(author), moderator, "answer", embed, *e.GuildID(), e.Client()) + e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Created channel " + discord.ChannelMention(channel.ID())).SetEphemeral(true).Build()) + } + } else { + if strings.HasPrefix(e.ButtonInteractionData().CustomID(), "form:") { + var formManageID string = strings.TrimPrefix(e.ButtonInteractionData().CustomID(), "form:") + e.Modal(shared.JsonStringBuildModal(e.User().ID.String(), formManageID, getFormType(formManageID), getFormOverwriteTitle(formManageID))) + } else if e.ButtonInteractionData().CustomID() == "form_demo" { + e.Modal(shared.JsonStringBuildModal(e.User().ID.String(), "form_demo", "form_demo")) + } + } + } + }, + ModalSubmit: func(e *events.ModalSubmitInteractionCreate) { + if !strings.HasPrefix(e.Data.CustomID, "form_demo") { + var form_manage_id string = strings.Split(e.Data.CustomID, ":")[1] + var result FormResult = getFormResultValues(form_manage_id) + var fields []discord.EmbedField + var modal shared.ModalJson = shared.GetModalByFormID(getFormType(form_manage_id)) + var overwrite_title string = getFormOverwriteTitle(form_manage_id) + if overwrite_title != "" { + modal.Title = overwrite_title + } + var inline bool + var index int = 0 + for _, component := range e.Data.Components { + var input discord.TextInputComponent = component.(discord.TextInputComponent) + inline = input.Style == discord.TextInputStyleShort + fields = append(fields, discord.EmbedField{ + Name: modal.Form[index].Label, + Value: input.Value, + Inline: &inline, + }) + index++ + } + + fields = append(fields, discord.EmbedField{ + Value: "From <#" + e.Channel().ID().String() + "> by " + e.User().Mention(), + }) + if result.ResultChannelID == "" { + if result.CommentCategoryID != "" { + channel := createFormComment(form_manage_id, e.User().ID, snowflake.MustParse(result.ModeratorID), "answer", discord.NewEmbedBuilder(). + SetAuthorName(*e.User().GlobalName).SetAuthorIcon(*e.User().AvatarURL()).SetTitle("\""+modal.Title+"\"").SetDescription("This is the submitted result"). + SetColor(custom.GetColor("primary")).SetFields(fields...). + Build(), *e.GuildID(), e.Client()) + err := e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Created channel " + discord.ChannelMention(channel.ID())).SetEphemeral(true).Build()) + if err != nil { + logrus.Error(err) + } + } else { + e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("You need to provide either a `result_channel` or enable `mods_can_answer` to create a valid form.").SetEphemeral(true). + Build()) + } + } else { + if result.AcceptChannelID == "" { + _, err := e.Client().Rest().CreateMessage(snowflake.MustParse(result.ResultChannelID), discord.NewMessageCreateBuilder(). + SetEmbeds(discord.NewEmbedBuilder(). + SetAuthorName(*e.User().GlobalName).SetAuthorIcon(*e.User().AvatarURL()).SetTitle("\""+modal.Title+"\"").SetDescription("This is the submitted result"). + SetColor(custom.GetColor("primary")).SetFields(fields...). + Build()). + SetContainerComponents(discord.NewActionRow(discord. + NewButton(discord.ButtonStylePrimary, "Comment", "form:"+form_manage_id+";comment", ""). + WithEmoji(discord.ComponentEmoji{Name: "👥"}))). + Build()) + if err != nil { + logrus.Error(err) + } else { + err = e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Submitted!").SetEphemeral(true).Build()) + if err != nil { + logrus.Error(err) + } + } + } else { + var buttons []discord.InteractiveComponent + if result.CommentCategoryID != "" { + buttons = []discord.InteractiveComponent{discord. + NewButton(discord.ButtonStylePrimary, "Comment", "form:"+form_manage_id+";comment", ""). + WithEmoji(discord.ComponentEmoji{Name: "👥"})} + } + buttons = append(buttons, discord. + NewButton(discord.ButtonStyleDanger, "Decline", "form:"+form_manage_id+";decline", ""). + WithEmoji(discord.ComponentEmoji{Name: "🛑"}), + discord. + NewButton(discord.ButtonStyleSuccess, "Approve", "form:"+form_manage_id+";approve", ""). + WithEmoji(discord.ComponentEmoji{Name: "🎉"})) + _, err := e.Client().Rest().CreateMessage(snowflake.MustParse(result.AcceptChannelID), discord.NewMessageCreateBuilder(). + SetEmbeds(discord.NewEmbedBuilder(). + SetAuthorName(*e.User().GlobalName).SetAuthorIcon(*e.User().AvatarURL()).SetTitle("\""+modal.Title+"\"").SetDescription("**This submission needs approval.**"). + SetColor(custom.GetColor("primary")).SetFields(fields...). + Build()). + SetContainerComponents(discord.NewActionRow(buttons...)). + Build()) + + if err != nil { + logrus.Error(err) + } else { + err = e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Submitted!").SetEphemeral(true).Build()) + if err != nil { + logrus.Error(err) + } + } + } + } + } else { + err := e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("The results would be submited...").SetEphemeral(true).Build()) + if err != nil { + logrus.Error(err) + } + } + + }, + Autocomplete: func(e *events.AutocompleteInteractionCreate) { + err := e.AutocompleteResult([]discord.AutocompleteChoice{ + &discord.AutocompleteChoiceString{ + Name: "Support Ticket", + Value: "template_ticket", + }, + &discord.AutocompleteChoiceString{ + Name: "Submit URL", + Value: "template_url", + }, + &discord.AutocompleteChoiceString{ + Name: "General", + Value: "template_general", + }, + }) + if err != nil { + logrus.Error(err) + } + }, + }, + { + Definition: discord.SlashCommandCreate{ + Name: "ticket", + DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageChannels), + Description: "A quick command to create Ticketpanels. (/form for more)", + Contexts: []discord.InteractionContextType{ + discord.InteractionContextTypeGuild, + discord.InteractionContextTypePrivateChannel}, + Options: []discord.ApplicationCommandOption{ + &discord.ApplicationCommandOptionString{ + Name: "title", + Description: "The title the ticket should have", + }, + &discord.ApplicationCommandOptionMentionable{ + Name: "moderator", + Description: "Who can interact with moderating buttons.", + }, + }, + }, + Interact: func(e *events.ApplicationCommandInteractionCreate) { + var title string = "Ticket" + var moderator string + data := e.SlashCommandInteractionData() + if data.String("title") != "" { + title = data.String("title") + } + moderator = data.Role("moderator").ID.String() + if moderator == "" { + moderator = data.User("moderator").ID.String() + } + var exists bool = true + var formManageID uuid.UUID = uuid.New() + for exists { + formManageID = uuid.New() + exists = getFormManageIdExists(formManageID) + } + messagebuild := discord.NewMessageCreateBuilder().SetEmbeds(discord.NewEmbedBuilder(). + SetTitle(title).SetDescription("Press the bottom button to open a form popup.").SetColor(custom.GetColor("primary")). + Build()).SetContainerComponents(discord.ActionRowComponent{ + discord.NewSuccessButton("Submit", "form:"+formManageID.String()).WithEmoji(discord.ComponentEmoji{ + Name: "anim_rocket", + ID: snowflake.MustParse("1215740398706757743"), + Animated: true, + })}). + Build() + message, err := e.Client().Rest().CreateMessage(e.Channel().ID(), messagebuild) + if err != nil { + logrus.Error(err) + return + } + if title == "" { + title = "Ticket" + } + var category string + c, err := e.Client().Rest().CreateGuildChannel(*e.GuildID(), discord.GuildCategoryChannelCreate{Name: title + " mod answers"}) + if err != nil { + logrus.Error(err) + } + category = c.ID().String() + if title == "Ticket" { + title = "" + } + + addFormButton(e.GuildID().String(), e.Channel().ID().String(), message.ID.String(), formManageID.String(), "template_ticket", "", title, "", category, moderator) + err = e.CreateMessage(discord.NewMessageCreateBuilder().SetContent("Successfully added ticket panel!\n(`/form` for more options or custom ticket forms.)").SetEphemeral(true).Build()) + if err != nil { + logrus.Error(err) + } + }, + }, + }, +} + +// moderator can be userID as well as roleID +func createFormComment(form_manage_id string, author snowflake.ID, moderator snowflake.ID, commentName string, embed discord.Embed, guildID snowflake.ID, client bot.Client) discord.Channel { + var category snowflake.ID = snowflake.MustParse(getFormResultValues(form_manage_id).CommentCategoryID) + _, err := client.Rest().GetChannel(category) + if err != nil { + c, err := client.Rest().CreateGuildChannel(guildID, discord.GuildCategoryChannelCreate{Name: strings.Trim(embed.Title, "\"") + " mod " + commentName + "s"}) + if err != nil { + logrus.Error(err) + } + category = c.ID() + updateFormCommentCategory(form_manage_id, category.String()) + } + ch, err := client.Rest().CreateGuildChannel(guildID, discord.GuildTextChannelCreate{ + ParentID: category, + Name: strings.ToLower(embed.Author.Name) + "-" + commentName, + }) + if err != nil { + logrus.Error(err) + } + var permissionOverwrites []discord.PermissionOverwrite = []discord.PermissionOverwrite{ + discord.RolePermissionOverwrite{ + RoleID: guildID, + Deny: discord.PermissionViewChannel, + }} + + if shared.IsIDRole(client, guildID, moderator) { + permissionOverwrites = append(permissionOverwrites, discord.RolePermissionOverwrite{ + RoleID: moderator, + Allow: discord.PermissionViewChannel, + }) + } else { + permissionOverwrites = append(permissionOverwrites, discord.MemberPermissionOverwrite{ + UserID: moderator, + Allow: discord.PermissionViewChannel, + }) + } + permissionOverwrites = append(permissionOverwrites, discord.RolePermissionOverwrite{ + RoleID: author, + Allow: discord.PermissionViewChannel, + }) + _, err = client.Rest().UpdateChannel(ch.ID(), discord.GuildTextChannelUpdate{PermissionOverwrites: &permissionOverwrites}) + if err != nil { + logrus.Error(err) + } + modTypeChar := "" + if shared.IsIDRole(client, guildID, moderator) { + modTypeChar = "&" + } + embed.Description = "This was submitted" + _, err = client.Rest().CreateMessage(ch.ID(), discord.NewMessageCreateBuilder(). + SetContent("<@"+modTypeChar+moderator.String()+"> <@"+author.String()+">").SetEmbeds(embed). + Build()) + if err != nil { + logrus.Error(err) + } + return ch +} + +func getFormButtonIDs() []string { + var IDs []string = []string{"form_demo"} + var formButtonIDs []string = getFormManageIDs() + for _, buttonID := range formButtonIDs { + IDs = append(IDs, "form:"+buttonID) + } + return IDs +} diff --git a/plugin_src/forms/tool.go b/plugin_src/forms/tool.go new file mode 100644 index 0000000..d2692f2 --- /dev/null +++ b/plugin_src/forms/tool.go @@ -0,0 +1,15 @@ +package main + +import ( + "github.com/disgoorg/disgo/bot" + "github.com/disgoorg/snowflake/v2" +) + +func findAndDeleteUnusedMessages(c bot.Client) { + for _, message := range getAllSavedMessages() { + _, err := c.Rest().GetMessage(snowflake.MustParse(message.ChannelID), snowflake.MustParse(message.ID)) + if err != nil { + tryDeleteUnusedMessage(message.ID) + } + } +} diff --git a/plugin_src/info/main.go b/plugin_src/info/main.go index 4187b36..b55c781 100644 --- a/plugin_src/info/main.go +++ b/plugin_src/info/main.go @@ -3,12 +3,12 @@ package main import ( "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" - "github.com/vaporvee/acecore/cmd" + "github.com/vaporvee/acecore/shared" ) -var Plugin = &cmd.Plugin{ +var Plugin = &shared.Plugin{ Name: "Info", - Commands: []cmd.Command{ + Commands: []shared.Command{ { Definition: discord.SlashCommandCreate{ Name: "info", diff --git a/plugin_src/simplefun/cmd_ask.go b/plugin_src/simplefun/cmd_ask.go index 6ba5065..b9969b9 100644 --- a/plugin_src/simplefun/cmd_ask.go +++ b/plugin_src/simplefun/cmd_ask.go @@ -4,11 +4,11 @@ import ( "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" "github.com/vaporvee/acecore/custom" + "github.com/vaporvee/acecore/shared" ) -var cmd_ask = cmd.Command{ +var cmd_ask = shared.Command{ Definition: discord.SlashCommandCreate{ Name: "ask", Description: "Ask anything and get a gif as response!", diff --git a/plugin_src/simplefun/cmd_cat.go b/plugin_src/simplefun/cmd_cat.go index d37bf27..b9425d7 100644 --- a/plugin_src/simplefun/cmd_cat.go +++ b/plugin_src/simplefun/cmd_cat.go @@ -8,11 +8,11 @@ import ( "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" "github.com/vaporvee/acecore/custom" + "github.com/vaporvee/acecore/shared" ) -var cmd_cat = cmd.Command{ +var cmd_cat = shared.Command{ Definition: discord.SlashCommandCreate{ Name: "cat", Description: "Random cat pictures", diff --git a/plugin_src/simplefun/cmd_dadjoke.go b/plugin_src/simplefun/cmd_dadjoke.go index a5cff7c..6a31ad6 100644 --- a/plugin_src/simplefun/cmd_dadjoke.go +++ b/plugin_src/simplefun/cmd_dadjoke.go @@ -4,10 +4,10 @@ import ( "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" "github.com/sirupsen/logrus" - "github.com/vaporvee/acecore/cmd" + "github.com/vaporvee/acecore/shared" ) -var cmd_dadjoke = cmd.Command{ +var cmd_dadjoke = shared.Command{ Definition: discord.SlashCommandCreate{ Name: "dadjoke", Description: "Gives you a random joke that is as bad as your dad would tell them", diff --git a/plugin_src/simplefun/go.mod b/plugin_src/simplefun/go.mod deleted file mode 100644 index 81a9d83..0000000 --- a/plugin_src/simplefun/go.mod +++ /dev/null @@ -1,20 +0,0 @@ -module github.com/vaporvee/acecore/simplefun - -go 1.22.1 - -require ( - github.com/disgoorg/disgo v0.18.2 - github.com/sirupsen/logrus v1.9.3 - github.com/vaporvee/acecore v0.0.0-20240414202630-d814d39cf135 - github.com/vaporvee/acecore/cmd v0.0.0-20240414202630-d814d39cf135 -) - -require ( - github.com/disgoorg/json v1.1.0 // indirect - github.com/disgoorg/snowflake/v2 v2.0.1 // indirect - github.com/gorilla/websocket v1.5.1 // indirect - github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad // indirect - golang.org/x/crypto v0.19.0 // indirect - golang.org/x/net v0.21.0 // indirect - golang.org/x/sys v0.17.0 // indirect -) diff --git a/plugin_src/simplefun/main.go b/plugin_src/simplefun/main.go index 734668d..f2123fc 100644 --- a/plugin_src/simplefun/main.go +++ b/plugin_src/simplefun/main.go @@ -1,10 +1,40 @@ package main import ( - "github.com/vaporvee/acecore/cmd" + "encoding/json" + "io" + "net/http" + + "github.com/sirupsen/logrus" + "github.com/vaporvee/acecore/shared" ) -var Plugin = &cmd.Plugin{ +var Plugin = &shared.Plugin{ Name: "Simple Fun", - Commands: []cmd.Command{cmd_ask, cmd_cat, cmd_dadjoke}, + Commands: []shared.Command{cmd_ask, cmd_cat, cmd_dadjoke}, +} + +func simpleGetFromAPI(key string, url string) interface{} { + client := &http.Client{} + req, err := http.NewRequest("GET", url, nil) + if err != nil { + logrus.Error("Error creating request:", err) + } + req.Header.Set("Accept", "application/json") + resp, err := client.Do(req) + if err != nil { + logrus.Error("Error making request:", err) + } + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + logrus.Error("Error reading response body:", err) + } + + var result map[string]interface{} + err = json.Unmarshal(body, &result) + if err != nil { + logrus.Error("Error decoding JSON:", err) + } + return result[key] } diff --git a/plugin_src/simplefun/tool.go b/plugin_src/simplefun/tool.go deleted file mode 100644 index 21f19b4..0000000 --- a/plugin_src/simplefun/tool.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "encoding/json" - "io" - "net/http" - - "github.com/sirupsen/logrus" -) - -func simpleGetFromAPI(key string, url string) interface{} { - client := &http.Client{} - req, err := http.NewRequest("GET", url, nil) - if err != nil { - logrus.Error("Error creating request:", err) - } - req.Header.Set("Accept", "application/json") - resp, err := client.Do(req) - if err != nil { - logrus.Error("Error making request:", err) - } - defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) - if err != nil { - logrus.Error("Error reading response body:", err) - } - - var result map[string]interface{} - err = json.Unmarshal(body, &result) - if err != nil { - logrus.Error("Error decoding JSON:", err) - } - return result[key] -} diff --git a/plugin_src/stickymessages/data.go b/plugin_src/stickymessages/data.go new file mode 100644 index 0000000..9c26004 --- /dev/null +++ b/plugin_src/stickymessages/data.go @@ -0,0 +1,62 @@ +package main + +import ( + "github.com/sirupsen/logrus" +) + +func addSticky(guildID string, channelID string, messageContent string, messageID string) { + _, err := db.Exec("INSERT INTO sticky (guild_id, channel_id, message_id, message_content) VALUES ($1, $2, $3, $4)", guildID, channelID, messageID, messageContent) + if err != nil { + logrus.Error(err) + } + +} + +func hasSticky(guildID string, channelID string) bool { + var exists bool + err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM sticky WHERE guild_id = $1 AND channel_id = $2)", guildID, channelID).Scan(&exists) + if err != nil { + logrus.Error(err) + } + return exists +} + +func getStickyMessageID(guildID string, channelID string) string { + var messageID string + exists := hasSticky(guildID, channelID) + if exists { + err := db.QueryRow("SELECT message_id FROM sticky WHERE guild_id = $1 AND channel_id = $2", guildID, channelID).Scan(&messageID) + if err != nil { + logrus.Error(err) + } + } + return messageID +} +func getStickyMessageContent(guildID string, channelID string) string { + var messageID string + exists := hasSticky(guildID, channelID) + if exists { + err := db.QueryRow("SELECT message_content FROM sticky WHERE guild_id = $1 AND channel_id = $2", guildID, channelID).Scan(&messageID) + if err != nil { + logrus.Error(err) + } + } + return messageID +} + +func updateStickyMessageID(guildID string, channelID string, messageID string) { + exists := hasSticky(guildID, channelID) + if exists { + _, err := db.Exec("UPDATE sticky SET message_id = $1 WHERE guild_id = $2 AND channel_id = $3", messageID, guildID, channelID) + if err != nil { + logrus.Error(err) + } + } +} + +func removeSticky(guildID string, channelID string) { + _, err := db.Exec("DELETE FROM sticky WHERE guild_id = $1 AND channel_id = $2", guildID, channelID) + if err != nil { + logrus.Error(err) + } +} diff --git a/plugin_src/stickymessages/listener.go b/plugin_src/stickymessages/listener.go new file mode 100644 index 0000000..9b554bc --- /dev/null +++ b/plugin_src/stickymessages/listener.go @@ -0,0 +1,33 @@ +package main + +import ( + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/snowflake/v2" + "github.com/sirupsen/logrus" + "github.com/vaporvee/acecore/custom" +) + +func messageCreate(e *events.MessageCreate) { + if len(e.Message.Embeds) == 0 || e.Message.Embeds[0].Footer == nil || e.Message.Embeds[0].Footer.Text != "📌 Sticky message" { + if hasSticky(e.Message.GuildID.String(), e.Message.ChannelID.String()) { + stickymessageID := getStickyMessageID(e.Message.GuildID.String(), e.Message.ChannelID.String()) + err := e.Client().Rest().DeleteMessage(e.ChannelID, snowflake.MustParse(stickymessageID)) + stickyMessage, _ := e.Client().Rest().CreateMessage(e.ChannelID, discord.MessageCreate{ + Embeds: []discord.Embed{ + { + Footer: &discord.EmbedFooter{ + Text: "📌 Sticky message", + }, + Color: custom.GetColor("primary"), + Description: getStickyMessageContent(e.Message.GuildID.String(), e.Message.ChannelID.String()), + }, + }, + }) + if err != nil { + logrus.Error(err) + } + updateStickyMessageID(e.Message.GuildID.String(), e.Message.ChannelID.String(), stickyMessage.ID.String()) + } + } +} diff --git a/plugin_src/stickymessages/main.go b/plugin_src/stickymessages/main.go new file mode 100644 index 0000000..7092e22 --- /dev/null +++ b/plugin_src/stickymessages/main.go @@ -0,0 +1,145 @@ +package main + +import ( + "database/sql" + + "github.com/disgoorg/disgo/bot" + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/json" + "github.com/disgoorg/snowflake/v2" + "github.com/sirupsen/logrus" + "github.com/vaporvee/acecore/custom" + "github.com/vaporvee/acecore/shared" +) + +var db *sql.DB + +var dbCreateQuery string = `CREATE TABLE IF NOT EXISTS sticky ( + message_id TEXT NOT NULL, + channel_id TEXT NOT NULL, + message_content TEXT NOT NULL, + guild_id TEXT NOT NULL, + PRIMARY KEY (channel_id, guild_id) +); +` + +var Plugin = &shared.Plugin{ + Name: "Sticky Messages", + Init: func(d *sql.DB) error { + db = d + _, err := d.Exec(dbCreateQuery) + if err != nil { + return err + } + shared.BotConfigs = append(shared.BotConfigs, bot.WithEventListenerFunc(messageCreate)) + return nil + }, + Commands: []shared.Command{ + { + Definition: discord.SlashCommandCreate{ + Name: "sticky", + Description: "Stick or unstick messages to the bottom of the current channel", + DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageMessages), + Contexts: []discord.InteractionContextType{ + discord.InteractionContextTypeGuild, + discord.InteractionContextTypePrivateChannel}, + IntegrationTypes: []discord.ApplicationIntegrationType{ + discord.ApplicationIntegrationTypeGuildInstall}, + Options: []discord.ApplicationCommandOption{ + &discord.ApplicationCommandOptionString{ + Name: "message", + Description: "The message you want to stick to the bottom of this channel", + Required: false, + }, + }, + }, + Interact: func(e *events.ApplicationCommandInteractionCreate) { + if len(e.SlashCommandInteractionData().Options) == 0 { + if hasSticky(e.GuildID().String(), e.Channel().ID().String()) { + err := e.Client().Rest().DeleteMessage(e.Channel().ID(), snowflake.MustParse(getStickyMessageID(e.GuildID().String(), e.Channel().ID().String()))) + if err != nil { + logrus.Error(err) + } + removeSticky(e.GuildID().String(), e.Channel().ID().String()) + err = e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("The sticky message was removed from this channel!").SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } else { + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("This channel has no sticky message!").SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } + } else { + inputStickyMessage(e) + } + }, + }, + { + Definition: discord.MessageCommandCreate{ + Name: "Stick to channel", + DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageMessages), + Contexts: []discord.InteractionContextType{ + discord.InteractionContextTypeGuild, + discord.InteractionContextTypePrivateChannel}, + IntegrationTypes: []discord.ApplicationIntegrationType{ + discord.ApplicationIntegrationTypeGuildInstall}, + }, + Interact: func(e *events.ApplicationCommandInteractionCreate) { + inputStickyMessage(e) + }, + }, + }, +} + +func inputStickyMessage(e *events.ApplicationCommandInteractionCreate) { + var messageText string + if e.ApplicationCommandInteraction.Data.Type() == discord.ApplicationCommandTypeMessage { + messageText = e.MessageCommandInteractionData().TargetMessage().Content //TODO add more data then just content + } else { + messageText = e.SlashCommandInteractionData().String("message") + } + if messageText == "" { + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Can't add empty sticky messages!").SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } else { + message, err := e.Client().Rest().CreateMessage(e.Channel().ID(), discord.MessageCreate{Embeds: []discord.Embed{ + {Description: messageText, Footer: &discord.EmbedFooter{Text: "📌 Sticky message"}, Color: custom.GetColor("primary")}}}) + if err != nil { + logrus.Error(err) + } + + if hasSticky(e.GuildID().String(), e.Channel().ID().String()) { + err = e.Client().Rest().DeleteMessage(e.Channel().ID(), snowflake.MustParse(getStickyMessageID(e.GuildID().String(), e.Channel().ID().String()))) + if err != nil { + logrus.Error(err, getStickyMessageID(e.GuildID().String(), e.Channel().ID().String())) + } + removeSticky(e.GuildID().String(), e.Channel().ID().String()) + addSticky(e.GuildID().String(), e.Channel().ID().String(), messageText, message.ID.String()) + err = e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Sticky message in this channel was updated!").SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } else { + addSticky(e.GuildID().String(), e.Channel().ID().String(), messageText, message.ID.String()) + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Message sticked to the channel!").SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } + } +} diff --git a/plugin_src/tags/cmd_tag.go b/plugin_src/tags/cmd_tag.go new file mode 100644 index 0000000..6e3eb14 --- /dev/null +++ b/plugin_src/tags/cmd_tag.go @@ -0,0 +1,217 @@ +package main + +import ( + "database/sql" + + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/json" + "github.com/sirupsen/logrus" + "github.com/vaporvee/acecore/shared" +) + +var db *sql.DB + +var createTableQuery string = `CREATE TABLE IF NOT EXISTS tags ( + tag_id TEXT NOT NULL, + tag_name TEXT NOT NULL, + tag_content TEXT NOT NULL, + guild_id TEXT NOT NULL, + PRIMARY KEY (tag_id, guild_id) + ); +` + +var Plugin = &shared.Plugin{ + Name: "Tag System", + Init: func(d *sql.DB) error { + db = d + _, err := db.Exec(createTableQuery) + if err != nil { + logrus.Fatal(err) + } + return nil + }, + Commands: []shared.Command{ + { + Definition: discord.SlashCommandCreate{ + Name: "tag", + DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageGuild), + Description: "A command to show and edit saved presaved messages.", + Contexts: []discord.InteractionContextType{ + discord.InteractionContextTypeGuild, + discord.InteractionContextTypePrivateChannel}, + IntegrationTypes: []discord.ApplicationIntegrationType{ + discord.ApplicationIntegrationTypeGuildInstall}, + Options: []discord.ApplicationCommandOption{ + discord.ApplicationCommandOptionSubCommand{ + Name: "get", + Description: "A command to get messages saved to the bot.", + Options: []discord.ApplicationCommandOption{ + discord.ApplicationCommandOptionString{ + Name: "tag", + Description: "Your predefined tag for the saved message", + Required: true, + Autocomplete: true, + }, + }, + }, + discord.ApplicationCommandOptionSubCommand{ + Name: "add", + Description: "A command to add messages saved to the bot.", + }, + discord.ApplicationCommandOptionSubCommand{ + Name: "remove", + Description: "A command to remove messages saved to the bot.", + Options: []discord.ApplicationCommandOption{ + discord.ApplicationCommandOptionString{ + Name: "tag", + Description: "The tag you want to remove", + Required: true, + Autocomplete: true, + }, + }, + }, + }, + }, + Interact: func(e *events.ApplicationCommandInteractionCreate) { + switch *e.SlashCommandInteractionData().SubCommandName { + case "get": + GetTagCommand(e) + case "add": + AddTagCommand(e) + case "remove": + removeTag(e.GuildID().String(), e.SlashCommandInteractionData().String("tag")) + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Tag removed!").SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + } + }, + ModalIDs: []string{"tag_add_modal"}, + ModalSubmit: func(e *events.ModalSubmitInteractionCreate) { + tagName := e.Data.Text("tag_add_modal_name") + tagContent := e.Data.Text("tag_add_modal_content") + addTag(e.GuildID().String(), tagName, tagContent) + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent("Tag \"" + tagName + "\" added!").SetEphemeral(true). + Build()) + if err != nil { + logrus.Error(err) + } + }, + Autocomplete: func(e *events.AutocompleteInteractionCreate) { + AutocompleteTag(e) + }, + }, + { + Definition: discord.SlashCommandCreate{ + Name: "g", + Description: "A short command to get presaved messages.", + Contexts: []discord.InteractionContextType{ + discord.InteractionContextTypeGuild, + discord.InteractionContextTypePrivateChannel}, + IntegrationTypes: []discord.ApplicationIntegrationType{ + discord.ApplicationIntegrationTypeGuildInstall}, + Options: []discord.ApplicationCommandOption{ + discord.ApplicationCommandOptionString{ + Name: "tag", + Description: "Your predefined tag for the saved message", + Required: true, + Autocomplete: true, + }, + }, + }, + Interact: func(e *events.ApplicationCommandInteractionCreate) { + GetTagCommand(e) + }, + Autocomplete: func(e *events.AutocompleteInteractionCreate) { + AutocompleteTag(e) + }, + }, + { + Definition: discord.MessageCommandCreate{ + Name: "Save as tag", + DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionManageGuild), + Contexts: []discord.InteractionContextType{ + discord.InteractionContextTypeGuild, + discord.InteractionContextTypePrivateChannel}, + IntegrationTypes: []discord.ApplicationIntegrationType{ + discord.ApplicationIntegrationTypeGuildInstall}, + }, + Interact: func(e *events.ApplicationCommandInteractionCreate) { + AddTagCommand(e) + }, + }, + }, +} + +func GetTagCommand(e *events.ApplicationCommandInteractionCreate) { + err := e.CreateMessage(discord.NewMessageCreateBuilder(). + SetContent(getTagContent(e.GuildID().String(), e.SlashCommandInteractionData().String("tag"))). + Build()) + if err != nil { + logrus.Error(err) + } +} + +func AddTagCommand(e *events.ApplicationCommandInteractionCreate) { + var prevalue string + if e.ApplicationCommandInteraction.Data.Type() == discord.ApplicationCommandTypeMessage { + prevalue = e.MessageCommandInteractionData().TargetMessage().Content + } + err := e.Modal(discord.ModalCreate{ + CustomID: "tag_add_modal" + e.User().ID.String(), + Title: "Add a custom tag command", + Components: []discord.ContainerComponent{ + discord.ActionRowComponent{ + discord.TextInputComponent{ + CustomID: "tag_add_modal_name", + Label: "Name", + Style: discord.TextInputStyleShort, + Required: true, + MaxLength: 20, + Value: "", + }, + }, + discord.ActionRowComponent{ + discord.TextInputComponent{ + CustomID: "tag_add_modal_content", + Label: "Content", + Style: discord.TextInputStyleParagraph, + Required: true, + MaxLength: 2000, + Value: prevalue, + }, + }, + }, + }) + if err != nil { + logrus.Error(err) + } +} + +func AutocompleteTag(e *events.AutocompleteInteractionCreate) { + err := e.AutocompleteResult(generateTagChoices(e.GuildID().String())) + if err != nil { + logrus.Error(err) + } +} + +func generateTagChoices(guildID string) []discord.AutocompleteChoice { + choices := []discord.AutocompleteChoice{} + IDs, err := getTagIDs(guildID) + if err != nil { + logrus.Error(err) + return choices + } + for _, id := range IDs { + id_name := getTagName(guildID, id) + choices = append(choices, &discord.AutocompleteChoiceString{ + Name: id_name, + Value: id, + }) + } + return choices +} diff --git a/plugin_src/tags/data.go b/plugin_src/tags/data.go new file mode 100644 index 0000000..2b2b366 --- /dev/null +++ b/plugin_src/tags/data.go @@ -0,0 +1,70 @@ +package main + +import ( + "github.com/google/uuid" + "github.com/sirupsen/logrus" +) + +func addTag(guildID, tagName, tagContent string) bool { + var exists bool = true + //TODO: add modify command + id := uuid.New() + for exists { + id = uuid.New() + err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM tags WHERE guild_id = $1 AND tag_id = $2)", guildID, id).Scan(&exists) + if err != nil { + logrus.Error(err) + } + } + _, err := db.Exec("INSERT INTO tags (guild_id, tag_name, tag_content, tag_id) VALUES ($1, $2, $3, $4)", guildID, tagName, tagContent, id) + if err != nil { + logrus.Error(err) + } + + return exists +} +func removeTag(guildID string, tagID string) { + var exists bool + err := db.QueryRow("SELECT EXISTS (SELECT 1 FROM tags WHERE guild_id = $1 AND tag_id = $2)", guildID, tagID).Scan(&exists) + if err != nil { + logrus.Error(err) + } + if exists { + _, err = db.Exec("DELETE FROM tags WHERE guild_id = $1 AND tag_id = $2", guildID, tagID) + if err != nil { + logrus.Error(err) + } + } +} +func getTagIDs(guildID string) ([]string, error) { + var IDs []string + rows, err := db.Query("SELECT tag_id FROM tags WHERE guild_id = $1", guildID) + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var id string + if err := rows.Scan(&id); err != nil { + return nil, err + } + IDs = append(IDs, id) + } + + if err := rows.Err(); err != nil { + return nil, err + } + + return IDs, nil +} +func getTagName(guildID string, tagID string) string { + var tagName string + db.QueryRow("SELECT tag_name FROM tags WHERE guild_id = $1 AND tag_id = $2", guildID, tagID).Scan(&tagName) + return tagName +} +func getTagContent(guildID string, tagID string) string { + var tagContent string + db.QueryRow("SELECT tag_content FROM tags WHERE guild_id = $1 AND tag_id = $2", guildID, tagID).Scan(&tagContent) + return tagContent +} diff --git a/form_templates/form_demo.json b/shared/form_templates/form_demo.json similarity index 100% rename from form_templates/form_demo.json rename to shared/form_templates/form_demo.json diff --git a/form_templates/template_general.json b/shared/form_templates/template_general.json similarity index 100% rename from form_templates/template_general.json rename to shared/form_templates/template_general.json diff --git a/form_templates/template_ticket.json b/shared/form_templates/template_ticket.json similarity index 100% rename from form_templates/template_ticket.json rename to shared/form_templates/template_ticket.json diff --git a/form_templates/template_url.json b/shared/form_templates/template_url.json similarity index 100% rename from form_templates/template_url.json rename to shared/form_templates/template_url.json diff --git a/cmd/go.mod b/shared/go.mod similarity index 82% rename from cmd/go.mod rename to shared/go.mod index bb7d4bd..8a0e69a 100644 --- a/cmd/go.mod +++ b/shared/go.mod @@ -1,4 +1,4 @@ -module github.com/vaporvee/acecore/cmd +module github.com/vaporvee/acecore/shared go 1.22.1 @@ -9,6 +9,7 @@ require ( github.com/disgoorg/snowflake/v2 v2.0.1 // indirect github.com/gorilla/websocket v1.5.1 // indirect github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad // indirect + github.com/sirupsen/logrus v1.9.3 // indirect golang.org/x/crypto v0.19.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/sys v0.17.0 // indirect diff --git a/plugin_src/simplefun/go.sum b/shared/go.sum similarity index 85% rename from plugin_src/simplefun/go.sum rename to shared/go.sum index ddde2be..73a90c7 100644 --- a/plugin_src/simplefun/go.sum +++ b/shared/go.sum @@ -19,10 +19,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/vaporvee/acecore v0.0.0-20240414202630-d814d39cf135 h1:LdMezyBJ9Q8/VIugcvc6X37/0L9poxKU6zq36ooJN3U= -github.com/vaporvee/acecore v0.0.0-20240414202630-d814d39cf135/go.mod h1:kRHYJwIF7PW99J8BzDqVtV7c0PoitgdpR/e06emJm1s= -github.com/vaporvee/acecore/cmd v0.0.0-20240414202630-d814d39cf135 h1:SbwOoMX4LViUCuH8syFUKPsKXBONY3PhSrkKVNmFJYc= -github.com/vaporvee/acecore/cmd v0.0.0-20240414202630-d814d39cf135/go.mod h1:03W2NrAPbAqa7gsqAM+2K/wT28stj9BmEhC5NzeGe3A= golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= diff --git a/cmd/main.go b/shared/main.go similarity index 80% rename from cmd/main.go rename to shared/main.go index 537cf08..efc3161 100644 --- a/cmd/main.go +++ b/shared/main.go @@ -1,13 +1,15 @@ -package cmd +package shared import ( "database/sql" + "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" ) type Command struct { + Ready func(e *events.Ready) Definition discord.ApplicationCommandCreate Interact func(e *events.ApplicationCommandInteractionCreate) Autocomplete func(e *events.AutocompleteInteractionCreate) @@ -21,6 +23,8 @@ type Command struct { type Plugin struct { Name string - Register func(e *events.Ready, db *sql.DB) error + Init func(d *sql.DB) error Commands []Command } + +var BotConfigs []bot.ConfigOpt diff --git a/shared/tool.go b/shared/tool.go new file mode 100644 index 0000000..39e5ed1 --- /dev/null +++ b/shared/tool.go @@ -0,0 +1,114 @@ +package shared + +import ( + "embed" + "encoding/json" + "fmt" + "strings" + + "github.com/disgoorg/disgo/bot" + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/snowflake/v2" + "github.com/sirupsen/logrus" +) + +type ModalJsonField struct { + Label string `json:"label"` + IsParagraph bool `json:"is_paragraph"` + Value string `json:"value"` + Required bool `json:"required"` + Placeholder string `json:"placeholder"` + MinLength int `json:"min_length"` + MaxLength int `json:"max_length"` +} + +type ModalJson struct { + FormType string `json:"form_type"` + Title string `json:"title"` + Form []ModalJsonField `json:"form"` +} + +// Why does the golang compiler care about commands?? +// +//go:embed form_templates/*.json +var FormTemplates embed.FS + +func GetModalByFormID(formID string) ModalJson { + var modal ModalJson + if formID == "" { + return modal + } + entries, err := FormTemplates.ReadDir("form_templates") + if err != nil { + logrus.Error(err) + return modal + } + for _, entry := range entries { + if strings.HasPrefix(entry.Name(), formID) { + jsonFile, err := FormTemplates.ReadFile("form_templates/" + entry.Name()) + if err != nil { + logrus.Error(err) + continue + } + err = json.Unmarshal(jsonFile, &modal) + if err != nil { + logrus.Error(err) + continue + } + break + } + } + return modal +} + +func JsonStringBuildModal(userID string, manageID string, formID string, overwrite ...string) discord.ModalCreate { + var modal ModalJson = GetModalByFormID(formID) + var components []discord.ContainerComponent + for index, component := range modal.Form { + var style discord.TextInputStyle = discord.TextInputStyleShort + if component.IsParagraph { + style = discord.TextInputStyleParagraph + } + components = append(components, discord.ActionRowComponent{ + discord.TextInputComponent{ + CustomID: fmt.Sprint(index), + Label: component.Label, + Style: style, + Placeholder: component.Placeholder, + Required: component.Required, + MaxLength: component.MaxLength, + MinLength: &component.MinLength, + Value: component.Value, + }, + }) + } + if overwrite != nil && overwrite[0] != "" { + modal.Title = overwrite[0] + } + + return discord.ModalCreate{ + CustomID: "form:" + manageID + ":" + userID, + Title: modal.Title, + Components: components, + } + +} + +func IsIDRole(c bot.Client, guildID snowflake.ID, id snowflake.ID) bool { + _, err1 := c.Rest().GetMember(guildID, id) + if err1 == nil { + return false + } + roles, err2 := c.Rest().GetRoles(guildID) + if err2 == nil { + for _, role := range roles { + if role.ID == id { + return true + } + } + } + + logrus.Error(err1) + logrus.Error(err2) + return false +} diff --git a/tool.go b/tool.go deleted file mode 100644 index cefb796..0000000 --- a/tool.go +++ /dev/null @@ -1,230 +0,0 @@ -package main - -import ( - "embed" - "encoding/json" - "fmt" - "io" - "net/http" - "strings" - - "github.com/disgoorg/disgo/bot" - "github.com/disgoorg/disgo/discord" - "github.com/disgoorg/disgo/rest" - "github.com/disgoorg/snowflake/v2" - "github.com/sirupsen/logrus" -) - -type ModalJsonField struct { - Label string `json:"label"` - IsParagraph bool `json:"is_paragraph"` - Value string `json:"value"` - Required bool `json:"required"` - Placeholder string `json:"placeholder"` - MinLength int `json:"min_length"` - MaxLength int `json:"max_length"` -} - -type ModalJson struct { - FormType string `json:"form_type"` - Title string `json:"title"` - Form []ModalJsonField `json:"form"` -} - -type MessageIDs struct { - ID string - ChannelID string -} - -func jsonStringBuildModal(userID string, manageID string, formID string, overwrite ...string) discord.ModalCreate { - var modal ModalJson = getModalByFormID(formID) - var components []discord.ContainerComponent - for index, component := range modal.Form { - var style discord.TextInputStyle = discord.TextInputStyleShort - if component.IsParagraph { - style = discord.TextInputStyleParagraph - } - components = append(components, discord.ActionRowComponent{ - discord.TextInputComponent{ - CustomID: fmt.Sprint(index), - Label: component.Label, - Style: style, - Placeholder: component.Placeholder, - Required: component.Required, - MaxLength: component.MaxLength, - MinLength: &component.MinLength, - Value: component.Value, - }, - }) - } - if overwrite != nil && overwrite[0] != "" { - modal.Title = overwrite[0] - } - - return discord.ModalCreate{ - CustomID: "form:" + manageID + ":" + userID, - Title: modal.Title, - Components: components, - } - -} - -// Why does the golang compiler care about commands?? -// -//go:embed form_templates/*.json -var formTemplates embed.FS - -func getModalByFormID(formID string) ModalJson { - var modal ModalJson - if formID == "" { - return modal - } - entries, err := formTemplates.ReadDir("form_templates") - if err != nil { - logrus.Error(err) - return modal - } - for _, entry := range entries { - if strings.HasPrefix(entry.Name(), formID) { - jsonFile, err := formTemplates.ReadFile("form_templates/" + entry.Name()) - if err != nil { - logrus.Error(err) - continue - } - err = json.Unmarshal(jsonFile, &modal) - if err != nil { - logrus.Error(err) - continue - } - break - } - } - return modal -} - -func getHighestRole(guildID string, c bot.Client) (*discord.Role, error) { - botmember, err := c.Rest().GetMember(snowflake.MustParse(guildID), c.ApplicationID()) - if err != nil { - return nil, err - } - roles, err := c.Rest().GetRoles(snowflake.MustParse(guildID)) - if err != nil { - return nil, err - } - var highestRole *discord.Role - for _, roleID := range botmember.RoleIDs { - for _, role := range roles { - if role.ID == roleID { - if highestRole == nil || role.Position > highestRole.Position { - highestRole = &role - } - break - } - } - } - return highestRole, nil -} - -func simpleGetFromAPI(key string, url string) interface{} { - client := &http.Client{} - req, err := http.NewRequest("GET", url, nil) - if err != nil { - logrus.Error("Error creating request:", err) - } - req.Header.Set("Accept", "application/json") - resp, err := client.Do(req) - if err != nil { - logrus.Error("Error making request:", err) - } - defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) - if err != nil { - logrus.Error("Error reading response body:", err) - } - - var result map[string]interface{} - err = json.Unmarshal(body, &result) - if err != nil { - logrus.Error("Error decoding JSON:", err) - } - return result[key] -} - -func findAndDeleteUnusedMessages(c bot.Client) { - for _, message := range getAllSavedMessages() { - _, err := c.Rest().GetMessage(snowflake.MustParse(message.ChannelID), snowflake.MustParse(message.ID)) - if err != nil { - tryDeleteUnusedMessage(message.ID) - } - } -} - -func isIDRole(c bot.Client, guildID snowflake.ID, id snowflake.ID) bool { - _, err1 := c.Rest().GetMember(guildID, id) - if err1 == nil { - return false - } - roles, err2 := c.Rest().GetRoles(guildID) - if err2 == nil { - for _, role := range roles { - if role.ID == id { - return true - } - } - } - - logrus.Error(err1) - logrus.Error(err2) - return false -} - -func isGIFImage(imageData []byte) bool { - if len(imageData) < 6 { - return false - } - // Check for the GIF89a header at the beginning of the byte array - if string(imageData[0:6]) == "GIF89a" { - return true - } - // Check for the GIF87a header at the beginning of the byte array - if string(imageData[0:6]) == "GIF87a" { - return true - } - return false -} - -func messageIsPoll(channelID string, messageID string, client bot.Client) bool { - url := rest.DefaultConfig().URL + "/channels/" + channelID + "/messages/" + messageID - - req, err := http.NewRequest("GET", url, nil) - if err != nil { - logrus.Error(err) - return false - } - - auth := "Bot " + client.Token() - req.Header.Set("Authorization", auth) - - resp, err := client.Rest().HTTPClient().Do(req) - if err != nil { - logrus.Error(err) - return false - } - defer resp.Body.Close() - - body, err := io.ReadAll(resp.Body) - if err != nil { - logrus.Error(err) - return false - } - - var data map[string]interface{} - err = json.Unmarshal(body, &data) - if err != nil { - logrus.Error(err) - return false - } - - _, ok := data["poll"] - return ok -} diff --git a/web/html/privacy.html b/web/html/privacy.html index 38bdc30..06b05d9 100644 --- a/web/html/privacy.html +++ b/web/html/privacy.html @@ -43,7 +43,7 @@ services.
  • - cmd.Command usage: We store data about some commands that you use within + shared.Command usage: We store data about some commands that you use within acecore in order to make the commands usable and functioning.