using System; using System.Collections.Generic; using System.IO; using Microsoft.Data.Sqlite; using ChronoFlow.Model; using ChronoFlow.Security; namespace ChronoFlow.Persistence { // Schnittstelle für die Zeiterfassungsfunktionen public interface IZeiterfassungsRepository { Task> GetEintraegeFuerMitarbeiterAsync(string mitarbeiterName); Task UpdateStatusUndKommentarAsync(int id, bool erledigt, string mitarbeiterKommentar); } /// /// Implementierung des SQLite-Datenbankzugriffs für Benutzer und Zeiteinträge. /// public class SqliteZeiterfassungsService : IZeiterfassungsRepository { // Pfad zur SQLite-Datenbankdatei private readonly string _dbPath = "chrono_data.sb"; /// /// Konstruktor: Erstellt Datenbank falls nicht vorhanden und stellt die Struktur sicher. /// public SqliteZeiterfassungsService() { if (!File.Exists(_dbPath)) ErstelleDatenbank(); // Auch bei bestehender Datei sicherstellen, dass alle Spalten vorhanden sind PrüfeUndErweitereDatenbank(); // Async-Aufruf wird absichtlich nicht awaitet _ = StelleDatenbankstrukturSicherAsync(); } /// /// Erstellt die Basis-Datenbankstruktur, falls Datei noch nicht existiert. /// 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, Mitarbeitennummer TEXT, Abteilung TEXT, MussPasswortAendern INTEGER DEFAULT 1 );"; cmd2.ExecuteNonQuery(); } public void ErstelleNeuenBenutzer(User benutzer) { // Erstellt eine neue Benutzerzeile in der Datenbank using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = @" INSERT INTO Benutzer (Username, Password, Role, Mitarbeitennummer, Abteilung, MussPasswortAendern) VALUES ($Username, $Password, $Role, $Mitarbeiternummer, $Abteilung, $MussPasswortAendern); "; cmd.Parameters.AddWithValue("$Username", benutzer.Username); cmd.Parameters.AddWithValue("$Password", benutzer.Password); cmd.Parameters.AddWithValue("$Role", benutzer.Role); cmd.Parameters.AddWithValue("$Mitarbeiternummer", benutzer.Mitarbeiternummer ?? ""); cmd.Parameters.AddWithValue("$Abteilung", benutzer.Abteilung ?? ""); cmd.Parameters.AddWithValue("$MussPasswortAendern", benutzer.MussPasswortAendern ? 1 : 0); int rowsAffected = cmd.ExecuteNonQuery(); Console.WriteLine( $"✅ Neuer Benutzer '{benutzer.Username}' wurde gespeichert (Rows affected: {rowsAffected})."); } private void PrüfeUndErweitereDatenbank() { // Stellt sicher, dass die Datenbank alle benötigten Spalten enthält using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); AddColumnIfMissing(connection, "Benutzer", "Mitarbeitennummer", "TEXT"); AddColumnIfMissing(connection, "Benutzer", "Abteilung", "TEXT"); AddColumnIfMissing(connection, "Benutzer", "MussPasswortAendern", "INTEGER DEFAULT 1"); AddColumnIfMissing(connection, "Benutzer", "LetzterLogin", "TEXT"); AddColumnIfMissing(connection, "Benutzer", "VorletzterLogin", "TEXT"); AddColumnIfMissing(connection, "Zeiteintraege", "LetzteBearbeitung", "TEXT"); } private void AddColumnIfMissing(SqliteConnection connection, string tableName, string columnName, string columnType) { // Prüft, ob eine Spalte existiert und fügt sie bei Bedarf hinzu var checkCmd = connection.CreateCommand(); checkCmd.CommandText = $"PRAGMA table_info({tableName});"; using var reader = checkCmd.ExecuteReader(); bool columnExists = false; while (reader.Read()) { var existingColumnName = reader.GetString(1); if (existingColumnName.Equals(columnName, StringComparison.OrdinalIgnoreCase)) { columnExists = true; break; } } if (!columnExists) { var alterCmd = connection.CreateCommand(); alterCmd.CommandText = $"ALTER TABLE {tableName} ADD COLUMN {columnName} {columnType};"; alterCmd.ExecuteNonQuery(); Console.WriteLine($"✅ Spalte '{columnName}' in Tabelle '{tableName}' hinzugefügt."); } } public void ErstelleStandardAdmin() { // Erstellt einen Admin-Benutzer, wenn dieser noch nicht existiert using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var checkCmd = connection.CreateCommand(); checkCmd.CommandText = "SELECT COUNT(*) FROM Benutzer WHERE Username = 'admin';"; var count = Convert.ToInt32(checkCmd.ExecuteScalar()); if (count == 0) { var hashedPassword = PasswordHasher.HashPassword("admin"); var insertCmd = connection.CreateCommand(); insertCmd.CommandText = @" INSERT INTO Benutzer (Username, Password, Role, Mitarbeitennummer, Abteilung, MussPasswortAendern) VALUES ('admin', $Password, 'Admin', '0001', 'IT', 1); "; insertCmd.Parameters.AddWithValue("$Password", hashedPassword); insertCmd.ExecuteNonQuery(); Console.WriteLine("✅ Standard-Admin erfolgreich eingefügt."); } else { Console.WriteLine("ℹ Standard-Admin existiert bereits – kein neuer Eintrag erstellt."); } } public List LadeAlleBenutzer() { var benutzerListe = new List(); try { using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = @" SELECT Id, Username, Password, Role, Mitarbeitennummer, Abteilung, MussPasswortAendern, LetzterLogin, VorletzterLogin FROM Benutzer; "; using var reader = cmd.ExecuteReader(); while (reader.Read()) { // Parsing wie gehabt benutzerListe.Add(new User { Id = reader.GetInt32(0), Username = reader.GetString(1), Password = reader.GetString(2), Role = reader.GetString(3), Mitarbeiternummer = reader.IsDBNull(4) ? "" : reader.GetString(4), Abteilung = reader.IsDBNull(5) ? "" : reader.GetString(5), MussPasswortAendern = reader.GetInt32(6) == 1, LetzterLogin = reader.IsDBNull(7) ? DateTime.MinValue : DateTime.Parse(reader.GetString(7)), VorletzterLogin = reader.IsDBNull(8) ? DateTime.MinValue : DateTime.Parse(reader.GetString(8)), OriginalUsername = reader.GetString(1) }); } } catch (SqliteException ex) when (ex.SqliteErrorCode == 5) { Console.WriteLine("❌ Datenbank ist gesperrt. Bitte schließen Sie andere Programme, die auf die Datenbank zugreifen."); throw new InvalidOperationException("Die Datenbank ist derzeit gesperrt – bitte schließen Sie andere Programme (z.B. DB Browser) und starten Sie die Anwendung neu."); } return benutzerListe; } /// /// Aktualisiert einen vorhandenen Benutzer in der Datenbank. /// public void UpdateBenutzer(User benutzer) { using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = @" UPDATE Benutzer SET Username = $NewUsername, Password = $Password, Role = $Role, Mitarbeitennummer = $Mitarbeiternummer, Abteilung = $Abteilung, MussPasswortAendern = $MussPasswortAendern WHERE Username = $OriginalUsername; "; cmd.Parameters.AddWithValue("$NewUsername", benutzer.Username); cmd.Parameters.AddWithValue("$Password", benutzer.Password); cmd.Parameters.AddWithValue("$Role", benutzer.Role); cmd.Parameters.AddWithValue("$Mitarbeiternummer", benutzer.Mitarbeiternummer ?? ""); cmd.Parameters.AddWithValue("$Abteilung", benutzer.Abteilung ?? ""); cmd.Parameters.AddWithValue("$MussPasswortAendern", benutzer.MussPasswortAendern ? 1 : 0); cmd.Parameters.AddWithValue("$OriginalUsername", benutzer.OriginalUsername); int rowsAffected = cmd.ExecuteNonQuery(); Console.WriteLine($"✏ Benutzer aktualisiert: {benutzer.Username} (Rows affected: {rowsAffected})"); } /// /// Löscht einen Benutzer anhand seines Benutzernamens. /// public void LoescheBenutzer(string username) { using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = "DELETE FROM Benutzer WHERE Username = $Username;"; cmd.Parameters.AddWithValue("$Username", username); int rowsAffected = cmd.ExecuteNonQuery(); Console.WriteLine($"❌ Benutzer gelöscht: {username} (Rows affected: {rowsAffected})"); } /// /// Gibt eine Liste aller Benutzernamen mit Rolle 'Mitarbeiter' zurück. /// 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; } /// /// Speichert einen neuen Zeiteintrag in der Datenbank. /// /// /// Speichert einen neuen Zeiteintrag in der Datenbank. /// /// Das zu speichernde Zeiteintrag-Objekt. public void SpeichereEintrag(Zeiteintrag eintrag) { using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); // SQL-Befehl mit zusätzlicher Spalte „Projektleiter“ var cmd = connection.CreateCommand(); cmd.CommandText = @" INSERT INTO Zeiteintraege (Mitarbeiter, Startzeit, Endzeit, Projekt, Kommentar, Erledigt, MitarbeiterKommentar, LetzteBearbeitung, Projektleiter) VALUES ($Mitarbeiter, $Startzeit, $Endzeit, $Projekt, $Kommentar, $Erledigt, $MitarbeiterKommentar, $LetzteBearbeitung, $Projektleiter);"; // Parameter an das SQL-Kommando binden cmd.Parameters.AddWithValue("$Mitarbeiter", eintrag.Mitarbeiter); cmd.Parameters.AddWithValue("$Startzeit", eintrag.Startzeit.ToString("o")); // ISO-8601-Format 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.Parameters.AddWithValue("$LetzteBearbeitung", DateTime.Now.ToString("o")); cmd.Parameters.AddWithValue("$Projektleiter", eintrag.Projektleiter ?? ""); // Ausführung des SQL-Befehls cmd.ExecuteNonQuery(); Console.WriteLine($"✅ Zeiteintrag für {eintrag.Mitarbeiter} gespeichert."); } /// /// Lädt alle Zeiteinträge aus der Datenbank. /// public async Task> LadeAlleEintraegeAsync() { var eintraege = new List(); using var connection = new SqliteConnection($"Data Source={_dbPath}"); await connection.OpenAsync(); var command = connection.CreateCommand(); command.CommandText = "SELECT * FROM Zeiteintraege"; using var reader = await command.ExecuteReaderAsync(); while (await reader.ReadAsync()) { eintraege.Add(new Zeiteintrag { Id = reader.GetInt32(0), 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 = reader.GetInt32(6) == 1, MitarbeiterKommentar = reader.GetString(7), LetzteBearbeitung = DateTime.Parse(reader.GetString(8)), Projektleiter = reader.IsDBNull(9) ? "" : reader.GetString(9) }); } return eintraege; } /// /// Lädt alle vorhandenen Zeiteinträge aus der Datenbank. /// Wird z. B. von Admins oder Projektleitern verwendet, um eine Gesamtübersicht /// aller Projekte und Aufgaben zu erhalten. /// 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()) { var eintrag = new Zeiteintrag { Id = reader.GetInt32(0), 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 = reader.GetBoolean(6), MitarbeiterKommentar = reader.GetString(7), LetzteBearbeitung = reader.IsDBNull(8) ? DateTime.MinValue : DateTime.Parse(reader.GetString(8)), Projektleiter = reader.IsDBNull(9) ? "" : reader.GetString(9) }; eintraege.Add(eintrag); } return eintraege; } /// /// Aktualisiert ein bestehendes Projekt in der Datenbank anhand der ID. /// /// Das Projekt, das aktualisiert werden soll. public void UpdateProjekt(Zeiteintrag projekt) { using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = @" UPDATE Zeiteintraege SET Projekt = $Projekt, Kommentar = $Kommentar, Startzeit = $Startzeit, Endzeit = $Endzeit, Mitarbeiter = $Mitarbeiter, Erledigt = $Erledigt, LetzteBearbeitung = $LetzteBearbeitung WHERE Id = $Id;"; cmd.Parameters.AddWithValue("$Projekt", projekt.Projekt); cmd.Parameters.AddWithValue("$Kommentar", projekt.Kommentar ?? ""); cmd.Parameters.AddWithValue("$Startzeit", projekt.Startzeit.ToString("o")); cmd.Parameters.AddWithValue("$Endzeit", projekt.Endzeit.ToString("o")); cmd.Parameters.AddWithValue("$Mitarbeiter", projekt.Mitarbeiter); cmd.Parameters.AddWithValue("$Erledigt", projekt.Erledigt ? 1 : 0); cmd.Parameters.AddWithValue("$Id", projekt.Id); cmd.Parameters.AddWithValue("$LetzteBearbeitung", DateTime.Now.ToString("o")); int rowsAffected = cmd.ExecuteNonQuery(); Console.WriteLine($"✏ Projekt aktualisiert (Id={projekt.Id}, Rows affected: {rowsAffected})"); } /// /// Löscht ein Projekt anhand seiner ID aus der Datenbank. /// /// Die ID des zu löschenden Projekts. public void LoescheProjekt(int id) { using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = "DELETE FROM Zeiteintraege WHERE Id = $Id;"; cmd.Parameters.AddWithValue("$Id", id); int rows = cmd.ExecuteNonQuery(); Console.WriteLine($"❌ Projekt gelöscht (Id: {id}, Rows: {rows})"); } /// /// Aktualisiert nur den Status "Erledigt" eines Projekts. /// /// ID des Projekts. /// Neuer Status (true/false). public void UpdateProjektStatus(int id, bool erledigt) { using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = @" UPDATE Zeiteintraege SET Erledigt = $Erledigt WHERE Id = $Id; "; cmd.Parameters.AddWithValue("$Erledigt", erledigt ? 1 : 0); cmd.Parameters.AddWithValue("$Id", id); int rowsAffected = cmd.ExecuteNonQuery(); Console.WriteLine( $"✅ Projektstatus aktualisiert (Id={id}, Erledigt={erledigt}, Rows affected: {rowsAffected})"); } /// /// Lädt alle Projekte, die als erledigt markiert sind. /// /// Liste abgeschlossener Zeiteinträge. public List LadeAbgeschlosseneProjekte() { var abgeschlossene = new List(); using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = "SELECT * FROM Zeiteintraege WHERE Erledigt = 1;"; using var reader = cmd.ExecuteReader(); while (reader.Read()) { abgeschlossene.Add(new Zeiteintrag { Id = reader.GetInt32(0), 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 abgeschlossene; } /// /// Lädt die letzten Projekte basierend auf der ID (absteigend sortiert). /// /// Anzahl der letzten Projekte. /// Liste der letzten Zeiteinträge. public List LadeLetzteProjekte(int anzahl = 3) { var projekte = new List(); using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = @" SELECT * FROM Zeiteintraege ORDER BY Id DESC LIMIT $Anzahl; "; cmd.Parameters.AddWithValue("$Anzahl", anzahl); using var reader = cmd.ExecuteReader(); while (reader.Read()) { projekte.Add(new Zeiteintrag { Id = reader.GetInt32(0), 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 projekte; } /// /// Lädt alle noch nicht erledigten Projekte (Zeiteinträge) aus der Datenbank. /// /// Liste offener Zeiteinträge public List LadeOffeneProjekte() { var offene = new List(); using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = "SELECT * FROM Zeiteintraege WHERE Erledigt = 0;"; using var reader = cmd.ExecuteReader(); while (reader.Read()) { offene.Add(new Zeiteintrag { Id = reader.GetInt32(0), 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), LetzteBearbeitung = reader.IsDBNull(8) ? DateTime.MinValue : DateTime.Parse(reader.GetString(8)), Projektleiter = reader.IsDBNull(9) ? "" : reader.GetString(9) // << NEU }); } return offene; } /// /// Setzt das Passwort eines Benutzers zurück (auf 'changeme'). /// Das Passwort wird automatisch gehasht. /// public void ResetBenutzerPasswort(string username) { using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); // Neues Standardpasswort hashen var hashedDefault = PasswordHasher.HashPassword("changeme"); var cmd = connection.CreateCommand(); cmd.CommandText = @" UPDATE Benutzer SET Password = $Password, MussPasswortAendern = 1 WHERE Username = $Username; "; cmd.Parameters.AddWithValue("$Password", hashedDefault); cmd.Parameters.AddWithValue("$Username", username); int rowsAffected = cmd.ExecuteNonQuery(); Console.WriteLine($"🔒 Passwort für Benutzer '{username}' zurückgesetzt (Rows affected: {rowsAffected})"); } /// /// Lädt alle Zeiteinträge eines bestimmten Mitarbeiters aus der Datenbank. /// /// Name des Mitarbeiters /// Liste der zugehörigen Zeiteinträge public async Task> GetEintraegeFuerMitarbeiterAsync(string name) { var eintraege = new List(); using var connection = new SqliteConnection($"Data Source={_dbPath}"); await connection.OpenAsync(); var cmd = connection.CreateCommand(); cmd.CommandText = @" SELECT Id, Mitarbeiter, Startzeit, Endzeit, Projekt, Kommentar, Erledigt, MitarbeiterKommentar, LetzteBearbeitung, Projektleiter FROM Zeiteintraege WHERE Mitarbeiter = $Name;"; cmd.Parameters.AddWithValue("$Name", name); using var reader = await cmd.ExecuteReaderAsync(); while (await reader.ReadAsync()) { eintraege.Add(new Zeiteintrag { Id = reader.GetInt32(0), Mitarbeiter = reader.GetString(1), Startzeit = reader.GetDateTime(2), Endzeit = reader.GetDateTime(3), Projekt = reader.GetString(4), Kommentar = reader.GetString(5), Erledigt = reader.GetBoolean(6), MitarbeiterKommentar = reader.GetString(7), LetzteBearbeitung = reader.IsDBNull(8) ? DateTime.MinValue : reader.GetDateTime(8), Projektleiter = reader.IsDBNull(9) ? "" : reader.GetString(9) // << NEU }); } return eintraege; } /// /// Überprüft, ob die Spalte 'VorletzterLogin' in der Tabelle 'Benutzer' vorhanden ist. /// Falls nicht, wird sie hinzugefügt. /// public async Task StelleDatenbankstrukturSicherAsync() { using var connection = new SqliteConnection($"Data Source={_dbPath}"); await connection.OpenAsync(); // ========= 🧪 Spalte 'VorletzterLogin' in 'Benutzer' prüfen ========= var checkBenutzerCmd = connection.CreateCommand(); checkBenutzerCmd.CommandText = "PRAGMA table_info(Benutzer);"; var readerBenutzer = await checkBenutzerCmd.ExecuteReaderAsync(); bool vorletzterLoginExistiert = false; while (await readerBenutzer.ReadAsync()) { if (readerBenutzer.GetString(1).Equals("VorletzterLogin", StringComparison.OrdinalIgnoreCase)) { vorletzterLoginExistiert = true; break; } } await readerBenutzer.DisposeAsync(); if (!vorletzterLoginExistiert) { var alterBenutzerCmd = connection.CreateCommand(); alterBenutzerCmd.CommandText = "ALTER TABLE Benutzer ADD COLUMN VorletzterLogin TEXT;"; await alterBenutzerCmd.ExecuteNonQueryAsync(); Console.WriteLine("🛠 Spalte 'VorletzterLogin' wurde zur Tabelle 'Benutzer' hinzugefügt."); } else { Console.WriteLine("✅ Spalte 'VorletzterLogin' ist bereits vorhanden."); } // ========= 🧪 Spalte 'Projektleiter' in 'Zeiteintraege' prüfen ========= var checkProjektleiterCmd = connection.CreateCommand(); checkProjektleiterCmd.CommandText = "PRAGMA table_info(Zeiteintraege);"; var readerProjektleiter = await checkProjektleiterCmd.ExecuteReaderAsync(); bool projektleiterExistiert = false; while (await readerProjektleiter.ReadAsync()) { if (readerProjektleiter.GetString(1).Equals("Projektleiter", StringComparison.OrdinalIgnoreCase)) { projektleiterExistiert = true; break; } } await readerProjektleiter.DisposeAsync(); if (!projektleiterExistiert) { var alterZeiteintraegeCmd = connection.CreateCommand(); alterZeiteintraegeCmd.CommandText = "ALTER TABLE Zeiteintraege ADD COLUMN Projektleiter TEXT;"; await alterZeiteintraegeCmd.ExecuteNonQueryAsync(); Console.WriteLine("🛠 Spalte 'Projektleiter' wurde zur Tabelle 'Zeiteintraege' hinzugefügt."); } else { Console.WriteLine("✅ Spalte 'Projektleiter' ist bereits vorhanden."); } // ========= 🛠 Neue Tabelle 'ProjektMitarbeiter' erstellen ========= var createProjektMitarbeiterCmd = connection.CreateCommand(); createProjektMitarbeiterCmd.CommandText = @" CREATE TABLE IF NOT EXISTS ProjektMitarbeiter ( ProjektId INTEGER NOT NULL, Mitarbeiter TEXT NOT NULL, PRIMARY KEY (ProjektId, Mitarbeiter), FOREIGN KEY (ProjektId) REFERENCES Zeiteintraege(Id) ); "; await createProjektMitarbeiterCmd.ExecuteNonQueryAsync(); Console.WriteLine("✅ Tabelle 'ProjektMitarbeiter' wurde (falls nötig) erstellt."); } /// /// Aktualisiert die Login-Zeitpunkte des Benutzers in der Datenbank. /// /// Der Benutzer, dessen Loginzeiten aktualisiert werden sollen public void UpdateLoginZeiten(User user) { using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = @" UPDATE Benutzer SET LetzterLogin = $LetzterLogin, VorletzterLogin = $VorletzterLogin WHERE Username = $Username; "; // Setzt die Parameter für das SQL-Statement cmd.Parameters.AddWithValue("$LetzterLogin", user.LetzterLogin.ToString("o")); // ISO 8601-Format cmd.Parameters.AddWithValue("$VorletzterLogin", user.VorletzterLogin.ToString("o")); // ebenfalls ISO cmd.Parameters.AddWithValue("$Username", user.Username); // Nutzername als Schlüssel cmd.ExecuteNonQuery(); // Führt das Update aus } /// /// Aktualisiert den Erledigt-Status, Kommentar und das Bearbeitungsdatum eines Zeiteintrags. /// /// ID des Zeiteintrags /// Neuer Status: erledigt oder nicht /// Neuer Kommentar des Mitarbeiters public async Task UpdateStatusUndKommentarAsync(int id, bool erledigt, string mitarbeiterKommentar) { using var connection = new SqliteConnection($"Data Source={_dbPath}"); await connection.OpenAsync(); var cmd = connection.CreateCommand(); cmd.CommandText = @" UPDATE Zeiteintraege SET Erledigt = $Erledigt, MitarbeiterKommentar = $Kommentar, LetzteBearbeitung = $Bearbeitet WHERE Id = $Id; "; cmd.Parameters.AddWithValue("$Erledigt", erledigt ? 1 : 0); cmd.Parameters.AddWithValue("$Kommentar", mitarbeiterKommentar ?? ""); cmd.Parameters.AddWithValue("$Bearbeitet", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); cmd.Parameters.AddWithValue("$Id", id); int rowsAffected = await cmd.ExecuteNonQueryAsync(); Console.WriteLine($"✏ Zeiteintrag (Id={id}) aktualisiert: erledigt={erledigt}, LetzteBearbeitung gesetzt."); } } }