Discord Components & Role Selection (#5)

This commit is contained in:
2023-04-01 01:23:37 -04:00
committed by GitHub
parent 5e6a433b92
commit e1038a15cd
25 changed files with 696 additions and 31 deletions

View File

@ -0,0 +1,61 @@
package modules
import (
"fmt"
"github.com/yeslayla/birdbot/common"
"github.com/yeslayla/birdbot/mastodon"
)
type announceEventsModule struct {
bot common.ModuleManager
mastodon *mastodon.Mastodon
guildID string
}
// NewAnnounceEventsComponent creates a new component
func NewAnnounceEventsComponent(mastodon *mastodon.Mastodon, guildID string) common.Module {
return &announceEventsModule{
mastodon: mastodon,
guildID: guildID,
}
}
// Initialize registers event listeners
func (c *announceEventsModule) Initialize(birdbot common.ModuleManager) error {
c.bot = birdbot
_ = birdbot.OnEventCreate(c.OnEventCreate)
_ = birdbot.OnEventDelete(c.OnEventDelete)
return nil
}
// OnEventCreate notifies about the event creation to given providers
func (c *announceEventsModule) OnEventCreate(e common.Event) error {
eventURL := fmt.Sprintf("https://discordapp.com/events/%s/%s", c.guildID, e.ID)
c.bot.Notify(fmt.Sprintf("%s is organizing an event '%s': %s", e.Organizer.DiscordMention(), e.Name, eventURL))
// Toot an announcement if Mastodon is configured
if c.mastodon != nil {
err := c.mastodon.Toot(fmt.Sprintf("A new event has been organized '%s': %s", e.Name, eventURL))
if err != nil {
fmt.Println("Failed to send Mastodon Toot:", err)
}
}
return nil
}
func (c *announceEventsModule) OnEventDelete(e common.Event) error {
_ = c.bot.Notify(fmt.Sprintf("%s cancelled '%s' on %s, %d!", e.Organizer.DiscordMention(), e.Name, e.DateTime.Month().String(), e.DateTime.Day()))
if c.mastodon != nil {
err := c.mastodon.Toot(fmt.Sprintf("'%s' cancelled on %s, %d!", e.Name, e.DateTime.Month().String(), e.DateTime.Day()))
if err != nil {
fmt.Println("Failed to send Mastodon Toot:", err)
}
}
return nil
}

View File

@ -0,0 +1,89 @@
package modules
import (
"log"
"github.com/yeslayla/birdbot/common"
"github.com/yeslayla/birdbot/core"
"github.com/yeslayla/birdbot/discord"
)
type manageEventChannelsModule struct {
session *discord.Discord
categoryID string
archiveCategoryID string
}
// NewManageEventChannelsComponent creates a new component
func NewManageEventChannelsComponent(categoryID string, archiveCategoryID string, session *discord.Discord) common.Module {
return &manageEventChannelsModule{
session: session,
categoryID: categoryID,
archiveCategoryID: archiveCategoryID,
}
}
// Initialize registers event listeners
func (c *manageEventChannelsModule) Initialize(birdbot common.ModuleManager) error {
_ = birdbot.OnEventCreate(c.OnEventCreate)
_ = birdbot.OnEventComplete(c.OnEventComplete)
_ = birdbot.OnEventDelete(c.OnEventDelete)
return nil
}
// OnEventCreate creates a new channel for an event and moves it to a given category
func (c *manageEventChannelsModule) OnEventCreate(e common.Event) error {
channel, err := c.session.NewChannelFromName(core.GenerateChannelFromEvent(e).Name)
if err != nil {
log.Print("Failed to create channel for event: ", err)
}
if c.categoryID != "" {
err = c.session.MoveChannelToCategory(channel, c.categoryID)
if err != nil {
log.Printf("Failed to move channel to events category '%s': %v", channel.Name, err)
}
}
return nil
}
// OnEventDelete deletes the channel associated with the given event
func (c *manageEventChannelsModule) OnEventDelete(e common.Event) error {
_, err := c.session.DeleteChannel(core.GenerateChannelFromEvent(e))
if err != nil {
log.Print("Failed to create channel for event: ", err)
}
return nil
}
// OnEventComplete archives a given event channel if not given
// an archive category will delete the channel instead
func (c *manageEventChannelsModule) OnEventComplete(e common.Event) error {
channel := core.GenerateChannelFromEvent(e)
if c.archiveCategoryID != "" {
if err := c.session.MoveChannelToCategory(channel, c.archiveCategoryID); err != nil {
log.Print("Failed to move channel to archive category: ", err)
}
if err := c.session.ArchiveChannel(channel); err != nil {
log.Print("Failed to archive channel: ", err)
}
log.Printf("Archived channel: '%s'", channel.Name)
} else {
// Delete Channel
_, err := c.session.DeleteChannel(channel)
if err != nil {
log.Print("Failed to delete channel: ", err)
}
log.Printf("Deleted channel: '%s'", channel.Name)
}
return nil
}

View File

@ -0,0 +1,43 @@
package modules
import (
"log"
"strings"
"github.com/yeslayla/birdbot/common"
"github.com/yeslayla/birdbot/discord"
)
type recurringEventsModule struct {
session *discord.Discord
}
// NewRecurringEventsComponent creates a new component instance
func NewRecurringEventsComponent() common.Module {
return &recurringEventsModule{}
}
// Initialize registers event listeners
func (c *recurringEventsModule) Initialize(birdbot common.ModuleManager) error {
_ = birdbot.OnEventComplete(c.OnEventComplete)
return nil
}
// OnEventComplete checks for keywords before creating a new event
func (c *recurringEventsModule) OnEventComplete(e common.Event) error {
if strings.Contains(strings.ToLower(e.Description), "recurring weekly") {
startTime := e.DateTime.AddDate(0, 0, 7)
finishTime := e.CompleteDateTime.AddDate(0, 0, 7)
nextEvent := e
nextEvent.DateTime = startTime
nextEvent.CompleteDateTime = finishTime
if err := c.session.CreateEvent(nextEvent); err != nil {
log.Print("Failed to create recurring event: ", err)
}
}
return nil
}

90
modules/role_selection.go Normal file
View File

@ -0,0 +1,90 @@
package modules
import (
"fmt"
"log"
"github.com/yeslayla/birdbot/common"
"github.com/yeslayla/birdbot/core"
"github.com/yeslayla/birdbot/discord"
)
type roleSelectionModule struct {
session *discord.Discord
cfg core.RoleSelectionConfig
exlusive bool
}
// NewRoleSelectionComponent creates a new component
func NewRoleSelectionComponent(discord *discord.Discord, cfg core.RoleSelectionConfig) common.Module {
return &roleSelectionModule{
session: discord,
cfg: cfg,
exlusive: true,
}
}
// Initialize setups component on discord and registers handlers
func (c *roleSelectionModule) Initialize(birdbot common.ModuleManager) error {
roles := []*discord.Role{}
roleButtons := []discord.Component{}
for _, roleConfig := range c.cfg.Roles {
// Create & Validate Roles
role := c.session.GetRoleAndCreate(roleConfig.RoleName)
configColor, _ := core.HexToColor(roleConfig.Color)
if role.Color != configColor {
role.Color = configColor
role.Save()
}
// Create button
btn := c.session.NewButton(fmt.Sprint(c.cfg.Title, role.Name), role.Name)
btn.OnClick(func(user common.User) {
// Remove other roles if exclusive
if c.exlusive {
for _, r := range roles {
if r.ID == role.ID {
continue
}
if c.session.HasRole(user, r) {
c.session.UnassignRole(user, r)
}
}
}
// Toggle role
if c.session.HasRole(user, role) {
if err := c.session.UnassignRole(user, role); err != nil {
log.Printf("Failed to unassign role: %s", err)
}
} else if err := c.session.AssignRole(user, role); err != nil {
log.Printf("Failed to assign role: %s", err)
}
})
roles = append(roles, role)
roleButtons = append(roleButtons, btn)
}
components := []discord.Component{}
var actionRow *discord.ActionRow
for i, btn := range roleButtons {
if i%5 == 0 {
actionRow = c.session.NewActionRow()
components = append(components, actionRow)
}
actionRow.AddComponent(btn)
}
c.session.CreateMessageComponent(c.cfg.SelectionChannel, fmt.Sprintf("**%s**\n%s", c.cfg.Title, c.cfg.Description), components)
return nil
}