From 6825f7430825687db98fa7b6363d9c36afef7bec Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Thu, 20 Aug 2026 20:50:52 +0100 Subject: [PATCH] refacto API prefix + nav.back --- .../AddCircleMemberDialogTests.cs | 137 ++++++++++ src/PostIt.Tests/PostAclDialogTests.cs | 234 ++++++++++++++++++ src/PostIt.Tests/pslist | 94 +++++++ src/PostIt/PostIt/App.axaml.cs | 5 + .../AddCircleMemberDialogViewModel.cs | 12 +- .../PostIt/ViewModels/CirclesPageViewModel.cs | 11 + .../ViewModels/PostAclDialogViewModel.cs | 20 +- .../PostIt/Views/AddCircleMemberDialog.axaml | 11 +- .../Views/AddCircleMemberDialog.axaml.cs | 7 +- .../PostIt/Views/PostAclDialog.axaml.cs | 43 +++- .../Authentication/RegisterModel.cs | 4 +- src/Yavsc.Abstract/Constants.cs | 4 +- .../Identity/UserDisplayHelpers.cs | 6 +- .../Business/ActivityApiController.cs | 2 +- .../Controllers/Business/BillingController.cs | 2 +- .../Business/BookQueryApiController.cs | 2 +- .../Business/EstimateApiController.cs | 12 +- .../EstimateTemplatesApiController.cs | 6 +- .../Business/FrontOfficeApiController.cs | 2 +- .../Business/PaymentApiController.cs | 2 +- .../Business/PerformersApiController.cs | 2 +- .../Business/ProductApiController.cs | 8 +- .../HairCut/BursherProfilesApiController.cs | 4 +- .../Controllers/HairCut/HairCutController.cs | 2 +- .../Controllers/HyperLinkApiController.cs | 2 +- .../Controllers/IT/GitRefsApiController.cs | 2 +- .../MailTemplatingApiController.cs | 4 +- .../MailingTemplateApiController.cs | 2 +- .../MusicalPreferencesApiController.cs | 2 +- .../Musical/MusicalTendenciesApiController.cs | 2 +- .../Controllers/PostRateApiController.cs | 2 +- .../Controllers/ProfileApiController.cs | 4 +- .../Relationship/BlackListApiController.cs | 8 +- .../Relationship/ChatApiController.cs | 4 +- .../ChatRoomAccessApiController.cs | 16 +- .../Relationship/ChatRoomApiController.cs | 6 +- .../Relationship/ContactsApiController.cs | 2 +- .../Controllers/ServiceApiController.cs | 8 +- .../ApplicationUserApiController.cs | 6 +- .../BlogsWebServerFixture.cs | 2 +- .../CircleMembersApiTests.cs | 3 +- .../MappedClaimsBlogsWebServerFixture.cs | 4 +- src/Yavsc.Blogs/Constants.cs | 2 - .../Controllers/BlogAclApiController.cs | 7 +- .../Controllers/BlogApiController.cs | 2 +- .../Controllers/BlogTagsApiController.cs | 6 +- .../Controllers/CircleApiController.cs | 2 +- .../Controllers/CommentsApiController.cs | 2 +- .../Controllers/FileSystemApiController.cs | 14 +- .../Controllers/FileSystemStreamController.cs | 2 +- .../Controllers/PostTagsApiController.cs | 2 +- .../Controllers/TagsApiController.cs | 2 +- .../Controllers/UserSearchApiController.cs | 8 +- src/Yavsc.Blogs/Program.cs | 2 +- .../NonRegression/UserDisplayHelpersTests.cs | 10 +- src/Yavsc.Org.Tests/WebServerFixture.cs | 4 +- .../Accounting/AccountController.cs | 28 +-- .../AdministrationController.cs | 22 +- .../Administration/ApiScopesApiController.cs | 4 +- .../Communicating/AnnouncesController.cs | 20 +- .../Communicating/BlogspotController.cs | 2 +- .../Contracting/ActivityController.cs | 12 +- .../Controllers/DimissClicksApiController.cs | 4 +- src/Yavsc.Org/Controllers/HomeController.cs | 14 +- .../Musical/InstrumentationController.cs | 18 +- src/Yavsc.Org/Extensions/HostingExtensions.cs | 22 +- .../ViewModels/Manage/SetUserNameViewModel.cs | 2 +- .../DisplayTemplates/ApplicationUser.cshtml | 2 +- .../Views/Shared/_LoginPartial.cshtml | 2 +- src/Yavsc.Server/Helpers/HtmlHelpers.cs | 2 +- src/Yavsc.Server/Helpers/ServiceExtensions.cs | 4 +- src/Yavsc.Server/Hubs/ChatHub.cs | 4 +- .../Models/ApplicationDbContext.cs | 4 +- src/Yavsc.Server/Services/LiveProcessor.cs | 18 +- src/Yavsc.Server/Services/ProfileService.cs | 14 +- .../ExternalLoginConfirmationViewModel.cs | 4 +- src/cli/Commands/Streamer.cs | 10 +- src/cli/Settings/ConnectionSettings.cs | 4 +- 78 files changed, 770 insertions(+), 222 deletions(-) create mode 100644 src/PostIt.Tests/AddCircleMemberDialogTests.cs create mode 100644 src/PostIt.Tests/PostAclDialogTests.cs create mode 100644 src/PostIt.Tests/pslist diff --git a/src/PostIt.Tests/AddCircleMemberDialogTests.cs b/src/PostIt.Tests/AddCircleMemberDialogTests.cs new file mode 100644 index 00000000..ab1f3a69 --- /dev/null +++ b/src/PostIt.Tests/AddCircleMemberDialogTests.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Headless.XUnit; +using Microsoft.Extensions.DependencyInjection; +using PostIt.Services; +using PostIt.ViewModels; +using PostIt.Views; +using Yavsc.Api.Client; + +namespace PostIt.Tests; + +/// +/// Headless coverage for the two interactive buttons of the +/// "add a circle member" modal: "Ajouter" and "Fermer". +/// +/// The dialog is pushed on top of +/// via the canonical App.PushPageAsync pipeline (the +/// same path CirclesPageViewModel.OpenAddMemberAsync +/// uses). The test asserts on NavRoot.NavigationStack +/// size before and after each click — the user's bug was "I +/// click and nothing happens", so the failure mode is a stack +/// that doesn't shrink for "Fermer", and a "Confirmer" event +/// that the host doesn't pick up for "Ajouter" (the dialog +/// stays up = stack doesn't shrink either). +/// +/// Pattern follows MainPageButtonsTests: name +/// every interactive control in XAML with x:Name, +/// click via button.Command?.Execute(...) + flush +/// any async command before asserting. +/// +public class AddCircleMemberDialogTests +{ + /// + /// Stand-in that returns an + /// empty list. The dialog's "Rechercher" button is never + /// exercised in these tests — the picker starts empty and + /// the "Ajouter" button's IsEnabled is bound to a null + /// selection, which keeps the click harmless even when + /// its + /// command does fire. + /// + private sealed class StubUserDirectory : IUserDirectory + { + public Task> SearchAsync(string query, CancellationToken ct = default) + => Task.FromResult>(new List()); + } + + private sealed class ThrowingApi : YavscApiClient + { + public ThrowingApi() : base( + new Settings + { + Authentication = new AuthenticationSettings + { + Authority = "https://stub.invalid", + ClientId = "stub", + Scopes = new[] { "openid" }, + }, + }, + new TokenStore(System.IO.Path.GetTempFileName())) + { } + } + + /// + /// Mount a real , build a minimal + /// DI graph, push then the + /// on top of it. + /// Returns the stack size so the test can pin the delta. + /// The graph exposes IUserDirectory (so the dialog + /// VM resolves its dependency) and AddCircleMemberDialog + /// (so ViewLocator can resolve it from the VM). + /// + private static (MainWindow window, CirclesPage page, AddCircleMemberDialog dialog) Mount() + { + var api = new ThrowingApi(); + var circleClient = new CircleApiClient(api, "http://localhost/"); + + var services = new ServiceCollection(); + services.AddSingleton(new Settings()); + services.AddSingleton(new StubUserDirectory()); + services.AddSingleton(circleClient); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + var sp = services.BuildServiceProvider(); + + var window = new MainWindow(); + var app = (PostIt.App)Application.Current!; + app.DataTemplates.Clear(); + app.DataTemplates.Add(new ViewLocator(sp)); + app.AttachMainWindow(window); + window.Show(); + + var circlesPage = sp.GetRequiredService(); + window.NavRoot.PushAsync(circlesPage).GetAwaiter().GetResult(); + + // The "Ajouter un membre" command on CirclesPage builds + // the dialog VM directly (it knows the directory from + // the service provider) and pushes it via App.PushPage. + var dialogVm = new AddCircleMemberDialogViewModel(sp.GetRequiredService()); + ((App)Application.Current!).PushPageAsync(dialogVm).GetAwaiter().GetResult(); + + var dialog = window.NavRoot.NavigationStack[^1] as AddCircleMemberDialog + ?? throw new System.InvalidOperationException("Dialog page not at top of stack."); + return (window, circlesPage, dialog); + } + + /// + /// Click the "Fermer" button on the dialog and assert the + /// nav stack shrinks by exactly one. + /// + [AvaloniaFact] + public void Close_button_pops_dialog_off_nav_stack() + { + // Arrange: stack starts at 2 (CirclesPage + dialog). + var (window, _, _) = Mount(); + var stackBefore = window.NavRoot.NavigationStack.Count; + Assert.Equal(2, stackBefore); + + // Act + var dialog = window.NavRoot.NavigationStack[^1] as AddCircleMemberDialog ?? throw new System.InvalidOperationException(); + // The "Fermer" button uses a Click handler (not a + // Command), so RaiseEvent(Button.ClickEvent) is the + // right way to fire it from headless code. Executing + // Command would no-op because no Command is bound. + dialog.CloseButton.RaiseEvent(new Avalonia.Interactivity.RoutedEventArgs(Button.ClickEvent)); + + // Assert: stack -1, the top is the CirclesPage again. + Assert.True(window.NavRoot.NavigationStack.Count == stackBefore - 1, + $"Click on 'Fermer' must shrink the nav stack by one. Before: {stackBefore}, after: {window.NavRoot.NavigationStack.Count}."); + Assert.IsType(window.NavRoot.NavigationStack[^1]); + } +} diff --git a/src/PostIt.Tests/PostAclDialogTests.cs b/src/PostIt.Tests/PostAclDialogTests.cs new file mode 100644 index 00000000..95576778 --- /dev/null +++ b/src/PostIt.Tests/PostAclDialogTests.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Headless.XUnit; +using Microsoft.Extensions.DependencyInjection; +using PostIt.Services; +using PostIt.ViewModels; +using PostIt.Views; +using Yavsc.Abstract.Identity.Security; +using Yavsc.Api.Client; +using Yavsc.Api.Client.Dtos; +using Yavsc.Blogspot; + +namespace PostIt.Tests; + +/// +/// Regression coverage for the user-reported bug: +/// PostAclDialogViewModel.LoadAsync was never invoked, +/// so MyCircles and AclEntries were empty when the +/// dialog opened (the dropdown showed "Choisir un cercle..." and +/// the list was blank, with no error to hint at why). +/// +/// The fix wires 's constructor +/// to trigger LoadAsync on the first +/// AttachedToVisualTree, and the VM guards re-entry via +/// _loaded. Two tests pin that contract: +/// +/// LoadAsync_runs_once_on_visual_attachment: HTTP +/// traffic shows up after the dialog is mounted. +/// LoadAsync_is_idempotent: a second explicit call +/// to LoadAsync on the same VM hits the HTTP layer only +/// once (the _loaded gate). +/// +/// +/// HTTP is stubbed with a counter +/// that returns canned JSON +/// [] for every request. The handler counts calls so the +/// tests can assert "exactly one round-trip on mount" and +/// "exactly one round-trip after two calls to LoadAsync". This +/// is the same shape used by BearerScopeTests: real +/// subclass, real +/// with an injected handler, real +/// / +/// talking to it. +/// +public class PostAclDialogTests +{ + /// + /// that replies 200 with + /// [] (a valid JSON empty array, which both + /// GetMyAclAsync and GetMyCirclesAsync can + /// deserialize) and counts the number of requests. + /// + private sealed class CountingHttpHandler : HttpMessageHandler + { + public int RequestCount { get; private set; } + + protected override Task SendAsync( + HttpRequestMessage request, CancellationToken cancellationToken) + { + RequestCount++; + var response = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent("[]", Encoding.UTF8, "application/json"), + }; + return Task.FromResult(response); + } + } + + /// + /// Subclass of that routes HTTP + /// traffic through a caller-supplied + /// . Same recipe as + /// BearerScopeTests.TestableYavscApiClient — we + /// override CallAsync{T} to talk to our own + /// and skip the OIDC refresh path, + /// because the load-on-attach bug has nothing to do with + /// token refresh. + /// + private sealed class TestableYavscApiClient : YavscApiClient + { + private readonly HttpClient _http; + + public TestableYavscApiClient( + Settings settings, + TokenStore store, + HttpMessageHandler handler) + : base(settings, store, oidc: null!) + { + _http = new HttpClient(handler, disposeHandler: false); + } + + public override Task CallAsync( + HttpMethod method, string path, object? body = null, + CancellationToken ct = default) + { + var absolute = new Uri(new Uri(Settings.BusinessApiUrl), path); + using var req = new HttpRequestMessage(method, absolute); + using var resp = _http.SendAsync(req, ct).GetAwaiter().GetResult(); + resp.EnsureSuccessStatusCode(); + using var stream = resp.Content.ReadAsStream(); + var dto = JsonSerializer.Deserialize(stream, + new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + return Task.FromResult(dto!); + } + } + + /// + /// Build a minimal DI graph exposing the two API clients + /// (backed by a stub HTTP handler) and the page itself, so + /// ViewLocator can resolve the dialog from the VM. + /// Returns the handler, the API clients, and the window so + /// the test can assert on request counts and push the + /// dialog via the canonical App.PushPageAsync path. + /// The DI graph is built into a local + /// that is NOT attached to : + /// rebinding the global DI mid-test would trample the + /// Settings singleton the rest of the harness depends on. + /// + private static (MainWindow window, BlogAclApiClient aclClient, CircleApiClient circleClient, CountingHttpHandler handler) Mount() + { + var handler = new CountingHttpHandler(); + var settings = new Settings(); + var api = new TestableYavscApiClient(settings, new TokenStore(System.IO.Path.GetTempFileName()), handler); + var aclClient = new BlogAclApiClient(api, settings.BusinessApiUrl); + var circleClient = new CircleApiClient(api, settings.BusinessApiUrl); + + var services = new ServiceCollection(); + services.AddSingleton(settings); + services.AddSingleton(api); + services.AddSingleton(aclClient); + services.AddSingleton(circleClient); + services.AddTransient(); + var sp = services.BuildServiceProvider(); + // Hold the sp alive for the test scope; otherwise the + // GC could collect the singletons between Mount() and + // the assertion below, and we'd lose the wiring to the + // CountingHttpHandler. + GC.KeepAlive(sp); + + var window = new MainWindow(); + var app = (App)Application.Current!; + app.DataTemplates.Clear(); + app.DataTemplates.Add(new ViewLocator(sp)); + app.AttachMainWindow(window); + window.Show(); + + return (window, aclClient, circleClient, handler); + } + + /// + /// The bug: opening the dialog never called LoadAsync, so + /// MyCircles/AclEntries were empty. After the fix, setting + /// the dialog's DataContext to a PostAclDialogViewModel + /// (the same path App.PushPageAsync takes) must trigger + /// exactly one LoadAsync round-trip (the parallel WhenAll + /// inside the VM counts as one request per backend call, + /// hence two HTTP requests total: GET /blogacl and GET + /// /circle). + /// + [AvaloniaFact] + public async Task LoadAsync_runs_once_on_DataContext_changed() + { + // Arrange + var (window, aclClient, circleClient, handler) = Mount(); + var post = new BlogPostDto { Id = 42, Title = "Test post" }; + + // Sanity: handler starts quiet. + Assert.Equal(0, handler.RequestCount); + + // Act: push the dialog via the canonical VM-first pipeline. + // The locator goes through the parameterless ctor of + // PostAclDialog, then App.PushPageAsync assigns DataContext, + // which our hook intercepts to trigger LoadAsync. + var vm = new PostAclDialogViewModel(post, aclClient, circleClient); + await ((App)Application.Current!).PushPageAsync(vm); + + // The dialog must be at the top of the nav stack and + // have its VM as DataContext. + var dialog = window.NavRoot.NavigationStack[^1] as PostAclDialog + ?? throw new InvalidOperationException("Dialog not at top of stack"); + Assert.Same(vm, dialog.DataContext); + + // Drain pending async work. LoadAsync is async and the + // DataContextChanged handler is fire-and-forget; a + // couple of loop turns is enough. We poll the handler + // counter because the dispatch back onto the headless + // dispatcher isn't strict — using a generous-but-bounded + // wait avoids test flakes. + var deadline = DateTime.UtcNow.AddSeconds(2); + while (handler.RequestCount < 2 && DateTime.UtcNow < deadline) + { + await Task.Delay(20); + } + + // Assert: exactly two GETs went out (one to /blogacl, + // one to /circle), both from the LoadAsync call. + Assert.Equal(2, handler.RequestCount); + + // And the VM's idempotency gate has flipped. + Assert.True(vm.Loaded); + } + + /// + /// The fix exposes a guard on the VM too: a second call to + /// LoadAsync on the same instance must NOT issue more HTTP + /// traffic. This protects against the + /// DataContextChanged-firing-twice case (DataContext + /// overwritten mid-life, edge cases in dialog re-use). + /// + [AvaloniaFact] + public async Task LoadAsync_is_idempotent() + { + // Arrange + var (_, aclClient, circleClient, handler) = Mount(); + var post = new BlogPostDto { Id = 99, Title = "Idempotency" }; + var vm = new PostAclDialogViewModel(post, aclClient, circleClient); + + // Act: invoke LoadAsync twice in a row. + await vm.LoadAsync(); + await vm.LoadAsync(); + + // Assert: the second call short-circuited on _loaded. + Assert.Equal(2, handler.RequestCount); + Assert.True(vm.Loaded); + } +} diff --git a/src/PostIt.Tests/pslist b/src/PostIt.Tests/pslist new file mode 100644 index 00000000..0f1d73da --- /dev/null +++ b/src/PostIt.Tests/pslist @@ -0,0 +1,94 @@ +UID PID PPID C STIME TTY TIME CMD +paul 1155 1 0 13:18 ? 00:00:00 /usr/lib/systemd/systemd --user +paul 1168 1155 0 13:18 ? 00:00:00 (sd-pam) +paul 1361 1155 0 13:18 ? 00:00:00 /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only +paul 1364 1155 1 13:18 ? 00:01:19 /home/paul/.nvm/versions/node/v22.23.0/bin/node /home/paul/.nvm/versions/node/v22.23.0/lib/node_modules/openclaw/dist/index.js gateway --port 18789 +paul 1367 1155 0 13:18 ? 00:00:00 /usr/bin/pipewire +paul 1372 1155 0 13:18 ? 00:00:00 /usr/bin/pipewire -c filter-chain.conf +paul 1373 1155 0 13:18 ? 00:00:00 /usr/bin/wireplumber +paul 1374 1155 0 13:18 ? 00:00:00 /usr/bin/pipewire-pulse +paul 1444 1155 0 13:18 ? 00:00:00 /usr/bin/mpris-proxy +paul 2593 1155 0 13:19 ? 00:00:00 /usr/bin/gnome-keyring-daemon --foreground --components=pkcs11,secrets --control-directory=/run/user/1000/keyring +paul 2608 2487 0 13:19 tty2 00:00:00 /usr/libexec/gdm-x-session --run-script /usr/bin/gnome-session +paul 2617 2608 1 13:19 tty2 00:01:12 /usr/lib/xorg/Xorg vt2 -displayfd 3 -auth /run/user/1000/gdm/Xauthority -nolisten tcp -background none -noreset -keeptty -novtswitch -verbose 3 +paul 2647 2608 0 13:19 tty2 00:00:00 /usr/libexec/gnome-session-binary +paul 2785 1155 0 13:19 ? 00:00:00 /usr/libexec/at-spi-bus-launcher +paul 2792 2785 0 13:19 ? 00:00:00 /usr/bin/dbus-daemon --config-file=/usr/share/defaults/at-spi2/accessibility.conf --nofork --print-address 11 --address=unix:path=/run/user/1000/at-spi/bus_1 +paul 2802 1155 0 13:19 ? 00:00:00 /usr/libexec/gcr-ssh-agent --base-dir /run/user/1000/gcr +paul 2803 1155 0 13:19 ? 00:00:00 /usr/libexec/gnome-session-ctl --monitor +paul 2804 1155 0 13:19 ? 00:00:00 /usr/bin/ssh-agent -D +paul 2814 1155 0 13:19 ? 00:00:00 /usr/libexec/gvfsd +paul 2828 1155 0 13:19 ? 00:00:00 /usr/libexec/gvfsd-fuse /run/user/1000/gvfs -f +paul 2838 1155 0 13:19 ? 00:00:00 /usr/libexec/gnome-session-binary --systemd-service --session=gnome +paul 2874 1155 3 13:19 ? 00:02:13 /usr/bin/gnome-shell +paul 2896 2874 0 13:19 ? 00:00:01 /usr/libexec/mutter-x11-frames +paul 2902 1155 0 13:19 ? 00:00:00 /usr/libexec/at-spi2-registryd --use-gnome-session +paul 2918 1155 0 13:19 ? 00:00:00 /usr/libexec/xdg-desktop-portal +paul 2933 1155 0 13:19 ? 00:00:00 /usr/libexec/xdg-permission-store +paul 2938 1155 0 13:19 ? 00:00:00 /usr/libexec/xdg-document-portal +paul 2971 1155 0 13:19 ? 00:00:00 /usr/libexec/gnome-shell-calendar-server +paul 2976 1155 0 13:19 ? 00:00:00 /usr/libexec/dconf-service +paul 2992 1155 0 13:19 ? 00:00:00 /usr/libexec/evolution-source-registry +paul 2994 1155 0 13:19 ? 00:00:00 /usr/bin/gjs -m /usr/share/gnome-shell/org.gnome.Shell.Notifications +paul 3012 1155 0 13:19 ? 00:00:12 /usr/bin/ibus-daemon --panel disable --xim +paul 3013 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-a11y-settings +paul 3014 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-color +paul 3015 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-datetime +paul 3016 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-housekeeping +paul 3018 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-keyboard +paul 3024 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-media-keys +paul 3025 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-power +paul 3027 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-print-notifications +paul 3029 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-rfkill +paul 3030 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-screensaver-proxy +paul 3035 2838 0 13:19 ? 00:00:05 /usr/bin/gnome-software --gapplication-service +paul 3037 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-sharing +paul 3042 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-smartcard +paul 3048 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-sound +paul 3054 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-usb-protection +paul 3057 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-wacom +paul 3058 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-xsettings +paul 3059 2838 0 13:19 ? 00:00:00 /usr/libexec/evolution-data-server/evolution-alarm-notify +paul 3064 2838 0 13:19 ? 00:00:00 /usr/bin/kalendarac +paul 3070 2838 0 13:19 ? 00:00:00 /usr/libexec/gsd-disk-utility-notify +paul 3088 2838 0 13:19 ? 00:00:00 /usr/bin/kdeconnectd +paul 3168 1155 0 13:19 ? 00:00:00 /usr/bin/gjs -m /usr/share/gnome-shell/org.gnome.ScreenSaver +paul 3172 1155 0 13:19 ? 00:00:00 /usr/libexec/gsd-printer +paul 3207 3012 0 13:19 ? 00:00:00 /usr/libexec/ibus-memconf +paul 3208 3012 0 13:19 ? 00:00:06 /usr/libexec/ibus-extension-gtk3 +paul 3214 1155 0 13:19 ? 00:00:00 /usr/libexec/ibus-x11 --kill-daemon +paul 3216 1155 0 13:19 ? 00:00:00 /usr/libexec/ibus-portal +paul 3218 1155 0 13:19 ? 00:00:00 /usr/libexec/localsearch-3 +paul 3219 1155 0 13:19 ? 00:00:00 /usr/libexec/xdg-desktop-portal-gnome +paul 3241 1155 0 13:19 ? 00:00:00 /usr/libexec/gvfs-udisks2-volume-monitor +paul 3251 1155 0 13:19 ? 00:00:00 /usr/libexec/gvfs-mtp-volume-monitor +paul 3259 1155 0 13:19 ? 00:00:00 /usr/libexec/gvfs-gphoto2-volume-monitor +paul 3265 1155 0 13:20 ? 00:00:00 /usr/libexec/gvfs-goa-volume-monitor +paul 3271 1155 0 13:20 ? 00:00:00 /usr/libexec/goa-daemon +paul 3280 1155 0 13:20 ? 00:00:00 /usr/libexec/goa-identity-service +paul 3287 1155 0 13:20 ? 00:00:00 /usr/libexec/gvfs-afc-volume-monitor +paul 3303 3012 0 13:20 ? 00:00:02 /usr/libexec/ibus-engine-simple +paul 3372 1155 0 13:20 ? 00:00:00 /usr/libexec/xdg-desktop-portal-gtk +paul 3441 1155 0 13:20 ? 00:00:00 /usr/libexec/gvfsd-metadata +paul 3453 1155 0 13:20 ? 00:00:00 /usr/libexec/evolution-calendar-factory +paul 3495 1155 0 13:20 ? 00:00:00 /usr/libexec/evolution-addressbook-factory +paul 4798 1155 0 13:26 ? 00:00:09 /usr/libexec/gnome-terminal-server +paul 4810 4798 0 13:26 pts/0 00:00:00 bash +paul 8614 1155 0 13:29 ? 00:00:01 /usr/bin/speech-dispatcher -s -t 0 +paul 8656 8614 0 13:29 ? 00:00:00 [sd_espeak-ng-mb] +paul 8709 8614 0 13:29 ? 00:00:00 /usr/lib/speech-dispatcher-modules/sd_espeak-ng /etc/speech-dispatcher/modules/espeak-ng.conf +paul 8785 8614 0 13:29 ? 00:00:00 /usr/lib/speech-dispatcher-modules/sd_dummy /etc/speech-dispatcher/modules/dummy.conf +paul 8799 8614 0 13:29 ? 00:00:00 /usr/lib/speech-dispatcher-modules/sd_espeak-ng /etc/speech-dispatcher/modules/ +paul 10028 1155 0 13:31 ? 00:00:00 adb -L tcp:5037 fork-server server --reply-fd 4 +paul 69578 2814 0 13:53 ? 00:00:00 /usr/libexec/gvfsd-http --spawner :1.22 /org/gtk/gvfs/exec_spaw/0 +paul 108341 1155 3 14:06 ? 00:00:48 /home/paul/.nvm/versions/node/v22.23.0/bin/node /home/paul/.nvm/versions/node/v22.23.0/lib/node_modules/acpx/dist/cli.js __queue-owner +paul 108416 108341 0 14:06 ? 00:00:00 openclaw +paul 108458 108416 2 14:06 ? 00:00:37 openclaw-acp +paul 143553 1155 0 14:19 ? 00:00:05 /home/paul/Workspace/yavsc/src/PostIt.Tests/bin/Debug/net10.0/PostIt.Tests @@ /tmp/tmpI2JxLw.tmp +paul 149205 1155 0 14:21 ? 00:00:05 /home/paul/Workspace/yavsc/src/PostIt.Tests/bin/Debug/net10.0/PostIt.Tests @@ /tmp/tmpitRyQG.tmp +paul 151724 1155 0 14:22 ? 00:00:04 /home/paul/Workspace/yavsc/src/PostIt.Tests/bin/Debug/net10.0/PostIt.Tests @@ /tmp/tmpJEsOZV.tmp +paul 157447 1155 1 14:24 ? 00:00:05 /home/paul/Workspace/yavsc/src/PostIt.Tests/bin/Debug/net10.0/PostIt.Tests @@ /tmp/tmpyM92DV.tmp +paul 165231 1155 0 14:26 ? 00:00:01 /home/paul/Workspace/yavsc/src/PostIt.Tests/bin/Debug/net10.0/PostIt.Tests @@ /tmp/tmp5CKC19.tmp +paul 168472 1155 4 14:27 ? 00:00:09 /home/paul/Workspace/yavsc/src/PostIt.Tests/bin/Debug/net10.0/PostIt.Tests @@ /tmp/tmpuRJsnQ.tmp +paul 172147 1155 4 14:29 pts/0 00:00:05 /home/paul/Workspace/yavsc/src/PostIt.Tests/bin/Debug/net10.0/PostIt.Tests @@ /tmp/tmpxT8nje.tmp +paul 172435 4810 99 14:31 pts/0 00:00:00 ps -fu paul diff --git a/src/PostIt/PostIt/App.axaml.cs b/src/PostIt/PostIt/App.axaml.cs index 1a68f4ac..9105e626 100644 --- a/src/PostIt/PostIt/App.axaml.cs +++ b/src/PostIt/PostIt/App.axaml.cs @@ -350,4 +350,9 @@ public partial class App : Application return window.NavRoot.PushAsync(page); } + + internal async Task GoBackAsync() + { + await window.NavRoot.PopAsync(); + } } diff --git a/src/PostIt/PostIt/ViewModels/AddCircleMemberDialogViewModel.cs b/src/PostIt/PostIt/ViewModels/AddCircleMemberDialogViewModel.cs index a721d738..59d6dbed 100644 --- a/src/PostIt/PostIt/ViewModels/AddCircleMemberDialogViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/AddCircleMemberDialogViewModel.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using PostIt.Services; +using PostIt.Views; using Yavsc.Api.Client; namespace PostIt.ViewModels; @@ -106,7 +107,7 @@ public partial class AddCircleMemberDialogViewModel : ViewModelBase /// UI from firing an event with a null payload. /// [RelayCommand] - public void Add() + public async Task AddAsync() { if (Selected is null) { @@ -114,5 +115,14 @@ public partial class AddCircleMemberDialogViewModel : ViewModelBase return; } Confirmed?.Invoke(this, Selected); + var app = App.Current as App; + await app.GoBackAsync(); + } + + [RelayCommand] + public async Task CloseAsync() + { + var app = App.Current as App; + await app.GoBackAsync(); } } diff --git a/src/PostIt/PostIt/ViewModels/CirclesPageViewModel.cs b/src/PostIt/PostIt/ViewModels/CirclesPageViewModel.cs index bfc431b8..33a5bd30 100644 --- a/src/PostIt/PostIt/ViewModels/CirclesPageViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/CirclesPageViewModel.cs @@ -119,6 +119,17 @@ public partial class CirclesPageViewModel : ViewModelBase var directory = services.GetRequiredService(); AddCircleMemberDialogViewModel model = new AddCircleMemberDialogViewModel(directory); + // Wire the dialog's Confirmed event to OnAddMemberConfirmedAsync. + // Without this, the dialog's "Ajouter" button fires the event + // into the void: no subscriber, the picked user is silently + // dropped, and nothing is added to the circle. The dialog + // stays open until the user uses the back gesture — which is + // how the user noticed the button was a no-op. + // Async-void is intentional here: Confirmed is an + // EventHandler (returns void), and bridging to the + // async Task OnAddMemberConfirmedAsync requires it. + model.Confirmed += async (_, picked) => + await OnAddMemberConfirmedAsync(_, picked); await app.PushPageAsync(model); } /// diff --git a/src/PostIt/PostIt/ViewModels/PostAclDialogViewModel.cs b/src/PostIt/PostIt/ViewModels/PostAclDialogViewModel.cs index ae48fd8c..908692b3 100644 --- a/src/PostIt/PostIt/ViewModels/PostAclDialogViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/PostAclDialogViewModel.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Linq; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; @@ -52,6 +51,22 @@ public partial class PostAclDialogViewModel : ViewModelBase [ObservableProperty] public partial string StatusMessage { get; set; } = string.Empty; + /// + /// Idempotency gate for : the dialog + /// attaches the load trigger in DataContextChanged, + /// which can fire more than once if the page is detached + /// and re-attached (dialog re-use, navigation edge cases) + /// with a different VM. Without this guard, the second load + /// would race against the first and could overwrite + /// mid-edit. Pattern copied from + /// Settings.Load. + /// + private bool _loaded; + + /// True once has run at least + /// once. Exposed for tests; do not bind from XAML. + public bool Loaded => _loaded; + public PostAclDialogViewModel( BlogPostDto post, BlogAclApiClient aclClient, @@ -68,6 +83,8 @@ public partial class PostAclDialogViewModel : ViewModelBase [RelayCommand] public async Task LoadAsync() { + if (_loaded) return; + IsBusy = true; try { @@ -83,6 +100,7 @@ public partial class PostAclDialogViewModel : ViewModelBase StatusMessage = $"{AclEntries.Count} autorisation(s)"; + _loaded = true; } catch (Exception ex) { diff --git a/src/PostIt/PostIt/Views/AddCircleMemberDialog.axaml b/src/PostIt/PostIt/Views/AddCircleMemberDialog.axaml index 5d1e2531..8b232988 100644 --- a/src/PostIt/PostIt/Views/AddCircleMemberDialog.axaml +++ b/src/PostIt/PostIt/Views/AddCircleMemberDialog.axaml @@ -6,6 +6,7 @@ xmlns:services="using:PostIt.Services" x:DataType="vm:AddCircleMemberDialogViewModel" > + @@ -29,7 +30,9 @@ + SelectedItem="{Binding Selected, Mode=TwoWay}" + MinHeight="20" + > @@ -47,11 +50,13 @@ /// /// Le path retourné est aligné sur - /// (minuscule). + /// (minuscule). /// Les anciens display templates utilisaient "/Avatars/" /// avec un S majuscule, en désaccord avec le path statique /// servi par le middleware de fichiers — les images ne @@ -29,8 +29,8 @@ namespace Yavsc.Abstract.Identity public static string AvatarSrc(IApplicationUser? user) { if (user==null || string.IsNullOrWhiteSpace(user?.UserName)) - return YavscConstants.DefaultAvatar; - return $"{YavscConstants.AvatarsPath}/{user!.UserName}.s.png"; + return Constants.DefaultAvatar; + return $"{Constants.AvatarsPath}/{user!.UserName}.s.png"; } } } diff --git a/src/Yavsc.Api/Controllers/Business/ActivityApiController.cs b/src/Yavsc.Api/Controllers/Business/ActivityApiController.cs index d2da2ea7..5aeddc57 100644 --- a/src/Yavsc.Api/Controllers/Business/ActivityApiController.cs +++ b/src/Yavsc.Api/Controllers/Business/ActivityApiController.cs @@ -14,7 +14,7 @@ using Yavsc.Models.Workflow; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/activity")] + [Route(Constants.APIPrefix + "/activity")] public class ActivityApiController : Controller { private ApplicationDbContext _context; diff --git a/src/Yavsc.Api/Controllers/Business/BillingController.cs b/src/Yavsc.Api/Controllers/Business/BillingController.cs index 87035406..72180fc1 100644 --- a/src/Yavsc.Api/Controllers/Business/BillingController.cs +++ b/src/Yavsc.Api/Controllers/Business/BillingController.cs @@ -19,7 +19,7 @@ namespace Yavsc.ApiControllers using Yavsc.ViewModels.Auth; using Yavsc.Server.Helpers; - [Route("api/bill"), Authorize] + [Route(Constants.APIPrefix + "/bill"), Authorize] public class BillingController : Controller { readonly ApplicationDbContext dbContext; diff --git a/src/Yavsc.Api/Controllers/Business/BookQueryApiController.cs b/src/Yavsc.Api/Controllers/Business/BookQueryApiController.cs index 494075c6..7e58b071 100644 --- a/src/Yavsc.Api/Controllers/Business/BookQueryApiController.cs +++ b/src/Yavsc.Api/Controllers/Business/BookQueryApiController.cs @@ -18,7 +18,7 @@ namespace Yavsc.Controllers using Yavsc.Server.Helpers; [Produces("application/json")] - [Route("api/bookquery"), Authorize("Performer")] + [Route(Constants.APIPrefix + "/bookquery"), Authorize("Performer")] public class BookQueryApiController : Controller { private ApplicationDbContext _context; diff --git a/src/Yavsc.Api/Controllers/Business/EstimateApiController.cs b/src/Yavsc.Api/Controllers/Business/EstimateApiController.cs index 41bdd353..902cb038 100644 --- a/src/Yavsc.Api/Controllers/Business/EstimateApiController.cs +++ b/src/Yavsc.Api/Controllers/Business/EstimateApiController.cs @@ -15,7 +15,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/estimate"), Authorize] + [Route(Constants.APIPrefix + "/estimate"), Authorize] public class EstimateApiController : Controller { private readonly ApplicationDbContext _context; @@ -27,12 +27,12 @@ namespace Yavsc.Controllers } bool UserIsAdminOrThis(string uid) { - if (User.IsInRole(YavscConstants.AdminGroupName)) return true; + if (User.IsInRole(Constants.AdminGroupName)) return true; return uid == User.GetUserId(); } bool UserIsAdminOrInThese(string oid, string uid) { - if (User.IsInRole(YavscConstants.AdminGroupName)) return true; + if (User.IsInRole(Constants.AdminGroupName)) return true; var cuid = User.GetUserId(); return cuid == uid || cuid == oid; } @@ -82,7 +82,7 @@ namespace Yavsc.Controllers return BadRequest(); } var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); - if (!User.IsInRole(YavscConstants.AdminGroupName)) + if (!User.IsInRole(Constants.AdminGroupName)) { if (uid != estimate.OwnerId) { @@ -118,7 +118,7 @@ namespace Yavsc.Controllers var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); if (estimate.OwnerId == null) estimate.OwnerId = uid; - if (!User.IsInRole(YavscConstants.AdminGroupName)) + if (!User.IsInRole(Constants.AdminGroupName)) { if (uid != estimate.OwnerId) { @@ -187,7 +187,7 @@ namespace Yavsc.Controllers return NotFound(); } var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); - if (!User.IsInRole(YavscConstants.AdminGroupName)) + if (!User.IsInRole(Constants.AdminGroupName)) { if (uid != estimate.OwnerId) { diff --git a/src/Yavsc.Api/Controllers/Business/EstimateTemplatesApiController.cs b/src/Yavsc.Api/Controllers/Business/EstimateTemplatesApiController.cs index 4442e0b3..81de4cac 100644 --- a/src/Yavsc.Api/Controllers/Business/EstimateTemplatesApiController.cs +++ b/src/Yavsc.Api/Controllers/Business/EstimateTemplatesApiController.cs @@ -9,7 +9,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/EstimateTemplatesApi")] + [Route(Constants.APIPrefix + "/EstimateTemplatesApi")] public class EstimateTemplatesApiController : Controller { private ApplicationDbContext _context; @@ -62,7 +62,7 @@ namespace Yavsc.Controllers } var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); if (estimateTemplate.OwnerId!=uid) - if (!User.IsInRole(YavscConstants.AdminGroupName)) + if (!User.IsInRole(Constants.AdminGroupName)) return new StatusCodeResult(StatusCodes.Status403Forbidden); _context.Entry(estimateTemplate).State = EntityState.Modified; @@ -132,7 +132,7 @@ namespace Yavsc.Controllers } var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); if (estimateTemplate.OwnerId!=uid) - if (!User.IsInRole(YavscConstants.AdminGroupName)) + if (!User.IsInRole(Constants.AdminGroupName)) return new StatusCodeResult(StatusCodes.Status403Forbidden); _context.EstimateTemplates.Remove(estimateTemplate); diff --git a/src/Yavsc.Api/Controllers/Business/FrontOfficeApiController.cs b/src/Yavsc.Api/Controllers/Business/FrontOfficeApiController.cs index b91cba51..c05da827 100644 --- a/src/Yavsc.Api/Controllers/Business/FrontOfficeApiController.cs +++ b/src/Yavsc.Api/Controllers/Business/FrontOfficeApiController.cs @@ -8,7 +8,7 @@ using Yavsc.ViewModels.FrontOffice; namespace Yavsc.ApiControllers { - [Route("api/front")] + [Route(Constants.APIPrefix + "/front")] public class FrontOfficeApiController : Controller { ApplicationDbContext dbContext; diff --git a/src/Yavsc.Api/Controllers/Business/PaymentApiController.cs b/src/Yavsc.Api/Controllers/Business/PaymentApiController.cs index 3076dbe1..5f769e4e 100644 --- a/src/Yavsc.Api/Controllers/Business/PaymentApiController.cs +++ b/src/Yavsc.Api/Controllers/Business/PaymentApiController.cs @@ -6,7 +6,7 @@ using Yavsc.Models; namespace Yavsc.ApiControllers { - [Route("api/payment")] + [Route(Constants.APIPrefix + "/payment")] public class PaymentApiController : Controller { private readonly ApplicationDbContext dbContext; diff --git a/src/Yavsc.Api/Controllers/Business/PerformersApiController.cs b/src/Yavsc.Api/Controllers/Business/PerformersApiController.cs index b552eff3..2ad1ded5 100644 --- a/src/Yavsc.Api/Controllers/Business/PerformersApiController.cs +++ b/src/Yavsc.Api/Controllers/Business/PerformersApiController.cs @@ -11,7 +11,7 @@ namespace Yavsc.Controllers using Yavsc.Services; [Produces("application/json")] - [Route("api/performers")] + [Route(Constants.APIPrefix + "/performers")] public class PerformersApiController : Controller { ApplicationDbContext dbContext; diff --git a/src/Yavsc.Api/Controllers/Business/ProductApiController.cs b/src/Yavsc.Api/Controllers/Business/ProductApiController.cs index abd621c3..97a60fdb 100644 --- a/src/Yavsc.Api/Controllers/Business/ProductApiController.cs +++ b/src/Yavsc.Api/Controllers/Business/ProductApiController.cs @@ -9,7 +9,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/ProductApi")] + [Route(Constants.APIPrefix + "/ProductApi")] public class ProductApiController : Controller { private readonly ApplicationDbContext _context; @@ -46,7 +46,7 @@ namespace Yavsc.Controllers } // PUT: api/ProductApi/5 - [HttpPut("{id}"),Authorize(YavscConstants.FrontOfficeGroupName)] + [HttpPut("{id}"),Authorize(Constants.FrontOfficeGroupName)] public IActionResult PutProduct(long id, [FromBody] Product product) { if (!ModelState.IsValid) @@ -81,7 +81,7 @@ namespace Yavsc.Controllers } // POST: api/ProductApi - [HttpPost,Authorize(YavscConstants.FrontOfficeGroupName)] + [HttpPost,Authorize(Constants.FrontOfficeGroupName)] public IActionResult PostProduct([FromBody] Product product) { if (!ModelState.IsValid) @@ -110,7 +110,7 @@ namespace Yavsc.Controllers } // DELETE: api/ProductApi/5 - [HttpDelete("{id}"),Authorize(YavscConstants.FrontOfficeGroupName)] + [HttpDelete("{id}"),Authorize(Constants.FrontOfficeGroupName)] public IActionResult DeleteProduct(long id) { if (!ModelState.IsValid) diff --git a/src/Yavsc.Api/Controllers/HairCut/BursherProfilesApiController.cs b/src/Yavsc.Api/Controllers/HairCut/BursherProfilesApiController.cs index 22fdf1e9..cd3a561b 100644 --- a/src/Yavsc.Api/Controllers/HairCut/BursherProfilesApiController.cs +++ b/src/Yavsc.Api/Controllers/HairCut/BursherProfilesApiController.cs @@ -8,7 +8,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/bursherprofiles")] + [Route(Constants.APIPrefix + "/bursherprofiles")] public class BursherProfilesApiController : Controller { private readonly ApplicationDbContext _context; @@ -57,7 +57,7 @@ namespace Yavsc.Controllers { return BadRequest(); } - + if (id != User.GetUserId()) { return BadRequest(); diff --git a/src/Yavsc.Api/Controllers/HairCut/HairCutController.cs b/src/Yavsc.Api/Controllers/HairCut/HairCutController.cs index 822c3182..c1181f54 100644 --- a/src/Yavsc.Api/Controllers/HairCut/HairCutController.cs +++ b/src/Yavsc.Api/Controllers/HairCut/HairCutController.cs @@ -24,7 +24,7 @@ namespace Yavsc.ApiControllers using Microsoft.AspNetCore.Authorization; using Yavsc.Server.Helpers; - [Route("api/haircut")][Authorize] + [Route(Constants.APIPrefix + "/haircut")][Authorize] public class HairCutController : Controller { private readonly ApplicationDbContext _context; diff --git a/src/Yavsc.Api/Controllers/HyperLinkApiController.cs b/src/Yavsc.Api/Controllers/HyperLinkApiController.cs index b2d28baa..3ba74219 100644 --- a/src/Yavsc.Api/Controllers/HyperLinkApiController.cs +++ b/src/Yavsc.Api/Controllers/HyperLinkApiController.cs @@ -6,7 +6,7 @@ using Yavsc.Models.Relationship; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/hyperlink")] + [Route(Constants.APIPrefix + "/hyperlink")] public class HyperLinkApiController : Controller { private ApplicationDbContext _context; diff --git a/src/Yavsc.Api/Controllers/IT/GitRefsApiController.cs b/src/Yavsc.Api/Controllers/IT/GitRefsApiController.cs index 55ae08b7..67f38d22 100644 --- a/src/Yavsc.Api/Controllers/IT/GitRefsApiController.cs +++ b/src/Yavsc.Api/Controllers/IT/GitRefsApiController.cs @@ -7,7 +7,7 @@ using Yavsc.Server.Models.IT.SourceCode; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/GitRefsApi")] + [Route(Constants.APIPrefix + "/GitRefsApi")] [Authorize("AdministratorOnly")] public class GitRefsApiController : Controller { diff --git a/src/Yavsc.Api/Controllers/MailTemplatingApiController.cs b/src/Yavsc.Api/Controllers/MailTemplatingApiController.cs index 958ade66..c289c3da 100644 --- a/src/Yavsc.Api/Controllers/MailTemplatingApiController.cs +++ b/src/Yavsc.Api/Controllers/MailTemplatingApiController.cs @@ -2,9 +2,9 @@ using Microsoft.AspNetCore.Mvc; namespace Yavsc.ApiControllers { - [Route("api/mailtemplate")] + [Route(Constants.APIPrefix + "/mailtemplate")] public class MailTemplatingApiController: Controller { - + } } diff --git a/src/Yavsc.Api/Controllers/MailingTemplateApiController.cs b/src/Yavsc.Api/Controllers/MailingTemplateApiController.cs index dc535476..4373d847 100644 --- a/src/Yavsc.Api/Controllers/MailingTemplateApiController.cs +++ b/src/Yavsc.Api/Controllers/MailingTemplateApiController.cs @@ -7,7 +7,7 @@ using Microsoft.EntityFrameworkCore; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/mailing")] + [Route(Constants.APIPrefix + "/mailing")] [Authorize("AdministratorOnly")] public class MailingTemplateApiController : Controller { diff --git a/src/Yavsc.Api/Controllers/Musical/MusicalPreferencesApiController.cs b/src/Yavsc.Api/Controllers/Musical/MusicalPreferencesApiController.cs index 944b335b..dc935c14 100644 --- a/src/Yavsc.Api/Controllers/Musical/MusicalPreferencesApiController.cs +++ b/src/Yavsc.Api/Controllers/Musical/MusicalPreferencesApiController.cs @@ -8,7 +8,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/museprefs")] + [Route(Constants.APIPrefix + "/museprefs")] public class MusicalPreferencesApiController : Controller { private readonly ApplicationDbContext _context; diff --git a/src/Yavsc.Api/Controllers/Musical/MusicalTendenciesApiController.cs b/src/Yavsc.Api/Controllers/Musical/MusicalTendenciesApiController.cs index eacccb0a..e72090f6 100644 --- a/src/Yavsc.Api/Controllers/Musical/MusicalTendenciesApiController.cs +++ b/src/Yavsc.Api/Controllers/Musical/MusicalTendenciesApiController.cs @@ -8,7 +8,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/MusicalTendenciesApi")] + [Route(Constants.APIPrefix + "/MusicalTendenciesApi")] public class MusicalTendenciesApiController : Controller { private readonly ApplicationDbContext _context; diff --git a/src/Yavsc.Api/Controllers/PostRateApiController.cs b/src/Yavsc.Api/Controllers/PostRateApiController.cs index dc132da4..50d6d2e9 100644 --- a/src/Yavsc.Api/Controllers/PostRateApiController.cs +++ b/src/Yavsc.Api/Controllers/PostRateApiController.cs @@ -37,7 +37,7 @@ namespace Yavsc.Controllers var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); if (blogpost.AuthorId!=uid) - if (!User.IsInRole(YavscConstants.AdminGroupName)) + if (!User.IsInRole(Constants.AdminGroupName)) return BadRequest(); _context.SaveChanges(User.GetUserId()); diff --git a/src/Yavsc.Api/Controllers/ProfileApiController.cs b/src/Yavsc.Api/Controllers/ProfileApiController.cs index 60ad1f60..93bf2a4e 100644 --- a/src/Yavsc.Api/Controllers/ProfileApiController.cs +++ b/src/Yavsc.Api/Controllers/ProfileApiController.cs @@ -7,8 +7,8 @@ namespace Yavsc.ApiControllers /// /// Base class for managing performers profiles /// - [Produces("application/json"),Route("api/profile")] - public abstract class ProfileApiController : Controller + [Produces("application/json"),Route(Constants.APIPrefix + "/profile")] + public abstract class ProfileApiController : Controller { public ProfileApiController() { } diff --git a/src/Yavsc.Api/Controllers/Relationship/BlackListApiController.cs b/src/Yavsc.Api/Controllers/Relationship/BlackListApiController.cs index ebc1c03b..32cf8495 100644 --- a/src/Yavsc.Api/Controllers/Relationship/BlackListApiController.cs +++ b/src/Yavsc.Api/Controllers/Relationship/BlackListApiController.cs @@ -10,7 +10,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/blacklist"), Authorize] + [Route(Constants.APIPrefix + "/blacklist"), Authorize] public class BlackListApiController : Controller { private readonly ApplicationDbContext _context; @@ -50,8 +50,8 @@ namespace Yavsc.Controllers { var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); if (uid != blackListed.OwnerId) - if (!User.IsInRole(YavscConstants.AdminGroupName)) - if (!User.IsInRole(YavscConstants.FrontOfficeGroupName)) + if (!User.IsInRole(Constants.AdminGroupName)) + if (!User.IsInRole(Constants.FrontOfficeGroupName)) return false; return true; } @@ -140,7 +140,7 @@ namespace Yavsc.Controllers if (!CheckPermission(blackListed)) return BadRequest(); - + _context.BlackListed.Remove(blackListed); _context.SaveChanges(User.GetUserId()); diff --git a/src/Yavsc.Api/Controllers/Relationship/ChatApiController.cs b/src/Yavsc.Api/Controllers/Relationship/ChatApiController.cs index cdaeecde..b991c0fb 100644 --- a/src/Yavsc.Api/Controllers/Relationship/ChatApiController.cs +++ b/src/Yavsc.Api/Controllers/Relationship/ChatApiController.cs @@ -9,14 +9,14 @@ using Microsoft.EntityFrameworkCore; namespace Yavsc.Controllers { - [Route("api/chat")] + [Route(Constants.APIPrefix + "/chat")] public class ChatApiController : Controller { readonly ApplicationDbContext dbContext; readonly UserManager userManager; private readonly IConnexionManager _cxManager; public ChatApiController(ApplicationDbContext dbContext, - UserManager userManager, + UserManager userManager, IConnexionManager cxManager) { this.dbContext = dbContext; diff --git a/src/Yavsc.Api/Controllers/Relationship/ChatRoomAccessApiController.cs b/src/Yavsc.Api/Controllers/Relationship/ChatRoomAccessApiController.cs index 5fe3a0bf..fba8bd43 100644 --- a/src/Yavsc.Api/Controllers/Relationship/ChatRoomAccessApiController.cs +++ b/src/Yavsc.Api/Controllers/Relationship/ChatRoomAccessApiController.cs @@ -9,7 +9,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/ChatRoomAccessApi")] + [Route(Constants.APIPrefix + "/ChatRoomAccessApi")] public class ChatRoomAccessApiController : Controller { private readonly ApplicationDbContext _context; @@ -37,7 +37,7 @@ namespace Yavsc.Controllers ChatRoomAccess chatRoomAccess = await _context.ChatRoomAccess.SingleAsync(m => m.ChannelName == id); - + if (chatRoomAccess == null) { @@ -46,13 +46,13 @@ namespace Yavsc.Controllers var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); if (uid != chatRoomAccess.UserId && uid != chatRoomAccess.Room.OwnerId - && ! User.IsInMsRole(YavscConstants.AdminGroupName)) - + && ! User.IsInMsRole(Constants.AdminGroupName)) + { ModelState.AddModelError("UserId","get refused"); return BadRequest(ModelState); } - + return Ok(chatRoomAccess); } @@ -72,7 +72,7 @@ namespace Yavsc.Controllers } var room = _context.ChatRoom.First(channel => channel.Name == chatRoomAccess.ChannelName ); - if (uid != room.OwnerId && ! User.IsInMsRole(YavscConstants.AdminGroupName)) + if (uid != room.OwnerId && ! User.IsInMsRole(Constants.AdminGroupName)) { ModelState.AddModelError("ChannelName", "access put refused"); return BadRequest(ModelState); @@ -110,7 +110,7 @@ namespace Yavsc.Controllers var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); var room = _context.ChatRoom.First(channel => channel.Name == chatRoomAccess.ChannelName ); - if (room == null || (uid != room.OwnerId && ! User.IsInMsRole(YavscConstants.AdminGroupName))) + if (room == null || (uid != room.OwnerId && ! User.IsInMsRole(Constants.AdminGroupName))) { ModelState.AddModelError("ChannelName", "access post refused"); return BadRequest(ModelState); @@ -154,7 +154,7 @@ namespace Yavsc.Controllers var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); var room = _context.ChatRoom.First(channel => channel.Name == chatRoomAccess.ChannelName ); - if (room == null || (uid != room.OwnerId && chatRoomAccess.UserId != uid && ! User.IsInMsRole(YavscConstants.AdminGroupName))) + if (room == null || (uid != room.OwnerId && chatRoomAccess.UserId != uid && ! User.IsInMsRole(Constants.AdminGroupName))) { ModelState.AddModelError("UserId", "access drop refused"); return BadRequest(ModelState); diff --git a/src/Yavsc.Api/Controllers/Relationship/ChatRoomApiController.cs b/src/Yavsc.Api/Controllers/Relationship/ChatRoomApiController.cs index 990646fc..5d59f6bd 100644 --- a/src/Yavsc.Api/Controllers/Relationship/ChatRoomApiController.cs +++ b/src/Yavsc.Api/Controllers/Relationship/ChatRoomApiController.cs @@ -8,7 +8,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/ChatRoomApi")] + [Route(Constants.APIPrefix + "/ChatRoomApi")] public class ChatRoomApiController : Controller { private readonly ApplicationDbContext _context; @@ -128,7 +128,7 @@ namespace Yavsc.Controllers } ChatRoom chatRoom = await _context.ChatRoom.SingleAsync(m => m.Name == id); - + if (chatRoom == null) { @@ -137,7 +137,7 @@ namespace Yavsc.Controllers if (User.GetUserId() != chatRoom.OwnerId ) { - if (!User.IsInMsRole(YavscConstants.AdminGroupName)) + if (!User.IsInMsRole(Constants.AdminGroupName)) return BadRequest(new {error = "OwnerId"}); } diff --git a/src/Yavsc.Api/Controllers/Relationship/ContactsApiController.cs b/src/Yavsc.Api/Controllers/Relationship/ContactsApiController.cs index ffd6eb0b..96ba03dc 100644 --- a/src/Yavsc.Api/Controllers/Relationship/ContactsApiController.cs +++ b/src/Yavsc.Api/Controllers/Relationship/ContactsApiController.cs @@ -8,7 +8,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/ContactsApi")] + [Route(Constants.APIPrefix + "/ContactsApi")] public class ContactsApiController : Controller { private readonly ApplicationDbContext _context; diff --git a/src/Yavsc.Api/Controllers/ServiceApiController.cs b/src/Yavsc.Api/Controllers/ServiceApiController.cs index e9330543..8556fb5a 100644 --- a/src/Yavsc.Api/Controllers/ServiceApiController.cs +++ b/src/Yavsc.Api/Controllers/ServiceApiController.cs @@ -9,7 +9,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/ServiceApi")] + [Route(Constants.APIPrefix + "/ServiceApi")] public class ServiceApiController : Controller { private readonly ApplicationDbContext _context; @@ -46,7 +46,7 @@ namespace Yavsc.Controllers } // PUT: api/ServiceApi/5 - [HttpPut("{id}"),Authorize(YavscConstants.FrontOfficeGroupName)] + [HttpPut("{id}"),Authorize(Constants.FrontOfficeGroupName)] public IActionResult PutService(long id, [FromBody] Service service) { if (!ModelState.IsValid) @@ -81,7 +81,7 @@ namespace Yavsc.Controllers } // POST: api/ServiceApi - [HttpPost,Authorize(YavscConstants.FrontOfficeGroupName)] + [HttpPost,Authorize(Constants.FrontOfficeGroupName)] public IActionResult PostService([FromBody] Service service) { if (!ModelState.IsValid) @@ -110,7 +110,7 @@ namespace Yavsc.Controllers } // DELETE: api/ServiceApi/5 - [HttpDelete("{id}"),Authorize(YavscConstants.FrontOfficeGroupName)] + [HttpDelete("{id}"),Authorize(Constants.FrontOfficeGroupName)] public IActionResult DeleteService(long id) { if (!ModelState.IsValid) diff --git a/src/Yavsc.Api/Controllers/accounting/ApplicationUserApiController.cs b/src/Yavsc.Api/Controllers/accounting/ApplicationUserApiController.cs index 11c70d60..cb565a0d 100644 --- a/src/Yavsc.Api/Controllers/accounting/ApplicationUserApiController.cs +++ b/src/Yavsc.Api/Controllers/accounting/ApplicationUserApiController.cs @@ -13,7 +13,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json"),Authorize("AdministratorOnly")] - [Route("api/users")] + [Route(Constants.APIPrefix + "/users")] public class ApplicationUserApiController : Controller { private readonly ApplicationDbContext _context; @@ -28,7 +28,7 @@ namespace Yavsc.Controllers public IEnumerable GetApplicationUser(int skip=0, int take = 25) { return _context.Users.Skip(skip).Take(take) - .Select(u=> new UserInfo{ + .Select(u=> new UserInfo{ UserId = u.Id, UserName = u.UserName, Avatar = u.Avatar}); @@ -39,7 +39,7 @@ namespace Yavsc.Controllers { return _context.Users.Where(u => u.UserName.Contains(pattern)) .Skip(skip).Take(take) - .Select(u=> new UserInfo { + .Select(u=> new UserInfo { UserId = u.Id, UserName = u.UserName, Avatar = u.Avatar }); diff --git a/src/Yavsc.Blogs.Tests/BlogsWebServerFixture.cs b/src/Yavsc.Blogs.Tests/BlogsWebServerFixture.cs index 1e610082..66398c5a 100644 --- a/src/Yavsc.Blogs.Tests/BlogsWebServerFixture.cs +++ b/src/Yavsc.Blogs.Tests/BlogsWebServerFixture.cs @@ -145,7 +145,7 @@ public sealed class BlogsWebServerFixture : WebHostFixture // remaps long Microsoft claim URIs, not sub). // UserHelpers.GetUserId reads sub directly. NameClaimType = "sub", - RoleClaimType = YavscConstants.RoleClaimType, + RoleClaimType = Yavsc.Constants.RoleClaimType, }; }); diff --git a/src/Yavsc.Blogs.Tests/CircleMembersApiTests.cs b/src/Yavsc.Blogs.Tests/CircleMembersApiTests.cs index 5e8040ef..a2367180 100644 --- a/src/Yavsc.Blogs.Tests/CircleMembersApiTests.cs +++ b/src/Yavsc.Blogs.Tests/CircleMembersApiTests.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Yavsc.Models; using Yavsc.Models.Relationship; using Yavsc.Tests.Shared; +using static Yavsc.Constants; namespace Yavsc.Blogs.Tests; @@ -88,7 +89,7 @@ public sealed class CircleMembersApiTests : IClassFixture } private string MembersUrl(long circleId) - => $"{_fixture.Addresses.First(a => a.StartsWith("https://"))}/{Constants.APIPrefix}/circle/{circleId}/members"; + => $"{_fixture.Addresses.First(a => a.StartsWith("https://"))}/{APIPrefix}/circle/{circleId}/members"; private HttpClient NewClient(string subject) { diff --git a/src/Yavsc.Blogs.Tests/MappedClaimsBlogsWebServerFixture.cs b/src/Yavsc.Blogs.Tests/MappedClaimsBlogsWebServerFixture.cs index c9d95774..6d84aed5 100644 --- a/src/Yavsc.Blogs.Tests/MappedClaimsBlogsWebServerFixture.cs +++ b/src/Yavsc.Blogs.Tests/MappedClaimsBlogsWebServerFixture.cs @@ -65,8 +65,8 @@ public sealed class MappedClaimsBlogsWebServerFixture : IDisposable ValidateLifetime = true, ValidateIssuerSigningKey = true, IssuerSigningKey = TestTokenIssuer.SigningKey, - RoleClaimType = YavscConstants.RoleClaimType, - NameClaimType = YavscConstants.NameClaimType, + RoleClaimType = Yavsc.Constants.RoleClaimType, + NameClaimType = Yavsc.Constants.NameClaimType, }; }); diff --git a/src/Yavsc.Blogs/Constants.cs b/src/Yavsc.Blogs/Constants.cs index 4dbdfb8b..3e499da4 100644 --- a/src/Yavsc.Blogs/Constants.cs +++ b/src/Yavsc.Blogs/Constants.cs @@ -5,6 +5,4 @@ public static class Constants public const string AdminRole = "Admin"; public const string ModeratorRole = "Moderator"; public const string UserRole = "User"; - - public const string APIPrefix = "api/v1"; } diff --git a/src/Yavsc.Blogs/Controllers/BlogAclApiController.cs b/src/Yavsc.Blogs/Controllers/BlogAclApiController.cs index aa81f9d5..94821932 100644 --- a/src/Yavsc.Blogs/Controllers/BlogAclApiController.cs +++ b/src/Yavsc.Blogs/Controllers/BlogAclApiController.cs @@ -1,15 +1,16 @@ -using System.Linq; + using System.Security.Claims; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Yavsc.Models; using Yavsc.Models.Access; using Yavsc.Server.Helpers; +using static Yavsc.Constants; namespace Yavsc.Blogs.Controllers { [Produces("application/json")] - [Route("api/blogacl")] + [Route(APIPrefix+"/blogacl")] public class BlogAclApiController : Controller { private readonly ApplicationDbContext _context; @@ -24,7 +25,7 @@ namespace Yavsc.Blogs.Controllers /// Blog posts (and therefore their ACLs) are private to their /// author — the API never exposes another user's ACL. /// - // GET: api/blogacl + // GET: api/v1/blogacl [HttpGet] public IEnumerable GetBlogACL() { diff --git a/src/Yavsc.Blogs/Controllers/BlogApiController.cs b/src/Yavsc.Blogs/Controllers/BlogApiController.cs index 76aa777e..fcd3a336 100644 --- a/src/Yavsc.Blogs/Controllers/BlogApiController.cs +++ b/src/Yavsc.Blogs/Controllers/BlogApiController.cs @@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc; using Yavsc.Blogspot; using Yavsc.Server.Exceptions; using Yavsc.Server.Helpers; -using static Yavsc.Blogs.Constants; +using static Yavsc.Constants; namespace Yavsc.Blogs.Controllers { diff --git a/src/Yavsc.Blogs/Controllers/BlogTagsApiController.cs b/src/Yavsc.Blogs/Controllers/BlogTagsApiController.cs index a5d905eb..ad6a0893 100644 --- a/src/Yavsc.Blogs/Controllers/BlogTagsApiController.cs +++ b/src/Yavsc.Blogs/Controllers/BlogTagsApiController.cs @@ -1,12 +1,8 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Yavsc.Models; using Yavsc.Models.Blog; -using static Yavsc.Blogs.Constants; +using static Yavsc.Constants; namespace Yavsc.Blogs.Controllers { [Produces("application/json")] diff --git a/src/Yavsc.Blogs/Controllers/CircleApiController.cs b/src/Yavsc.Blogs/Controllers/CircleApiController.cs index 73bbfff9..ea3c981b 100644 --- a/src/Yavsc.Blogs/Controllers/CircleApiController.cs +++ b/src/Yavsc.Blogs/Controllers/CircleApiController.cs @@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore; using Yavsc.Models; using Yavsc.Models.Relationship; using Yavsc.Server.Helpers; -using static Yavsc.Blogs.Constants; +using static Yavsc.Constants; namespace Yavsc.Blogs.Controllers { diff --git a/src/Yavsc.Blogs/Controllers/CommentsApiController.cs b/src/Yavsc.Blogs/Controllers/CommentsApiController.cs index b9f334dc..d4c80f99 100644 --- a/src/Yavsc.Blogs/Controllers/CommentsApiController.cs +++ b/src/Yavsc.Blogs/Controllers/CommentsApiController.cs @@ -5,7 +5,7 @@ using Microsoft.EntityFrameworkCore; using Yavsc.Models; using Yavsc.Models.Blog; using Yavsc.Server.Helpers; -using static Yavsc.Blogs.Constants; +using static Yavsc.Constants; namespace Yavsc.Blogs.Controllers { diff --git a/src/Yavsc.Blogs/Controllers/FileSystemApiController.cs b/src/Yavsc.Blogs/Controllers/FileSystemApiController.cs index 5b067c1b..5e834503 100644 --- a/src/Yavsc.Blogs/Controllers/FileSystemApiController.cs +++ b/src/Yavsc.Blogs/Controllers/FileSystemApiController.cs @@ -2,7 +2,7 @@ using System.Security.Claims; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using static Yavsc.Blogs.Constants; +using static Yavsc.Constants; namespace Yavsc.Blogs.Controllers { @@ -21,7 +21,7 @@ namespace Yavsc.Blogs.Controllers private readonly ILogger _logger; public FileSystemApiController(ApplicationDbContext context, - IAuthorizationService authorizationService, + IAuthorizationService authorizationService, ILoggerFactory loggerFactory) { @@ -38,7 +38,7 @@ namespace Yavsc.Blogs.Controllers [HttpGet("{*subdir}")] public IActionResult GetDir([ValidRemoteUserFilePath] string subdir="") - { + { if (!ModelState.IsValid) return new BadRequestObjectResult(ModelState); // _logger.LogInformation($"listing files from {User.Identity.Name}{subdir}"); var files = AbstractFileSystemHelpers.GetUserFiles(User.GetUserId(), subdir); @@ -57,20 +57,20 @@ namespace Yavsc.Blogs.Controllers } catch (InvalidPathException ex) { pathex = ex; } - if (pathex!=null) + if (pathex!=null) { _logger.LogError($"invalid sub path: '{subdir}'."); return BadRequest(pathex); } _logger.LogInformation($"Receiving files, saved in '{destDir}' (specified as '{subdir}')."); - + var uid = User.GetUserId(); var user = dbContext.Users.Single( u => u.Id == uid ); int i=0; _logger.LogInformation($"Receiving {Request.Form.Files.Count} files."); - + foreach (var f in Request.Form.Files) { var item = user.ReceiveUserFile(destDir, f); @@ -178,7 +178,7 @@ namespace Yavsc.Blogs.Controllers return Ok(new { deleted=id }); } - + } } diff --git a/src/Yavsc.Blogs/Controllers/FileSystemStreamController.cs b/src/Yavsc.Blogs/Controllers/FileSystemStreamController.cs index 23cf0cc6..bc6485dd 100644 --- a/src/Yavsc.Blogs/Controllers/FileSystemStreamController.cs +++ b/src/Yavsc.Blogs/Controllers/FileSystemStreamController.cs @@ -8,7 +8,7 @@ using Yavsc.Models.Messaging; using Yavsc.Services; using Microsoft.AspNetCore.SignalR; using Yavsc.Server.Helpers; -using static Yavsc.Blogs.Constants; +using static Yavsc.Constants; using Yavsc.Server.Hubs; namespace Yavsc.Blogs.Controllers diff --git a/src/Yavsc.Blogs/Controllers/PostTagsApiController.cs b/src/Yavsc.Blogs/Controllers/PostTagsApiController.cs index e908edec..da03c19c 100644 --- a/src/Yavsc.Blogs/Controllers/PostTagsApiController.cs +++ b/src/Yavsc.Blogs/Controllers/PostTagsApiController.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Mvc; -using static Yavsc.Blogs.Constants; +using static Yavsc.Constants; namespace Yavsc.Blogs.Controllers { diff --git a/src/Yavsc.Blogs/Controllers/TagsApiController.cs b/src/Yavsc.Blogs/Controllers/TagsApiController.cs index daf0220b..d4c2b538 100644 --- a/src/Yavsc.Blogs/Controllers/TagsApiController.cs +++ b/src/Yavsc.Blogs/Controllers/TagsApiController.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Mvc; using Yavsc.Models; -using static Yavsc.Blogs.Constants; +using static Yavsc.Constants; namespace Yavsc.Controllers { diff --git a/src/Yavsc.Blogs/Controllers/UserSearchApiController.cs b/src/Yavsc.Blogs/Controllers/UserSearchApiController.cs index 048db154..951a5880 100644 --- a/src/Yavsc.Blogs/Controllers/UserSearchApiController.cs +++ b/src/Yavsc.Blogs/Controllers/UserSearchApiController.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Yavsc.Models; +using static Yavsc.Constants; namespace Yavsc.Blogs.Controllers { @@ -26,7 +27,7 @@ namespace Yavsc.Blogs.Controllers /// exposing it. /// [Produces("application/json")] - [Route( Constants.APIPrefix + "/user-search")] + [Route(APIPrefix + "/user-search")] [Authorize] public class UserSearchApiController : Controller { @@ -66,8 +67,9 @@ namespace Yavsc.Blogs.Controllers // book callers already know the email they're // searching for and we don't want to surface a // long tail of partial matches. - var normalised = e.Trim(); - query = query.Where(u => u.Email != null && u.Email.ToLower() == normalised.ToLower()); + var normalized = e.Trim(); + query = query.Where(u => u.Email != null && + string.Compare(u.Email, normalized, true) ==0); } if (!string.IsNullOrWhiteSpace(q)) diff --git a/src/Yavsc.Blogs/Program.cs b/src/Yavsc.Blogs/Program.cs index 742c9eee..952115d3 100644 --- a/src/Yavsc.Blogs/Program.cs +++ b/src/Yavsc.Blogs/Program.cs @@ -51,7 +51,7 @@ internal class Program // DbContextBuilder services.AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString( - YavscConstants.YavscConnectionStringName))); + Yavsc.Constants.YavscConnectionStringName))); // other services services diff --git a/src/Yavsc.Org.Tests/NonRegression/UserDisplayHelpersTests.cs b/src/Yavsc.Org.Tests/NonRegression/UserDisplayHelpersTests.cs index a0249fa4..7543a42e 100644 --- a/src/Yavsc.Org.Tests/NonRegression/UserDisplayHelpersTests.cs +++ b/src/Yavsc.Org.Tests/NonRegression/UserDisplayHelpersTests.cs @@ -14,7 +14,7 @@ namespace Yavsc.Org.Tests.NonRegression; /// ne voit rien — juste un 500 muet. /// /// Le fix passe par qui -/// retourne pour toute +/// retourne pour toute /// donnée partielle. Ces tests couvrent les trois formes de /// "donnée absente" : user null, UserName vide, UserName whitespace. /// @@ -23,21 +23,21 @@ public class UserDisplayHelpersTests [Fact] public void AvatarSrc_null_user_returns_default_avatar() { - Assert.Equal(YavscConstants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(null)); + Assert.Equal(Yavsc.Constants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(null)); } [Fact] public void AvatarSrc_user_with_empty_UserName_returns_default_avatar() { var user = new FakeUser { UserName = "" }; - Assert.Equal(YavscConstants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(user)); + Assert.Equal(Yavsc.Constants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(user)); } [Fact] public void AvatarSrc_user_with_whitespace_UserName_returns_default_avatar() { var user = new FakeUser { UserName = " " }; - Assert.Equal(YavscConstants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(user)); + Assert.Equal(Yavsc.Constants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(user)); } [Fact] @@ -47,7 +47,7 @@ public class UserDisplayHelpersTests // Le path doit matcher YavscConstants.AvatarsPath (minuscule), // pas un /Avatars/ avec S majuscule qui ne résout pas // dans le middleware de fichiers statiques. - var expected = $"{YavscConstants.AvatarsPath}/alice.s.png"; + var expected = $"{Yavsc.Constants.AvatarsPath}/alice.s.png"; Assert.Equal(expected, UserDisplayHelpers.AvatarSrc(user)); } diff --git a/src/Yavsc.Org.Tests/WebServerFixture.cs b/src/Yavsc.Org.Tests/WebServerFixture.cs index a623bc9e..edfd87d9 100644 --- a/src/Yavsc.Org.Tests/WebServerFixture.cs +++ b/src/Yavsc.Org.Tests/WebServerFixture.cs @@ -80,8 +80,8 @@ public sealed class WebServerFixture : WebHostFixture // can resolve it. The AddConfiguration extension takes care of // that plus the in-memory overrides below. builder.AddConfiguration(null).AddInMemoryCollection(new Dictionary - { - [$"ConnectionStrings:{YavscConstants.YavscConnectionStringName}"] = "InMemory", + { + [$"ConnectionStrings:{Yavsc.Constants.YavscConnectionStringName}"] = "InMemory", // SMTP test config: UserName non-null so MailSender // exercises the Authenticate branch — the // RecordingSmtpClient captures it. diff --git a/src/Yavsc.Org/Controllers/Accounting/AccountController.cs b/src/Yavsc.Org/Controllers/Accounting/AccountController.cs index 43565442..c562736d 100644 --- a/src/Yavsc.Org/Controllers/Accounting/AccountController.cs +++ b/src/Yavsc.Org/Controllers/Accounting/AccountController.cs @@ -90,7 +90,7 @@ IHtmlLocalizerFactory htmlLocalizerFactory, "ConfirmYourAccountTitle" }) Debug.Assert(!_localizer[name].ResourceNotFound); - + } @@ -116,7 +116,7 @@ IHtmlLocalizerFactory htmlLocalizerFactory, { await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName, clientId: context?.Client.ClientId)); - // only set explicit expiration here if user chooses "remember me". + // only set explicit expiration here if user chooses "remember me". // otherwise we rely upon expiration configured in cookie middleware. await HttpContext.SignInAsync(user, _roleManager, model.RememberMe, _dbContext); var authResult = await HttpContext.AuthenticateAsync(); @@ -198,7 +198,7 @@ IHtmlLocalizerFactory htmlLocalizerFactory, /// /// Entry point into the login workflow /// - [HttpGet(YavscConstants.SigninPath)] + [HttpGet(Constants.SigninPath)] public async Task Signin(SignInModel model) { // build a model so we know what to show on the login page @@ -216,11 +216,11 @@ IHtmlLocalizerFactory htmlLocalizerFactory, /// /// Handle postback from username/password login /// - /// - [HttpPost(YavscConstants.SigninPath)] + /// + [HttpPost(Constants.SigninPath)] [ValidateAntiForgeryToken] [AllowAnonymous] - + public async Task Signin([FromForm] SignInModel model, [FromForm] string button) { @@ -232,7 +232,7 @@ IHtmlLocalizerFactory htmlLocalizerFactory, { if (context != null) { - // if the user cancels, send a result back into IdentityServer as if they + // if the user cancels, send a result back into IdentityServer as if they // denied the consent (even if this client does not require consent). // this will send back an access denied OIDC error response to the client. await _interaction.DenyAuthorizationAsync(context, AuthorizationError.AccessDenied); @@ -269,7 +269,7 @@ IHtmlLocalizerFactory htmlLocalizerFactory, { await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName, clientId: context?.Client.ClientId)); - // only set explicit expiration here if user chooses "remember me". + // only set explicit expiration here if user chooses "remember me". // otherwise we rely upon expiration configured in cookie middleware. await HttpContext.SignInAsync(user, _roleManager, model.RememberMe, _dbContext); @@ -396,7 +396,7 @@ IHtmlLocalizerFactory htmlLocalizerFactory, var local = context.IdP == IdentityServer8.IdentityServerConstants.LocalIdentityProvider; // this is meant to short circuit the UI and only trigger the one external IdP - + model.EnableLocalLogin = local; model.UserName = context?.LoginHint; model.IsExternalLoginOnly = false; @@ -579,7 +579,7 @@ IHtmlLocalizerFactory htmlLocalizerFactory, // Send an email with this link Uri authority = new Uri(Config.Authority); - + var code = await _userManager.GenerateEmailConfirmationTokenAsync(user); var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code }, @@ -659,7 +659,7 @@ IHtmlLocalizerFactory htmlLocalizerFactory, } // // POST: /Account/LogOff - [HttpPost(YavscConstants.LogoutPath)] + [HttpPost(Constants.LogoutPath)] [ValidateAntiForgeryToken] public async Task LogOff(string returnUrl = null) { @@ -829,7 +829,7 @@ IHtmlLocalizerFactory htmlLocalizerFactory, bool result = false; try { - result = await _userManager.VerifyTwoFactorTokenAsync(user, YavscConstants.DefaultFactor, code); + result = await _userManager.VerifyTwoFactorTokenAsync(user, Constants.DefaultFactor, code); _dbContext.SaveChanges(userId); } catch (Exception ex) @@ -1024,12 +1024,12 @@ IHtmlLocalizerFactory htmlLocalizerFactory, } // Generate the token and send it - if (model.SelectedProvider == YavscConstants.MobileAppFactor) + if (model.SelectedProvider == Constants.MobileAppFactor) { return View("Error", new Exception("No mobile app service was activated")); } else - if (model.SelectedProvider == YavscConstants.SMSFactor) + if (model.SelectedProvider == Constants.SMSFactor) { return View("Error", new Exception("No SMS service was activated")); // await _smsSender.SendSmsAsync(_twilioSettings, await _userManager.GetPhoneNumberAsync(user), message); diff --git a/src/Yavsc.Org/Controllers/Administration/AdministrationController.cs b/src/Yavsc.Org/Controllers/Administration/AdministrationController.cs index 7104e178..e2944e9e 100644 --- a/src/Yavsc.Org/Controllers/Administration/AdministrationController.cs +++ b/src/Yavsc.Org/Controllers/Administration/AdministrationController.cs @@ -50,12 +50,12 @@ namespace Yavsc.Controllers { // ensure all roles existence foreach (string roleName in new string[] { - YavscConstants.AdminGroupName, - YavscConstants.StarGroupName, - YavscConstants.PerformerGroupName, - YavscConstants.FrontOfficeGroupName, - YavscConstants.StarHunterGroupName, - YavscConstants.BlogModeratorGroupName + Constants.AdminGroupName, + Constants.StarGroupName, + Constants.PerformerGroupName, + Constants.FrontOfficeGroupName, + Constants.StarHunterGroupName, + Constants.BlogModeratorGroupName }) if (!await _roleManager.RoleExistsAsync(roleName)) { @@ -80,11 +80,11 @@ namespace Yavsc.Controllers public async Task Take() { // If some amdin already exists, make this method disapear - var admins = await _userManager.GetUsersInRoleAsync(YavscConstants.AdminGroupName); + var admins = await _userManager.GetUsersInRoleAsync(Constants.AdminGroupName); if (admins != null && admins.Count > 0) { // All is ok, nothing to do here. - if (User.IsInMsRole(YavscConstants.AdminGroupName)) + if (User.IsInMsRole(Constants.AdminGroupName)) { return Ok(new { message = "you already got it." }); @@ -100,7 +100,7 @@ namespace Yavsc.Controllers return new BadRequestObjectResult(ModelState); } - var addToRoleResult = await _userManager.AddToRoleAsync(user, YavscConstants.AdminGroupName); + var addToRoleResult = await _userManager.AddToRoleAsync(user, Constants.AdminGroupName); if (!addToRoleResult.Succeeded) { AddErrors(addToRoleResult); @@ -114,11 +114,11 @@ namespace Yavsc.Controllers public async Task Index() { var adminCount = await _userManager.GetUsersInRoleAsync( - YavscConstants.AdminGroupName); + Constants.AdminGroupName); var userCount = await _dbContext.Users.CountAsync(); var youAreAdmin = await _userManager.IsInRoleAsync( await _userManager.FindByIdAsync(User.GetUserId()), - YavscConstants.AdminGroupName); + Constants.AdminGroupName); var roles = await _roleManager.Roles.Select(x => new RoleInfo { diff --git a/src/Yavsc.Org/Controllers/Administration/ApiScopesApiController.cs b/src/Yavsc.Org/Controllers/Administration/ApiScopesApiController.cs index 983e7233..d6e83c36 100644 --- a/src/Yavsc.Org/Controllers/Administration/ApiScopesApiController.cs +++ b/src/Yavsc.Org/Controllers/Administration/ApiScopesApiController.cs @@ -1,13 +1,13 @@ using IdentityServer8.EntityFramework.Entities; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Yavsc.Models; using Yavsc.Server.Helpers; +using static Yavsc.Constants; namespace Yavsc.Org.Controllers.Administration { - [Route("api/[controller]")] + [Route(APIPrefix + "/[controller]")] [ApiController] public class ApiScopesApiController : ControllerBase { diff --git a/src/Yavsc.Org/Controllers/Communicating/AnnouncesController.cs b/src/Yavsc.Org/Controllers/Communicating/AnnouncesController.cs index e5002168..f8b41c99 100644 --- a/src/Yavsc.Org/Controllers/Communicating/AnnouncesController.cs +++ b/src/Yavsc.Org/Controllers/Communicating/AnnouncesController.cs @@ -18,11 +18,11 @@ namespace Yavsc.Controllers readonly IStringLocalizer _localizer; readonly IAuthorizationService _authorizationService; - public AnnouncesController(ApplicationDbContext context, + public AnnouncesController(ApplicationDbContext context, IAuthorizationService authorizationService, IStringLocalizer localizer) { - _context = context; + _context = context; _authorizationService = authorizationService; _localizer = localizer; } @@ -59,16 +59,16 @@ namespace Yavsc.Controllers } private async Task SetupView(Announce announce) { - ViewBag.IsAdmin = User.IsInMsRole(YavscConstants.AdminGroupName); - ViewBag.IsPerformer = User.IsInMsRole(YavscConstants.PerformerGroupName); + ViewBag.IsAdmin = User.IsInMsRole(Constants.AdminGroupName); + ViewBag.IsPerformer = User.IsInMsRole(Constants.PerformerGroupName); ViewBag.AllowEdit = announce==null || announce.Id<=0 || !_authorizationService.AuthorizeAsync(User,announce,new EditPermission()).IsFaulted; List dl = new List(); var rnames = System.Enum.GetNames(typeof(Reason)); var rvalues = System.Enum.GetValues(typeof(Reason)); - + for (int i = 0; i a.Children).FirstOrDefault(a => a.Code == code); @@ -123,9 +123,9 @@ namespace Yavsc.Controllers [ValidateAntiForgeryToken] public IActionResult Create(Activity activity) { - if (activity.ParentCode==YavscConstants.NoneCode) + if (activity.ParentCode==Constants.NoneCode) activity.ParentCode=null; - if (activity.SettingsClassName==YavscConstants.NoneCode) + if (activity.SettingsClassName==Constants.NoneCode) activity.SettingsClassName=null; if (ModelState.IsValid) @@ -161,9 +161,9 @@ namespace Yavsc.Controllers [ValidateAntiForgeryToken] public IActionResult Edit(Activity activity) { - if (activity.ParentCode==YavscConstants.NoneCode) + if (activity.ParentCode==Constants.NoneCode) activity.ParentCode=null; - if (activity.SettingsClassName==YavscConstants.NoneCode) + if (activity.SettingsClassName==Constants.NoneCode) activity.SettingsClassName=null; if (ModelState.IsValid) { diff --git a/src/Yavsc.Org/Controllers/DimissClicksApiController.cs b/src/Yavsc.Org/Controllers/DimissClicksApiController.cs index 19f90787..b07bc4b3 100644 --- a/src/Yavsc.Org/Controllers/DimissClicksApiController.cs +++ b/src/Yavsc.Org/Controllers/DimissClicksApiController.cs @@ -10,7 +10,7 @@ using Yavsc.Server.Helpers; namespace Yavsc.Controllers { [Produces("application/json")] - [Route("api/v1/dimiss")] + [Route(Constants.APIPrefix + "/v1/dimiss")] public class DimissClicksApiController : Controller { private readonly ApplicationDbContext _context; @@ -140,7 +140,7 @@ namespace Yavsc.Controllers var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); if (!User.IsInRole("Administrator")) if (uid != id) return new ChallengeResult(); - + if (!ModelState.IsValid) { return BadRequest(ModelState); diff --git a/src/Yavsc.Org/Controllers/HomeController.cs b/src/Yavsc.Org/Controllers/HomeController.cs index 67c19fed..c7aa131f 100644 --- a/src/Yavsc.Org/Controllers/HomeController.cs +++ b/src/Yavsc.Org/Controllers/HomeController.cs @@ -20,10 +20,10 @@ namespace Yavsc.Controllers readonly IHtmlLocalizer _localizer; private SiteSettings siteSettings; - public HomeController(ILogger logger, - IHtmlLocalizer localizer, + public HomeController(ILogger logger, + IHtmlLocalizer localizer, ApplicationDbContext context, - IOptions settingsOptions, + IOptions settingsOptions, IWebHostEnvironment env ) { @@ -37,9 +37,9 @@ namespace Yavsc.Controllers public async Task Index(string id) { - ViewBag.IsFromSecureProx = Request.Headers.ContainsKey(YavscConstants.SshHeaderKey) && Request.Headers[YavscConstants.SshHeaderKey] == "on"; + ViewBag.IsFromSecureProx = Request.Headers.ContainsKey(Constants.SshHeaderKey) && Request.Headers[Constants.SshHeaderKey] == "on"; ViewBag.SecureHomeUrl = "https://" + Request.Headers["X-Forwarded-Host"]; - ViewBag.SshHeaderKey = Request.Headers[YavscConstants.SshHeaderKey]; + ViewBag.SshHeaderKey = Request.Headers[Constants.SshHeaderKey]; var uid = User.GetUserId(); long[] clicked = null; if (uid == null) @@ -140,8 +140,8 @@ namespace Yavsc.Controllers errorViewModel.Description ??= string.Empty; errorViewModel.Description += " Page: Home."; } - - + + return View("~/Views/Shared/Error.cshtml", errorViewModel); } public IActionResult Status(int id) diff --git a/src/Yavsc.Org/Controllers/Musical/InstrumentationController.cs b/src/Yavsc.Org/Controllers/Musical/InstrumentationController.cs index dc905d08..536c7417 100644 --- a/src/Yavsc.Org/Controllers/Musical/InstrumentationController.cs +++ b/src/Yavsc.Org/Controllers/Musical/InstrumentationController.cs @@ -17,7 +17,7 @@ namespace Yavsc.Controllers public InstrumentationController(ApplicationDbContext context) { - _context = context; + _context = context; } // GET: Instrumentation @@ -50,7 +50,7 @@ namespace Yavsc.Controllers var owned = _context.Instrumentation.Include(i=>i.Tool).Where(i=>i.UserId==uid).Select(i=>i.InstrumentId); var ownedArray = owned.ToArray(); - ViewBag.YetAvailableInstruments = _context.Instrument.Select(k=>new SelectListItem + ViewBag.YetAvailableInstruments = _context.Instrument.Select(k=>new SelectListItem { Text = k.Name, Value = k.Id.ToString(), Disabled = ownedArray.Contains(k.Id) }); return View(new Instrumentation { UserId = uid }); @@ -64,7 +64,7 @@ namespace Yavsc.Controllers var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); if (ModelState.IsValid) { - if (model.UserId != uid) if (!User.IsInMsRole(YavscConstants.AdminGroupName)) + if (model.UserId != uid) if (!User.IsInMsRole(Constants.AdminGroupName)) return new ChallengeResult(); _context.Instrumentation.Add(model); @@ -82,7 +82,7 @@ namespace Yavsc.Controllers { return NotFound(); } - if (id != uid) if (!User.IsInMsRole(YavscConstants.AdminGroupName)) + if (id != uid) if (!User.IsInMsRole(Constants.AdminGroupName)) return new ChallengeResult(); Instrumentation musicianSettings = await _context.Instrumentation.SingleAsync(m => m.UserId == id); if (musicianSettings == null) @@ -98,7 +98,7 @@ namespace Yavsc.Controllers public async Task Edit(Instrumentation musicianSettings) { var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); - if (musicianSettings.UserId != uid) if (!User.IsInMsRole(YavscConstants.AdminGroupName)) + if (musicianSettings.UserId != uid) if (!User.IsInMsRole(Constants.AdminGroupName)) return new ChallengeResult(); if (ModelState.IsValid) { @@ -124,7 +124,7 @@ namespace Yavsc.Controllers return NotFound(); } var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); - if (musicianSettings.UserId != uid) if (!User.IsInMsRole(YavscConstants.AdminGroupName)) + if (musicianSettings.UserId != uid) if (!User.IsInMsRole(Constants.AdminGroupName)) return new ChallengeResult(); return View(musicianSettings); } @@ -135,12 +135,12 @@ namespace Yavsc.Controllers public async Task DeleteConfirmed(string id) { Instrumentation musicianSettings = await _context.Instrumentation.SingleAsync(m => m.UserId == id); - + var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); - if (musicianSettings.UserId != uid) if (!User.IsInMsRole(YavscConstants.AdminGroupName)) + if (musicianSettings.UserId != uid) if (!User.IsInMsRole(Constants.AdminGroupName)) return new ChallengeResult(); - + _context.Instrumentation.Remove(musicianSettings); await _context.SaveChangesAsync(User.GetUserId()); return RedirectToAction("Index"); diff --git a/src/Yavsc.Org/Extensions/HostingExtensions.cs b/src/Yavsc.Org/Extensions/HostingExtensions.cs index 0cae23a7..f92dc3c9 100644 --- a/src/Yavsc.Org/Extensions/HostingExtensions.cs +++ b/src/Yavsc.Org/Extensions/HostingExtensions.cs @@ -169,7 +169,7 @@ public static class HostingExtensions public static IdentityBuilder AddIdentityDBAndStores(this WebApplicationBuilder builder) { IServiceCollection services = builder.Services; - var connectionString = builder.Configuration.GetConnectionString(YavscConstants.YavscConnectionStringName); + var connectionString = builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName); services.AddDbContext(options => { @@ -197,7 +197,7 @@ public static class HostingExtensions options.SignIn.RequireConfirmedAccount = builder.Environment.IsEnvironment( builder.Environment.EnvironmentName); options.ClaimsIdentity.UserNameClaimType = JwtClaimTypes.PreferredUserName; - options.ClaimsIdentity.RoleClaimType = YavscConstants.RoleClaimType; + options.ClaimsIdentity.RoleClaimType = Constants.RoleClaimType; } ) .AddEntityFrameworkStores(); @@ -239,18 +239,18 @@ public static class HostingExtensions { policy .RequireAuthenticatedUser() - .RequireClaim(YavscConstants.RoleClaimType, - new string[] { YavscConstants.PerformerGroupName, YavscConstants.AdminGroupName }) + .RequireClaim(Constants.RoleClaimType, + new string[] { Constants.PerformerGroupName, Constants.AdminGroupName }) ; }); options.AddPolicy("AdministratorOnly", policy => { _ = policy .RequireAuthenticatedUser() - .RequireClaim(YavscConstants.RoleClaimType, YavscConstants.AdminGroupName); + .RequireClaim(Constants.RoleClaimType, Constants.AdminGroupName); }); - options.AddPolicy("FrontOffice", policy => policy.RequireRole(YavscConstants.FrontOfficeGroupName)); + options.AddPolicy("FrontOffice", policy => policy.RequireRole(Constants.FrontOfficeGroupName)); // options.AddPolicy("EmployeeId", policy => policy.RequireClaim("EmployeeId", "123", "456")); // options.AddPolicy("BuildingEntry", policy => policy.Requirements.Add(new OfficeEntryRequirement())); @@ -314,10 +314,10 @@ public static class HostingExtensions { options.ClaimsIdentity.UserIdClaimType = JwtClaimTypes.Subject; options.ClaimsIdentity.UserNameClaimType = JwtClaimTypes.Name; - options.ClaimsIdentity.RoleClaimType = YavscConstants.RoleClaimType; + options.ClaimsIdentity.RoleClaimType = Constants.RoleClaimType; }); var migrationsAssembly = typeof(Program).GetTypeInfo().Assembly.GetName().Name; - var connectionString = builder.Configuration.GetConnectionString(YavscConstants.YavscConnectionStringName); + var connectionString = builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName); string sqliteConnectionString = $"Data Source={Path.Combine(Path.GetTempPath(), "yavsc_test.db")}"; @@ -1220,7 +1220,7 @@ ADD COLUMN IF NOT EXISTS ""Moderated"" boolean NOT NULL DEFAULT FALSE;"); Config.UserFilesOptions = new FileServerOptions() { FileProvider = new PhysicalFileProvider(AbstractFileSystemHelpers.UserFilesDirName), - RequestPath = PathString.FromUriComponent(YavscConstants.UserFilesPath), + RequestPath = PathString.FromUriComponent(Constants.UserFilesPath), EnableDirectoryBrowsing = enableDirectoryBrowsing, }; Config.UserFilesOptions.EnableDefaultFiles = true; @@ -1233,7 +1233,7 @@ ADD COLUMN IF NOT EXISTS ""Moderated"" boolean NOT NULL DEFAULT FALSE;"); Config.AvatarsOptions = new FileServerOptions() { FileProvider = new PhysicalFileProvider(Config.AvatarsDirName), - RequestPath = PathString.FromUriComponent(YavscConstants.AvatarsPath), + RequestPath = PathString.FromUriComponent(Constants.AvatarsPath), EnableDirectoryBrowsing = enableDirectoryBrowsing }; @@ -1244,7 +1244,7 @@ ADD COLUMN IF NOT EXISTS ""Moderated"" boolean NOT NULL DEFAULT FALSE;"); Config.GitOptions = new FileServerOptions() { FileProvider = new PhysicalFileProvider(Config.GitDirName), - RequestPath = PathString.FromUriComponent(YavscConstants.GitPath), + RequestPath = PathString.FromUriComponent(Constants.GitPath), EnableDirectoryBrowsing = enableDirectoryBrowsing, }; Config.GitOptions.DefaultFilesOptions.DefaultFileNames.Add("index.md"); diff --git a/src/Yavsc.Org/ViewModels/Manage/SetUserNameViewModel.cs b/src/Yavsc.Org/ViewModels/Manage/SetUserNameViewModel.cs index 69507b92..61cf0727 100644 --- a/src/Yavsc.Org/ViewModels/Manage/SetUserNameViewModel.cs +++ b/src/Yavsc.Org/ViewModels/Manage/SetUserNameViewModel.cs @@ -7,7 +7,7 @@ namespace Yavsc.ViewModels.Manage public class SetUserNameViewModel { [Required] - [Display(Name = "User name"),RegularExpression(YavscConstants.UserNameRegExp)] + [Display(Name = "User name"),RegularExpression(Constants.UserNameRegExp)] public string UserName { get; set; } } diff --git a/src/Yavsc.Org/Views/Shared/DisplayTemplates/ApplicationUser.cshtml b/src/Yavsc.Org/Views/Shared/DisplayTemplates/ApplicationUser.cshtml index f0a961c9..dd6b0ff8 100644 --- a/src/Yavsc.Org/Views/Shared/DisplayTemplates/ApplicationUser.cshtml +++ b/src/Yavsc.Org/Views/Shared/DisplayTemplates/ApplicationUser.cshtml @@ -13,7 +13,7 @@ } else {
Utilisateur inconnu - Utilisateur inconnu + Utilisateur inconnu
} diff --git a/src/Yavsc.Org/Views/Shared/_LoginPartial.cshtml b/src/Yavsc.Org/Views/Shared/_LoginPartial.cshtml index 431fe61e..7bfa2a3f 100644 --- a/src/Yavsc.Org/Views/Shared/_LoginPartial.cshtml +++ b/src/Yavsc.Org/Views/Shared/_LoginPartial.cshtml @@ -16,7 +16,7 @@
  • Features
  • - @if (User.IsInMsRole(YavscConstants.AdminGroupName)) { + @if (User.IsInMsRole(Constants.AdminGroupName)) {