From 7114904412e1a8375a26c47ca3cdaf902d73b2ca Mon Sep 17 00:00:00 2001 From: Adam Gaiswinkler Date: Thu, 15 Jan 2026 00:01:55 +0100 Subject: [PATCH] Feature: Hall of Fame Module Implementation (1.0.1) - Added Hall of Fame module logic (Models, Controller, Service). - Implemented 'One Entry Per User' and 'Publish/Draft' workflow. - Updated UI to Grid Layout (Index.razor) and Unified Form (Edit.razor). - Added Database Migration 01000001 for new columns. - Bumped version to 1.0.1. --- .../Edit.razor | 110 +++++++++++++-- .../Index.razor | 82 ++++++----- Client/Services/HallOfFameService.cs | 7 + ...Absolventenverein.Module.HallOfFame.nuspec | 2 +- Package/debug.sh | 15 +- Server/Controllers/HallOfFameController.cs | 48 ++++++- .../01000001_AddHallOfFameColumns.cs | 130 ++++++++++++++++++ .../EntityBuilders/HallOfFameEntityBuilder.cs | 13 ++ ...ntenverein.Module.HallOfFame.Server.csproj | 2 +- Server/Services/HallOfFameService.cs | 14 ++ Shared/Models/HallOfFame.cs | 8 ++ ...ntenverein.Module.HallOfFame.Shared.csproj | 2 +- 12 files changed, 378 insertions(+), 55 deletions(-) mode change 100644 => 100755 Package/debug.sh create mode 100644 Server/Migrations/01000001_AddHallOfFameColumns.cs diff --git a/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Edit.razor b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Edit.razor index aa449d1..e7f45c8 100644 --- a/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Edit.razor +++ b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Edit.razor @@ -10,15 +10,54 @@
-
- +
+
- + +
Bitte gib einen Namen ein (max. 120 Zeichen).
+
+
+
+ +
+ +
Bitte gib einen gültigen Jahrgang ein.
+
+
+
+ +
+ +
Bitte gib eine Beschreibung ein.
+
+
+
+ +
+ +
+
+
+ +
+ +
Bitte gib eine gültige URL ein (startet mit http:// oder https://).
+
+
+
+ +
+

Aktuell: @(_status ?? "Neu")

- - @Localizer["Cancel"] + +
+ + + Abbrechen +
+

@if (PageState.Action == "Edit") { @@ -27,11 +66,11 @@ @code { - public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit; + public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View; // Logic handles checking user own entry public override string Actions => "Add,Edit"; - public override string Title => "Manage HallOfFame"; + public override string Title => "Hall of Fame Eintrag verwalten"; public override List Resources => new List() { @@ -43,6 +82,12 @@ private int _id; private string _name; + private int _year = DateTime.Now.Year; + private string _description; + private string _image; + private string _link; + private string _status = "Draft"; + private string _createdby; private DateTime _createdon; private string _modifiedby; @@ -56,15 +101,39 @@ { _id = Int32.Parse(PageState.QueryString["id"]); HallOfFame HallOfFame = await HallOfFameService.GetHallOfFameAsync(_id, ModuleState.ModuleId); + + // Security check: only allow editing own entry if (HallOfFame != null) { + if (HallOfFame.UserId != PageState.User.UserId) + { + NavigationManager.NavigateTo(NavigateUrl()); + return; + } + _name = HallOfFame.Name; + _year = HallOfFame.Year; + _description = HallOfFame.Description; + _image = HallOfFame.Image; + _link = HallOfFame.Link; + _status = HallOfFame.Status; + _createdby = HallOfFame.CreatedBy; _createdon = HallOfFame.CreatedOn; _modifiedby = HallOfFame.ModifiedBy; _modifiedon = HallOfFame.ModifiedOn; } } + else // Add Mode + { + // Check if user already has an entry to prevent duplicates + var existing = await HallOfFameService.GetHallOfFameByUserIdAsync(PageState.User.UserId, ModuleState.ModuleId); + if (existing != null) + { + // Use NavigateUrl with parameters properly (simplified here) + NavigationManager.NavigateTo(EditUrl(existing.HallOfFameId.ToString())); + } + } } catch (Exception ex) { @@ -73,7 +142,7 @@ } } - private async Task Save() + private async Task Save(string status) { try { @@ -81,20 +150,39 @@ var interop = new Oqtane.UI.Interop(JSRuntime); if (await interop.FormValid(form)) { + _status = status; + if (PageState.Action == "Add") { HallOfFame HallOfFame = new HallOfFame(); HallOfFame.ModuleId = ModuleState.ModuleId; + HallOfFame.UserId = PageState.User.UserId; // Set Owner HallOfFame.Name = _name; + HallOfFame.Year = _year; + HallOfFame.Description = _description; + HallOfFame.Image = _image; + HallOfFame.Link = _link; + HallOfFame.Status = _status; + HallOfFame = await HallOfFameService.AddHallOfFameAsync(HallOfFame); await logger.LogInformation("HallOfFame Added {HallOfFame}", HallOfFame); } else { HallOfFame HallOfFame = await HallOfFameService.GetHallOfFameAsync(_id, ModuleState.ModuleId); - HallOfFame.Name = _name; - await HallOfFameService.UpdateHallOfFameAsync(HallOfFame); - await logger.LogInformation("HallOfFame Updated {HallOfFame}", HallOfFame); + // Ensure we don't overwrite with invalid user logic, though server checks too + if (HallOfFame.UserId == PageState.User.UserId) + { + HallOfFame.Name = _name; + HallOfFame.Year = _year; + HallOfFame.Description = _description; + HallOfFame.Image = _image; + HallOfFame.Link = _link; + HallOfFame.Status = _status; + + await HallOfFameService.UpdateHallOfFameAsync(HallOfFame); + await logger.LogInformation("HallOfFame Updated {HallOfFame}", HallOfFame); + } } NavigationManager.NavigateTo(NavigateUrl()); } diff --git a/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Index.razor b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Index.razor index 4e243a2..c10e17b 100644 --- a/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Index.razor +++ b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Index.razor @@ -13,27 +13,55 @@ } else { - -
-
+
+
+ @if (PageState.User != null) + { + if (_myEntry != null) + { + + } + else + { + + } + } + else + { +

Einloggen, um einen Eintrag zu erstellen.

+ } +
+
+ @if (@_HallOfFames.Count != 0) { - -
-   -   - @Localizer["Name"] -
- - - - @context.Name - -
+
+ @foreach (var item in _HallOfFames) + { +
+
+ @if (!string.IsNullOrEmpty(item.Image)) + { + @item.Name + } +
+
@item.Name (@item.Year)
+

@item.Description

+ @if (!string.IsNullOrEmpty(item.Link)) + { + Mehr Infos + } +
+
+
+ } +
} else { -

@Localizer["Message.DisplayNone"]

+
+ Es sind noch keine Hall-of-Fame-Einträge veröffentlicht. +
} } @@ -47,12 +75,18 @@ else }; List _HallOfFames; + HallOfFame _myEntry; protected override async Task OnInitializedAsync() { try { _HallOfFames = await HallOfFameService.GetHallOfFamesAsync(ModuleState.ModuleId); + + if (PageState.User != null) + { + _myEntry = await HallOfFameService.GetHallOfFameByUserIdAsync(PageState.User.UserId, ModuleState.ModuleId); + } } catch (Exception ex) { @@ -60,20 +94,4 @@ else AddModuleMessage(Localizer["Message.LoadError"], MessageType.Error); } } - - private async Task Delete(HallOfFame HallOfFame) - { - try - { - await HallOfFameService.DeleteHallOfFameAsync(HallOfFame.HallOfFameId, ModuleState.ModuleId); - await logger.LogInformation("HallOfFame Deleted {HallOfFame}", HallOfFame); - _HallOfFames = await HallOfFameService.GetHallOfFamesAsync(ModuleState.ModuleId); - StateHasChanged(); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Deleting HallOfFame {HallOfFame} {Error}", HallOfFame, ex.Message); - AddModuleMessage(Localizer["Message.DeleteError"], MessageType.Error); - } - } } \ No newline at end of file diff --git a/Client/Services/HallOfFameService.cs b/Client/Services/HallOfFameService.cs index 5e736b4..8451938 100644 --- a/Client/Services/HallOfFameService.cs +++ b/Client/Services/HallOfFameService.cs @@ -13,6 +13,8 @@ namespace SZUAbsolventenverein.Module.HallOfFame.Services Task GetHallOfFameAsync(int HallOfFameId, int ModuleId); + Task GetHallOfFameByUserIdAsync(int UserId, int ModuleId); + Task AddHallOfFameAsync(Models.HallOfFame HallOfFame); Task UpdateHallOfFameAsync(Models.HallOfFame HallOfFame); @@ -37,6 +39,11 @@ namespace SZUAbsolventenverein.Module.HallOfFame.Services return await GetJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{HallOfFameId}/{ModuleId}", EntityNames.Module, ModuleId)); } + public async Task GetHallOfFameByUserIdAsync(int UserId, int ModuleId) + { + return await GetJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/user/{UserId}?moduleid={ModuleId}", EntityNames.Module, ModuleId)); + } + public async Task AddHallOfFameAsync(Models.HallOfFame HallOfFame) { return await PostJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}", EntityNames.Module, HallOfFame.ModuleId), HallOfFame); diff --git a/Package/SZUAbsolventenverein.Module.HallOfFame.nuspec b/Package/SZUAbsolventenverein.Module.HallOfFame.nuspec index 90ec2c9..12a13fb 100644 --- a/Package/SZUAbsolventenverein.Module.HallOfFame.nuspec +++ b/Package/SZUAbsolventenverein.Module.HallOfFame.nuspec @@ -2,7 +2,7 @@ $projectname$ - 1.0.0 + 1.0.1 SZUAbsolventenverein SZUAbsolventenverein HallOfFame diff --git a/Package/debug.sh b/Package/debug.sh old mode 100644 new mode 100755 index 4a8b343..f90961d --- a/Package/debug.sh +++ b/Package/debug.sh @@ -3,10 +3,11 @@ TargetFramework=$1 ProjectName=$2 -cp -f "../Client/bin/Debug/$TargetFramework/$ProjectName$.Client.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" -cp -f "../Client/bin/Debug/$TargetFramework/$ProjectName$.Client.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" -cp -f "../Server/bin/Debug/$TargetFramework/$ProjectName$.Server.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" -cp -f "../Server/bin/Debug/$TargetFramework/$ProjectName$.Server.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" -cp -f "../Shared/bin/Debug/$TargetFramework/$ProjectName$.Shared.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" -cp -f "../Shared/bin/Debug/$TargetFramework/$ProjectName$.Shared.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" -cp -rf "../Server/wwwroot/"* "../../oqtane.framework/Oqtane.Server/wwwroot/_content/%ProjectName%/" +cp -f "../Client/bin/Debug/$TargetFramework/$ProjectName.Client.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" +cp -f "../Client/bin/Debug/$TargetFramework/$ProjectName.Client.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" +cp -f "../Server/bin/Debug/$TargetFramework/$ProjectName.Server.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" +cp -f "../Server/bin/Debug/$TargetFramework/$ProjectName.Server.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" +cp -f "../Shared/bin/Debug/$TargetFramework/$ProjectName.Shared.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" +cp -f "../Shared/bin/Debug/$TargetFramework/$ProjectName.Shared.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/$TargetFramework/" +mkdir -p "../../oqtane.framework/Oqtane.Server/wwwroot/_content/$ProjectName/" +cp -rf "../Server/wwwroot/"* "../../oqtane.framework/Oqtane.Server/wwwroot/_content/$ProjectName/" diff --git a/Server/Controllers/HallOfFameController.cs b/Server/Controllers/HallOfFameController.cs index 9196ebd..fb95661 100644 --- a/Server/Controllers/HallOfFameController.cs +++ b/Server/Controllers/HallOfFameController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using System.Collections.Generic; +using System.Linq; using Microsoft.AspNetCore.Http; using Oqtane.Shared; using Oqtane.Enums; @@ -22,6 +23,7 @@ namespace SZUAbsolventenverein.Module.HallOfFame.Controllers _HallOfFameService = HallOfFameService; } + // GET: api/?moduleid=x // GET: api/?moduleid=x [HttpGet] [Authorize(Policy = PolicyNames.ViewModule)] @@ -30,7 +32,11 @@ namespace SZUAbsolventenverein.Module.HallOfFame.Controllers int ModuleId; if (int.TryParse(moduleid, out ModuleId) && IsAuthorizedEntityId(EntityNames.Module, ModuleId)) { - return await _HallOfFameService.GetHallOfFamesAsync(ModuleId); + var list = await _HallOfFameService.GetHallOfFamesAsync(ModuleId); + // Filter: Show only Published unless user has Edit permissions (simplified check for now, can be expanded) + // For now, let's filter in memory or service. The requirement says: "Hauptseite zeigt nur Published". + // We will filter here. + return list.Where(item => item.Status == "Published"); } else { @@ -58,6 +64,25 @@ namespace SZUAbsolventenverein.Module.HallOfFame.Controllers } } + // GET api//user/5?moduleid=x + [HttpGet("user/{userid}")] + [Authorize(Policy = PolicyNames.ViewModule)] + public async Task GetByUserId(int userid, string moduleid) + { + int ModuleId; + if (int.TryParse(moduleid, out ModuleId) && IsAuthorizedEntityId(EntityNames.Module, ModuleId)) + { + var list = await _HallOfFameService.GetHallOfFamesAsync(ModuleId); + return list.FirstOrDefault(item => item.UserId == userid); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame GetByUserId Attempt {UserId} {ModuleId}", userid, moduleid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } + } + // POST api/ [HttpPost] [Authorize(Policy = PolicyNames.EditModule)] @@ -65,6 +90,15 @@ namespace SZUAbsolventenverein.Module.HallOfFame.Controllers { if (ModelState.IsValid && IsAuthorizedEntityId(EntityNames.Module, HallOfFame.ModuleId)) { + // Enforce one entry per user + var allEntries = await _HallOfFameService.GetHallOfFamesAsync(HallOfFame.ModuleId); + if (allEntries.Any(e => e.UserId == HallOfFame.UserId)) + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "User {UserId} already has a Hall of Fame entry.", HallOfFame.UserId); + HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; + return null; + } + HallOfFame = await _HallOfFameService.AddHallOfFameAsync(HallOfFame); } else @@ -83,7 +117,17 @@ namespace SZUAbsolventenverein.Module.HallOfFame.Controllers { if (ModelState.IsValid && HallOfFame.HallOfFameId == id && IsAuthorizedEntityId(EntityNames.Module, HallOfFame.ModuleId)) { - HallOfFame = await _HallOfFameService.UpdateHallOfFameAsync(HallOfFame); + var existing = await _HallOfFameService.GetHallOfFameAsync(id, HallOfFame.ModuleId); + if (existing != null && existing.UserId == HallOfFame.UserId) + { + HallOfFame = await _HallOfFameService.UpdateHallOfFameAsync(HallOfFame); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame Put Attempt by User {UserId} for Entry {HallOfFameId}", HallOfFame.UserId, id); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + HallOfFame = null; + } } else { diff --git a/Server/Migrations/01000001_AddHallOfFameColumns.cs b/Server/Migrations/01000001_AddHallOfFameColumns.cs new file mode 100644 index 0000000..34f8349 --- /dev/null +++ b/Server/Migrations/01000001_AddHallOfFameColumns.cs @@ -0,0 +1,130 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations; +using SZUAbsolventenverein.Module.HallOfFame.Migrations.EntityBuilders; +using SZUAbsolventenverein.Module.HallOfFame.Repository; + +namespace SZUAbsolventenverein.Module.HallOfFame.Migrations +{ + [DbContext(typeof(HallOfFameContext))] + [Migration("SZUAbsolventenverein.Module.HallOfFame.01.00.00.01")] + public class AddHallOfFameColumns : MultiDatabaseMigration + { + public AddHallOfFameColumns(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + var entityBuilder = new HallOfFameEntityBuilder(migrationBuilder, ActiveDatabase); + + // Add new columns manually since we are upgrading an existing table + // Note: Integer columns are generated as default/nullable depending on definition, Oqtane Helpers handle generic types. + // Using logic similar to Oqtane.Migrations.EntityBuilders + + if (ActiveDatabase.Name == "Sqlite") // Sqlite specific or generic + { + // Generic AddColumn: Table, Name, Type, Nullable + // However, Oqtane EntityBuilder usually builds tables. + // We will use migrationBuilder directly via helper if possible or standard AddColumn. + + migrationBuilder.AddColumn( + name: "Year", + table: "SZUAbsolventenvereinHallOfFame", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "Description", + table: "SZUAbsolventenvereinHallOfFame", + nullable: true); // Allow nulls initially or empty? MaxString usually nullable in Oqtane context? Let's check. + + migrationBuilder.AddColumn( + name: "Image", + table: "SZUAbsolventenvereinHallOfFame", + nullable: true); + + migrationBuilder.AddColumn( + name: "Link", + table: "SZUAbsolventenvereinHallOfFame", + nullable: true); + + migrationBuilder.AddColumn( + name: "Status", + table: "SZUAbsolventenvereinHallOfFame", + maxLength: 50, + nullable: true); + + migrationBuilder.AddColumn( + name: "UserId", + table: "SZUAbsolventenvereinHallOfFame", + nullable: false, + defaultValue: 0); + } + else + { + // For SQL Server / others, simply use same AddColumn but allow EF Core to handle types + migrationBuilder.AddColumn( + name: "Year", + table: "SZUAbsolventenvereinHallOfFame", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "Description", + table: "SZUAbsolventenvereinHallOfFame", + nullable: true); + + migrationBuilder.AddColumn( + name: "Image", + table: "SZUAbsolventenvereinHallOfFame", + nullable: true); + + migrationBuilder.AddColumn( + name: "Link", + table: "SZUAbsolventenvereinHallOfFame", + nullable: true); + + migrationBuilder.AddColumn( + name: "Status", + table: "SZUAbsolventenvereinHallOfFame", + maxLength: 50, + nullable: true); + + migrationBuilder.AddColumn( + name: "UserId", + table: "SZUAbsolventenvereinHallOfFame", + nullable: false, + defaultValue: 0); + } + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Year", + table: "SZUAbsolventenvereinHallOfFame"); + + migrationBuilder.DropColumn( + name: "Description", + table: "SZUAbsolventenvereinHallOfFame"); + + migrationBuilder.DropColumn( + name: "Image", + table: "SZUAbsolventenvereinHallOfFame"); + + migrationBuilder.DropColumn( + name: "Link", + table: "SZUAbsolventenvereinHallOfFame"); + + migrationBuilder.DropColumn( + name: "Status", + table: "SZUAbsolventenvereinHallOfFame"); + + migrationBuilder.DropColumn( + name: "UserId", + table: "SZUAbsolventenvereinHallOfFame"); + } + } +} diff --git a/Server/Migrations/EntityBuilders/HallOfFameEntityBuilder.cs b/Server/Migrations/EntityBuilders/HallOfFameEntityBuilder.cs index ad61792..b3d6d56 100644 --- a/Server/Migrations/EntityBuilders/HallOfFameEntityBuilder.cs +++ b/Server/Migrations/EntityBuilders/HallOfFameEntityBuilder.cs @@ -25,6 +25,12 @@ namespace SZUAbsolventenverein.Module.HallOfFame.Migrations.EntityBuilders HallOfFameId = AddAutoIncrementColumn(table,"HallOfFameId"); ModuleId = AddIntegerColumn(table,"ModuleId"); Name = AddMaxStringColumn(table,"Name"); + Year = AddIntegerColumn(table,"Year"); + Description = AddMaxStringColumn(table,"Description"); + Image = AddMaxStringColumn(table,"Image"); + Link = AddMaxStringColumn(table,"Link"); + Status = AddStringColumn(table,"Status", 50); + UserId = AddIntegerColumn(table,"UserId"); AddAuditableColumns(table); return this; } @@ -32,5 +38,12 @@ namespace SZUAbsolventenverein.Module.HallOfFame.Migrations.EntityBuilders public OperationBuilder HallOfFameId { get; set; } public OperationBuilder ModuleId { get; set; } public OperationBuilder Name { get; set; } + public OperationBuilder Year { get; set; } + public OperationBuilder Description { get; set; } + public OperationBuilder Image { get; set; } + public OperationBuilder Link { get; set; } + public OperationBuilder Status { get; set; } + public OperationBuilder UserId { get; set; } } } + diff --git a/Server/SZUAbsolventenverein.Module.HallOfFame.Server.csproj b/Server/SZUAbsolventenverein.Module.HallOfFame.Server.csproj index 33fd804..2b06cec 100644 --- a/Server/SZUAbsolventenverein.Module.HallOfFame.Server.csproj +++ b/Server/SZUAbsolventenverein.Module.HallOfFame.Server.csproj @@ -3,7 +3,7 @@ net9.0 true - 1.0.0 + 1.0.1 SZUAbsolventenverein.Module.HallOfFame SZUAbsolventenverein SZUAbsolventenverein diff --git a/Server/Services/HallOfFameService.cs b/Server/Services/HallOfFameService.cs index 006e13e..6d8845a 100644 --- a/Server/Services/HallOfFameService.cs +++ b/Server/Services/HallOfFameService.cs @@ -54,6 +54,20 @@ namespace SZUAbsolventenverein.Module.HallOfFame.Services } } + public Task GetHallOfFameByUserIdAsync(int UserId, int ModuleId) + { + if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View)) + { + // Assuming Repository doesn't have specific method yet, using LINQ on GetHallOfFames + return Task.FromResult(_HallOfFameRepository.GetHallOfFames(ModuleId).FirstOrDefault(item => item.UserId == UserId)); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame GetByUserId Attempt {UserId} {ModuleId}", UserId, ModuleId); + return null; + } + } + public Task AddHallOfFameAsync(Models.HallOfFame HallOfFame) { if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, HallOfFame.ModuleId, PermissionNames.Edit)) diff --git a/Shared/Models/HallOfFame.cs b/Shared/Models/HallOfFame.cs index 140aead..4219d5b 100644 --- a/Shared/Models/HallOfFame.cs +++ b/Shared/Models/HallOfFame.cs @@ -12,6 +12,14 @@ namespace SZUAbsolventenverein.Module.HallOfFame.Models public int HallOfFameId { get; set; } public int ModuleId { get; set; } public string Name { get; set; } + + public int Year { get; set; } + public string Description { get; set; } + public string Image { get; set; } + public string Link { get; set; } + public string Status { get; set; } // "Draft" or "Published" + public int UserId { get; set; } // Owner + public string CreatedBy { get; set; } public DateTime CreatedOn { get; set; } diff --git a/Shared/SZUAbsolventenverein.Module.HallOfFame.Shared.csproj b/Shared/SZUAbsolventenverein.Module.HallOfFame.Shared.csproj index a0e0308..e990d20 100644 --- a/Shared/SZUAbsolventenverein.Module.HallOfFame.Shared.csproj +++ b/Shared/SZUAbsolventenverein.Module.HallOfFame.Shared.csproj @@ -2,7 +2,7 @@ net9.0 - 1.0.0 + 1.0.1 SZUAbsolventenverein.Module.HallOfFame SZUAbsolventenverein SZUAbsolventenverein