using System; using System.Collections.Generic; using System.IO; using Microsoft.Data.Sqlite; using ChronoFlow.Model; using ChronoFlow.Security; namespace ChronoFlow.Persistence { public interface IZeiterfassungsRepository { Task> GetEintraegeFuerMitarbeiterAsync(string mitarbeiterName); Task UpdateStatusUndKommentarAsync(int id, bool erledigt, string mitarbeiterKommentar); } public class SqliteZeiterfassungsService : IZeiterfassungsRepository { private readonly string _dbPath = "chrono_data.sb"; public SqliteZeiterfassungsService() { if (!File.Exists(_dbPath)) ErstelleDatenbank(); // IMMER prüfen, auch nach neuem Erstellen PrüfeUndErweitereDatenbank(); } 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) { 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() { 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"); } private void AddColumnIfMissing(SqliteConnection connection, string tableName, string columnName, string columnType) { 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() { 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(); using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); var cmd = connection.CreateCommand(); cmd.CommandText = "SELECT Id, Username, Password, Role, Mitarbeitennummer, Abteilung, MussPasswortAendern FROM Benutzer;"; using var reader = cmd.ExecuteReader(); while (reader.Read()) { 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, OriginalUsername = reader.GetString(1) }); } return benutzerListe; } 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})"); } 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})"); } 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 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(); Console.WriteLine($"✅ Zeiteintrag für {eintrag.Mitarbeiter} gespeichert."); } 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 { 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 eintraege; } 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 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); int rowsAffected = cmd.ExecuteNonQuery(); Console.WriteLine($"✏ Projekt aktualisiert (Id={projekt.Id}, Rows affected: {rowsAffected})"); } 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})"); } 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})"); } 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; } 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; } 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) }); } return offene; } public void ResetBenutzerPasswort(string username) { using var connection = new SqliteConnection($"Data Source={_dbPath}"); connection.Open(); 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})"); } public async Task> GetEintraegeFuerMitarbeiterAsync(string mitarbeiterName) { var eintraege = new List(); using var connection = new SqliteConnection($"Data Source={_dbPath}"); await connection.OpenAsync(); var cmd = connection.CreateCommand(); cmd.CommandText = @" SELECT * FROM Zeiteintraege WHERE Mitarbeiter = $Mitarbeiter; "; cmd.Parameters.AddWithValue("$Mitarbeiter", mitarbeiterName); using var reader = await cmd.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 = Convert.ToInt32(reader["Erledigt"]) == 1, MitarbeiterKommentar = reader.GetString(7) }); } return eintraege; } 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 WHERE Id = $Id; "; cmd.Parameters.AddWithValue("$Erledigt", erledigt ? 1 : 0); cmd.Parameters.AddWithValue("$Kommentar", mitarbeiterKommentar ?? ""); cmd.Parameters.AddWithValue("$Id", id); int rowsAffected = await cmd.ExecuteNonQueryAsync(); Console.WriteLine($"✏ Zeiteintrag (Id={id}) aktualisiert: erledigt={erledigt}, kommentar gesetzt."); } } }