- Dashboard: Fehlzeiten-Warnung lädt Mitarbeitssitzungen einmal vorab statt pro Schüler/Eintrag einzeln nachzuschlagen (N+1 vermieden); neues IParticipationSessionRepository.GetAll() dafür. - CI: .gitea/workflows/ci.yml baut und testet bei jedem Push/PR. Dabei fehlende Release|Any CPU-Konfiguration für 6 Projekte in der .sln behoben (LehrerApp.Data.Tests wurde bei Release-Builds der Solution bislang stillschweigend übersprungen). TreatWarningsAsErrors jetzt aktiv. - SettingsViewModel (1986 Zeilen) als partial class auf 20 Themen- dateien aufgeteilt, Verhalten unverändert. - Backup: optionaler zweiter Sicherungsordner (USB-Stick/Netzlaufwerk, best-effort) und Integritätsprüfung nach jedem Backup (DatabaseEncryptionService.CanOpenAndRead). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
86 lines
2.9 KiB
C#
86 lines
2.9 KiB
C#
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using LehrerApp.Core.Interfaces;
|
|
using LehrerApp.Core.Models;
|
|
using LehrerApp.Core.Services;
|
|
using LehrerApp.Data;
|
|
using LehrerApp.Desktop.Services;
|
|
using LehrerApp.Desktop.ViewModels.Planning;
|
|
using LehrerApp.Sync;
|
|
using LehrerApp.Sync.Crypto;
|
|
using System.Collections.ObjectModel;
|
|
using System.Globalization;
|
|
using System.Security.Cryptography;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace LehrerApp.Desktop.ViewModels.Settings;
|
|
|
|
public partial class SettingsViewModel
|
|
{
|
|
// ── Sicherheit: Datenbank-Verschlüsselung (13.3.4) ───────────────────────
|
|
|
|
[ObservableProperty] private bool _isDbEncrypted;
|
|
[ObservableProperty] private string _currentDbPassword = "";
|
|
[ObservableProperty] private string _newDbPassword = "";
|
|
[ObservableProperty] private string _newDbPasswordConfirm = "";
|
|
[ObservableProperty] private string _dbPasswordError = "";
|
|
|
|
public string DbEncryptionStatusLabel => IsDbEncrypted ? "verschlüsselt" : "nicht verschlüsselt";
|
|
|
|
partial void OnIsDbEncryptedChanged(bool value) => OnPropertyChanged(nameof(DbEncryptionStatusLabel));
|
|
|
|
// ── Datenbank-Verschlüsselung: Setzen / Ändern / Entfernen ───────────────
|
|
|
|
[RelayCommand]
|
|
private void SaveDbPassword()
|
|
{
|
|
DbPasswordError = "";
|
|
var valid = true;
|
|
var wantsPassword = !string.IsNullOrWhiteSpace(NewDbPassword) || !string.IsNullOrWhiteSpace(NewDbPasswordConfirm);
|
|
|
|
if (IsDbEncrypted && !_dbEncryption.VerifyPassword(AppBootstrapper.DbPath, CurrentDbPassword))
|
|
{
|
|
DbPasswordError = "Aktuelles Passwort ist falsch.";
|
|
valid = false;
|
|
}
|
|
|
|
if (!wantsPassword)
|
|
{
|
|
DbPasswordError = "Bitte ein neues Passwort eingeben.";
|
|
valid = false;
|
|
}
|
|
else if (NewDbPassword != NewDbPasswordConfirm)
|
|
{
|
|
DbPasswordError = "Neue Passwörter stimmen nicht überein.";
|
|
valid = false;
|
|
}
|
|
else if (NewDbPassword.Length < 4)
|
|
{
|
|
DbPasswordError = "Mindestens 4 Zeichen.";
|
|
valid = false;
|
|
}
|
|
|
|
if (!valid) return;
|
|
|
|
_dbContext.Dispose();
|
|
_dbEncryption.SetPassword(AppBootstrapper.DbPath, IsDbEncrypted ? CurrentDbPassword : null, NewDbPassword.Trim());
|
|
AppBootstrapper.RestartApplication();
|
|
}
|
|
|
|
[RelayCommand]
|
|
private void RemoveDbPassword()
|
|
{
|
|
DbPasswordError = "";
|
|
if (!_dbEncryption.VerifyPassword(AppBootstrapper.DbPath, CurrentDbPassword))
|
|
{
|
|
DbPasswordError = "Aktuelles Passwort ist falsch.";
|
|
return;
|
|
}
|
|
|
|
_dbContext.Dispose();
|
|
_dbEncryption.SetPassword(AppBootstrapper.DbPath, CurrentDbPassword, null);
|
|
AppBootstrapper.RestartApplication();
|
|
}
|
|
}
|