Conversation
af567e7 to
c4c5f1f
Compare
shikanime
left a comment
There was a problem hiding this comment.
Verdict : Changements demandés
Migration fidèle sur le plan requêtes (where, take: 5, rejet de rôle inconnu, union before/after des rôles impactés — la sémantique legacy est respectée). Point positif : la logique where est copiée sans « amélioration » silencieuse, ce qui rend la parité vérifiable ligne à ligne. Un point bloquant de pont événements → plugins, détaillé inline.
| user.adminRoleIds?.forEach(roleId => impactedRoleIds.add(roleId)) | ||
| } | ||
| for (const roleId of impactedRoleIds) { | ||
| await this.eventEmitter.emitAsync('adminRole.upsert', { roleId }) |
There was a problem hiding this comment.
[🔴 Bloquant] emitAsync('adminRole.upsert') n'a aucun consommateur @OnEvent('adminRole.upsert') dans server-nestjs : à la bascule (apps/server sert encore la route aujourd'hui, donc rien de cassé en prod), la synchro Keycloak/GitLab des groupes admin est silencieusement perdue. Suggestion : ajouter le pont dans keycloak.service.ts / gitlab.service.ts sur le modèle de project.upsert → capturePluginResult, ou tracer un ticket de suivi bloquant la bascule.
There was a problem hiding this comment.
Vérifié : le consommateur existe désormais. La branche de base #2749 (pr/admin-role-event-bridge, tête 01467dc713) ajoute @OnEvent('adminRole.upsert') dans keycloak.service.ts:59 et gitlab.service.ts:87, tous deux via capturePluginResult, avec admin-role-bridge.spec.ts de part et d'autre : le pont demandé existe, plus de perte silencieuse à la bascule.
roleId: string (parité legacy hook.adminRole.upsert(roleId)), gitlab lit un objet AdminRoleEventPayload (app-events.service.ts:38) et admin-role.service.ts:45/124 de #2749 émet cet objet — donc le handler keycloak de #2749 ne matche déjà plus ses propres événements (roles.find(({ id }) => id === roleId)), et user.service.ts:64 qui émet { roleId } ne satisfait ni l'un ni l'autre.
Je laisse ce fil ouvert : la forme canonique doit être tranchée dans #2749 (base), puis #2738 s'alignera dessus. Hors périmètre de #2738 seul.
shikanime
left a comment
There was a problem hiding this comment.
And remove // -- comments
Aligne le module user sur le pattern établi par le module zone (#2487) : - `user-queries.utils.ts` : suppression du `userSelect`/`UserRecord` morts, signatures sur `Prisma.TransactionClient`, `createUser` purement DB (la validation du doublon email monte dans le service en `ConflictException`). - `user.service.ts` : extraction de `resolveAdminRoleIds`, `patchUsersInTx`, `emitImpactedRoleEvents` ; patch des rôles sous transaction. - `user.module.ts` : imports repliés sur `InfrastructureModule` (déjà exporté par celui-ci). Refs #2738 Co-authored-by: Automata <automata@shikanime.studio> Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr> Change-Id: I3bd632f95dd466e585698eba738efcd86a6a6964
Aligne le module user sur le pattern établi par le module zone (#2487) : - `user-queries.utils.ts` : suppression du `userSelect`/`UserRecord` morts, signatures sur `Prisma.TransactionClient`, `createUser` purement DB (la validation du doublon email monte dans le service en `ConflictException`). - `user.service.ts` : extraction de `resolveAdminRoleIds`, `patchUsersInTx`, `emitImpactedRoleEvents` ; patch des rôles sous transaction. - `user.module.ts` : imports repliés sur `InfrastructureModule` (déjà exporté par celui-ci). Refs #2738 Co-authored-by: Automata <automata@shikanime.studio> Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr> Change-Id: I3bd632f95dd466e585698eba738efcd86a6a6964
2f18b61 to
b9e3500
Compare
Aligne le module user sur le pattern établi par le module zone (#2487) : - `user-queries.utils.ts` : suppression du `userSelect`/`UserRecord` morts, signatures sur `Prisma.TransactionClient`, `createUser` purement DB (la validation du doublon email monte dans le service en `ConflictException`). - `user.service.ts` : extraction de `resolveAdminRoleIds`, `patchUsersInTx`, `emitImpactedRoleEvents` ; patch des rôles sous transaction. - `user.module.ts` : imports repliés sur `InfrastructureModule` (déjà exporté par celui-ci). Refs #2738 Co-authored-by: Automata <automata@shikanime.studio> Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr> Change-Id: I3bd632f95dd466e585698eba738efcd86a6a6964
b9e3500 to
ccba51a
Compare
Aligne le module user sur le pattern établi par le module zone (#2487) : - `user-queries.utils.ts` : suppression du `userSelect`/`UserRecord` morts, signatures sur `Prisma.TransactionClient`, `createUser` purement DB (la validation du doublon email monte dans le service en `ConflictException`). - `user.service.ts` : extraction de `resolveAdminRoleIds`, `patchUsersInTx`, `emitImpactedRoleEvents` ; patch des rôles sous transaction. - `user.module.ts` : imports repliés sur `InfrastructureModule` (déjà exporté par celui-ci). Refs #2738 Co-authored-by: Automata <automata@shikanime.studio> Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr> Change-Id: I3bd632f95dd466e585698eba738efcd86a6a6964
ccba51a to
cdb5dcb
Compare
Aligne le module user sur le pattern établi par le module zone (#2487) : - `user-queries.utils.ts` : suppression du `userSelect`/`UserRecord` morts, signatures sur `Prisma.TransactionClient`, `createUser` purement DB (la validation du doublon email monte dans le service en `ConflictException`). - `user.service.ts` : extraction de `resolveAdminRoleIds`, `patchUsersInTx`, `emitImpactedRoleEvents` ; patch des rôles sous transaction. - `user.module.ts` : imports repliés sur `InfrastructureModule` (déjà exporté par celui-ci). Refs #2738 Co-authored-by: Automata <automata@shikanime.studio> Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr> Change-Id: I3bd632f95dd466e585698eba738efcd86a6a6964
cdb5dcb to
2826688
Compare
|
🤖 Hey ! A preview of the application is available at : https://console-pr-2738.dso.cpin-hp.numerique-interieur.fr Please be patient, deployment may take a few minutes. |
| const users = [makeUser()] | ||
| service.getAllUsers.mockResolvedValue(users) | ||
|
|
||
| const result = await controller.getAllUsers({ adminRoleIds: ['r1'], relationType: 'OR' } as never) |
There was a problem hiding this comment.
Avoid the use of as never
There was a problem hiding this comment.
Corrigé : voir 4131482912 — plus aucun as never, entrées parsées par les schémas partagés.
| const relationType = query.relationType ?? 'AND' | ||
| const { relationType: _, ...listQuery } = query | ||
| const users = await this.userService.getAllUsers(listQuery, relationType) | ||
| return users.map(toContractUser) |
There was a problem hiding this comment.
Just pass query at this point
There was a problem hiding this comment.
Corrigé : le contrôleur passe query tel quel ; le défaut relationType ?? 'AND' vit dans buildAllUsersWhere.
| users: PatchUsersBody, | ||
| ): Promise<User[]> { | ||
| const usersBefore = await getUsers(this.prisma, { id: { in: users.map(({ id }) => id) } }) | ||
| await this.prisma.$transaction(tx => patchUsers(tx, users)) |
There was a problem hiding this comment.
Probably useless ? Just pass this.prisma ? Or wrap usersBefore in transaction
There was a problem hiding this comment.
Conservé tel quel : usersBefore doit être lu avant la transaction, la lecture dans la transaction ne réduirait pas la fenêtre de course.
StephaneTrebel
left a comment
There was a problem hiding this comment.
🔴 Changements demandés. Le payload adminRole.upsert émis par cette PR est incompatible avec les consommateurs Keycloak et GitLab de sa base #2749, ce qui laisse les groupes externes non synchronisés après un patch utilisateur. Les échappatoires as never des tests restent interdites ; la CI du head est verte, mais une preuve de bout en bout de la chaîne événementielle manque.
| user.adminRoleIds?.forEach(roleId => impactedRoleIds.add(roleId)) | ||
| } | ||
| for (const roleId of impactedRoleIds) { | ||
| await this.eventEmitter.emitAsync('adminRole.upsert', { roleId }) |
There was a problem hiding this comment.
🔴 blocking: Cette émission { roleId } ne correspond à aucun consommateur de la branche de base #2749 : KeycloakService.handleAdminRoleUpsert attend un string, tandis que GitlabService.handleAdminRoleUpsert attend un AdminRoleEventPayload (id, oidcGroup, members). Après un PATCH, Keycloak ne trouve donc aucun rôle et GitLab ne peut associer aucun groupe : la synchronisation legacy est perdue silencieusement. Trancher le payload canonique dans #2749, aligner ses deux consommateurs puis émettre exactement cette forme ici, avec un test de chaîne PATCH → événement → plugins.
There was a problem hiding this comment.
Corrigé : emitImpactedRoleEvents charge désormais les rôles (id, oidcGroup) et leurs membres, puis émet le payload canonique { id, oidcGroup, members } attendu par KeycloakService.handleAdminRoleUpsert et GitlabService.handleAdminRoleUpsert.
| service.patchUsers.mockResolvedValue(users) | ||
| const body = [{ id: users[0].id, adminRoleIds: ['r1'] }] | ||
|
|
||
| expect(await controller.patchUsers(body as never)).toEqual(users.map(toContractUser)) |
There was a problem hiding this comment.
🟠 important: as never est interdit dans ce dépôt : il coupe la preuve de type du test et masque ici la compatibilité réelle de PatchUsersBody. Le même échappatoire demeure à la ligne 41. Construire des entrées typées par les schémas partagés, sans assertion.
There was a problem hiding this comment.
Corrigé : les deux as never disparaissent — entrées typées via AllUsersQuerySchema.parse / PatchUsersBodySchema.parse dans le spec contrôleur.
shikanime
left a comment
There was a problem hiding this comment.
Verdict : Commentaire
L'extraction des schémas de contrat dans packages/shared est mécanique et les deux côtés client/serveur restent alignés. Le pont d'événements adminRole.upsert émet désormais le payload complet {id, oidcGroup, members} attendu par les consommateurs — la forme { roleId } signalée en review est corrigée. Rien de bloquant côté diff.
| select: { id: true, email: true, firstName: true, lastName: true, adminRoleIds: true }, | ||
| }) | ||
| for (const role of roles) { | ||
| await this.eventEmitter.emitAsync('adminRole.upsert', { |
There was a problem hiding this comment.
[✨ Éloge] emitImpactedRoleEvents calcule l'union des rôles avant/après puis relit les membres depuis la base après commit du $transaction : payload idempotent au replay et aligné sur le contrat des consommateurs Keycloak/GitLab — c'est le patron d'émission post-commit qu'il faut généraliser.
…ion semantics Co-authored-by: Automata <automata@shikanime.studio>
Signed-off-by: Shikanime Deva <22115108+shikanime@users.noreply.github.com>
Aligne le module user sur le pattern établi par le module zone (#2487) : - `user-queries.utils.ts` : suppression du `userSelect`/`UserRecord` morts, signatures sur `Prisma.TransactionClient`, `createUser` purement DB (la validation du doublon email monte dans le service en `ConflictException`). - `user.service.ts` : extraction de `resolveAdminRoleIds`, `patchUsersInTx`, `emitImpactedRoleEvents` ; patch des rôles sous transaction. - `user.module.ts` : imports repliés sur `InfrastructureModule` (déjà exporté par celui-ci). Refs #2738 Co-authored-by: Automata <automata@shikanime.studio> Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr> Change-Id: I3bd632f95dd466e585698eba738efcd86a6a6964
`AllUsersQuerySchema` étant exporté, l'alias `AllUsersQuery` est redondant ; les consommateurs dérivent le type par `z.infer`. `LettersQuery` est conservé (utilisé par le client). Refs #1889 Co-authored-by: Automata <automata@shikanime.studio> Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr> Change-Id: I5d954715680b8fbcd866edf4bb300dc36a6a6964
Co-authored-by: Automata <automata@shikanime.studio> Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr>
- supprimer UserService.createUser et les helpers createUser/getUserByEmail (aucun appelant ni route au contrat : chemin mort signalé en revue) - supprimer l'import faker inutilisé de user.controller.spec.ts - verrouiller par spec : 400 (BadRequestException) sur adminRole inconnue, take:5 sur la recherche par lettres, émission union avant ∪ après Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr>
Reflect.getMetadata assertions pass whether or not the guard is enforced and add no behavioural coverage; the guard logic stays covered in user.guard.spec.ts and the controller delegation tests are untouched. Co-authored-by: Automata <automata@shikanime.studio> Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr>
…nputs
Emit the full { id, oidcGroup, members } payload that the 2749 event
bridge consumers expect, drop as never from the controller spec by
parsing inputs through the shared schemas, and move the relationType
default into buildAllUsersWhere so the controller passes the query
straight through.
Co-authored-by: Automata <automata@shikanime.studio>
Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr>
Change-Id: I28676aa618050a7042ed24dfa9e66b896a6a6964
85c653b to
24825dd
Compare
Signed-off-by: William Phetsinorath <william.phetsinorath-open@interieur.gouv.fr> Change-Id: Ieb2ee298f5d0547bf988787721ed029a6a6a6964
24825dd to
cf16ba8
Compare
|

2 New Issues
0 Fixed Issues
0 Accepted Issues
Issues liées
Refs #1889
Quel est le comportement actuel ?
Les routes d'administration des utilisateurs (
/api/v1/users) sont servies par l'ancienne application Fastifyapps/server.Quel est le nouveau comportement ?
Migration du module
userversapps/server-nestjs:UserController,UserService,UserModule.user-queries.utils.ts: sélections Prisma typées.main.module.ts.apps/server/src/resources/user/(400 sur rôle admin inconnu,take: 5sur la recherche, émissionuser.upsertpar rôle).Cette PR introduit-elle un breaking change ?
Non.
Autres informations
Recréée pour #1889 (remplace #2498, non réouvrable après suppression de branche).