15 Commits

Author SHA1 Message Date
6a84c767f2 Fix: Go-Version auf 1.18 kompatibel gemacht und Build-Probleme behoben
- go.mod: Version von 1.23.0 auf 1.18 korrigiert
- golang.org/x/sys von v0.35.0 auf v0.15.0 downgraded für Go 1.18 Kompatibilität
- README aktualisiert: Go 1.18 als Mindestanforderung dokumentiert
- Build-Anweisungen verbessert mit Multi-Platform Build-Empfehlungen
- Wichtiger Hinweis zu Go-Version-Kompatibilität hinzugefügt
2025-08-22 09:27:07 +02:00
2bfe8f6196 Go-Version auf 1.23.0 zurückgesetzt und go.sum aktualisiert 2025-08-22 09:12:31 +02:00
bea61b0c95 Merge Branch 'Urlaubsmodus' (Urlaubsmodus, Settings-API, Dummy-PC, DB-Migration) 2025-08-22 08:54:18 +02:00
ce2eea5f43 DB-Migration: fehlende autostart_* Spalten hinzufügen und Defaults setzen 2025-08-22 08:53:18 +02:00
bdeabaad2e README: Urlaubsmodus, Settings-API und automatischen Dummy-PC dokumentiert 2025-08-22 08:52:24 +02:00
5c13a34bbf InitDB: Dummy-PC 'Test' automatisch anlegen, falls pcs leer ist 2025-08-22 08:46:19 +02:00
d85181e797 Startup: Dummy-PC 'Test' automatisch anlegen bei leerer Datenbank 2025-08-22 08:42:38 +02:00
b860571f40 Logo durch MediSoftware_Logo_rb_cut.png ersetzt 2025-08-22 08:38:58 +02:00
1dfa0c9b32 Urlaubsmodus implementiert - Globale Checkbox zum Deaktivieren des Schedulers 2025-08-22 08:35:13 +02:00
0488e4ec47 Update README 2025-08-22 08:22:02 +02:00
5b03441b4d dist/ Verzeichnis aus Repository entfernt - Build-Artefakte gehören nicht ins Git 2025-08-22 08:18:19 +02:00
49c3ece8f5 Update .gitignore 2025-08-22 08:17:14 +02:00
12655429ac README: Umfassende Dokumentation des Scheduler-Systems und Logging-Features 2025-08-22 08:15:39 +02:00
9f49a1b865 Setup: Icon für mediWOL WEB UI Verknüpfung auf SetupIconFile gesetzt 2025-08-22 08:12:05 +02:00
774e3c953f Setup: Automatisches Öffnen der Web-Oberfläche nach Service-Start 2025-08-22 07:59:08 +02:00
16 changed files with 365 additions and 84 deletions

2
.gitignore vendored
View File

@ -46,3 +46,5 @@ Thumbs.db
# Temporary files
tmp/
temp/
dist/

159
README.md
View File

@ -8,6 +8,9 @@ Ein moderner Wake-on-LAN Manager, entwickelt mit Go und einer schönen Web-Oberf
- **Wake-on-LAN**: Ein-Klick-Aufwecken von Computern über MAC-Adressen
- **IP-Adressverwaltung**: Pro Gerät wird eine IP-Adresse gespeichert
- **Online-Status (Ping)**: Geräte können per Ping geprüft und im UI als Online/Offline angezeigt werden
- **Automatischer Start**: Scheduler für geplante Wake-on-LAN Ereignisse mit Crontab-Syntax
- **Urlaubsmodus**: Globaler Schalter, der den geplanten Autostart für alle Geräte deaktiviert
- **Logging-System**: Vollständige Protokollierung aller WOL-Ereignisse (Button-Klick und Scheduler)
- **Moderne Web-Oberfläche**: Responsive Design mit Bootstrap und FontAwesome
- **SQLite-Datenbank**: Einfache lokale Datenspeicherung
- **Cross-Platform**: Läuft auf Windows und Linux
@ -15,7 +18,7 @@ Ein moderner Wake-on-LAN Manager, entwickelt mit Go und einer schönen Web-Oberf
## Voraussetzungen
- Go 1.21 oder höher
- Go 1.18 oder höher
- Git
## Installation
@ -114,6 +117,27 @@ Falls weder Kommandozeilenparameter noch Umgebungsvariable gesetzt sind, wird Po
- Klicken Sie auf den "Löschen"-Button neben dem gewünschten PC
- Bestätigen Sie die Löschung
### Autostart konfigurieren
1. **Autostart aktivieren**: Aktivieren Sie die Checkbox "Autostart aktiv"
2. **Crontab-Syntax eingeben**: Verwenden Sie das Format `Minute Stunde Tag Monat Wochentag`
- **Standard**: `30 7 * * Mon-Fri` (Mo-Fr um 7:30 Uhr)
- **Beispiele**:
- `0 8 * * *` = Täglich um 8:00 Uhr
- `0 9 * * Mon,Wed,Fri` = Mo, Mi, Fr um 9:00 Uhr
- `30 7 * * 1-5` = Mo-Fr um 7:30 Uhr
3. **Hilfe**: Link zu [crontab.guru](https://crontab.guru/) für Crontab-Syntax
4. **Speichern**: Änderungen werden automatisch vom Scheduler übernommen
### Urlaubsmodus
- Aktivieren/Deaktivieren über die Checkbox "Urlaubsmodus" auf der Startseite
- Tooltip: "Der Urlaubsmodus deaktiviert den geplanten Autostart für alle Geräte"
- Wirkung: Solange aktiv, führt der Scheduler keine geplanten WOL-Tasks aus
### Logs einsehen
- **Tooltips**: Die letzten 5 Log-Einträge werden als Tooltip über jeder PC-Zeile angezeigt
- **Logs-Seite**: Vollständige Log-Übersicht unter `/logs`
- **Log-Details**: Jeder Eintrag enthält Timestamp, PC-Name, MAC-Adresse und Auslöser (Button/Scheduler)
## Windows Installer
### Features
@ -147,6 +171,8 @@ ISCC.exe installer\medi-wol-setup.iss
## Build-Anweisungen
> **Wichtig**: Das Projekt verwendet Go 1.18 und kompatible Abhängigkeiten. Für neuere Go-Versionen müssen die Abhängigkeiten entsprechend angepasst werden.
### Windows Build
#### Lokaler Build (Windows)
@ -282,6 +308,7 @@ medi-wol/
│ ├── database/ # Datenbanklogik
│ ├── handlers/ # HTTP-Handler
│ ├── models/ # Datenmodelle
│ ├── scheduler/ # Autostart-Scheduler für WOL-Ereignisse
│ └── wol/ # Wake-on-LAN Service
├── web/ # Web-Oberfläche
│ ├── static/ # CSS, JavaScript
@ -292,6 +319,8 @@ medi-wol/
├── go.mod # Go-Module
├── build.bat # Windows Build-Skript (inkl. Installer)
├── build.sh # Linux Build-Skript
├── AUTOSTART_README.md # Dokumentation des Autostart-Systems
├── LOGGING_README.md # Dokumentation des Logging-Systems
└── README.md # Diese Datei
```
@ -302,6 +331,7 @@ Das `installer/` Verzeichnis enthält alle Dateien für den Windows Installer:
## API-Endpunkte
### PC-Management
- `GET /` - Hauptseite
- `GET /api/pcs` - Alle PCs abrufen
- `POST /api/pcs` - Neuen PC erstellen
@ -310,19 +340,53 @@ Das `installer/` Verzeichnis enthält alle Dateien für den Windows Installer:
- `POST /api/pcs/:id/wake` - PC aufwecken
- `GET /api/pcs/status` - Online-Status aller PCs abrufen (Ping)
### Settings
- `GET /api/settings/vacation-mode` - Status des Urlaubsmodus abrufen
- `POST /api/settings/vacation-mode` - Urlaubsmodus setzen (`{ "vacation_mode": true|false }`)
### Logging
- `GET /logs` - Logs-Seite anzeigen
- `GET /api/logs` - Alle Log-Einträge abrufen
- `GET /api/logs/pc/:id` - Logs für einen spezifischen PC abrufen
- `GET /api/logs/pc/:id/recent` - Die letzten 5 Logs für einen PC abrufen
## Datenbank
Die Anwendung verwendet SQLite als lokale Datenbank. Die Datenbankdatei `medi-wol.db` wird automatisch im Projektverzeichnis erstellt.
Hinweis: Beim ersten Start bzw. wenn die Tabelle `pcs` leer ist, wird automatisch ein Dummy-PC angelegt:
- Name: `Test`, IP: `192.168.0.1`, MAC: `00:11:22:33:AA:FF`, Cron: `30 7 * * Mon-Fri`, Autostart: deaktiviert
### Tabellenstruktur `pcs`
| Spalte | Typ | Hinweis |
|-------------|----------|------------------------|
| id | INTEGER | Primärschlüssel |
| name | TEXT | Pflichtfeld |
| mac | TEXT | Pflichtfeld, eindeutig |
| ip | TEXT | Pflichtfeld |
| created_at | DATETIME | Automatisch |
| updated_at | DATETIME | Automatisch |
| Spalte | Typ | Hinweis |
|------------------|----------|--------------------------------------------|
| id | INTEGER | Primärschlüssel |
| name | TEXT | Pflichtfeld |
| mac | TEXT | Pflichtfeld, eindeutig |
| ip | TEXT | Pflichtfeld |
| autostart_cron | TEXT | Crontab-Syntax für Autostart (Standard: `30 7 * * Mon-Fri`) |
| autostart_enabled| BOOLEAN | Autostart aktiviert (Standard: false) |
| created_at | DATETIME | Automatisch |
| updated_at | DATETIME | Automatisch |
### Tabellenstruktur `settings`
| Spalte | Typ | Hinweis |
|-----------|----------|---------------------------------|
| id | INTEGER | Primärschlüssel |
| key | TEXT | Eindeutiger Schlüssel |
| value | TEXT | Wert (z. B. "true"/"false") |
| created_at| DATETIME | Automatisch |
| updated_at| DATETIME | Automatisch |
### Tabellenstruktur `wol_logs`
| Spalte | Typ | Hinweis |
|-------------|----------|--------------------------------------------|
| id | INTEGER | Primärschlüssel |
| timestamp | DATETIME | Zeitstempel des WOL-Ereignisses |
| pc_id | INTEGER | Referenz auf PC (Foreign Key) |
| pc_name | TEXT | Name des PCs zum Zeitpunkt des Ereignisses |
| mac | TEXT | MAC-Adresse des PCs |
| trigger | TEXT | Auslöser: "button" oder "cron" |
## Wake-on-LAN
@ -356,6 +420,11 @@ go build -ldflags="-s -w" -o medi-wol.exe cmd/server/main.go
# Linux
go build -ldflags="-s -w" -o medi-wol cmd/server/main.go
# Multi-Platform Build (empfohlen)
./build.sh # Linux/macOS
# oder
.\build.bat # Windows
```
### Tests ausführen
@ -375,6 +444,32 @@ golint ./...
go vet ./...
```
## Scheduler-System
### Übersicht
Der integrierte Scheduler ermöglicht es, Wake-on-LAN Ereignisse automatisch zu geplanten Zeiten auszuführen. Dies ist ideal für:
- **Bürozeiten**: PCs starten automatisch vor Arbeitsbeginn
- **Wartungsfenster**: Regelmäßige Systemstarts für Updates
- **Energiesparen**: PCs werden nur bei Bedarf gestartet
### Funktionsweise
1. **Crontab-Parser**: Unterstützt Standard Crontab-Syntax
2. **Minuten-Intervall**: Prüft jede Minute auf fällige Aufgaben
3. **Automatische Ausführung**: Sendet WOL-Pakete ohne Benutzerinteraktion
4. **Logging**: Alle Scheduler-Ereignisse werden protokolliert
### Unterstützte Crontab-Formate
- **Einfache Werte**: `30 7 * * Mon-Fri` (Mo-Fr um 7:30 Uhr)
- **Bereiche**: `0 8-18 * * *` (8:00-18:00 Uhr stündlich)
- **Wochentage**: `0 9 * * Mon,Wed,Fri` (Mo, Mi, Fr um 9:00 Uhr)
- **Wochentag-Bereiche**: `0 8 * * Mon-Fri` (Mo-Fr um 8:00 Uhr)
### Konfiguration
- **Standard**: `30 7 * * Mon-Fri` (Mo-Fr um 7:30 Uhr)
- **Anpassung**: Über die Web-Oberfläche bei jedem PC individuell
- **Aktivierung**: Checkbox "Autostart aktiv" pro PC
- **Sofortige Übernahme**: Änderungen werden sofort vom Scheduler berücksichtigt
## Deployment
### Windows Service
@ -448,49 +543,3 @@ docker run -d -p 9090:9090 -e PORT=9090 medi-wol:latest
Dieses Projekt ist für den internen Gebrauch bestimmt.
## Support
Bei Fragen oder Problemen wenden Sie sich an das Entwicklungsteam.
Hier sind drei einfache Wege nimm Variante A (empfohlen) für die neueste Version.
- A) Offizielles Tarball (empfohlen)
1) Alte Installation entfernen (falls vorhanden):
```bash
sudo rm -rf /usr/local/go
```
2) Tarball laden und installieren (ersetze 1.22.6 und Arch bei Bedarf: amd64/arm64):
```bash
wget https://go.dev/dl/go1.22.6.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.22.6.linux-amd64.tar.gz
```
3) PATH setzen (dauerhaft):
```bash
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
source ~/.profile
```
4) Prüfen:
```bash
go version
```
- B) Snap (schnell, meist aktuell)
```bash
sudo snap install go --classic
go version
```
- C) Ubuntu-Paket (einfach, aber oft älter)
```bash
sudo apt update
sudo apt install -y golang-go
go version
```
Hinweise:
- Standard-GOPATH ist ~/go. Optional:
```bash
echo 'export GOPATH=$HOME/go' >> ~/.profile
echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.profile
source ~/.profile
```

0
build.sh Normal file → Executable file
View File

View File

@ -48,6 +48,25 @@ func main() {
}
defer db.Close()
// Dummy-PC anlegen, falls keine Geräte vorhanden sind
pcs, err := db.GetAllPCs()
if err != nil {
log.Printf("Warnung: Konnte PCs nicht laden: %v", err)
} else if len(pcs) == 0 {
_, createErr := db.CreatePC(
"Test",
"00:11:22:33:AA:FF",
"192.168.0.1",
"30 7 * * Mon-Fri",
false,
)
if createErr != nil {
log.Printf("Warnung: Konnte Dummy-PC nicht anlegen: %v", createErr)
} else {
log.Println("Dummy-PC 'Test' automatisch angelegt (leere Datenbank)")
}
}
// Wake-on-LAN Service initialisieren
wolService := wol.NewService()
@ -79,6 +98,10 @@ func main() {
r.GET("/api/logs", pcHandler.GetAllLogs)
r.GET("/api/logs/pc/:id", pcHandler.GetLogsByPCID)
r.GET("/api/logs/pc/:id/recent", pcHandler.GetRecentLogsByPCID)
// Settings-API
r.GET("/api/settings/vacation-mode", pcHandler.GetVacationMode)
r.POST("/api/settings/vacation-mode", pcHandler.SetVacationMode)
// Statische Dateien bereitstellen (nach den spezifischen Routen)
r.Static("/static", "./web/static")

Binary file not shown.

Binary file not shown.

4
go.mod
View File

@ -1,10 +1,10 @@
module medi-wol
go 1.23.0
go 1.18
require (
github.com/gin-gonic/gin v1.9.1
golang.org/x/sys v0.35.0
golang.org/x/sys v0.15.0
modernc.org/sqlite v1.28.0
)

13
go.sum
View File

@ -16,7 +16,6 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
@ -28,10 +27,8 @@ github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@ -46,7 +43,6 @@ github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNa
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -83,11 +79,10 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
@ -110,9 +105,7 @@ modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.29.0 h1:tTFRFq69YKCF2QyGNuRUQxKBm1uZZLubf6Cjh/pVHXs=
modernc.org/libc v1.29.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
@ -126,9 +119,7 @@ modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c=
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

@ -27,16 +27,14 @@ Compression=lzma
SolidCompression=yes
WizardStyle=modern
PrivilegesRequired=admin
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
ArchitecturesAllowed=x64os
ArchitecturesInstallIn64BitMode=x64os
[Languages]
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 6.1; Check: not IsAdminInstallMode
Name: "startservice"; Description: "{cm:StartServiceAfterInstall}"; GroupDescription: "{cm:ServiceOptions}"
[Files]
@ -48,10 +46,8 @@ Source: "..\LICENSE"; DestDir: "{app}"; Flags: ignoreversion
Source: "..\README.md"; DestDir: "{app}"; Flags: ignoreversion
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\{#MyAppExeName}"
Name: "{group}\mediWOL WEB UI"; Filename: "cmd.exe"; Parameters: "/c start http://localhost:{code:GetPort}"; IconFilename: "medi-wol.ico"
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon
[Run]
; Installiere Medi-WOL als Windows-Dienst mit NSSM
@ -76,6 +72,8 @@ Filename: "{app}\nssm.exe"; Parameters: "set ""{#MyAppServiceName}"" AppStopMeth
Filename: "{app}\nssm.exe"; Parameters: "set ""{#MyAppServiceName}"" AppStopMethodThreads 1500"; Flags: runhidden
; Service nach Installation starten mit Verzögerung
Filename: "{app}\nssm.exe"; Parameters: "start ""{#MyAppServiceName}"""; StatusMsg: "Starte Medi-WOL Dienst..."; Flags: runhidden waituntilterminated; Check: ShouldStartService
; Warte auf Service-Start und öffne dann die Web-Oberfläche
Filename: "cmd.exe"; Parameters: "/c timeout /t 3 /nobreak >nul && start http://localhost:{code:GetPort}"; StatusMsg: "Öffne Medi-WOL Web-Oberfläche..."; Flags: runhidden; Check: ShouldStartService
; Windows Firewall-Ausnahmen für den Service hinzufügen
Filename: "netsh.exe"; Parameters: "advfirewall firewall add rule name=""{#MyAppServiceName} - Inbound"" dir=in action=allow program=""{app}\{#MyAppExeName}"" enable=yes"; StatusMsg: "Erstelle Windows Firewall-Ausnahme (Eingehend)..."; Flags: runhidden
Filename: "netsh.exe"; Parameters: "advfirewall firewall add rule name=""{#MyAppServiceName} - Outbound"" dir=out action=allow program=""{app}\{#MyAppExeName}"" enable=yes"; StatusMsg: "Erstelle Windows Firewall-Ausnahme (Ausgehend)..."; Flags: runhidden
@ -83,13 +81,13 @@ Filename: "netsh.exe"; Parameters: "advfirewall firewall add rule name=""{#MyApp
[UninstallRun]
; Stoppe den Windows-Dienst vor der Deinstallation
Filename: "{app}\nssm.exe"; Parameters: "stop ""{#MyAppServiceName}"""; Flags: runhidden
Filename: "{app}\nssm.exe"; Parameters: "stop ""{#MyAppServiceName}"""; Flags: runhidden; RunOnceId: "StopService"
; Entferne den Windows-Dienst
Filename: "{app}\nssm.exe"; Parameters: "remove ""{#MyAppServiceName}"" confirm"; StatusMsg: "Entferne Medi-WOL Dienst..."; Flags: runhidden
Filename: "{app}\nssm.exe"; Parameters: "remove ""{#MyAppServiceName}"" confirm"; StatusMsg: "Entferne Medi-WOL Dienst..."; Flags: runhidden; RunOnceId: "RemoveService"
; Entferne Windows Firewall-Regeln
Filename: "netsh.exe"; Parameters: "advfirewall firewall delete rule name=""{#MyAppServiceName} - Inbound"""; Flags: runhidden
Filename: "netsh.exe"; Parameters: "advfirewall firewall delete rule name=""{#MyAppServiceName} - Outbound"""; Flags: runhidden
Filename: "netsh.exe"; Parameters: "advfirewall firewall delete rule name=""{#MyAppServiceName} - Port {code:GetPort}"""; Flags: runhidden
Filename: "netsh.exe"; Parameters: "advfirewall firewall delete rule name=""{#MyAppServiceName} - Inbound"""; Flags: runhidden; RunOnceId: "RemoveFirewallInbound"
Filename: "netsh.exe"; Parameters: "advfirewall firewall delete rule name=""{#MyAppServiceName} - Outbound"""; Flags: runhidden; RunOnceId: "RemoveFirewallOutbound"
Filename: "netsh.exe"; Parameters: "advfirewall firewall delete rule name=""{#MyAppServiceName} - Port {code:GetPort}"""; Flags: runhidden; RunOnceId: "RemoveFirewallPort"
[Code]
var
@ -150,9 +148,6 @@ end;
[CustomMessages]
german.CreateDesktopIcon=Desktop-Verknüpfung erstellen
german.CreateQuickLaunchIcon=Quick Launch-Verknüpfung erstellen
german.AdditionalIcons=Zusätzliche Verknüpfungen:
german.ServiceOptions=Service-Optionen:
german.StartServiceAfterInstall=Service nach der Installation starten
german.UninstallProgram=Medi-WOL entfernen

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -39,6 +39,21 @@ func InitDB() (*DB, error) {
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 (
@ -56,6 +71,44 @@ func InitDB() (*DB, error) {
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 {
@ -267,3 +320,32 @@ func (db *DB) GetRecentLogsByPCID(pcID int) ([]models.LogEvent, error) {
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
}

View File

@ -327,3 +327,55 @@ func (h *PCHandler) GetRecentLogsByPCID(c *gin.Context) {
Logs: logs,
})
}
// GetVacationMode gibt den aktuellen Urlaubsmodus-Status zurück
func (h *PCHandler) GetVacationMode(c *gin.Context) {
enabled, err := h.db.IsVacationModeEnabled()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "Fehler beim Laden des Urlaubsmodus: " + err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"vacation_mode": enabled,
})
}
// SetVacationMode setzt den Urlaubsmodus
func (h *PCHandler) SetVacationMode(c *gin.Context) {
var req struct {
VacationMode bool `json:"vacation_mode" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"success": false,
"message": "Ungültige Anfrage: " + err.Error(),
})
return
}
value := "false"
if req.VacationMode {
value = "true"
}
err := h.db.SetSetting("vacation_mode", value)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"success": false,
"message": "Fehler beim Speichern des Urlaubsmodus: " + err.Error(),
})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Urlaubsmodus erfolgreich aktualisiert",
"vacation_mode": req.VacationMode,
})
}

View File

@ -57,8 +57,19 @@ func (s *Scheduler) run() {
// checkAndExecuteScheduledTasks prüft alle geplanten Aufgaben
func (s *Scheduler) checkAndExecuteScheduledTasks() {
now := time.Now()
// Prüfe zuerst, ob der Urlaubsmodus aktiviert ist
vacationMode, err := s.db.IsVacationModeEnabled()
if err != nil {
log.Printf("Fehler beim Prüfen des Urlaubsmodus: %v", err)
return
}
if vacationMode {
log.Println("Urlaubsmodus aktiviert - Autostart deaktiviert")
return
}
now := time.Now()
// Alle PCs mit aktiviertem Autostart holen
pcs, err := s.db.GetPCsWithAutostart()
if err != nil {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -12,6 +12,7 @@ class PCManager {
init() {
this.loadPCs();
this.loadVacationMode();
this.setupEventListeners();
this.startAutoStatus();
}
@ -47,6 +48,11 @@ class PCManager {
document.getElementById('refreshStatusBtn').addEventListener('click', () => {
this.refreshStatus();
});
// Urlaubsmodus Checkbox
document.getElementById('vacationMode').addEventListener('change', (e) => {
this.setVacationMode(e.target.checked);
});
}
async loadPCs() {
@ -460,6 +466,60 @@ class PCManager {
content += '</div>';
return content;
}
// Urlaubsmodus laden
async loadVacationMode() {
try {
const response = await fetch('/api/settings/vacation-mode');
const data = await response.json();
if (data.success) {
const vacationModeCheckbox = document.getElementById('vacationMode');
if (vacationModeCheckbox) {
vacationModeCheckbox.checked = data.vacation_mode;
}
}
} catch (error) {
console.error('Fehler beim Laden des Urlaubsmodus:', error);
}
}
// Urlaubsmodus setzen
async setVacationMode(enabled) {
try {
const response = await fetch('/api/settings/vacation-mode', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
vacation_mode: enabled
})
});
const data = await response.json();
if (data.success) {
const status = enabled ? 'aktiviert' : 'deaktiviert';
this.showNotification('Erfolg', `Urlaubsmodus ${status}`, 'success');
} else {
this.showNotification('Fehler', data.message, 'danger');
// Checkbox zurücksetzen bei Fehler
const vacationModeCheckbox = document.getElementById('vacationMode');
if (vacationModeCheckbox) {
vacationModeCheckbox.checked = !enabled;
}
}
} catch (error) {
console.error('Fehler beim Setzen des Urlaubsmodus:', error);
this.showNotification('Fehler', 'Fehler beim Setzen des Urlaubsmodus', 'danger');
// Checkbox zurücksetzen bei Fehler
const vacationModeCheckbox = document.getElementById('vacationMode');
if (vacationModeCheckbox) {
vacationModeCheckbox.checked = !enabled;
}
}
}
}
// PC Manager initialisieren, wenn die Seite geladen ist

View File

@ -42,6 +42,22 @@
</div>
</div>
<!-- Urlaubsmodus-Checkbox -->
<div class="row mb-3">
<div class="col-12 text-center">
<div class="form-check d-inline-block">
<input class="form-check-input" type="checkbox" id="vacationMode" style="transform: scale(1.2);">
<label class="form-check-label ms-2" for="vacationMode">
<strong>Urlaubsmodus</strong>
</label>
<i class="fas fa-info-circle ms-2 text-muted"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Der Urlaubsmodus deaktiviert den geplanten Autostart für alle Geräte"></i>
</div>
</div>
</div>
<!-- Neuen PC hinzufügen -->
<div class="row mb-4">
<div class="col-12">