diff --git a/guild_config.db b/guild_config.db index 88142dc..ef1986b 100644 Binary files a/guild_config.db and b/guild_config.db differ diff --git a/main.go b/main.go index f928dcb..207c10d 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,8 @@ import ( "log" "os" "os/signal" + "strconv" + "strings" "sync" "syscall" "time" @@ -24,10 +26,7 @@ var ( // Pfad zur SQLite-Datenbank var dbPath = func() string { - if v := os.Getenv("DB_PATH"); v != "" { - return v - } - return "guild_config.db" + return GetENV("DB_PATH", "guild_config.db") }() // ===== Per-Guild Config (in-memory) ===== @@ -35,6 +34,7 @@ type GuildConfig struct { LobbyName string `json:"lobby_name"` CategoryName string `json:"category_name"` TimeoutMin int `json:"timeout_min"` + Language string `json:"language"` // Neue Eigenschaft für Sprache } var db *sql.DB @@ -43,6 +43,43 @@ var db *sql.DB var guildCfgs sync.Map // Für Guild-Konfigurationen var createdCmds sync.Map // Für erstellte Commands +// Sprache für eine Guild setzen +func setLanguage(guildID, language string) error { + cfg := getCfg(guildID) + cfg.Language = language + return saveGuildCfgs() +} + +// Sprachabruf +func getLanguage(guildID string) string { + cfg := getCfg(guildID) + return cfg.Language +} + +// Funktion zum Hinzufügen der 'language' Spalte, falls sie nicht existiert +func addLanguageColumnIfNotExists() { + // Überprüfen, ob die Tabelle 'guild_config' existiert + var tableExists bool + err := db.QueryRow("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='guild_config'").Scan(&tableExists) + if err != nil || !tableExists { + log.Printf("Tabelle 'guild_config' existiert nicht: %v", err) + } + + // Überprüfen, ob die Spalte 'language' existiert + _, err = db.Exec("ALTER TABLE guild_config ADD COLUMN language TEXT DEFAULT 'de'") + if err != nil && !isColumnAlreadyExistsError(err) { + log.Printf("Fehler beim Hinzufügen der 'language' Spalte: %v", err) + } else { + log.Println("Spalte 'language' wurde hinzugefügt oder existiert bereits.") + } +} + +// Hilfsfunktion zur Fehlerbehandlung, um zu überprüfen, ob der Fehler auf eine bereits vorhandene Spalte hinweist +func isColumnAlreadyExistsError(err error) bool { + // Fehlerbehandlung für 'duplicate column name' + return err != nil && err.Error() == "SQLITE_ERROR: duplicate column name: language" +} + // Initialize DB func initDB() { var err error @@ -56,12 +93,17 @@ func initDB() { guild_id TEXT PRIMARY KEY, lobby_name TEXT, category_name TEXT, - timeout_min INTEGER + timeout_min INTEGER, + language TEXT DEFAULT 'de' -- Neue Spalte für Sprache hinzufügen );` _, err = db.Exec(createTableSQL) if err != nil { log.Fatalf("Fehler beim Erstellen der Tabelle: %v", err) } + + // Neue Spalte für die Sprache hinzufügen, wenn sie noch nicht existiert + addLanguageColumnIfNotExists() + } // Close DB connection @@ -71,31 +113,32 @@ func closeDB() { } } -// Laden der Guild-Konfiguration aus der Datenbank +// Laden der Guild-Konfiguration mit Sprache func loadGuildCfgs() error { - rows, err := db.Query("SELECT guild_id, lobby_name, category_name, timeout_min FROM guild_config") + rows, err := db.Query("SELECT guild_id, lobby_name, category_name, timeout_min, language FROM guild_config") if err != nil { return err } defer rows.Close() for rows.Next() { - var guildID, lobbyName, categoryName string + var guildID, lobbyName, categoryName, language string var timeoutMin int - if err := rows.Scan(&guildID, &lobbyName, &categoryName, &timeoutMin); err != nil { + if err := rows.Scan(&guildID, &lobbyName, &categoryName, &timeoutMin, &language); err != nil { return err } guildCfgs.Store(guildID, &GuildConfig{ LobbyName: lobbyName, CategoryName: categoryName, TimeoutMin: timeoutMin, + Language: language, // Sprache laden }) } return nil } -// Speichern der Guild-Konfiguration in die Datenbank +// Speichern der Guild-Konfiguration mit Sprache func saveGuildCfgs() error { tx, err := db.Begin() if err != nil { @@ -108,14 +151,15 @@ func saveGuildCfgs() error { cfg := value.(*GuildConfig) _, err := tx.Exec(` - INSERT INTO guild_config (guild_id, lobby_name, category_name, timeout_min) - VALUES (?, ?, ?, ?) + INSERT INTO guild_config (guild_id, lobby_name, category_name, timeout_min, language) + VALUES (?, ?, ?, ?, ?) ON CONFLICT(guild_id) DO UPDATE SET lobby_name = excluded.lobby_name, category_name = excluded.category_name, - timeout_min = excluded.timeout_min - `, guildID, cfg.LobbyName, cfg.CategoryName, cfg.TimeoutMin) + timeout_min = excluded.timeout_min, + language = excluded.language -- Sprache speichern + `, guildID, cfg.LobbyName, cfg.CategoryName, cfg.TimeoutMin, cfg.Language) if err != nil { log.Printf("Fehler beim Speichern der Guild-Konfiguration: %v", err) } @@ -132,17 +176,19 @@ func getCfg(guildID string) *GuildConfig { return cfg.(*GuildConfig) } var guildCfg GuildConfig - err := db.QueryRow("SELECT lobby_name, category_name, timeout_min FROM guild_config WHERE guild_id = ?", guildID).Scan(&guildCfg.LobbyName, &guildCfg.CategoryName, &guildCfg.TimeoutMin) + err := db.QueryRow("SELECT lobby_name, category_name, timeout_min, language FROM guild_config WHERE guild_id = ?", guildID).Scan(&guildCfg.LobbyName, &guildCfg.CategoryName, &guildCfg.TimeoutMin, &guildCfg.Language) if err != nil { if err == sql.ErrNoRows { log.Printf("Guild-Konfiguration für %s nicht gefunden, verwenden der Standardwerte", guildID) } else { log.Printf("Fehler beim Abrufen der Guild-Konfiguration für %s: %v", guildID, err) } + // Standardwerte verwenden guildCfg = GuildConfig{ LobbyName: defaultLobbyName, CategoryName: defaultCategory, TimeoutMin: envTimeoutDefault(1), + Language: "de", // Standard-Sprache ist Deutsch } } guildCfgs.Store(guildID, &guildCfg) @@ -725,6 +771,59 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter }, }) + case "setlanguage": + // Admin-Check zuerst + if !isGuildAdmin(s, guildID, i.User, i.Member) { + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "❌ Nur Administratoren dürfen das.", + Flags: discordgo.MessageFlagsEphemeral, + }, + }) + return + } + + // Option "language" lesen + var language string + for _, o := range data.Options { + if o.Name == "language" { + language = o.StringValue() + break + } + } + if language == "" { + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "Bitte gib eine gültige Sprache an (z.B. 'de', 'en').", + Flags: discordgo.MessageFlagsEphemeral, + }, + }) + return + } + + // Speichern + if err := setLanguage(guildID, language); err != nil { + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: "⚠️ Fehler beim Speichern der Sprache.", + Flags: discordgo.MessageFlagsEphemeral, + }, + }) + return + } + + // Antwort <= 3s + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: fmt.Sprintf("✅ Sprache auf '%s' gesetzt.", language), + Flags: discordgo.MessageFlagsEphemeral, + }, + }) + } } } @@ -799,13 +898,43 @@ var ( }, }, }, + { + Name: "setlanguage", + Description: "Setzt die Sprache für diese Guild.", + DefaultMemberPermissions: &adminPerm, + Options: []*discordgo.ApplicationCommandOption{ + { + Type: discordgo.ApplicationCommandOptionString, + Name: "language", + Description: "Die Sprache, die gesetzt werden soll (z.B. 'de', 'en').", + Required: true, + }, + }, + }, } ) +func GetENV(k, d string) string { + if v := os.Getenv(k); v != "" { + return v + } + return d +} + +func Enabled(k string, def bool) bool { + b, err := strconv.ParseBool(strings.ToLower(os.Getenv(k))) + if err != nil { + return def + } + return b +} + // ===== main: Multi-Guild, pro Guild registrieren ===== func main() { initDB() - token := os.Getenv("DISCORD_TOKEN") + + loadTranslationsFromFile(GetENV("TRANSLATIONS_FILE", "./language.json")) + token := GetENV("DISCORD_TOKEN", "") token = "MTQwMzg1MTM5NDQ1MjI5MTU4NA.GVi04l.qjraLIbFdi_N49UcSUv_BqK89ihb6xXY648J7A" if token == "" { log.Fatal("Bitte setze DISCORD_TOKEN") @@ -852,6 +981,7 @@ func main() { if err := saveGuildCfgs(); err != nil { log.Printf("Speichern zum Shutdown fehlgeschlagen: %v", err) } + closeDB() _ = s.Close() }