From 5dfa690432e8895c02a406f5f3a9cff29e25e8b0 Mon Sep 17 00:00:00 2001 From: Adam Gaiswinkler Date: Fri, 2 Jan 2026 22:52:11 +0100 Subject: [PATCH] Initial commit --- .gitignore | 41 +++++ Client/AssemblyInfo.cs | 4 + Client/Interop.cs | 15 ++ .../Edit.razor | 112 +++++++++++++ .../Index.razor | 79 ++++++++++ .../ModuleInfo.cs | 19 +++ .../Settings.razor | 47 ++++++ .../Edit.resx | 141 +++++++++++++++++ .../Index.resx | 147 ++++++++++++++++++ .../Settings.resx | 126 +++++++++++++++ ...ntenverein.Module.HallOfFame.Client.csproj | 38 +++++ Client/Services/HallOfFameService.cs | 55 +++++++ Client/Startup/ClientStartup.cs | 18 +++ Client/_Imports.razor | 24 +++ ...tenverein.Module.HallOfFame.Package.csproj | 29 ++++ ...Absolventenverein.Module.HallOfFame.nuspec | 38 +++++ Package/debug.cmd | 11 ++ Package/debug.sh | 12 ++ Package/icon.png | Bin 0 -> 7800 bytes Package/release.cmd | 8 + Package/release.sh | 7 + SZUAbsolventenverein.Module.HallOfFame.sln | 47 ++++++ Server/AssemblyInfo.cs | 4 + Server/Controllers/HallOfFameController.cs | 114 ++++++++++++++ Server/Manager/HallOfFameManager.cs | 87 +++++++++++ .../Migrations/01000000_InitializeModule.cs | 30 ++++ .../EntityBuilders/HallOfFameEntityBuilder.cs | 36 +++++ Server/Repository/HallOfFameContext.cs | 26 ++++ Server/Repository/HallOfFameRepository.cs | 75 +++++++++ ...ntenverein.Module.HallOfFame.Server.csproj | 37 +++++ Server/Services/HallOfFameService.cs | 101 ++++++++++++ Server/Startup/ServerStartup.cs | 28 ++++ Server/wwwroot/Module.css | 1 + Server/wwwroot/Module.js | 5 + Shared/Models/HallOfFame.cs | 21 +++ ...ntenverein.Module.HallOfFame.Shared.csproj | 22 +++ template.json | 6 + 37 files changed, 1611 insertions(+) create mode 100644 .gitignore create mode 100644 Client/AssemblyInfo.cs create mode 100644 Client/Interop.cs create mode 100644 Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Edit.razor create mode 100644 Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Index.razor create mode 100644 Client/Modules/SZUAbsolventenverein.Module.HallOfFame/ModuleInfo.cs create mode 100644 Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Settings.razor create mode 100644 Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Edit.resx create mode 100644 Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Index.resx create mode 100644 Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Settings.resx create mode 100644 Client/SZUAbsolventenverein.Module.HallOfFame.Client.csproj create mode 100644 Client/Services/HallOfFameService.cs create mode 100644 Client/Startup/ClientStartup.cs create mode 100644 Client/_Imports.razor create mode 100644 Package/SZUAbsolventenverein.Module.HallOfFame.Package.csproj create mode 100644 Package/SZUAbsolventenverein.Module.HallOfFame.nuspec create mode 100644 Package/debug.cmd create mode 100644 Package/debug.sh create mode 100644 Package/icon.png create mode 100644 Package/release.cmd create mode 100644 Package/release.sh create mode 100644 SZUAbsolventenverein.Module.HallOfFame.sln create mode 100644 Server/AssemblyInfo.cs create mode 100644 Server/Controllers/HallOfFameController.cs create mode 100644 Server/Manager/HallOfFameManager.cs create mode 100644 Server/Migrations/01000000_InitializeModule.cs create mode 100644 Server/Migrations/EntityBuilders/HallOfFameEntityBuilder.cs create mode 100644 Server/Repository/HallOfFameContext.cs create mode 100644 Server/Repository/HallOfFameRepository.cs create mode 100644 Server/SZUAbsolventenverein.Module.HallOfFame.Server.csproj create mode 100644 Server/Services/HallOfFameService.cs create mode 100644 Server/Startup/ServerStartup.cs create mode 100644 Server/wwwroot/Module.css create mode 100644 Server/wwwroot/Module.js create mode 100644 Shared/Models/HallOfFame.cs create mode 100644 Shared/SZUAbsolventenverein.Module.HallOfFame.Shared.csproj create mode 100644 template.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f5fe63a --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww]in32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# Visual Studio Code +.vscode/ + +# Mac +.DS_Store diff --git a/Client/AssemblyInfo.cs b/Client/AssemblyInfo.cs new file mode 100644 index 0000000..f2d477f --- /dev/null +++ b/Client/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Resources; +using Microsoft.Extensions.Localization; + +[assembly: RootNamespace("SZUAbsolventenverein.Module.HallOfFame.Client")] diff --git a/Client/Interop.cs b/Client/Interop.cs new file mode 100644 index 0000000..9e5fa85 --- /dev/null +++ b/Client/Interop.cs @@ -0,0 +1,15 @@ +using Microsoft.JSInterop; +using System.Threading.Tasks; + +namespace SZUAbsolventenverein.Module.HallOfFame +{ + public class Interop + { + private readonly IJSRuntime _jsRuntime; + + public Interop(IJSRuntime jsRuntime) + { + _jsRuntime = jsRuntime; + } + } +} diff --git a/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Edit.razor b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Edit.razor new file mode 100644 index 0000000..aa449d1 --- /dev/null +++ b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Edit.razor @@ -0,0 +1,112 @@ +@using Oqtane.Modules.Controls +@using SZUAbsolventenverein.Module.HallOfFame.Services +@using SZUAbsolventenverein.Module.HallOfFame.Models + +@namespace SZUAbsolventenverein.Module.HallOfFame +@inherits ModuleBase +@inject IHallOfFameService HallOfFameService +@inject NavigationManager NavigationManager +@inject IStringLocalizer Localizer + +
+
+
+ +
+ +
+
+
+ + @Localizer["Cancel"] +

+ @if (PageState.Action == "Edit") + { + + } +
+ +@code { + public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit; + + public override string Actions => "Add,Edit"; + + public override string Title => "Manage HallOfFame"; + + public override List Resources => new List() + { + new Stylesheet("_content/SZUAbsolventenverein.Module.HallOfFame/Module.css") + }; + + private ElementReference form; + private bool validated = false; + + private int _id; + private string _name; + private string _createdby; + private DateTime _createdon; + private string _modifiedby; + private DateTime _modifiedon; + + protected override async Task OnInitializedAsync() + { + try + { + if (PageState.Action == "Edit") + { + _id = Int32.Parse(PageState.QueryString["id"]); + HallOfFame HallOfFame = await HallOfFameService.GetHallOfFameAsync(_id, ModuleState.ModuleId); + if (HallOfFame != null) + { + _name = HallOfFame.Name; + _createdby = HallOfFame.CreatedBy; + _createdon = HallOfFame.CreatedOn; + _modifiedby = HallOfFame.ModifiedBy; + _modifiedon = HallOfFame.ModifiedOn; + } + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading HallOfFame {HallOfFameId} {Error}", _id, ex.Message); + AddModuleMessage(Localizer["Message.LoadError"], MessageType.Error); + } + } + + private async Task Save() + { + try + { + validated = true; + var interop = new Oqtane.UI.Interop(JSRuntime); + if (await interop.FormValid(form)) + { + if (PageState.Action == "Add") + { + HallOfFame HallOfFame = new HallOfFame(); + HallOfFame.ModuleId = ModuleState.ModuleId; + HallOfFame.Name = _name; + 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); + } + NavigationManager.NavigateTo(NavigateUrl()); + } + else + { + AddModuleMessage(Localizer["Message.SaveValidation"], MessageType.Warning); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Saving HallOfFame {Error}", ex.Message); + AddModuleMessage(Localizer["Message.SaveError"], MessageType.Error); + } + } +} diff --git a/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Index.razor b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Index.razor new file mode 100644 index 0000000..4e243a2 --- /dev/null +++ b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Index.razor @@ -0,0 +1,79 @@ +@using SZUAbsolventenverein.Module.HallOfFame.Services +@using SZUAbsolventenverein.Module.HallOfFame.Models + +@namespace SZUAbsolventenverein.Module.HallOfFame +@inherits ModuleBase +@inject IHallOfFameService HallOfFameService +@inject NavigationManager NavigationManager +@inject IStringLocalizer Localizer + +@if (_HallOfFames == null) +{ +

Loading...

+} +else +{ + +
+
+ @if (@_HallOfFames.Count != 0) + { + +
+   +   + @Localizer["Name"] +
+ + + + @context.Name + +
+ } + else + { +

@Localizer["Message.DisplayNone"]

+ } +} + +@code { + public override string RenderMode => RenderModes.Static; + + public override List Resources => new List() + { + new Stylesheet("_content/SZUAbsolventenverein.Module.HallOfFame/Module.css"), + new Script("_content/SZUAbsolventenverein.Module.HallOfFame/Module.js") + }; + + List _HallOfFames; + + protected override async Task OnInitializedAsync() + { + try + { + _HallOfFames = await HallOfFameService.GetHallOfFamesAsync(ModuleState.ModuleId); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading HallOfFame {Error}", ex.Message); + 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/Modules/SZUAbsolventenverein.Module.HallOfFame/ModuleInfo.cs b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/ModuleInfo.cs new file mode 100644 index 0000000..5898e34 --- /dev/null +++ b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/ModuleInfo.cs @@ -0,0 +1,19 @@ +using Oqtane.Models; +using Oqtane.Modules; + +namespace SZUAbsolventenverein.Module.HallOfFame +{ + public class ModuleInfo : IModule + { + public ModuleDefinition ModuleDefinition => new ModuleDefinition + { + Name = "HallOfFame", + Description = "The Hall of Fame module displays selected individuals or achievements within the CMS. Entries are shown online, can be exported as a PDF, and are only published with user consen.", + Version = "1.0.0", + ServerManagerType = "SZUAbsolventenverein.Module.HallOfFame.Manager.HallOfFameManager, SZUAbsolventenverein.Module.HallOfFame.Server.Oqtane", + ReleaseVersions = "1.0.0", + Dependencies = "SZUAbsolventenverein.Module.HallOfFame.Shared.Oqtane", + PackageName = "SZUAbsolventenverein.Module.HallOfFame" + }; + } +} diff --git a/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Settings.razor b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Settings.razor new file mode 100644 index 0000000..2e04af3 --- /dev/null +++ b/Client/Modules/SZUAbsolventenverein.Module.HallOfFame/Settings.razor @@ -0,0 +1,47 @@ +@namespace SZUAbsolventenverein.Module.HallOfFame +@inherits ModuleBase +@inject ISettingService SettingService +@inject IStringLocalizer Localizer + +
+
+ +
+ +
+
+
+ +@code { + private string resourceType = "SZUAbsolventenverein.Module.HallOfFame.Settings, SZUAbsolventenverein.Module.HallOfFame.Client.Oqtane"; // for localization + public override string Title => "HallOfFame Settings"; + + string _value; + + protected override async Task OnInitializedAsync() + { + try + { + Dictionary settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId); + _value = SettingService.GetSetting(settings, "SettingName", ""); + } + catch (Exception ex) + { + AddModuleMessage(ex.Message, MessageType.Error); + } + } + + public async Task UpdateSettings() + { + try + { + Dictionary settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId); + SettingService.SetSetting(settings, "SettingName", _value); + await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId); + } + catch (Exception ex) + { + AddModuleMessage(ex.Message, MessageType.Error); + } + } +} diff --git a/Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Edit.resx b/Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Edit.resx new file mode 100644 index 0000000..1239960 --- /dev/null +++ b/Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Edit.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Name: + + + Enter the name + + + Save + + + Cancel + + + Error Loading HallOfFame + + + Please Provide All Required Information + + + Error Saving HallOfFame + + \ No newline at end of file diff --git a/Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Index.resx b/Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Index.resx new file mode 100644 index 0000000..6004d80 --- /dev/null +++ b/Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Index.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Name + + + Add HallOfFame + + + Edit + + + Delete + + + Delete HallOfFame + + + Are You Sure You Wish To Delete This HallOfFame? + + + No HallOfFames To Display + + + Error Loading HallOfFame + + + Error Deleting HallOfFame + + \ No newline at end of file diff --git a/Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Settings.resx b/Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Settings.resx new file mode 100644 index 0000000..83dc88f --- /dev/null +++ b/Client/Resources/SZUAbsolventenverein.Module.HallOfFame/Settings.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Name: + + + Enter a value + + \ No newline at end of file diff --git a/Client/SZUAbsolventenverein.Module.HallOfFame.Client.csproj b/Client/SZUAbsolventenverein.Module.HallOfFame.Client.csproj new file mode 100644 index 0000000..ec854a8 --- /dev/null +++ b/Client/SZUAbsolventenverein.Module.HallOfFame.Client.csproj @@ -0,0 +1,38 @@ + + + + net9.0 + 1.0.0 + SZUAbsolventenverein + SZUAbsolventenverein + The Hall of Fame module displays selected individuals or achievements within the CMS. Entries are shown online, can be exported as a PDF, and are only published with user consen. + SZUAbsolventenverein.Module.HallOfFame + SZUAbsolventenverein + SZUAbsolventenverein.Module.HallOfFame.Client.Oqtane + true + + + + + + + + + + + + + + + + ..\..\oqtane.framework\Oqtane.Server\bin\Debug\net9.0\Oqtane.Client.dll + ..\..\oqtane.framework\Oqtane.Server\bin\Debug\net9.0\Oqtane.Shared.dll + + + + + false + false + + + diff --git a/Client/Services/HallOfFameService.cs b/Client/Services/HallOfFameService.cs new file mode 100644 index 0000000..5e736b4 --- /dev/null +++ b/Client/Services/HallOfFameService.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Oqtane.Services; +using Oqtane.Shared; + +namespace SZUAbsolventenverein.Module.HallOfFame.Services +{ + public interface IHallOfFameService + { + Task> GetHallOfFamesAsync(int ModuleId); + + Task GetHallOfFameAsync(int HallOfFameId, int ModuleId); + + Task AddHallOfFameAsync(Models.HallOfFame HallOfFame); + + Task UpdateHallOfFameAsync(Models.HallOfFame HallOfFame); + + Task DeleteHallOfFameAsync(int HallOfFameId, int ModuleId); + } + + public class HallOfFameService : ServiceBase, IHallOfFameService + { + public HallOfFameService(HttpClient http, SiteState siteState) : base(http, siteState) { } + + private string Apiurl => CreateApiUrl("HallOfFame"); + + public async Task> GetHallOfFamesAsync(int ModuleId) + { + List HallOfFames = await GetJsonAsync>(CreateAuthorizationPolicyUrl($"{Apiurl}?moduleid={ModuleId}", EntityNames.Module, ModuleId), Enumerable.Empty().ToList()); + return HallOfFames.OrderBy(item => item.Name).ToList(); + } + + public async Task GetHallOfFameAsync(int HallOfFameId, int ModuleId) + { + return await GetJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{HallOfFameId}/{ModuleId}", EntityNames.Module, ModuleId)); + } + + public async Task AddHallOfFameAsync(Models.HallOfFame HallOfFame) + { + return await PostJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}", EntityNames.Module, HallOfFame.ModuleId), HallOfFame); + } + + public async Task UpdateHallOfFameAsync(Models.HallOfFame HallOfFame) + { + return await PutJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{HallOfFame.HallOfFameId}", EntityNames.Module, HallOfFame.ModuleId), HallOfFame); + } + + public async Task DeleteHallOfFameAsync(int HallOfFameId, int ModuleId) + { + await DeleteAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{HallOfFameId}/{ModuleId}", EntityNames.Module, ModuleId)); + } + } +} diff --git a/Client/Startup/ClientStartup.cs b/Client/Startup/ClientStartup.cs new file mode 100644 index 0000000..3a541c2 --- /dev/null +++ b/Client/Startup/ClientStartup.cs @@ -0,0 +1,18 @@ +using Microsoft.Extensions.DependencyInjection; +using System.Linq; +using Oqtane.Services; +using SZUAbsolventenverein.Module.HallOfFame.Services; + +namespace SZUAbsolventenverein.Module.HallOfFame.Startup +{ + public class ClientStartup : IClientStartup + { + public void ConfigureServices(IServiceCollection services) + { + if (!services.Any(s => s.ServiceType == typeof(IHallOfFameService))) + { + services.AddScoped(); + } + } + } +} diff --git a/Client/_Imports.razor b/Client/_Imports.razor new file mode 100644 index 0000000..2f6fb1b --- /dev/null +++ b/Client/_Imports.razor @@ -0,0 +1,24 @@ +@using System +@using System.Linq +@using System.Collections.Generic +@using System.Net.Http +@using System.Net.Http.Json + +@using Microsoft.AspNetCore.Components.Authorization +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.Extensions.Localization +@using Microsoft.JSInterop + +@using Oqtane.Models +@using Oqtane.Modules +@using Oqtane.Modules.Controls +@using Oqtane.Providers +@using Oqtane.Security +@using Oqtane.Services +@using Oqtane.Shared +@using Oqtane.Themes +@using Oqtane.Themes.Controls +@using Oqtane.UI +@using Oqtane.Enums +@using Oqtane.Interfaces \ No newline at end of file diff --git a/Package/SZUAbsolventenverein.Module.HallOfFame.Package.csproj b/Package/SZUAbsolventenverein.Module.HallOfFame.Package.csproj new file mode 100644 index 0000000..6f2b2d9 --- /dev/null +++ b/Package/SZUAbsolventenverein.Module.HallOfFame.Package.csproj @@ -0,0 +1,29 @@ + + + + net9.0 + false + false + + + + + True + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/SZUAbsolventenverein.Module.HallOfFame.nuspec b/Package/SZUAbsolventenverein.Module.HallOfFame.nuspec new file mode 100644 index 0000000..90ec2c9 --- /dev/null +++ b/Package/SZUAbsolventenverein.Module.HallOfFame.nuspec @@ -0,0 +1,38 @@ + + + + $projectname$ + 1.0.0 + SZUAbsolventenverein + SZUAbsolventenverein + HallOfFame + The Hall of Fame module displays selected individuals or achievements within the CMS. Entries are shown online, can be exported as a PDF, and are only published with user consen. + SZUAbsolventenverein + false + MIT + https://github.com/oqtane/oqtane.framework + icon.png + oqtane module + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/debug.cmd b/Package/debug.cmd new file mode 100644 index 0000000..cebe487 --- /dev/null +++ b/Package/debug.cmd @@ -0,0 +1,11 @@ +@echo off +set TargetFramework=%1 +set ProjectName=%2 + +XCOPY "..\Client\bin\Debug\%TargetFramework%\%ProjectName%.Client.Oqtane.dll" "..\..\oqtane.framework\Oqtane.Server\bin\Debug\%TargetFramework%\" /Y +XCOPY "..\Client\bin\Debug\%TargetFramework%\%ProjectName%.Client.Oqtane.pdb" "..\..\oqtane.framework\Oqtane.Server\bin\Debug\%TargetFramework%\" /Y +XCOPY "..\Server\bin\Debug\%TargetFramework%\%ProjectName%.Server.Oqtane.dll" "..\..\oqtane.framework\Oqtane.Server\bin\Debug\%TargetFramework%\" /Y +XCOPY "..\Server\bin\Debug\%TargetFramework%\%ProjectName%.Server.Oqtane.pdb" "..\..\oqtane.framework\Oqtane.Server\bin\Debug\%TargetFramework%\" /Y +XCOPY "..\Shared\bin\Debug\%TargetFramework%\%ProjectName%.Shared.Oqtane.dll" "..\..\oqtane.framework\Oqtane.Server\bin\Debug\%TargetFramework%\" /Y +XCOPY "..\Shared\bin\Debug\%TargetFramework%\%ProjectName%.Shared.Oqtane.pdb" "..\..\oqtane.framework\Oqtane.Server\bin\Debug\%TargetFramework%\" /Y +XCOPY "..\Server\wwwroot\*" "..\..\oqtane.framework\Oqtane.Server\wwwroot\_content\%ProjectName%\" /Y /S /I \ No newline at end of file diff --git a/Package/debug.sh b/Package/debug.sh new file mode 100644 index 0000000..4a8b343 --- /dev/null +++ b/Package/debug.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +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%/" diff --git a/Package/icon.png b/Package/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7422cf2f313e352d93b08d4e87fec74e52117713 GIT binary patch literal 7800 zcma)B=WnameWv!_qOKN2O=^qUn-WD)qOK+>QG*giQ6eQ#d++7Ou7fyn(OeryM}jua zbYrw>jHU_F-~u;}oa?5I5yN(!#z~ugDVh&K|ARh{&dH(N+Ybev-#qU)=eJ%$`rYFn z+DB~(vDvX2jV9sYfOQ=5caMK4cyySMaCn3>Fw?9N>_^2YE4N=@p`?vxw(sri#nZdZ*MOrC#R^W=<@RN@bK{9;2=9YySTV` zYiny|Wo2e&COth}-EOzr=X-m5l|4HC;1&nG4(j*pLhKHuczr1C$j?Ck73>wMO; zv9Y0?PN!4pX0y4mv2lNYe`#rHYHCXP|4$`m8g8^p%cx^o#C+$zr~#^_?iPIVRQ%~yT4!@X7I|rV07eF(HL_L&Ni@v+Bqb)L4f;&F#u{CSN4Slo}LCaBrmy~a7@UCGIZ|e z&b{|pIWaDCc%nVf$A1LISSWNxagP}WUeQ_a2qaZNi3pCMu{>_V_fLP@32`66aQhfM z0fz7tGy}5D3!mW3Y;b_d7(IZ~%oRK5G;j{GKKXv!LDnqWB|DGd>EQHf0eM$=UoDe8 zk=L_30XgmsT#b!F0X*z^(iNzr4UC5pXgKB62e?BGNQ}{yLb33GSBPAgJt@R@Sc`1h71T)Fd5v z2rFJr*ko=wf`^cW`LjRP>E!v~tkN!mJ7pea)LRP`}g7=>X<3Z*p>k?KVOF_;W zv+UBRpNAQLSqBcBH*w$>fQonXSak}eeN4N6Noi05^iXzLYZj+`7mL$hD`tWXTJOf4Cdd=7w`ZU<~jfZWbM5D zDcNsrf#N}vC$H{G&q@NOgb@5}*R{3W5R+4#BW#a8(#kjH8yYQ#>o;?yH^QIRJVbZR zS!yoCh;V{efgD~iYjDoNdI$xB#oB*<=LIOU!YD{AuPNjq6sqlE z*UAWY9z(ALola!UL;T~HT-y*-0W;`=^|Ji?LK1$#dC)1|%Nb_RFv^{dGt#TA=6z$9 zJRJJ+=-bd^qQHO+A%<=rF*33^p{?k$k|2^x4dCtE z_yOn&v<%|O#z88!VJvP)}lIsoYxakPKsfVywA=1GQWd z2VR!j5XnOUU3_M|&_DQI@aL=WfOA8EZtf3g$q=-P^>;l*EO;5v&YbLQ@{X@6M@?oqXwakxDvVdy9Stp z!o8n^1Qrwbp=`(v?=kzFrkj=TehtFPs90t!;6P`9yVLTaz%M>K&9dm^XKzR+d<^K= zh(E8+$}YJ5s_@cz!Sjrm!AeGS^62NMY8^^+z|?=h1{dH5&JG#_HJC%4Q%f^@Q1u{z zikWv_IjLJLHnUnAhI`zWQxmjs&>`Rc+czJ}kSxj8=1JEX2VjyN%O4j4d~Z67uL^Yh zo0ne{?js1^{LAkhF%kf`1T+W%zT-N{f%xDH4)7&Q^-sPimRP9wu^%I>Aqd{hj$Azf z%keY2wV=fVz8zqx0F%;u>k$=}TQMuU5maln9j+bQ%}$qhhgp~b0qladVrdB1ea@-p z3ccRWm_cS+0}|jYV6oPLc(%?u z=D!)V!@#j?(vxo=mG?nu19?HQzj|JqFwBrK%~zl$&^CKkfQ6!PDKwsdfm{ZKtZ#k% z3Si+%aAoEJ!@Q7_5KPCvy~cWL?E&+Lf^~re(v-#kYV(DuZDa&SFP^@%y#QqZ z#QxD9|LE0?QPu~upwQ3w+U~w?JowX>z>YLxx%uahlA%ph`!YQI<-x~ng~|$meg)z# z0Y3{R+u(oloUlXrTI*a`SlJOncwl%S{C*)gB3EmRzyl1SJcztTTmsI3?9ZMY?Ed>3 zf8)LPLxrWtdj*Q>&;IKVUxiM0$*J-O3#F2!&Ikh;7Z>r&H#6+uBzeG?_S$7N%EvM< z?2M*_^BM*bFbTn-3>X^AJ-07F*~^P-jo>4iSlCvcM!>7INN9|s!ey)3TA(bUgt9Dw z0|r{4^1<3Xv_j=D2#s}S6)H;xB`%0}*~<2?Yc;PQ^#NEo|iWe|)_@sKpI#bt!9JH0I8V#nSoJTA>}wXbQ^-u?Nbi zvTWAL95Yt{hjK|lG&t*pZ|(pA-s5rhmsVKdzyIZ3Vpu&L<}U6dHAYx=W)@({0gPAG zq0kwQPb7gk+X!`k^aZhQtAOMXVEh@&W2Q}j4P$uc6_!k(wuiH3TP!3LcAfLV2|ONO z*Mxw}++a9}ybA}h4aC_`PsOnBI~K+$9=crnNlAv|w= z1(KH@WDK&|1X4M38B24n4xGE>Pm_HR&kAHDd1aU==l{Z~11?R!eC_IcV$6iZbrdS8( z#+u&w>#LxLTjTs;$N-}d;A`#0_GvzH(v;iY>HqN~u_6a4OY}bYGH#=ePv%?xD9hCEfbosIv$VEpOluHkyhK2l)8g@F>Z!&cVuPSSE-yl;hF$h`y8pjDkT zpkMoHTUZrmyDU`MLi+e@e%1yZqlTv7tD|n%iHs|b<7ky%Z-PsY( z`T_3#n8!;Oi?29W6k?Nv%AX+u-L=`wM{=+7XqYO%1@V|8rkga{7to9;uKDB_WDEnd*5v5X1ORw%j`xijAD=g zx3oVS%c}sH-D;gv25wCF!}vHkWOzqo;TE`2ZfAj!3Iz#_of>ZczG6^Lwf&Sn;VyDU zw{au#rabuuv3SB#Va+kKH*MFW#jIm#bN=-R)AEbw<$cMAoC<(31}v1R1Z0Gdm!P}Y zT(h9`ln8JEIUZQ!R2M-_K8B51*z4HoVATK@p!oc{v^MUeTllJ17zX(!Xocrs4p3N4 z)1oZxg+N|W6f9=)CuX}_e8-B?a4RxgzaWrfay7~nw?O;4blVJJ7L#ff+!1_ox`&UaGu~_ zIOwAN@!-85`~x@;UUPi{F*BN2c?{Vm2MN@E4!{%^?pS%wC{`X}wvh)K-xrH5ZvJ_yy^#gsY z3=yoXh7}%DK-R*Lus9n({DU(4I^-m%0>t(ixdtl&0fV-G{f5v&Ga*AF&*b;cH6Yyg z`EdiR>`E|=aLb3lpjI7eW7f~~J4+XbQ1Y+95{Lb~i|>^^QW(mf3RZJ-J4_%7|BTW+ M>>IU0xA6S`1HzXf%>V!Z literal 0 HcmV?d00001 diff --git a/Package/release.cmd b/Package/release.cmd new file mode 100644 index 0000000..9eb2046 --- /dev/null +++ b/Package/release.cmd @@ -0,0 +1,8 @@ +@echo off +set TargetFramework=%1 +set ProjectName=%2 + +del "*.nupkg" +"..\..\oqtane.framework\oqtane.package\FixProps.exe" +"..\..\oqtane.framework\oqtane.package\nuget.exe" pack %ProjectName%.nuspec -Properties targetframework=%TargetFramework%;projectname=%ProjectName% +XCOPY "*.nupkg" "..\..\oqtane.framework\Oqtane.Server\Packages\" /Y \ No newline at end of file diff --git a/Package/release.sh b/Package/release.sh new file mode 100644 index 0000000..443bf64 --- /dev/null +++ b/Package/release.sh @@ -0,0 +1,7 @@ +TargetFramework=$1 +ProjectName=$2 + +find . -name "*.nupkg" -delete +"..\..\oqtane.framework\oqtane.package\FixProps.exe" +"..\..\oqtane.framework\oqtane.package\nuget.exe" pack %ProjectName%.nuspec -Properties targetframework=%TargetFramework%;projectname=%ProjectName% +cp -f "*.nupkg" "..\..\oqtane.framework\Oqtane.Server\Packages\" \ No newline at end of file diff --git a/SZUAbsolventenverein.Module.HallOfFame.sln b/SZUAbsolventenverein.Module.HallOfFame.sln new file mode 100644 index 0000000..ad7ea67 --- /dev/null +++ b/SZUAbsolventenverein.Module.HallOfFame.sln @@ -0,0 +1,47 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28621.142 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oqtane.Server", "..\oqtane.framework\Oqtane.Server\Oqtane.Server.csproj", "{3AB6FCC9-EFEB-4C0E-A2CF-8103914C5196}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SZUAbsolventenverein.Module.HallOfFame.Client", "Client\SZUAbsolventenverein.Module.HallOfFame.Client.csproj", "{AA8E58A1-CD09-4208-BF66-A8BB341FD669}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SZUAbsolventenverein.Module.HallOfFame.Server", "Server\SZUAbsolventenverein.Module.HallOfFame.Server.csproj", "{04B05448-788F-433D-92C0-FED35122D45A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SZUAbsolventenverein.Module.HallOfFame.Shared", "Shared\SZUAbsolventenverein.Module.HallOfFame.Shared.csproj", "{18D73F73-D7BE-4388-85BA-FBD9AC96FCA2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SZUAbsolventenverein.Module.HallOfFame.Package", "Package\SZUAbsolventenverein.Module.HallOfFame.Package.csproj", "{C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3AB6FCC9-EFEB-4C0E-A2CF-8103914C5196}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AB6FCC9-EFEB-4C0E-A2CF-8103914C5196}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA8E58A1-CD09-4208-BF66-A8BB341FD669}.Release|Any CPU.Build.0 = Release|Any CPU + {04B05448-788F-433D-92C0-FED35122D45A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04B05448-788F-433D-92C0-FED35122D45A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04B05448-788F-433D-92C0-FED35122D45A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04B05448-788F-433D-92C0-FED35122D45A}.Release|Any CPU.Build.0 = Release|Any CPU + {18D73F73-D7BE-4388-85BA-FBD9AC96FCA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18D73F73-D7BE-4388-85BA-FBD9AC96FCA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18D73F73-D7BE-4388-85BA-FBD9AC96FCA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18D73F73-D7BE-4388-85BA-FBD9AC96FCA2}.Release|Any CPU.Build.0 = Release|Any CPU + {C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C5CE512D-CBB7-4545-AF0F-9B6591A0C3A7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1D016F15-46FE-4726-8DFD-2E4FD4DC7668} + EndGlobalSection +EndGlobal diff --git a/Server/AssemblyInfo.cs b/Server/AssemblyInfo.cs new file mode 100644 index 0000000..013c97d --- /dev/null +++ b/Server/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Resources; +using Microsoft.Extensions.Localization; + +[assembly: RootNamespace("SZUAbsolventenverein.Module.HallOfFame.Server")] diff --git a/Server/Controllers/HallOfFameController.cs b/Server/Controllers/HallOfFameController.cs new file mode 100644 index 0000000..9196ebd --- /dev/null +++ b/Server/Controllers/HallOfFameController.cs @@ -0,0 +1,114 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; +using Oqtane.Shared; +using Oqtane.Enums; +using Oqtane.Infrastructure; +using SZUAbsolventenverein.Module.HallOfFame.Services; +using Oqtane.Controllers; +using System.Net; +using System.Threading.Tasks; + +namespace SZUAbsolventenverein.Module.HallOfFame.Controllers +{ + [Route(ControllerRoutes.ApiRoute)] + public class HallOfFameController : ModuleControllerBase + { + private readonly IHallOfFameService _HallOfFameService; + + public HallOfFameController(IHallOfFameService HallOfFameService, ILogManager logger, IHttpContextAccessor accessor) : base(logger, accessor) + { + _HallOfFameService = HallOfFameService; + } + + // GET: api/?moduleid=x + [HttpGet] + [Authorize(Policy = PolicyNames.ViewModule)] + public async Task> Get(string moduleid) + { + int ModuleId; + if (int.TryParse(moduleid, out ModuleId) && IsAuthorizedEntityId(EntityNames.Module, ModuleId)) + { + return await _HallOfFameService.GetHallOfFamesAsync(ModuleId); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame Get Attempt {ModuleId}", moduleid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } + } + + // GET api//5 + [HttpGet("{id}/{moduleid}")] + [Authorize(Policy = PolicyNames.ViewModule)] + public async Task Get(int id, int moduleid) + { + Models.HallOfFame HallOfFame = await _HallOfFameService.GetHallOfFameAsync(id, moduleid); + if (HallOfFame != null && IsAuthorizedEntityId(EntityNames.Module, HallOfFame.ModuleId)) + { + return HallOfFame; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame Get Attempt {HallOfFameId} {ModuleId}", id, moduleid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } + } + + // POST api/ + [HttpPost] + [Authorize(Policy = PolicyNames.EditModule)] + public async Task Post([FromBody] Models.HallOfFame HallOfFame) + { + if (ModelState.IsValid && IsAuthorizedEntityId(EntityNames.Module, HallOfFame.ModuleId)) + { + HallOfFame = await _HallOfFameService.AddHallOfFameAsync(HallOfFame); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame Post Attempt {HallOfFame}", HallOfFame); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + HallOfFame = null; + } + return HallOfFame; + } + + // PUT api//5 + [HttpPut("{id}")] + [Authorize(Policy = PolicyNames.EditModule)] + public async Task Put(int id, [FromBody] Models.HallOfFame HallOfFame) + { + if (ModelState.IsValid && HallOfFame.HallOfFameId == id && IsAuthorizedEntityId(EntityNames.Module, HallOfFame.ModuleId)) + { + HallOfFame = await _HallOfFameService.UpdateHallOfFameAsync(HallOfFame); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame Put Attempt {HallOfFame}", HallOfFame); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + HallOfFame = null; + } + return HallOfFame; + } + + // DELETE api//5 + [HttpDelete("{id}/{moduleid}")] + [Authorize(Policy = PolicyNames.EditModule)] + public async Task Delete(int id, int moduleid) + { + Models.HallOfFame HallOfFame = await _HallOfFameService.GetHallOfFameAsync(id, moduleid); + if (HallOfFame != null && IsAuthorizedEntityId(EntityNames.Module, HallOfFame.ModuleId)) + { + await _HallOfFameService.DeleteHallOfFameAsync(id, HallOfFame.ModuleId); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame Delete Attempt {HallOfFameId} {ModuleId}", id, moduleid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + } + } + } +} diff --git a/Server/Manager/HallOfFameManager.cs b/Server/Manager/HallOfFameManager.cs new file mode 100644 index 0000000..afc8ed2 --- /dev/null +++ b/Server/Manager/HallOfFameManager.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using Oqtane.Modules; +using Oqtane.Models; +using Oqtane.Infrastructure; +using Oqtane.Interfaces; +using Oqtane.Enums; +using Oqtane.Repository; +using SZUAbsolventenverein.Module.HallOfFame.Repository; +using System.Threading.Tasks; + +namespace SZUAbsolventenverein.Module.HallOfFame.Manager +{ + public class HallOfFameManager : MigratableModuleBase, IInstallable, IPortable, ISearchable + { + private readonly IHallOfFameRepository _HallOfFameRepository; + private readonly IDBContextDependencies _DBContextDependencies; + + public HallOfFameManager(IHallOfFameRepository HallOfFameRepository, IDBContextDependencies DBContextDependencies) + { + _HallOfFameRepository = HallOfFameRepository; + _DBContextDependencies = DBContextDependencies; + } + + public bool Install(Tenant tenant, string version) + { + return Migrate(new HallOfFameContext(_DBContextDependencies), tenant, MigrationType.Up); + } + + public bool Uninstall(Tenant tenant) + { + return Migrate(new HallOfFameContext(_DBContextDependencies), tenant, MigrationType.Down); + } + + public string ExportModule(Oqtane.Models.Module module) + { + string content = ""; + List HallOfFames = _HallOfFameRepository.GetHallOfFames(module.ModuleId).ToList(); + if (HallOfFames != null) + { + content = JsonSerializer.Serialize(HallOfFames); + } + return content; + } + + public void ImportModule(Oqtane.Models.Module module, string content, string version) + { + List HallOfFames = null; + if (!string.IsNullOrEmpty(content)) + { + HallOfFames = JsonSerializer.Deserialize>(content); + } + if (HallOfFames != null) + { + foreach(var HallOfFame in HallOfFames) + { + _HallOfFameRepository.AddHallOfFame(new Models.HallOfFame { ModuleId = module.ModuleId, Name = HallOfFame.Name }); + } + } + } + + public Task> GetSearchContentsAsync(PageModule pageModule, DateTime lastIndexedOn) + { + var searchContentList = new List(); + + foreach (var HallOfFame in _HallOfFameRepository.GetHallOfFames(pageModule.ModuleId)) + { + if (HallOfFame.ModifiedOn >= lastIndexedOn) + { + searchContentList.Add(new SearchContent + { + EntityName = "SZUAbsolventenvereinHallOfFame", + EntityId = HallOfFame.HallOfFameId.ToString(), + Title = HallOfFame.Name, + Body = HallOfFame.Name, + ContentModifiedBy = HallOfFame.ModifiedBy, + ContentModifiedOn = HallOfFame.ModifiedOn + }); + } + } + + return Task.FromResult(searchContentList); + } + } +} diff --git a/Server/Migrations/01000000_InitializeModule.cs b/Server/Migrations/01000000_InitializeModule.cs new file mode 100644 index 0000000..bf478df --- /dev/null +++ b/Server/Migrations/01000000_InitializeModule.cs @@ -0,0 +1,30 @@ +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.00")] + public class InitializeModule : MultiDatabaseMigration + { + public InitializeModule(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + var entityBuilder = new HallOfFameEntityBuilder(migrationBuilder, ActiveDatabase); + entityBuilder.Create(); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + var entityBuilder = new HallOfFameEntityBuilder(migrationBuilder, ActiveDatabase); + entityBuilder.Drop(); + } + } +} diff --git a/Server/Migrations/EntityBuilders/HallOfFameEntityBuilder.cs b/Server/Migrations/EntityBuilders/HallOfFameEntityBuilder.cs new file mode 100644 index 0000000..ad61792 --- /dev/null +++ b/Server/Migrations/EntityBuilders/HallOfFameEntityBuilder.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations.Operations; +using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations; +using Oqtane.Migrations.EntityBuilders; + +namespace SZUAbsolventenverein.Module.HallOfFame.Migrations.EntityBuilders +{ + public class HallOfFameEntityBuilder : AuditableBaseEntityBuilder + { + private const string _entityTableName = "SZUAbsolventenvereinHallOfFame"; + private readonly PrimaryKey _primaryKey = new("PK_SZUAbsolventenvereinHallOfFame", x => x.HallOfFameId); + private readonly ForeignKey _moduleForeignKey = new("FK_SZUAbsolventenvereinHallOfFame_Module", x => x.ModuleId, "Module", "ModuleId", ReferentialAction.Cascade); + + public HallOfFameEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database) + { + EntityTableName = _entityTableName; + PrimaryKey = _primaryKey; + ForeignKeys.Add(_moduleForeignKey); + } + + protected override HallOfFameEntityBuilder BuildTable(ColumnsBuilder table) + { + HallOfFameId = AddAutoIncrementColumn(table,"HallOfFameId"); + ModuleId = AddIntegerColumn(table,"ModuleId"); + Name = AddMaxStringColumn(table,"Name"); + AddAuditableColumns(table); + return this; + } + + public OperationBuilder HallOfFameId { get; set; } + public OperationBuilder ModuleId { get; set; } + public OperationBuilder Name { get; set; } + } +} diff --git a/Server/Repository/HallOfFameContext.cs b/Server/Repository/HallOfFameContext.cs new file mode 100644 index 0000000..88d3d62 --- /dev/null +++ b/Server/Repository/HallOfFameContext.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Http; +using Oqtane.Modules; +using Oqtane.Repository; +using Oqtane.Infrastructure; +using Oqtane.Repository.Databases.Interfaces; + +namespace SZUAbsolventenverein.Module.HallOfFame.Repository +{ + public class HallOfFameContext : DBContextBase, ITransientService, IMultiDatabase + { + public virtual DbSet HallOfFame { get; set; } + + public HallOfFameContext(IDBContextDependencies DBContextDependencies) : base(DBContextDependencies) + { + // ContextBase handles multi-tenant database connections + } + + protected override void OnModelCreating(ModelBuilder builder) + { + base.OnModelCreating(builder); + + builder.Entity().ToTable(ActiveDatabase.RewriteName("SZUAbsolventenvereinHallOfFame")); + } + } +} diff --git a/Server/Repository/HallOfFameRepository.cs b/Server/Repository/HallOfFameRepository.cs new file mode 100644 index 0000000..5f50af0 --- /dev/null +++ b/Server/Repository/HallOfFameRepository.cs @@ -0,0 +1,75 @@ +using Microsoft.EntityFrameworkCore; +using System.Linq; +using System.Collections.Generic; +using Oqtane.Modules; + +namespace SZUAbsolventenverein.Module.HallOfFame.Repository +{ + public interface IHallOfFameRepository + { + IEnumerable GetHallOfFames(int ModuleId); + Models.HallOfFame GetHallOfFame(int HallOfFameId); + Models.HallOfFame GetHallOfFame(int HallOfFameId, bool tracking); + Models.HallOfFame AddHallOfFame(Models.HallOfFame HallOfFame); + Models.HallOfFame UpdateHallOfFame(Models.HallOfFame HallOfFame); + void DeleteHallOfFame(int HallOfFameId); + } + + public class HallOfFameRepository : IHallOfFameRepository, ITransientService + { + private readonly IDbContextFactory _factory; + + public HallOfFameRepository(IDbContextFactory factory) + { + _factory = factory; + } + + public IEnumerable GetHallOfFames(int ModuleId) + { + using var db = _factory.CreateDbContext(); + return db.HallOfFame.Where(item => item.ModuleId == ModuleId).ToList(); + } + + public Models.HallOfFame GetHallOfFame(int HallOfFameId) + { + return GetHallOfFame(HallOfFameId, true); + } + + public Models.HallOfFame GetHallOfFame(int HallOfFameId, bool tracking) + { + using var db = _factory.CreateDbContext(); + if (tracking) + { + return db.HallOfFame.Find(HallOfFameId); + } + else + { + return db.HallOfFame.AsNoTracking().FirstOrDefault(item => item.HallOfFameId == HallOfFameId); + } + } + + public Models.HallOfFame AddHallOfFame(Models.HallOfFame HallOfFame) + { + using var db = _factory.CreateDbContext(); + db.HallOfFame.Add(HallOfFame); + db.SaveChanges(); + return HallOfFame; + } + + public Models.HallOfFame UpdateHallOfFame(Models.HallOfFame HallOfFame) + { + using var db = _factory.CreateDbContext(); + db.Entry(HallOfFame).State = EntityState.Modified; + db.SaveChanges(); + return HallOfFame; + } + + public void DeleteHallOfFame(int HallOfFameId) + { + using var db = _factory.CreateDbContext(); + Models.HallOfFame HallOfFame = db.HallOfFame.Find(HallOfFameId); + db.HallOfFame.Remove(HallOfFame); + db.SaveChanges(); + } + } +} diff --git a/Server/SZUAbsolventenverein.Module.HallOfFame.Server.csproj b/Server/SZUAbsolventenverein.Module.HallOfFame.Server.csproj new file mode 100644 index 0000000..33fd804 --- /dev/null +++ b/Server/SZUAbsolventenverein.Module.HallOfFame.Server.csproj @@ -0,0 +1,37 @@ + + + + net9.0 + true + 1.0.0 + SZUAbsolventenverein.Module.HallOfFame + SZUAbsolventenverein + SZUAbsolventenverein + The Hall of Fame module displays selected individuals or achievements within the CMS. Entries are shown online, can be exported as a PDF, and are only published with user consen. + SZUAbsolventenverein + SZUAbsolventenverein.Module.HallOfFame.Server.Oqtane + true + + + + + + + + + + + + + + + + + + + + + ..\..\oqtane.framework\Oqtane.Server\bin\Debug\net9.0\Oqtane.Server.dll + ..\..\oqtane.framework\Oqtane.Server\bin\Debug\net9.0\Oqtane.Shared.dll + + diff --git a/Server/Services/HallOfFameService.cs b/Server/Services/HallOfFameService.cs new file mode 100644 index 0000000..006e13e --- /dev/null +++ b/Server/Services/HallOfFameService.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Oqtane.Enums; +using Oqtane.Infrastructure; +using Oqtane.Models; +using Oqtane.Security; +using Oqtane.Shared; +using SZUAbsolventenverein.Module.HallOfFame.Repository; + +namespace SZUAbsolventenverein.Module.HallOfFame.Services +{ + public class ServerHallOfFameService : IHallOfFameService + { + private readonly IHallOfFameRepository _HallOfFameRepository; + private readonly IUserPermissions _userPermissions; + private readonly ILogManager _logger; + private readonly IHttpContextAccessor _accessor; + private readonly Alias _alias; + + public ServerHallOfFameService(IHallOfFameRepository HallOfFameRepository, IUserPermissions userPermissions, ITenantManager tenantManager, ILogManager logger, IHttpContextAccessor accessor) + { + _HallOfFameRepository = HallOfFameRepository; + _userPermissions = userPermissions; + _logger = logger; + _accessor = accessor; + _alias = tenantManager.GetAlias(); + } + + public Task> GetHallOfFamesAsync(int ModuleId) + { + if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View)) + { + return Task.FromResult(_HallOfFameRepository.GetHallOfFames(ModuleId).ToList()); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame Get Attempt {ModuleId}", ModuleId); + return null; + } + } + + public Task GetHallOfFameAsync(int HallOfFameId, int ModuleId) + { + if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View)) + { + return Task.FromResult(_HallOfFameRepository.GetHallOfFame(HallOfFameId)); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame Get Attempt {HallOfFameId} {ModuleId}", HallOfFameId, ModuleId); + return null; + } + } + + public Task AddHallOfFameAsync(Models.HallOfFame HallOfFame) + { + if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, HallOfFame.ModuleId, PermissionNames.Edit)) + { + HallOfFame = _HallOfFameRepository.AddHallOfFame(HallOfFame); + _logger.Log(LogLevel.Information, this, LogFunction.Create, "HallOfFame Added {HallOfFame}", HallOfFame); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame Add Attempt {HallOfFame}", HallOfFame); + HallOfFame = null; + } + return Task.FromResult(HallOfFame); + } + + public Task UpdateHallOfFameAsync(Models.HallOfFame HallOfFame) + { + if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, HallOfFame.ModuleId, PermissionNames.Edit)) + { + HallOfFame = _HallOfFameRepository.UpdateHallOfFame(HallOfFame); + _logger.Log(LogLevel.Information, this, LogFunction.Update, "HallOfFame Updated {HallOfFame}", HallOfFame); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame Update Attempt {HallOfFame}", HallOfFame); + HallOfFame = null; + } + return Task.FromResult(HallOfFame); + } + + public Task DeleteHallOfFameAsync(int HallOfFameId, int ModuleId) + { + if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.Edit)) + { + _HallOfFameRepository.DeleteHallOfFame(HallOfFameId); + _logger.Log(LogLevel.Information, this, LogFunction.Delete, "HallOfFame Deleted {HallOfFameId}", HallOfFameId); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized HallOfFame Delete Attempt {HallOfFameId} {ModuleId}", HallOfFameId, ModuleId); + } + return Task.CompletedTask; + } + } +} diff --git a/Server/Startup/ServerStartup.cs b/Server/Startup/ServerStartup.cs new file mode 100644 index 0000000..73882f4 --- /dev/null +++ b/Server/Startup/ServerStartup.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Oqtane.Infrastructure; +using SZUAbsolventenverein.Module.HallOfFame.Repository; +using SZUAbsolventenverein.Module.HallOfFame.Services; + +namespace SZUAbsolventenverein.Module.HallOfFame.Startup +{ + public class ServerStartup : IServerStartup + { + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + // not implemented + } + + public void ConfigureMvc(IMvcBuilder mvcBuilder) + { + // not implemented + } + + public void ConfigureServices(IServiceCollection services) + { + services.AddTransient(); + services.AddDbContextFactory(opt => { }, ServiceLifetime.Transient); + } + } +} diff --git a/Server/wwwroot/Module.css b/Server/wwwroot/Module.css new file mode 100644 index 0000000..0856a26 --- /dev/null +++ b/Server/wwwroot/Module.css @@ -0,0 +1 @@ +/* Module Custom Styles */ \ No newline at end of file diff --git a/Server/wwwroot/Module.js b/Server/wwwroot/Module.js new file mode 100644 index 0000000..6aec395 --- /dev/null +++ b/Server/wwwroot/Module.js @@ -0,0 +1,5 @@ +/* Module Script */ +var SZUAbsolventenverein = SZUAbsolventenverein || {}; + +SZUAbsolventenverein.HallOfFame = { +}; \ No newline at end of file diff --git a/Shared/Models/HallOfFame.cs b/Shared/Models/HallOfFame.cs new file mode 100644 index 0000000..140aead --- /dev/null +++ b/Shared/Models/HallOfFame.cs @@ -0,0 +1,21 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Oqtane.Models; + +namespace SZUAbsolventenverein.Module.HallOfFame.Models +{ + [Table("SZUAbsolventenvereinHallOfFame")] + public class HallOfFame : IAuditable + { + [Key] + public int HallOfFameId { get; set; } + public int ModuleId { get; set; } + public string Name { get; set; } + + public string CreatedBy { get; set; } + public DateTime CreatedOn { get; set; } + public string ModifiedBy { get; set; } + public DateTime ModifiedOn { get; set; } + } +} diff --git a/Shared/SZUAbsolventenverein.Module.HallOfFame.Shared.csproj b/Shared/SZUAbsolventenverein.Module.HallOfFame.Shared.csproj new file mode 100644 index 0000000..a0e0308 --- /dev/null +++ b/Shared/SZUAbsolventenverein.Module.HallOfFame.Shared.csproj @@ -0,0 +1,22 @@ + + + + net9.0 + 1.0.0 + SZUAbsolventenverein.Module.HallOfFame + SZUAbsolventenverein + SZUAbsolventenverein + The Hall of Fame module displays selected individuals or achievements within the CMS. Entries are shown online, can be exported as a PDF, and are only published with user consen. + SZUAbsolventenverein + SZUAbsolventenverein.Module.HallOfFame.Shared.Oqtane + + + + + + + + ..\..\oqtane.framework\Oqtane.Server\bin\Debug\net9.0\Oqtane.Shared.dll + + + diff --git a/template.json b/template.json new file mode 100644 index 0000000..950fa61 --- /dev/null +++ b/template.json @@ -0,0 +1,6 @@ +{ + "Title": "Default Module Template", + "Type": "External", + "Version": "5.2.0", + "Namespace": "SZUAbsolventenverein.Module.HallOfFame" +}