Skip to content

Commit

Permalink
added advent calendar functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Kesuaheli committed Nov 26, 2023
1 parent eb624d8 commit e7e314e
Show file tree
Hide file tree
Showing 14 changed files with 580 additions and 3 deletions.
3 changes: 3 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,8 @@ event:
morning_hour: 8
morning_minute: 0

adventcalendar:
images: data/images/adventcalendar

webserver:
favicon: webserver/favicon.png
12 changes: 12 additions & 0 deletions data/lang/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ discord.command:
base: adventskalender
base.description: Admin Commands für das Adventskalender Giveaway

module:
adventcalendar:
post.message: Noch %d Mal schlafen bis Heilig Abend! Heute öffnet sich das **Türchen %d**.
post.message.day_23: Fast geschafft! Nur noch einmal schlafen!
post.message.day_24: Ho Ho Ho! Heute ist Heilig Abend!
post.message2: Klicke unten auf den Knopf um dich im Gewinnspiel einzutragen!
post.button: Gewinnspiel

enter.invalid: Das ist eine alte Nachricht, du kannst dich hier nicht mehr eintragen!
enter.success: Du hast dich erfolgreich eingetragen! Du hast jetzt %d Tickets.
enter.already_entered: Du hast dich heute bereits eingetragen! (Du hast momentan %d Tickets)

youtube:
embed_footer: YouTube Glocke
msg.new_vid: "%s hat ein neues Video hochgeladen"
12 changes: 12 additions & 0 deletions data/lang/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ discord.command:
base: adventcalendar
base.description: Admin commands for the Advent Calendar Giveaway

module:
adventcalendar:
post.message: Just sleep %d more times! Its time for **door %d**.
post.message.day_23: Almost there! Just sleep once more!
post.message.day_24: Ho Ho Ho! Its Christmas Eve!
post.message2: Click the button below to join the Giveaway!
post.button: Join

enter.invalid: This is an old message, you cannot join here anymore!
enter.success: You successfully joined! You know have %d tickets.
enter.already_entered: You already joined for today. (You have %d tickets)

youtube:
embed_footer: YouTube notification bell
msg.new_vid: "%s just uploaded a new video"
2 changes: 2 additions & 0 deletions event/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ func handleInteractionCreate(s *discordgo.Session, i *discordgo.InteractionCreat
data := i.MessageComponentData()
if c, ok := component.ComponentMap[strings.Split(data.CustomID, ".")[0]]; ok {
c.Handle(s, i)
} else {
log.Printf("got component interaction from unknown module '%s' (full id '%s')", strings.Split(data.CustomID, ".")[0], data.CustomID)
}
}
}
4 changes: 3 additions & 1 deletion event/scheduledTriggers.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package event

import (
"cake4everybot/modules/adventcalendar"
"cake4everybot/modules/birthday"
webYT "cake4everybot/webserver/youtube"

Expand All @@ -26,11 +27,12 @@ import (

func addScheduledTriggers(s *discordgo.Session, webChan chan struct{}) {
go scheduleFunction(s, 0, 0,
birthday.Check,
adventcalendar.Midnight,
)

go scheduleFunction(s, viper.GetInt("event.morning_hour"), viper.GetInt("event.morning_minute"),
birthday.Check,
adventcalendar.Post,
)

go refreshYoutube(webChan)
Expand Down
16 changes: 16 additions & 0 deletions modules/adventcalendar/adventcalendarbase.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ package adventcalendar

import (
"cake4everybot/util"
"fmt"
logger "log"
"time"

"github.com/bwmarrin/discordgo"
)
Expand All @@ -34,3 +36,17 @@ type adventcalendarBase struct {
member *discordgo.Member
user *discordgo.User
}

type giveawayEntry struct {
userID string
weight int
lastEntry time.Time
}

func (e giveawayEntry) toEmbedField(s *discordgo.Session) (f *discordgo.MessageEmbedField) {
return &discordgo.MessageEmbedField{
Name: fmt.Sprintf("%s", e.userID),

Check failure on line 48 in modules/adventcalendar/adventcalendarbase.go

View workflow job for this annotation

GitHub Actions / Test

the argument is already a string, there's no need to use fmt.Sprintf (S1025)
Value: fmt.Sprintf("<@%s>\n%d tickets\nlast entry: %s", e.userID, e.weight, e.lastEntry.Format(time.DateOnly)),
Inline: true,
}
}
38 changes: 37 additions & 1 deletion modules/adventcalendar/chatCommand.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2023 Kesuaheli
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package adventcalendar

import (
Expand All @@ -20,6 +34,18 @@ func (Chat) AppCmd() *discordgo.ApplicationCommand {
NameLocalizations: util.TranslateLocalization(tp + "base"),
Description: lang.GetDefault(tp + "base.description"),
DescriptionLocalizations: util.TranslateLocalization(tp + "base.description"),
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "midnight",
Description: "Midnight trigger",
},
{
Type: discordgo.ApplicationCommandOptionSubCommand,
Name: "morning",
Description: "Morning trigger",
},
},
}
}

Expand All @@ -34,7 +60,17 @@ func (cmd Chat) Handle(s *discordgo.Session, i *discordgo.InteractionCreate) {
cmd.member = &discordgo.Member{User: i.User}
}

log.Print("currently unused command")
switch i.ApplicationCommandData().Options[0].Name {
case "midnight":
Midnight(s)
cmd.ReplyHidden("Midnight()")
return
case "morning":
Post(s)
cmd.ReplyHidden("Post()")
return
}

}

// SetID sets the registered command ID for internal uses after uploading to discord
Expand Down
70 changes: 69 additions & 1 deletion modules/adventcalendar/component.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
// Copyright 2023 Kesuaheli
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package adventcalendar

import (
"cake4everybot/data/lang"
"cake4everybot/util"
"fmt"
"strings"
"time"

"github.com/bwmarrin/discordgo"
)

// The Component of the advent calendar package.
type Component struct {
adventcalendarBase
data discordgo.MessageComponentInteractionData
}

// Handle handles the functionality of a component.
func (c Component) Handle(s *discordgo.Session, i *discordgo.InteractionCreate) {

c.InteractionUtil = util.InteractionUtil{Session: s, Interaction: i}
c.member = i.Member
c.user = i.User
Expand All @@ -22,9 +40,59 @@ func (c Component) Handle(s *discordgo.Session, i *discordgo.InteractionCreate)
} else if i.User != nil {
c.member = &discordgo.Member{User: i.User}
}
c.data = i.MessageComponentData()

ids := strings.Split(c.data.CustomID, ".")
// pop the first level identifier
util.ShiftL(ids)

switch util.ShiftL(ids) {
case "post":
c.handlePost(s, ids)
return
default:
log.Printf("Unknown component interaction ID: %s", c.data.CustomID)
}
}

// ID returns the custom ID of the modal to identify the module
func (Component) ID() string {
return "adventcalendar"
}

func (c *Component) handlePost(s *discordgo.Session, ids []string) {
var (
buttonYear = util.ShiftL(ids)
buttonMonth = util.ShiftL(ids)
buttonDay = util.ShiftL(ids)
)
timeValue := fmt.Sprintf("%s-%s-%s", buttonYear, buttonMonth, buttonDay)
postTime, err := time.Parse(time.DateOnly, timeValue)
if err != nil {
log.Printf("ERROR: could not parse date: %s: %+v", timeValue, err)
c.ReplyError()
return
}

if now := time.Now(); now.Year() != postTime.Year() ||
now.Month() != postTime.Month() ||
now.Day() != postTime.Day() {
c.ReplyHiddenSimpleEmbedf(0xFF0000, lang.GetDefault("module.adventcalendar.enter.invalid"))
return
}

entry := getEntry(c.user.ID)
if entry.userID != c.user.ID {
log.Printf("ERROR: getEntry() returned with userID '%s' but want '%s'", entry.userID, c.user.ID)
c.ReplyError()
return
}
if entry.lastEntry.Equal(postTime) {
c.ReplyHiddenSimpleEmbedf(0x5865f2, lang.GetDefault("module.adventcalendar.enter.already_entered"), entry.weight)
return
}

entry = addGiveawayWeight(c.user.ID, 1)

c.ReplyHiddenSimpleEmbedf(0x00FF00, lang.GetDefault("module.adventcalendar.enter.success"), entry.weight)
}
127 changes: 127 additions & 0 deletions modules/adventcalendar/database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright 2023 Kesuaheli
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package adventcalendar

import (
"cake4everybot/database"
"database/sql"
"fmt"
"strings"
"time"
)

func getEntry(userID string) giveawayEntry {
var (
weight int
lastEntryID string
)
err := database.QueryRow("SELECT weight,last_entry_id FROM giveaway WHERE id=?", userID).Scan(&weight, &lastEntryID)
if err == sql.ErrNoRows {
return giveawayEntry{userID: userID, weight: 0}
}
if err != nil {
log.Printf("Database failed to get giveaway entries for '%s': %+v", userID, err)
return giveawayEntry{}
}

if lastEntryID == "" {
return giveawayEntry{userID: userID, weight: weight}
}

dateValue, ok := strings.CutPrefix(lastEntryID, "xmas-")
if !ok {
return giveawayEntry{}
}

lastEntry, err := time.Parse(time.DateOnly, dateValue)
if err != nil {
log.Printf("could not convert last_entry_id '%s' to time: %+v", lastEntryID, err)
return giveawayEntry{}
}
return giveawayEntry{userID, weight, lastEntry}
}

func addGiveawayWeight(userID string, amount int) giveawayEntry {
var weight int
var new bool
err := database.QueryRow("SELECT weight FROM giveaway WHERE id=?", userID).Scan(&weight)
if err == sql.ErrNoRows {
new = true
} else if err != nil {
log.Printf("Database failed to get giveaway weight for '%s': %+v", userID, err)
return giveawayEntry{}
}

weight += amount
dateValue := time.Now().Format(time.DateOnly)
lastEntryID := fmt.Sprintf("xmas-%s", dateValue)
lastEntry, _ := time.Parse(time.DateOnly, dateValue)

if new {
_, err = database.Exec("INSERT INTO giveaway (id,weight,last_entry_id) VALUES (?,?,?)", userID, weight, lastEntryID)
if err != nil {
log.Printf("Database failed to insert giveaway for '%s': %+v", userID, err)
return giveawayEntry{}
}
return giveawayEntry{userID, weight, lastEntry}
}
_, err = database.Exec("UPDATE giveaway SET weight=?,last_entry_id=? WHERE id=?", weight, lastEntryID, userID)
if err != nil {
log.Printf("Database failed to update weight (new: %d) for '%s': %+v", weight, userID, err)
return giveawayEntry{}
}
return giveawayEntry{userID, weight, lastEntry}
}

func getGetAllEntries() []giveawayEntry {
rows, err := database.Query("SELECT id,weight,last_entry_id FROM giveaway")
if err != nil {
log.Printf("ERROR: could not get entries from database: %+v", err)
return []giveawayEntry{}
}
defer rows.Close()

var entries []giveawayEntry
for rows.Next() {
var (
userID string
weight int
lastEntryID string
)
err = rows.Scan(&userID, &weight, &lastEntryID)
if err != nil {
log.Printf("Warning: could not scan variables from row")
continue
}

if lastEntryID == "" {
entries = append(entries, giveawayEntry{userID: userID, weight: weight})
continue
}

dateValue, ok := strings.CutPrefix(lastEntryID, "xmas-")
if !ok {
continue
}

lastEntry, err := time.Parse(time.DateOnly, dateValue)
if err != nil {
log.Printf("ERROR: could not convert last_entry_id '%s' to time: %+v", lastEntryID, err)
continue
}
entries = append(entries, giveawayEntry{userID, weight, lastEntry})
}
return entries
}
Loading

0 comments on commit e7e314e

Please sign in to comment.