commit a8e70e8b59bc694b7c5eec67443a03e2eb563536 Author: Leopold Date: Sun Nov 30 20:33:23 2025 +0100 inital commit diff --git a/.woodpecker/build.yaml b/.woodpecker/build.yaml new file mode 100644 index 0000000..5ed969b --- /dev/null +++ b/.woodpecker/build.yaml @@ -0,0 +1,19 @@ +when: + - event: push + branch: main + +steps: +- name: publish + image: woodpeckerci/plugin-kaniko + settings: + platforms: linux/amd64 + repo: llamprecht/fahdbot + registry: git.sakoma.wang + tags: ${CI_COMMIT_SHA} + cache: true + username: llamprecht + build_args: + - COMMIT_SHA=${CI_COMMIT_SHA} + - COMMIT_AUTHOR_EMAIL=${CI_COMMIT_AUTHOR_EMAIL} + password: + from_secret: container_registry_token diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ed9ed8b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM golang:1.25 + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download + +COPY *.go ./ + +RUN CGO_ENABLED=0 GOOS=linux go build -o /bot + + +CMD ["/bot"] diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..71c254e --- /dev/null +++ b/go.mod @@ -0,0 +1,14 @@ +module git.sakoma.wang/llamprecht/fahdbot + +go 1.25.4 + +require github.com/disgoorg/disgo v0.18.16 + +require ( + github.com/disgoorg/json v1.2.0 // indirect + github.com/disgoorg/snowflake/v2 v2.0.3 // indirect + github.com/gorilla/websocket v1.5.3 // indirect + github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/sys v0.28.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5f85463 --- /dev/null +++ b/go.sum @@ -0,0 +1,22 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/disgoorg/disgo v0.18.16 h1:Yk6pA9TaGbuM4hWfWafH0jAfmkWvZBFY7rh49DgljGE= +github.com/disgoorg/disgo v0.18.16/go.mod h1:dXYVH059d6aK7mI+Nh/3svSRWedNd09P7C2VX3RqbJY= +github.com/disgoorg/json v1.2.0 h1:6e/j4BCfSHIvucG1cd7tJPAOp1RgnnMFSqkvZUtEd1Y= +github.com/disgoorg/json v1.2.0/go.mod h1:BHDwdde0rpQFDVsRLKhma6Y7fTbQKub/zdGO5O9NqqA= +github.com/disgoorg/snowflake/v2 v2.0.3 h1:3B+PpFjr7j4ad7oeJu4RlQ+nYOTadsKapJIzgvSI2Ro= +github.com/disgoorg/snowflake/v2 v2.0.3/go.mod h1:W6r7NUA7DwfZLwr00km6G4UnZ0zcoLBRufhkFWgAc4c= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad h1:qIQkSlF5vAUHxEmTbaqt1hkJ/t6skqEGYiMag343ucI= +github.com/sasha-s/go-csync v0.0.0-20240107134140-fcbab37b09ad/go.mod h1:/pA7k3zsXKdjjAiUhB5CjuKib9KJGCaLvZwtxGC8U0s= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..74378c4 --- /dev/null +++ b/main.go @@ -0,0 +1,129 @@ +package main + +import ( + "context" + "fmt" + "log/slog" + "os" + "os/signal" + "strings" + "syscall" + + "github.com/disgoorg/disgo" + "github.com/disgoorg/disgo/bot" + "github.com/disgoorg/disgo/discord" + "github.com/disgoorg/disgo/events" + "github.com/disgoorg/disgo/gateway" + "github.com/disgoorg/snowflake/v2" +) + +type config struct { + botToken string + guildID snowflake.ID + roleID snowflake.ID +} + +var ( + commands = []discord.ApplicationCommandCreate{ + discord.SlashCommandCreate{ + Name: "schedule", + Description: "Collects who is available to a given date", + Options: []discord.ApplicationCommandOption{ + discord.ApplicationCommandOptionString{ + Name: "date", + Description: "When is it scheduled", + Required: true, + }, + }, + }, + } +) + +func main() { + slog.Info("getting config") + conf := getConfig() + slog.Info("defining intents") + client, err := disgo.New(conf.botToken, + // set gateway options + bot.WithGatewayConfigOpts( + // set enabled intents + gateway.WithIntents( + gateway.IntentGuilds, + gateway.IntentGuildMessages, + //gateway.IntentDirectMessages, + ), + ), + // add event listeners + bot.WithEventListenerFunc(commandListener), + bot.WithEventListenerFunc(interactListener), + ) + if err != nil { + panic(err) + } + slog.Info("writing Slash commands") + if _, err = client.Rest().SetGuildCommands(client.ApplicationID(), conf.guildID, commands); err != nil { + slog.Error("error while registering commands", slog.Any("err", err)) + } + + slog.Info("starting bot") + // connect to the gateway + if err = client.OpenGateway(context.TODO()); err != nil { + panic(err) + } + + slog.Info("bot startet successfully") + s := make(chan os.Signal, 1) + signal.Notify(s, syscall.SIGINT, syscall.SIGTERM) + <-s +} + +func getConfig() config { + conf := config{} + conf.botToken = os.Getenv("DISCORD_TOKEN") + conf.guildID = snowflake.GetEnv("DISCORD_GUILD_ID") + conf.roleID = snowflake.GetEnv("DISCORD_ROLE_ID") + return conf +} + +func commandListener(event *events.ApplicationCommandInteractionCreate) { + data := event.SlashCommandInteractionData() + if data.CommandName() == "schedule" { + err := event.CreateMessage( + discord.NewMessageCreateBuilder(). + SetContent(fmt.Sprintf("Will you attend on %s?\n", data.String("date"))). + AddActionRow( + discord.ButtonComponent{ + Style: discord.ButtonStylePrimary, + Label: "I will attend", + CustomID: "attend", + }, + discord.ButtonComponent{ + Style: discord.ButtonStyleSecondary, + Label: "I will not attend", + CustomID: "noattend", + }, + ). + Build(), + ) + if err != nil { + slog.Error("error on sending response", slog.Any("err", err)) + } + } +} + +func interactListener(event *events.ComponentInteractionCreate) { + switch event.ButtonInteractionData().CustomID() { + case "attend": + currentcontent := event.Message.Content + event.UpdateMessage(discord.NewMessageUpdateBuilder(). + SetContentf("%s\n%s\n", currentcontent, event.User().Username). + Build(), + ) + case "noattend": + currentcontent := event.Message.Content + event.UpdateMessage(discord.NewMessageUpdateBuilder(). + SetContent(strings.ReplaceAll(currentcontent, event.User().Username, "")). + Build(), + ) + } +}