fix(postit): preserve performer identity during save

This commit is contained in:
Paul Schneider 2026-10-07 12:35:09 +01:00
commit 5e22b9a232
Signed by: notazof
GPG key ID: AD4B9B545FBD7D12
3 changed files with 78 additions and 24 deletions

View file

@ -143,4 +143,27 @@ public class HomePageProviderFlowTests
Assert.Equal(string.Empty, payload.GoogleCalendarId); Assert.Equal(string.Empty, payload.GoogleCalendarId);
Assert.Equal(string.Empty, payload.BankInfoSummary); Assert.Equal(string.Empty, payload.BankInfoSummary);
} }
[Fact]
public void PerformerConfigurationPage_preserves_current_user_id_in_save_payload()
{
var vm = new PerformerConfigurationPageViewModel
{
PerformerId = "user-42",
UserName = "alice",
ExerciseCountryCode = "fr",
SIREN = "123456789",
Website = "https://example.com",
Active = true,
AcceptNotifications = true,
AcceptPublicContact = true,
UseGeoLocalizationToReduceDistanceWithClients = true
};
var payload = vm.BuildPerformerProfileSettings();
Assert.Equal("user-42", payload.PerformerId);
Assert.Equal("alice", payload.UserName);
Assert.Equal("fr", payload.ExerciseCountryCode);
}
} }

View file

@ -29,12 +29,15 @@ public partial class ActivitySelectionOption : ObservableObject
public partial class PerformerConfigurationPageViewModel : ViewModelBase public partial class PerformerConfigurationPageViewModel : ViewModelBase
{ {
private readonly YavscApiClient _api; private readonly YavscApiClient? _api;
private readonly ActivityApiClient _activityClient; private readonly ActivityApiClient? _activityClient;
[ObservableProperty] [ObservableProperty]
public partial bool IsBusy { get; set; } public partial bool IsBusy { get; set; }
[ObservableProperty]
public partial string PerformerId { get; set; } = string.Empty;
[ObservableProperty] [ObservableProperty]
public partial string UserName { get; set; } = "—"; public partial string UserName { get; set; } = "—";
@ -68,25 +71,32 @@ public partial class PerformerConfigurationPageViewModel : ViewModelBase
public override bool CanNavigateNext { get => false; protected set { _ = value; } } public override bool CanNavigateNext { get => false; protected set { _ = value; } }
public override bool CanNavigatePrevious { get => true; protected set { _ = value; } } public override bool CanNavigatePrevious { get => true; protected set { _ = value; } }
public PerformerConfigurationPageViewModel(YavscApiClient api, ActivityApiClient activityClient) public PerformerConfigurationPageViewModel(YavscApiClient? api, ActivityApiClient? activityClient)
{ {
_api = api ?? throw new ArgumentNullException(nameof(api)); _api = api;
_activityClient = activityClient ?? throw new ArgumentNullException(nameof(activityClient)); _activityClient = activityClient;
} }
public PerformerConfigurationPageViewModel() : this(null!, null!) { } public PerformerConfigurationPageViewModel() : this(null, null) { }
public Task InitializeAsync() => RefreshAsync(); public Task InitializeAsync() => RefreshAsync();
[RelayCommand] [RelayCommand]
public async Task RefreshAsync() public async Task RefreshAsync()
{ {
if (_api is null || _activityClient is null)
{
StatusMessage = "Client API de configuration indisponible.";
return;
}
IsBusy = true; IsBusy = true;
try try
{ {
var endpoint = new Uri(new Uri(_api.Settings.ApiUrl.TrimEnd('/') + "/", UriKind.Absolute), "account/performer-profile").ToString(); var endpoint = new Uri(new Uri(_api.Settings.ApiUrl.TrimEnd('/') + "/", UriKind.Absolute), "account/performer-profile").ToString();
var dto = await _api.CallAsync<PerformerProfileSettings>(HttpMethod.Get, endpoint).ConfigureAwait(true); var dto = await _api.CallAsync<PerformerProfileSettings>(HttpMethod.Get, endpoint).ConfigureAwait(true);
PerformerId = dto?.PerformerId ?? string.Empty;
UserName = dto?.UserName ?? "—"; UserName = dto?.UserName ?? "—";
ExerciseCountryCode = string.IsNullOrWhiteSpace(dto?.ExerciseCountryCode) ? "fr" : dto.ExerciseCountryCode; ExerciseCountryCode = string.IsNullOrWhiteSpace(dto?.ExerciseCountryCode) ? "fr" : dto.ExerciseCountryCode;
SIREN = dto?.SIREN ?? string.Empty; SIREN = dto?.SIREN ?? string.Empty;
@ -123,29 +133,40 @@ public partial class PerformerConfigurationPageViewModel : ViewModelBase
} }
} }
public PerformerProfileSettings BuildPerformerProfileSettings()
{
return new PerformerProfileSettings
{
PerformerId = string.IsNullOrWhiteSpace(PerformerId) ? string.Empty : PerformerId,
UserName = UserName,
ExerciseCountryCode = string.IsNullOrWhiteSpace(ExerciseCountryCode) ? "fr" : ExerciseCountryCode,
SIREN = SIREN,
WebSite = Website,
Active = Active,
AcceptNotifications = AcceptNotifications,
AcceptPublicContact = AcceptPublicContact,
UseGeoLocalizationToReduceDistanceWithClients = UseGeoLocalizationToReduceDistanceWithClients,
SelectedActivityCodes = AvailableActivities
.Where(a => a.IsSelected)
.Select(a => a.Code)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList()
};
}
[RelayCommand] [RelayCommand]
public async Task SaveAsync() public async Task SaveAsync()
{ {
if (_api is null)
{
StatusMessage = "Client API de configuration indisponible.";
return;
}
IsBusy = true; IsBusy = true;
try try
{ {
var dto = new PerformerProfileSettings var dto = BuildPerformerProfileSettings();
{
PerformerId = string.Empty,
UserName = UserName,
ExerciseCountryCode = string.IsNullOrWhiteSpace(ExerciseCountryCode) ? "fr" : ExerciseCountryCode,
SIREN = SIREN,
WebSite = Website,
Active = Active,
AcceptNotifications = AcceptNotifications,
AcceptPublicContact = AcceptPublicContact,
UseGeoLocalizationToReduceDistanceWithClients = UseGeoLocalizationToReduceDistanceWithClients,
SelectedActivityCodes = AvailableActivities
.Where(a => a.IsSelected)
.Select(a => a.Code)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList()
};
var endpoint = new Uri(new Uri(_api.Settings.ApiUrl.TrimEnd('/') + "/", UriKind.Absolute), "account/performer-profile").ToString(); var endpoint = new Uri(new Uri(_api.Settings.ApiUrl.TrimEnd('/') + "/", UriKind.Absolute), "account/performer-profile").ToString();
var response = await _api.CallAsync<PerformerProfileSettings>(HttpMethod.Put, endpoint, dto).ConfigureAwait(true); var response = await _api.CallAsync<PerformerProfileSettings>(HttpMethod.Put, endpoint, dto).ConfigureAwait(true);

View file

@ -228,7 +228,17 @@ namespace Yavsc.WebApi.Controllers
} }
var uid = User.GetUserId(); var uid = User.GetUserId();
if (string.IsNullOrWhiteSpace(uid) || !string.Equals(model.PerformerId, uid, StringComparison.Ordinal)) if (string.IsNullOrWhiteSpace(uid))
{
return Challenge();
}
if (string.IsNullOrWhiteSpace(model.PerformerId))
{
model.PerformerId = uid;
}
if (!string.Equals(model.PerformerId, uid, StringComparison.Ordinal))
{ {
return Forbid(); return Forbid();
} }