Compentize Workload (#4)
This commit is contained in:
154
app/bot.go
154
app/bot.go
@ -1,13 +1,10 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ilyakaznacheev/cleanenv"
|
"github.com/yeslayla/birdbot/common"
|
||||||
"github.com/yeslayla/birdbot/core"
|
"github.com/yeslayla/birdbot/core"
|
||||||
"github.com/yeslayla/birdbot/discord"
|
"github.com/yeslayla/birdbot/discord"
|
||||||
"github.com/yeslayla/birdbot/mastodon"
|
"github.com/yeslayla/birdbot/mastodon"
|
||||||
@ -17,34 +14,29 @@ var Version string
|
|||||||
var Build string
|
var Build string
|
||||||
|
|
||||||
type Bot struct {
|
type Bot struct {
|
||||||
session *discord.Discord
|
Session *discord.Discord
|
||||||
mastodon *mastodon.Mastodon
|
Mastodon *mastodon.Mastodon
|
||||||
|
|
||||||
// Discord Objects
|
// Discord Objects
|
||||||
guildID string
|
guildID string
|
||||||
eventCategoryID string
|
eventCategoryID string
|
||||||
archiveCategoryID string
|
archiveCategoryID string
|
||||||
notificationChannelID string
|
notificationChannelID string
|
||||||
|
|
||||||
|
onReadyHandlers [](func() error)
|
||||||
|
onNotifyHandlers [](func(string) error)
|
||||||
|
|
||||||
|
onEventCreatedHandlers [](func(common.Event) error)
|
||||||
|
onEventDeletedHandlers [](func(common.Event) error)
|
||||||
|
onEventUpdatedHandlers [](func(common.Event) error)
|
||||||
|
onEventCompletedHandlers [](func(common.Event) error)
|
||||||
|
|
||||||
|
gameModules []common.GameModule
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initalize creates the discord session and registers handlers
|
// Initalize creates the discord session and registers handlers
|
||||||
func (app *Bot) Initialize(config_path string) error {
|
func (app *Bot) Initialize(cfg *core.Config) error {
|
||||||
log.Printf("Using config: %s", config_path)
|
|
||||||
cfg := &core.Config{}
|
|
||||||
|
|
||||||
_, err := os.Stat(config_path)
|
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
|
||||||
log.Printf("Config file not found: '%s'", config_path)
|
|
||||||
err := cleanenv.ReadEnv(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err := cleanenv.ReadConfig(config_path, cfg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Load directly from config
|
// Load directly from config
|
||||||
app.guildID = cfg.Discord.GuildID
|
app.guildID = cfg.Discord.GuildID
|
||||||
app.eventCategoryID = cfg.Discord.EventCategory
|
app.eventCategoryID = cfg.Discord.EventCategory
|
||||||
@ -58,30 +50,30 @@ func (app *Bot) Initialize(config_path string) error {
|
|||||||
if cfg.Mastodon.ClientID != "" && cfg.Mastodon.ClientSecret != "" &&
|
if cfg.Mastodon.ClientID != "" && cfg.Mastodon.ClientSecret != "" &&
|
||||||
cfg.Mastodon.Username != "" && cfg.Mastodon.Password != "" &&
|
cfg.Mastodon.Username != "" && cfg.Mastodon.Password != "" &&
|
||||||
cfg.Mastodon.Server != "" {
|
cfg.Mastodon.Server != "" {
|
||||||
app.mastodon = mastodon.NewMastodon(cfg.Mastodon.Server, cfg.Mastodon.ClientID, cfg.Mastodon.ClientSecret,
|
app.Mastodon = mastodon.NewMastodon(cfg.Mastodon.Server, cfg.Mastodon.ClientID, cfg.Mastodon.ClientSecret,
|
||||||
cfg.Mastodon.Username, cfg.Mastodon.Password)
|
cfg.Mastodon.Username, cfg.Mastodon.Password)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.session = discord.New(app.guildID, cfg.Discord.Token)
|
app.Session = discord.New(app.guildID, cfg.Discord.Token)
|
||||||
|
|
||||||
// Register Event Handlers
|
// Register Event Handlers
|
||||||
app.session.OnReady(app.onReady)
|
app.Session.OnReady(app.onReady)
|
||||||
app.session.OnEventCreate(app.onEventCreate)
|
app.Session.OnEventCreate(app.onEventCreate)
|
||||||
app.session.OnEventDelete(app.onEventDelete)
|
app.Session.OnEventDelete(app.onEventDelete)
|
||||||
app.session.OnEventUpdate(app.onEventUpdate)
|
app.Session.OnEventUpdate(app.onEventUpdate)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run opens the session with Discord until exit
|
// Run opens the session with Discord until exit
|
||||||
func (app *Bot) Run() error {
|
func (app *Bot) Run() error {
|
||||||
return app.session.Run()
|
return app.Session.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop triggers a graceful shutdown of the app
|
// Stop triggers a graceful shutdown of the app
|
||||||
func (app *Bot) Stop() {
|
func (app *Bot) Stop() {
|
||||||
log.Print("Shuting down...")
|
log.Print("Shuting down...")
|
||||||
app.session.Stop()
|
app.Session.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify sends a message to the notification channe;
|
// Notify sends a message to the notification channe;
|
||||||
@ -93,110 +85,76 @@ func (app *Bot) Notify(message string) {
|
|||||||
|
|
||||||
log.Print("Notification: ", message)
|
log.Print("Notification: ", message)
|
||||||
|
|
||||||
channel := app.session.NewChannelFromID(app.notificationChannelID)
|
channel := app.Session.NewChannelFromID(app.notificationChannelID)
|
||||||
if channel == nil {
|
if channel == nil {
|
||||||
log.Printf("Failed notification: channel was not found with ID '%v'", app.notificationChannelID)
|
log.Printf("Failed notification: channel was not found with ID '%v'", app.notificationChannelID)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := app.session.SendMessage(channel, message)
|
err := app.Session.SendMessage(channel, message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print("Failed notification: ", err)
|
log.Print("Failed notification: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, handler := range app.onNotifyHandlers {
|
||||||
|
if err := handler(message); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bot) onReady(d *discord.Discord) {
|
func (app *Bot) onReady(d *discord.Discord) {
|
||||||
app.session.SetStatus(fmt.Sprintf("with fire! (%s)", Version))
|
app.Session.SetStatus(fmt.Sprintf("with fire! (%s)", Version))
|
||||||
|
|
||||||
|
for _, handler := range app.onReadyHandlers {
|
||||||
|
if err := handler(); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bot) onEventCreate(d *discord.Discord, event *core.Event) {
|
func (app *Bot) onEventCreate(d *discord.Discord, event common.Event) {
|
||||||
|
|
||||||
log.Print("Event Created: '", event.Name, "':'", event.Location, "'")
|
log.Print("Event Created: '", event.Name, "':'", event.Location, "'")
|
||||||
|
for _, handler := range app.onEventCreatedHandlers {
|
||||||
channel, err := app.session.NewChannelFromName(event.Channel().Name)
|
if err := handler(event); err != nil {
|
||||||
if err != nil {
|
log.Println(err)
|
||||||
log.Print("Failed to create channel for event: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if app.eventCategoryID != "" {
|
|
||||||
err = app.session.MoveChannelToCategory(channel, app.eventCategoryID)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to move channel to events category '%s': %v", channel.Name, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eventURL := fmt.Sprintf("https://discordapp.com/events/%s/%s", app.guildID, event.ID)
|
|
||||||
app.Notify(fmt.Sprintf("%s is organizing an event '%s': %s", event.Organizer.Mention(), event.Name, eventURL))
|
|
||||||
|
|
||||||
if app.mastodon != nil {
|
|
||||||
err = app.mastodon.Toot(fmt.Sprintf("A new event has been organized '%s': %s", event.Name, eventURL))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Failed to send Mastodon Toot:", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *Bot) onEventDelete(d *discord.Discord, event common.Event) {
|
||||||
|
|
||||||
|
for _, handler := range app.onEventDeletedHandlers {
|
||||||
|
if err := handler(event); err != nil {
|
||||||
|
log.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bot) onEventDelete(d *discord.Discord, event *core.Event) {
|
|
||||||
|
|
||||||
_, err := app.session.DeleteChannel(event.Channel())
|
|
||||||
if err != nil {
|
|
||||||
log.Print("Failed to create channel for event: ", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Notify(fmt.Sprintf("%s cancelled '%s' on %s, %d!", event.Organizer.Mention(), event.Name, event.DateTime.Month().String(), event.DateTime.Day()))
|
func (app *Bot) onEventUpdate(d *discord.Discord, event common.Event) {
|
||||||
|
|
||||||
if app.mastodon != nil {
|
for _, handler := range app.onEventUpdatedHandlers {
|
||||||
err = app.mastodon.Toot(fmt.Sprintf("'%s' cancelled on %s, %d!", event.Name, event.DateTime.Month().String(), event.DateTime.Day()))
|
if err := handler(event); err != nil {
|
||||||
if err != nil {
|
log.Println(err)
|
||||||
fmt.Println("Failed to send Mastodon Toot:", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bot) onEventUpdate(d *discord.Discord, event *core.Event) {
|
|
||||||
// Pass event onwards
|
// Pass event onwards
|
||||||
if event.Completed {
|
if event.Completed {
|
||||||
app.onEventComplete(d, event)
|
app.onEventComplete(d, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bot) onEventComplete(d *discord.Discord, event *core.Event) {
|
func (app *Bot) onEventComplete(d *discord.Discord, event common.Event) {
|
||||||
|
|
||||||
channel := event.Channel()
|
for _, handler := range app.onEventCompletedHandlers {
|
||||||
|
if err := handler(event); err != nil {
|
||||||
if app.archiveCategoryID != "" {
|
log.Println(err)
|
||||||
|
|
||||||
if err := app.session.MoveChannelToCategory(channel, app.archiveCategoryID); err != nil {
|
|
||||||
log.Print("Failed to move channel to archive category: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := app.session.ArchiveChannel(channel); err != nil {
|
|
||||||
log.Print("Failed to archive channel: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Archived channel: '%s'", channel.Name)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// Delete Channel
|
|
||||||
_, err := app.session.DeleteChannel(channel)
|
|
||||||
if err != nil {
|
|
||||||
log.Print("Failed to delete channel: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Deleted channel: '%s'", channel.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(strings.ToLower(event.Description), "recurring weekly") {
|
|
||||||
startTime := event.DateTime.AddDate(0, 0, 7)
|
|
||||||
finishTime := event.CompleteTime.AddDate(0, 0, 7)
|
|
||||||
nextEvent := event
|
|
||||||
nextEvent.DateTime = startTime
|
|
||||||
nextEvent.CompleteTime = finishTime
|
|
||||||
|
|
||||||
if err := app.session.CreateEvent(nextEvent); err != nil {
|
|
||||||
log.Print("Failed to create recurring event: ", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBot() *Bot {
|
func NewBot() *Bot {
|
||||||
|
64
app/component_loader.go
Normal file
64
app/component_loader.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/yeslayla/birdbot/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ComponentLoader struct {
|
||||||
|
bot *Bot
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewComponentLoader(bot *Bot) *ComponentLoader {
|
||||||
|
return &ComponentLoader{
|
||||||
|
bot: bot,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loader *ComponentLoader) LoadComponent(component common.Component) {
|
||||||
|
if err := component.Initialize(loader); err != nil {
|
||||||
|
log.Print("Failed to load component: ", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loader *ComponentLoader) OnReady(handler func() error) error {
|
||||||
|
loader.bot.onReadyHandlers = append(loader.bot.onReadyHandlers, handler)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loader *ComponentLoader) OnNotify(handler func(string) error) error {
|
||||||
|
loader.bot.onNotifyHandlers = append(loader.bot.onNotifyHandlers, handler)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loader *ComponentLoader) OnEventCreate(handler func(common.Event) error) error {
|
||||||
|
loader.bot.onEventCreatedHandlers = append(loader.bot.onEventCreatedHandlers, handler)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (loader *ComponentLoader) OnEventDelete(handler func(common.Event) error) error {
|
||||||
|
loader.bot.onEventDeletedHandlers = append(loader.bot.onEventDeletedHandlers, handler)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (loader *ComponentLoader) OnEventUpdate(handler func(common.Event) error) error {
|
||||||
|
loader.bot.onEventUpdatedHandlers = append(loader.bot.onEventUpdatedHandlers, handler)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (loader *ComponentLoader) OnEventComplete(handler func(common.Event) error) error {
|
||||||
|
loader.bot.onEventCompletedHandlers = append(loader.bot.onEventCompletedHandlers, handler)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loader *ComponentLoader) RegisterGameModule(ID string, plugin common.GameModule) error {
|
||||||
|
return fmt.Errorf("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loader *ComponentLoader) CreateEvent(event common.Event) error {
|
||||||
|
return loader.bot.Session.CreateEvent(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loader *ComponentLoader) Notify(message string) error {
|
||||||
|
loader.bot.Notify(message)
|
||||||
|
return nil
|
||||||
|
}
|
22
common/component.go
Normal file
22
common/component.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
type Component interface {
|
||||||
|
Initialize(birdbot ComponentManager) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type ComponentManager interface {
|
||||||
|
OnReady(func() error) error
|
||||||
|
|
||||||
|
OnNotify(func(string) error) error
|
||||||
|
|
||||||
|
// Event events
|
||||||
|
OnEventCreate(func(Event) error) error
|
||||||
|
OnEventDelete(func(Event) error) error
|
||||||
|
OnEventUpdate(func(Event) error) error
|
||||||
|
OnEventComplete(func(Event) error) error
|
||||||
|
|
||||||
|
RegisterGameModule(ID string, plugin GameModule) error
|
||||||
|
|
||||||
|
CreateEvent(event Event) error
|
||||||
|
Notify(message string) error
|
||||||
|
}
|
18
common/event.go
Normal file
18
common/event.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Event struct {
|
||||||
|
Name string
|
||||||
|
ID string
|
||||||
|
Location string
|
||||||
|
Completed bool
|
||||||
|
DateTime time.Time
|
||||||
|
CompleteDateTime time.Time
|
||||||
|
Description string
|
||||||
|
ImageURL string
|
||||||
|
|
||||||
|
Organizer User
|
||||||
|
}
|
6
common/game_plugin.go
Normal file
6
common/game_plugin.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
type GameModule interface {
|
||||||
|
SendMessage(user string, message string)
|
||||||
|
RecieveMessage(user User, message string)
|
||||||
|
}
|
18
common/user.go
Normal file
18
common/user.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID string
|
||||||
|
AvatarURL string
|
||||||
|
DisplayName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscordMention generated a Discord mention string for the user
|
||||||
|
func (user *User) DiscordMention() string {
|
||||||
|
if user == nil {
|
||||||
|
return "<NULL>"
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("<@%s>", user.ID)
|
||||||
|
}
|
@ -1,7 +1,43 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/yeslayla/birdbot/common"
|
||||||
|
)
|
||||||
|
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
Name string
|
Name string
|
||||||
ID string
|
ID string
|
||||||
Verified bool
|
Verified bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GenerateEventChannelName(eventName string, location string, dateTime time.Time) string {
|
||||||
|
month := GetMonthPrefix(dateTime)
|
||||||
|
day := dateTime.Day()
|
||||||
|
city := GetCityFromLocation(location)
|
||||||
|
year := dateTime.Year()
|
||||||
|
|
||||||
|
channel := fmt.Sprint(month, "-", day, city, "-", eventName, "-", year)
|
||||||
|
channel = strings.ReplaceAll(channel, " ", "-")
|
||||||
|
channel = strings.ToLower(channel)
|
||||||
|
|
||||||
|
re, _ := regexp.Compile(`[^\w\-]`)
|
||||||
|
channel = re.ReplaceAllString(channel, "")
|
||||||
|
|
||||||
|
return channel
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateChannel returns a channel object associated with an event
|
||||||
|
func GenerateChannel(event common.Event) *Channel {
|
||||||
|
|
||||||
|
channelName := GenerateEventChannelName(event.Name, event.Location, event.DateTime)
|
||||||
|
|
||||||
|
return &Channel{
|
||||||
|
Name: channelName,
|
||||||
|
Verified: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ package core
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
Discord DiscordConfig `yaml:"discord"`
|
Discord DiscordConfig `yaml:"discord"`
|
||||||
Mastodon MastodonConfig `yaml:"mastodon"`
|
Mastodon MastodonConfig `yaml:"mastodon"`
|
||||||
|
Features Features `yaml:"features"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DiscordConfig struct {
|
type DiscordConfig struct {
|
||||||
@ -21,3 +22,10 @@ type MastodonConfig struct {
|
|||||||
ClientID string `yaml:"client_id" env:"MASTODON_CLIENT_ID"`
|
ClientID string `yaml:"client_id" env:"MASTODON_CLIENT_ID"`
|
||||||
ClientSecret string `yaml:"client_secret" env:"MASTODON_CLIENT_SECRET"`
|
ClientSecret string `yaml:"client_secret" env:"MASTODON_CLIENT_SECRET"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Features struct {
|
||||||
|
ManageEventChannels bool `yaml:"manage_event_channels" env:"BIRD_EVENT_CHANNELS" env-default:"true"`
|
||||||
|
AnnounceEvents bool `yaml:"announce_events" env:"BIRD_ANNOUNCE_EVENTS" env-default:"true"`
|
||||||
|
ReccurringEvents bool `yaml:"recurring_events" env:"BIRD_RECURRING_EVENTS" env-default:"true"`
|
||||||
|
LoadGamePlugins bool `yaml:"load_game_plugins" env:"BIRD_LOAD_GAME_PLUGINS" env-default:"true"`
|
||||||
|
}
|
||||||
|
@ -1,99 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const REMOTE_LOCATION string = "online"
|
|
||||||
|
|
||||||
type Event struct {
|
|
||||||
Name string
|
|
||||||
ID string
|
|
||||||
Location string
|
|
||||||
Completed bool
|
|
||||||
DateTime time.Time
|
|
||||||
CompleteTime time.Time
|
|
||||||
Description string
|
|
||||||
Image string
|
|
||||||
|
|
||||||
Organizer *User
|
|
||||||
}
|
|
||||||
|
|
||||||
// Channel returns a channel object associated with an event
|
|
||||||
func (event *Event) Channel() *Channel {
|
|
||||||
|
|
||||||
month := event.GetMonthPrefix()
|
|
||||||
day := event.DateTime.Day()
|
|
||||||
city := event.GetCityFromLocation()
|
|
||||||
year := event.DateTime.Year()
|
|
||||||
|
|
||||||
channel := fmt.Sprint(month, "-", day, city, "-", event.Name, "-", year)
|
|
||||||
channel = strings.ReplaceAll(channel, " ", "-")
|
|
||||||
channel = strings.ToLower(channel)
|
|
||||||
|
|
||||||
re, _ := regexp.Compile(`[^\w\-]`)
|
|
||||||
channel = re.ReplaceAllString(channel, "")
|
|
||||||
|
|
||||||
return &Channel{
|
|
||||||
Name: channel,
|
|
||||||
Verified: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCityFromLocation returns the city name of an event's location
|
|
||||||
func (event *Event) GetCityFromLocation() string {
|
|
||||||
|
|
||||||
if event.Location == REMOTE_LOCATION {
|
|
||||||
return fmt.Sprint("-", REMOTE_LOCATION)
|
|
||||||
}
|
|
||||||
parts := strings.Split(event.Location, " ")
|
|
||||||
index := -1
|
|
||||||
loc := event.Location
|
|
||||||
|
|
||||||
for i, v := range parts {
|
|
||||||
part := strings.ToLower(v)
|
|
||||||
if part == "mi" || part == "michigan" {
|
|
||||||
index = i - 1
|
|
||||||
if index < 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if index > 0 && parts[index] == "," {
|
|
||||||
index -= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if index > 1 && strings.Contains(parts[index-2], ",") {
|
|
||||||
loc = fmt.Sprintf("%s-%s", parts[index-1], parts[index])
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
loc = parts[index]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprint("-", loc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMonthPrefix returns a month in short form
|
|
||||||
func (event *Event) GetMonthPrefix() string {
|
|
||||||
month := event.DateTime.Month()
|
|
||||||
data := map[time.Month]string{
|
|
||||||
time.January: "jan",
|
|
||||||
time.February: "feb",
|
|
||||||
time.March: "march",
|
|
||||||
time.April: "april",
|
|
||||||
time.May: "may",
|
|
||||||
time.June: "june",
|
|
||||||
time.July: "july",
|
|
||||||
time.August: "aug",
|
|
||||||
time.September: "sept",
|
|
||||||
time.October: "oct",
|
|
||||||
time.November: "nov",
|
|
||||||
time.December: "dec",
|
|
||||||
}
|
|
||||||
|
|
||||||
return data[month]
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetChannelName(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
// Test Valid Address
|
|
||||||
event := Event{
|
|
||||||
Name: "Hello World",
|
|
||||||
Location: "1234 Place Rd, Ann Arbor, MI 00000",
|
|
||||||
DateTime: time.Date(2022, time.January, 5, 0, 0, 0, 0, time.UTC),
|
|
||||||
}
|
|
||||||
assert.Equal("jan-5-ann-arbor-hello-world-2022", event.Channel().Name)
|
|
||||||
|
|
||||||
// Test Unparsable Location
|
|
||||||
// lmanley: Note it'd be nice to expand support for this
|
|
||||||
event = Event{
|
|
||||||
Name: "Hello World",
|
|
||||||
Location: "Michigan Theater, Ann Arbor",
|
|
||||||
DateTime: time.Date(2022, time.January, 5, 0, 0, 0, 0, time.UTC),
|
|
||||||
}
|
|
||||||
assert.Equal("jan-5-hello-world-2022", event.Channel().Name)
|
|
||||||
|
|
||||||
// Test Short Location
|
|
||||||
event = Event{
|
|
||||||
Name: "Hello World",
|
|
||||||
Location: "Monroe, MI",
|
|
||||||
DateTime: time.Date(2022, time.January, 5, 0, 0, 0, 0, time.UTC),
|
|
||||||
}
|
|
||||||
assert.Equal("jan-5-monroe-hello-world-2022", event.Channel().Name)
|
|
||||||
|
|
||||||
// Test Short Location
|
|
||||||
event = Event{
|
|
||||||
Name: "Hello World",
|
|
||||||
Location: "Monroe St, Monroe , MI",
|
|
||||||
DateTime: time.Date(2022, time.January, 5, 0, 0, 0, 0, time.UTC),
|
|
||||||
}
|
|
||||||
assert.Equal("jan-5-monroe-hello-world-2022", event.Channel().Name)
|
|
||||||
|
|
||||||
// Test Remote Event
|
|
||||||
event = Event{
|
|
||||||
Name: "Hello World",
|
|
||||||
Location: REMOTE_LOCATION,
|
|
||||||
DateTime: time.Date(2022, time.January, 5, 0, 0, 0, 0, time.UTC),
|
|
||||||
}
|
|
||||||
assert.Equal("jan-5-online-hello-world-2022", event.Channel().Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMonthPrefix(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
event := Event{
|
|
||||||
DateTime: time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC),
|
|
||||||
}
|
|
||||||
assert.Equal("jan", event.GetMonthPrefix())
|
|
||||||
}
|
|
42
core/location.go
Normal file
42
core/location.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const REMOTE_LOCATION string = "online"
|
||||||
|
|
||||||
|
// GetCityFromLocation returns the city name of an event's location
|
||||||
|
func GetCityFromLocation(location string) string {
|
||||||
|
|
||||||
|
if location == REMOTE_LOCATION {
|
||||||
|
return fmt.Sprint("-", REMOTE_LOCATION)
|
||||||
|
}
|
||||||
|
parts := strings.Split(location, " ")
|
||||||
|
index := -1
|
||||||
|
loc := location
|
||||||
|
|
||||||
|
for i, v := range parts {
|
||||||
|
part := strings.ToLower(v)
|
||||||
|
if part == "mi" || part == "michigan" {
|
||||||
|
index = i - 1
|
||||||
|
if index < 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if index > 0 && parts[index] == "," {
|
||||||
|
index -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if index > 1 && strings.Contains(parts[index-2], ",") {
|
||||||
|
loc = fmt.Sprintf("%s-%s", parts[index-1], parts[index])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
loc = parts[index]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprint("-", loc)
|
||||||
|
}
|
24
core/time.go
Normal file
24
core/time.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// GetMonthPrefix returns a month in short form
|
||||||
|
func GetMonthPrefix(dateTime time.Time) string {
|
||||||
|
month := dateTime.Month()
|
||||||
|
data := map[time.Month]string{
|
||||||
|
time.January: "jan",
|
||||||
|
time.February: "feb",
|
||||||
|
time.March: "march",
|
||||||
|
time.April: "april",
|
||||||
|
time.May: "may",
|
||||||
|
time.June: "june",
|
||||||
|
time.July: "july",
|
||||||
|
time.August: "aug",
|
||||||
|
time.September: "sept",
|
||||||
|
time.October: "oct",
|
||||||
|
time.November: "nov",
|
||||||
|
time.December: "dec",
|
||||||
|
}
|
||||||
|
|
||||||
|
return data[month]
|
||||||
|
}
|
16
core/user.go
16
core/user.go
@ -1,16 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
ID string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mention generated a Discord mention string for the user
|
|
||||||
func (user *User) Mention() string {
|
|
||||||
if user == nil {
|
|
||||||
return "<NULL>"
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("<@%s>", user.ID)
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestUserMention(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
|
|
||||||
// Create user object
|
|
||||||
user := &User{
|
|
||||||
ID: "sample_id",
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal("<@sample_id>", user.Mention())
|
|
||||||
|
|
||||||
// Test null user
|
|
||||||
var nullUser *User = nil
|
|
||||||
assert.NotEmpty(nullUser.Mention())
|
|
||||||
|
|
||||||
}
|
|
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
"github.com/stretchr/testify/mock"
|
"github.com/stretchr/testify/mock"
|
||||||
"github.com/yeslayla/birdbot/core"
|
"github.com/yeslayla/birdbot/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Discord struct {
|
type Discord struct {
|
||||||
@ -64,7 +64,7 @@ func (discord *Discord) OnReady(handler func(*Discord)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OnEventCreate registers a handler when a guild scheduled event is created
|
// OnEventCreate registers a handler when a guild scheduled event is created
|
||||||
func (discord *Discord) OnEventCreate(handler func(*Discord, *core.Event)) {
|
func (discord *Discord) OnEventCreate(handler func(*Discord, common.Event)) {
|
||||||
discord.session.AddHandler(func(s *discordgo.Session, r *discordgo.GuildScheduledEventCreate) {
|
discord.session.AddHandler(func(s *discordgo.Session, r *discordgo.GuildScheduledEventCreate) {
|
||||||
if r.GuildID != discord.guildID {
|
if r.GuildID != discord.guildID {
|
||||||
return
|
return
|
||||||
@ -75,7 +75,7 @@ func (discord *Discord) OnEventCreate(handler func(*Discord, *core.Event)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OnEventDelete registers a handler when a guild scheduled event is deleted
|
// OnEventDelete registers a handler when a guild scheduled event is deleted
|
||||||
func (discord *Discord) OnEventDelete(handler func(*Discord, *core.Event)) {
|
func (discord *Discord) OnEventDelete(handler func(*Discord, common.Event)) {
|
||||||
discord.session.AddHandler(func(s *discordgo.Session, r *discordgo.GuildScheduledEventDelete) {
|
discord.session.AddHandler(func(s *discordgo.Session, r *discordgo.GuildScheduledEventDelete) {
|
||||||
if r.GuildID != discord.guildID {
|
if r.GuildID != discord.guildID {
|
||||||
return
|
return
|
||||||
@ -86,7 +86,7 @@ func (discord *Discord) OnEventDelete(handler func(*Discord, *core.Event)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OnEventUpdate registers a handler when a guild scheduled event is updated
|
// OnEventUpdate registers a handler when a guild scheduled event is updated
|
||||||
func (discord *Discord) OnEventUpdate(handler func(*Discord, *core.Event)) {
|
func (discord *Discord) OnEventUpdate(handler func(*Discord, common.Event)) {
|
||||||
discord.session.AddHandler(func(s *discordgo.Session, r *discordgo.GuildScheduledEventUpdate) {
|
discord.session.AddHandler(func(s *discordgo.Session, r *discordgo.GuildScheduledEventUpdate) {
|
||||||
if r.GuildID != discord.guildID {
|
if r.GuildID != discord.guildID {
|
||||||
return
|
return
|
||||||
|
@ -4,27 +4,28 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/yeslayla/birdbot/common"
|
||||||
"github.com/yeslayla/birdbot/core"
|
"github.com/yeslayla/birdbot/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewEvent converts a discordgo.GuildScheduledEvent to birdbot event
|
// NewEvent converts a discordgo.GuildScheduledEvent to birdbot event
|
||||||
func NewEvent(guildEvent *discordgo.GuildScheduledEvent) *core.Event {
|
func NewEvent(guildEvent *discordgo.GuildScheduledEvent) common.Event {
|
||||||
event := &core.Event{
|
event := common.Event{
|
||||||
Name: guildEvent.Name,
|
Name: guildEvent.Name,
|
||||||
Description: guildEvent.Description,
|
Description: guildEvent.Description,
|
||||||
ID: guildEvent.ID,
|
ID: guildEvent.ID,
|
||||||
Organizer: &core.User{
|
Organizer: common.User{
|
||||||
ID: guildEvent.CreatorID,
|
ID: guildEvent.CreatorID,
|
||||||
},
|
},
|
||||||
DateTime: guildEvent.ScheduledStartTime,
|
DateTime: guildEvent.ScheduledStartTime,
|
||||||
Image: guildEvent.Image,
|
ImageURL: guildEvent.Image,
|
||||||
}
|
}
|
||||||
|
|
||||||
if guildEvent.ScheduledEndTime != nil {
|
if guildEvent.ScheduledEndTime != nil {
|
||||||
event.CompleteTime = *guildEvent.ScheduledEndTime
|
event.CompleteDateTime = *guildEvent.ScheduledEndTime
|
||||||
} else {
|
} else {
|
||||||
year, month, day := guildEvent.ScheduledStartTime.Date()
|
year, month, day := guildEvent.ScheduledStartTime.Date()
|
||||||
event.CompleteTime = time.Date(year, month, day, 0, 0, 0, 0, guildEvent.ScheduledStartTime.Location())
|
event.CompleteDateTime = time.Date(year, month, day, 0, 0, 0, 0, guildEvent.ScheduledStartTime.Location())
|
||||||
}
|
}
|
||||||
|
|
||||||
event.Completed = guildEvent.Status == discordgo.GuildScheduledEventStatusCompleted
|
event.Completed = guildEvent.Status == discordgo.GuildScheduledEventStatusCompleted
|
||||||
@ -38,14 +39,14 @@ func NewEvent(guildEvent *discordgo.GuildScheduledEvent) *core.Event {
|
|||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
|
|
||||||
func (discord *Discord) CreateEvent(event *core.Event) error {
|
func (discord *Discord) CreateEvent(event common.Event) error {
|
||||||
|
|
||||||
params := &discordgo.GuildScheduledEventParams{
|
params := &discordgo.GuildScheduledEventParams{
|
||||||
Name: event.Name,
|
Name: event.Name,
|
||||||
Description: event.Description,
|
Description: event.Description,
|
||||||
ScheduledStartTime: &event.DateTime,
|
ScheduledStartTime: &event.DateTime,
|
||||||
ScheduledEndTime: &event.CompleteTime,
|
ScheduledEndTime: &event.CompleteDateTime,
|
||||||
Image: event.Image,
|
Image: event.ImageURL,
|
||||||
EntityType: discordgo.GuildScheduledEventEntityTypeExternal,
|
EntityType: discordgo.GuildScheduledEventEntityTypeExternal,
|
||||||
PrivacyLevel: discordgo.GuildScheduledEventPrivacyLevelGuildOnly,
|
PrivacyLevel: discordgo.GuildScheduledEventPrivacyLevelGuildOnly,
|
||||||
}
|
}
|
||||||
|
@ -4,17 +4,19 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
"github.com/yeslayla/birdbot/core"
|
"github.com/yeslayla/birdbot/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewUser creates a new user object from a discordgo.User object
|
// NewUser creates a new user object from a discordgo.User object
|
||||||
func NewUser(user *discordgo.User) *core.User {
|
func NewUser(user *discordgo.User) common.User {
|
||||||
if user == nil {
|
if user == nil {
|
||||||
log.Print("Cannot user object, user is nil!")
|
log.Print("Cannot user object, user is nil!")
|
||||||
return nil
|
return common.User{
|
||||||
|
ID: "-1",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &core.User{
|
return common.User{
|
||||||
ID: user.ID,
|
ID: user.ID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
56
events/announce_events.go
Normal file
56
events/announce_events.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package events
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/yeslayla/birdbot/common"
|
||||||
|
"github.com/yeslayla/birdbot/mastodon"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AnnounceEventsComponent struct {
|
||||||
|
bot common.ComponentManager
|
||||||
|
mastodon *mastodon.Mastodon
|
||||||
|
guildID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAnnounceEventsComponent(mastodon *mastodon.Mastodon, guildID string) *AnnounceEventsComponent {
|
||||||
|
return &AnnounceEventsComponent{
|
||||||
|
mastodon: mastodon,
|
||||||
|
guildID: guildID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AnnounceEventsComponent) Initialize(birdbot common.ComponentManager) error {
|
||||||
|
c.bot = birdbot
|
||||||
|
|
||||||
|
_ = birdbot.OnEventCreate(c.OnEventCreate)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *AnnounceEventsComponent) 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))
|
||||||
|
|
||||||
|
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 *AnnounceEventsComponent) 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
|
||||||
|
}
|
81
events/manage_event_channels.go
Normal file
81
events/manage_event_channels.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package events
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/yeslayla/birdbot/common"
|
||||||
|
"github.com/yeslayla/birdbot/core"
|
||||||
|
"github.com/yeslayla/birdbot/discord"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ManageEventChannelsComponent struct {
|
||||||
|
session *discord.Discord
|
||||||
|
categoryID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewManageEventChannelsComponent(categoryID string, session *discord.Discord) *ManageEventChannelsComponent {
|
||||||
|
return &ManageEventChannelsComponent{
|
||||||
|
session: session,
|
||||||
|
categoryID: categoryID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ManageEventChannelsComponent) Initialize(birdbot common.ComponentManager) error {
|
||||||
|
_ = birdbot.OnEventCreate(c.OnEventCreate)
|
||||||
|
_ = birdbot.OnEventComplete(c.OnEventComplete)
|
||||||
|
_ = birdbot.OnEventDelete(c.OnEventDelete)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ManageEventChannelsComponent) OnEventCreate(e common.Event) error {
|
||||||
|
channel, err := c.session.NewChannelFromName(core.GenerateChannel(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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ManageEventChannelsComponent) OnEventDelete(e common.Event) error {
|
||||||
|
_, err := c.session.DeleteChannel(core.GenerateChannel(e))
|
||||||
|
if err != nil {
|
||||||
|
log.Print("Failed to create channel for event: ", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ManageEventChannelsComponent) OnEventComplete(e common.Event) error {
|
||||||
|
channel := core.GenerateChannel(e)
|
||||||
|
|
||||||
|
if c.categoryID != "" {
|
||||||
|
|
||||||
|
if err := c.session.MoveChannelToCategory(channel, c.categoryID); 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
|
||||||
|
}
|
40
events/recurring_events.go
Normal file
40
events/recurring_events.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package events
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/yeslayla/birdbot/common"
|
||||||
|
"github.com/yeslayla/birdbot/discord"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RecurringEventsComponent struct {
|
||||||
|
session *discord.Discord
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRecurringEventsComponent() *RecurringEventsComponent {
|
||||||
|
return &RecurringEventsComponent{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RecurringEventsComponent) Initialize(birdbot common.ComponentManager) error {
|
||||||
|
_ = birdbot.OnEventComplete(c.OnEventComplete)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RecurringEventsComponent) 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
|
||||||
|
}
|
35
main.go
35
main.go
@ -1,13 +1,17 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
"github.com/ilyakaznacheev/cleanenv"
|
||||||
"github.com/yeslayla/birdbot/app"
|
"github.com/yeslayla/birdbot/app"
|
||||||
|
"github.com/yeslayla/birdbot/core"
|
||||||
|
"github.com/yeslayla/birdbot/events"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -27,12 +31,41 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("Using config: %s", config_file)
|
||||||
|
cfg := &core.Config{}
|
||||||
|
|
||||||
|
_, err := os.Stat(config_file)
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
log.Printf("Config file not found: '%s'", config_file)
|
||||||
|
err := cleanenv.ReadEnv(cfg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := cleanenv.ReadConfig(config_file, cfg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bot := app.NewBot()
|
bot := app.NewBot()
|
||||||
|
|
||||||
if err := bot.Initialize(config_file); err != nil {
|
if err := bot.Initialize(cfg); err != nil {
|
||||||
log.Fatal("Failed to initialize: ", err)
|
log.Fatal("Failed to initialize: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loader := app.NewComponentLoader(bot)
|
||||||
|
|
||||||
|
if cfg.Features.AnnounceEvents {
|
||||||
|
loader.LoadComponent(events.NewAnnounceEventsComponent(bot.Mastodon, cfg.Discord.NotificationChannel))
|
||||||
|
}
|
||||||
|
if cfg.Features.ManageEventChannels {
|
||||||
|
loader.LoadComponent(events.NewManageEventChannelsComponent(cfg.Discord.EventCategory, bot.Session))
|
||||||
|
}
|
||||||
|
if cfg.Features.ReccurringEvents {
|
||||||
|
loader.LoadComponent(events.NewRecurringEventsComponent())
|
||||||
|
}
|
||||||
|
|
||||||
if err := bot.Run(); err != nil {
|
if err := bot.Run(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user