diff --git a/ChronoFlow.Controller/ZeiterfassungsController.cs b/ChronoFlow.Controller/ZeiterfassungsController.cs index c7de1ec..42f4a35 100644 --- a/ChronoFlow.Controller/ZeiterfassungsController.cs +++ b/ChronoFlow.Controller/ZeiterfassungsController.cs @@ -1,20 +1,38 @@ using System.Collections.Generic; using ChronoFlow.Model; +using ChronoFlow.Persistence; namespace ChronoFlow.Controller { + /// + /// Vermittelt zwischen der View und dem Speichersystem (SQLite) + /// public class ZeiterfassungsController { - private readonly List _eintraege = new(); + private readonly SqliteZeiterfassungsService _dbService; + /// + /// Konstruktor: Initialisiert die Verbindung zum SQLite-Dienst + /// + public ZeiterfassungsController() + { + _dbService = new SqliteZeiterfassungsService(); + } + + /// + /// Speichert einen neuen Zeiteintrag dauerhaft in der SQLite-Datenbank + /// public void SpeichereEintrag(Zeiteintrag eintrag) { - _eintraege.Add(eintrag); + _dbService.SpeichereEintrag(eintrag); } + /// + /// Lädt alle vorhandenen Einträge aus der Datenbank + /// public List LadeAlleEintraege() { - return new List(_eintraege); + return _dbService.LadeAlleZeiteintraege(); } } -} +} \ No newline at end of file diff --git a/ChronoFlow.Model/User.cs b/ChronoFlow.Model/User.cs index 27c19ca..a2247f6 100644 --- a/ChronoFlow.Model/User.cs +++ b/ChronoFlow.Model/User.cs @@ -10,5 +10,7 @@ namespace ChronoFlow.Model public string Username { get; set; } public string Password { get; set; } //vorerst im Klartext, wird später geändert public string Role { get; set; } //"Admin" oder "Mitarbeiter" + public string Mitarbeiternummer { get; set; } = ""; + public string Abteilung { get; set; } = ""; } } \ No newline at end of file diff --git a/ChronoFlow.Persistence/ChronoFlow.Persistence.csproj b/ChronoFlow.Persistence/ChronoFlow.Persistence.csproj index 7474d79..30dbf86 100644 --- a/ChronoFlow.Persistence/ChronoFlow.Persistence.csproj +++ b/ChronoFlow.Persistence/ChronoFlow.Persistence.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/ChronoFlow.Persistence/SqliteZeiterfassungsService.cs b/ChronoFlow.Persistence/SqliteZeiterfassungsService.cs new file mode 100644 index 0000000..c5147f4 --- /dev/null +++ b/ChronoFlow.Persistence/SqliteZeiterfassungsService.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using Microsoft.Data.Sqlite; +using ChronoFlow.Model; + +namespace ChronoFlow.Persistence +{ + public class SqliteZeiterfassungsService + { + private readonly string _dbPath = "chrono_data_v2.sb"; + + public SqliteZeiterfassungsService() + { + // Prüfe, ob die DB existiert, sonst erstelle sie + if (!File.Exists(_dbPath)) + ErstelleDatenbank(); + } + + private void ErstelleDatenbank() + { + Console.WriteLine("🛠️ ErstelleDatenbank wurde aufgerufen!"); + + using var connection = new SqliteConnection($"Data Source={_dbPath}"); + connection.Open(); + + var cmd1 = connection.CreateCommand(); + cmd1.CommandText = @" + CREATE TABLE IF NOT EXISTS Zeiteintraege ( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + Mitarbeiter TEXT NOT NULL, + Startzeit TEXT NOT NULL, + Endzeit TEXT NOT NULL, + Projekt TEXT, + Kommentar TEXT, + Erledigt INTEGER, + MitarbeiterKommentar TEXT + );"; + cmd1.ExecuteNonQuery(); + + var cmd2 = connection.CreateCommand(); + cmd2.CommandText = @" + CREATE TABLE IF NOT EXISTS Benutzer ( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + Username TEXT NOT NULL, + Password TEXT NOT NULL, + Role TEXT NOT NULL, + Mitarbeiternummer TEXT, + Abteilung TEXT + );"; + cmd2.ExecuteNonQuery(); + } + + + public void SpeichereEintrag(Zeiteintrag eintrag) + { + using var connection = new SqliteConnection($"Data Source={_dbPath}"); + connection.Open(); + + var cmd = connection.CreateCommand(); + cmd.CommandText = @" + INSERT INTO Zeiteintraege + (Mitarbeiter, Startzeit, Endzeit, Projekt, Kommentar, Erledigt, MitarbeiterKommentar) + VALUES ($Mitarbeiter, $Startzeit, $Endzeit, $Projekt, $Kommentar, $Erledigt, $MitarbeiterKommentar); + "; + + cmd.Parameters.AddWithValue("$Mitarbeiter", eintrag.Mitarbeiter); + cmd.Parameters.AddWithValue("$Startzeit", eintrag.Startzeit.ToString("o")); + cmd.Parameters.AddWithValue("$Endzeit", eintrag.Endzeit.ToString("o")); + cmd.Parameters.AddWithValue("$Projekt", eintrag.Projekt ?? ""); + cmd.Parameters.AddWithValue("$Kommentar", eintrag.Kommentar ?? ""); + cmd.Parameters.AddWithValue("$Erledigt", eintrag.Erledigt ? 1 : 0); + cmd.Parameters.AddWithValue("$MitarbeiterKommentar", eintrag.MitarbeiterKommentar ?? ""); + + cmd.ExecuteNonQuery(); + } + + public List LadeAlleZeiteintraege() + { + var eintraege = new List(); + + using var connection = new SqliteConnection($"Data Source={_dbPath}"); + connection.Open(); + + var cmd = connection.CreateCommand(); + cmd.CommandText = "SELECT * FROM Zeiteintraege;"; + + using var reader = cmd.ExecuteReader(); + while (reader.Read()) + { + eintraege.Add(new Zeiteintrag + { + Mitarbeiter = reader.GetString(1), + Startzeit = DateTime.Parse(reader.GetString(2)), + Endzeit = DateTime.Parse(reader.GetString(3)), + Projekt = reader.GetString(4), + Kommentar = reader.GetString(5), + Erledigt = Convert.ToInt32(reader["Erledigt"]) == 1, + MitarbeiterKommentar = reader.GetString(7) + }); + } + + return eintraege; + } + public List LadeAlleMitarbeiterNamen() + { + var namen = new List(); + + using var connection = new SqliteConnection($"Data Source={_dbPath}"); + connection.Open(); + + var cmd = connection.CreateCommand(); + cmd.CommandText = "SELECT Username From Benutzer Where Role = 'Mitarbeiter';"; + + using var reader = cmd.ExecuteReader(); + while (reader.Read()) + { + namen.Add(reader.GetString(0)); + } + return namen; + } + public List LadeAlleBenutzer() + { + var benutzerListe = new List(); + + using var connection = new SqliteConnection($"Data Source={_dbPath}"); + connection.Open(); + + var cmd = connection.CreateCommand(); + cmd.CommandText = "SELECT Username, Password, Role, Mitarbeiternummer, Abteilung FROM Benutzer;"; + + using var reader = cmd.ExecuteReader(); + while (reader.Read()) + { + benutzerListe.Add(new User + { + Username = reader.GetString(0), + Password = reader.GetString(1), + Role = reader.GetString(2), + Mitarbeiternummer = reader.IsDBNull(3) ? "" : reader.GetString(3), + Abteilung = reader.IsDBNull(4) ? "" : reader.GetString(4) + }); + } + + return benutzerListe; + } + + public void ErstelleStandardAdmin() + { + using var connection = new SqliteConnection($"Data Source={_dbPath}"); + connection.Open(); + + var cmd = connection.CreateCommand(); + cmd.CommandText = @" + INSERT INTO Benutzer (Username, Password, Role, Mitarbeiternummer, Abteilung) + VALUES ('admin', 'admin', 'Admin', '0001', 'IT'); + "; + + cmd.ExecuteNonQuery(); + + Console.WriteLine("✅ Standard-Admin erfolgreich eingefügt."); + } + + public List LadeAlleBenutzernamen() + { + var benutzernamen = new List(); + + using var connection = new SqliteConnection($"Data Source={_dbPath}"); + connection.Open(); + + using var cmd = connection.CreateCommand();//<--- Wir erstellen cmd + cmd.CommandText = "SELECT Username From Benutzer;"; + + using var reader = cmd.ExecuteReader(); + while (reader.Read()) + { + benutzernamen.Add(reader.GetString(0)); + } + return benutzernamen; + } + + } +} diff --git a/ChronoFlow.View/App.axaml.cs b/ChronoFlow.View/App.axaml.cs index e27c051..930c6d5 100644 --- a/ChronoFlow.View/App.axaml.cs +++ b/ChronoFlow.View/App.axaml.cs @@ -2,6 +2,7 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using ChronoFlow.View; +using ChronoFlow.Persistence; namespace ChronoFlow; @@ -16,6 +17,13 @@ public partial class App : Application { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { + // ⬇ Initialisiert den SQLite-Service beim Programmstart, + // um sicherzustellen, dass die Datenbank-Datei und alle benötigten Tabellen + // (z.B. Zeiteintraege, Benutzer) vorhanden sind. + // Ohne diesen Aufruf würden neue Tabellen nicht angelegt werden, + // falls die Datei chrono_data.sb noch nicht existiert. + var dbInit = new SqliteZeiterfassungsService(); + // Starte das Programm mit dem Login-Fenster desktop.MainWindow = new LoginWindow(); } diff --git a/ChronoFlow.View/LoginWindow.axaml.cs b/ChronoFlow.View/LoginWindow.axaml.cs index d732ab1..4520a55 100644 --- a/ChronoFlow.View/LoginWindow.axaml.cs +++ b/ChronoFlow.View/LoginWindow.axaml.cs @@ -1,6 +1,9 @@ +using System.Linq; using Avalonia.Controls; using Avalonia.Interactivity; +using Avalonia.Metadata; using ChronoFlow.Controller; +using ChronoFlow.Persistence; namespace ChronoFlow.View { @@ -15,6 +18,9 @@ namespace ChronoFlow.View { InitializeComponent(); // Verbindet XAML mit diesem Code _loginController = new LoginController(); // Unsere "Logik-Klasse" + var service = new SqliteZeiterfassungsService(); + service.ErstelleStandardAdmin(); + } /// @@ -22,11 +28,20 @@ namespace ChronoFlow.View /// private void LoginButton_Click(object? sender, RoutedEventArgs e) { - // Holt Benutzername und Passwort aus den Eingabefeldern - string username = UsernameBox?.Text ?? string.Empty; - string password = PasswordBox?.Text ?? string.Empty; - // Übergibt die Eingaben an den LoginController - var user = _loginController.Authenticate(username, password); + var username = UsernameBox.Text?.Trim(); + var password = PasswordBox.Text?.Trim(); + + if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password)) + { + ErrorText.Text = "Bitte Benutzername und Passwort eingeben"; + ErrorText.IsVisible = true; + return; + } + + var service = new SqliteZeiterfassungsService(); + var benutzerListe = service.LadeAlleBenutzer(); + + var user = benutzerListe.FirstOrDefault(u => u.Username == username && u.Password == password); if (user != null) { diff --git a/ChronoFlow.View/MainWindow.axaml b/ChronoFlow.View/MainWindow.axaml index 89be531..76ba89e 100644 --- a/ChronoFlow.View/MainWindow.axaml +++ b/ChronoFlow.View/MainWindow.axaml @@ -6,13 +6,14 @@ x:Class="ChronoFlow.View.MainWindow" Title="ChronoFlow.View"> - +