diff --git a/ReadMe.md b/ReadMe.md index 494f401..630a3a5 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -8,6 +8,7 @@ Bird Bot is a discord bot for managing and organizing events for a small discord - Notifying when events are created & cancelled - Delete text channels after events - Archive text channels after events +- Create recurring weekly events ## Usage diff --git a/app/bot.go b/app/bot.go index 75c7932..66e6c7e 100644 --- a/app/bot.go +++ b/app/bot.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "os" + "strings" "github.com/ilyakaznacheev/cleanenv" "github.com/yeslayla/birdbot/core" @@ -104,7 +105,7 @@ func (app *Bot) Notify(message string) { } func (app *Bot) onReady(d *discord.Discord) { - app.Notify(fmt.Sprintf("BirdBot %s is ready!", Version)) + app.session.SetStatus(fmt.Sprintf("with fire! (%s)", Version)) } func (app *Bot) onEventCreate(d *discord.Discord, event *core.Event) { @@ -184,6 +185,18 @@ func (app *Bot) onEventComplete(d *discord.Discord, event *core.Event) { 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 { diff --git a/core/event.go b/core/event.go index 82746e0..702aaf4 100644 --- a/core/event.go +++ b/core/event.go @@ -10,11 +10,14 @@ import ( const REMOTE_LOCATION string = "online" type Event struct { - Name string - ID string - Location string - Completed bool - DateTime time.Time + Name string + ID string + Location string + Completed bool + DateTime time.Time + CompleteTime time.Time + Description string + Image string Organizer *User } @@ -25,8 +28,9 @@ 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) + channel := fmt.Sprint(month, "-", day, city, "-", event.Name, "-", year) channel = strings.ReplaceAll(channel, " ", "-") channel = strings.ToLower(channel) diff --git a/core/event_test.go b/core/event_test.go index 111671d..410a1ba 100644 --- a/core/event_test.go +++ b/core/event_test.go @@ -16,7 +16,7 @@ func TestGetChannelName(t *testing.T) { 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", event.Channel().Name) + 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 @@ -25,7 +25,7 @@ func TestGetChannelName(t *testing.T) { Location: "Michigan Theater, Ann Arbor", DateTime: time.Date(2022, time.January, 5, 0, 0, 0, 0, time.UTC), } - assert.Equal("jan-5-hello-world", event.Channel().Name) + assert.Equal("jan-5-hello-world-2022", event.Channel().Name) // Test Short Location event = Event{ @@ -33,7 +33,7 @@ func TestGetChannelName(t *testing.T) { Location: "Monroe, MI", DateTime: time.Date(2022, time.January, 5, 0, 0, 0, 0, time.UTC), } - assert.Equal("jan-5-monroe-hello-world", event.Channel().Name) + assert.Equal("jan-5-monroe-hello-world-2022", event.Channel().Name) // Test Short Location event = Event{ @@ -41,7 +41,7 @@ func TestGetChannelName(t *testing.T) { 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", event.Channel().Name) + assert.Equal("jan-5-monroe-hello-world-2022", event.Channel().Name) // Test Remote Event event = Event{ @@ -49,7 +49,7 @@ func TestGetChannelName(t *testing.T) { Location: REMOTE_LOCATION, DateTime: time.Date(2022, time.January, 5, 0, 0, 0, 0, time.UTC), } - assert.Equal("jan-5-online-hello-world", event.Channel().Name) + assert.Equal("jan-5-online-hello-world-2022", event.Channel().Name) } func TestMonthPrefix(t *testing.T) { diff --git a/discord/discord.go b/discord/discord.go index 05c6dc8..1653962 100644 --- a/discord/discord.go +++ b/discord/discord.go @@ -95,3 +95,9 @@ func (discord *Discord) OnEventUpdate(handler func(*Discord, *core.Event)) { handler(discord, event) }) } + +func (discord *Discord) SetStatus(status string) { + if err := discord.session.UpdateGameStatus(0, status); err != nil { + log.Fatal("Failed to update status: ", err) + } +} diff --git a/discord/event.go b/discord/event.go index c33aff7..5fd5af6 100644 --- a/discord/event.go +++ b/discord/event.go @@ -1,6 +1,8 @@ package discord import ( + "time" + "github.com/bwmarrin/discordgo" "github.com/yeslayla/birdbot/core" ) @@ -8,12 +10,21 @@ import ( // NewEvent converts a discordgo.GuildScheduledEvent to birdbot event func NewEvent(guildEvent *discordgo.GuildScheduledEvent) *core.Event { event := &core.Event{ - Name: guildEvent.Name, - ID: guildEvent.ID, + Name: guildEvent.Name, + Description: guildEvent.Description, + ID: guildEvent.ID, Organizer: &core.User{ ID: guildEvent.CreatorID, }, DateTime: guildEvent.ScheduledStartTime, + Image: guildEvent.Image, + } + + if guildEvent.ScheduledEndTime != nil { + event.CompleteTime = *guildEvent.ScheduledEndTime + } else { + year, month, day := guildEvent.ScheduledStartTime.Date() + event.CompleteTime = time.Date(year, month, day, 0, 0, 0, 0, guildEvent.ScheduledStartTime.Location()) } event.Completed = guildEvent.Status == discordgo.GuildScheduledEventStatusCompleted @@ -26,3 +37,26 @@ func NewEvent(guildEvent *discordgo.GuildScheduledEvent) *core.Event { return event } + +func (discord *Discord) CreateEvent(event *core.Event) error { + + params := &discordgo.GuildScheduledEventParams{ + Name: event.Name, + Description: event.Description, + ScheduledStartTime: &event.DateTime, + ScheduledEndTime: &event.CompleteTime, + Image: event.Image, + EntityType: discordgo.GuildScheduledEventEntityTypeExternal, + PrivacyLevel: discordgo.GuildScheduledEventPrivacyLevelGuildOnly, + } + + if event.Location != "" { + params.EntityMetadata = &discordgo.GuildScheduledEventEntityMetadata{ + Location: event.Location, + } + } + + _, err := discord.session.GuildScheduledEventCreate(discord.guildID, params) + + return err +} diff --git a/main.go b/main.go index 8c33a94..0335a4f 100644 --- a/main.go +++ b/main.go @@ -4,14 +4,21 @@ import ( "flag" "fmt" "log" + "os" + "path" "github.com/yeslayla/birdbot/app" ) func main() { + + configDir, _ := os.UserConfigDir() + + defaultConfigPath := path.Join(configDir, "birdbot", "config.yaml") + var config_file string var version bool - flag.StringVar(&config_file, "c", "birdbot.yaml", "Path to config file") + flag.StringVar(&config_file, "c", defaultConfigPath, "Path to config file") flag.BoolVar(&version, "v", false, "List version") flag.Parse() @@ -21,6 +28,7 @@ func main() { } bot := app.NewBot() + if err := bot.Initialize(config_file); err != nil { log.Fatal("Failed to initialize: ", err) }