Commit graph

6 commits

Author SHA1 Message Date
88461786ee
Roll back refacto on Posit.Tests 2026-08-21 16:18:20 +01:00
a44c04ad77
feat(postit): circles+ACL UI, blog fixture→SQLite, seed default user
Bundled end-of-branch commit on feat/postit-acl-members.

PostIt UI for circles + per-post ACL
- Reorganise PostIt.Tests into Auth/ and Blogs/ subfolders
  (Bearer/OIDC scope tests vs. blog API fakes live where they
  belong) and introduces PostItHeadlessCollection so the
  Avalonia.Headless tests share a single xUnit collection
  instead of contending with the EF-Core test host.
- Adds BlogAclApiTests (a brand-new behavioural layer over
  POST /api/v1/blogacl) and the fakes it relies on
  (BlogApiTestFakes, BlogPostAuthorDtoTests, AddCircleMember
  DialogTests); pulls UserId-through-OIDC-sub path into
  BearerScopeTests / FakeAuthorizingBrowser /
  OidcStubAuthority.
- App.axaml.cs gets a small PushPageAsync touch-up the new
  tests rely on.
- Drops UnitTest1.cs (xUnit scaffold, never used).

Yavsc.Blogs.Tests — SQLite instead of InMemory
- Bumps Yavsc.Blogs.Tests.csproj on
  Microsoft.EntityFrameworkCore.Sqlite and rewrites
  BlogsWebServerFixture to hold a single shared
  SqliteConnection (Cache=Shared) for the fixture lifetime,
  with a sync Dispose close to dodge async teardown hangs.
  Reason: the EF Core InMemory provider silently ignores FKs,
  which masked the kind of bug we are about to pin in the
  ACL tests. SQLite enforces them, so any future INSERT that
  forgets to seed its parent rows fails loudly here instead
  of passing the test and breaking prod.
- PublishEndpointTests and BlogApiSmokeTests get a one-line
  tweak to follow the new connection lifecycle.

Foreign-key fallout: seed the default user in the fixture
- Adds BlogsWebServerFixture.SeedUser(userName). Now that
  SQLite enforces BlogPost.AuthorId → AspNetUsers.Id, every
  test that POST/PUT/DELETE a BlogPost and sends AuthorId=
  'tester' in the payload needs an AspNetUsers row to satisfy
  the FK or it returns 500 with SQLite Error 19.
- BlogApiTests wraps the existing ResetDatabase with a
  ResetAndSeedDefaultUser helper for the six mutating tests;
  the four GET-only and ModelState-only tests keep the bare
  ResetDatabase.
- Side benefit: every test in Yavsc.Blogs.Tests now finishes
  cleanly instead of hanging at teardown — previously a stuck
  test held the shared SqliteConnection open and the next
  tests waited indefinitely.

Verified: dotnet test src/Yavsc.Blogs.Tests passes 25/25
green from a clean run, no fixture teardown hang.
2026-08-20 23:59:21 +01:00
1b289c1387
refactor(model): rename Yavsc.Blogspot.BlogPost to BlogPostDto
When commit 0e95e283 moved BlogPost from PostIt.Models to
Yavsc.Blogspot, it created an unfortunate collision with the
server-side EF entity Yavsc.Models.Blog.BlogPost. The two
classes have nothing in common beyond the name; the DTO is
the wire shape PostIt exchanges with the Blogs API, the EF
entity is the persistence model. Server code that imports both
namespaces (BlogSpotService.cs, etc.) ended up with 'BlogPost
is an ambiguous reference between X and Y' errors.

Renaming the client DTO to BlogPostDto (matching the
naming convention of the other DTOs in Yavsc.Api.Client.Dtos
— CircleDto, CircleAuthorizationDto, UserSearchResultDto)
disambiguates without renaming the EF entity on the server.

The namespace stays Yavsc.Blogspot; only the class name
changes. All call sites (client code, tests, XAML DataTemplates,
XML doc comments) are updated mechanically.
2026-08-18 00:20:01 +01:00
0e95e28327
refactor(model): move BlogPost DTO from PostIt.Models to Yavsc.Blogspot
BlogPost is shared between the server (Yavsc.Server/Models/Blog/
BlogPost.cs is the EF entity) and any client that talks to the
blogs API. Keeping the client-side DTO in PostIt.Models made
sense when there was only one consumer; now that the
Yavsc.Api.Client project is about to host BlogApiClient alongside
CircleApiClient and BlogAclApiClient, the DTO has to live in a
layer both the client project and PostIt can reference without
inverting the dependency.

Yavsc.Abstract is the existing home for cross-tier interfaces
and DTOs (IBlogPost, IBlogPostPayLoad, IApplicationUser).
Yavsc.Blogspot is the sub-namespace already used by the
matching interface, so the new concrete class follows.

Why not move Circle and CircleAuthorizationToBlogPost at the
same time? Both depend on the concrete ApplicationUser class
(via the Owner and Target/Allowed navigation properties) which
lives in Yavsc.Server. Moving them would mean either dragging
ApplicationUser into the abstract layer (huge blast radius —
auth, billing, chat, etc.) or weakening the navigation
properties (breaks EF Core shaping). They're staying where
they are; the new Yavsc.Api.Client will get DTO counterparts
instead.

Updated call sites:
- 4 .cs files: replace 'using PostIt.Models;' with
  'using Yavsc.Blogspot;' where the file was actually using
  BlogPost. Files that only used SignaturePadData keep their
  'using PostIt.Models;' — that type stays put.
- 1 .axaml file: xmlns:models="using:PostIt.Models" ->
  xmlns:models="using:Yavsc.Blogspot" (one DataTemplate for
  the post list in MainPage).

Build + tests green (51/51).
2026-08-17 23:45:45 +01:00
b25e0e842e
refacto blogPost
Some checks failed
Dotnet build and test / log-the-inputs (push) Has been cancelled
Dotnet build and test / build (push) Has been cancelled
2026-08-03 01:36:12 +01:00
03cd9843d3 PostIt/Yavsc.Blogs: surface 4xx body + pin controller + red UI test for Save
The 'Save' button in PostIt has been returning 400 from
/api/v1/blog ever since the editor's title and article fields
were re-bound to SelectedPost.Title / SelectedPost.Article.
The user types into the editor, taps Save, the controller
rejects with 'The Title field is required', and the PostIt
status bar shows only the generic 'Response status code does
not indicate success: 400' — no field name, no reason.

Three pieces here make the regression diagnosable and pin a
test for the fix:

1. YavscApiClient: replace EnsureSuccessStatusCode() at both
   call sites with a small helper that reads the response
   body and embeds it in the thrown HttpRequestException. The
   VM's existing catch (Exception) in ExecuteAsync forwards
   ex.Message to the status bar, so the next 'click Save'
   tells the user exactly which field the server rejected.

2. Yavsc.Blogs.Tests: two integration tests on the real
   controller (no HTTP mock) — one pins that a well-formed
   PostIt-shaped payload (Title + Article + AuthorId + dates,
   Id=0) is accepted with 201, the other pins that a payload
   with Title=string.Empty is rejected with 400. Together they
   pin the contract the VM has to honour.

3. PostIt.Tests: a red [AvaloniaFact] UI test that mounts
   MainPage inside a headless Window, types a title into the
   TextBox without first selecting a post in the list, taps
   Save, and asserts the body of the first POST contains
   the typed title. Today this test fails with Title='',
   reproducing the production 400. The matching fix (a
   Title/Article buffer on MainPageViewModel that the XAML
   binds to, and that Save uses to build the outgoing
   BlogPost) is the next commit; the test is the safety net.
2026-07-11 02:52:50 +01:00