Files
medi-wol/internal/database/database.go

352 lines
9.4 KiB
Go

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
}
// Migration: fehlende Spalten hinzufügen (für bestehende DBs)
// autostart_cron
_, err = db.Exec("ALTER TABLE pcs ADD COLUMN autostart_cron TEXT DEFAULT '30 7 * * Mon-Fri'")
if err != nil {
// Spalte existiert bereits, ignorieren
}
// autostart_enabled
_, err = db.Exec("ALTER TABLE pcs ADD COLUMN autostart_enabled BOOLEAN DEFAULT 0")
if err != nil {
// Spalte existiert bereits, ignorieren
}
// Standardwerte für evtl. NULL-Einträge setzen
_, _ = db.Exec("UPDATE pcs SET autostart_cron = '30 7 * * Mon-Fri' WHERE autostart_cron IS NULL")
_, _ = db.Exec("UPDATE pcs SET autostart_enabled = 0 WHERE autostart_enabled IS NULL")
// 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
}
// Falls keine PCs vorhanden sind, Dummy-PC anlegen
var pcCount int
err = db.QueryRow("SELECT COUNT(*) FROM pcs").Scan(&pcCount)
if err != nil {
log.Printf("Warnung: Konnte Anzahl der PCs nicht ermitteln: %v", err)
} else if pcCount == 0 {
_, insErr := db.Exec(
"INSERT INTO pcs (name, mac, ip, autostart_cron, autostart_enabled, created_at, updated_at) VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)",
"Test", "00:11:22:33:AA:FF", "192.168.0.1", "30 7 * * Mon-Fri", 0,
)
if insErr != nil {
log.Printf("Warnung: Konnte Dummy-PC nicht anlegen: %v", insErr)
} else {
log.Println("Dummy-PC 'Test' in InitDB automatisch angelegt (leere Datenbank)")
}
}
// 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
}