Skip to content

Commit

Permalink
Example of dynamic poll with two answers
Browse files Browse the repository at this point in the history
  • Loading branch information
Rpi-Dude committed Aug 18, 2024
1 parent b736321 commit 397cfed
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 1 deletion.
221 changes: 221 additions & 0 deletions examples/polls/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
package main

import (
"flag"
"log"
"os"
"os/signal"

"github.com/bwmarrin/discordgo"
)

// Bot parameters
var (
GuildID = flag.String("guild", "", "Test guild ID. If not passed - bot registers commands globally")
BotToken = flag.String("token", "", "Bot access token")
RemoveCommands = flag.Bool("rmcmd", true, "Remove all commands after shutdowning or not")
)

var s *discordgo.Session

func init() { flag.Parse() }

func init() {
var err error
s, err = discordgo.New("Bot " + *BotToken)
if err != nil {
log.Fatalf("Invalid bot parameters: %v", err)
}
}

var (
commands = []*discordgo.ApplicationCommand{
{
Name: "poll",
Description: "Sample command for creating polls",
Options: []*discordgo.ApplicationCommandOption{
{
// Questions are limited to 300 characters
Type: discordgo.ApplicationCommandOptionString,
Name: "question",
Description: "The question/heading for the poll",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionBoolean,
Name: "mulit-select",
Description: "Allow multiple Choices",
Required: true,
},
{
// Duration can go upto 32 days
Type: discordgo.ApplicationCommandOptionInteger,
Name: "duration",
Description: "Duration of the poll",
Required: true,
// The duration is an integer indicated in hours
Choices: []*discordgo.ApplicationCommandOptionChoice{
{
Name: "1 hour",
Value: 1,
},
{
Name: "4 hours",
Value: 4,
},
{
Name: "8 hours",
Value: 8,
},
{
Name: "24 hours",
Value: 24,
},
{
Name: "3 days",
Value: 72,
},
{
Name: "1 week",
Value: 168,
},
{
Name: "2 weeks",
Value: 336,
},
},
},
// Answers and emojis
{
// The answers are limited to 55 characters
Type: discordgo.ApplicationCommandOptionString,
Name: "answer-1",
Description: "First option for the poll",
Required: true,
},
{
Type: discordgo.ApplicationCommandOptionString,
Name: "answer-2",
Description: "Second option for the poll",
},
// Can be further continued upto 10
},
},
}

commandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){
"poll": func(s *discordgo.Session, i *discordgo.InteractionCreate) {

// Access options in the order provided by the user
options := i.ApplicationCommandData().Options

// Create an array of answers
answers := make([]discordgo.PollAnswer, len(options)-3)

for i := 0; i < len(answers); i++ {
answer := discordgo.PollAnswer{
AnswerID: 0,
Media: &discordgo.PollMedia{
Text: options[i+3].StringValue(),
},
}
answers[i] = answer
}

// Create a variable to hold the values from the command
poll := discordgo.Poll{
Question: discordgo.PollMedia{Text: i.ApplicationCommandData().Options[0].StringValue()},
Answers: answers,
AllowMultiselect: i.ApplicationCommandData().Options[1].BoolValue(),
Duration: int(i.ApplicationCommandData().Options[2].IntValue()),
}

s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Poll: &poll,
},
})
},
}
)

func init() {
s.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) {
if h, ok := commandHandlers[i.ApplicationCommandData().Name]; ok {
h(s, i)
}
})
}

func main() {
s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) {
log.Printf("Logged in as: %v#%v", s.State.User.Username, s.State.User.Discriminator)
})

err := s.Open()
if err != nil {
log.Fatalf("Cannot open the session: %v", err)
}

syncCommands(s, "", commands)

defer s.Close()

stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
log.Println("Press Ctrl+C to exit")
<-stop

}

func syncCommands(s *discordgo.Session, guildID string, desiredCommandList []*discordgo.ApplicationCommand) {
existingCommands, err := s.ApplicationCommands(s.State.User.ID, guildID)
if err != nil {
log.Fatalf("Failed to fetch commands for guild %s: %v", guildID, err)
return
}

desiredMap := make(map[string]*discordgo.ApplicationCommand)
for _, cmd := range desiredCommandList {
desiredMap[cmd.Name] = cmd
}

existingMap := make(map[string]*discordgo.ApplicationCommand)
for _, cmd := range existingCommands {
existingMap[cmd.Name] = cmd
}

// Delete commands not in the desired list
for _, cmd := range existingCommands {
if _, found := desiredMap[cmd.Name]; !found {
err := s.ApplicationCommandDelete(s.State.User.ID, guildID, cmd.ID)
if err != nil {
log.Printf("Failed to delete command %s (%s) in guild %s: %v", cmd.Name, cmd.ID, guildID, err)
} else {
log.Printf("Successfully deleted command %s (%s) in guild %s", cmd.Name, cmd.ID, guildID)
}
}
}

// Create or update existing commands
for _, cmd := range desiredCommandList {
if existingCmd, found := existingMap[cmd.Name]; found {
// Edit existing command
_, err := s.ApplicationCommandEdit(s.State.User.ID, guildID, existingCmd.ID, cmd)
if err != nil {
log.Printf("Failed to edit command %s (%s) in guild %s: %v", cmd.Name, cmd.ID, guildID, err)
} else {
log.Printf("Successfully edited command %s (%s) in guild %s", cmd.Name, cmd.ID, guildID)
}
} else {
// Create new command
_, err := s.ApplicationCommandCreate(s.State.User.ID, guildID, cmd)
if err != nil {
log.Printf("Failed to create command %s in guild %s: %v", cmd.Name, guildID, err)
} else {
log.Printf("Successfully created command %s in guild %s", cmd.Name, guildID)
}
}
}
}
2 changes: 1 addition & 1 deletion structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2374,7 +2374,7 @@ type PollResults struct {

// Poll contains all poll related data.
type Poll struct {
Question string `json:"question"`
Question PollMedia `json:"question"`
Answers []PollAnswer `json:"answers"`
AllowMultiselect bool `json:"allow_multiselect"`
LayoutType PollLayoutType `json:"layout_type,omitempty"`
Expand Down

0 comments on commit 397cfed

Please sign in to comment.