diff --git a/src/Koogle.Application/DTOs/AuthDto.cs b/src/Koogle.Application/DTOs/AuthDto.cs
index 8065a97..9fa7392 100644
--- a/src/Koogle.Application/DTOs/AuthDto.cs
+++ b/src/Koogle.Application/DTOs/AuthDto.cs
@@ -52,6 +52,15 @@ namespace Koogle.Application.DTOs
public string ConfirmPassword { get; set; } = "";
}
+ ///
+ /// From DTO for switching session from one club to another
+ ///
+ public class SwitchClubFormDto
+ {
+ public Guid UserProfileId { get; set; }
+
+ public Guid ClubId { get; set; }
+ }
///
/// DTO for user registration.
///
diff --git a/src/Koogle.Application/Services/UserService.cs b/src/Koogle.Application/Services/UserService.cs
index 04489f2..c75f326 100644
--- a/src/Koogle.Application/Services/UserService.cs
+++ b/src/Koogle.Application/Services/UserService.cs
@@ -709,6 +709,22 @@ public class UserService : IUserService
profile.CurrentClubId = clubId;
await _appDb.SaveChangesAsync(ct);
+
+ // Refresh signin to update claims with new club
+ var identityUser = await _userManager.FindByIdAsync(profile.IdentityUserId.ToString());
+ if (identityUser != null)
+ {
+ try
+ {
+ await _signInManager.RefreshSignInAsync(identityUser);
+ }
+ catch (Exception e)
+ {
+
+ throw;
+ }
+ }
+
return true;
}
diff --git a/src/Koogle.Web/Components/Shared/ClubSwitcher.razor b/src/Koogle.Web/Components/Shared/ClubSwitcher.razor
index 7d1af7c..64f962c 100644
--- a/src/Koogle.Web/Components/Shared/ClubSwitcher.razor
+++ b/src/Koogle.Web/Components/Shared/ClubSwitcher.razor
@@ -1,10 +1,16 @@
+@using System.Net
@using Fluxor
+@using Koogle.Application.DTOs
@using Koogle.Web.Store.AuthState
@using Koogle.Application.Interfaces
@inject IState AuthState
@inject NavigationManager NavigationManager
@inject IUserService UserService
+@inject HttpClient HttpClient;
+@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
+@inject IHttpContextAccessor HttpContextAccessor
+@inject IDispatcher Dispatcher
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
@@ -22,10 +28,10 @@
@foreach (var club in AuthState.Value.AvailableClubs)
{
+ Disabled="@(club.ClubId == AuthState.Value.CurrentClub?.ClubId)">
@if (club.ClubId == AuthState.Value.CurrentClub?.ClubId)
{
-
+
}
@club.ClubName
@@ -47,23 +53,64 @@ else if (AuthState.Value.IsAuthenticated && AuthState.Value.HasNoClub)
}
@code {
+ private string _antiToken;
+
+ protected override void OnAfterRender(bool firstRender)
+ {
+ if (firstRender)
+ {
+ var http = HttpContextAccessor.HttpContext!;
+ var tokens = Antiforgery.GetAndStoreTokens(http);
+ _antiToken = tokens.RequestToken!;
+ }
+ }
+
private async Task SwitchClubAsync(Guid clubId)
{
if (AuthState.Value.CurrentUser == null)
return;
+ var model = new SwitchClubFormDto()
+ {
+ ClubId = clubId,
+ UserProfileId = AuthState.Value.CurrentUser.ProfileId
+ };
+
try
{
- var success = await UserService.SwitchClubAsync(AuthState.Value.CurrentUser.ProfileId, clubId);
- if (success)
- {
- // Force page reload to refresh claims
- NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
- }
+ HttpClient.DefaultRequestHeaders.Remove("RequestVerificationToken");
+ HttpClient.DefaultRequestHeaders.Add(
+ "RequestVerificationToken",
+ _antiToken
+ );
+
+ var basepath = NavigationManager.BaseUri;
+ var url = $"{basepath}auth/switch-club";
+ await HttpClient.PostAsJsonAsync(url, model);
+
+ // Dispatcher.Dispatch(new AuthState.InitializeAuthSuccessAction(model.UserProfileId, model.ClubId, roles));
+
+
+ NavigationManager.NavigateTo("/dashboard", forceLoad: true);
}
- catch (Exception ex)
+ catch (Exception e)
{
- Console.WriteLine($"Club switch failed: {ex.Message}");
+ Console.WriteLine(e);
+ throw;
}
+
+ // try
+ // {
+ // var success = await UserService.SwitchClubAsync(AuthState.Value.CurrentUser.ProfileId, clubId);
+ // if (success)
+ // {
+ // // Force page reload to refresh claims
+ // NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
+ // }
+ // }
+ // catch (Exception ex)
+ // {
+ // Console.WriteLine($"Club switch failed: {ex.Message}");
+ // }
}
}
diff --git a/src/Koogle.Web/Controllers/AuthController.cs b/src/Koogle.Web/Controllers/AuthController.cs
index 825d1bc..31b4958 100644
--- a/src/Koogle.Web/Controllers/AuthController.cs
+++ b/src/Koogle.Web/Controllers/AuthController.cs
@@ -7,6 +7,7 @@ using Koogle.Web.Store.AuthState;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
+using static QRCoder.PayloadGenerator;
namespace Koogle.Web.Controllers
{
@@ -18,7 +19,8 @@ namespace Koogle.Web.Controllers
/// Aus dem Grund werden Login/Logout Aktionen hier im MVC Controller mit einem "normalen" Post-Request abgewickelt.
///
[Microsoft.AspNetCore.Mvc.Route("auth")]
- public class AuthController(IDispatcher dispatcher, IUserService userService, IEmailService emailService) : Controller
+ public class AuthController(IDispatcher dispatcher, IUserService userService, IEmailService emailService)
+ : Controller
{
private readonly IDispatcher _dispatcher = dispatcher;
private readonly IUserService _userService = userService;
@@ -37,6 +39,7 @@ namespace Koogle.Web.Controllers
// (club-setup if no clubs, dashboard otherwise)
return LocalRedirect(result.RedirectUrl ?? "/dashboard");
}
+
return LocalRedirect("/account/login?error=true");
}
@@ -67,8 +70,10 @@ namespace Koogle.Web.Controllers
// If invite token was provided, redirect to join page
if (!string.IsNullOrWhiteSpace(input.InviteToken))
{
- return LocalRedirect($"/account/login?registered=true&invite={Uri.EscapeDataString(input.InviteToken)}");
+ return LocalRedirect(
+ $"/account/login?registered=true&invite={Uri.EscapeDataString(input.InviteToken)}");
}
+
return LocalRedirect("/account/login?registered=true");
}
@@ -93,7 +98,8 @@ namespace Koogle.Web.Controllers
if (token != null)
{
var baseUrl = $"{Request.Scheme}://{Request.Host}";
- var resetUrl = $"{baseUrl}/account/reset-password?email={Uri.EscapeDataString(email)}&token={Uri.EscapeDataString(token)}";
+ var resetUrl =
+ $"{baseUrl}/account/reset-password?email={Uri.EscapeDataString(email)}&token={Uri.EscapeDataString(token)}";
await _emailService.SendPasswordResetEmailAsync(email, resetUrl);
}
@@ -110,7 +116,8 @@ namespace Koogle.Web.Controllers
// Validate password confirmation
if (input.NewPassword != input.ConfirmPassword)
{
- return LocalRedirect($"/account/reset-password?email={Uri.EscapeDataString(input.Email)}&token={Uri.EscapeDataString(input.Token)}&error=PasswordMismatch");
+ return LocalRedirect(
+ $"/account/reset-password?email={Uri.EscapeDataString(input.Email)}&token={Uri.EscapeDataString(input.Token)}&error=PasswordMismatch");
}
var dto = new ResetPasswordDto
@@ -127,9 +134,20 @@ namespace Koogle.Web.Controllers
}
var errors = string.Join(",", result.Errors.Select(e => e.Code));
- return LocalRedirect($"/account/reset-password?email={Uri.EscapeDataString(input.Email)}&token={Uri.EscapeDataString(input.Token)}&error={errors}");
+ return LocalRedirect(
+ $"/account/reset-password?email={Uri.EscapeDataString(input.Email)}&token={Uri.EscapeDataString(input.Token)}&error={errors}");
+ }
+
+ ///
+ /// Handles switch club.
+ ///
+ [HttpPost("switch-club")]
+ //[ValidateAntiForgeryToken]
+ public async Task SwitchClub([FromBody] SwitchClubFormDto input)
+ {
+ await _userService.SwitchClubAsync(input.UserProfileId, input.ClubId);
+ return LocalRedirect($"/dashboard");
}
}
-
}
diff --git a/src/Koogle.Web/wwwroot/club-media/demozwei/gifs/534a4e93-ceb8-4886-8965-f1e299443ebc.gif b/src/Koogle.Web/wwwroot/club-media/demozwei/gifs/534a4e93-ceb8-4886-8965-f1e299443ebc.gif
new file mode 100644
index 0000000..4bd66d6
Binary files /dev/null and b/src/Koogle.Web/wwwroot/club-media/demozwei/gifs/534a4e93-ceb8-4886-8965-f1e299443ebc.gif differ
diff --git a/src/Koogle.Web/wwwroot/club-media/demozwei/gifs/a1744438-6fb7-4ef4-8278-24cb841d33f2.gif b/src/Koogle.Web/wwwroot/club-media/demozwei/gifs/a1744438-6fb7-4ef4-8278-24cb841d33f2.gif
new file mode 100644
index 0000000..169e2a7
Binary files /dev/null and b/src/Koogle.Web/wwwroot/club-media/demozwei/gifs/a1744438-6fb7-4ef4-8278-24cb841d33f2.gif differ