From c554af94790e7e13c9bdb70182286e28b55d7330 Mon Sep 17 00:00:00 2001 From: LD-Reborn Date: Sun, 23 Nov 2025 13:57:02 +0100 Subject: [PATCH 1/3] Implemented user settings view --- src/Controllers/SettingsController.cs | 57 +++++++++- src/Controllers/UsersController.cs | 14 +-- src/Helpers/UsersHelper.cs | 10 ++ src/Models/SettingsRequestModels.cs | 9 ++ src/Models/SettingsResponseModels.cs | 8 ++ src/Models/UserSettingsModel.cs | 6 + src/Resources/Views.Settings.User.de.resx | 67 +++++++++++ src/Views/Settings/User.cshtml | 133 +++++++++++++++++++++- 8 files changed, 286 insertions(+), 18 deletions(-) create mode 100644 src/Models/UserSettingsModel.cs create mode 100644 src/Resources/Views.Settings.User.de.resx diff --git a/src/Controllers/SettingsController.cs b/src/Controllers/SettingsController.cs index 713cc57..bcdb255 100644 --- a/src/Controllers/SettingsController.cs +++ b/src/Controllers/SettingsController.cs @@ -3,11 +3,7 @@ using Microsoft.AspNetCore.Mvc; using Novell.Directory.Ldap; using Berufsschule_HAM.Models; using Berufsschule_HAM.Helpers; -using System.Security.Cryptography; -using System.Text; using Microsoft.AspNetCore.Authorization; -using System.Text.Json; -using System.Buffers.Text; [Authorize] [Route("[controller]")] @@ -23,11 +19,60 @@ public class SettingsController : Controller } [HttpGet("User")] - public new IActionResult User() + public async Task UserAsync() { - return View(); + try + { + var userID = User.Identity?.Name ?? throw new Exception("No name specified"); + UserSettingsModel userSettingsModel = new() + { + userModel = await _ldap.GetUserByUidAsync(userID) + }; + return View(userSettingsModel); + } catch (Exception ex) + { + _logger.LogWarning("An exception happened when trying to show user settings view: {ex.Message} - {ex.StackTrace}", [ex.Message, ex.StackTrace]); + return Redirect("/Home/Logout"); + } } + [HttpPut("User")] + public async Task UpdateUserAsync([FromBody]UserUpdateRequestModel userUpdateRequestModel) + { + if (userUpdateRequestModel is null) + { + return new() {Success = false, ErrorMessage = "userUpdateRequestModel is null"}; + } + try + { + var userID = User.Identity?.Name ?? throw new Exception("No name specified"); + bool anyUpdated = false; + if (userUpdateRequestModel.Password is not null && userUpdateRequestModel.Password.Length > 0) + { + await _ldap.UpdateUser(userID, "userPassword", await UsersHelper.HashPassword(_ldap, userUpdateRequestModel.Password)); + anyUpdated = true; + } + if (userUpdateRequestModel.Image is not null && userUpdateRequestModel.Image.Length > 0) + { + await _ldap.UpdateUser(userID, "jpegPhoto", userUpdateRequestModel.Image); + anyUpdated = true; + } + if (anyUpdated) + { + return new() {Success = true}; + } + else + { + return new() {Success = false, ErrorMessage = "Nothing was updated"}; + } + } catch (Exception ex) + { + _logger.LogWarning("An exception happened when trying to update a user: {ex.Message} - {ex.StackTrace}", [ex.Message, ex.StackTrace]); + return new() {Success = false, ErrorMessage = ex.Message}; + } + } + + [Authorize(Roles = "CanManageSettings")] [HttpGet("Admin")] public async Task AdminAsync() diff --git a/src/Controllers/UsersController.cs b/src/Controllers/UsersController.cs index 5e4fd51..76b5378 100644 --- a/src/Controllers/UsersController.cs +++ b/src/Controllers/UsersController.cs @@ -70,7 +70,6 @@ public class UsersController : Controller } try { - Task settingsTask = _ldap.GetAdminSettingsModelAsync(); string? jpegPhoto = requestModel.JpegPhoto; string? title = requestModel.Title; string userPassword = requestModel.UserPassword ?? ""; @@ -81,10 +80,7 @@ public class UsersController : Controller description ??= new() {Address = new(), BirthDate = "", Workplace = "", Groups = []}; if (!userPassword.StartsWith('{')) { - AdminSettingsModel settings = await settingsTask; - byte[] passwordBytes = Encoding.UTF8.GetBytes(userPassword); - byte[] hashedPassword = settings.hashAlgorithm?.ComputeHash(passwordBytes) ?? throw new Exception("Hash algorithm not instantiated yet"); - userPassword = $"{{{settings.DefaultHashAlgorithm.ToUpperInvariant()}}}{Convert.ToBase64String(hashedPassword)}"; + userPassword = await UsersHelper.HashPassword(_ldap, userPassword); } LdapAttributeSet attributeSet = @@ -118,7 +114,6 @@ public class UsersController : Controller } try { - Task settingsTask = _ldap.GetAdminSettingsModelAsync(); string uid = requestModel.Uid; UserModel? user = null; if (requestModel.NewUid is not null && requestModel.NewUid.Length > 0) @@ -140,11 +135,8 @@ public class UsersController : Controller await _ldap.UpdateUser(uid, "jpegPhoto", requestModel.JpegPhoto); } if (requestModel.UserPassword is not null && requestModel.UserPassword.Length > 0) - { - AdminSettingsModel settings = await settingsTask; - byte[] passwordBytes = Encoding.UTF8.GetBytes(requestModel.UserPassword); - byte[] hashedPassword = settings.hashAlgorithm?.ComputeHash(passwordBytes) ?? throw new Exception("Hash algorithm not instantiated yet"); - requestModel.UserPassword = $"{{{settings.DefaultHashAlgorithm.ToUpperInvariant()}}}{Convert.ToBase64String(hashedPassword)}"; + { + requestModel.UserPassword = await UsersHelper.HashPassword(_ldap, requestModel.UserPassword); await _ldap.UpdateUser(uid, "userPassword", requestModel.UserPassword); } diff --git a/src/Helpers/UsersHelper.cs b/src/Helpers/UsersHelper.cs index 41edf60..975fd85 100644 --- a/src/Helpers/UsersHelper.cs +++ b/src/Helpers/UsersHelper.cs @@ -1,6 +1,8 @@ using System.Globalization; using System.Text; using System.Text.RegularExpressions; +using Berufsschule_HAM.Models; +using Berufsschule_HAM.Services; namespace Berufsschule_HAM.Helpers; public static partial class UsersHelper @@ -39,6 +41,14 @@ public static partial class UsersHelper return cleaned; } + public static async Task HashPassword(LdapService ldapService, string password) + { + AdminSettingsModel settings = await ldapService.GetAdminSettingsModelAsync(); + byte[] passwordBytes = Encoding.UTF8.GetBytes(password); + byte[] hashedPassword = settings.hashAlgorithm?.ComputeHash(passwordBytes) ?? throw new Exception("Hash algorithm not instantiated yet"); + return $"{{{settings.DefaultHashAlgorithm.ToUpperInvariant()}}}{Convert.ToBase64String(hashedPassword)}"; + } + [GeneratedRegex("[^a-z]")] private static partial Regex AtoZ(); } \ No newline at end of file diff --git a/src/Models/SettingsRequestModels.cs b/src/Models/SettingsRequestModels.cs index 1979cee..f57623e 100644 --- a/src/Models/SettingsRequestModels.cs +++ b/src/Models/SettingsRequestModels.cs @@ -2,6 +2,15 @@ using System.Text.Json.Serialization; namespace Berufsschule_HAM.Models; +public class UserUpdateRequestModel +{ + [JsonPropertyName("Password")] + public string? Password { get; set; } + + [JsonPropertyName("Image")] + public string? Image { get; set; } +} + public class AdminUpdateRequestModel { [JsonPropertyName("AdminSettingsModel")] diff --git a/src/Models/SettingsResponseModels.cs b/src/Models/SettingsResponseModels.cs index 8687996..7e0dbc2 100644 --- a/src/Models/SettingsResponseModels.cs +++ b/src/Models/SettingsResponseModels.cs @@ -2,6 +2,14 @@ using System.Text.Json.Serialization; namespace Berufsschule_HAM.Models; +public class UserUpdateResponseModel +{ + [JsonPropertyName("Success")] + public required bool Success { get; set; } + [JsonPropertyName("ErrorMessage")] + public string? ErrorMessage { get; set; } +} + public class AdminUpdateResponseModel { [JsonPropertyName("Success")] diff --git a/src/Models/UserSettingsModel.cs b/src/Models/UserSettingsModel.cs new file mode 100644 index 0000000..8adddbc --- /dev/null +++ b/src/Models/UserSettingsModel.cs @@ -0,0 +1,6 @@ +using Berufsschule_HAM.Models; + +public class UserSettingsModel +{ + public required UserModel userModel; +} \ No newline at end of file diff --git a/src/Resources/Views.Settings.User.de.resx b/src/Resources/Views.Settings.User.de.resx new file mode 100644 index 0000000..532804f --- /dev/null +++ b/src/Resources/Views.Settings.User.de.resx @@ -0,0 +1,67 @@ + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, ... + + + System.Resources.ResXResourceWriter, System.Windows.Forms, ... + + + + Einstellungen + + + Persönliche Daten + + + Benutzername + + + Anrede + + + Name + + + Nachname + + + Geburtsdatum + + + Adresse + + + Konto + + + Arbeitsplatz + + + Passwort + + + Profilbild + + + Änderungen anwenden + + + Passwort muss mindestens 8 Zeichen lang sein und Groß- und Kleinbuchstaben, sowie Zahlen und Sonderzeichen enthalten + + + Einstellungen erfolgreich aktualisiert + + + Unbekannter Fehler + + + Fehler bei der Kommunikation mit dem Server + + diff --git a/src/Views/Settings/User.cshtml b/src/Views/Settings/User.cshtml index e9c7309..e64adff 100644 --- a/src/Views/Settings/User.cshtml +++ b/src/Views/Settings/User.cshtml @@ -1 +1,132 @@ -

Empty view lol

\ No newline at end of file +@using Microsoft.AspNetCore.Mvc.Localization +@using Berufsschule_HAM.Models +@model UserSettingsModel +@inject IViewLocalizer T +@inject IConfiguration Configuration +@{ + ViewData["Title"] = T["User settings"]; + string barcodeType = Configuration["BarcodeType"] ?? "EAN13"; +} + + +
+

@T["Account"]

+
+
+ + +
+
+ + +
+
+
+
+ + + +
+ +
+
+
+

@T["Personal data"]

+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+
+
+ + + \ No newline at end of file From 1c6bbcfe1d70172e9a9bdbebd395d1f316a69d7e Mon Sep 17 00:00:00 2001 From: LD-Reborn Date: Sun, 23 Nov 2025 13:57:20 +0100 Subject: [PATCH 2/3] Fixed admin settings page title --- src/Resources/Views.Settings.Admin.de.resx | 4 ++-- src/Views/Settings/Admin.cshtml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Resources/Views.Settings.Admin.de.resx b/src/Resources/Views.Settings.Admin.de.resx index 1dc9306..b8644ee 100644 --- a/src/Resources/Views.Settings.Admin.de.resx +++ b/src/Resources/Views.Settings.Admin.de.resx @@ -13,8 +13,8 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, ... - - Benutzer + + Administration diff --git a/src/Views/Settings/Admin.cshtml b/src/Views/Settings/Admin.cshtml index 53915f3..79ea760 100644 --- a/src/Views/Settings/Admin.cshtml +++ b/src/Views/Settings/Admin.cshtml @@ -10,7 +10,7 @@ @inject IViewLocalizer T @inject LdapService ldap @{ - ViewData["Title"] = T["Users"]; + ViewData["Title"] = T["Admin settings"]; List supportedBarcodeTypes = ["code128c", "ean13", "ean8", "upc", "itf14", "itf"]; string userImageCacheSize = ImageHelper.ToHumanReadableSize(ImageHelper.GetImageCacheSize()); } From bf17c755fc288a6d1b2131630e09afcb1877c5cf Mon Sep 17 00:00:00 2001 From: LD-Reborn Date: Sun, 23 Nov 2025 13:57:33 +0100 Subject: [PATCH 3/3] Fixed skip link not visible --- src/Views/Shared/_Layout.cshtml | 4 ++-- src/wwwroot/css/site.css | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Views/Shared/_Layout.cshtml b/src/Views/Shared/_Layout.cshtml index 0b60559..c8471b6 100644 --- a/src/Views/Shared/_Layout.cshtml +++ b/src/Views/Shared/_Layout.cshtml @@ -103,12 +103,12 @@ {