From a31292e4768c2a24afb826e73b263f9316205071 Mon Sep 17 00:00:00 2001 From: KoCoder Date: Thu, 4 Dec 2025 22:57:22 +0100 Subject: [PATCH] NEW: Zusagen / Absagen Chart (PoC) --- Client/Interop.cs | 15 +++ .../Edit.razor | 43 ++++++- Client/Services/EventRegistrationService.cs | 34 ++---- .../EventRegistrationController.cs | 18 +++ Server/Services/EventRegistrationService.cs | 110 ++++++------------ .../Module.js | 21 ++++ 6 files changed, 138 insertions(+), 103 deletions(-) diff --git a/Client/Interop.cs b/Client/Interop.cs index 73f008a..78135c5 100644 --- a/Client/Interop.cs +++ b/Client/Interop.cs @@ -11,5 +11,20 @@ namespace SZUAbsolventenverein.Module.EventRegistration { _jsRuntime = jsRuntime; } + + public async Task CreateChart(string divid, string type, string[] labels, object[] datasets, object options) + { + try + { + await _jsRuntime.InvokeVoidAsync( + "SZUAbsolventenverein.EventRegistration.createChart", + divid, type, (object) labels, (object) datasets, options); + } + catch + { + // handle exception + } + } + } } diff --git a/Client/Modules/SZUAbsolventenverein.Module.EventRegistration/Edit.razor b/Client/Modules/SZUAbsolventenverein.Module.EventRegistration/Edit.razor index 6edc5af..d13d989 100644 --- a/Client/Modules/SZUAbsolventenverein.Module.EventRegistration/Edit.razor +++ b/Client/Modules/SZUAbsolventenverein.Module.EventRegistration/Edit.razor @@ -42,6 +42,7 @@ { } +
@code { @@ -53,7 +54,9 @@ public override List Resources => new List() { - new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" } + new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "ChartJS", Url = "https://cdn.jsdelivr.net/npm/chart.js" }, + new Resource { ResourceType = ResourceType.Script, Bundle = "ChartJS", Url = ModulePath() + "Module.js"} }; @@ -71,6 +74,9 @@ private DateTime _createdon; private string _modifiedby; private DateTime _modifiedon; + + bool _refresh = false; + private List _responses; protected override async Task OnInitializedAsync() { @@ -92,6 +98,10 @@ _modifiedby = EventRegistration.ModifiedBy; _modifiedon = EventRegistration.ModifiedOn; } + + _responses = await EventRegistrationService.GetEventResponses(_id, ModuleState.ModuleId); + Console.WriteLine("Responses count: " + (_responses != null ? _responses.Count.ToString() : "null")); + _refresh = true; } } catch (Exception ex) @@ -101,6 +111,37 @@ } } + protected override async Task OnAfterRenderAsync(bool firstRender) + { + try + { + await base.OnAfterRenderAsync(firstRender); + + Console.WriteLine("Responses count: " + (_responses != null ? _responses.Count.ToString() : "null")); + + if (_refresh && _responses != null) + { + List labels = new List(); + List datasets = new List(); + string[] colors = new string[] { "#FF0000", "#FF8000", "#FFFF00", "#00FF00", "#00FFFF", "#0080FF", "#0000FF", "#8000FF", "#FF00FF", "#CCCCCC" }; + + labels.AddRange("Zusage", "Absage"); + datasets.Add(new { label = "DS1", data = new int[] { _responses.Count(r => r.ResponseType == true), _responses.Count(r => r.ResponseType == false) }, fill = false, backgroundColor = colors }); + object options = new { maintainAspectRatio = false, legend = new { display = true, position = "bottom", labels = new { fontColor = "white", fontSize = 16 } } }; + + var interop = new Interop(JSRuntime); + await interop.CreateChart("chart", "pie", labels.ToArray(), datasets.ToArray(), options); + + _refresh = false; + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Rendering Chart {Error}", ex.Message); + AddModuleMessage("Error Rendering Chart", MessageType.Error); + } + } + private async Task Save() { try diff --git a/Client/Services/EventRegistrationService.cs b/Client/Services/EventRegistrationService.cs index 6e45618..10589b1 100644 --- a/Client/Services/EventRegistrationService.cs +++ b/Client/Services/EventRegistrationService.cs @@ -14,28 +14,7 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services public EventRegistrationService(HttpClient http, SiteState siteState) : base(http, siteState) { } private string Apiurl => CreateApiUrl("EventRegistration"); - - /*public async Task> GetEventRegistrationsAsync(int ModuleId) - { - List EventRegistrations = await GetJsonAsync>(CreateAuthorizationPolicyUrl($"{Apiurl}?moduleid={ModuleId}", EntityNames.Module, ModuleId), Enumerable.Empty().ToList()); - return EventRegistrations.OrderBy(item => item.Name).ToList(); - } - - public async Task GetEventRegistrationAsync(int EventRegistrationId, int ModuleId) - { - return await GetJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{EventRegistrationId}/{ModuleId}", EntityNames.Module, ModuleId)); - } - - public async Task AddEventRegistrationAsync(Models.Event EventRegistration) - { - return await PostJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}", EntityNames.Module, EventRegistration.ModuleId), EventRegistration); - } - - public async Task UpdateEventRegistrationAsync(Models.Event EventRegistration) - { - return await PutJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{EventRegistration.EventRegistrationId}", EntityNames.Module, EventRegistration.ModuleId), EventRegistration); - }*/ - + public async Task> GetEventsAsync(int ModuleId) { List EventRegistrations = await GetJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}?moduleid={ModuleId}", EntityNames.Module, ModuleId), Enumerable.Empty().ToList()); @@ -51,9 +30,9 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services return await PostJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}", EntityNames.Module, NewEvent.ModuleId), NewEvent); } - public async Task UpdateEventAsync(Event NewEvent) + public async Task UpdateEventAsync(Event UpdatedEvent) { - return await PutJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{NewEvent.EventId}", EntityNames.Module, NewEvent.ModuleId), NewEvent); + return await PutJsonAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{UpdatedEvent.EventId}", EntityNames.Module, UpdatedEvent.ModuleId), UpdatedEvent); } public async Task DeleteEventAsync(int EventId, int ModuleId) @@ -76,7 +55,12 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services return await GetJsonAsync<(Event, Response)>(CreateAuthorizationPolicyUrl($"{Apiurl}/details/{EventId}/{ModuleId}", EntityNames.Module, ModuleId)); } - public Task> GetEventResponses(int EventId, int ModuleId) + public async Task> GetEventResponses(int EventId, int ModuleId) + { + return await GetJsonAsync>(CreateAuthorizationPolicyUrl($"{Apiurl}/all-responses/{EventId}/{ModuleId}", EntityNames.Module, ModuleId)); + } + + public Task> GetRecommendedEventResponses(int EventId, int MouleId) { throw new System.NotImplementedException(); } diff --git a/Server/Controllers/EventRegistrationController.cs b/Server/Controllers/EventRegistrationController.cs index c8fb682..657d221 100644 --- a/Server/Controllers/EventRegistrationController.cs +++ b/Server/Controllers/EventRegistrationController.cs @@ -130,6 +130,24 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Controllers return (null, null); } } + + // GET api//5 + [HttpGet("all-respones/{id}/{moduleid}")] + [Authorize(Policy = PolicyNames.ViewModule)] + public async Task> GetResponses(int id, int moduleid) + { + List eventResponses = await _EventRegistrationService.GetEventResponses(id, moduleid); + if (eventResponses != null && IsAuthorizedEntityId(EntityNames.Module, moduleid)) + { + return eventResponses; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized EventRegistration Get Attempt {EventRegistrationId} {ModuleId}", id, moduleid); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } + } // TODO: Add Event Response Endpoints. } diff --git a/Server/Services/EventRegistrationService.cs b/Server/Services/EventRegistrationService.cs index 2a6f537..8e6d304 100644 --- a/Server/Services/EventRegistrationService.cs +++ b/Server/Services/EventRegistrationService.cs @@ -121,6 +121,34 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services return null; } } + + public Task> GetEventsAsync(int ModuleId) + { + if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View)) + { + return Task.FromResult(_EventRepository.GetEvents(ModuleId).ToList()); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Events Get Attempt {ModuleId}", ModuleId); + return null; + } + } + + public Task UpdateEventAsync(Event UpdatedEvent) + { + if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, UpdatedEvent.ModuleId, PermissionNames.Edit)) + { + UpdatedEvent = _EventRepository.UpdateEvent(UpdatedEvent); + _logger.Log(LogLevel.Information, this, LogFunction.Update, "Event Updated {NewEvent}", UpdatedEvent); + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Event Update Attempt {NewEvent}", UpdatedEvent); + UpdatedEvent = null; + } + return Task.FromResult(UpdatedEvent); + } public Task<(Event, Response)> GetEventDetails(int EventId, int ModuleId) { @@ -148,86 +176,14 @@ namespace SZUAbsolventenverein.Module.EventRegistration.Services _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Event Response Get Attempt {ModuleId}", ModuleId); return null; } + } + + public Task> GetRecommendedEventResponses(int EventId, int MouleId) + { throw new System.NotImplementedException(); } - public Task> GetEventsAsync(int ModuleId) - { - if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View)) - { - return Task.FromResult(_EventRepository.GetEvents(ModuleId).ToList()); - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Events Get Attempt {ModuleId}", ModuleId); - return null; - } - } - - public Task UpdateEventAsync(Event NewEvent) - { - if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, NewEvent.ModuleId, PermissionNames.Edit)) - { - NewEvent = _EventRepository.UpdateEvent(NewEvent); - _logger.Log(LogLevel.Information, this, LogFunction.Update, "Event Updated {NewEvent}", NewEvent); - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Event Update Attempt {NewEvent}", NewEvent); - NewEvent = null; - } - return Task.FromResult(NewEvent); - } - - // TODO: Implement the methods for EventResponses - - /* - - public Task GetEventRegistrationAsync(int EventRegistrationId, int ModuleId) - { - if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, ModuleId, PermissionNames.View)) - { - return Task.FromResult(_EventRegistrationRepository.GetEventRegistration(EventRegistrationId)); - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized EventRegistration Get Attempt {EventRegistrationId} {ModuleId}", EventRegistrationId, ModuleId); - return null; - } - } - - public Task AddEventRegistrationAsync(Models.Event EventRegistration) - { - if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, EventRegistration.ModuleId, PermissionNames.Edit)) - { - EventRegistration = _EventRegistrationRepository.AddEventRegistration(EventRegistration); - _logger.Log(LogLevel.Information, this, LogFunction.Create, "EventRegistration Added {EventRegistration}", EventRegistration); - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized EventRegistration Add Attempt {EventRegistration}", EventRegistration); - EventRegistration = null; - } - return Task.FromResult(EventRegistration); - } - - public Task UpdateEventRegistrationAsync(Models.Event EventRegistration) - { - if (_userPermissions.IsAuthorized(_accessor.HttpContext.User, _alias.SiteId, EntityNames.Module, EventRegistration.ModuleId, PermissionNames.Edit)) - { - EventRegistration = _EventRegistrationRepository.UpdateEventRegistration(EventRegistration); - _logger.Log(LogLevel.Information, this, LogFunction.Update, "EventRegistration Updated {EventRegistration}", EventRegistration); - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized EventRegistration Update Attempt {EventRegistration}", EventRegistration); - EventRegistration = null; - } - return Task.FromResult(EventRegistration); - } - - }*/ - + private void SendEventResponseNotification(string subject, string body) { User user = _UserRepository.GetUser(_accessor.HttpContext.User.UserId()); diff --git a/Server/wwwroot/Modules/SZUAbsolventenverein.Module.EventRegistration/Module.js b/Server/wwwroot/Modules/SZUAbsolventenverein.Module.EventRegistration/Module.js index 7e346b4..472b49d 100644 --- a/Server/wwwroot/Modules/SZUAbsolventenverein.Module.EventRegistration/Module.js +++ b/Server/wwwroot/Modules/SZUAbsolventenverein.Module.EventRegistration/Module.js @@ -2,4 +2,25 @@ var SZUAbsolventenverein = SZUAbsolventenverein || {}; SZUAbsolventenverein.EventRegistration = { + createChart: async function (divid, type, labels, datasets, options) { + var container = document.getElementById(divid); + if (container.hasChildNodes()) { + while (container.firstChild) { + container.removeChild(container.firstChild); + } + } + var canvas = document.createElement('canvas'); + canvas.id = divid + '-canvas'; + container.appendChild(canvas); + var ctx = canvas.getContext('2d'); + var chart = new Chart(ctx, { + type: type, + data: { + labels: labels, + datasets: datasets + }, + options: options + }); + } + }; \ No newline at end of file