package database import ( "database/sql" "log" "medi-wol/internal/models" "time" _ "modernc.org/sqlite" ) // DB ist die Datenbankverbindung type DB struct { *sql.DB } // InitDB initialisiert die Datenbank und erstellt die Tabellen func InitDB() (*DB, error) { db, err := sql.Open("sqlite", "./medi-wol.db") if err != nil { return nil, err } // PC-Tabelle erstellen createPCTableSQL := ` CREATE TABLE IF NOT EXISTS pcs ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, mac TEXT NOT NULL UNIQUE, ip TEXT NOT NULL, autostart_cron TEXT DEFAULT '30 7 * * Mon-Fri', autostart_enabled BOOLEAN DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP );` _, err = db.Exec(createPCTableSQL) if err != nil { return nil, err } // Log-Tabelle erstellen createLogTableSQL := ` CREATE TABLE IF NOT EXISTS wol_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, pc_id INTEGER NOT NULL, pc_name TEXT NOT NULL, mac TEXT NOT NULL, trigger TEXT NOT NULL, FOREIGN KEY (pc_id) REFERENCES pcs (id) ON DELETE CASCADE );` _, err = db.Exec(createLogTableSQL) if err != nil { return nil, err } // Settings-Tabelle erstellen createSettingsTableSQL := ` CREATE TABLE IF NOT EXISTS settings ( id INTEGER PRIMARY KEY AUTOINCREMENT, key TEXT NOT NULL UNIQUE, value TEXT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP );` _, err = db.Exec(createSettingsTableSQL) if err != nil { return nil, err } // Standard-Einstellungen setzen _, err = db.Exec("INSERT OR IGNORE INTO settings (key, value) VALUES ('vacation_mode', 'false')") if err != nil { return nil, err } // Füge IP-Spalte hinzu, falls sie nicht existiert _, err = db.Exec("ALTER TABLE pcs ADD COLUMN ip TEXT DEFAULT ''") if err != nil { // Spalte existiert bereits, ignorieren } log.Println("Datenbank erfolgreich initialisiert") return &DB{db}, nil } // GetAllPCs holt alle PCs aus der Datenbank func (db *DB) GetAllPCs() ([]models.PC, error) { rows, err := db.Query("SELECT id, name, mac, ip, autostart_cron, autostart_enabled, created_at, updated_at FROM pcs ORDER BY name") if err != nil { return nil, err } defer rows.Close() var pcs []models.PC for rows.Next() { var pc models.PC err := rows.Scan(&pc.ID, &pc.Name, &pc.MAC, &pc.IP, &pc.AutostartCron, &pc.AutostartEnabled, &pc.CreatedAt, &pc.UpdatedAt) if err != nil { return nil, err } pcs = append(pcs, pc) } return pcs, nil } // CreatePC erstellt einen neuen PC-Eintrag func (db *DB) CreatePC(name, mac, ip, autostartCron string, autostartEnabled bool) (*models.PC, error) { now := time.Now() result, err := db.Exec( "INSERT INTO pcs (name, mac, ip, autostart_cron, autostart_enabled, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)", name, mac, ip, autostartCron, autostartEnabled, now, now, ) if err != nil { return nil, err } id, err := result.LastInsertId() if err != nil { return nil, err } return &models.PC{ ID: int(id), Name: name, MAC: mac, IP: ip, AutostartCron: autostartCron, AutostartEnabled: autostartEnabled, CreatedAt: now, UpdatedAt: now, }, nil } // UpdatePC aktualisiert einen bestehenden PC-Eintrag func (db *DB) UpdatePC(id int, name, mac, ip, autostartCron string, autostartEnabled bool) (*models.PC, error) { now := time.Now() _, err := db.Exec( "UPDATE pcs SET name = ?, mac = ?, ip = ?, autostart_cron = ?, autostart_enabled = ?, updated_at = ? WHERE id = ?", name, mac, ip, autostartCron, autostartEnabled, now, id, ) if err != nil { return nil, err } return &models.PC{ ID: id, Name: name, MAC: mac, IP: ip, AutostartCron: autostartCron, AutostartEnabled: autostartEnabled, UpdatedAt: now, }, nil } // DeletePC löscht einen PC-Eintrag func (db *DB) DeletePC(id int) error { _, err := db.Exec("DELETE FROM pcs WHERE id = ?", id) return err } // GetPCByID holt einen PC anhand der ID func (db *DB) GetPCByID(id int) (*models.PC, error) { var pc models.PC err := db.QueryRow( "SELECT id, name, mac, ip, autostart_cron, autostart_enabled, created_at, updated_at FROM pcs WHERE id = ?", id, ).Scan(&pc.ID, &pc.Name, &pc.MAC, &pc.IP, &pc.AutostartCron, &pc.AutostartEnabled, &pc.CreatedAt, &pc.UpdatedAt) if err != nil { return nil, err } return &pc, nil } // GetPCsWithAutostart holt alle PCs mit aktiviertem Autostart func (db *DB) GetPCsWithAutostart() ([]models.PC, error) { rows, err := db.Query("SELECT id, name, mac, ip, autostart_cron, autostart_enabled, created_at, updated_at FROM pcs WHERE autostart_enabled = 1") if err != nil { return nil, err } defer rows.Close() var pcs []models.PC for rows.Next() { var pc models.PC err := rows.Scan(&pc.ID, &pc.Name, &pc.MAC, &pc.IP, &pc.AutostartCron, &pc.AutostartEnabled, &pc.CreatedAt, &pc.UpdatedAt) if err != nil { return nil, err } pcs = append(pcs, pc) } return pcs, nil } // CreateLog erstellt einen neuen Log-Eintrag func (db *DB) CreateLog(pcID int, pcName, mac, trigger string) (*models.LogEvent, error) { now := time.Now() result, err := db.Exec( "INSERT INTO wol_logs (timestamp, pc_id, pc_name, mac, trigger) VALUES (?, ?, ?, ?, ?)", now, pcID, pcName, mac, trigger, ) if err != nil { return nil, err } id, err := result.LastInsertId() if err != nil { return nil, err } return &models.LogEvent{ ID: int(id), Timestamp: now, PCID: pcID, PCName: pcName, MAC: mac, Trigger: trigger, }, nil } // GetAllLogs holt alle Log-Einträge aus der Datenbank func (db *DB) GetAllLogs() ([]models.LogEvent, error) { rows, err := db.Query("SELECT id, timestamp, pc_id, pc_name, mac, trigger FROM wol_logs ORDER BY timestamp DESC") if err != nil { return nil, err } defer rows.Close() var logs []models.LogEvent for rows.Next() { var log models.LogEvent err := rows.Scan(&log.ID, &log.Timestamp, &log.PCID, &log.PCName, &log.MAC, &log.Trigger) if err != nil { return nil, err } logs = append(logs, log) } return logs, nil } // GetLogsByPCID holt alle Log-Einträge für einen bestimmten PC func (db *DB) GetLogsByPCID(pcID int) ([]models.LogEvent, error) { rows, err := db.Query("SELECT id, timestamp, pc_id, pc_name, mac, trigger FROM wol_logs WHERE pc_id = ? ORDER BY timestamp DESC", pcID) if err != nil { return nil, err } defer rows.Close() var logs []models.LogEvent for rows.Next() { var log models.LogEvent err := rows.Scan(&log.ID, &log.Timestamp, &log.PCID, &log.PCName, &log.MAC, &log.Trigger) if err != nil { return nil, err } logs = append(logs, log) } return logs, nil } // GetRecentLogsByPCID holt die letzten 5 Log-Einträge für einen bestimmten PC func (db *DB) GetRecentLogsByPCID(pcID int) ([]models.LogEvent, error) { rows, err := db.Query("SELECT id, timestamp, pc_id, pc_name, mac, trigger FROM wol_logs WHERE pc_id = ? ORDER BY timestamp DESC LIMIT 5", pcID) if err != nil { return nil, err } defer rows.Close() var logs []models.LogEvent for rows.Next() { var log models.LogEvent err := rows.Scan(&log.ID, &log.Timestamp, &log.PCID, &log.PCName, &log.MAC, &log.Trigger) if err != nil { return nil, err } logs = append(logs, log) } return logs, nil } // GetSetting holt eine Einstellung aus der Datenbank func (db *DB) GetSetting(key string) (string, error) { var value string err := db.QueryRow("SELECT value FROM settings WHERE key = ?", key).Scan(&value) if err != nil { return "", err } return value, nil } // SetSetting setzt eine Einstellung in der Datenbank func (db *DB) SetSetting(key, value string) error { now := time.Now() _, err := db.Exec( "INSERT OR REPLACE INTO settings (key, value, updated_at) VALUES (?, ?, ?)", key, value, now, ) return err } // IsVacationModeEnabled prüft, ob der Urlaubsmodus aktiviert ist func (db *DB) IsVacationModeEnabled() (bool, error) { value, err := db.GetSetting("vacation_mode") if err != nil { return false, err } return value == "true", nil }