Compare commits
12 Commits
schedule-c
...
Urlaubsmod
| Author | SHA1 | Date | |
|---|---|---|---|
| ce2eea5f43 | |||
| bdeabaad2e | |||
| 5c13a34bbf | |||
| d85181e797 | |||
| b860571f40 | |||
| 1dfa0c9b32 | |||
| 0488e4ec47 | |||
| 5b03441b4d | |||
| 49c3ece8f5 | |||
| 12655429ac | |||
| 9f49a1b865 | |||
| 774e3c953f |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -46,3 +46,5 @@ Thumbs.db
|
|||||||
# Temporary files
|
# Temporary files
|
||||||
tmp/
|
tmp/
|
||||||
temp/
|
temp/
|
||||||
|
|
||||||
|
dist/
|
||||||
|
|||||||
150
README.md
150
README.md
@@ -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
|
- **Wake-on-LAN**: Ein-Klick-Aufwecken von Computern über MAC-Adressen
|
||||||
- **IP-Adressverwaltung**: Pro Gerät wird eine IP-Adresse gespeichert
|
- **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
|
- **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
|
- **Moderne Web-Oberfläche**: Responsive Design mit Bootstrap und FontAwesome
|
||||||
- **SQLite-Datenbank**: Einfache lokale Datenspeicherung
|
- **SQLite-Datenbank**: Einfache lokale Datenspeicherung
|
||||||
- **Cross-Platform**: Läuft auf Windows und Linux
|
- **Cross-Platform**: Läuft auf Windows und Linux
|
||||||
@@ -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
|
- Klicken Sie auf den "Löschen"-Button neben dem gewünschten PC
|
||||||
- Bestätigen Sie die Löschung
|
- 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
|
## Windows Installer
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
@@ -282,6 +306,7 @@ medi-wol/
|
|||||||
│ ├── database/ # Datenbanklogik
|
│ ├── database/ # Datenbanklogik
|
||||||
│ ├── handlers/ # HTTP-Handler
|
│ ├── handlers/ # HTTP-Handler
|
||||||
│ ├── models/ # Datenmodelle
|
│ ├── models/ # Datenmodelle
|
||||||
|
│ ├── scheduler/ # Autostart-Scheduler für WOL-Ereignisse
|
||||||
│ └── wol/ # Wake-on-LAN Service
|
│ └── wol/ # Wake-on-LAN Service
|
||||||
├── web/ # Web-Oberfläche
|
├── web/ # Web-Oberfläche
|
||||||
│ ├── static/ # CSS, JavaScript
|
│ ├── static/ # CSS, JavaScript
|
||||||
@@ -292,6 +317,8 @@ medi-wol/
|
|||||||
├── go.mod # Go-Module
|
├── go.mod # Go-Module
|
||||||
├── build.bat # Windows Build-Skript (inkl. Installer)
|
├── build.bat # Windows Build-Skript (inkl. Installer)
|
||||||
├── build.sh # Linux Build-Skript
|
├── build.sh # Linux Build-Skript
|
||||||
|
├── AUTOSTART_README.md # Dokumentation des Autostart-Systems
|
||||||
|
├── LOGGING_README.md # Dokumentation des Logging-Systems
|
||||||
└── README.md # Diese Datei
|
└── README.md # Diese Datei
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -302,6 +329,7 @@ Das `installer/` Verzeichnis enthält alle Dateien für den Windows Installer:
|
|||||||
|
|
||||||
## API-Endpunkte
|
## API-Endpunkte
|
||||||
|
|
||||||
|
### PC-Management
|
||||||
- `GET /` - Hauptseite
|
- `GET /` - Hauptseite
|
||||||
- `GET /api/pcs` - Alle PCs abrufen
|
- `GET /api/pcs` - Alle PCs abrufen
|
||||||
- `POST /api/pcs` - Neuen PC erstellen
|
- `POST /api/pcs` - Neuen PC erstellen
|
||||||
@@ -310,19 +338,53 @@ Das `installer/` Verzeichnis enthält alle Dateien für den Windows Installer:
|
|||||||
- `POST /api/pcs/:id/wake` - PC aufwecken
|
- `POST /api/pcs/:id/wake` - PC aufwecken
|
||||||
- `GET /api/pcs/status` - Online-Status aller PCs abrufen (Ping)
|
- `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
|
## Datenbank
|
||||||
|
|
||||||
Die Anwendung verwendet SQLite als lokale Datenbank. Die Datenbankdatei `medi-wol.db` wird automatisch im Projektverzeichnis erstellt.
|
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`
|
### Tabellenstruktur `pcs`
|
||||||
| Spalte | Typ | Hinweis |
|
| Spalte | Typ | Hinweis |
|
||||||
|-------------|----------|------------------------|
|
|------------------|----------|--------------------------------------------|
|
||||||
| id | INTEGER | Primärschlüssel |
|
| id | INTEGER | Primärschlüssel |
|
||||||
| name | TEXT | Pflichtfeld |
|
| name | TEXT | Pflichtfeld |
|
||||||
| mac | TEXT | Pflichtfeld, eindeutig |
|
| mac | TEXT | Pflichtfeld, eindeutig |
|
||||||
| ip | TEXT | Pflichtfeld |
|
| ip | TEXT | Pflichtfeld |
|
||||||
| created_at | DATETIME | Automatisch |
|
| autostart_cron | TEXT | Crontab-Syntax für Autostart (Standard: `30 7 * * Mon-Fri`) |
|
||||||
| updated_at | DATETIME | Automatisch |
|
| 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
|
## Wake-on-LAN
|
||||||
|
|
||||||
@@ -375,6 +437,32 @@ golint ./...
|
|||||||
go vet ./...
|
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
|
## Deployment
|
||||||
|
|
||||||
### Windows Service
|
### Windows Service
|
||||||
@@ -448,49 +536,3 @@ docker run -d -p 9090:9090 -e PORT=9090 medi-wol:latest
|
|||||||
|
|
||||||
Dieses Projekt ist für den internen Gebrauch bestimmt.
|
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
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -48,6 +48,25 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer db.Close()
|
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
|
// Wake-on-LAN Service initialisieren
|
||||||
wolService := wol.NewService()
|
wolService := wol.NewService()
|
||||||
|
|
||||||
@@ -80,6 +99,10 @@ func main() {
|
|||||||
r.GET("/api/logs/pc/:id", pcHandler.GetLogsByPCID)
|
r.GET("/api/logs/pc/:id", pcHandler.GetLogsByPCID)
|
||||||
r.GET("/api/logs/pc/:id/recent", pcHandler.GetRecentLogsByPCID)
|
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)
|
// Statische Dateien bereitstellen (nach den spezifischen Routen)
|
||||||
r.Static("/static", "./web/static")
|
r.Static("/static", "./web/static")
|
||||||
|
|
||||||
|
|||||||
BIN
dist/medi-wol-linux-amd64
vendored
BIN
dist/medi-wol-linux-amd64
vendored
Binary file not shown.
BIN
dist/medi-wol-linux-arm64
vendored
BIN
dist/medi-wol-linux-arm64
vendored
Binary file not shown.
@@ -27,16 +27,14 @@ Compression=lzma
|
|||||||
SolidCompression=yes
|
SolidCompression=yes
|
||||||
WizardStyle=modern
|
WizardStyle=modern
|
||||||
PrivilegesRequired=admin
|
PrivilegesRequired=admin
|
||||||
ArchitecturesAllowed=x64
|
ArchitecturesAllowed=x64os
|
||||||
ArchitecturesInstallIn64BitMode=x64
|
ArchitecturesInstallIn64BitMode=x64os
|
||||||
|
|
||||||
[Languages]
|
[Languages]
|
||||||
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
|
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
|
||||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
|
|
||||||
[Tasks]
|
[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}"
|
Name: "startservice"; Description: "{cm:StartServiceAfterInstall}"; GroupDescription: "{cm:ServiceOptions}"
|
||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
@@ -48,10 +46,8 @@ Source: "..\LICENSE"; DestDir: "{app}"; Flags: ignoreversion
|
|||||||
Source: "..\README.md"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "..\README.md"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
|
||||||
[Icons]
|
[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: "{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]
|
[Run]
|
||||||
; Installiere Medi-WOL als Windows-Dienst mit NSSM
|
; 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
|
Filename: "{app}\nssm.exe"; Parameters: "set ""{#MyAppServiceName}"" AppStopMethodThreads 1500"; Flags: runhidden
|
||||||
; Service nach Installation starten mit Verzögerung
|
; Service nach Installation starten mit Verzögerung
|
||||||
Filename: "{app}\nssm.exe"; Parameters: "start ""{#MyAppServiceName}"""; StatusMsg: "Starte Medi-WOL Dienst..."; Flags: runhidden waituntilterminated; Check: ShouldStartService
|
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
|
; 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} - 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
|
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]
|
[UninstallRun]
|
||||||
; Stoppe den Windows-Dienst vor der Deinstallation
|
; 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
|
; 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
|
; 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} - Inbound"""; Flags: runhidden; RunOnceId: "RemoveFirewallInbound"
|
||||||
Filename: "netsh.exe"; Parameters: "advfirewall firewall delete rule name=""{#MyAppServiceName} - Outbound"""; Flags: runhidden
|
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
|
Filename: "netsh.exe"; Parameters: "advfirewall firewall delete rule name=""{#MyAppServiceName} - Port {code:GetPort}"""; Flags: runhidden; RunOnceId: "RemoveFirewallPort"
|
||||||
|
|
||||||
[Code]
|
[Code]
|
||||||
var
|
var
|
||||||
@@ -150,9 +148,6 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
[CustomMessages]
|
[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.ServiceOptions=Service-Optionen:
|
||||||
german.StartServiceAfterInstall=Service nach der Installation starten
|
german.StartServiceAfterInstall=Service nach der Installation starten
|
||||||
german.UninstallProgram=Medi-WOL entfernen
|
german.UninstallProgram=Medi-WOL entfernen
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.2 KiB |
@@ -39,6 +39,21 @@ func InitDB() (*DB, error) {
|
|||||||
return nil, err
|
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
|
// Log-Tabelle erstellen
|
||||||
createLogTableSQL := `
|
createLogTableSQL := `
|
||||||
CREATE TABLE IF NOT EXISTS wol_logs (
|
CREATE TABLE IF NOT EXISTS wol_logs (
|
||||||
@@ -56,6 +71,44 @@ func InitDB() (*DB, error) {
|
|||||||
return nil, err
|
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
|
// Füge IP-Spalte hinzu, falls sie nicht existiert
|
||||||
_, err = db.Exec("ALTER TABLE pcs ADD COLUMN ip TEXT DEFAULT ''")
|
_, err = db.Exec("ALTER TABLE pcs ADD COLUMN ip TEXT DEFAULT ''")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -267,3 +320,32 @@ func (db *DB) GetRecentLogsByPCID(pcID int) ([]models.LogEvent, error) {
|
|||||||
|
|
||||||
return logs, nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -327,3 +327,55 @@ func (h *PCHandler) GetRecentLogsByPCID(c *gin.Context) {
|
|||||||
Logs: logs,
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -57,8 +57,19 @@ func (s *Scheduler) run() {
|
|||||||
|
|
||||||
// checkAndExecuteScheduledTasks prüft alle geplanten Aufgaben
|
// checkAndExecuteScheduledTasks prüft alle geplanten Aufgaben
|
||||||
func (s *Scheduler) checkAndExecuteScheduledTasks() {
|
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
|
// Alle PCs mit aktiviertem Autostart holen
|
||||||
pcs, err := s.db.GetPCsWithAutostart()
|
pcs, err := s.db.GetPCsWithAutostart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 24 KiB |
@@ -12,6 +12,7 @@ class PCManager {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.loadPCs();
|
this.loadPCs();
|
||||||
|
this.loadVacationMode();
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
this.startAutoStatus();
|
this.startAutoStatus();
|
||||||
}
|
}
|
||||||
@@ -47,6 +48,11 @@ class PCManager {
|
|||||||
document.getElementById('refreshStatusBtn').addEventListener('click', () => {
|
document.getElementById('refreshStatusBtn').addEventListener('click', () => {
|
||||||
this.refreshStatus();
|
this.refreshStatus();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Urlaubsmodus Checkbox
|
||||||
|
document.getElementById('vacationMode').addEventListener('change', (e) => {
|
||||||
|
this.setVacationMode(e.target.checked);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadPCs() {
|
async loadPCs() {
|
||||||
@@ -460,6 +466,60 @@ class PCManager {
|
|||||||
content += '</div>';
|
content += '</div>';
|
||||||
return content;
|
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
|
// PC Manager initialisieren, wenn die Seite geladen ist
|
||||||
|
|||||||
@@ -42,6 +42,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 -->
|
<!-- Neuen PC hinzufügen -->
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
|||||||
Reference in New Issue
Block a user