postit: point Register button at /Account/Register
/signin only renders the local-account sign-in form on Yavsc.Org; new accounts live at /Account/Register. Update RegisterUrl in LoginPageViewModel and the matching test accordingly.
This commit is contained in:
parent
36e179c494
commit
9e190e3d3d
5 changed files with 98 additions and 13 deletions
|
|
@ -60,7 +60,7 @@ public class LoginPageViewModelTests
|
||||||
|
|
||||||
// Trailing slash on Authority is normalised away.
|
// Trailing slash on Authority is normalised away.
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
"https://yavsc.example.com/signin?ReturnUrl=~%2F&AllowRememberLogin=true",
|
"https://yavsc.example.com/Account/Register",
|
||||||
vm.RegisterUrl);
|
vm.RegisterUrl);
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
"https://yavsc.example.com/Account/ForgotPassword",
|
"https://yavsc.example.com/Account/ForgotPassword",
|
||||||
|
|
|
||||||
36
src/PostIt.Tests/SettingsLoadTests.cs
Normal file
36
src/PostIt.Tests/SettingsLoadTests.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace PostIt.Tests;
|
||||||
|
|
||||||
|
public class SettingsLoadTests
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// On the dev machine, the user-level settings file
|
||||||
|
/// (~/.config/PostIt/postit-settings.json) does not exist, so Load()
|
||||||
|
/// must fall back to the embedded default resource shipped inside
|
||||||
|
/// PostIt.dll.
|
||||||
|
/// </summary>
|
||||||
|
[Fact]
|
||||||
|
public async Task Load_falls_back_to_embedded_resource_when_user_file_missing()
|
||||||
|
{
|
||||||
|
// Skip if a user-level file exists (CI / different dev machines).
|
||||||
|
var userConfigPath = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
|
"PostIt",
|
||||||
|
"postit-settings.json");
|
||||||
|
if (File.Exists(userConfigPath))
|
||||||
|
{
|
||||||
|
return; // nothing to assert: user file wins.
|
||||||
|
}
|
||||||
|
|
||||||
|
var settings = new PostIt.Settings();
|
||||||
|
await settings.Load();
|
||||||
|
|
||||||
|
// The bundled postit-settings.json points at yavsc.pschneider.fr.
|
||||||
|
Assert.False(string.IsNullOrWhiteSpace(settings.Authentication?.Authority));
|
||||||
|
Assert.Equal("postit", settings.Authentication.ClientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -26,4 +26,9 @@
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="postit-settings.json">
|
||||||
|
<LogicalName>PostIt.postit-settings.json</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Platform.Storage;
|
using Avalonia.Platform.Storage;
|
||||||
|
|
@ -9,6 +11,8 @@ using System.IO;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("PostIt.Tests")]
|
||||||
|
|
||||||
namespace PostIt;
|
namespace PostIt;
|
||||||
|
|
||||||
public partial class Settings : ObservableObject
|
public partial class Settings : ObservableObject
|
||||||
|
|
@ -87,7 +91,16 @@ public partial class Settings : ObservableObject
|
||||||
if (!configFileInfo.Exists)
|
if (!configFileInfo.Exists)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"🩎 Settings file not found at {configFileInfo.FullName}");
|
Console.Error.WriteLine($"🩎 Settings file not found at {configFileInfo.FullName}");
|
||||||
return; // no settings file
|
// Only fall back to the embedded default when the in-memory
|
||||||
|
// settings haven't been populated yet. This protects callers
|
||||||
|
// (notably tests) that pre-load Settings with explicit values
|
||||||
|
// from being silently overwritten by the bundled default.
|
||||||
|
if (string.IsNullOrWhiteSpace(this.Authentication?.Authority)
|
||||||
|
&& !TryLoadEmbeddedFallback())
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("🩎 No embedded default settings; running with empty configuration.");
|
||||||
|
}
|
||||||
|
return; // no user settings file
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"🔎 Loading settings from {configFileInfo.FullName}");
|
Console.WriteLine($"🔎 Loading settings from {configFileInfo.FullName}");
|
||||||
|
|
@ -97,17 +110,49 @@ public partial class Settings : ObservableObject
|
||||||
using var stream = configFileInfo.OpenRead();
|
using var stream = configFileInfo.OpenRead();
|
||||||
using var reader = new StreamReader(stream);
|
using var reader = new StreamReader(stream);
|
||||||
var json = await reader.ReadToEndAsync();
|
var json = await reader.ReadToEndAsync();
|
||||||
if (string.IsNullOrWhiteSpace(json))
|
ApplyJson(json, $"user file {configFileInfo.FullName}");
|
||||||
{
|
}
|
||||||
Console.Error.WriteLine("🩎 Settings file is empty.");
|
catch (Exception ex)
|
||||||
return;
|
{
|
||||||
}
|
Console.Error.WriteLine($"🩎 Error loading settings: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryLoadEmbeddedFallback()
|
||||||
|
{
|
||||||
|
const string ResourceName = "PostIt.postit-settings.json";
|
||||||
|
var assembly = typeof(Settings).Assembly;
|
||||||
|
using var stream = assembly.GetManifestResourceStream(ResourceName);
|
||||||
|
if (stream is null)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"🩎 Embedded resource {ResourceName} not found.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
using var reader = new StreamReader(stream);
|
||||||
|
var json = reader.ReadToEnd();
|
||||||
|
if (string.IsNullOrWhiteSpace(json))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("🩎 Embedded settings resource is empty.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Console.WriteLine($"🔎 Loading embedded default settings ({ResourceName}).");
|
||||||
|
ApplyJson(json, $"embedded resource {ResourceName}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyJson(string json, string source)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(json))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"🩎 Settings payload is empty (source: {source}).");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
var settings = JsonSerializer.Deserialize<Settings>(json);
|
var settings = JsonSerializer.Deserialize<Settings>(json);
|
||||||
|
|
||||||
if (settings is null)
|
if (settings is null)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("🩎 Settings file is invalid.");
|
Console.Error.WriteLine($"🩎 Settings payload is invalid (source: {source}).");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.Authentication = settings.Authentication;
|
this.Authentication = settings.Authentication;
|
||||||
|
|
@ -115,11 +160,10 @@ public partial class Settings : ObservableObject
|
||||||
this.ApiUrl = settings.ApiUrl;
|
this.ApiUrl = settings.ApiUrl;
|
||||||
this.RedirectUri = string.IsNullOrWhiteSpace(settings.RedirectUri) ? DefaultLoopbackRedirectUri : settings.RedirectUri;
|
this.RedirectUri = string.IsNullOrWhiteSpace(settings.RedirectUri) ? DefaultLoopbackRedirectUri : settings.RedirectUri;
|
||||||
this.Scopes = settings.Scopes;
|
this.Scopes = settings.Scopes;
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine($"🩎 Error loading settings: {ex.Message}");
|
Console.Error.WriteLine($"🩎 Error applying settings from {source}: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13,12 +13,12 @@ public partial class LoginPageViewModel : ViewModelBase
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// URL of the Yavsc.Org register/sign-in page for new users.
|
/// URL of the Yavsc.Org account-registration page.
|
||||||
/// Derived from <see cref="Settings.Authentication"/>'s Authority.
|
/// Derived from <see cref="Settings.Authentication"/>'s Authority.
|
||||||
/// Empty when the authority is not configured.
|
/// Empty when the authority is not configured.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string RegisterUrl =>
|
public string RegisterUrl =>
|
||||||
BuildExternalUrl("/signin?ReturnUrl=~%2F&AllowRememberLogin=true");
|
BuildExternalUrl("/Account/Register");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// URL of the Yavsc.Org password-reset page (open to anonymous users).
|
/// URL of the Yavsc.Org password-reset page (open to anonymous users).
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue