ChronoFlow/ChronoFlow.Persistence/SqliteZeiterfassungsService.cs
2025-06-28 14:27:18 +02:00

790 lines
32 KiB
C#
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<List<Zeiteintrag>> GetEintraegeFuerMitarbeiterAsync(string mitarbeiterName);
Task UpdateStatusUndKommentarAsync(int id, bool erledigt, string mitarbeiterKommentar);
}
/// <summary>
/// Implementierung des SQLite-Datenbankzugriffs für Benutzer und Zeiteinträge.
/// </summary>
public class SqliteZeiterfassungsService : IZeiterfassungsRepository
{
// Pfad zur SQLite-Datenbankdatei
private readonly string _dbPath = "chrono_data.sb";
/// <summary>
/// Konstruktor: Erstellt Datenbank falls nicht vorhanden und stellt die Struktur sicher.
/// </summary>
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();
}
/// <summary>
/// Erstellt die Basis-Datenbankstruktur, falls Datei noch nicht existiert.
/// </summary>
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<User> LadeAlleBenutzer()
{
var benutzerListe = new List<User>();
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;
}
/// <summary>
/// Aktualisiert einen vorhandenen Benutzer in der Datenbank.
/// </summary>
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})");
}
/// <summary>
/// Löscht einen Benutzer anhand seines Benutzernamens.
/// </summary>
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})");
}
/// <summary>
/// Gibt eine Liste aller Benutzernamen mit Rolle 'Mitarbeiter' zurück.
/// </summary>
public List<string> LadeAlleMitarbeiterNamen()
{
var namen = new List<string>();
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;
}
/// <summary>
/// Speichert einen neuen Zeiteintrag in der Datenbank.
/// </summary>
/// <summary>
/// Speichert einen neuen Zeiteintrag in der Datenbank.
/// </summary>
/// <param name="eintrag">Das zu speichernde Zeiteintrag-Objekt.</param>
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.");
}
/// <summary>
/// Lädt alle Zeiteinträge aus der Datenbank.
/// </summary>
public async Task<List<Zeiteintrag>> LadeAlleEintraegeAsync()
{
var eintraege = new List<Zeiteintrag>();
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;
}
/// <summary>
/// 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.
/// </summary>
public List<Zeiteintrag> LadeAlleZeiteintraege()
{
var eintraege = new List<Zeiteintrag>();
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;
}
/// <summary>
/// Aktualisiert ein bestehendes Projekt in der Datenbank anhand der ID.
/// </summary>
/// <param name="projekt">Das Projekt, das aktualisiert werden soll.</param>
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})");
}
/// <summary>
/// Löscht ein Projekt anhand seiner ID aus der Datenbank.
/// </summary>
/// <param name="id">Die ID des zu löschenden Projekts.</param>
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})");
}
/// <summary>
/// Aktualisiert nur den Status "Erledigt" eines Projekts.
/// </summary>
/// <param name="id">ID des Projekts.</param>
/// <param name="erledigt">Neuer Status (true/false).</param>
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})");
}
/// <summary>
/// Lädt alle Projekte, die als erledigt markiert sind.
/// </summary>
/// <returns>Liste abgeschlossener Zeiteinträge.</returns>
public List<Zeiteintrag> LadeAbgeschlosseneProjekte()
{
var abgeschlossene = new List<Zeiteintrag>();
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;
}
/// <summary>
/// Lädt die letzten Projekte basierend auf der ID (absteigend sortiert).
/// </summary>
/// <param name="anzahl">Anzahl der letzten Projekte.</param>
/// <returns>Liste der letzten Zeiteinträge.</returns>
public List<Zeiteintrag> LadeLetzteProjekte(int anzahl = 3)
{
var projekte = new List<Zeiteintrag>();
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;
}
/// <summary>
/// Lädt alle noch nicht erledigten Projekte (Zeiteinträge) aus der Datenbank.
/// </summary>
/// <returns>Liste offener Zeiteinträge</returns>
public List<Zeiteintrag> LadeOffeneProjekte()
{
var offene = new List<Zeiteintrag>();
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;
}
/// <summary>
/// Setzt das Passwort eines Benutzers zurück (auf 'changeme').
/// Das Passwort wird automatisch gehasht.
/// </summary>
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})");
}
/// <summary>
/// Lädt alle Zeiteinträge eines bestimmten Mitarbeiters aus der Datenbank.
/// </summary>
/// <param name="name">Name des Mitarbeiters</param>
/// <returns>Liste der zugehörigen Zeiteinträge</returns>
public async Task<List<Zeiteintrag>> GetEintraegeFuerMitarbeiterAsync(string name)
{
var eintraege = new List<Zeiteintrag>();
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;
}
/// <summary>
/// Überprüft, ob die Spalte 'VorletzterLogin' in der Tabelle 'Benutzer' vorhanden ist.
/// Falls nicht, wird sie hinzugefügt.
/// </summary>
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.");
}
/// <summary>
/// Aktualisiert die Login-Zeitpunkte des Benutzers in der Datenbank.
/// </summary>
/// <param name="user">Der Benutzer, dessen Loginzeiten aktualisiert werden sollen</param>
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
}
/// <summary>
/// Aktualisiert den Erledigt-Status, Kommentar und das Bearbeitungsdatum eines Zeiteintrags.
/// </summary>
/// <param name="id">ID des Zeiteintrags</param>
/// <param name="erledigt">Neuer Status: erledigt oder nicht</param>
/// <param name="mitarbeiterKommentar">Neuer Kommentar des Mitarbeiters</param>
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.");
}
}
}