From 2fd799c09f775c7b43e96f5c5f039291991bc17b Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sat, 20 Jun 2026 15:01:03 +0100 Subject: [PATCH] refactoring the login --- .gitignore | 1 + .vscode/launch.json | 84 +------------------ .vscode/settings.json | 1 + src/PostIt/PostIt/PostIt.csproj | 4 +- src/PostIt/PostIt/Settings/Settings.cs | 11 ++- src/PostIt/PostIt/ViewLocator.cs | 1 + .../PostIt/ViewModels/LoginPageViewModel.cs | 67 +++++++++++++++ src/PostIt/PostIt/ViewModels/MainViewModel.cs | 38 --------- src/PostIt/PostIt/Views/LoginPage.axaml | 56 +++++++------ src/PostIt/PostIt/Views/LoginPage.axaml.cs | 15 ++-- src/PostIt/PostIt/Views/MainPage.axaml | 5 +- src/PostIt/PostIt/Views/MainViewModel.cs | 26 ------ ...tings.json => postit-settings sample.json} | 0 13 files changed, 121 insertions(+), 188 deletions(-) create mode 100644 src/PostIt/PostIt/ViewModels/LoginPageViewModel.cs delete mode 100644 src/PostIt/PostIt/Views/MainViewModel.cs rename src/PostIt/PostIt/{settings.json => postit-settings sample.json} (100%) diff --git a/.gitignore b/.gitignore index 8f23f904..8baa2e72 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ package-lock.json data/ appsettings.*.json appsettings-*.*.json +*-settings.json generated/ *.tmp diff --git a/.vscode/launch.json b/.vscode/launch.json index 3c7324c3..05251ded 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,97 +5,17 @@ "version": "0.2.0", "configurations": [ { - "name": ".NET API", - "type": "coreclr", - "request": "launch", - "program": "${workspaceFolder}/src/Api/bin/Debug/net10.0/Api.dll", - "args": [], - "cwd": "${workspaceFolder}/src/Api", - "serverReadyAction": { - "pattern": "\\bNow listening on:\\s+(https?://\\S+)" - }, - "env": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "envFile": "${workspaceFolder}/src/Api/.env" - }, - { - "name": "C#: API Debug", + "name": "API", "type": "dotnet", "request": "launch", "projectPath": "${workspaceFolder}/src/Api/Api.csproj" }, { - "name": "Blogs", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceFolder}/src/Yavsc.Blogs/bin/Debug/net10.0/Yavsc.Blogs.dll", - "args": [], - "cwd": "${workspaceFolder}/src/Yavsc.Blogs/", - "stopAtEntry": false, - "serverReadyAction": { - "action": "openExternally", - "pattern": "\\bNow listening on:\\s+(https?://\\S+)" - }, - "env": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - { - "name": "C#: Yavsc.Org Debug", + "name": "Yavsc.Org", "type": "dotnet", "request": "launch", "projectPath": "${workspaceFolder}/src/Yavsc.Org/Yavsc.Org.csproj" }, - { - "name": "Web", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build-web", - "program": "${workspaceFolder}/src/Yavsc.Web/bin/Debug/net10.0/Yavsc.Web.dll", - "args": [], - "cwd": "${workspaceFolder}/src/Yavsc.Web", - "stopAtEntry": false, - "serverReadyAction": { - "action": "openExternally", - "pattern": "\\bNow listening on:\\s+(https?://\\S+)" - }, - "env": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - { - "name": "cli", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceFolder}/src/cli/bin/Debug/net10.0/cli.dll", - "args": [], - "cwd": "${workspaceFolder}", - "stopAtEntry": false, - "console": "internalConsole" - }, - { - "name": "Web", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "build", - "program": "${workspaceFolder}/src/Yavsc.Web/bin/Debug/net10.0/Yavsc.Web.dll", - "args": [], - "cwd": "${workspaceFolder}/src/Yavsc.Web", - "stopAtEntry": false, - "serverReadyAction": { - "action": "openExternally", - "pattern": "\\bNow listening on:\\s+(https?://\\S+)" - }, - "env": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "sourceFileMap": { - "/Views": "${workspaceFolder}/src/Yavsc.Web/Views" - } - }, { "name": "PostIt", "type": "dotnet", diff --git a/.vscode/settings.json b/.vscode/settings.json index 756fef9b..728a2954 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,7 @@ "envsubst", "Newtonsoft", "Npgsql", + "postit", "pschneider", "SLNDIR", "validable", diff --git a/src/PostIt/PostIt/PostIt.csproj b/src/PostIt/PostIt/PostIt.csproj index 9fee58a3..8cf9465c 100644 --- a/src/PostIt/PostIt/PostIt.csproj +++ b/src/PostIt/PostIt/PostIt.csproj @@ -22,8 +22,8 @@ - + PreserveNewest - \ No newline at end of file + diff --git a/src/PostIt/PostIt/Settings/Settings.cs b/src/PostIt/PostIt/Settings/Settings.cs index 1064004c..3996b540 100644 --- a/src/PostIt/PostIt/Settings/Settings.cs +++ b/src/PostIt/PostIt/Settings/Settings.cs @@ -12,7 +12,7 @@ namespace PostIt; public partial class Settings : ObservableObject { - const string SettingsFileName = "settings.json"; + const string SettingsFileName = "postit-settings.json"; IStorageFolder? folder = null; [ObservableProperty] @@ -42,8 +42,13 @@ public partial class Settings : ObservableObject internal async Task Load() { - String configPath = - Path.Combine(AppContext.BaseDirectory, SettingsFileName); + string configDir = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "PostIt" +); + Directory.CreateDirectory(configDir); + + string configPath = Path.Combine(configDir, SettingsFileName); FileInfo configFileInfo = new FileInfo(configPath); diff --git a/src/PostIt/PostIt/ViewLocator.cs b/src/PostIt/PostIt/ViewLocator.cs index 38f2b3fe..c6b66dfa 100644 --- a/src/PostIt/PostIt/ViewLocator.cs +++ b/src/PostIt/PostIt/ViewLocator.cs @@ -27,6 +27,7 @@ public class ViewLocator : IDataTemplate { MainPageViewModel => _services.GetRequiredService(), SettingsPageViewModel => _services.GetRequiredService(), + LoginPageViewModel => _services.GetRequiredService(), _ => new TextBlock { Text = $"No view for {data.GetType().Name}" } }; } diff --git a/src/PostIt/PostIt/ViewModels/LoginPageViewModel.cs b/src/PostIt/PostIt/ViewModels/LoginPageViewModel.cs new file mode 100644 index 00000000..4fb25097 --- /dev/null +++ b/src/PostIt/PostIt/ViewModels/LoginPageViewModel.cs @@ -0,0 +1,67 @@ +using CommunityToolkit.Mvvm.Input; +using IdentityModel.OidcClient; +using System; +using System.Threading.Tasks; + +namespace PostIt.ViewModels; + +public partial class LoginPageViewModel : ViewModelBase +{ + public string UserEmail { get; set; } + public string Password { get; set; } + + private string _AccessToken; + public string AccessToken { get => _AccessToken; private set => this.SetProperty(ref _AccessToken, value); } + + public bool RememberMe { get; set; } + public override bool CanNavigateNext { get => false; protected set => throw new System.NotImplementedException(); } + public override bool CanNavigatePrevious { get => true; protected set => throw new System.NotImplementedException(); } + + public Settings Settings { get; } + + private string _StatusMessage; + public string StatusMessage { get => _StatusMessage; private set => this.SetProperty(ref _StatusMessage, value); } + + private bool _IsBusy; + public bool IsBusy { get=> _IsBusy; private set=> this.SetProperty(ref _IsBusy, value); } + + public LoginPageViewModel() + { + Settings = new Settings(); + StatusMessage = "Ready"; + } + + [RelayCommand] + public async Task LoginAsync() + { + try + { + Settings.Load().Wait(); + + var client = new OidcClient(Settings.GetOidcClientOptions()); + var loginResult = await client.LoginAsync(new LoginRequest()); + + if (loginResult.IsError) + { + StatusMessage = loginResult.Error; + return; + } + + StatusMessage = "Interactive token acquired."; + + this.IsBusy = false; + AccessToken = loginResult.AccessToken; + /* TODO save or not user log and password + await Task.Run(() => + { + Settings.Save().Wait(); + });*/ + + } + catch (Exception ex) + { + this.IsBusy = false; + StatusMessage = "Error: "+ex.Message; + } + } +} \ No newline at end of file diff --git a/src/PostIt/PostIt/ViewModels/MainViewModel.cs b/src/PostIt/PostIt/ViewModels/MainViewModel.cs index 10f9febe..0f437a99 100644 --- a/src/PostIt/PostIt/ViewModels/MainViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/MainViewModel.cs @@ -107,44 +107,6 @@ public partial class MainPageViewModel : ViewModelBase ApplyFilter(); } - [RelayCommand] - internal async Task Login() - { - await ExecuteAsync(async () => - { - // Try interactive OIDC login first - try - { - - var loginWin = new PostIt.Views.LoginPage(); - var result = await loginWin.StartLoginAsync(Settings.GetOidcClientOptions()); - - if (result is not null && !result.IsError && !string.IsNullOrWhiteSpace(result.AccessToken)) - { - BearerToken = result.AccessToken; - StatusMessage = "Interactive token acquired."; - return; - } - } - catch - { - // ignore and fallback to client credentials - } - - // Fallback to client credentials if interactive fails - var tokenResponse = await RequestClientCredentialsTokenAsync(); - if (string.IsNullOrWhiteSpace(tokenResponse.AccessToken)) - { - throw new InvalidOperationException("Failed to acquire a token using client credentials."); - } - - BearerToken = tokenResponse.AccessToken; - StatusMessage = string.IsNullOrWhiteSpace(tokenResponse.Error) - ? "Bearer token acquired (client credentials)." - : $"Token acquired with warning: {tokenResponse.ErrorDescription}"; - }); - } - [RelayCommand] internal async Task Save() { diff --git a/src/PostIt/PostIt/Views/LoginPage.axaml b/src/PostIt/PostIt/Views/LoginPage.axaml index 5b79bb60..f7b9fc53 100644 --- a/src/PostIt/PostIt/Views/LoginPage.axaml +++ b/src/PostIt/PostIt/Views/LoginPage.axaml @@ -1,37 +1,39 @@ + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:vm="using:PostIt.ViewModels" + x:Class="PostIt.Views.LoginPage" + x:DataType="vm:LoginPageViewModel" + Header="Login"> - + - + - - - - + + + + - - - - + + + + -