diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e528b7a4..7a045bbd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -115,13 +115,6 @@ Quelques règles non capturées par `.editorconfig` : - Préférer les types BCL (`int`, `string`) aux types framework (`Int32`, `String`). - Préférer les expressions de pattern matching aux casts explicites. -- **Pas de `object` dans le code source applicatif.** Types de retour, - paramètres, champs, propriétés, variables locales : tout doit être - typé statiquement. `dynamic` est interdit pour les mêmes raisons. - Un cast en `object` est presque toujours le symptôme d'un contrat - qu'on a laissé s'effriter (DTO, payload, handler) — refactore - le contrat (record typé, DTO dédié, méthode dédiée) au lieu de - shimer avec un cast. ## Branches & commits diff --git a/Directory.Packages.props b/Directory.Packages.props index 84380e44..e4b09159 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -18,7 +18,6 @@ - diff --git a/contrib/Makefile b/contrib/Makefile index 151045db..62e1e22d 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -1,4 +1,4 @@ -APP_PROJECT_NAMES=Org Blogs +APP_PROJECT_NAMES=Api Org Blogs SLNDIR=.. include $(SLNDIR)/.env @@ -7,6 +7,7 @@ include .env generated/: @mkdir -p $@ +generated/yavscApi.service: generated/yavscOrg.service: generated/yavscBlogs.service: @@ -33,11 +34,12 @@ generated/yavsc%.service: generated/ template.service $(SLNDIR)/.env @echo Created service file: $@ -copy-services: copy-service-Org copy-service-Blogs +copy-services: copy-service-Org copy-service-Api copy-service-Blogs copy-service-Org: /etc/systemd/system/yavscOrg.service +copy-service-Api: /etc/systemd/system/yavscApi.service copy-service-Blogs: /etc/systemd/system/yavscBlogs.service -copy-binaries: build_publish_Org build_publish_Blogs stop-services +copy-binaries: build_publish_Org build_publish_Api build_publish_Blogs stop-services @for project in $(APP_PROJECT_NAMES); \ do LCAPI=$$(echo $${project}|tr [:upper:] [:lower:]) ; \ echo "$${project} -> $${LCAPI}" ; \ @@ -53,7 +55,7 @@ copy-binaries: build_publish_Org build_publish_Blogs stop-services done @sudo chown -R $(USER_AND_GROUP) $(BASEAPPDIR) -/etc/systemd/system/yavsc%.service: generated/yavsc%.service +/etc/systemd/system/yavsc%.service: generated/yavsc%.service sudo cp $^ $@ sudo chown root:root $@ @@ -63,14 +65,14 @@ build_publish_%: clean_publish_dir_% clean_publish_dir_%: @rm -rf $(SLNDIR)/src/Yavsc.$*/bin/$(CONFIGURATION)/$(DOTNET_FRAMEWORK)/publish -install: build_publish copy-binaries copy-services +install: build_publish copy-binaries copy-services @sudo systemctl daemon-reload @for project in $(APP_PROJECT_NAMES); \ do \ sudo systemctl enable yavsc$${project} ; \ sudo systemctl start yavsc$${project} ; \ done - + reinstall: copy-binaries @sync @for project in $(APP_PROJECT_NAMES); do \ @@ -84,12 +86,13 @@ stop-services: $(SLNDIR)/src/Yavsc.Org/bin/$(CONFIGURATION)/$(DOTNET_FRAMEWORK)/publish: build_publish $(SLNDIR)/src/Yavsc.Blogs/bin/$(CONFIGURATION)/$(DOTNET_FRAMEWORK)/publish: build_publish +$(SLNDIR)/src/Yavsc.Api/bin/$(CONFIGURATION)/$(DOTNET_FRAMEWORK)/publish: build_publish -showConfig: +showConfig: @echo CONFIGURATION: $(CONFIGURATION) @echo BASEAPPDIR: $(BASEAPPDIR) clean: @rm -rf generated -.PHONY: build_publish mep showConfig copy-service-Org copy-service-Blogs reinstall clean +.PHONY: build_publish mep showConfig copy-service-Api copy-service-Org copy-service-Blogs reinstall clean diff --git a/src/PostIt.Tests/AddCircleMemberDialogTests.cs b/src/PostIt.Tests/AddCircleMemberDialogTests.cs deleted file mode 100644 index 289ff727..00000000 --- a/src/PostIt.Tests/AddCircleMemberDialogTests.cs +++ /dev/null @@ -1,156 +0,0 @@ - -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())) - { } - } - - private static async Task BuildApp() - { - TestAppContext context = new TestAppContext - { - - - }; - - return context; - } - /// - /// 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 async Task Mount() - { - TestAppContext context = new TestAppContext(); - - 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(); - - context.Window = new MainWindow(); - context.App = (PostIt.App)Application.Current!; - context.App.DataTemplates.Clear(); - context.App.DataTemplates.Add(new ViewLocator(sp)); - context.App.AttachMainWindow(context.Window); - context.Window.Show(); - - context.page = sp.GetRequiredService(); - context.Window.NavRoot.PushAsync(context.page).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. - await context.App.PushPageAsync(sp.GetRequiredService()); - - context.dialog = context.Window.NavRoot.NavigationStack[^1] as AddCircleMemberDialog - ?? throw new System.InvalidOperationException("Dialog page not at top of stack."); - - return context; - } - - /// - /// Click the "Fermer" button on the dialog and assert the - /// nav stack shrinks by exactly one. - /// - [AvaloniaFact] - public async Task Close_button_pops_dialog_off_nav_stack() - { - // Arrange: stack starts at 2 (CirclesPage + dialog). - var context = await Mount(); - var window = context.Window!; - - 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. - - // FIXME Assert.NotNull(dialog.CloseButton): - // in order to click it by its def : - - // dialog.CloseButton.RaiseEvent(new Avalonia.Interactivity.RoutedEventArgs(Button.ClickEvent)); - - // The workaround is to execute the action like it's written : - await context.App!.GoBackAsync(); - - // 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 deleted file mode 100644 index 95576778..00000000 --- a/src/PostIt.Tests/PostAclDialogTests.cs +++ /dev/null @@ -1,234 +0,0 @@ -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/TestAppContext.cs b/src/PostIt.Tests/TestAppContext.cs deleted file mode 100644 index 2843c965..00000000 --- a/src/PostIt.Tests/TestAppContext.cs +++ /dev/null @@ -1,11 +0,0 @@ -using PostIt.Views; - -namespace PostIt.Tests; - -internal class TestAppContext -{ - public MainWindow? Window {get; set; } - public CirclesPage? page {get; set; } - public AddCircleMemberDialog? dialog { get; set; } - public App? App { get; internal set; } -} diff --git a/src/PostIt.Tests/pslist b/src/PostIt.Tests/pslist deleted file mode 100644 index 0f1d73da..00000000 --- a/src/PostIt.Tests/pslist +++ /dev/null @@ -1,94 +0,0 @@ -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 d2399873..1a68f4ac 100644 --- a/src/PostIt/PostIt/App.axaml.cs +++ b/src/PostIt/PostIt/App.axaml.cs @@ -49,7 +49,7 @@ public partial class App : Application // build is ever reconfigured to skip the early check. if (TryHandOffCustomSchemeUrl()) return; - this.ServiceProvider = BuildServices(new ServiceCollection()); + this.ServiceProvider = BuildServices(); AttachServiceProvider(ServiceProvider); var settings = ServiceProvider.GetRequiredService(); var sessionStatus = ServiceProvider.GetRequiredService(); @@ -139,7 +139,7 @@ public partial class App : Application /// or service resolves through the same wiring the real app /// does, and a green test is a green contract for prod. /// - internal static IServiceProvider BuildServices(ServiceCollection services) + internal static IServiceProvider BuildServices() { var settings = new Settings(); settings.Load(); @@ -156,6 +156,7 @@ public partial class App : Application var contactService = new ContactService(); var userDirectory = new UserDirectory(userSearchClient); + var services = new ServiceCollection(); // Vues services.AddTransient(); @@ -349,9 +350,4 @@ 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 59d6dbed..a721d738 100644 --- a/src/PostIt/PostIt/ViewModels/AddCircleMemberDialogViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/AddCircleMemberDialogViewModel.cs @@ -5,7 +5,6 @@ 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; @@ -107,7 +106,7 @@ public partial class AddCircleMemberDialogViewModel : ViewModelBase /// UI from firing an event with a null payload. /// [RelayCommand] - public async Task AddAsync() + public void Add() { if (Selected is null) { @@ -115,14 +114,5 @@ 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 33a5bd30..bfc431b8 100644 --- a/src/PostIt/PostIt/ViewModels/CirclesPageViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/CirclesPageViewModel.cs @@ -119,17 +119,6 @@ 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 ae9e71d5..ae48fd8c 100644 --- a/src/PostIt/PostIt/ViewModels/PostAclDialogViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/PostAclDialogViewModel.cs @@ -1,13 +1,14 @@ 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; using Yavsc.Blogspot; using Yavsc.Api.Client; using Yavsc.Api.Client.Dtos; -using Yavsc.Abstract.BlogSpot; +using Yavsc.Abstract.Identity.Security; namespace PostIt.ViewModels; @@ -37,12 +38,10 @@ public partial class PostAclDialogViewModel : ViewModelBase public BlogPostDto Post { get; } [ObservableProperty] - public partial ObservableCollection - MyCircles { get; set; } = new(); + public partial ObservableCollection MyCircles { get; set; } = new(); [ObservableProperty] - public partial ObservableCollection - AclEntries { get; set; } = new(); + public partial ObservableCollection AclEntries { get; set; } = new(); [ObservableProperty] public partial CircleDto? SelectedCircleToAdd { get; set; } @@ -53,22 +52,6 @@ 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, @@ -85,8 +68,6 @@ public partial class PostAclDialogViewModel : ViewModelBase [RelayCommand] public async Task LoadAsync() { - if (_loaded) return; - IsBusy = true; try { @@ -102,7 +83,6 @@ public partial class PostAclDialogViewModel : ViewModelBase StatusMessage = $"{AclEntries.Count} autorisation(s)"; - _loaded = true; } catch (Exception ex) { @@ -126,10 +106,9 @@ public partial class PostAclDialogViewModel : ViewModelBase IsBusy = true; try { - var created = await _aclClient.GrantAsync(new Yavsc.Abstract.BlogSpot.PostAccessControlRulePayload + var created = await _aclClient.GrantAsync(new CircleAuthorization { - CircleId = SelectedCircleToAdd.Id, - BlogPostId = Post.Id + CircleId = SelectedCircleToAdd.Id }); if (created is not null) { @@ -152,7 +131,7 @@ public partial class PostAclDialogViewModel : ViewModelBase } [RelayCommand] - public async Task RevokeAsync(PostAccessControlRulePayload? acl) + public async Task RevokeAsync(CircleAuthorization? acl) { if (acl is null) return; IsBusy = true; diff --git a/src/PostIt/PostIt/Views/AddCircleMemberDialog.axaml b/src/PostIt/PostIt/Views/AddCircleMemberDialog.axaml index 8b232988..5d1e2531 100644 --- a/src/PostIt/PostIt/Views/AddCircleMemberDialog.axaml +++ b/src/PostIt/PostIt/Views/AddCircleMemberDialog.axaml @@ -6,7 +6,6 @@ xmlns:services="using:PostIt.Services" x:DataType="vm:AddCircleMemberDialogViewModel" > - @@ -30,9 +29,7 @@ + SelectedItem="{Binding Selected, Mode=TwoWay}"> @@ -50,13 +47,11 @@ /// /// 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 Constants.DefaultAvatar; - return $"{Constants.AvatarsPath}/{user!.UserName}.s.png"; + return YavscConstants.DefaultAvatar; + return $"{YavscConstants.AvatarsPath}/{user!.UserName}.s.png"; } } } diff --git a/src/Yavsc.Api.Client/BlogAclApiClient.cs b/src/Yavsc.Api.Client/BlogAclApiClient.cs index 9a93d310..e8c8bf01 100644 --- a/src/Yavsc.Api.Client/BlogAclApiClient.cs +++ b/src/Yavsc.Api.Client/BlogAclApiClient.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using Yavsc.Abstract.BlogSpot; using Yavsc.Abstract.Identity.Security; using Yavsc.Api.Client.Dtos; @@ -34,16 +33,16 @@ public sealed class BlogAclApiClient api.Http.BaseAddress = new Uri(blogsBaseAddress); } - public Task> GetMyAclAsync(CancellationToken ct = default) - => _api.CallAsync>(HttpMethod.Get, Path, ct: ct); + public Task> GetMyAclAsync(CancellationToken ct = default) + => _api.CallAsync>(HttpMethod.Get, Path, ct: ct); - public Task GetAclAsync(long circleId, CancellationToken ct = default) - => _api.CallAsync(HttpMethod.Get, $"{Path}/{circleId}", ct: ct); + public Task GetAclAsync(long circleId, CancellationToken ct = default) + => _api.CallAsync(HttpMethod.Get, $"{Path}/{circleId}", ct: ct); - public Task GrantAsync(PostAccessControlRulePayload acl, CancellationToken ct = default) - => _api.CallAsync(HttpMethod.Post, Path, body: acl, ct: ct); + public Task GrantAsync(CircleAuthorization acl, CancellationToken ct = default) + => _api.CallAsync(HttpMethod.Post, Path, body: acl, ct: ct); - public Task UpdateAclAsync(long circleId, PostAccessControlRulePayload acl, CancellationToken ct = default) + public Task UpdateAclAsync(long circleId, CircleAuthorization acl, CancellationToken ct = default) => _api.CallAsync(HttpMethod.Put, $"{Path}/{circleId}", body: acl, ct: ct); public Task RevokeAsync(long circleId, CancellationToken ct = default) diff --git a/src/Yavsc.Api/Controllers/Business/ActivityApiController.cs b/src/Yavsc.Api/Controllers/Business/ActivityApiController.cs index 5aeddc57..d2da2ea7 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(Constants.APIPrefix + "/activity")] + [Route("api/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 72180fc1..87035406 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(Constants.APIPrefix + "/bill"), Authorize] + [Route("api/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 7e58b071..494075c6 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(Constants.APIPrefix + "/bookquery"), Authorize("Performer")] + [Route("api/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 902cb038..41bdd353 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(Constants.APIPrefix + "/estimate"), Authorize] + [Route("api/estimate"), Authorize] public class EstimateApiController : Controller { private readonly ApplicationDbContext _context; @@ -27,12 +27,12 @@ namespace Yavsc.Controllers } bool UserIsAdminOrThis(string uid) { - if (User.IsInRole(Constants.AdminGroupName)) return true; + if (User.IsInRole(YavscConstants.AdminGroupName)) return true; return uid == User.GetUserId(); } bool UserIsAdminOrInThese(string oid, string uid) { - if (User.IsInRole(Constants.AdminGroupName)) return true; + if (User.IsInRole(YavscConstants.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(Constants.AdminGroupName)) + if (!User.IsInRole(YavscConstants.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(Constants.AdminGroupName)) + if (!User.IsInRole(YavscConstants.AdminGroupName)) { if (uid != estimate.OwnerId) { @@ -187,7 +187,7 @@ namespace Yavsc.Controllers return NotFound(); } var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); - if (!User.IsInRole(Constants.AdminGroupName)) + if (!User.IsInRole(YavscConstants.AdminGroupName)) { if (uid != estimate.OwnerId) { diff --git a/src/Yavsc.Api/Controllers/Business/EstimateTemplatesApiController.cs b/src/Yavsc.Api/Controllers/Business/EstimateTemplatesApiController.cs index 81de4cac..4442e0b3 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(Constants.APIPrefix + "/EstimateTemplatesApi")] + [Route("api/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(Constants.AdminGroupName)) + if (!User.IsInRole(YavscConstants.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(Constants.AdminGroupName)) + if (!User.IsInRole(YavscConstants.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 c05da827..b91cba51 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(Constants.APIPrefix + "/front")] + [Route("api/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 5f769e4e..3076dbe1 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(Constants.APIPrefix + "/payment")] + [Route("api/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 2ad1ded5..b552eff3 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(Constants.APIPrefix + "/performers")] + [Route("api/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 97a60fdb..abd621c3 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(Constants.APIPrefix + "/ProductApi")] + [Route("api/ProductApi")] public class ProductApiController : Controller { private readonly ApplicationDbContext _context; @@ -46,7 +46,7 @@ namespace Yavsc.Controllers } // PUT: api/ProductApi/5 - [HttpPut("{id}"),Authorize(Constants.FrontOfficeGroupName)] + [HttpPut("{id}"),Authorize(YavscConstants.FrontOfficeGroupName)] public IActionResult PutProduct(long id, [FromBody] Product product) { if (!ModelState.IsValid) @@ -81,7 +81,7 @@ namespace Yavsc.Controllers } // POST: api/ProductApi - [HttpPost,Authorize(Constants.FrontOfficeGroupName)] + [HttpPost,Authorize(YavscConstants.FrontOfficeGroupName)] public IActionResult PostProduct([FromBody] Product product) { if (!ModelState.IsValid) @@ -110,7 +110,7 @@ namespace Yavsc.Controllers } // DELETE: api/ProductApi/5 - [HttpDelete("{id}"),Authorize(Constants.FrontOfficeGroupName)] + [HttpDelete("{id}"),Authorize(YavscConstants.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 cd3a561b..22fdf1e9 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(Constants.APIPrefix + "/bursherprofiles")] + [Route("api/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 c1181f54..822c3182 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(Constants.APIPrefix + "/haircut")][Authorize] + [Route("api/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 3ba74219..b2d28baa 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(Constants.APIPrefix + "/hyperlink")] + [Route("api/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 67f38d22..55ae08b7 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(Constants.APIPrefix + "/GitRefsApi")] + [Route("api/GitRefsApi")] [Authorize("AdministratorOnly")] public class GitRefsApiController : Controller { diff --git a/src/Yavsc.Api/Controllers/MailTemplatingApiController.cs b/src/Yavsc.Api/Controllers/MailTemplatingApiController.cs index c289c3da..958ade66 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(Constants.APIPrefix + "/mailtemplate")] + [Route("api/mailtemplate")] public class MailTemplatingApiController: Controller { - + } } diff --git a/src/Yavsc.Api/Controllers/MailingTemplateApiController.cs b/src/Yavsc.Api/Controllers/MailingTemplateApiController.cs index 4373d847..dc535476 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(Constants.APIPrefix + "/mailing")] + [Route("api/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 dc935c14..944b335b 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(Constants.APIPrefix + "/museprefs")] + [Route("api/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 e72090f6..eacccb0a 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(Constants.APIPrefix + "/MusicalTendenciesApi")] + [Route("api/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 50d6d2e9..dc132da4 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(Constants.AdminGroupName)) + if (!User.IsInRole(YavscConstants.AdminGroupName)) return BadRequest(); _context.SaveChanges(User.GetUserId()); diff --git a/src/Yavsc.Api/Controllers/ProfileApiController.cs b/src/Yavsc.Api/Controllers/ProfileApiController.cs index 93bf2a4e..60ad1f60 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(Constants.APIPrefix + "/profile")] - public abstract class ProfileApiController : Controller + [Produces("application/json"),Route("api/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 32cf8495..ebc1c03b 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(Constants.APIPrefix + "/blacklist"), Authorize] + [Route("api/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(Constants.AdminGroupName)) - if (!User.IsInRole(Constants.FrontOfficeGroupName)) + if (!User.IsInRole(YavscConstants.AdminGroupName)) + if (!User.IsInRole(YavscConstants.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 b991c0fb..cdaeecde 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(Constants.APIPrefix + "/chat")] + [Route("api/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 fba8bd43..5fe3a0bf 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(Constants.APIPrefix + "/ChatRoomAccessApi")] + [Route("api/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(Constants.AdminGroupName)) - + && ! User.IsInMsRole(YavscConstants.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(Constants.AdminGroupName)) + if (uid != room.OwnerId && ! User.IsInMsRole(YavscConstants.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(Constants.AdminGroupName))) + if (room == null || (uid != room.OwnerId && ! User.IsInMsRole(YavscConstants.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(Constants.AdminGroupName))) + if (room == null || (uid != room.OwnerId && chatRoomAccess.UserId != uid && ! User.IsInMsRole(YavscConstants.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 5d59f6bd..990646fc 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(Constants.APIPrefix + "/ChatRoomApi")] + [Route("api/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(Constants.AdminGroupName)) + if (!User.IsInMsRole(YavscConstants.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 96ba03dc..ffd6eb0b 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(Constants.APIPrefix + "/ContactsApi")] + [Route("api/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 8556fb5a..e9330543 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(Constants.APIPrefix + "/ServiceApi")] + [Route("api/ServiceApi")] public class ServiceApiController : Controller { private readonly ApplicationDbContext _context; @@ -46,7 +46,7 @@ namespace Yavsc.Controllers } // PUT: api/ServiceApi/5 - [HttpPut("{id}"),Authorize(Constants.FrontOfficeGroupName)] + [HttpPut("{id}"),Authorize(YavscConstants.FrontOfficeGroupName)] public IActionResult PutService(long id, [FromBody] Service service) { if (!ModelState.IsValid) @@ -81,7 +81,7 @@ namespace Yavsc.Controllers } // POST: api/ServiceApi - [HttpPost,Authorize(Constants.FrontOfficeGroupName)] + [HttpPost,Authorize(YavscConstants.FrontOfficeGroupName)] public IActionResult PostService([FromBody] Service service) { if (!ModelState.IsValid) @@ -110,7 +110,7 @@ namespace Yavsc.Controllers } // DELETE: api/ServiceApi/5 - [HttpDelete("{id}"),Authorize(Constants.FrontOfficeGroupName)] + [HttpDelete("{id}"),Authorize(YavscConstants.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 cb565a0d..11c70d60 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(Constants.APIPrefix + "/users")] + [Route("api/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/BlogAclApiTests.cs b/src/Yavsc.Blogs.Tests/BlogAclApiTests.cs deleted file mode 100644 index 49259d05..00000000 --- a/src/Yavsc.Blogs.Tests/BlogAclApiTests.cs +++ /dev/null @@ -1,221 +0,0 @@ -using System.Net; -using System.Net.Http.Json; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Yavsc.Abstract.BlogSpot; -using Yavsc.Models; -using Yavsc.Models.Access; -using Yavsc.Models.Blog; -using Yavsc.Models.Relationship; -using Yavsc.Tests.Shared; -using static Yavsc.Constants; - -namespace Yavsc.Blogs.Tests; - -/// -/// Behavioural tests for BlogAclApiController.PostCircleAuthorizationToBlogPost: -/// POST /api/v1/blogacl with a JSON body of -/// CircleAuthorizationToBlogPost (CircleId + BlogPostId). -/// -/// Same fixture as : -/// provides a SQLite -/// :memory: ApplicationDbContext (so FKs are -/// enforced the way a real relational engine would) and JWT -/// bearer auth via TestTokenIssuer. No mocks — the real -/// DbContext receives the real INSERT attempt. -/// -/// The bug being pinned by these tests: the POST endpoint -/// calls _context.CircleAuthorizationToBlogPost.Add(...) -/// then SaveChangesAsync. The entity has a composite -/// key (CircleId + BlogPostId) and two FKs; EF Core refuses -/// the INSERT with -/// System.InvalidOperationException: The value of -/// 'CircleAuthorizationToBlogPost.BlogPostId' is unknown when -/// attempting to save changes when the principal entities -/// (the existing BlogPost and Circle) are not -/// attached to the DbContext in the same change-tracker graph. -/// -[Collection("Yavsc Blogs")] -public sealed class BlogAclApiTests : IClassFixture -{ - private readonly BlogsWebServerFixture _fixture; - - - public BlogAclApiTests(BlogsWebServerFixture fixture) - { - _fixture = fixture; - } - - - private string BlogAclUrl() - => $"{_fixture.Addresses.First(a => a.StartsWith("https://"))}/{APIPrefix}/blogacl"; - - /// Delete any ACL rows tied to the fixture's seeded - /// (CircleId, BlogPostId) pair. The shared SQLite store - /// persists across tests, so tests that POST a successful ACL - /// row would otherwise conflict with whichever other test runs - /// next against the same pair — xUnit does not guarantee - /// execution order. Calling this at the start of each - /// insert-bearing test guarantees a clean slate regardless of - /// the previous test's outcome. - private void CleanupAcl() - { - using var scope = _fixture.Services.CreateScope(); - var db = scope.ServiceProvider.GetRequiredService(); - db.CircleAuthorizationToBlogPost - .Where(a => a.CircleId == _fixture.CircleId - && a.BlogPostId == _fixture.PostId) - .ExecuteDelete(); - } - - private HttpClient NewClient(string subject) - { - var handler = new HttpClientHandler - { - ServerCertificateCustomValidationCallback = (_, _, _, _) => true - }; - var http = new HttpClient(handler) - { - BaseAddress = new Uri(_fixture.Addresses.First(a => a.StartsWith("https://"))) - }; - // The Blogs fixture disables JwtSecurityTokenHandler's - // inbound claim-type remap, so the JWT's "sub" stays "sub" - // rather than being rewritten to ClaimTypes.NameIdentifier. - // The controller, however, reads the user id via - // User.FindFirstValue(ClaimTypes.NameIdentifier), so we add - // an explicit nameid claim to keep the legacy lookup happy. - http.DefaultRequestHeaders.Authorization = - new System.Net.Http.Headers.AuthenticationHeaderValue( - "Bearer", - TestTokenIssuer.Issue( - subject, - extraClaims: new[] - { - new System.Security.Claims.Claim( - System.Security.Claims.ClaimTypes.NameIdentifier, - subject), - })); - return http; - } - - /// - /// Reproduces the prod 500 logged on 2026-08-21 on mercure: - /// InvalidOperationException: The value of - /// 'CircleAuthorizationToBlogPost.BlogPostId' is unknown - /// when POSTs the - /// shape { "circleId": <id> } — the exact body the - /// PostIt client builds from - /// (which only carries CircleId). The server deserialises - /// it into , leaves - /// BlogPostId at its default(long) = 0, attaches - /// no Target navigation, and EF Core refuses to INSERT - /// during PrepareToSave(). The fix lives in PostIt - /// (enrich the payload with blogPostId + comment) - /// and on the wire DTO ( must - /// carry those fields); the server validates. Until that ships, - /// this test stays red. - /// - [Fact] - public async Task PostCircleAuthorization_returns_201_when_payload_mirrors_PostIt_shape_against_existing_circle_named_test() - { - // The prod circle already exists with Name="test", Public=true, - // owned by the caller. We seed the same shape pre-POST so the - // test reproduces the prod scenario end-to-end. - CleanupAcl(); - using var http = NewClient("alice"); - - var payload = new PostAccessControlRulePayload - { - CircleId = _fixture.CircleId, - BlogPostId = _fixture.PostId - }; - - var response = await http.PostAsJsonAsync(BlogAclUrl(), payload, - TestContext.Current.CancellationToken); - - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - } - - /// - /// Payload templates for . - /// Each row carries the shape we want to POST; -1L and - /// -2L are negative sentinels that the test substitutes - /// with the ids of freshly seeded Circle / BlogPost - /// rows before sending, so every shape lands against a real - /// principal entity and the seeded fixtures are not dead. - /// - public static IEnumerable BlogAclPayloadsForNever500() - { - - // circleId only (the historical bug shape, 2026-08-21 mercure): - // must be rejected, never 500. - return new object[][] - { - [ - new PostAccessControlRulePayload - { - BlogPostId = -2, - CircleId = -1 - } - ], - [new PostAccessControlRulePayload - { - BlogPostId = 1, - CircleId = -1 - } - ], - [new PostAccessControlRulePayload - { - BlogPostId = 1, - CircleId = 1 - } - ] - } ; - } - - /// - /// Hard rule (Paul, 2026-08-21): a 500 is never acceptable - /// - [Theory] - [MemberData(nameof(BlogAclPayloadsForNever500))] - public async Task PostCircleAuthorization_never_returns_500(PostAccessControlRulePayload payload) - { - using var http = NewClient("alice"); - - var response = await http.PostAsJsonAsync( - BlogAclUrl(), payload, - TestContext.Current.CancellationToken); - - Assert.NotEqual(HttpStatusCode.InternalServerError, response.StatusCode); - } - - [Fact] - async Task PostCircleAuthorization_dosent_return_500 () - { - CleanupAcl(); - await PostCircleAuthorization_never_returns_500( - - new PostAccessControlRulePayload - { - BlogPostId = -1, - CircleId = _fixture.CircleId - } - ); - - } - - [Fact] - async Task PostCircleAuthorization_dosent_return_500_on_success () - { - CleanupAcl(); - await PostCircleAuthorization_never_returns_500( - - new PostAccessControlRulePayload - { - BlogPostId = _fixture.PostId, - CircleId = _fixture.CircleId - } - ); - - } -} diff --git a/src/Yavsc.Blogs.Tests/BlogApiSmokeTests.cs b/src/Yavsc.Blogs.Tests/BlogApiSmokeTests.cs index 162d76fe..b84e75b6 100644 --- a/src/Yavsc.Blogs.Tests/BlogApiSmokeTests.cs +++ b/src/Yavsc.Blogs.Tests/BlogApiSmokeTests.cs @@ -12,7 +12,6 @@ namespace Yavsc.Blogs.Tests; /// surface. The first behavioural test (GET /api/v1/blog returns /// 200) lands in a follow-up commit. /// -[Collection("Yavsc Blogs")] public sealed class BlogApiSmokeTests : IClassFixture { private readonly BlogsWebServerFixture _fixture; diff --git a/src/Yavsc.Blogs.Tests/BlogApiTests.cs b/src/Yavsc.Blogs.Tests/BlogApiTests.cs index bde5a6cc..cc7aaec8 100644 --- a/src/Yavsc.Blogs.Tests/BlogApiTests.cs +++ b/src/Yavsc.Blogs.Tests/BlogApiTests.cs @@ -22,7 +22,7 @@ namespace Yavsc.Blogs.Tests; /// header (or sending a token signed with the wrong key) gets a /// 401 back from the framework. /// -[Collection("Yavsc Blogs")] +[Collection("JwtClaimMapping")] public sealed class BlogApiTests : IClassFixture { private readonly BlogsWebServerFixture _fixture; @@ -45,21 +45,6 @@ public sealed class BlogApiTests : IClassFixture db.Database.EnsureCreated(); } - /// Reset the database and seed the - /// tester row. Required - /// for any test that POST/PUT/DELETE a BlogPost: - /// BlogPost.AuthorId is a FK to - /// AspNetUsers.Id, and SQLite (unlike the EF Core - /// InMemory provider) enforces it. Without the seed, the - /// POST handler hits - /// SQLite Error 19: 'FOREIGN KEY constraint failed' - /// at SaveChanges and the controller returns 500. - private void ResetAndSeedDefaultUser() - { - ResetDatabase(); - _fixture.SeedUser("tester"); - } - /// The fixture's WebApplication is bound to /// https://localhost:<random> via /// . We pick the first @@ -131,7 +116,7 @@ public sealed class BlogApiTests : IClassFixture [Fact] public async Task PostBlog_creates_a_post_and_Get_returns_it_in_the_list() { - ResetAndSeedDefaultUser(); + ResetDatabase(); using var http = NewClient(); // Create a minimal BlogPost. The server assigns Id, so we @@ -169,7 +154,7 @@ public sealed class BlogApiTests : IClassFixture [Fact] public async Task PostBlog_sets_AuthorId_on_created_post_and_list_entry() { - ResetAndSeedDefaultUser(); + ResetDatabase(); using var http = NewClient(subject: "tester"); var draft = new BlogPost @@ -201,7 +186,7 @@ public sealed class BlogApiTests : IClassFixture [Fact] public async Task PostBlogComment_returns_201_for_existing_post() { - ResetAndSeedDefaultUser(); + ResetDatabase(); using var http = NewClient(subject: "tester"); var draft = new BlogPost @@ -264,7 +249,7 @@ public sealed class BlogApiTests : IClassFixture [Fact] public async Task PutBlog_with_valid_token_and_owner_returns_204_and_Get_reflects_update() { - ResetAndSeedDefaultUser(); + ResetDatabase(); // The JWT's sub must match the post's AuthorId: // PermissionHandler.IsOwner checks blog.AuthorId == user.GetUserId(), // and UserHelpers.GetUserId reads "sub" off the principal. @@ -315,7 +300,7 @@ public sealed class BlogApiTests : IClassFixture [Fact] public async Task DeleteBlog_removes_a_post_and_Get_returns_an_empty_list() { - ResetAndSeedDefaultUser(); + ResetDatabase(); using var http = NewClient(); // Seed a post we can delete. @@ -357,7 +342,7 @@ public sealed class BlogApiTests : IClassFixture // ModelState validation starts rejecting the PostIt payload // (missing field, wrong casing, etc.), this test fails // before the regression reaches a user. - ResetAndSeedDefaultUser(); + ResetDatabase(); using var http = NewClient(subject: "tester"); // Mirrors what MainPageViewModel.Save builds: a BlogPost with diff --git a/src/Yavsc.Blogs.Tests/BlogsWebServerFixture.cs b/src/Yavsc.Blogs.Tests/BlogsWebServerFixture.cs index 218904ef..1e610082 100644 --- a/src/Yavsc.Blogs.Tests/BlogsWebServerFixture.cs +++ b/src/Yavsc.Blogs.Tests/BlogsWebServerFixture.cs @@ -1,33 +1,27 @@ +using System.Text; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; -using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; using Yavsc.Blogs.Controllers; using Yavsc.Models; -using Yavsc.Models.Blog; -using Yavsc.Models.Relationship; using Yavsc.Services; using Yavsc.Tests.Shared; namespace Yavsc.Blogs.Tests; /// -/// Shared integration-test host for the Yavsc.Blogs API surface. -/// Specialisation of that wires up -/// only the bits the blog API actually depends on: +/// Test host for the Yavsc.Blogs API surface. Specialisation of +/// that wires up only the bits the +/// blog API actually depends on: /// /// -/// A SQLite :memory: database -/// () backed -/// by a single shared held open -/// for the lifetime of the host. SQLite enforces real foreign -/// keys and real transactional semantics, so the tests see the -/// same INSERT-time FK validation a production Postgres host -/// would — unlike the EF Core InMemory provider, which silently -/// ignores FKs and masks bugs that surface only against a real -/// relational engine. +/// An in-memory +/// (the real one — no mock) so BlogSpotService.Index can run +/// against an empty table and return an empty list. /// A trivial /// stub: the GET index path doesn't read the file system, so any /// implementation is fine. @@ -50,61 +44,31 @@ namespace Yavsc.Blogs.Tests; /// /// No IdentityServer, no SMTP, no static assets — the Org fixture /// owns all of that and we don't need any of it for blog integration -/// tests. Marked so the -/// host is shared across every [Collection("Yavsc Blogs")] -/// test class: one host, one SQLite DB, one Kestrel port. +/// tests. /// -[CollectionDefinition("Yavsc Blogs")] public sealed class BlogsWebServerFixture : WebHostFixture { protected override int HttpsPort => 5103; - public long CircleId { get; private set; } - public long PostId { get; private set; } - - // A single SqliteConnection held open at the static level, - // mirroring how Yavsc.Org.Tests.WebServerFixture hoists its - // shared configuration into static slots. Closing the - // connection destroys the in-memory database — so we close - // it only when the last fixture instance is disposed (see - // Dispose below), exactly when WebHostFixture tears down the - // host. - private static SqliteConnection? _sharedSqliteConnection; - private static readonly object _sqliteLock = new(); + private InMemoryDatabaseRoot? _inMemoryRoot; protected override WebApplication BuildApp(WebApplicationBuilder builder) { - // Open the shared in-memory connection lazily on the first - // fixture construction. Subsequent constructions (xUnit - // creates one fixture instance per IClassFixture) reuse - // the same connection so all DbContexts across all tests - // see the same database. - SqliteConnection sharedConnection; - lock (_sqliteLock) - { - if (_sharedSqliteConnection is null) - { - // Mode=Memory + Cache=Shared gives us a named - // in-memory database that every connection string - // referencing "File:YavscBlogsTests?mode=memory&cache=shared" - // will resolve to the same backing store, as long - // as at least one SqliteConnection stays open - // against it. - _sharedSqliteConnection = new SqliteConnection( - "Data Source=YavscBlogsTests;Mode=Memory;Cache=Shared"); - _sharedSqliteConnection.Open(); - } - sharedConnection = _sharedSqliteConnection; - } - + // Use the real ApplicationDbContext with an in-memory store. + // BlogSpotService reads _context.BlogSpot directly, so any + // attempt to mock it would be wasted work; the real service + // against an empty table returns an empty list, which is + // exactly what the first test wants to assert. + // + // Share a single InMemoryDatabaseRoot across the test + // lifetime so POST + GET on the same fixture see the same + // store. Without the root, EF Core's In-Memory provider + // creates independent stores per DbContext in some + // configurations, and the second request would see an + // empty list even after the first wrote a row. + _inMemoryRoot = new InMemoryDatabaseRoot(); builder.Services.AddDbContext(opt => - // UseSqlite(DbConnection) keeps the connection we just - // opened alive for the DbContext's lifetime, instead of - // letting EF open and close its own. Without this, - // each DbContext would get a fresh connection pointing - // at an empty :memory: store and nothing would persist - // across requests. - opt.UseSqlite(sharedConnection)); + opt.UseInMemoryDatabase("Yavsc.Blogs.Tests", _inMemoryRoot)); // Trivial file-system auth: the GET index path never calls // into it, but the DI container needs an instance. @@ -181,7 +145,7 @@ public sealed class BlogsWebServerFixture : WebHostFixture // remaps long Microsoft claim URIs, not sub). // UserHelpers.GetUserId reads sub directly. NameClaimType = "sub", - RoleClaimType = Yavsc.Constants.RoleClaimType, + RoleClaimType = YavscConstants.RoleClaimType, }; }); @@ -200,139 +164,10 @@ public sealed class BlogsWebServerFixture : WebHostFixture app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); - - // EnsureCreated + seed alice, run once at host startup. - // EnsureCreated is idempotent (creates only the tables that - // don't exist yet) and runs against the shared - // SqliteConnection (Cache=Shared), so every DbContext that - // resolves through this fixture's host sees the same schema. - // We do NOT call EnsureDeleted: the SqliteConnection is held - // open at the static level and closing it destroys the - // :memory: store for every other DbContext — the org - // fixture can afford EnsureDeleted because its store is - // built fresh per fixture, but the blogs fixture's static - // connection outlives a single fixture instance. - using (var seedScope = app.Services.CreateScope()) - { - var db = seedScope.ServiceProvider - .GetRequiredService(); - db.Database.EnsureCreated(); - if (!db.Users.Any(u => u.Id == "alice")) - { - db.Users.Add(new ApplicationUser - { - Id = "alice", - UserName = "alice", - Email = "alice@example.com", - EmailConfirmed = true, - FullName = "Alice Dupont", - Avatar = "/avatars/alice.png", - }); - db.SaveChanges(); - - // Inline the seed of the circle + post. We don't - // call SeedCircle/SeedBlogPost (the instance helpers) - // because those resolve through this.Services, which - // is null until WebHostFixture.InitializeAsync has - // finished wiring the shared slot — i.e. after this - // method returns. Use app.Services directly. - var circle = new Circle - { - OwnerId = "alice", - Name = "test", - Public = true, - }; - db.Circle.Add(circle); - db.SaveChanges(); - CircleId = circle.Id; - - var post = new BlogPost - { - AuthorId = "alice", - Title = "Billet ACL test", - Article = "Test article body.", - DateCreated = DateTime.UtcNow, - DateModified = DateTime.UtcNow, - }; - db.BlogSpot.Add(post); - db.SaveChanges(); - PostId = post.Id; - } - } - await Task.CompletedTask; return app; } - public override void Dispose() - { - try - { - base.Dispose(); - } - finally - { - // Close the shared SQLite connection only when the - // last fixture instance goes away, matching the - // lifetime contract of WebHostFixture.Dispose. We - // rely on base.Dispose's _instanceCount decrement - // having run, so we close only if the host is gone - // (base already nulled _app when count==0). - lock (_sqliteLock) - { - if (_sharedSqliteConnection is not null) - { - // Synchronous close: SQLite's Close() is - // documented as safe to call from a sync - // context and avoids the GetAwaiter().GetResult() - // pattern that's historically caused teardown - // hangs in this repo's async pipeline. - _sharedSqliteConnection.Close(); - _sharedSqliteConnection.Dispose(); - _sharedSqliteConnection = null; - } - } - } - } - - /// Seed an in the shared - /// SQLite store, so tests that POST/PUT/DELETE a - /// BlogPost (whose AuthorId is a FK to - /// AspNetUsers.Id) don't trip the FK constraint that - /// SQLite enforces but the EF Core InMemory provider silently - /// ignored. Idempotent on : a - /// second call for the same id is a no-op (the user already - /// exists). - /// Both the PK id and the login name. - /// The JWT subject in tests is this same string, so seeding - /// this id is enough to make the FK from a - /// BlogPost.AuthorId resolve. - /// Optional hook to fill in fields - /// like FullName / Avatar / EmailConfirmed - /// that downstream tests assert on. - public ApplicationUser SeedUser(string userName, Action? configure = null) - { - using var scope = Services.CreateScope(); - var db = scope.ServiceProvider.GetRequiredService(); - var existing = db.Users.SingleOrDefault(u => u.Id == userName); - if (existing != null) return existing; - - // Email is an alternate key on ApplicationUser; seeding - // it explicitly avoids the InMemory provider's null-claim - // tracking quirk (cf. PublishEndpointTests.ResetDatabase) - // and keeps the column shape realistic for prod. - var user = new ApplicationUser - { - Id = userName, - UserName = userName, - Email = $"{userName}@example.test", - }; - configure?.Invoke(user); - db.Users.Add(user); - db.SaveChanges(); - return user; - } - /// Trivial stub. The /// blog API endpoints exercised by the first tests don't read the /// file system, so the implementation can be a no-op. @@ -345,39 +180,4 @@ public sealed class BlogsWebServerFixture : WebHostFixture { } } - - - - /// Create a circle owned by - /// directly in the SQLite store and return its server-assigned - /// id. - private long SeedCircle(string ownerId, string name, bool isPublic = false) - { - using var scope = Services.CreateScope(); - var db = scope.ServiceProvider.GetRequiredService(); - var circle = new Circle { OwnerId = ownerId, Name = name, Public = isPublic }; - db.Circle.Add(circle); - db.SaveChanges(); - return circle.Id; - } - - /// Create a blog post owned by - /// directly in the SQLite store and return its server-assigned - /// id. - private long SeedBlogPost(string authorId, string title) - { - using var scope = Services.CreateScope(); - var db = scope.ServiceProvider.GetRequiredService(); - var post = new BlogPost - { - AuthorId = authorId, - Title = title, - Article = "Test article body.", - DateCreated = DateTime.UtcNow, - DateModified = DateTime.UtcNow, - }; - db.BlogSpot.Add(post); - db.SaveChanges(); - return post.Id; - } } diff --git a/src/Yavsc.Blogs.Tests/CircleMembersApiTests.cs b/src/Yavsc.Blogs.Tests/CircleMembersApiTests.cs index a2367180..5e8040ef 100644 --- a/src/Yavsc.Blogs.Tests/CircleMembersApiTests.cs +++ b/src/Yavsc.Blogs.Tests/CircleMembersApiTests.cs @@ -6,7 +6,6 @@ using Microsoft.Extensions.DependencyInjection; using Yavsc.Models; using Yavsc.Models.Relationship; using Yavsc.Tests.Shared; -using static Yavsc.Constants; namespace Yavsc.Blogs.Tests; @@ -89,7 +88,7 @@ public sealed class CircleMembersApiTests : IClassFixture } private string MembersUrl(long circleId) - => $"{_fixture.Addresses.First(a => a.StartsWith("https://"))}/{APIPrefix}/circle/{circleId}/members"; + => $"{_fixture.Addresses.First(a => a.StartsWith("https://"))}/{Constants.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 6d84aed5..c9d95774 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 = Yavsc.Constants.RoleClaimType, - NameClaimType = Yavsc.Constants.NameClaimType, + RoleClaimType = YavscConstants.RoleClaimType, + NameClaimType = YavscConstants.NameClaimType, }; }); diff --git a/src/Yavsc.Blogs.Tests/PublishEndpointTests.cs b/src/Yavsc.Blogs.Tests/PublishEndpointTests.cs index e767a57a..af1a26c6 100644 --- a/src/Yavsc.Blogs.Tests/PublishEndpointTests.cs +++ b/src/Yavsc.Blogs.Tests/PublishEndpointTests.cs @@ -25,7 +25,7 @@ namespace Yavsc.Blogs.Tests; /// in-memory ApplicationDbContext, JWT bearer auth /// via . /// -[Collection("Yavsc Blogs")] +[Collection("JwtClaimMapping")] public sealed class PublishEndpointTests : IClassFixture { private readonly BlogsWebServerFixture _fixture; diff --git a/src/Yavsc.Blogs.Tests/Yavsc.Blogs.Tests.csproj b/src/Yavsc.Blogs.Tests/Yavsc.Blogs.Tests.csproj index fc7883ce..256bdc4d 100644 --- a/src/Yavsc.Blogs.Tests/Yavsc.Blogs.Tests.csproj +++ b/src/Yavsc.Blogs.Tests/Yavsc.Blogs.Tests.csproj @@ -17,7 +17,6 @@ - diff --git a/src/Yavsc.Blogs/Constants.cs b/src/Yavsc.Blogs/Constants.cs index 3e499da4..4dbdfb8b 100644 --- a/src/Yavsc.Blogs/Constants.cs +++ b/src/Yavsc.Blogs/Constants.cs @@ -5,4 +5,6 @@ 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 a33d75d8..aa81f9d5 100644 --- a/src/Yavsc.Blogs/Controllers/BlogAclApiController.cs +++ b/src/Yavsc.Blogs/Controllers/BlogAclApiController.cs @@ -1,17 +1,15 @@ - +using System.Linq; using System.Security.Claims; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Yavsc.Abstract.BlogSpot; using Yavsc.Models; using Yavsc.Models.Access; using Yavsc.Server.Helpers; -using static Yavsc.Constants; namespace Yavsc.Blogs.Controllers { [Produces("application/json")] - [Route(APIPrefix+"/blogacl")] + [Route("api/blogacl")] public class BlogAclApiController : Controller { private readonly ApplicationDbContext _context; @@ -26,7 +24,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/v1/blogacl + // GET: api/blogacl [HttpGet] public IEnumerable GetBlogACL() { @@ -70,7 +68,7 @@ namespace Yavsc.Blogs.Controllers return BadRequest(); } - if (!await CheckOwnerAsync(circleAuthorizationToBlogPost.CircleId)) + if (!CheckOwner(circleAuthorizationToBlogPost.CircleId)) { return new ChallengeResult(); } @@ -94,42 +92,27 @@ namespace Yavsc.Blogs.Controllers return new StatusCodeResult(StatusCodes.Status204NoContent); } - private async Task CheckOwnerAsync (long circleId) + private bool CheckOwner (long circleId) { + var uid = User.FindFirstValue(ClaimTypes.NameIdentifier); - if (uid==null) return false; - var circle = await _context.Circle.FirstOrDefaultAsync(c=>c.Id==circleId); - if (circle == null) return false; - return circle.OwnerId == uid; + var circle = _context.Circle.First(c=>c.Id==circleId); + _context.Entry(circle).State = EntityState.Detached; + return (circle.OwnerId == uid); } // POST: api/BlogAclApi [HttpPost] - public async Task PostCircleAuthorizationToBlogPost( - [FromBody] PostAccessControlRulePayload circleAuthorizationToBlogPost) + public async Task PostCircleAuthorizationToBlogPost([FromBody] CircleAuthorizationToBlogPost circleAuthorizationToBlogPost) { if (!ModelState.IsValid) { return BadRequest(ModelState); } - // No 500: a missing or zero BlogPostId is a client - // error, not an EF Core FK violation waiting to happen. - // The 2026-08-21 prod 500 was this exact path (PostIt - // sent only circleId, server saw BlogPostId = 0 and - // SaveChangesAsync threw InvalidOperationException). - if (circleAuthorizationToBlogPost.BlogPostId <= 0) - { - return BadRequest("BlogPostId is required and must be > 0."); - } - if (!await CheckOwnerAsync(circleAuthorizationToBlogPost.CircleId)) + if (!CheckOwner(circleAuthorizationToBlogPost.CircleId)) { return new ChallengeResult(); } - CircleAuthorizationToBlogPost entity = new CircleAuthorizationToBlogPost - { - BlogPostId = circleAuthorizationToBlogPost.BlogPostId, - CircleId = circleAuthorizationToBlogPost.CircleId - }; - _context.CircleAuthorizationToBlogPost.Add(entity); + _context.CircleAuthorizationToBlogPost.Add(circleAuthorizationToBlogPost); try { await _context.SaveChangesAsync(User.GetUserId()); diff --git a/src/Yavsc.Blogs/Controllers/BlogApiController.cs b/src/Yavsc.Blogs/Controllers/BlogApiController.cs index fcd3a336..76aa777e 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.Constants; +using static Yavsc.Blogs.Constants; namespace Yavsc.Blogs.Controllers { diff --git a/src/Yavsc.Blogs/Controllers/BlogTagsApiController.cs b/src/Yavsc.Blogs/Controllers/BlogTagsApiController.cs index ad6a0893..a5d905eb 100644 --- a/src/Yavsc.Blogs/Controllers/BlogTagsApiController.cs +++ b/src/Yavsc.Blogs/Controllers/BlogTagsApiController.cs @@ -1,8 +1,12 @@ +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.Constants; +using static Yavsc.Blogs.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 ea3c981b..73bbfff9 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.Constants; +using static Yavsc.Blogs.Constants; namespace Yavsc.Blogs.Controllers { diff --git a/src/Yavsc.Blogs/Controllers/CommentsApiController.cs b/src/Yavsc.Blogs/Controllers/CommentsApiController.cs index d4c80f99..b9f334dc 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.Constants; +using static Yavsc.Blogs.Constants; namespace Yavsc.Blogs.Controllers { diff --git a/src/Yavsc.Blogs/Controllers/FileSystemApiController.cs b/src/Yavsc.Blogs/Controllers/FileSystemApiController.cs index 5e834503..5b067c1b 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.Constants; +using static Yavsc.Blogs.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 bc6485dd..23cf0cc6 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.Constants; +using static Yavsc.Blogs.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 da03c19c..e908edec 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.Constants; +using static Yavsc.Blogs.Constants; namespace Yavsc.Blogs.Controllers { diff --git a/src/Yavsc.Blogs/Controllers/TagsApiController.cs b/src/Yavsc.Blogs/Controllers/TagsApiController.cs index d4c2b538..daf0220b 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.Constants; +using static Yavsc.Blogs.Constants; namespace Yavsc.Controllers { diff --git a/src/Yavsc.Blogs/Controllers/UserSearchApiController.cs b/src/Yavsc.Blogs/Controllers/UserSearchApiController.cs index 951a5880..048db154 100644 --- a/src/Yavsc.Blogs/Controllers/UserSearchApiController.cs +++ b/src/Yavsc.Blogs/Controllers/UserSearchApiController.cs @@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Yavsc.Models; -using static Yavsc.Constants; namespace Yavsc.Blogs.Controllers { @@ -27,7 +26,7 @@ namespace Yavsc.Blogs.Controllers /// exposing it. /// [Produces("application/json")] - [Route(APIPrefix + "/user-search")] + [Route( Constants.APIPrefix + "/user-search")] [Authorize] public class UserSearchApiController : Controller { @@ -67,9 +66,8 @@ 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 normalized = e.Trim(); - query = query.Where(u => u.Email != null && - string.Compare(u.Email, normalized, true) ==0); + var normalised = e.Trim(); + query = query.Where(u => u.Email != null && u.Email.ToLower() == normalised.ToLower()); } if (!string.IsNullOrWhiteSpace(q)) diff --git a/src/Yavsc.Blogs/Program.cs b/src/Yavsc.Blogs/Program.cs index 952115d3..742c9eee 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( - Yavsc.Constants.YavscConnectionStringName))); + YavscConstants.YavscConnectionStringName))); // other services services diff --git a/src/Yavsc.Org.Tests/NonRegression/EMailling.cs b/src/Yavsc.Org.Tests/NonRegression/EMailling.cs index 743dbbc1..453c2650 100644 --- a/src/Yavsc.Org.Tests/NonRegression/EMailling.cs +++ b/src/Yavsc.Org.Tests/NonRegression/EMailling.cs @@ -19,11 +19,11 @@ namespace Yavsc.Org.Tests { this.output = output; _serverFixture = serverFixture; - _logger = serverFixture.Logger!; + _logger = serverFixture.Logger; } [Fact] - public async Task SendEMailSynchrone() + public void SendEMailSynchrone() { using IServiceScope scope = _serverFixture.Services.CreateScope(); @@ -32,12 +32,12 @@ namespace Yavsc.Org.Tests scope.ServiceProvider.GetRequiredService()); output.WriteLine("SendEMailSynchrone ..."); - await mailSender.SendEmailAsync + mailSender.SendEmailAsync ( - _serverFixture.SiteSettings!.Owner.Name, - _serverFixture.SiteSettings!.Owner.EMail, + _serverFixture.SiteSettings.Owner.Name, + _serverFixture.SiteSettings.Owner.EMail, $"monthly email", - "test boby monthly email"); + "test boby monthly email").Wait(); // Assert the SMTP roundtrip was short-circuited by the // recording fake installed in WebServerFixture: exactly diff --git a/src/Yavsc.Org.Tests/NonRegression/UserDisplayHelpersTests.cs b/src/Yavsc.Org.Tests/NonRegression/UserDisplayHelpersTests.cs index 7543a42e..a0249fa4 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(Yavsc.Constants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(null)); + Assert.Equal(YavscConstants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(null)); } [Fact] public void AvatarSrc_user_with_empty_UserName_returns_default_avatar() { var user = new FakeUser { UserName = "" }; - Assert.Equal(Yavsc.Constants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(user)); + Assert.Equal(YavscConstants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(user)); } [Fact] public void AvatarSrc_user_with_whitespace_UserName_returns_default_avatar() { var user = new FakeUser { UserName = " " }; - Assert.Equal(Yavsc.Constants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(user)); + Assert.Equal(YavscConstants.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 = $"{Yavsc.Constants.AvatarsPath}/alice.s.png"; + var expected = $"{YavscConstants.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 edfd87d9..a623bc9e 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:{Yavsc.Constants.YavscConnectionStringName}"] = "InMemory", + { + [$"ConnectionStrings:{YavscConstants.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 c562736d..43565442 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(Constants.SigninPath)] + [HttpGet(YavscConstants.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(Constants.SigninPath)] + /// + [HttpPost(YavscConstants.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(Constants.LogoutPath)] + [HttpPost(YavscConstants.LogoutPath)] [ValidateAntiForgeryToken] public async Task LogOff(string returnUrl = null) { @@ -829,7 +829,7 @@ IHtmlLocalizerFactory htmlLocalizerFactory, bool result = false; try { - result = await _userManager.VerifyTwoFactorTokenAsync(user, Constants.DefaultFactor, code); + result = await _userManager.VerifyTwoFactorTokenAsync(user, YavscConstants.DefaultFactor, code); _dbContext.SaveChanges(userId); } catch (Exception ex) @@ -1024,12 +1024,12 @@ IHtmlLocalizerFactory htmlLocalizerFactory, } // Generate the token and send it - if (model.SelectedProvider == Constants.MobileAppFactor) + if (model.SelectedProvider == YavscConstants.MobileAppFactor) { return View("Error", new Exception("No mobile app service was activated")); } else - if (model.SelectedProvider == Constants.SMSFactor) + if (model.SelectedProvider == YavscConstants.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 e2944e9e..7104e178 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[] { - Constants.AdminGroupName, - Constants.StarGroupName, - Constants.PerformerGroupName, - Constants.FrontOfficeGroupName, - Constants.StarHunterGroupName, - Constants.BlogModeratorGroupName + YavscConstants.AdminGroupName, + YavscConstants.StarGroupName, + YavscConstants.PerformerGroupName, + YavscConstants.FrontOfficeGroupName, + YavscConstants.StarHunterGroupName, + YavscConstants.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(Constants.AdminGroupName); + var admins = await _userManager.GetUsersInRoleAsync(YavscConstants.AdminGroupName); if (admins != null && admins.Count > 0) { // All is ok, nothing to do here. - if (User.IsInMsRole(Constants.AdminGroupName)) + if (User.IsInMsRole(YavscConstants.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, Constants.AdminGroupName); + var addToRoleResult = await _userManager.AddToRoleAsync(user, YavscConstants.AdminGroupName); if (!addToRoleResult.Succeeded) { AddErrors(addToRoleResult); @@ -114,11 +114,11 @@ namespace Yavsc.Controllers public async Task Index() { var adminCount = await _userManager.GetUsersInRoleAsync( - Constants.AdminGroupName); + YavscConstants.AdminGroupName); var userCount = await _dbContext.Users.CountAsync(); var youAreAdmin = await _userManager.IsInRoleAsync( await _userManager.FindByIdAsync(User.GetUserId()), - Constants.AdminGroupName); + YavscConstants.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 d6e83c36..983e7233 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(APIPrefix + "/[controller]")] + [Route("api/[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 f8b41c99..e5002168 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(Constants.AdminGroupName); - ViewBag.IsPerformer = User.IsInMsRole(Constants.PerformerGroupName); + ViewBag.IsAdmin = User.IsInMsRole(YavscConstants.AdminGroupName); + ViewBag.IsPerformer = User.IsInMsRole(YavscConstants.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==Constants.NoneCode) + if (activity.ParentCode==YavscConstants.NoneCode) activity.ParentCode=null; - if (activity.SettingsClassName==Constants.NoneCode) + if (activity.SettingsClassName==YavscConstants.NoneCode) activity.SettingsClassName=null; if (ModelState.IsValid) @@ -161,9 +161,9 @@ namespace Yavsc.Controllers [ValidateAntiForgeryToken] public IActionResult Edit(Activity activity) { - if (activity.ParentCode==Constants.NoneCode) + if (activity.ParentCode==YavscConstants.NoneCode) activity.ParentCode=null; - if (activity.SettingsClassName==Constants.NoneCode) + if (activity.SettingsClassName==YavscConstants.NoneCode) activity.SettingsClassName=null; if (ModelState.IsValid) { diff --git a/src/Yavsc.Org/Controllers/DimissClicksApiController.cs b/src/Yavsc.Org/Controllers/DimissClicksApiController.cs index b07bc4b3..19f90787 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(Constants.APIPrefix + "/v1/dimiss")] + [Route("api/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 c7aa131f..67c19fed 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(Constants.SshHeaderKey) && Request.Headers[Constants.SshHeaderKey] == "on"; + ViewBag.IsFromSecureProx = Request.Headers.ContainsKey(YavscConstants.SshHeaderKey) && Request.Headers[YavscConstants.SshHeaderKey] == "on"; ViewBag.SecureHomeUrl = "https://" + Request.Headers["X-Forwarded-Host"]; - ViewBag.SshHeaderKey = Request.Headers[Constants.SshHeaderKey]; + ViewBag.SshHeaderKey = Request.Headers[YavscConstants.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 536c7417..dc905d08 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(Constants.AdminGroupName)) + if (model.UserId != uid) if (!User.IsInMsRole(YavscConstants.AdminGroupName)) return new ChallengeResult(); _context.Instrumentation.Add(model); @@ -82,7 +82,7 @@ namespace Yavsc.Controllers { return NotFound(); } - if (id != uid) if (!User.IsInMsRole(Constants.AdminGroupName)) + if (id != uid) if (!User.IsInMsRole(YavscConstants.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(Constants.AdminGroupName)) + if (musicianSettings.UserId != uid) if (!User.IsInMsRole(YavscConstants.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(Constants.AdminGroupName)) + if (musicianSettings.UserId != uid) if (!User.IsInMsRole(YavscConstants.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(Constants.AdminGroupName)) + if (musicianSettings.UserId != uid) if (!User.IsInMsRole(YavscConstants.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 f92dc3c9..0cae23a7 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(Constants.YavscConnectionStringName); + var connectionString = builder.Configuration.GetConnectionString(YavscConstants.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 = Constants.RoleClaimType; + options.ClaimsIdentity.RoleClaimType = YavscConstants.RoleClaimType; } ) .AddEntityFrameworkStores(); @@ -239,18 +239,18 @@ public static class HostingExtensions { policy .RequireAuthenticatedUser() - .RequireClaim(Constants.RoleClaimType, - new string[] { Constants.PerformerGroupName, Constants.AdminGroupName }) + .RequireClaim(YavscConstants.RoleClaimType, + new string[] { YavscConstants.PerformerGroupName, YavscConstants.AdminGroupName }) ; }); options.AddPolicy("AdministratorOnly", policy => { _ = policy .RequireAuthenticatedUser() - .RequireClaim(Constants.RoleClaimType, Constants.AdminGroupName); + .RequireClaim(YavscConstants.RoleClaimType, YavscConstants.AdminGroupName); }); - options.AddPolicy("FrontOffice", policy => policy.RequireRole(Constants.FrontOfficeGroupName)); + options.AddPolicy("FrontOffice", policy => policy.RequireRole(YavscConstants.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 = Constants.RoleClaimType; + options.ClaimsIdentity.RoleClaimType = YavscConstants.RoleClaimType; }); var migrationsAssembly = typeof(Program).GetTypeInfo().Assembly.GetName().Name; - var connectionString = builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName); + var connectionString = builder.Configuration.GetConnectionString(YavscConstants.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(Constants.UserFilesPath), + RequestPath = PathString.FromUriComponent(YavscConstants.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(Constants.AvatarsPath), + RequestPath = PathString.FromUriComponent(YavscConstants.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(Constants.GitPath), + RequestPath = PathString.FromUriComponent(YavscConstants.GitPath), EnableDirectoryBrowsing = enableDirectoryBrowsing, }; Config.GitOptions.DefaultFilesOptions.DefaultFileNames.Add("index.md"); diff --git a/src/Yavsc.Org/Migrations/20260820232152_DropCommentFromCircleAuthorizationToBlogPost.Designer.cs b/src/Yavsc.Org/Migrations/20260820232152_DropCommentFromCircleAuthorizationToBlogPost.Designer.cs deleted file mode 100644 index a9af372c..00000000 --- a/src/Yavsc.Org/Migrations/20260820232152_DropCommentFromCircleAuthorizationToBlogPost.Designer.cs +++ /dev/null @@ -1,4645 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; -using Yavsc.Models; - -#nullable disable - -namespace Yavsc.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20260820232152_DropCommentFromCircleAuthorizationToBlogPost")] - partial class DropCommentFromCircleAuthorizationToBlogPost - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.9") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiResource", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("AllowedAccessTokenSigningAlgorithms") - .HasColumnType("text"); - - b.Property("Created") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("DisplayName") - .HasColumnType("text"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("LastAccessed") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("NonEditable") - .HasColumnType("boolean"); - - b.Property("ShowInDiscoveryDocument") - .HasColumnType("boolean"); - - b.Property("Updated") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.ToTable("ApiResources"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiResourceClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ApiResourceId") - .HasColumnType("integer"); - - b.Property("ApiResourceId1") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ApiResourceId"); - - b.HasIndex("ApiResourceId1"); - - b.ToTable("ApiResourceClaims"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiResourceProperty", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ApiResourceId") - .HasColumnType("integer"); - - b.Property("ApiResourceId1") - .HasColumnType("integer"); - - b.Property("Key") - .HasColumnType("text"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ApiResourceId"); - - b.HasIndex("ApiResourceId1"); - - b.ToTable("ApiResourceProperties"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiResourceScope", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ApiResourceId") - .HasColumnType("integer"); - - b.Property("ApiResourceId1") - .HasColumnType("integer"); - - b.Property("Scope") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ApiResourceId"); - - b.HasIndex("ApiResourceId1"); - - b.ToTable("ApiResourceScopes"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiResourceSecret", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ApiResourceId") - .HasColumnType("integer"); - - b.Property("ApiResourceId1") - .HasColumnType("integer"); - - b.Property("Created") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("Expiration") - .HasColumnType("timestamp with time zone"); - - b.Property("Type") - .HasColumnType("text"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ApiResourceId"); - - b.HasIndex("ApiResourceId1"); - - b.ToTable("ApiResourceSecrets"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiScope", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("DisplayName") - .HasColumnType("text"); - - b.Property("Emphasize") - .HasColumnType("boolean"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Required") - .HasColumnType("boolean"); - - b.Property("ShowInDiscoveryDocument") - .HasColumnType("boolean"); - - b.HasKey("Id"); - - b.ToTable("ApiScopes"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiScopeClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ScopeId") - .HasColumnType("integer"); - - b.Property("ScopeId1") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ScopeId"); - - b.HasIndex("ScopeId1"); - - b.ToTable("ApiScopeClaims"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiScopeProperty", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Key") - .HasColumnType("text"); - - b.Property("ScopeId") - .HasColumnType("integer"); - - b.Property("ScopeId1") - .HasColumnType("integer"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ScopeId"); - - b.HasIndex("ScopeId1"); - - b.ToTable("ApiScopeProperties"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.Client", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("AbsoluteRefreshTokenLifetime") - .HasColumnType("integer"); - - b.Property("AccessTokenLifetime") - .HasColumnType("integer"); - - b.Property("AccessTokenType") - .HasColumnType("integer"); - - b.Property("AllowAccessTokensViaBrowser") - .HasColumnType("boolean"); - - b.Property("AllowOfflineAccess") - .HasColumnType("boolean"); - - b.Property("AllowPlainTextPkce") - .HasColumnType("boolean"); - - b.Property("AllowRememberConsent") - .HasColumnType("boolean"); - - b.Property("AllowedIdentityTokenSigningAlgorithms") - .HasColumnType("text"); - - b.Property("AlwaysIncludeUserClaimsInIdToken") - .HasColumnType("boolean"); - - b.Property("AlwaysSendClientClaims") - .HasColumnType("boolean"); - - b.Property("AuthorizationCodeLifetime") - .HasColumnType("integer"); - - b.Property("BackChannelLogoutSessionRequired") - .HasColumnType("boolean"); - - b.Property("BackChannelLogoutUri") - .HasColumnType("text"); - - b.Property("ClientClaimsPrefix") - .HasColumnType("text"); - - b.Property("ClientId") - .HasColumnType("text"); - - b.Property("ClientName") - .HasColumnType("text"); - - b.Property("ClientUri") - .HasColumnType("text"); - - b.Property("ConsentLifetime") - .HasColumnType("integer"); - - b.Property("Created") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("DeviceCodeLifetime") - .HasColumnType("integer"); - - b.Property("EnableLocalLogin") - .HasColumnType("boolean"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("FrontChannelLogoutSessionRequired") - .HasColumnType("boolean"); - - b.Property("FrontChannelLogoutUri") - .HasColumnType("text"); - - b.Property("IdentityTokenLifetime") - .HasColumnType("integer"); - - b.Property("IncludeJwtId") - .HasColumnType("boolean"); - - b.Property("LastAccessed") - .HasColumnType("timestamp with time zone"); - - b.Property("LogoUri") - .HasColumnType("text"); - - b.Property("NonEditable") - .HasColumnType("boolean"); - - b.Property("PairWiseSubjectSalt") - .HasColumnType("text"); - - b.Property("ProtocolType") - .HasColumnType("text"); - - b.Property("RefreshTokenExpiration") - .HasColumnType("integer"); - - b.Property("RefreshTokenUsage") - .HasColumnType("integer"); - - b.Property("RequireClientSecret") - .HasColumnType("boolean"); - - b.Property("RequireConsent") - .HasColumnType("boolean"); - - b.Property("RequirePkce") - .HasColumnType("boolean"); - - b.Property("RequireRequestObject") - .HasColumnType("boolean"); - - b.Property("SlidingRefreshTokenLifetime") - .HasColumnType("integer"); - - b.Property("UpdateAccessTokenClaimsOnRefresh") - .HasColumnType("boolean"); - - b.Property("Updated") - .HasColumnType("timestamp with time zone"); - - b.Property("UserCodeType") - .HasColumnType("text"); - - b.Property("UserSsoLifetime") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.ToTable("Clients"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("ClientId") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("text"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ClientId"); - - b.ToTable("ClientClaims"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientCorsOrigin", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("ClientId") - .HasColumnType("integer"); - - b.Property("ClientId1") - .HasColumnType("integer"); - - b.Property("Origin") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ClientId"); - - b.HasIndex("ClientId1"); - - b.ToTable("ClientCorsOrigins"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientGrantType", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("ClientId") - .HasColumnType("integer"); - - b.Property("GrantType") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ClientId"); - - b.ToTable("ClientGrantTypes"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientIdPRestriction", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("ClientId") - .HasColumnType("integer"); - - b.Property("ClientId1") - .HasColumnType("integer"); - - b.Property("Provider") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ClientId"); - - b.HasIndex("ClientId1"); - - b.ToTable("ClientIdPRestrictions"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("ClientId") - .HasColumnType("integer"); - - b.Property("ClientId1") - .HasColumnType("integer"); - - b.Property("PostLogoutRedirectUri") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ClientId"); - - b.HasIndex("ClientId1"); - - b.ToTable("ClientPostLogoutRedirectUris"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientProperty", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("ClientId") - .HasColumnType("integer"); - - b.Property("ClientId1") - .HasColumnType("integer"); - - b.Property("Key") - .HasColumnType("text"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ClientId"); - - b.HasIndex("ClientId1"); - - b.ToTable("ClientProperties"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientRedirectUri", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("ClientId") - .HasColumnType("integer"); - - b.Property("RedirectUri") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ClientId"); - - b.ToTable("ClientRedirectUris"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientScope", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("ClientId") - .HasColumnType("integer"); - - b.Property("Scope") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ClientId"); - - b.ToTable("ClientScopes"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientSecret", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityAlwaysColumn(b.Property("Id")); - - b.Property("ClientId") - .HasColumnType("integer"); - - b.Property("ClientId1") - .HasColumnType("integer"); - - b.Property("Created") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("Expiration") - .HasColumnType("timestamp with time zone"); - - b.Property("Type") - .HasColumnType("text"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ClientId"); - - b.HasIndex("ClientId1"); - - b.ToTable("ClientSecrets"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.DeviceFlowCodes", b => - { - b.Property("UserCode") - .HasColumnType("text"); - - b.Property("DeviceCode") - .HasColumnType("text"); - - b.Property("ClientId") - .HasColumnType("text"); - - b.Property("CreationTime") - .HasColumnType("timestamp with time zone"); - - b.Property("Data") - .HasColumnType("text"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("Expiration") - .HasColumnType("timestamp with time zone"); - - b.Property("SessionId") - .HasColumnType("text"); - - b.Property("SubjectId") - .HasColumnType("text"); - - b.HasKey("UserCode", "DeviceCode"); - - b.ToTable("DeviceFlowCodes"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.IdentityResource", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Created") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("DisplayName") - .HasColumnType("text"); - - b.Property("Emphasize") - .HasColumnType("boolean"); - - b.Property("Enabled") - .HasColumnType("boolean"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("NonEditable") - .HasColumnType("boolean"); - - b.Property("Required") - .HasColumnType("boolean"); - - b.Property("ShowInDiscoveryDocument") - .HasColumnType("boolean"); - - b.Property("Updated") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.ToTable("IdentityResources"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.IdentityResourceClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("IdentityResourceId") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("IdentityResourceId"); - - b.ToTable("IdentityResourceClaims"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.IdentityResourceProperty", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("IdentityResourceId") - .HasColumnType("integer"); - - b.Property("Key") - .HasColumnType("text"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("IdentityResourceId"); - - b.ToTable("IdentityResourceProperties"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.PersistedGrant", b => - { - b.Property("Key") - .HasColumnType("text"); - - b.Property("ClientId") - .HasColumnType("text"); - - b.Property("ConsumedTime") - .HasColumnType("timestamp with time zone"); - - b.Property("CreationTime") - .HasColumnType("timestamp with time zone"); - - b.Property("Data") - .HasColumnType("text"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("Expiration") - .HasColumnType("timestamp with time zone"); - - b.Property("SessionId") - .HasColumnType("text"); - - b.Property("SubjectId") - .HasColumnType("text"); - - b.Property("Type") - .HasColumnType("text"); - - b.HasKey("Key"); - - b.ToTable("PersistedGrants"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .HasColumnType("text"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("text"); - - b.Property("ClaimValue") - .HasColumnType("text"); - - b.Property("RoleId") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ClaimType") - .HasColumnType("text"); - - b.Property("ClaimValue") - .HasColumnType("text"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("text"); - - b.Property("ProviderKey") - .HasColumnType("text"); - - b.Property("ProviderDisplayName") - .HasColumnType("text"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("text"); - - b.Property("RoleId") - .HasColumnType("text"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("text"); - - b.Property("LoginProvider") - .HasColumnType("text"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens", (string)null); - }); - - modelBuilder.Entity("Yavsc.Abstract.Identity.ClientProviderInfo", b => - { - b.Property("UserId") - .HasColumnType("text"); - - b.Property("Avatar") - .HasColumnType("text"); - - b.Property("BillingAddressId") - .HasColumnType("bigint"); - - b.Property("EMail") - .HasColumnType("text"); - - b.Property("Phone") - .HasColumnType("text"); - - b.Property("UserName") - .HasColumnType("text"); - - b.HasKey("UserId"); - - b.ToTable("ClientProviderInfo"); - }); - - modelBuilder.Entity("Yavsc.Abstract.Models.Messaging.Notification", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Target") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("body") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("click_action") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("color") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("icon") - .ValueGeneratedOnAdd() - .HasMaxLength(512) - .HasColumnType("character varying(512)") - .HasDefaultValue("exclam"); - - b.Property("sound") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("tag") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("title") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.HasKey("Id"); - - b.ToTable("Notification"); - }); - - modelBuilder.Entity("Yavsc.Models.Access.Ban", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("Reason") - .IsRequired() - .HasColumnType("text"); - - b.Property("TargetId") - .IsRequired() - .HasColumnType("text"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("TargetId"); - - b.ToTable("Ban"); - }); - - modelBuilder.Entity("Yavsc.Models.Access.BlackListed", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("OwnerId") - .IsRequired() - .HasColumnType("text"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("OwnerId"); - - b.HasIndex("UserId"); - - b.ToTable("BlackListed"); - }); - - modelBuilder.Entity("Yavsc.Models.Access.CircleAuthorizationToBlogPost", b => - { - b.Property("CircleId") - .HasColumnType("bigint"); - - b.Property("BlogPostId") - .HasColumnType("bigint"); - - b.HasKey("CircleId", "BlogPostId"); - - b.HasIndex("BlogPostId"); - - b.ToTable("CircleAuthorizationToBlogPost"); - }); - - modelBuilder.Entity("Yavsc.Models.AccountBalance", b => - { - b.Property("UserId") - .HasColumnType("text"); - - b.Property("ContactCredits") - .HasColumnType("bigint"); - - b.Property("Credits") - .HasColumnType("numeric"); - - b.HasKey("UserId"); - - b.ToTable("BankStatus"); - }); - - modelBuilder.Entity("Yavsc.Models.ApplicationUser", b => - { - b.Property("Id") - .HasColumnType("text"); - - b.Property("AccessFailedCount") - .HasColumnType("integer"); - - b.Property("AllowMonthlyEmail") - .HasColumnType("boolean"); - - b.Property("Avatar") - .ValueGeneratedOnAdd() - .HasMaxLength(512) - .HasColumnType("character varying(512)") - .HasDefaultValue("/images/Users/icon_user.png"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property("DedicatedGoogleCalendar") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("DiskQuota") - .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasDefaultValue(524288000L); - - b.Property("DiskUsage") - .HasColumnType("bigint"); - - b.Property("Email") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("EmailConfirmed") - .HasColumnType("boolean"); - - b.Property("FullName") - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("LockoutEnabled") - .HasColumnType("boolean"); - - b.Property("LockoutEnd") - .HasColumnType("timestamp with time zone"); - - b.Property("MaxFileSize") - .HasColumnType("bigint"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("PasswordHash") - .HasColumnType("text"); - - b.Property("PhoneNumber") - .HasColumnType("text"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("boolean"); - - b.Property("PostalAddressId") - .HasColumnType("bigint"); - - b.Property("SecurityStamp") - .HasColumnType("text"); - - b.Property("TwoFactorEnabled") - .HasColumnType("boolean"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasAlternateKey("Email"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.HasIndex("PostalAddressId"); - - b.ToTable("AspNetUsers", (string)null); - }); - - modelBuilder.Entity("Yavsc.Models.BalanceImpact", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("BalanceId") - .IsRequired() - .HasColumnType("text"); - - b.Property("ExecDate") - .HasColumnType("timestamp with time zone"); - - b.Property("Impact") - .HasColumnType("numeric"); - - b.Property("Reason") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("BalanceId"); - - b.ToTable("BalanceImpact"); - }); - - modelBuilder.Entity("Yavsc.Models.Bank.BankIdentity", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AccountNumber") - .HasColumnType("text"); - - b.Property("BIC") - .HasColumnType("text"); - - b.Property("BankCode") - .HasColumnType("text"); - - b.Property("BankedKey") - .HasColumnType("integer"); - - b.Property("IBAN") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("text"); - - b.Property("WicketCode") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("BankIdentity"); - }); - - modelBuilder.Entity("Yavsc.Models.Billing.CommandLine", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Count") - .HasColumnType("integer"); - - b.Property("Currency") - .HasColumnType("text"); - - b.Property("Description") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("EstimateId") - .HasColumnType("bigint"); - - b.Property("EstimateTemplateId") - .HasColumnType("bigint"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property("UnitaryCost") - .HasColumnType("numeric"); - - b.HasKey("Id"); - - b.HasIndex("EstimateId"); - - b.HasIndex("EstimateTemplateId"); - - b.ToTable("CommandLine"); - }); - - modelBuilder.Entity("Yavsc.Models.Billing.Estimate", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AttachedFilesString") - .HasColumnType("text"); - - b.Property("AttachedGraphicsString") - .HasColumnType("text"); - - b.Property("ClientId") - .IsRequired() - .HasColumnType("text"); - - b.Property("ClientValidationDate") - .HasColumnType("timestamp with time zone"); - - b.Property("CommandId") - .HasColumnType("bigint"); - - b.Property("CommandType") - .IsRequired() - .HasColumnType("text"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("OwnerId") - .HasColumnType("text"); - - b.Property("ProviderValidationDate") - .HasColumnType("timestamp with time zone"); - - b.Property("Title") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ClientId"); - - b.HasIndex("CommandId"); - - b.HasIndex("OwnerId"); - - b.ToTable("Estimates"); - }); - - modelBuilder.Entity("Yavsc.Models.Billing.EstimateTemplate", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("OwnerId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Title") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("EstimateTemplates"); - }); - - modelBuilder.Entity("Yavsc.Models.Billing.ExceptionSIREN", b => - { - b.Property("SIREN") - .HasColumnType("text"); - - b.HasKey("SIREN"); - - b.ToTable("ExceptionsSIREN"); - }); - - modelBuilder.Entity("Yavsc.Models.Billing.Signature", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CapturedAtUtc") - .HasColumnType("timestamp with time zone"); - - b.Property("CoordinateMax") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasDefaultValue(10000); - - b.Property("EstimateId") - .HasColumnType("bigint"); - - b.Property("FilePath") - .IsRequired() - .HasColumnType("text"); - - b.Property("SignerId") - .IsRequired() - .HasColumnType("text"); - - b.PrimitiveCollection("Strokes") - .IsRequired() - .HasColumnType("integer[]"); - - b.Property("Type") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("SignerId"); - - b.HasIndex("EstimateId", "Type") - .IsUnique(); - - b.ToTable("Signatures"); - }); - - modelBuilder.Entity("Yavsc.Models.Blog.BlogAttachedFile", b => - { - b.Property("FileId") - .HasColumnType("bigint"); - - b.Property("PostId") - .HasColumnType("bigint"); - - b.HasKey("FileId", "PostId"); - - b.HasIndex("PostId"); - - b.ToTable("BlogAttachedFiles"); - }); - - modelBuilder.Entity("Yavsc.Models.Blog.BlogPost", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Article") - .HasMaxLength(56224) - .HasColumnType("character varying(56224)"); - - b.Property("AuthorId") - .HasColumnType("text"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("Photo") - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("Title") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("AuthorId"); - - b.ToTable("BlogSpot"); - }); - - modelBuilder.Entity("Yavsc.Models.Blog.BlogTag", b => - { - b.Property("PostId") - .HasColumnType("bigint"); - - b.Property("TagId") - .HasColumnType("bigint"); - - b.HasKey("PostId", "TagId"); - - b.HasIndex("TagId"); - - b.ToTable("BlogTag"); - }); - - modelBuilder.Entity("Yavsc.Models.Blog.Comment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Article") - .HasColumnType("text"); - - b.Property("AuthorId") - .IsRequired() - .HasColumnType("text"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("ParentId") - .HasColumnType("bigint"); - - b.Property("ReceiverId") - .HasColumnType("bigint"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.Property("Visible") - .HasColumnType("boolean"); - - b.HasKey("Id"); - - b.HasIndex("AuthorId"); - - b.HasIndex("ParentId"); - - b.HasIndex("ReceiverId"); - - b.ToTable("Comment"); - }); - - modelBuilder.Entity("Yavsc.Models.Blog.UploadedFile", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ContentType") - .HasColumnType("text"); - - b.Property("Length") - .HasColumnType("bigint"); - - b.Property("Path") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("UploadedFiles"); - }); - - modelBuilder.Entity("Yavsc.Models.BlogSpotPublication", b => - { - b.Property("BlogpostId") - .HasColumnType("bigint"); - - b.HasKey("BlogpostId"); - - b.ToTable("blogSpotPublications"); - }); - - modelBuilder.Entity("Yavsc.Models.Calendar.Schedule", b => - { - b.Property("OwnerId") - .HasColumnType("text"); - - b.HasKey("OwnerId"); - - b.ToTable("Schedule"); - }); - - modelBuilder.Entity("Yavsc.Models.Calendar.ScheduledEvent", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("PeriodEnd") - .HasColumnType("timestamp with time zone"); - - b.Property("PeriodStart") - .HasColumnType("timestamp with time zone"); - - b.Property("Reccurence") - .HasColumnType("integer"); - - b.Property("ScheduleOwnerId") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ScheduleOwnerId"); - - b.HasIndex("PeriodStart", "PeriodEnd"); - - b.ToTable("ScheduledEvent"); - }); - - modelBuilder.Entity("Yavsc.Models.Chat.ChatConnection", b => - { - b.Property("ConnectionId") - .HasColumnType("text"); - - b.Property("ApplicationUserId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Connected") - .HasColumnType("boolean"); - - b.Property("UserAgent") - .HasColumnType("text"); - - b.HasKey("ConnectionId"); - - b.HasIndex("ApplicationUserId"); - - b.ToTable("ChatConnection"); - }); - - modelBuilder.Entity("Yavsc.Models.Chat.ChatRoom", b => - { - b.Property("Name") - .HasColumnType("text"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("LatestJoinPart") - .HasColumnType("timestamp with time zone"); - - b.Property("OwnerId") - .HasColumnType("text"); - - b.Property("Topic") - .HasColumnType("text"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.HasKey("Name"); - - b.HasIndex("OwnerId"); - - b.ToTable("ChatRoom"); - }); - - modelBuilder.Entity("Yavsc.Models.Chat.ChatRoomAccess", b => - { - b.Property("ChannelName") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("text"); - - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Level") - .HasColumnType("integer"); - - b.HasKey("ChannelName", "UserId"); - - b.HasIndex("UserId"); - - b.ToTable("ChatRoomAccess"); - }); - - modelBuilder.Entity("Yavsc.Models.Cratie.Option", b => - { - b.Property("Code") - .HasColumnType("text"); - - b.Property("CodeScrutin") - .HasColumnType("text"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.HasKey("Code", "CodeScrutin"); - - b.ToTable("Option"); - }); - - modelBuilder.Entity("Yavsc.Models.Drawing.Color", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Blue") - .HasColumnType("smallint"); - - b.Property("Green") - .HasColumnType("smallint"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Red") - .HasColumnType("smallint"); - - b.HasKey("Id"); - - b.ToTable("Color"); - }); - - modelBuilder.Entity("Yavsc.Models.Forms.Form", b => - { - b.Property("Id") - .HasColumnType("text"); - - b.Property("Summary") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Form"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.BrusherProfile", b => - { - b.Property("UserId") - .HasColumnType("text"); - - b.Property("ActionDistance") - .HasColumnType("integer"); - - b.Property("CarePrice") - .HasColumnType("numeric"); - - b.Property("FlatFeeDiscount") - .HasColumnType("numeric"); - - b.Property("HalfBalayagePrice") - .HasColumnType("numeric"); - - b.Property("HalfBrushingPrice") - .HasColumnType("numeric"); - - b.Property("HalfColorPrice") - .HasColumnType("numeric"); - - b.Property("HalfDefrisPrice") - .HasColumnType("numeric"); - - b.Property("HalfFoldingPrice") - .HasColumnType("numeric"); - - b.Property("HalfMechPrice") - .HasColumnType("numeric"); - - b.Property("HalfMultiColorPrice") - .HasColumnType("numeric"); - - b.Property("HalfPermanentPrice") - .HasColumnType("numeric"); - - b.Property("KidCutPrice") - .HasColumnType("numeric"); - - b.Property("LongBalayagePrice") - .HasColumnType("numeric"); - - b.Property("LongBrushingPrice") - .HasColumnType("numeric"); - - b.Property("LongColorPrice") - .HasColumnType("numeric"); - - b.Property("LongDefrisPrice") - .HasColumnType("numeric"); - - b.Property("LongFoldingPrice") - .HasColumnType("numeric"); - - b.Property("LongMechPrice") - .HasColumnType("numeric"); - - b.Property("LongMultiColorPrice") - .HasColumnType("numeric"); - - b.Property("LongPermanentPrice") - .HasColumnType("numeric"); - - b.Property("ManBrushPrice") - .HasColumnType("numeric"); - - b.Property("ManCutPrice") - .HasColumnType("numeric"); - - b.Property("ScheduleOwnerId") - .HasColumnType("text"); - - b.Property("ShampooPrice") - .HasColumnType("numeric"); - - b.Property("ShortBalayagePrice") - .HasColumnType("numeric"); - - b.Property("ShortBrushingPrice") - .HasColumnType("numeric"); - - b.Property("ShortColorPrice") - .HasColumnType("numeric"); - - b.Property("ShortDefrisPrice") - .HasColumnType("numeric"); - - b.Property("ShortFoldingPrice") - .HasColumnType("numeric"); - - b.Property("ShortMechPrice") - .HasColumnType("numeric"); - - b.Property("ShortMultiColorPrice") - .HasColumnType("numeric"); - - b.Property("ShortPermanentPrice") - .HasColumnType("numeric"); - - b.Property("WomenHalfCutPrice") - .HasColumnType("numeric"); - - b.Property("WomenLongCutPrice") - .HasColumnType("numeric"); - - b.Property("WomenShortCutPrice") - .HasColumnType("numeric"); - - b.HasKey("UserId"); - - b.HasIndex("ScheduleOwnerId"); - - b.ToTable("BrusherProfile"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairCutQuery", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ActivityCode") - .IsRequired() - .HasColumnType("text"); - - b.Property("AdditionalInfo") - .HasColumnType("text"); - - b.Property("ClientId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Consent") - .HasColumnType("boolean"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("EventDate") - .HasColumnType("timestamp with time zone"); - - b.Property("LocationId") - .HasColumnType("bigint"); - - b.Property("PaymentId") - .HasColumnType("text"); - - b.Property("PerformerId") - .IsRequired() - .HasColumnType("text"); - - b.Property("PrestationId") - .HasColumnType("bigint"); - - b.Property("Provisional") - .HasColumnType("numeric"); - - b.Property("SelectedProfileUserId") - .HasColumnType("text"); - - b.Property("Status") - .HasColumnType("integer"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.Property("ValidationDate") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("ActivityCode"); - - b.HasIndex("ClientId"); - - b.HasIndex("LocationId"); - - b.HasIndex("PaymentId"); - - b.HasIndex("PerformerId"); - - b.HasIndex("PrestationId"); - - b.HasIndex("SelectedProfileUserId"); - - b.ToTable("HairCutQueries"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairMultiCutQuery", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ActivityCode") - .IsRequired() - .HasColumnType("text"); - - b.Property("ClientId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Consent") - .HasColumnType("boolean"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("EventDate") - .HasColumnType("timestamp with time zone"); - - b.Property("LocationId") - .HasColumnType("bigint"); - - b.Property("PaymentId") - .HasColumnType("text"); - - b.Property("PerformerId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Provisional") - .HasColumnType("numeric"); - - b.Property("Status") - .HasColumnType("integer"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.Property("ValidationDate") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("ActivityCode"); - - b.HasIndex("ClientId"); - - b.HasIndex("LocationId"); - - b.HasIndex("PaymentId"); - - b.HasIndex("PerformerId"); - - b.ToTable("HairMultiCutQueries"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairPrestation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Cares") - .HasColumnType("boolean"); - - b.Property("Cut") - .HasColumnType("boolean"); - - b.Property("Dressing") - .HasColumnType("integer"); - - b.Property("Gender") - .HasColumnType("integer"); - - b.Property("Length") - .HasColumnType("integer"); - - b.Property("Shampoo") - .HasColumnType("boolean"); - - b.Property("Tech") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.ToTable("HairPrestation"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairPrestationCollectionItem", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("PrestationId") - .HasColumnType("bigint"); - - b.Property("QueryId") - .HasColumnType("bigint"); - - b.HasKey("Id"); - - b.HasIndex("PrestationId"); - - b.HasIndex("QueryId"); - - b.ToTable("HairPrestationCollectionItem"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairTaint", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Brand") - .HasColumnType("text"); - - b.Property("ColorId") - .HasColumnType("bigint"); - - b.HasKey("Id"); - - b.HasIndex("ColorId"); - - b.ToTable("HairTaint"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairTaintInstance", b => - { - b.Property("TaintId") - .HasColumnType("bigint"); - - b.Property("PrestationId") - .HasColumnType("bigint"); - - b.HasKey("TaintId", "PrestationId"); - - b.HasIndex("PrestationId"); - - b.ToTable("HairTaintInstance"); - }); - - modelBuilder.Entity("Yavsc.Models.IT.Evolution.Feature", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("ShortName") - .HasColumnType("text"); - - b.Property("Status") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.ToTable("Feature"); - }); - - modelBuilder.Entity("Yavsc.Models.IT.Fixing.Bug", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Description") - .HasMaxLength(10240) - .HasColumnType("character varying(10240)"); - - b.Property("FeatureId") - .HasColumnType("bigint"); - - b.Property("Status") - .HasColumnType("integer"); - - b.Property("Title") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("FeatureId"); - - b.ToTable("Bug"); - }); - - modelBuilder.Entity("Yavsc.Models.Identity.DeviceDeclaration", b => - { - b.Property("DeviceId") - .HasColumnType("text"); - - b.Property("DeclarationDate") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone") - .HasDefaultValueSql("LOCALTIMESTAMP"); - - b.Property("DeviceOwnerId") - .HasColumnType("text"); - - b.Property("LatestActivityUpdate") - .HasColumnType("timestamp with time zone"); - - b.Property("Model") - .HasColumnType("text"); - - b.Property("Platform") - .HasColumnType("text"); - - b.Property("Version") - .HasColumnType("text"); - - b.HasKey("DeviceId"); - - b.HasIndex("DeviceOwnerId"); - - b.ToTable("DeviceDeclaration"); - }); - - modelBuilder.Entity("Yavsc.Models.Kyc.DeclarationFlag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("DeclarationId") - .HasColumnType("bigint"); - - b.Property("MatchExcerpt") - .HasMaxLength(100) - .HasColumnType("character varying(100)"); - - b.Property("PatternId") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("DeclarationId"); - - b.HasIndex("PatternId"); - - b.ToTable("DeclarationFlag"); - }); - - modelBuilder.Entity("Yavsc.Models.Kyc.ModerationLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Action") - .HasColumnType("integer"); - - b.Property("DeclarationId") - .HasColumnType("bigint"); - - b.Property("ModeratorId") - .HasColumnType("text"); - - b.Property("ScoreDelta") - .HasColumnType("integer"); - - b.Property("Timestamp") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("DeclarationId"); - - b.HasIndex("ModeratorId"); - - b.HasIndex("Timestamp"); - - b.ToTable("ModerationLogs", t => - { - t.HasCheckConstraint("CK_ModerationLog_Immutable", "1=1"); - }); - }); - - modelBuilder.Entity("Yavsc.Models.Kyc.RegexAlertPattern", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Description") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("IsActive") - .HasColumnType("boolean"); - - b.Property("Pattern") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("character varying(500)"); - - b.Property("Severity") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("IsActive"); - - b.ToTable("RegexAlertPatterns"); - }); - - modelBuilder.Entity("Yavsc.Models.Kyc.TrustDeclaration", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Content") - .HasMaxLength(2000) - .HasColumnType("character varying(2000)"); - - b.Property("DeclarantTokenId") - .HasColumnType("uuid"); - - b.Property("ScoreDelta") - .HasColumnType("integer"); - - b.Property("Sentiment") - .HasColumnType("integer"); - - b.Property("Status") - .HasColumnType("integer"); - - b.Property("SubmittedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("TrustTokenId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("Status"); - - b.HasIndex("SubmittedAt"); - - b.HasIndex("TrustTokenId"); - - b.ToTable("TrustDeclarations"); - }); - - modelBuilder.Entity("Yavsc.Models.Kyc.TrustToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("TokenHash") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("character varying(128)"); - - b.Property("TokenSource") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)"); - - b.Property("TrustScore") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasIndex("TokenHash") - .IsUnique(); - - b.ToTable("TrustTokens"); - }); - - modelBuilder.Entity("Yavsc.Models.Market.Product", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Depth") - .HasColumnType("numeric"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("Height") - .HasColumnType("numeric"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Price") - .HasColumnType("numeric"); - - b.Property("Public") - .HasColumnType("boolean"); - - b.Property("Weight") - .HasColumnType("numeric"); - - b.Property("Width") - .HasColumnType("numeric"); - - b.HasKey("Id"); - - b.ToTable("Products"); - }); - - modelBuilder.Entity("Yavsc.Models.Market.Service", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ContextId") - .HasColumnType("text"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Public") - .HasColumnType("boolean"); - - b.HasKey("Id"); - - b.HasIndex("ContextId"); - - b.ToTable("Services"); - }); - - modelBuilder.Entity("Yavsc.Models.Messaging.Announce", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("For") - .HasColumnType("smallint"); - - b.Property("Message") - .HasColumnType("text"); - - b.Property("OwnerId") - .HasColumnType("text"); - - b.Property("Sender") - .HasColumnType("text"); - - b.Property("Topic") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("OwnerId"); - - b.ToTable("Announce"); - }); - - modelBuilder.Entity("Yavsc.Models.Messaging.DismissClicked", b => - { - b.Property("UserId") - .HasColumnType("text"); - - b.Property("NotificationId") - .HasColumnType("bigint"); - - b.HasKey("UserId", "NotificationId"); - - b.HasIndex("NotificationId"); - - b.ToTable("DismissClicked"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.Instrument", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Name") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.HasKey("Id"); - - b.ToTable("Instrument"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.InstrumentRating", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("InstrumentId") - .HasColumnType("bigint"); - - b.Property("OwnerId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Rate") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.HasAlternateKey("InstrumentId", "OwnerId"); - - b.HasIndex("OwnerId"); - - b.ToTable("InstrumentRating"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.MusicalPreference", b => - { - b.Property("OwnerProfileId") - .HasColumnType("text"); - - b.Property("DjSettingsUserId") - .HasColumnType("text"); - - b.Property("MusicLoverSettingsUserId") - .HasColumnType("text"); - - b.Property("Rate") - .HasColumnType("integer"); - - b.Property("TendencyId") - .HasColumnType("bigint"); - - b.HasKey("OwnerProfileId"); - - b.HasIndex("DjSettingsUserId"); - - b.HasIndex("MusicLoverSettingsUserId"); - - b.HasIndex("TendencyId"); - - b.ToTable("MusicalPreference"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.MusicalTendency", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Name") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("character varying(255)"); - - b.HasKey("Id"); - - b.ToTable("MusicalTendency"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.Profiles.DjSettings", b => - { - b.Property("UserId") - .HasColumnType("text"); - - b.Property("SoundCloudId") - .HasColumnType("text"); - - b.HasKey("UserId"); - - b.ToTable("DjSettings"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.Profiles.Instrumentation", b => - { - b.Property("InstrumentId") - .HasColumnType("bigint"); - - b.Property("UserId") - .HasColumnType("text"); - - b.HasKey("InstrumentId", "UserId"); - - b.HasIndex("UserId"); - - b.ToTable("Instrumentation"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.Profiles.MusicLoverSettings", b => - { - b.Property("UserId") - .HasColumnType("text"); - - b.HasKey("UserId"); - - b.ToTable("MusicLoverSettings"); - }); - - modelBuilder.Entity("Yavsc.Models.Payment.PayPalPayment", b => - { - b.Property("CreationToken") - .HasColumnType("text"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("ExecutorId") - .IsRequired() - .HasColumnType("text"); - - b.Property("OrderReference") - .HasColumnType("text"); - - b.Property("PaypalPayerId") - .HasColumnType("text"); - - b.Property("State") - .HasColumnType("text"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.HasKey("CreationToken"); - - b.HasIndex("ExecutorId"); - - b.ToTable("PayPalPayment"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.Circle", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ApplicationUserId") - .HasColumnType("text"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.Property("OwnerId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Public") - .HasColumnType("boolean"); - - b.HasKey("Id"); - - b.HasIndex("ApplicationUserId"); - - b.ToTable("Circle"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.CircleMember", b => - { - b.Property("MemberId") - .HasColumnType("text"); - - b.Property("CircleId") - .HasColumnType("bigint"); - - b.HasKey("MemberId", "CircleId"); - - b.HasIndex("CircleId"); - - b.ToTable("CircleMembers"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.Contact", b => - { - b.Property("OwnerId") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("text"); - - b.Property("AddressId") - .HasColumnType("bigint"); - - b.Property("ApplicationUserId") - .HasColumnType("text"); - - b.Property("EMail") - .HasColumnType("text"); - - b.Property("Name") - .HasColumnType("text"); - - b.HasKey("OwnerId", "UserId"); - - b.HasIndex("AddressId"); - - b.HasIndex("ApplicationUserId"); - - b.ToTable("Contact"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.HyperLink", b => - { - b.Property("HRef") - .HasColumnType("text"); - - b.Property("Method") - .HasColumnType("text"); - - b.Property("BrusherProfileUserId") - .HasColumnType("text"); - - b.Property("ContentType") - .HasColumnType("text"); - - b.Property("PayPalPaymentCreationToken") - .HasColumnType("text"); - - b.Property("Rel") - .HasColumnType("text"); - - b.HasKey("HRef", "Method"); - - b.HasIndex("BrusherProfileUserId"); - - b.HasIndex("PayPalPaymentCreationToken"); - - b.ToTable("HyperLink"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.Location", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Address") - .IsRequired() - .HasMaxLength(512) - .HasColumnType("character varying(512)"); - - b.Property("Latitude") - .HasColumnType("double precision"); - - b.Property("Longitude") - .HasColumnType("double precision"); - - b.HasKey("Id"); - - b.ToTable("Locations"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.PostalAddress", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("City") - .HasColumnType("text"); - - b.Property("Country") - .HasColumnType("text"); - - b.Property("PostalCode") - .HasColumnType("text"); - - b.Property("Province") - .HasColumnType("text"); - - b.Property("State") - .HasColumnType("text"); - - b.Property("Street1") - .HasColumnType("text"); - - b.Property("Street2") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("PostalAddress"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.Tag", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Tags"); - }); - - modelBuilder.Entity("Yavsc.Models.Skill", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Rate") - .HasColumnType("integer"); - - b.HasKey("Id"); - - b.ToTable("SiteSkills"); - }); - - modelBuilder.Entity("Yavsc.Models.Streaming.LiveFlow", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("DifferedFileName") - .HasColumnType("text"); - - b.Property("MediaType") - .HasColumnType("text"); - - b.Property("OwnerId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Pitch") - .HasColumnType("text"); - - b.Property("SequenceNumber") - .HasColumnType("integer"); - - b.Property("Title") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("OwnerId"); - - b.ToTable("LiveFlow"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.Activity", b => - { - b.Property("Code") - .HasColumnType("text"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("Hidden") - .HasColumnType("boolean"); - - b.Property("Moderated") - .HasColumnType("boolean"); - - b.Property("ModeratorGroupName") - .HasColumnType("text"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.Property("ParentCode") - .HasColumnType("text"); - - b.Property("Photo") - .HasColumnType("text"); - - b.Property("Rate") - .HasColumnType("integer"); - - b.Property("SettingsClassName") - .HasColumnType("text"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.HasKey("Code"); - - b.HasIndex("ParentCode"); - - b.ToTable("Activities"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.CoWorking", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("FormationSettingsUserId") - .HasColumnType("text"); - - b.Property("PerformerId") - .HasColumnType("text"); - - b.Property("WorkingForId") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("FormationSettingsUserId"); - - b.HasIndex("PerformerId"); - - b.HasIndex("WorkingForId"); - - b.ToTable("CoWorking"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.CommandForm", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ActionName") - .HasColumnType("text"); - - b.Property("ActivityCode") - .IsRequired() - .HasColumnType("text"); - - b.Property("Title") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ActivityCode"); - - b.ToTable("CommandForm"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.PerformerProfile", b => - { - b.Property("PerformerId") - .HasColumnType("text"); - - b.Property("AcceptNotifications") - .HasColumnType("boolean"); - - b.Property("AcceptPublicContact") - .HasColumnType("boolean"); - - b.Property("Active") - .HasColumnType("boolean"); - - b.Property("MaxDailyCost") - .HasColumnType("integer"); - - b.Property("MinDailyCost") - .HasColumnType("integer"); - - b.Property("OrganizationAddressId") - .HasColumnType("bigint"); - - b.Property("Rate") - .HasColumnType("integer"); - - b.Property("SIREN") - .IsRequired() - .HasColumnType("text"); - - b.Property("UseGeoLocalizationToReduceDistanceWithClients") - .HasColumnType("boolean"); - - b.Property("WebSite") - .HasColumnType("text"); - - b.HasKey("PerformerId"); - - b.HasIndex("OrganizationAddressId"); - - b.ToTable("Performers"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.Profiles.FormationSettings", b => - { - b.Property("UserId") - .HasColumnType("text"); - - b.Property("DisplayName") - .HasColumnType("text"); - - b.HasKey("UserId"); - - b.ToTable("FormationSettings"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.RdvQuery", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ActivityCode") - .IsRequired() - .HasColumnType("text"); - - b.Property("ClientId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Consent") - .HasColumnType("boolean"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("EventDate") - .HasColumnType("timestamp with time zone"); - - b.Property("LocationId") - .HasColumnType("bigint"); - - b.Property("LocationType") - .HasColumnType("integer"); - - b.Property("PaymentId") - .HasColumnType("text"); - - b.Property("PerformerId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Provisional") - .HasColumnType("numeric"); - - b.Property("Reason") - .HasColumnType("text"); - - b.Property("Status") - .HasColumnType("integer"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.Property("ValidationDate") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id"); - - b.HasIndex("ActivityCode"); - - b.HasIndex("ClientId"); - - b.HasIndex("LocationId"); - - b.HasIndex("PaymentId"); - - b.HasIndex("PerformerId"); - - b.ToTable("RdvQueries"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.UserActivity", b => - { - b.Property("DoesCode") - .HasColumnType("text"); - - b.Property("UserId") - .HasColumnType("text"); - - b.Property("Weight") - .HasColumnType("integer"); - - b.HasKey("DoesCode", "UserId"); - - b.HasIndex("UserId"); - - b.ToTable("UserActivities"); - }); - - modelBuilder.Entity("Yavsc.Server.Models.Calendar.Period", b => - { - b.Property("Start") - .HasColumnType("timestamp with time zone"); - - b.Property("End") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Start", "End"); - - b.ToTable("Period"); - }); - - modelBuilder.Entity("Yavsc.Server.Models.EMailing.MailingTemplate", b => - { - b.Property("Id") - .HasColumnType("text"); - - b.Property("Body") - .HasMaxLength(65536) - .HasColumnType("character varying(65536)"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("ReplyToAddress") - .HasColumnType("text"); - - b.Property("ToSend") - .HasColumnType("integer"); - - b.Property("Topic") - .HasColumnType("text"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("MailingTemplate"); - }); - - modelBuilder.Entity("Yavsc.Server.Models.IT.Project", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("ActivityCode") - .IsRequired() - .HasColumnType("text"); - - b.Property("ClientId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Consent") - .HasColumnType("boolean"); - - b.Property("DateCreated") - .HasColumnType("timestamp with time zone"); - - b.Property("DateModified") - .HasColumnType("timestamp with time zone"); - - b.Property("Description") - .HasColumnType("text"); - - b.Property("GitId") - .HasColumnType("bigint"); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.Property("OwnerId") - .HasColumnType("text"); - - b.Property("PaymentId") - .HasColumnType("text"); - - b.Property("PerformerId") - .IsRequired() - .HasColumnType("text"); - - b.Property("Provisional") - .HasColumnType("numeric"); - - b.Property("Status") - .HasColumnType("integer"); - - b.Property("UserCreated") - .HasColumnType("text"); - - b.Property("UserModified") - .HasColumnType("text"); - - b.Property("ValidationDate") - .HasColumnType("timestamp with time zone"); - - b.Property("Version") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("ActivityCode"); - - b.HasIndex("ClientId"); - - b.HasIndex("GitId"); - - b.HasIndex("PaymentId"); - - b.HasIndex("PerformerId"); - - b.ToTable("Project"); - }); - - modelBuilder.Entity("Yavsc.Server.Models.IT.ProjectBuildConfiguration", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Name") - .IsRequired() - .HasColumnType("text"); - - b.Property("ProjectId") - .HasColumnType("bigint"); - - b.HasKey("Id"); - - b.HasIndex("ProjectId"); - - b.ToTable("ProjectBuildConfiguration"); - }); - - modelBuilder.Entity("Yavsc.Server.Models.IT.SourceCode.GitRepositoryReference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("bigint"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Branch") - .HasColumnType("text"); - - b.Property("OwnerId") - .HasColumnType("text"); - - b.Property("Path") - .IsRequired() - .HasColumnType("text"); - - b.Property("Url") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("OwnerId"); - - b.ToTable("GitRepositoryReference"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiResourceClaim", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiResource", null) - .WithMany("UserClaims") - .HasForeignKey("ApiResourceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiResource", "ApiResource") - .WithMany() - .HasForeignKey("ApiResourceId1"); - - b.Navigation("ApiResource"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiResourceProperty", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiResource", null) - .WithMany("Properties") - .HasForeignKey("ApiResourceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiResource", "ApiResource") - .WithMany() - .HasForeignKey("ApiResourceId1"); - - b.Navigation("ApiResource"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiResourceScope", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiResource", null) - .WithMany("Scopes") - .HasForeignKey("ApiResourceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiResource", "ApiResource") - .WithMany() - .HasForeignKey("ApiResourceId1"); - - b.Navigation("ApiResource"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiResourceSecret", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiResource", null) - .WithMany("Secrets") - .HasForeignKey("ApiResourceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiResource", "ApiResource") - .WithMany() - .HasForeignKey("ApiResourceId1"); - - b.Navigation("ApiResource"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiScopeClaim", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiScope", null) - .WithMany("UserClaims") - .HasForeignKey("ScopeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiScope", "Scope") - .WithMany() - .HasForeignKey("ScopeId1"); - - b.Navigation("Scope"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiScopeProperty", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiScope", null) - .WithMany("Properties") - .HasForeignKey("ScopeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("IdentityServer8.EntityFramework.Entities.ApiScope", "Scope") - .WithMany() - .HasForeignKey("ScopeId1"); - - b.Navigation("Scope"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientClaim", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") - .WithMany("Claims") - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Client"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientCorsOrigin", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", null) - .WithMany("AllowedCorsOrigins") - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") - .WithMany() - .HasForeignKey("ClientId1"); - - b.Navigation("Client"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientGrantType", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") - .WithMany("AllowedGrantTypes") - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Client"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientIdPRestriction", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", null) - .WithMany("IdentityProviderRestrictions") - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") - .WithMany() - .HasForeignKey("ClientId1"); - - b.Navigation("Client"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientPostLogoutRedirectUri", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", null) - .WithMany("PostLogoutRedirectUris") - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") - .WithMany() - .HasForeignKey("ClientId1"); - - b.Navigation("Client"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientProperty", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", null) - .WithMany("Properties") - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") - .WithMany() - .HasForeignKey("ClientId1"); - - b.Navigation("Client"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientRedirectUri", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") - .WithMany("RedirectUris") - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Client"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientScope", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") - .WithMany("AllowedScopes") - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Client"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientSecret", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", null) - .WithMany("ClientSecrets") - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") - .WithMany() - .HasForeignKey("ClientId1"); - - b.Navigation("Client"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.IdentityResourceClaim", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.IdentityResource", "IdentityResource") - .WithMany("UserClaims") - .HasForeignKey("IdentityResourceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("IdentityResource"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.IdentityResourceProperty", b => - { - b.HasOne("IdentityServer8.EntityFramework.Entities.IdentityResource", "IdentityResource") - .WithMany("Properties") - .HasForeignKey("IdentityResourceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("IdentityResource"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Yavsc.Models.Access.Ban", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "TargetUser") - .WithMany() - .HasForeignKey("TargetId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("TargetUser"); - }); - - modelBuilder.Entity("Yavsc.Models.Access.BlackListed", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Owner") - .WithMany("BlackList") - .HasForeignKey("OwnerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Owner"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Yavsc.Models.Access.CircleAuthorizationToBlogPost", b => - { - b.HasOne("Yavsc.Models.Blog.BlogPost", "Target") - .WithMany("ACL") - .HasForeignKey("BlogPostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Relationship.Circle", "Allowed") - .WithMany() - .HasForeignKey("CircleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Allowed"); - - b.Navigation("Target"); - }); - - modelBuilder.Entity("Yavsc.Models.AccountBalance", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Owner") - .WithOne("AccountBalance") - .HasForeignKey("Yavsc.Models.AccountBalance", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Owner"); - }); - - modelBuilder.Entity("Yavsc.Models.ApplicationUser", b => - { - b.HasOne("Yavsc.Models.Relationship.Location", "PostalAddress") - .WithMany() - .HasForeignKey("PostalAddressId"); - - b.Navigation("PostalAddress"); - }); - - modelBuilder.Entity("Yavsc.Models.BalanceImpact", b => - { - b.HasOne("Yavsc.Models.AccountBalance", "Balance") - .WithMany() - .HasForeignKey("BalanceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Balance"); - }); - - modelBuilder.Entity("Yavsc.Models.Bank.BankIdentity", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "User") - .WithMany("BankInfo") - .HasForeignKey("UserId"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Yavsc.Models.Billing.CommandLine", b => - { - b.HasOne("Yavsc.Models.Billing.Estimate", null) - .WithMany("Bill") - .HasForeignKey("EstimateId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Billing.EstimateTemplate", null) - .WithMany("Bill") - .HasForeignKey("EstimateTemplateId"); - }); - - modelBuilder.Entity("Yavsc.Models.Billing.Estimate", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Client") - .WithMany() - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Workflow.RdvQuery", "Query") - .WithMany() - .HasForeignKey("CommandId"); - - b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "Owner") - .WithMany() - .HasForeignKey("OwnerId"); - - b.Navigation("Client"); - - b.Navigation("Owner"); - - b.Navigation("Query"); - }); - - modelBuilder.Entity("Yavsc.Models.Billing.Signature", b => - { - b.HasOne("Yavsc.Models.Billing.Estimate", "Estimate") - .WithMany("Signatures") - .HasForeignKey("EstimateId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", "Signer") - .WithMany() - .HasForeignKey("SignerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Estimate"); - - b.Navigation("Signer"); - }); - - modelBuilder.Entity("Yavsc.Models.Blog.BlogAttachedFile", b => - { - b.HasOne("Yavsc.Models.Blog.UploadedFile", "File") - .WithMany() - .HasForeignKey("FileId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Blog.BlogPost", "Post") - .WithMany() - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("File"); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("Yavsc.Models.Blog.BlogPost", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Author") - .WithMany("Posts") - .HasForeignKey("AuthorId") - .OnDelete(DeleteBehavior.Restrict); - - b.Navigation("Author"); - }); - - modelBuilder.Entity("Yavsc.Models.Blog.BlogTag", b => - { - b.HasOne("Yavsc.Models.Blog.BlogPost", "Post") - .WithMany("Tags") - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Relationship.Tag", "Tag") - .WithMany() - .HasForeignKey("TagId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Post"); - - b.Navigation("Tag"); - }); - - modelBuilder.Entity("Yavsc.Models.Blog.Comment", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Author") - .WithMany("BlogComments") - .HasForeignKey("AuthorId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("Yavsc.Models.Blog.Comment", "Parent") - .WithMany("Children") - .HasForeignKey("ParentId"); - - b.HasOne("Yavsc.Models.Blog.BlogPost", "Post") - .WithMany("Comments") - .HasForeignKey("ReceiverId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Author"); - - b.Navigation("Parent"); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("Yavsc.Models.BlogSpotPublication", b => - { - b.HasOne("Yavsc.Models.Blog.BlogPost", "BlogPost") - .WithMany() - .HasForeignKey("BlogpostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("BlogPost"); - }); - - modelBuilder.Entity("Yavsc.Models.Calendar.Schedule", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Owner") - .WithMany() - .HasForeignKey("OwnerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Owner"); - }); - - modelBuilder.Entity("Yavsc.Models.Calendar.ScheduledEvent", b => - { - b.HasOne("Yavsc.Models.Calendar.Schedule", null) - .WithMany("Events") - .HasForeignKey("ScheduleOwnerId"); - - b.HasOne("Yavsc.Server.Models.Calendar.Period", "Period") - .WithMany() - .HasForeignKey("PeriodStart", "PeriodEnd"); - - b.Navigation("Period"); - }); - - modelBuilder.Entity("Yavsc.Models.Chat.ChatConnection", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Owner") - .WithMany("Connections") - .HasForeignKey("ApplicationUserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Owner"); - }); - - modelBuilder.Entity("Yavsc.Models.Chat.ChatRoom", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Owner") - .WithMany("Rooms") - .HasForeignKey("OwnerId"); - - b.Navigation("Owner"); - }); - - modelBuilder.Entity("Yavsc.Models.Chat.ChatRoomAccess", b => - { - b.HasOne("Yavsc.Models.Chat.ChatRoom", "Room") - .WithMany("Moderation") - .HasForeignKey("ChannelName") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", "User") - .WithMany("RoomAccess") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Room"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.BrusherProfile", b => - { - b.HasOne("Yavsc.Models.Calendar.Schedule", "Schedule") - .WithMany() - .HasForeignKey("ScheduleOwnerId"); - - b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "BaseProfile") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("BaseProfile"); - - b.Navigation("Schedule"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairCutQuery", b => - { - b.HasOne("Yavsc.Models.Workflow.Activity", "Context") - .WithMany() - .HasForeignKey("ActivityCode") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", "Client") - .WithMany() - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Relationship.Location", "Location") - .WithMany() - .HasForeignKey("LocationId"); - - b.HasOne("Yavsc.Models.Payment.PayPalPayment", "Regularization") - .WithMany() - .HasForeignKey("PaymentId"); - - b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "PerformerProfile") - .WithMany() - .HasForeignKey("PerformerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Haircut.HairPrestation", "Prestation") - .WithMany() - .HasForeignKey("PrestationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Haircut.BrusherProfile", "SelectedProfile") - .WithMany() - .HasForeignKey("SelectedProfileUserId"); - - b.Navigation("Client"); - - b.Navigation("Context"); - - b.Navigation("Location"); - - b.Navigation("PerformerProfile"); - - b.Navigation("Prestation"); - - b.Navigation("Regularization"); - - b.Navigation("SelectedProfile"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairMultiCutQuery", b => - { - b.HasOne("Yavsc.Models.Workflow.Activity", "Context") - .WithMany() - .HasForeignKey("ActivityCode") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", "Client") - .WithMany() - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Relationship.Location", "Location") - .WithMany() - .HasForeignKey("LocationId"); - - b.HasOne("Yavsc.Models.Payment.PayPalPayment", "Regularization") - .WithMany() - .HasForeignKey("PaymentId"); - - b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "PerformerProfile") - .WithMany() - .HasForeignKey("PerformerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Client"); - - b.Navigation("Context"); - - b.Navigation("Location"); - - b.Navigation("PerformerProfile"); - - b.Navigation("Regularization"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairPrestationCollectionItem", b => - { - b.HasOne("Yavsc.Models.Haircut.HairPrestation", "Prestation") - .WithMany() - .HasForeignKey("PrestationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Haircut.HairMultiCutQuery", "Query") - .WithMany("Prestations") - .HasForeignKey("QueryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Prestation"); - - b.Navigation("Query"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairTaint", b => - { - b.HasOne("Yavsc.Models.Drawing.Color", "Color") - .WithMany() - .HasForeignKey("ColorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Color"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairTaintInstance", b => - { - b.HasOne("Yavsc.Models.Haircut.HairPrestation", "Prestation") - .WithMany("Taints") - .HasForeignKey("PrestationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Haircut.HairTaint", "Taint") - .WithMany() - .HasForeignKey("TaintId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Prestation"); - - b.Navigation("Taint"); - }); - - modelBuilder.Entity("Yavsc.Models.IT.Fixing.Bug", b => - { - b.HasOne("Yavsc.Models.IT.Evolution.Feature", "False") - .WithMany() - .HasForeignKey("FeatureId"); - - b.Navigation("False"); - }); - - modelBuilder.Entity("Yavsc.Models.Identity.DeviceDeclaration", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "DeviceOwner") - .WithMany("DeviceDeclaration") - .HasForeignKey("DeviceOwnerId"); - - b.Navigation("DeviceOwner"); - }); - - modelBuilder.Entity("Yavsc.Models.Kyc.DeclarationFlag", b => - { - b.HasOne("Yavsc.Models.Kyc.TrustDeclaration", "Declaration") - .WithMany("Flags") - .HasForeignKey("DeclarationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Kyc.RegexAlertPattern", "Pattern") - .WithMany() - .HasForeignKey("PatternId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Declaration"); - - b.Navigation("Pattern"); - }); - - modelBuilder.Entity("Yavsc.Models.Kyc.ModerationLog", b => - { - b.HasOne("Yavsc.Models.Kyc.TrustDeclaration", "Declaration") - .WithMany() - .HasForeignKey("DeclarationId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Declaration"); - }); - - modelBuilder.Entity("Yavsc.Models.Kyc.TrustDeclaration", b => - { - b.HasOne("Yavsc.Models.Kyc.TrustToken", "Subject") - .WithMany("Declarations") - .HasForeignKey("TrustTokenId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.Navigation("Subject"); - }); - - modelBuilder.Entity("Yavsc.Models.Market.Service", b => - { - b.HasOne("Yavsc.Models.Workflow.Activity", "Context") - .WithMany("Services") - .HasForeignKey("ContextId"); - - b.Navigation("Context"); - }); - - modelBuilder.Entity("Yavsc.Models.Messaging.Announce", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Owner") - .WithMany() - .HasForeignKey("OwnerId"); - - b.Navigation("Owner"); - }); - - modelBuilder.Entity("Yavsc.Models.Messaging.DismissClicked", b => - { - b.HasOne("Yavsc.Abstract.Models.Messaging.Notification", "Notified") - .WithMany() - .HasForeignKey("NotificationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Notified"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.InstrumentRating", b => - { - b.HasOne("Yavsc.Models.Musical.Instrument", "Instrument") - .WithMany() - .HasForeignKey("InstrumentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "Profile") - .WithMany() - .HasForeignKey("OwnerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Instrument"); - - b.Navigation("Profile"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.MusicalPreference", b => - { - b.HasOne("Yavsc.Models.Musical.Profiles.DjSettings", null) - .WithMany("SoundColor") - .HasForeignKey("DjSettingsUserId"); - - b.HasOne("Yavsc.Models.Musical.Profiles.MusicLoverSettings", null) - .WithMany("SoundColor") - .HasForeignKey("MusicLoverSettingsUserId"); - - b.HasOne("Yavsc.Models.Musical.MusicalTendency", "MusicalTendency") - .WithMany() - .HasForeignKey("TendencyId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("MusicalTendency"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.Profiles.Instrumentation", b => - { - b.HasOne("Yavsc.Models.Musical.Instrument", "Tool") - .WithMany() - .HasForeignKey("InstrumentId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "User") - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Tool"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Yavsc.Models.Payment.PayPalPayment", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Executor") - .WithMany() - .HasForeignKey("ExecutorId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Executor"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.Circle", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", null) - .WithMany("Circles") - .HasForeignKey("ApplicationUserId"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.CircleMember", b => - { - b.HasOne("Yavsc.Models.Relationship.Circle", "Circle") - .WithMany("Members") - .HasForeignKey("CircleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", "Member") - .WithMany("Membership") - .HasForeignKey("MemberId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Circle"); - - b.Navigation("Member"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.Contact", b => - { - b.HasOne("Yavsc.Models.Relationship.PostalAddress", "PostalAddress") - .WithMany() - .HasForeignKey("AddressId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", null) - .WithMany("Book") - .HasForeignKey("ApplicationUserId"); - - b.Navigation("PostalAddress"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.HyperLink", b => - { - b.HasOne("Yavsc.Models.Haircut.BrusherProfile", null) - .WithMany("Links") - .HasForeignKey("BrusherProfileUserId"); - - b.HasOne("Yavsc.Models.Payment.PayPalPayment", null) - .WithMany("Links") - .HasForeignKey("PayPalPaymentCreationToken"); - }); - - modelBuilder.Entity("Yavsc.Models.Streaming.LiveFlow", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Owner") - .WithMany() - .HasForeignKey("OwnerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Owner"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.Activity", b => - { - b.HasOne("Yavsc.Models.Workflow.Activity", "Parent") - .WithMany("Children") - .HasForeignKey("ParentCode"); - - b.Navigation("Parent"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.CoWorking", b => - { - b.HasOne("Yavsc.Models.Workflow.Profiles.FormationSettings", null) - .WithMany("CoWorking") - .HasForeignKey("FormationSettingsUserId"); - - b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "Performer") - .WithMany() - .HasForeignKey("PerformerId"); - - b.HasOne("Yavsc.Models.ApplicationUser", "WorkingFor") - .WithMany() - .HasForeignKey("WorkingForId"); - - b.Navigation("Performer"); - - b.Navigation("WorkingFor"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.CommandForm", b => - { - b.HasOne("Yavsc.Models.Workflow.Activity", "Context") - .WithMany("Forms") - .HasForeignKey("ActivityCode") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Context"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.PerformerProfile", b => - { - b.HasOne("Yavsc.Models.Relationship.Location", "OrganizationAddress") - .WithMany() - .HasForeignKey("OrganizationAddressId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", "Performer") - .WithMany() - .HasForeignKey("PerformerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("OrganizationAddress"); - - b.Navigation("Performer"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.RdvQuery", b => - { - b.HasOne("Yavsc.Models.Workflow.Activity", "Context") - .WithMany() - .HasForeignKey("ActivityCode") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", "Client") - .WithMany() - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Relationship.Location", "Location") - .WithMany() - .HasForeignKey("LocationId"); - - b.HasOne("Yavsc.Models.Payment.PayPalPayment", "Regularization") - .WithMany() - .HasForeignKey("PaymentId"); - - b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "PerformerProfile") - .WithMany() - .HasForeignKey("PerformerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Client"); - - b.Navigation("Context"); - - b.Navigation("Location"); - - b.Navigation("PerformerProfile"); - - b.Navigation("Regularization"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.UserActivity", b => - { - b.HasOne("Yavsc.Models.Workflow.Activity", "Does") - .WithMany() - .HasForeignKey("DoesCode") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "User") - .WithMany("Activity") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Does"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("Yavsc.Server.Models.IT.Project", b => - { - b.HasOne("Yavsc.Models.Workflow.Activity", "Context") - .WithMany() - .HasForeignKey("ActivityCode") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.ApplicationUser", "Client") - .WithMany() - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Server.Models.IT.SourceCode.GitRepositoryReference", "Repository") - .WithMany() - .HasForeignKey("GitId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Yavsc.Models.Payment.PayPalPayment", "Regularization") - .WithMany() - .HasForeignKey("PaymentId"); - - b.HasOne("Yavsc.Models.Workflow.PerformerProfile", "PerformerProfile") - .WithMany() - .HasForeignKey("PerformerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Client"); - - b.Navigation("Context"); - - b.Navigation("PerformerProfile"); - - b.Navigation("Regularization"); - - b.Navigation("Repository"); - }); - - modelBuilder.Entity("Yavsc.Server.Models.IT.ProjectBuildConfiguration", b => - { - b.HasOne("Yavsc.Server.Models.IT.Project", "TargetProject") - .WithMany("Configurations") - .HasForeignKey("ProjectId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("TargetProject"); - }); - - modelBuilder.Entity("Yavsc.Server.Models.IT.SourceCode.GitRepositoryReference", b => - { - b.HasOne("Yavsc.Models.ApplicationUser", "Owner") - .WithMany() - .HasForeignKey("OwnerId"); - - b.Navigation("Owner"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiResource", b => - { - b.Navigation("Properties"); - - b.Navigation("Scopes"); - - b.Navigation("Secrets"); - - b.Navigation("UserClaims"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ApiScope", b => - { - b.Navigation("Properties"); - - b.Navigation("UserClaims"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.Client", b => - { - b.Navigation("AllowedCorsOrigins"); - - b.Navigation("AllowedGrantTypes"); - - b.Navigation("AllowedScopes"); - - b.Navigation("Claims"); - - b.Navigation("ClientSecrets"); - - b.Navigation("IdentityProviderRestrictions"); - - b.Navigation("PostLogoutRedirectUris"); - - b.Navigation("Properties"); - - b.Navigation("RedirectUris"); - }); - - modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.IdentityResource", b => - { - b.Navigation("Properties"); - - b.Navigation("UserClaims"); - }); - - modelBuilder.Entity("Yavsc.Models.ApplicationUser", b => - { - b.Navigation("AccountBalance"); - - b.Navigation("BankInfo"); - - b.Navigation("BlackList"); - - b.Navigation("BlogComments"); - - b.Navigation("Book"); - - b.Navigation("Circles"); - - b.Navigation("Connections"); - - b.Navigation("DeviceDeclaration"); - - b.Navigation("Membership"); - - b.Navigation("Posts"); - - b.Navigation("RoomAccess"); - - b.Navigation("Rooms"); - }); - - modelBuilder.Entity("Yavsc.Models.Billing.Estimate", b => - { - b.Navigation("Bill"); - - b.Navigation("Signatures"); - }); - - modelBuilder.Entity("Yavsc.Models.Billing.EstimateTemplate", b => - { - b.Navigation("Bill"); - }); - - modelBuilder.Entity("Yavsc.Models.Blog.BlogPost", b => - { - b.Navigation("ACL"); - - b.Navigation("Comments"); - - b.Navigation("Tags"); - }); - - modelBuilder.Entity("Yavsc.Models.Blog.Comment", b => - { - b.Navigation("Children"); - }); - - modelBuilder.Entity("Yavsc.Models.Calendar.Schedule", b => - { - b.Navigation("Events"); - }); - - modelBuilder.Entity("Yavsc.Models.Chat.ChatRoom", b => - { - b.Navigation("Moderation"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.BrusherProfile", b => - { - b.Navigation("Links"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairMultiCutQuery", b => - { - b.Navigation("Prestations"); - }); - - modelBuilder.Entity("Yavsc.Models.Haircut.HairPrestation", b => - { - b.Navigation("Taints"); - }); - - modelBuilder.Entity("Yavsc.Models.Kyc.TrustDeclaration", b => - { - b.Navigation("Flags"); - }); - - modelBuilder.Entity("Yavsc.Models.Kyc.TrustToken", b => - { - b.Navigation("Declarations"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.Profiles.DjSettings", b => - { - b.Navigation("SoundColor"); - }); - - modelBuilder.Entity("Yavsc.Models.Musical.Profiles.MusicLoverSettings", b => - { - b.Navigation("SoundColor"); - }); - - modelBuilder.Entity("Yavsc.Models.Payment.PayPalPayment", b => - { - b.Navigation("Links"); - }); - - modelBuilder.Entity("Yavsc.Models.Relationship.Circle", b => - { - b.Navigation("Members"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.Activity", b => - { - b.Navigation("Children"); - - b.Navigation("Forms"); - - b.Navigation("Services"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.PerformerProfile", b => - { - b.Navigation("Activity"); - }); - - modelBuilder.Entity("Yavsc.Models.Workflow.Profiles.FormationSettings", b => - { - b.Navigation("CoWorking"); - }); - - modelBuilder.Entity("Yavsc.Server.Models.IT.Project", b => - { - b.Navigation("Configurations"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Yavsc.Org/Migrations/20260820232152_DropCommentFromCircleAuthorizationToBlogPost.cs b/src/Yavsc.Org/Migrations/20260820232152_DropCommentFromCircleAuthorizationToBlogPost.cs deleted file mode 100644 index f853889b..00000000 --- a/src/Yavsc.Org/Migrations/20260820232152_DropCommentFromCircleAuthorizationToBlogPost.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace Yavsc.Migrations -{ - /// - public partial class DropCommentFromCircleAuthorizationToBlogPost : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "Comment", - table: "CircleAuthorizationToBlogPost"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "Comment", - table: "CircleAuthorizationToBlogPost", - type: "boolean", - nullable: false, - defaultValue: false); - } - } -} diff --git a/src/Yavsc.Org/Migrations/ApplicationDbContextModelSnapshot.cs b/src/Yavsc.Org/Migrations/ApplicationDbContextModelSnapshot.cs index a0295ef6..ef96638c 100644 --- a/src/Yavsc.Org/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/src/Yavsc.Org/Migrations/ApplicationDbContextModelSnapshot.cs @@ -476,6 +476,9 @@ namespace Yavsc.Migrations b.Property("ClientId") .HasColumnType("integer"); + b.Property("ClientId1") + .HasColumnType("integer"); + b.Property("GrantType") .HasColumnType("text"); @@ -483,6 +486,8 @@ namespace Yavsc.Migrations b.HasIndex("ClientId"); + b.HasIndex("ClientId1"); + b.ToTable("ClientGrantTypes"); }); @@ -578,6 +583,9 @@ namespace Yavsc.Migrations b.Property("ClientId") .HasColumnType("integer"); + b.Property("ClientId1") + .HasColumnType("integer"); + b.Property("RedirectUri") .HasColumnType("text"); @@ -585,6 +593,8 @@ namespace Yavsc.Migrations b.HasIndex("ClientId"); + b.HasIndex("ClientId1"); + b.ToTable("ClientRedirectUris"); }); @@ -599,6 +609,9 @@ namespace Yavsc.Migrations b.Property("ClientId") .HasColumnType("integer"); + b.Property("ClientId1") + .HasColumnType("integer"); + b.Property("Scope") .HasColumnType("text"); @@ -606,6 +619,8 @@ namespace Yavsc.Migrations b.HasIndex("ClientId"); + b.HasIndex("ClientId1"); + b.ToTable("ClientScopes"); }); @@ -1081,6 +1096,9 @@ namespace Yavsc.Migrations b.Property("BlogPostId") .HasColumnType("bigint"); + b.Property("Comment") + .HasColumnType("boolean"); + b.HasKey("CircleId", "BlogPostId"); b.HasIndex("BlogPostId"); @@ -3442,12 +3460,16 @@ namespace Yavsc.Migrations modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientGrantType", b => { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") + b.HasOne("IdentityServer8.EntityFramework.Entities.Client", null) .WithMany("AllowedGrantTypes") .HasForeignKey("ClientId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") + .WithMany() + .HasForeignKey("ClientId1"); + b.Navigation("Client"); }); @@ -3498,23 +3520,31 @@ namespace Yavsc.Migrations modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientRedirectUri", b => { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") + b.HasOne("IdentityServer8.EntityFramework.Entities.Client", null) .WithMany("RedirectUris") .HasForeignKey("ClientId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") + .WithMany() + .HasForeignKey("ClientId1"); + b.Navigation("Client"); }); modelBuilder.Entity("IdentityServer8.EntityFramework.Entities.ClientScope", b => { - b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") + b.HasOne("IdentityServer8.EntityFramework.Entities.Client", null) .WithMany("AllowedScopes") .HasForeignKey("ClientId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.HasOne("IdentityServer8.EntityFramework.Entities.Client", "Client") + .WithMany() + .HasForeignKey("ClientId1"); + b.Navigation("Client"); }); diff --git a/src/Yavsc.Org/ViewModels/Manage/SetUserNameViewModel.cs b/src/Yavsc.Org/ViewModels/Manage/SetUserNameViewModel.cs index 61cf0727..69507b92 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(Constants.UserNameRegExp)] + [Display(Name = "User name"),RegularExpression(YavscConstants.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 dd6b0ff8..f0a961c9 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 7bfa2a3f..431fe61e 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(Constants.AdminGroupName)) { + @if (User.IsInMsRole(YavscConstants.AdminGroupName)) {