using Microsoft.AspNetCore.Components.Authorization; using Raven.Client.Documents; using ZahlenAnalyse.Web.Models; using ExcelDataReader; using System.Data; namespace ZahlenAnalyse.Web.Services; public class WorkspaceService { private readonly IDocumentStore _store; private readonly AuthenticationStateProvider _authStateProvider; // Den AuthStateProvider injizieren public WorkspaceService(IDocumentStore store, AuthenticationStateProvider authStateProvider) { _store = store; _authStateProvider = authStateProvider; } private async Task GetUserIdAsync() { var authState = await _authStateProvider.GetAuthenticationStateAsync(); var user = authState.User; var userid = user.FindFirst(c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value ?? user.FindFirst("sub")?.Value ?? string.Empty; return userid; } // --- Die Magie passiert hier --- private async Task EnrichWithAuditDataAsync(object entity) { // Wenn das Objekt weder IOwnedEntity noch IAuditableEntity ist, können wir abbrechen if (entity is not IOwnedEntity and not IAuditableEntity) return; var authState = await _authStateProvider.GetAuthenticationStateAsync(); var user = authState.User; if (entity is IOwnedEntity ownedEntity) { var userid = await GetUserIdAsync(); // Setzt bei JEDEM Speichern sicherheitshalber den aktuellen User als Owner ownedEntity.OwnerId = userid; } if (entity is IAuditableEntity auditableEntity) { // WICHTIG: Wir setzen CreatedBy und CreatedAt NUR, wenn sie noch leer sind. // Sonst würden wir bei einem Update (z.B. Namensänderung des Workspaces) // das ursprüngliche Erstellungsdatum und den ursprünglichen Ersteller überschreiben! if (string.IsNullOrWhiteSpace(auditableEntity.CreatedBy)) { auditableEntity.CreatedBy = user.FindFirst("name")?.Value ?? user.Identity?.Name ?? "Unbekannt"; auditableEntity.CreatedAt = DateTime.UtcNow; } } } public async Task SaveWorkspaceAsync(Workspace workspace) { // 1. Audit-Daten automatisch befüllen await EnrichWithAuditDataAsync(workspace); // 2. Speichern using var session = _store.OpenAsyncSession(); await session.StoreAsync(workspace); await session.SaveChangesAsync(); } public async Task> GetWorkspacesForUserAsync() { var authState = await _authStateProvider.GetAuthenticationStateAsync(); var ownerId = await GetUserIdAsync(); using var session = _store.OpenAsyncSession(); return await session.Query() .Where(w => w.OwnerId == ownerId) .ToListAsync(); } public async Task GetWorkspaceAsync(string id) { var authState = await _authStateProvider.GetAuthenticationStateAsync(); var currentUserId = await GetUserIdAsync(); using var session = _store.OpenAsyncSession(); var workspace = await session.LoadAsync(id); if (workspace != null && workspace.OwnerId != currentUserId) { return null; } return workspace; } public async Task SaveFaktAsync(AnalysisFakt fakt) { // Unsere elegante Hilfsmethode von vorhin füllt OwnerId, CreatedBy und CreatedAt! await EnrichWithAuditDataAsync(fakt); using var session = _store.OpenAsyncSession(); await session.StoreAsync(fakt); await session.SaveChangesAsync(); } public async Task> GetFaktenForWorkspaceAsync(string workspaceId) { using var session = _store.OpenAsyncSession(); var ownerId = await GetUserIdAsync(); return await session.Query() .Where(f => f.WorkspaceId == workspaceId && f.OwnerId == ownerId) .OrderByDescending(f => f.Date) .ToListAsync(); } public async Task ImportFromExcelAsync(string workspaceId, Stream fileStream) { // Encoding für deutsche Excel-Dateien System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); using var reader = ExcelReaderFactory.CreateReader(fileStream); var result = reader.AsDataSet(new ExcelDataSetConfiguration() { ConfigureDataTable = (_) => new ExcelDataTableConfiguration() { UseHeaderRow = true } }); var dataTable = result.Tables[0]; using var session = _store.OpenAsyncSession(); foreach (DataRow row in dataTable.Rows) { var fakt = new AnalysisFakt { WorkspaceId = workspaceId, Date = Convert.ToDateTime(row["Datum"]), Amount = Convert.ToDecimal(row["Betrag"]), // Hier mappen wir dynamisch die Dimensionen Dimensions = new Dictionary() }; // Wir gehen davon aus, dass deine Excel-Spaltennamen // den Dimensions-Namen entsprechen foreach (var col in dataTable.Columns.Cast().Skip(2)) // Datum/Betrag überspringen { fakt.Dimensions[col.ColumnName] = row[col.ColumnName].ToString() ?? ""; } await EnrichWithAuditDataAsync(fakt); await session.StoreAsync(fakt); } await session.SaveChangesAsync(); } }