Commit graph

3,228 commits

Author SHA1 Message Date
22d8974aab publish android 2026-08-03 02:35:50 +01:00
42ae86f050 Merge pull request 'build' (#12) from build into main
Reviewed-on: #12
2026-08-03 02:17:32 +01:00
17e33ebea9 build 2026-08-03 02:16:57 +01:00
c3388e3e2a Enable blogs on connected status 2026-08-03 01:48:15 +01:00
ec0085b7e3 refacto blogPost 2026-08-03 01:36:12 +01:00
d9d5aed385 Merge pull request 'ci: publish APK to GitHub release on v* tag' (#11) from release into main
Reviewed-on: #11
2026-08-02 23:29:21 +01:00
c6366bbda4 ci: publish APK to GitHub release on v* tag
Adds a publish-release job that triggers only on tag pushes (refs/tags/v*).
It reuses the APK artifact uploaded by apk-deploy, publishes a GitHub
release via softprops/action-gh-release, and attaches the APK.

Result: a stable permalink to the latest APK at
  https://github.com/<owner>/<repo>/releases/latest/download/PostIt.Android.apk
2026-08-02 23:23:00 +01:00
367afb005b Merge pull request 'Le créateur vient de l'authentification, donc on ne le prend pas du post' (#10) from fix/OIDC-debugging into main
Reviewed-on: #10
2026-08-02 23:04:09 +01:00
ce075b3aee Le créateur vient de l'authentification, donc on ne le prend pas du post 2026-08-02 23:02:54 +01:00
337884d831 Merge pull request 'postit: allow self-signed OIDC TLS in Development' (#9) from fix/OIDC-debugging into main
Reviewed-on: #9
2026-08-02 21:32:49 +01:00
e92be558de Navigate to Main Page 2026-08-02 21:08:25 +01:00
d8ee77b9de refacto error handling 2026-07-12 17:56:23 +01:00
96d175f13d Hsts 2026-07-12 16:27:13 +01:00
49292b1fa0 Hsts 2026-07-12 16:26:43 +01:00
e539acd599 Post logout redirect uri 2026-07-12 16:14:37 +01:00
3b3635758b org: show full error details in development 2026-07-12 16:07:28 +01:00
4723d1b1b8 postit: allow self-signed OIDC TLS in Development 2026-07-12 15:51:55 +01:00
d70069cf01 Merge pull request 'fix/auth-redirect-message' (#8) from fix/auth-redirect-message into main
Reviewed-on: #8
2026-07-12 15:22:20 +01:00
afcb6167e6 Localisation 1.0.2 2026-07-12 15:18:07 +01:00
fd773529ff Audiences 2026-07-12 15:17:53 +01:00
0957efb876 code format 2026-07-12 15:17:41 +01:00
33f8f2b74e auth: fix JWT default scheme and multi-audience validation 2026-07-12 14:53:17 +01:00
0bb3cf5add Merge pull request 'fic/jwt-validation' (#7) from fic/jwt-validation into main
Reviewed-on: #7
2026-07-12 06:46:05 +01:00
c295d1d463 blogs: use centralized JWT audience handling 2026-07-12 06:45:00 +01:00
1730e10207 tests: log warning when OIDC token fallback is used 2026-07-12 06:43:07 +01:00
41dadc7909 Merge remote-tracking branch 'origin/main' into fic/jwt-validation 2026-07-12 06:12:19 +01:00
99f29f926a WIP audiences 2026-07-12 06:10:24 +01:00
7e5efdc4fd Merge pull request 'fix/testing' (#6) from fix/testing into main
Reviewed-on: #6
2026-07-12 06:03:39 +01:00
4f958f4502 use an available port for authority 2026-07-12 06:01:42 +01:00
3a02eb253a tests: configure static fixture ports and update org test config 2026-07-12 05:48:47 +01:00
c129a1f9e3 ? 2026-07-12 04:36:35 +01:00
d7c8ef242b Revert "Test host: bind Kestrel to Site:Authority instead of dynamic port"
This reverts commit d58fad552a.
2026-07-12 03:48:49 +01:00
b2706466c6 using clauses cleanup 2026-07-12 03:48:30 +01:00
d58fad552a Test host: bind Kestrel to Site:Authority instead of dynamic port
The Yavsc.Org integration tests were failing 'Internal Server Error' on
the OIDC discovery document when run as part of the full test suite.

Root cause: WebHostFixture bound Kestrel to IPAddress.Loopback on a
dynamically-allocated port and exposed it via IServerAddressesFeature.
But the OIDC issuer URLs (and the issuer claim) come from Site:Authority,
which was left at the production value (mercure.pschneider.fr). So
IdentityServer8's discovery document advertised URLs unreachable from
the test process, and the discovery call returned a 500.

Fix:
  - WebServerFixture now overrides Site:Authority and Site:ExternalUrl
    in AddInMemoryCollection to 'https://localhost:44300' (the ASP.NET
    Core dev HTTPS convention).
  - WebHostFixture reads Site:Authority from configuration and binds
    Kestrel to that fixed URL. The exposed Addresses list is sourced
    from the same configuration value instead of the
    IServerAddressesFeature, so the listen URL and the OIDC issuer
    URLs always match.

Remoting.cs (Mandatory/Remoting.cs): add 'using
Microsoft.Extensions.DependencyInjection;' so the existing OIDC/DB
diagnostic block (capture raw HTTP response + dump OIDC-related DB
state on discovery failure) compiles. The diagnostic itself is left
in place — it's what surfaced the 500 in the first place.
2026-07-12 03:43:22 +01:00
587fdd13c2 Merge pull request 'fix/issue-3-splitquery' (#5) from fix/issue-3-splitquery into main
Reviewed-on: #5
2026-07-12 02:47:15 +01:00
3febd63b06 WIP audiences 2026-07-12 02:42:13 +01:00
d80fd598f5 ApplicationDbContext: drop redundant HasOne on 3 Client navs
LoadClientAsync(id) on ClientController used to trip an
IndexOutOfRangeException at the InMemory shaper for any
.Include() of one of three Client navs: RedirectUris,
AllowedScopes, AllowedGrantTypes. Five other Client navs (with
the same EF shape and the same application-level config) worked
fine.

Bisection pointed at the InMemory provider; that hypothesis was
wrong. The real cause is in ApplicationDbContext.OnModelCreating:
yavsc was redeclaring the HasOne<Client>().WithMany(...).
HasForeignKey(e => e.ClientId) for all eight Client* navs. The
same relation is already declared (more completely, with
.IsRequired().OnDelete(DeleteBehavior.Cascade)) by
IdentityServer8's ConfigureClientStore via ModelBuilderExtensions.

The redundant mapping on three specific entities — ClientScope,
ClientRedirectUri, ClientGrantType — interacts with the InMemory
provider's shaper in a way that throws IndexOutOfRange. Removing
the redundancy fixes it.

This commit also walks back e940a241:
- Drops .AsSplitQuery() from LoadClientAsync (no longer needed
  for the InMemory shaper, and the Postgres path it was a hedge
  against was a false alarm — there is no Postgres production
  bug here, only an InMemory shaper quirk surfaced by the
  redundant mapping).
- Removes the 9 Bisect_*_alone tests that were the artefact of
  the provider-hypothesis phase. They pointed at the right
  entities but for the wrong reason.
- Keeps EditRedirectUris_GET_after_add_lists_both_uris as the
  end-to-end regression sentinel: with the fix in place, it
  loads a Client with two RedirectUris and asserts both are
  rendered. Without the fix, it fails with IndexOutOfRange.
2026-07-12 02:39:13 +01:00
e940a241c9 ClientController: split LoadClientAsync into per-collection subqueries
LoadClientAsync chains 9 .Include() calls on dbContext.Clients.
On Postgres (and InMemory for some IdentityServer8 nav types), the
resulting cartesian product trips the query shaper with
IndexOutOfRangeException at IncludeCollection materialisation time.
Bug reproduces in production on the Blog admin pages that load a
Client by id.

AsSplitQuery() rewrites the load as 9 separate SELECTs joined by
client id, which sidesteps the cartesian explosion and any shaper
ambiguity between Claims/Properties/ClientSecrets (which share
Type/Value column names across some IdentityServer8 versions).

Tests:
- EditRedirectUris_GET_after_add_lists_both_uris: end-to-end
  reproducer that adds a second RedirectUri via POST then re-GETs
  the editor. Guards the fix on the integration path.
- Bisect_*_alone: nine unit tests that exercise the same
  .SingleOrDefaultAsync(c => c.Id == id).Include(nav) on the
  InMemory provider, one nav at a time. Pinpointed three
  problematic navs (RedirectUris, AllowedScopes, AllowedGrantTypes)
  on InMemory; kept as a regression net for any future shaper
  regressions on the InMemory provider (not the Postgres path).
2026-07-12 01:15:02 +01:00
c6714b4eeb Revert "repoduces the bug"
This reverts commit 93d625d270.
2026-07-11 22:17:58 +01:00
Lum
93d625d270 repoduces the bug 2026-07-11 21:56:25 +01:00
1d86a81fcb Tests: route Yavsc.Org test host through Testing environment
TestWebApplicationFactory used ASPNETCORE_ENVIRONMENT=Development, which
caused Program.Main's AddConfiguration("org") to load the tracked
appsettings-org.json (the reference file with the
'*** via dotnet user-secrets ou variable d'environnement ***'
placeholder connection string). Npgsql then failed to parse that
placeholder during host startup, failing six integration tests
(observed 2026-07-11: System.ArgumentException on
NpgsqlConnectionStringBuilder.set_Item).

Switching the test host to a dedicated Testing environment makes
AddConfiguration("org") pick up the new optional
appsettings-org.Testing.json file as the last source in the chain
(JSON → env vars), which overrides YavscConnection with the
InMemory marker and the Smtp section with the test stub values.

The .gitignore exception whitelists this file explicitly: it is a
configuration source for the test host, not a secrets file.

The WebServerFixture path is unchanged — it owns its
WebApplicationBuilder and adds the same in-memory override via its
BuildApp hook.
2026-07-11 20:50:39 +01:00
Lum
552e47c251 Blog: add test guarding the display-template fix + document test architecture
Le commit 2 a fixé la NPE du /BlogSpot/Details/{id} en passant
le display template par UserDisplayHelpers.AvatarSrc, qui
défend contre un UserName null. Ce commit complète le filet
de non-régression et pose la doc d'architecture des tests.

- ApplicationUserDisplayTemplateTests : assert que le cshtml ne
  concatène plus directement Model.UserName (ancien code fautif)
  et qu'il utilise bien le helper. Si quelqu'un revert la ligne
  4 du cshtml, les tests cassent. Les autres usages de
  Model.UserName (alt, title, asp-route-id) sont autorisés : ils
  ne sont pas la cause du 500, juste laids si null.
- doc/testing.md : vue d'ensemble de la stratégie de test
  (conventions NonRegression/Mandatory/Smoke/Controllers, EF
  in-memory via InMemoryDatabaseRoot partagé, auth stubs,
  quand ne pas écrire de test).
- src/Yavsc.Tests.Shared/README.md : détails du scaffold partagé
  (WebHostFixture + son cycle de vie et ses hooks,
  TestAuthPolicyProvider, TestTokenIssuer) et des deux
  spécialisations dans le repo
  (Yavsc.Org.Tests.WebServerFixture et
  Yavsc.Blogs.Tests.BlogsWebServerFixture).
- doc/README.md : entrée vers testing.md dans l'index.
2026-07-11 19:59:03 +01:00
Lum
4198e4dcf2 Blog: render user avatar through a null-safe helper
GET /BlogSpot/Details/1 retournait 500 (avec un 500-sur-500 sur
la page d'erreur elle-même) parce que DisplayTemplates
/ApplicationUser.cshtml faisait `var avuri = "/Avatars/" +
Model.UserName + ".s.png"` : avec <Nullable>enable</Nullable>,
Razor émet un null-check implicite sur Model.UserName et lève
NullReferenceException quand l'auteur n'a pas de UserName
posé (donnée héritée, user partiellement initialisé).

- UserDisplayHelpers.AvatarSrc : helper statique pur dans
  Yavsc.Abstract.Identity qui retourne
  YavscConstants.DefaultAvatar pour user null / UserName vide
  ou whitespace, et un path /avatars/<name>.s.png sinon.
- ApplicationUser.cshtml : utilise le helper.
- Tests : 4 cas (null, vide, whitespace, valide) dans
  Yavsc.Org.Tests/NonRegression.

Bonus : le path d'avatar passe de "/Avatars/" (S majuscule,
ne résolvait pas dans le middleware de fichiers statiques) à
YavscConstants.AvatarsPath ("/avatars" minuscule), pour fermer
l'autre trou que centraliser le calcul permettait de fixer
proprement.
2026-07-11 19:41:09 +01:00
Lum
51278dee31 Blog: enforce Restrict FK on BlogPost.Author and Comment.Author
Tout billet a un auteur, tout commentaire a un auteur. On aligne la
base sur ce contrat (Postgres) en droppant les orphelins existants
puis en remplaçant les FK en cascade par des FK Restrict.

- ApplicationDbContext: fluent pour BlogPost.Author et Comment.Author
  en DeleteBehavior.Restrict.
- ApplicationUser: ajoute la nav inverse BlogComments (manquait,
  EF aurait sinon créé une shadow FK).
- Migration 20260711173717_EnforceBlogAuthorFKs: Up purge les
  Comment/BlogSpot dont l'AuthorId n'existe plus, log le volume,
  puis drop+add des FK. Down laisse la cascade (état pré-migration).

Le code applicatif (BlogSpotService.Details) s'appuiera sur cette
contrainte dans un commit séparé.
2026-07-11 18:45:27 +01:00
6beff79e3e Merge commit 'f27f65c2d3' 2026-07-11 03:36:31 +01:00
f27f65c2d3 fixes the compile and timestamps to db 2026-07-11 03:26:13 +01:00
c8b98c7762 Merge pull request 'postIt' (#2) from postIt into main
Reviewed-on: #2
2026-07-11 02:57:28 +01:00
7f542b0777 Just post one, at least 1.0.1 2026-07-11 02:56:14 +01:00
8d61e73bfa 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
4aeba2ff42 Log the identity main params 2026-07-10 00:27:18 +01:00