790 lines
32 KiB
C#
790 lines
32 KiB
C#
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.");
|
||
}
|
||
}
|
||
} |