diff --git a/Client/Components/ReportComponent.razor b/Client/Components/ReportComponent.razor new file mode 100644 index 0000000..1d754a7 --- /dev/null +++ b/Client/Components/ReportComponent.razor @@ -0,0 +1,95 @@ +@inherits LocalizableComponent +@using Interfaces +@implements Interfaces.IReportUI +@inject IReportingHandler ReportingHandler + + + +@if (_showReportModal) +{ + +} + +@code { + public Type ReportType => typeof(ReportComponent); + + [Parameter] + public IReportable ReportableEntity { get; set; } + + private bool _showReportModal = false; + private string _reportReason = ""; + + private Task ShowReportModal() + { + _reportReason = ""; + _showReportModal = true; + return Task.CompletedTask; + } + + private void CloseReportModal() + { + _showReportModal = false; + } + public Dictionary ConstructParameterList(IReportable reportableEntity, object RenderModeBoundary) { + Dictionary _parameters = new Dictionary(); + + _parameters["ReportableEntity"] = reportableEntity; + _parameters["RenderModeBoundary"] = RenderModeBoundary; + + return _parameters; + } + private async Task ReportEntry() + { + // Basic null checks to avoid runtime NREs + if (ReportingHandler == null) + { + Console.WriteLine("ReportingHandler is not available (null). Ensure it is registered and injected."); + CloseReportModal(); + return; + } + + if (ReportableEntity == null) + { + Console.WriteLine("ReportableEntity is null. Cannot report."); + CloseReportModal(); + return; + } + + try + { + // If the handler exposes an async API use it instead. We run the synchronous call off the UI thread to avoid blocking. + await Task.Run(() => ReportingHandler.Report(ReportableEntity, _reportReason)); + Console.WriteLine($"Eintrag gemeldet mit Grund: {_reportReason}"); + AddModuleMessage($"Eintrag mit Grund {_reportReason} gemeldet.", MessageType.Success); + } + catch (Exception ex) + { + Console.WriteLine($"Reporting failed: {ex.Message}"); + AddModuleMessage($"Eintrag konnte nicht gemeldet werden, bitte melden sie sich direkt beim Absolventenverein: ({ex.StackTrace}).", MessageType.Error); + } + finally + { + CloseReportModal(); + StateHasChanged(); + } + } +} \ No newline at end of file diff --git a/Client/Modules/SZUAbsolventenverein.Module.AdminModules/Edit.razor b/Client/Modules/SZUAbsolventenverein.Module.AdminModules/Edit.razor index b275a06..760750f 100644 --- a/Client/Modules/SZUAbsolventenverein.Module.AdminModules/Edit.razor +++ b/Client/Modules/SZUAbsolventenverein.Module.AdminModules/Edit.razor @@ -1,4 +1,5 @@ @using Oqtane.Modules.Controls +@using SZUAbsolventenverein.Module.AdminModules.Client.Components @using SZUAbsolventenverein.Module.AdminModules.Services @using SZUAbsolventenverein.Module.AdminModules.Models @@ -24,6 +25,8 @@ @Localizer["Cancel"]

+ +

@if (PageState.Action == "Edit") { @@ -54,6 +57,8 @@ private string _modifiedby; private DateTime _modifiedon; + private AdminModules AdminModules; + protected override async Task OnInitializedAsync() { try @@ -70,6 +75,7 @@ _createdon = AdminModules.CreatedOn; _modifiedby = AdminModules.ModifiedBy; _modifiedon = AdminModules.ModifiedOn; + this.AdminModules = AdminModules; } } } diff --git a/Client/Modules/SZUAbsolventenverein.Module.AdminModules/Index.razor b/Client/Modules/SZUAbsolventenverein.Module.AdminModules/Index.razor index 92f39d0..53b21ac 100644 --- a/Client/Modules/SZUAbsolventenverein.Module.AdminModules/Index.razor +++ b/Client/Modules/SZUAbsolventenverein.Module.AdminModules/Index.razor @@ -1,3 +1,4 @@ +@using Interfaces @using SZUAbsolventenverein.Module.AdminModules.Services @using SZUAbsolventenverein.Module.AdminModules.Models @@ -6,6 +7,7 @@ @inject IAdminModulesService AdminModulesService @inject NavigationManager NavigationManager @inject IStringLocalizer Localizer +@inject IReportingHandler ReportingHandler; @if (_AdminModuless == null) { @@ -23,11 +25,13 @@ else       +   @Localizer["Name"] - + + @context.Name @@ -40,7 +44,7 @@ else } @code { - public override string RenderMode => RenderModes.Static; + public override string RenderMode => RenderModes.Interactive; public override List Resources => new List() { @@ -78,4 +82,19 @@ else AddModuleMessage(Localizer["Message.DeleteError"], MessageType.Error); } } + + private async Task Report(AdminModules AdminModules) + { + try + { + ReportingHandler.Report(AdminModules, "Reported by User"); + await logger.LogInformation("AdminModules Reported {AdminModules}", AdminModules); + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Reportign AdminModules {AdminModules} {Error}", AdminModules, ex.Message); + AddModuleMessage(Localizer["Message.DeleteError"], MessageType.Error); + } + } } \ No newline at end of file diff --git a/Client/Modules/SZUAbsolventenverein.Module.ReportSystem/Index.razor b/Client/Modules/SZUAbsolventenverein.Module.ReportSystem/Index.razor index 1b3ca78..bccba5e 100644 --- a/Client/Modules/SZUAbsolventenverein.Module.ReportSystem/Index.razor +++ b/Client/Modules/SZUAbsolventenverein.Module.ReportSystem/Index.razor @@ -7,8 +7,9 @@ @inject NavigationManager NavigationManager @inject IReportSystemReportingService ReportingService @inject IStringLocalizer Localizer +@inject IModuleService ModuleService -@if (reportings == null) +@if (_reportings == null) {

Loading...

} @@ -16,19 +17,24 @@ else {

- @if (reportings.Count != 0) + @if (_reportings.Count != 0) { - +
    -   + @Localizer["Submitter"] + @Localizer["Note"] @Localizer["Name"]
- + @context.CreatedBy + @context.CreatedOn + @context.ModuleId + @context.ReportingID + @context.Note @context.Reason
@@ -39,7 +45,6 @@ else } } - @code { public override string RenderMode => RenderModes.Interactive; @@ -49,13 +54,28 @@ else new Script("_content/SZUAbsolventenverein.Module.ReportSystem/Module.js") }; - private List reportings = new List(); - + private List _reportings = new List(); + private Dictionary _modules = new Dictionary(); + protected override async Task OnInitializedAsync() { try { - reportings = await ReportingService.GetReportsAsync(ModuleState.ModuleId); + _reportings = await ReportingService.GetReportsAsync(ModuleState.ModuleId); + foreach (var moduleId in _reportings.Select(r => r.ModuleId).Distinct()) + { + Console.WriteLine(moduleId); + try + { + _modules.Add(moduleId, await ModuleService.GetModuleAsync(moduleId)); + await logger.LogDebug(LogFunction.Create, "Module found {ModuleId} while loading Modules for Reportings.", moduleId); + } + catch (Exception ex) + { + _modules.Add(moduleId, new Module {Title = $"Module not found {ex.Message}"}); + await logger.LogDebug("Module not found {ModuleId} while loading Modules for Reportings. {error}", moduleId, ex); + } + } } catch (Exception ex) { @@ -68,7 +88,7 @@ else try { await ReportingService.DeleteReportingAsync(reporting.ReportingID, ModuleState.ModuleId); - reportings.Remove(reporting); + _reportings.Remove(reporting); StateHasChanged(); } catch (Exception ex) diff --git a/Client/SZUAbsolventenverein.Module.AdminModules.Client.csproj b/Client/SZUAbsolventenverein.Module.AdminModules.Client.csproj index b44f0ef..9eb7920 100644 --- a/Client/SZUAbsolventenverein.Module.AdminModules.Client.csproj +++ b/Client/SZUAbsolventenverein.Module.AdminModules.Client.csproj @@ -13,6 +13,7 @@ + diff --git a/Client/Services/ReportSystemReportingService.cs b/Client/Services/ReportSystemReportingService.cs index 340fc5a..2fcd279 100644 --- a/Client/Services/ReportSystemReportingService.cs +++ b/Client/Services/ReportSystemReportingService.cs @@ -19,7 +19,7 @@ namespace SZUAbsolventenverein.Module.ReportSystem.Services public void Report(IReportable reportable, string note) { CreateReportAsync(new Reporting - { ModuleId = reportable.ModuleID, EntityId = reportable.EntityID, Note = note, Reason = "Default Reason" }); + { ModuleId = reportable.ModuleID, EntityId = reportable.EntityID, Note = note, UserName = reportable.UserName, Reason = "Default Reason" }); } public Task CreateReportAsync(Reporting reporting) diff --git a/Client/Startup/ClientStartup.cs b/Client/Startup/ClientStartup.cs index 0b0e928..fcc6d06 100644 --- a/Client/Startup/ClientStartup.cs +++ b/Client/Startup/ClientStartup.cs @@ -1,7 +1,9 @@ +using System; using Microsoft.Extensions.DependencyInjection; using System.Linq; using Interfaces; using Oqtane.Services; +using SZUAbsolventenverein.Module.AdminModules.Client.Components; using SZUAbsolventenverein.Module.AdminModules.Services; using SZUAbsolventenverein.Module.ReportSystem.Services; @@ -20,10 +22,16 @@ namespace SZUAbsolventenverein.Module.AdminModules.Startup { services.AddScoped(); } + if (!services.Any(s => s.ServiceType == typeof(IReportSystemReportingService))) { services.AddScoped(); } + + if (!services.Any(s => s.ServiceType == typeof(IReportUI))) + { + services.AddScoped(); + } } } } diff --git a/SZUAbsolventenverein.Module.AdminModules.sln.DotSettings.user b/SZUAbsolventenverein.Module.AdminModules.sln.DotSettings.user index 69b84c8..da6fa63 100644 --- a/SZUAbsolventenverein.Module.AdminModules.sln.DotSettings.user +++ b/SZUAbsolventenverein.Module.AdminModules.sln.DotSettings.user @@ -1,6 +1,7 @@  True True + ForceIncluded ForceIncluded <AssemblyExplorer> <Assembly Path="/home/kocoder/alumnihub_10.0_amd64/SZUAbsolventenverein/Interfaces/bin/Debug/net10.0/Interfaces.dll" /> diff --git a/Server/Migrations/ReportSystem/01000001_AddUserName.cs b/Server/Migrations/ReportSystem/01000001_AddUserName.cs new file mode 100644 index 0000000..2950f63 --- /dev/null +++ b/Server/Migrations/ReportSystem/01000001_AddUserName.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations; +using SZUAbsolventenverein.Module.AdminModules.Migrations.EntityBuilders; +using SZUAbsolventenverein.Module.AdminModules.Repository; + +namespace SZUAbsolventenverein.Module.ReportSystem.Migrations +{ + [DbContext(typeof(ReportingContext))] + [Migration("SZUAbsolventenverein.Module.ReportSystem.01.00.00.01")] + public class AddUserName : MultiDatabaseMigration + { + public AddUserName(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + var entityBuilder = new ReportingEntityBuilder(migrationBuilder, ActiveDatabase); + entityBuilder.AddStringColumn("UserName", 256, false, false, ""); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + var entityBuilder = new ReportingEntityBuilder(migrationBuilder, ActiveDatabase); + entityBuilder.DropColumn("UserName"); + } + } +} \ No newline at end of file diff --git a/Server/Repository/AdminModulesContext.cs b/Server/Repository/AdminModulesContext.cs deleted file mode 100644 index 6eefc39..0000000 --- a/Server/Repository/AdminModulesContext.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.AspNetCore.Http; -using Oqtane.Modules; -using Oqtane.Repository; -using Oqtane.Infrastructure; -using Oqtane.Repository.Databases.Interfaces; - -namespace SZUAbsolventenverein.Module.AdminModules.Repository -{ - public class AdminModulesContext : DBContextBase, ITransientService, IMultiDatabase - { - public virtual DbSet AdminModules { get; set; } - - public AdminModulesContext(IDBContextDependencies DBContextDependencies) : base(DBContextDependencies) - { - // ContextBase handles multi-tenant database connections - } - - protected override void OnModelCreating(ModelBuilder builder) - { - base.OnModelCreating(builder); - - builder.Entity().ToTable(ActiveDatabase.RewriteName("SZUAbsolventenvereinAdminModules")); - } - } -} diff --git a/Server/Repository/AdminModulesRepository.cs b/Server/Repository/AdminModulesRepository.cs deleted file mode 100644 index 8683383..0000000 --- a/Server/Repository/AdminModulesRepository.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using System.Linq; -using System.Collections.Generic; -using Oqtane.Modules; - -namespace SZUAbsolventenverein.Module.AdminModules.Repository -{ - public interface IAdminModulesRepository - { - IEnumerable GetAdminModuless(int ModuleId); - Models.AdminModules GetAdminModules(int AdminModulesId); - Models.AdminModules GetAdminModules(int AdminModulesId, bool tracking); - Models.AdminModules AddAdminModules(Models.AdminModules AdminModules); - Models.AdminModules UpdateAdminModules(Models.AdminModules AdminModules); - void DeleteAdminModules(int AdminModulesId); - } - - public class AdminModulesRepository : IAdminModulesRepository, ITransientService - { - private readonly IDbContextFactory _factory; - - public AdminModulesRepository(IDbContextFactory factory) - { - _factory = factory; - } - - public IEnumerable GetAdminModuless(int ModuleId) - { - using var db = _factory.CreateDbContext(); - return db.AdminModules.Where(item => item.ModuleId == ModuleId).ToList(); - } - - public Models.AdminModules GetAdminModules(int AdminModulesId) - { - return GetAdminModules(AdminModulesId, true); - } - - public Models.AdminModules GetAdminModules(int AdminModulesId, bool tracking) - { - using var db = _factory.CreateDbContext(); - if (tracking) - { - return db.AdminModules.Find(AdminModulesId); - } - else - { - return db.AdminModules.AsNoTracking().FirstOrDefault(item => item.AdminModulesId == AdminModulesId); - } - } - - public Models.AdminModules AddAdminModules(Models.AdminModules AdminModules) - { - using var db = _factory.CreateDbContext(); - db.AdminModules.Add(AdminModules); - db.SaveChanges(); - return AdminModules; - } - - public Models.AdminModules UpdateAdminModules(Models.AdminModules AdminModules) - { - using var db = _factory.CreateDbContext(); - db.Entry(AdminModules).State = EntityState.Modified; - db.SaveChanges(); - return AdminModules; - } - - public void DeleteAdminModules(int AdminModulesId) - { - using var db = _factory.CreateDbContext(); - Models.AdminModules AdminModules = db.AdminModules.Find(AdminModulesId); - db.AdminModules.Remove(AdminModules); - db.SaveChanges(); - } - } -} diff --git a/Server/Services/ReportSystemReportingService.cs b/Server/Services/ReportSystemReportingService.cs index b733ca0..08466fa 100644 --- a/Server/Services/ReportSystemReportingService.cs +++ b/Server/Services/ReportSystemReportingService.cs @@ -7,42 +7,55 @@ using Microsoft.AspNetCore.Http; using Oqtane.Enums; using Oqtane.Infrastructure; using Oqtane.Models; +using Oqtane.Repository; using Oqtane.Security; using Oqtane.Shared; using SZUAbsolventenverein.Module.ReportSystem.Models; +using SZUAbsolventenverein.Module.ReportSystem.Permissions; using SZUAbsolventenverein.Module.ReportSystem.Repository; namespace SZUAbsolventenverein.Module.ReportSystem.Services { public class ServerReportSystemReportingService : IReportSystemReportingService, IReportingHandler { + private readonly IModuleDefinitionRepository _moduleDefinitionRepository; private readonly IReportingRepository _reportSystemRepository; private readonly IUserPermissions _userPermissions; private readonly ILogManager _logger; private readonly IHttpContextAccessor _accessor; private readonly Alias _alias; + private readonly int _moduleDefinitionId; - public ServerReportSystemReportingService(IReportingRepository reportSystemRepository, IUserPermissions userPermissions, ITenantManager tenantManager, ILogManager logger, IHttpContextAccessor accessor) + public ServerReportSystemReportingService(IModuleDefinitionRepository moduleDefinitionRepository, IReportingRepository reportSystemRepository, IUserPermissions userPermissions, ITenantManager tenantManager, ILogManager logger, IHttpContextAccessor accessor) { + _moduleDefinitionRepository = moduleDefinitionRepository; _reportSystemRepository = reportSystemRepository; _userPermissions = userPermissions; _logger = logger; _accessor = accessor; _alias = tenantManager.GetAlias(); + + ModuleDefinition md = moduleDefinitionRepository.GetModuleDefinitions(_alias.SiteId).ToList().Find(md => md.IsEnabled && md.Name == new ModuleInfo().ModuleDefinition.Name); + if (md == null) + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Reporting Module Not Found {ModuleName}", new ModuleInfo().ModuleDefinition.Name); + } + else + { + _moduleDefinitionId = md.ModuleDefinitionId; + } } public Task CreateReportAsync(Reporting Reporting) { - // true || - Console.WriteLine("HELP"); - if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.ModuleDefinition, 53, PermissionNames.Utilize)) + if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.ModuleDefinition, _moduleDefinitionId, PermissionNames.Utilize)) { - _logger.Log(LogLevel.Information, this, LogFunction.Update, "Reporting Updated {Reporting}", Reporting); + _logger.Log(LogLevel.Information, this, LogFunction.Update, "Reporting created {Reporting}", Reporting); return Task.FromResult(_reportSystemRepository.AddReporting(Reporting)); } else { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Reporting Update Attempt {Reporting}", Reporting); + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Reporting create attempt {Reporting}", Reporting); return null; } } @@ -107,8 +120,11 @@ namespace SZUAbsolventenverein.Module.ReportSystem.Services { // if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.Edit)) { - Reporting reporting = await CreateReportAsync(new Reporting {ModuleId = reportable.ModuleID, EntityId = reportable.EntityID, Note = note, Reason = "Default Reason"}); - _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Reporting recieved {ReportingId}", reporting.ReportingID); + Reporting reporting = await CreateReportAsync(new Reporting {ModuleId = reportable.ModuleID, EntityId = reportable.EntityID, UserName = reportable.UserName, Note = note, Reason = "Default Reason"}); + if (reporting != null) + { + _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Reporting recieved {ReportingId}", reporting.ReportingID); + } } // else { diff --git a/Shared/Models/AdminModules.cs b/Shared/Models/AdminModules.cs index 83500c9..bb8466b 100644 --- a/Shared/Models/AdminModules.cs +++ b/Shared/Models/AdminModules.cs @@ -1,12 +1,13 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Interfaces; using Oqtane.Models; namespace SZUAbsolventenverein.Module.AdminModules.Models { [Table("SZUAbsolventenvereinAdminModules")] - public class AdminModules : IAuditable + public class AdminModules : IAuditable, IReportable { [Key] public int AdminModulesId { get; set; } @@ -18,5 +19,13 @@ namespace SZUAbsolventenverein.Module.AdminModules.Models public DateTime CreatedOn { get; set; } public string ModifiedBy { get; set; } public DateTime ModifiedOn { get; set; } + + [NotMapped] public string ModuleName => ""; + + [NotMapped] public int ModuleID => ModuleId; + + [NotMapped] public int EntityID => AdminModulesId; + + [NotMapped] public string UserName => CreatedBy; } } diff --git a/Shared/Models/ReportSystem/Reporting.cs b/Shared/Models/ReportSystem/Reporting.cs index 2db78bf..84fd44f 100644 --- a/Shared/Models/ReportSystem/Reporting.cs +++ b/Shared/Models/ReportSystem/Reporting.cs @@ -10,6 +10,7 @@ public class Reporting : IAuditable public int ReportingID { get; set; } public int ModuleId { get; set; } public int EntityId { get; set; } + public string UserName { get; set; } public string Note { get; set; } public string Reason { get; set; } diff --git a/Shared/Permissions/ReportSystemPermissionNames.cs b/Shared/Permissions/ReportSystemPermissionNames.cs new file mode 100644 index 0000000..be0f518 --- /dev/null +++ b/Shared/Permissions/ReportSystemPermissionNames.cs @@ -0,0 +1,8 @@ +namespace SZUAbsolventenverein.Module.ReportSystem.Permissions +{ + public class ReportSystemPermissionNames + { + public const string Report = "Report"; + } +} + diff --git a/Shared/SZUAbsolventenverein.Module.AdminModules.Shared.csproj b/Shared/SZUAbsolventenverein.Module.AdminModules.Shared.csproj index 9bf2f70..5ffd333 100644 --- a/Shared/SZUAbsolventenverein.Module.AdminModules.Shared.csproj +++ b/Shared/SZUAbsolventenverein.Module.AdminModules.Shared.csproj @@ -12,6 +12,7 @@ +