diff --git a/back/src/config/bootstrap/inclusionConnectAuthMiddleware.ts b/back/src/config/bootstrap/inclusionConnectAuthMiddleware.ts index ae9a49b525..f12d509ccf 100644 --- a/back/src/config/bootstrap/inclusionConnectAuthMiddleware.ts +++ b/back/src/config/bootstrap/inclusionConnectAuthMiddleware.ts @@ -1,6 +1,6 @@ import { NextFunction, Request, Response } from "express"; import { errors, inclusionConnectTokenExpiredMessage } from "shared"; -import { oAuthModeByFeatureFlags } from "../../domains/core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../domains/core/authentication/inclusion-connect/port/OAuthGateway"; import { makeVerifyJwtES256 } from "../../domains/core/jwt"; import { UnitOfWorkPerformer } from "../../domains/core/unit-of-work/ports/UnitOfWorkPerformer"; @@ -25,7 +25,7 @@ export const makeInclusionConnectAuthMiddleware = ( const currentIcUser = await uowPerformer.perform(async (uow) => uow.userRepository.getById( payload.userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ), ); if (!currentIcUser) diff --git a/back/src/domains/agency/use-cases/RegisterAgencyToInclusionConnectUser.ts b/back/src/domains/agency/use-cases/RegisterAgencyToInclusionConnectUser.ts index 8359ce21ae..a5ebcbbbbc 100644 --- a/back/src/domains/agency/use-cases/RegisterAgencyToInclusionConnectUser.ts +++ b/back/src/domains/agency/use-cases/RegisterAgencyToInclusionConnectUser.ts @@ -5,7 +5,7 @@ import { errors, } from "shared"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { CreateNewEvent } from "../../core/events/ports/EventBus"; import { UnitOfWork } from "../../core/unit-of-work/ports/UnitOfWork"; import { UnitOfWorkPerformer } from "../../core/unit-of-work/ports/UnitOfWorkPerformer"; @@ -36,7 +36,7 @@ export class RegisterAgencyToInclusionConnectUser extends TransactionalUseCase< const user = await uow.userRepository.getById( inclusionConnectedPayload.userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!user) diff --git a/back/src/domains/convention/use-cases/GetApiConsumersByConvention.ts b/back/src/domains/convention/use-cases/GetApiConsumersByConvention.ts index 9357772718..7806afd1d6 100644 --- a/back/src/domains/convention/use-cases/GetApiConsumersByConvention.ts +++ b/back/src/domains/convention/use-cases/GetApiConsumersByConvention.ts @@ -9,7 +9,7 @@ import { withConventionIdSchema, } from "shared"; import { createTransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; export type GetApiConsumersByConvention = ReturnType< typeof makeGetApiConsumersByConvention @@ -33,7 +33,7 @@ export const makeGetApiConsumersByConvention = createTransactionalUseCase< const user = await uow.userRepository.getById( currentUser.id, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!user) diff --git a/back/src/domains/convention/use-cases/GetConvention.ts b/back/src/domains/convention/use-cases/GetConvention.ts index c655ef7d4c..8077cfce5b 100644 --- a/back/src/domains/convention/use-cases/GetConvention.ts +++ b/back/src/domains/convention/use-cases/GetConvention.ts @@ -6,7 +6,7 @@ import { ConventionReadDto, ConventionRelatedJwtPayload, InclusionConnectJwtPayload, - OAuthProvider, + OAuthGatewayProvider, WithConventionId, getIcUserRoleForAccessingConvention, stringToMd5, @@ -15,7 +15,7 @@ import { import { ForbiddenError, NotFoundError } from "shared"; import { conventionEmailsByRole } from "../../../utils/convention"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { UserRepository } from "../../core/authentication/inclusion-connect/port/UserRepository"; import { UnitOfWork } from "../../core/unit-of-work/ports/UnitOfWork"; @@ -46,7 +46,7 @@ export class GetConvention extends TransactionalUseCase< conventionId, ); - const mode = oAuthModeByFeatureFlags( + const provider = oAuthProviderByFeatureFlags( await uow.featureFlagRepository.getAll(), ); @@ -55,7 +55,7 @@ export class GetConvention extends TransactionalUseCase< authPayload, uow, convention, - provider: mode, + provider: provider, }); } @@ -64,7 +64,7 @@ export class GetConvention extends TransactionalUseCase< authPayload, uow, convention, - mode, + provider: provider, }); } @@ -80,7 +80,7 @@ export class GetConvention extends TransactionalUseCase< authPayload: ConventionDomainPayload; convention: ConventionReadDto; uow: UnitOfWork; - provider: OAuthProvider; + provider: OAuthGatewayProvider; }): Promise { const agency = await uow.agencyRepository.getById(convention.agencyId); if (!agency) { @@ -106,14 +106,14 @@ export class GetConvention extends TransactionalUseCase< authPayload, convention, uow, - mode, + provider, }: { authPayload: InclusionConnectJwtPayload; convention: ConventionReadDto; uow: UnitOfWork; - mode: OAuthProvider; + provider: OAuthGatewayProvider; }): Promise { - const user = await uow.userRepository.getById(authPayload.userId, mode); + const user = await uow.userRepository.getById(authPayload.userId, provider); if (!user) throw new NotFoundError(`No user found with id '${authPayload.userId}'`); @@ -150,7 +150,7 @@ export class GetConvention extends TransactionalUseCase< convention: ConventionReadDto; agency: AgencyDto; userRepository: UserRepository; - provider: OAuthProvider; + provider: OAuthGatewayProvider; }): Promise { const emailsByRole = conventionEmailsByRole(convention, agency)[ authPayload.role @@ -188,7 +188,7 @@ export class GetConvention extends TransactionalUseCase< authPayload: ConventionDomainPayload; userRepository: UserRepository; agencyId: AgencyId; - provider: OAuthProvider; + provider: OAuthGatewayProvider; }) { if (authPayload.role !== "counsellor" && authPayload.role !== "validator") return false; diff --git a/back/src/domains/convention/use-cases/RenewConvention.ts b/back/src/domains/convention/use-cases/RenewConvention.ts index 259815ff76..b28aa95eb4 100644 --- a/back/src/domains/convention/use-cases/RenewConvention.ts +++ b/back/src/domains/convention/use-cases/RenewConvention.ts @@ -11,7 +11,7 @@ import { } from "shared"; import { BadRequestError, ForbiddenError, NotFoundError } from "shared"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { UnitOfWork } from "../../core/unit-of-work/ports/UnitOfWork"; import { UnitOfWorkPerformer } from "../../core/unit-of-work/ports/UnitOfWorkPerformer"; import { AddConvention } from "./AddConvention"; @@ -95,7 +95,7 @@ export class RenewConvention extends TransactionalUseCase< const inclusionConnectedUser = await uow.userRepository.getById( jwtPayload.userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!inclusionConnectedUser) throw new NotFoundError( diff --git a/back/src/domains/convention/use-cases/SignConvention.ts b/back/src/domains/convention/use-cases/SignConvention.ts index ac0f736f28..9755c6af3c 100644 --- a/back/src/domains/convention/use-cases/SignConvention.ts +++ b/back/src/domains/convention/use-cases/SignConvention.ts @@ -14,7 +14,7 @@ import { } from "shared"; import { ForbiddenError, NotFoundError } from "shared"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { DomainTopic } from "../../core/events/events"; import { CreateNewEvent } from "../../core/events/ports/EventBus"; import { TimeGateway } from "../../core/time-gateway/ports/TimeGateway"; @@ -113,7 +113,7 @@ export class SignConvention extends TransactionalUseCase< return { role: jwtPayload.role, icUser: undefined }; const icUser = await uow.userRepository.getById( jwtPayload.userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!icUser) throw new NotFoundError(`No user found with id '${jwtPayload.userId}'`); diff --git a/back/src/domains/convention/use-cases/UpdateConventionStatus.ts b/back/src/domains/convention/use-cases/UpdateConventionStatus.ts index cf28958fdd..1ec75dc9c5 100644 --- a/back/src/domains/convention/use-cases/UpdateConventionStatus.ts +++ b/back/src/domains/convention/use-cases/UpdateConventionStatus.ts @@ -6,7 +6,7 @@ import { ConventionStatus, Email, InclusionConnectedUser, - OAuthProvider, + OAuthGatewayProvider, Role, UpdateConventionStatusRequestDto, UserId, @@ -20,7 +20,7 @@ import { validatedConventionStatuses, } from "shared"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { ConventionRequiresModificationPayload } from "../../core/events/eventPayload.dto"; import { DomainTopic, @@ -85,14 +85,14 @@ export class UpdateConventionStatus extends TransactionalUseCase< agencyId: conventionRead.agencyId, }); - const mode = oAuthModeByFeatureFlags( + const provider = oAuthProviderByFeatureFlags( await uow.featureFlagRepository.getAll(), ); const { user, roleInPayload } = await this.#getRoleInPayloadOrUser( uow, payload, - mode, + provider, ); const roles = roleInPayload @@ -184,7 +184,7 @@ export class UpdateConventionStatus extends TransactionalUseCase< uow, payload, conventionRead, - mode, + provider, ), triggeredBy, } @@ -210,7 +210,7 @@ export class UpdateConventionStatus extends TransactionalUseCase< async #getRoleInPayloadOrUser( uow: UnitOfWork, payload: UpdateConventionStatusSupportedJwtPayload, - mode: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise< | { user: InclusionConnectedUser; roleInPayload: undefined } | { user: undefined; roleInPayload: Role } @@ -218,7 +218,7 @@ export class UpdateConventionStatus extends TransactionalUseCase< if ("role" in payload) return { roleInPayload: payload.role, user: undefined }; - const user = await uow.userRepository.getById(payload.userId, mode); + const user = await uow.userRepository.getById(payload.userId, provider); if (!user) throw errors.user.notFound({ userId: payload.userId, @@ -260,9 +260,9 @@ export class UpdateConventionStatus extends TransactionalUseCase< uow: UnitOfWork, userId: UserId, agencyId: AgencyId, - mode: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { - const user = await uow.userRepository.getById(userId, mode); + const user = await uow.userRepository.getById(userId, provider); if (!user) throw errors.user.notFound({ userId }); const userAgencyRights = user.agencyRights.find( (agencyRight) => agencyRight.agency.id === agencyId, @@ -300,7 +300,7 @@ export class UpdateConventionStatus extends TransactionalUseCase< uow: UnitOfWork, payload: UpdateConventionStatusSupportedJwtPayload, originalConvention: ConventionDto, - mode: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise => { const getEmailFromEmailHash = async ( agencyId: AgencyId, @@ -329,7 +329,7 @@ export class UpdateConventionStatus extends TransactionalUseCase< uow, payload.userId, originalConvention.agencyId, - mode, + provider, ); return agencyIcUserEmail; } diff --git a/back/src/domains/convention/use-cases/notifications/NotifyIcUserAgencyRightChanged.ts b/back/src/domains/convention/use-cases/notifications/NotifyIcUserAgencyRightChanged.ts index 5daac08194..0dac751dc3 100644 --- a/back/src/domains/convention/use-cases/notifications/NotifyIcUserAgencyRightChanged.ts +++ b/back/src/domains/convention/use-cases/notifications/NotifyIcUserAgencyRightChanged.ts @@ -1,6 +1,6 @@ import { UserParamsForAgency, errors, userParamsForAgencySchema } from "shared"; import { TransactionalUseCase } from "../../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../../core/authentication/inclusion-connect/port/OAuthGateway"; import { SaveNotificationAndRelatedEvent } from "../../../core/notifications/helpers/Notification"; import { UnitOfWork } from "../../../core/unit-of-work/ports/UnitOfWork"; import { UnitOfWorkPerformer } from "../../../core/unit-of-work/ports/UnitOfWorkPerformer"; @@ -30,7 +30,7 @@ export class NotifyIcUserAgencyRightChanged extends TransactionalUseCase< const user = await uow.userRepository.getById( params.userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!user) throw errors.user.notFound({ userId: params.userId }); diff --git a/back/src/domains/convention/use-cases/notifications/NotifyIcUserAgencyRightRejected.ts b/back/src/domains/convention/use-cases/notifications/NotifyIcUserAgencyRightRejected.ts index f16ebacff8..d59659353f 100644 --- a/back/src/domains/convention/use-cases/notifications/NotifyIcUserAgencyRightRejected.ts +++ b/back/src/domains/convention/use-cases/notifications/NotifyIcUserAgencyRightRejected.ts @@ -4,7 +4,7 @@ import { rejectIcUserRoleForAgencyParamsSchema, } from "shared"; import { TransactionalUseCase } from "../../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../../core/authentication/inclusion-connect/port/OAuthGateway"; import { SaveNotificationAndRelatedEvent } from "../../../core/notifications/helpers/Notification"; import { UnitOfWork } from "../../../core/unit-of-work/ports/UnitOfWork"; import { UnitOfWorkPerformer } from "../../../core/unit-of-work/ports/UnitOfWorkPerformer"; @@ -35,7 +35,7 @@ export class NotifyIcUserAgencyRightRejected extends TransactionalUseCase< const user = await uow.userRepository.getById( params.userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!user) throw errors.user.notFound({ userId: params.userId }); diff --git a/back/src/domains/convention/use-cases/partners-errored-convention/MarkPartnersErroredConventionAsHandled.ts b/back/src/domains/convention/use-cases/partners-errored-convention/MarkPartnersErroredConventionAsHandled.ts index 7a6ac6d614..0e03d8f27c 100644 --- a/back/src/domains/convention/use-cases/partners-errored-convention/MarkPartnersErroredConventionAsHandled.ts +++ b/back/src/domains/convention/use-cases/partners-errored-convention/MarkPartnersErroredConventionAsHandled.ts @@ -5,7 +5,7 @@ import { markPartnersErroredConventionAsHandledRequestSchema, } from "shared"; import { TransactionalUseCase } from "../../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../../core/authentication/inclusion-connect/port/OAuthGateway"; import { CreateNewEvent } from "../../../core/events/ports/EventBus"; import { TimeGateway } from "../../../core/time-gateway/ports/TimeGateway"; import { UnitOfWork } from "../../../core/unit-of-work/ports/UnitOfWork"; @@ -45,7 +45,7 @@ export class MarkPartnersErroredConventionAsHandled extends TransactionalUseCase const currentUser = await uow.userRepository.getById( userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!currentUser) throw errors.user.notFound({ userId }); const userAgencyRights = currentUser.agencyRights.find( diff --git a/back/src/domains/core/authentication/inclusion-connect/adapters/PgOngoingOAuthRepository.integration.test.ts b/back/src/domains/core/authentication/inclusion-connect/adapters/PgOngoingOAuthRepository.integration.test.ts index a036990c42..c81df1756f 100644 --- a/back/src/domains/core/authentication/inclusion-connect/adapters/PgOngoingOAuthRepository.integration.test.ts +++ b/back/src/domains/core/authentication/inclusion-connect/adapters/PgOngoingOAuthRepository.integration.test.ts @@ -1,5 +1,10 @@ import { Pool } from "pg"; -import { IdentityProvider, User, expectToEqual, oAuthProviders } from "shared"; +import { + IdentityProvider, + User, + expectToEqual, + oAuthGatewayProviders, +} from "shared"; import { KyselyDb, makeKyselyDb, @@ -31,7 +36,7 @@ describe("PgOngoingOAuthRepository", () => { await pool.end(); }); - describe.each(oAuthProviders)("with mode '%s'", (mode) => { + describe.each(oAuthGatewayProviders)("with mode '%s'", (mode) => { it("saves an ongoing OAuth, then gets it from its states, then updates it", async () => { const state = "11111111-1111-1111-1111-111111111111"; diff --git a/back/src/domains/core/authentication/inclusion-connect/adapters/PgUserRepository.integration.test.ts b/back/src/domains/core/authentication/inclusion-connect/adapters/PgUserRepository.integration.test.ts index 00ff35d5e4..cb0aed2ee6 100644 --- a/back/src/domains/core/authentication/inclusion-connect/adapters/PgUserRepository.integration.test.ts +++ b/back/src/domains/core/authentication/inclusion-connect/adapters/PgUserRepository.integration.test.ts @@ -5,7 +5,7 @@ import { AgencyRight, AgencyRole, InclusionConnectedUser, - OAuthProvider, + OAuthGatewayProvider, User, UserId, defaultValidatorEmail, @@ -13,7 +13,7 @@ import { expectArraysToEqualIgnoringOrder, expectPromiseToFailWithError, expectToEqual, - oAuthProviders, + oAuthGatewayProviders, } from "shared"; import { KyselyDb, @@ -72,674 +72,698 @@ describe("PgAuthenticatedUserRepository", () => { await pool.end(); }); - describe.each(oAuthProviders)(`With OAuthGatewayMode '%s'`, (mode) => { - it("saves a user, than finds it from external_id, then updates it", async () => { - await userRepository.save(user, mode); - - const fetchedUser = await userRepository.findByExternalId( - userExternalId, - mode, - ); - expectToEqual(fetchedUser, user); - - const updatedUser: User = { - id: userId, - email: "updated-mail@mail.com", - lastName: "Dodo", - firstName: "Johnny", - externalId: userExternalId, - createdAt, - }; - await userRepository.save(updatedUser, mode); - const fetchedUpdatedUser = await userRepository.findByExternalId( - userExternalId, - mode, - ); - expectToEqual(fetchedUpdatedUser, updatedUser); - }); - - describe("when user already exists but not inclusion connected", () => { - it("adds the missing data to the entry", async () => { - const userNotIcConnected: User = { - ...user, - firstName: "", - lastName: "", - externalId: null, - }; - await userRepository.save(userNotIcConnected, mode); + describe.each(oAuthGatewayProviders)( + `With oAuthProvider '%s'`, + (provider) => { + it("saves a user, than finds it from external_id, then updates it", async () => { + await userRepository.save(user, provider); - await userRepository.save(user, mode); - const fetchedUpdatedUser = await userRepository.findByEmail( - user.email, - mode, + const fetchedUser = await userRepository.findByExternalId( + userExternalId, + provider, ); - expectToEqual(fetchedUpdatedUser, user); - }); - }); - - describe("findByExternalId", () => { - it("returns an user", async () => { - await userRepository.save(user, mode); - const response = await userRepository.findByExternalId( + expectToEqual(fetchedUser, user); + + const updatedUser: User = { + id: userId, + email: "updated-mail@mail.com", + lastName: "Dodo", + firstName: "Johnny", + externalId: userExternalId, + createdAt, + }; + await userRepository.save(updatedUser, provider); + const fetchedUpdatedUser = await userRepository.findByExternalId( userExternalId, - mode, + provider, ); - expectToEqual(response, user); + expectToEqual(fetchedUpdatedUser, updatedUser); }); - it("returns undefined when user not found", async () => { - const response = await userRepository.findByExternalId( - "an-external-id", - mode, - ); - expect(response).toBeUndefined(); + describe("when user already exists but not connected", () => { + it("adds the missing data to the entry", async () => { + const userNotIcConnected: User = { + ...user, + firstName: "", + lastName: "", + externalId: null, + }; + await userRepository.save(userNotIcConnected, provider); + + await userRepository.save(user, provider); + const fetchedUpdatedUser = await userRepository.findByEmail( + user.email, + provider, + ); + expectToEqual(fetchedUpdatedUser, user); + }); }); - }); - describe("findByEmail", () => { - it("returns a user", async () => { - await userRepository.save(user, mode); - const response = await userRepository.findByEmail(user.email, mode); - expectToEqual(response, user); + describe("findByExternalId", () => { + it("returns an user", async () => { + await userRepository.save(user, provider); + const response = await userRepository.findByExternalId( + userExternalId, + provider, + ); + expectToEqual(response, user); + }); + + it("returns undefined when user not found", async () => { + const response = await userRepository.findByExternalId( + "an-external-id", + provider, + ); + expect(response).toBeUndefined(); + }); }); - it("returns undefined when user not found", async () => { - const response = await userRepository.findByEmail( - "some@email.com", - mode, - ); - expect(response).toBeUndefined(); + describe("findByEmail", () => { + it("returns a user", async () => { + await userRepository.save(user, provider); + const response = await userRepository.findByEmail( + user.email, + provider, + ); + expectToEqual(response, user); + }); + + it("returns undefined when user not found", async () => { + const response = await userRepository.findByEmail( + "some@email.com", + provider, + ); + expect(response).toBeUndefined(); + }); }); - }); - describe("getById", () => { - describe("when no agency is connected", () => { - it("gets the Inclusion Connected User from its Id", async () => { - await insertUser(db, user1, mode); + describe("getById", () => { + describe("when no agency is connected", () => { + it("gets the connected user from its Id", async () => { + await insertUser(db, user1, provider); + await db + .insertInto("users_admins") + .values({ user_id: user1.id }) + .execute(); + const adminUser = await userRepository.getById(user1.id, provider); + expectToEqual(adminUser, { + ...user1, + establishments: [], + agencyRights: [], + ...withEmptyDashboards, + isBackofficeAdmin: true, + }); + }); + + it("gets the connected user with admin right for admins", async () => { + await insertUser(db, user1, provider); + const inclusionConnectedUser = await userRepository.getById( + user1.id, + provider, + ); + expectToEqual(inclusionConnectedUser, { + ...user1, + establishments: [], + agencyRights: [], + ...withEmptyDashboards, + }); + }); + }); + + it("gets the connected user from its Id with the connected agencies", async () => { + await Promise.all([ + await agencyRepository.insert(agency1), + await agencyRepository.insert(agency2), + await insertUser(db, user1, provider), + ]); + + // create the link between the user and the agencies + await insertAgencyRegistrationToUser(db, { + agencyId: agency1.id, + userId: user1.id, + roles: ["toReview"], + isNotifiedByEmail: false, + }); + await insertAgencyRegistrationToUser(db, { + agencyId: agency2.id, + userId: user1.id, + roles: ["validator"], + isNotifiedByEmail: false, + }); + + const inclusionConnectedUser = await userRepository.getById( + user1.id, + provider, + ); + expectToEqual(inclusionConnectedUser, { + ...user1, + establishments: [], + agencyRights: [ + { + agency: agency1, + roles: ["toReview"], + isNotifiedByEmail: false, + }, + { + agency: agency2, + roles: ["validator"], + isNotifiedByEmail: false, + }, + ], + ...withEmptyDashboards, + }); + }); + + it("gets the user with the connected establishments when they exist", async () => { + const contact1 = new ContactEntityBuilder() + .withEmail(user1.email) + .build(); + const customizedEstablishment1Name = "My awsome name"; + const establishment1 = new EstablishmentAggregateBuilder() + .withEstablishmentCustomizedName(customizedEstablishment1Name) + .withContact(contact1) + .build(); + + const contact2 = new ContactEntityBuilder() + .withId("22222222-2222-4bbb-2222-222222222222") + .withEmail(user1.email) + .build(); + + const establishment2Name = "Establishment 2"; + const establishment2 = new EstablishmentAggregateBuilder() + .withEstablishmentSiret("12345678901234") + .withLocationId("11111111-1111-4111-1111-111111111111") + .withEstablishmentCustomizedName("") + .withEstablishmentName(establishment2Name) + .withContact(contact2) + .build(); + + const establishmentRepository = + new PgEstablishmentAggregateRepository(db); + + await establishmentRepository.insertEstablishmentAggregate( + establishment1, + ); + await establishmentRepository.insertEstablishmentAggregate( + establishment2, + ); + await insertUser(db, user1, provider); await db .insertInto("users_admins") .values({ user_id: user1.id }) .execute(); - const adminUser = await userRepository.getById(user1.id, mode); + const adminUser = await userRepository.getById(user1.id, provider); expectToEqual(adminUser, { ...user1, - establishments: [], agencyRights: [], - ...withEmptyDashboards, + dashboards: { + agencies: {}, + establishments: {}, + }, isBackofficeAdmin: true, + establishments: [ + { + siret: establishment2.establishment.siret, + businessName: establishment2Name, + }, + { + siret: establishment1.establishment.siret, + businessName: customizedEstablishment1Name, + }, + ], }); }); - it("gets the inclusion connected User with admin right for admins", async () => { - await insertUser(db, user1, mode); + it("gets the user without the agency rights on agencies that are closed or rejected", async () => { + const rejectedAgency = new AgencyDtoBuilder() + .withValidatorEmails(["closed-agency-validator@email.fr"]) + .withId("11111111-1111-4bbb-1111-111111111114") + .withStatus("rejected") + .withName("Agence rejected") + .build(); + + const closedAgency = new AgencyDtoBuilder() + .withValidatorEmails(["rejected-agency-validator@email.fr"]) + .withId("11111111-1111-4bbb-1111-111111111115") + .withName("Agence closed") + .withStatus("closed") + .build(); + + await Promise.all([ + await agencyRepository.insert(agency1), + await agencyRepository.insert(agency2), + await agencyRepository.insert(rejectedAgency), + await agencyRepository.insert(closedAgency), + await insertUser(db, user1, provider), + ]); + + // create the link between the user and the agencies + await insertAgencyRegistrationToUser(db, { + agencyId: agency1.id, + userId: user1.id, + roles: ["toReview"], + isNotifiedByEmail: false, + }); + await insertAgencyRegistrationToUser(db, { + agencyId: agency2.id, + userId: user1.id, + roles: ["validator"], + isNotifiedByEmail: false, + }); + await insertAgencyRegistrationToUser(db, { + agencyId: closedAgency.id, + userId: user1.id, + roles: ["toReview"], + isNotifiedByEmail: false, + }); + await insertAgencyRegistrationToUser(db, { + agencyId: rejectedAgency.id, + userId: user1.id, + roles: ["validator"], + isNotifiedByEmail: false, + }); + const inclusionConnectedUser = await userRepository.getById( user1.id, - mode, + provider, ); expectToEqual(inclusionConnectedUser, { ...user1, establishments: [], - agencyRights: [], + agencyRights: [ + { + agency: agency1, + roles: ["toReview"], + isNotifiedByEmail: false, + }, + { + agency: agency2, + roles: ["validator"], + isNotifiedByEmail: false, + }, + ], ...withEmptyDashboards, }); }); }); - it("gets the Inclusion Connected User from its Id with the connected agencies", async () => { - await Promise.all([ - await agencyRepository.insert(agency1), - await agencyRepository.insert(agency2), - await insertUser(db, user1, mode), - ]); - - // create the link between the user and the agencies - await insertAgencyRegistrationToUser(db, { - agencyId: agency1.id, - userId: user1.id, - roles: ["toReview"], - isNotifiedByEmail: false, - }); - await insertAgencyRegistrationToUser(db, { - agencyId: agency2.id, - userId: user1.id, - roles: ["validator"], - isNotifiedByEmail: false, - }); - - const inclusionConnectedUser = await userRepository.getById( - user1.id, - mode, - ); - expectToEqual(inclusionConnectedUser, { - ...user1, - establishments: [], - agencyRights: [ - { agency: agency1, roles: ["toReview"], isNotifiedByEmail: false }, - { agency: agency2, roles: ["validator"], isNotifiedByEmail: false }, - ], - ...withEmptyDashboards, - }); - }); - - it("gets the icUser with the connected establishments when they exist", async () => { - const contact1 = new ContactEntityBuilder() - .withEmail(user1.email) - .build(); - const customizedEstablishment1Name = "My awsome name"; - const establishment1 = new EstablishmentAggregateBuilder() - .withEstablishmentCustomizedName(customizedEstablishment1Name) - .withContact(contact1) - .build(); - - const contact2 = new ContactEntityBuilder() - .withId("22222222-2222-4bbb-2222-222222222222") - .withEmail(user1.email) - .build(); - - const establishment2Name = "Establishment 2"; - const establishment2 = new EstablishmentAggregateBuilder() - .withEstablishmentSiret("12345678901234") - .withLocationId("11111111-1111-4111-1111-111111111111") - .withEstablishmentCustomizedName("") - .withEstablishmentName(establishment2Name) - .withContact(contact2) - .build(); - - const establishmentRepository = new PgEstablishmentAggregateRepository( - db, - ); - - await establishmentRepository.insertEstablishmentAggregate( - establishment1, - ); - await establishmentRepository.insertEstablishmentAggregate( - establishment2, - ); - await insertUser(db, user1, mode); - await db - .insertInto("users_admins") - .values({ user_id: user1.id }) - .execute(); - const adminUser = await userRepository.getById(user1.id, mode); - expectToEqual(adminUser, { - ...user1, - agencyRights: [], - dashboards: { - agencies: {}, - establishments: {}, - }, - isBackofficeAdmin: true, - establishments: [ - { - siret: establishment2.establishment.siret, - businessName: establishment2Name, - }, - { - siret: establishment1.establishment.siret, - businessName: customizedEstablishment1Name, - }, - ], - }); - }); - - it("gets the icUser without the agency rights on agencies that are closed or rejected", async () => { - const rejectedAgency = new AgencyDtoBuilder() - .withValidatorEmails(["closed-agency-validator@email.fr"]) - .withId("11111111-1111-4bbb-1111-111111111114") - .withStatus("rejected") - .withName("Agence rejected") - .build(); - - const closedAgency = new AgencyDtoBuilder() - .withValidatorEmails(["rejected-agency-validator@email.fr"]) - .withId("11111111-1111-4bbb-1111-111111111115") - .withName("Agence closed") - .withStatus("closed") - .build(); - - await Promise.all([ - await agencyRepository.insert(agency1), - await agencyRepository.insert(agency2), - await agencyRepository.insert(rejectedAgency), - await agencyRepository.insert(closedAgency), - await insertUser(db, user1, mode), - ]); - - // create the link between the user and the agencies - await insertAgencyRegistrationToUser(db, { - agencyId: agency1.id, - userId: user1.id, - roles: ["toReview"], - isNotifiedByEmail: false, - }); - await insertAgencyRegistrationToUser(db, { - agencyId: agency2.id, - userId: user1.id, - roles: ["validator"], - isNotifiedByEmail: false, - }); - await insertAgencyRegistrationToUser(db, { - agencyId: closedAgency.id, - userId: user1.id, - roles: ["toReview"], - isNotifiedByEmail: false, - }); - await insertAgencyRegistrationToUser(db, { - agencyId: rejectedAgency.id, - userId: user1.id, - roles: ["validator"], - isNotifiedByEmail: false, - }); - - const inclusionConnectedUser = await userRepository.getById( - user1.id, - mode, - ); - expectToEqual(inclusionConnectedUser, { - ...user1, - establishments: [], - agencyRights: [ - { agency: agency1, roles: ["toReview"], isNotifiedByEmail: false }, - { agency: agency2, roles: ["validator"], isNotifiedByEmail: false }, - ], - ...withEmptyDashboards, - }); - }); - }); - - describe("updateAgencyRights", () => { - it("updates an element in users__agencies table", async () => { - await agencyRepository.insert(agency1); - await insertUser(db, user1, mode); - const agencyRights: AgencyRight[] = [ - { - roles: ["counsellor"], - agency: agency1, - isNotifiedByEmail: false, - }, - ]; - await userRepository.updateAgencyRights({ - userId: user1.id, - agencyRights: agencyRights, - }); - expectToEqual(await userRepository.getById(user1.id, mode), { - ...user1, - establishments: [], - agencyRights: agencyRights, - ...withEmptyDashboards, - }); - - await userRepository.updateAgencyRights({ - userId: user1.id, - agencyRights: [ - { - roles: ["validator"], - agency: agency1, - isNotifiedByEmail: true, - }, - ], - }); - - expectToEqual(await userRepository.getById(user1.id, mode), { - ...user1, - establishments: [], - agencyRights: [ - { - roles: ["validator"], - agency: { - ...agency1, - validatorEmails: [...agency1.validatorEmails, user1.email], - }, - isNotifiedByEmail: true, - }, - ], - ...withEmptyDashboards, - }); - }); - it("adds an element in users__agencies table", async () => { - await agencyRepository.insert(agency1); - await insertUser(db, user1, mode); - const icUserToUpdate: InclusionConnectedUser = { - ...user1, - establishments: [], - agencyRights: [ + describe("updateAgencyRights", () => { + it("updates an element in users__agencies table", async () => { + await agencyRepository.insert(agency1); + await insertUser(db, user1, provider); + const agencyRights: AgencyRight[] = [ { roles: ["counsellor"], agency: agency1, isNotifiedByEmail: false, }, - ], - ...withEmptyDashboards, - }; - - await userRepository.updateAgencyRights({ - userId: icUserToUpdate.id, - agencyRights: icUserToUpdate.agencyRights, - }); - - const savedIcUser = await userRepository.getById(user1.id, mode); - expectToEqual(savedIcUser, icUserToUpdate); - }); - - it("Delete an element in users__agencies table when no agency rights are provided", async () => { - await agencyRepository.insert(agency1); - await insertUser(db, user1, mode); - const icUserToSave: InclusionConnectedUser = { - ...user1, - establishments: [], - agencyRights: [], - ...withEmptyDashboards, - }; - - await userRepository.updateAgencyRights({ - userId: icUserToSave.id, - agencyRights: icUserToSave.agencyRights, - }); - - const savedIcUser = await userRepository.getById(user1.id, mode); - expectToEqual(savedIcUser, icUserToSave); - }); - - it("Delete just one element in users__agencies table when two agency rights are provided", async () => { - await agencyRepository.insert(agency1); - await agencyRepository.insert(agency2); - - await insertUser(db, user1, mode); + ]; + await userRepository.updateAgencyRights({ + userId: user1.id, + agencyRights: agencyRights, + }); + expectToEqual(await userRepository.getById(user1.id, provider), { + ...user1, + establishments: [], + agencyRights: agencyRights, + ...withEmptyDashboards, + }); - const icUserToSave: InclusionConnectedUser = { - ...user1, - establishments: [], - agencyRights: [ - { - agency: agency1, - roles: ["validator"], - isNotifiedByEmail: false, - }, - { - agency: agency2, - roles: ["toReview"], - isNotifiedByEmail: false, - }, - ], - ...withEmptyDashboards, - }; + await userRepository.updateAgencyRights({ + userId: user1.id, + agencyRights: [ + { + roles: ["validator"], + agency: agency1, + isNotifiedByEmail: true, + }, + ], + }); - await userRepository.updateAgencyRights({ - userId: icUserToSave.id, - agencyRights: icUserToSave.agencyRights, + expectToEqual(await userRepository.getById(user1.id, provider), { + ...user1, + establishments: [], + agencyRights: [ + { + roles: ["validator"], + agency: { + ...agency1, + validatorEmails: [...agency1.validatorEmails, user1.email], + }, + isNotifiedByEmail: true, + }, + ], + ...withEmptyDashboards, + }); }); + it("adds an element in users__agencies table", async () => { + await agencyRepository.insert(agency1); + await insertUser(db, user1, provider); + const icUserToUpdate: InclusionConnectedUser = { + ...user1, + establishments: [], + agencyRights: [ + { + roles: ["counsellor"], + agency: agency1, + isNotifiedByEmail: false, + }, + ], + ...withEmptyDashboards, + }; - const savedIcUser = await userRepository.getById(user1.id, mode); - - expectToEqual(savedIcUser, icUserToSave); - - const updatedIcUserToSave: InclusionConnectedUser = { - ...user1, - establishments: [], - agencyRights: [ - { - agency: agency1, - roles: ["validator"], - isNotifiedByEmail: false, - }, - ], - ...withEmptyDashboards, - }; + await userRepository.updateAgencyRights({ + userId: icUserToUpdate.id, + agencyRights: icUserToUpdate.agencyRights, + }); - await userRepository.updateAgencyRights({ - userId: updatedIcUserToSave.id, - agencyRights: updatedIcUserToSave.agencyRights, + const savedIcUser = await userRepository.getById(user1.id, provider); + expectToEqual(savedIcUser, icUserToUpdate); }); - const updatedSavedIcUser = await userRepository.getById(user1.id, mode); - expectToEqual(updatedSavedIcUser, updatedIcUserToSave); - }); - }); - describe("update user", () => { - it("updates users email in users table", async () => { - await agencyRepository.insert(agency1); - await insertUser(db, user1, mode); - await insertAgencyRegistrationToUser(db, { - agencyId: agency1.id, - userId: user1.id, - roles: ["counsellor"], - isNotifiedByEmail: false, - }); - const updatedEmail = "new-email@email.fr"; + it("Delete an element in users__agencies table when no agency rights are provided", async () => { + await agencyRepository.insert(agency1); + await insertUser(db, user1, provider); + const icUserToSave: InclusionConnectedUser = { + ...user1, + establishments: [], + agencyRights: [], + ...withEmptyDashboards, + }; - await userRepository.updateEmail(user1.id, updatedEmail); + await userRepository.updateAgencyRights({ + userId: icUserToSave.id, + agencyRights: icUserToSave.agencyRights, + }); - const agencyRights: AgencyRight[] = [ - { - roles: ["counsellor"], - agency: agency1, - isNotifiedByEmail: false, - }, - ]; - expectToEqual(await userRepository.getById(user1.id, mode), { - ...user1, - email: updatedEmail, - establishments: [], - agencyRights: agencyRights, - ...withEmptyDashboards, - }); - }); - }); - - describe("getWithFilters", () => { - it("returns empty array if no filters are given", async () => { - await Promise.all([ - agencyRepository.insert(agency1), - insertUser(db, user1, mode), - ]); - - await insertAgencyRegistrationToUser(db, { - agencyId: agency1.id, - userId: user1.id, - roles: ["toReview"], - isNotifiedByEmail: false, + const savedIcUser = await userRepository.getById(user1.id, provider); + expectToEqual(savedIcUser, icUserToSave); }); - const icUsers = await userRepository.getWithFilter({}, mode); - expect(icUsers).toEqual([]); - }); - - it("fetches Inclusion Connected Users with status 'toReview'", async () => { - await agencyRepository.insert(agency1); - await agencyRepository.insert(agency2); - await insertUser(db, user1, mode); - await insertUser(db, user2, mode); - await insertAgencyRegistrationToUser(db, { - agencyId: agency1.id, - userId: user1.id, - roles: ["toReview"], - isNotifiedByEmail: false, - }); - await insertAgencyRegistrationToUser(db, { - agencyId: agency2.id, - userId: user1.id, - roles: ["validator"], - isNotifiedByEmail: false, - }); - await insertAgencyRegistrationToUser(db, { - agencyId: agency2.id, - userId: user2.id, - roles: ["toReview"], - isNotifiedByEmail: false, - }); + it("Delete just one element in users__agencies table when two agency rights are provided", async () => { + await agencyRepository.insert(agency1); + await agencyRepository.insert(agency2); - const icUsers = await userRepository.getWithFilter( - { - agencyRole: "toReview", - }, - mode, - ); + await insertUser(db, user1, provider); - expectArraysToEqualIgnoringOrder(icUsers, [ - { + const icUserToSave: InclusionConnectedUser = { ...user1, establishments: [], agencyRights: [ { agency: agency1, - roles: ["toReview"], + roles: ["validator"], isNotifiedByEmail: false, }, { agency: agency2, - roles: ["validator"], + roles: ["toReview"], isNotifiedByEmail: false, }, ], ...withEmptyDashboards, - }, - { - ...user2, + }; + + await userRepository.updateAgencyRights({ + userId: icUserToSave.id, + agencyRights: icUserToSave.agencyRights, + }); + + const savedIcUser = await userRepository.getById(user1.id, provider); + + expectToEqual(savedIcUser, icUserToSave); + + const updatedIcUserToSave: InclusionConnectedUser = { + ...user1, establishments: [], agencyRights: [ { - agency: agency2, - roles: ["toReview"], + agency: agency1, + roles: ["validator"], isNotifiedByEmail: false, }, ], ...withEmptyDashboards, - }, - ]); - }); + }; + + await userRepository.updateAgencyRights({ + userId: updatedIcUserToSave.id, + agencyRights: updatedIcUserToSave.agencyRights, + }); - it("fetches inclusion connected users given its status 'validator' and agencyId", async () => { - await agencyRepository.insert(agency1); - await agencyRepository.insert(agency2); - await insertUser(db, user1, mode); - await insertUser(db, user2, mode); - await insertAgencyRegistrationToUser(db, { - agencyId: agency1.id, - userId: user1.id, - roles: ["validator"], - isNotifiedByEmail: false, + const updatedSavedIcUser = await userRepository.getById( + user1.id, + provider, + ); + expectToEqual(updatedSavedIcUser, updatedIcUserToSave); }); - await insertAgencyRegistrationToUser(db, { - agencyId: agency1.id, - userId: user2.id, - roles: ["toReview"], - isNotifiedByEmail: false, + }); + describe("update user", () => { + it("updates users email in users table", async () => { + await agencyRepository.insert(agency1); + await insertUser(db, user1, provider); + await insertAgencyRegistrationToUser(db, { + agencyId: agency1.id, + userId: user1.id, + roles: ["counsellor"], + isNotifiedByEmail: false, + }); + const updatedEmail = "new-email@email.fr"; + + await userRepository.updateEmail(user1.id, updatedEmail); + + const agencyRights: AgencyRight[] = [ + { + roles: ["counsellor"], + agency: agency1, + isNotifiedByEmail: false, + }, + ]; + expectToEqual(await userRepository.getById(user1.id, provider), { + ...user1, + email: updatedEmail, + establishments: [], + agencyRights: agencyRights, + ...withEmptyDashboards, + }); }); - await insertAgencyRegistrationToUser(db, { - agencyId: agency2.id, - userId: user1.id, - roles: ["validator"], - isNotifiedByEmail: false, + }); + + describe("getWithFilters", () => { + it("returns empty array if no filters are given", async () => { + await Promise.all([ + agencyRepository.insert(agency1), + insertUser(db, user1, provider), + ]); + + await insertAgencyRegistrationToUser(db, { + agencyId: agency1.id, + userId: user1.id, + roles: ["toReview"], + isNotifiedByEmail: false, + }); + + const icUsers = await userRepository.getWithFilter({}, provider); + expect(icUsers).toEqual([]); }); - const icUsers = await userRepository.getWithFilter( - { - agencyRole: "validator", + it("fetches connected users with status 'toReview'", async () => { + await agencyRepository.insert(agency1); + await agencyRepository.insert(agency2); + await insertUser(db, user1, provider); + await insertUser(db, user2, provider); + await insertAgencyRegistrationToUser(db, { agencyId: agency1.id, - }, - mode, - ); + userId: user1.id, + roles: ["toReview"], + isNotifiedByEmail: false, + }); + await insertAgencyRegistrationToUser(db, { + agencyId: agency2.id, + userId: user1.id, + roles: ["validator"], + isNotifiedByEmail: false, + }); + await insertAgencyRegistrationToUser(db, { + agencyId: agency2.id, + userId: user2.id, + roles: ["toReview"], + isNotifiedByEmail: false, + }); - expectArraysToEqualIgnoringOrder( - icUsers.map((icUser) => icUser.email), - [user1.email, defaultValidator.email], - ); + const icUsers = await userRepository.getWithFilter( + { + agencyRole: "toReview", + }, + provider, + ); - // biome-ignore lint/style/noNonNullAssertion: - const icUser1 = icUsers.find((u) => u.email === user1.email)!; - // biome-ignore lint/style/noNonNullAssertion: - const icDefaultValidator = icUsers.find( - (u) => u.email === defaultValidator.email, - )!; + expectArraysToEqualIgnoringOrder(icUsers, [ + { + ...user1, + establishments: [], + agencyRights: [ + { + agency: agency1, + roles: ["toReview"], + isNotifiedByEmail: false, + }, + { + agency: agency2, + roles: ["validator"], + isNotifiedByEmail: false, + }, + ], + ...withEmptyDashboards, + }, + { + ...user2, + establishments: [], + agencyRights: [ + { + agency: agency2, + roles: ["toReview"], + isNotifiedByEmail: false, + }, + ], + ...withEmptyDashboards, + }, + ]); + }); - expectToEqual(icUser1.agencyRights, [ - { + it("fetches connected users given its status 'validator' and agencyId", async () => { + await agencyRepository.insert(agency1); + await agencyRepository.insert(agency2); + await insertUser(db, user1, provider); + await insertUser(db, user2, provider); + await insertAgencyRegistrationToUser(db, { + agencyId: agency1.id, + userId: user1.id, + roles: ["validator"], + isNotifiedByEmail: false, + }); + await insertAgencyRegistrationToUser(db, { + agencyId: agency1.id, + userId: user2.id, + roles: ["toReview"], + isNotifiedByEmail: false, + }); + await insertAgencyRegistrationToUser(db, { + agencyId: agency2.id, + userId: user1.id, roles: ["validator"], - agency: agency1, isNotifiedByEmail: false, - }, - ]); + }); - expectToEqual(icDefaultValidator.agencyRights, [ - { + const icUsers = await userRepository.getWithFilter( + { + agencyRole: "validator", + agencyId: agency1.id, + }, + provider, + ); + + expectArraysToEqualIgnoringOrder( + icUsers.map((icUser) => icUser.email), + [user1.email, defaultValidator.email], + ); + + // biome-ignore lint/style/noNonNullAssertion: + const icUser1 = icUsers.find((u) => u.email === user1.email)!; + // biome-ignore lint/style/noNonNullAssertion: + const icDefaultValidator = icUsers.find( + (u) => u.email === defaultValidator.email, + )!; + + expectToEqual(icUser1.agencyRights, [ + { + roles: ["validator"], + agency: agency1, + isNotifiedByEmail: false, + }, + ]); + + expectToEqual(icDefaultValidator.agencyRights, [ + { + roles: ["validator"], + agency: agency1, + isNotifiedByEmail: true, + }, + ]); + }); + it("fetches connected users given email", async () => { + await agencyRepository.insert(agency1); + await insertUser(db, user1, provider); + await insertUser(db, user2, provider); + await insertAgencyRegistrationToUser(db, { + agencyId: agency1.id, + userId: user1.id, roles: ["validator"], - agency: agency1, + isNotifiedByEmail: false, + }); + await insertAgencyRegistrationToUser(db, { + agencyId: agency1.id, + userId: user2.id, + roles: ["toReview"], isNotifiedByEmail: true, - }, - ]); - }); - it("fetches Inclusion Connected Users given email", async () => { - await agencyRepository.insert(agency1); - await insertUser(db, user1, mode); - await insertUser(db, user2, mode); - await insertAgencyRegistrationToUser(db, { - agencyId: agency1.id, - userId: user1.id, - roles: ["validator"], - isNotifiedByEmail: false, - }); - await insertAgencyRegistrationToUser(db, { - agencyId: agency1.id, - userId: user2.id, - roles: ["toReview"], - isNotifiedByEmail: true, - }); + }); - const icUsers = await userRepository.getWithFilter( - { - email: user1.email, - }, - mode, - ); + const icUsers = await userRepository.getWithFilter( + { + email: user1.email, + }, + provider, + ); - expectArraysToEqualIgnoringOrder(icUsers, [ - { - ...user1, - establishments: [], - agencyRights: [ - { - agency: agency1, - roles: ["validator"], - isNotifiedByEmail: false, - }, - ], - ...withEmptyDashboards, - }, - ]); - }); - }); - - describe("delete", () => { - it("deletes an existing user", async () => { - await insertUser(db, user1, mode); - await agencyRepository.insert(agency1); - await insertAgencyRegistrationToUser(db, { - userId: user1.id, - agencyId: agency1.id, - roles: ["validator"], - isNotifiedByEmail: false, + expectArraysToEqualIgnoringOrder(icUsers, [ + { + ...user1, + establishments: [], + agencyRights: [ + { + agency: agency1, + roles: ["validator"], + isNotifiedByEmail: false, + }, + ], + ...withEmptyDashboards, + }, + ]); }); - await userRepository.delete(user1.id); - const response = await userRepository.getById(user1.id, mode); - expectToEqual(response, undefined); - expectToEqual( - await db - .selectFrom("users__agencies") - .selectAll() - .where("user_id", "=", user1.id) - .execute(), - [], - ); }); - it("does not throw when user does not exist", async () => { - await expectPromiseToFailWithError( - userRepository.delete(user1.id), - errors.user.notFound({ userId: user1.id }), - ); + describe("delete", () => { + it("deletes an existing user", async () => { + await insertUser(db, user1, provider); + await agencyRepository.insert(agency1); + await insertAgencyRegistrationToUser(db, { + userId: user1.id, + agencyId: agency1.id, + roles: ["validator"], + isNotifiedByEmail: false, + }); + await userRepository.delete(user1.id); + const response = await userRepository.getById(user1.id, provider); + expectToEqual(response, undefined); + expectToEqual( + await db + .selectFrom("users__agencies") + .selectAll() + .where("user_id", "=", user1.id) + .execute(), + [], + ); + }); + + it("does not throw when user does not exist", async () => { + await expectPromiseToFailWithError( + userRepository.delete(user1.id), + errors.user.notFound({ userId: user1.id }), + ); + }); }); - }); - }); + }, + ); }); const user1: User = { @@ -791,7 +815,7 @@ const agency2 = new AgencyDtoBuilder() const insertUser = async ( db: KyselyDb, { id, email, firstName, lastName, externalId, createdAt }: User, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ) => { await db .insertInto("users") diff --git a/back/src/domains/core/authentication/inclusion-connect/adapters/PgUserRepository.ts b/back/src/domains/core/authentication/inclusion-connect/adapters/PgUserRepository.ts index e3416905b4..8a9ad1d83c 100644 --- a/back/src/domains/core/authentication/inclusion-connect/adapters/PgUserRepository.ts +++ b/back/src/domains/core/authentication/inclusion-connect/adapters/PgUserRepository.ts @@ -6,7 +6,7 @@ import { AgencyRole, Email, InclusionConnectedUser, - OAuthProvider, + OAuthGatewayProvider, User, UserId, activeAgencyStatuses, @@ -40,7 +40,7 @@ export class PgUserRepository implements UserRepository { public async findByExternalId( externalId: string, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { const response = await this.transaction .selectFrom("users") @@ -67,7 +67,7 @@ export class PgUserRepository implements UserRepository { public async findByEmail( email: Email, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { const response = await this.#getUserQueryBuilder(provider) .where("email", "ilike", email) @@ -75,7 +75,7 @@ export class PgUserRepository implements UserRepository { return toAuthenticatedUser(response); } - #getUserQueryBuilder(provider: OAuthProvider) { + #getUserQueryBuilder(provider: OAuthGatewayProvider) { return this.transaction .selectFrom("users") .select([ @@ -90,7 +90,7 @@ export class PgUserRepository implements UserRepository { ]); } - public async save(user: User, provider: OAuthProvider): Promise { + public async save(user: User, provider: OAuthGatewayProvider): Promise { const { id, email, firstName, lastName, externalId, createdAt } = user; const existingUser = await this.#findById(id, provider); @@ -150,7 +150,7 @@ export class PgUserRepository implements UserRepository { async #findById( userId: UserId, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { const response = await this.#getUserQueryBuilder(provider) .where("id", "=", userId) @@ -160,7 +160,7 @@ export class PgUserRepository implements UserRepository { public async getById( userId: string, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { const icUsers = await this.#getInclusionConnectedUsers( { userId }, @@ -171,7 +171,7 @@ export class PgUserRepository implements UserRepository { public async getWithFilter( { agencyRole, agencyId, email }: InclusionConnectedFilters, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { return this.#getInclusionConnectedUsers( { agencyRole, agencyId, email }, @@ -212,7 +212,7 @@ export class PgUserRepository implements UserRepository { agencyId?: AgencyId; email?: Email; }, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { const buildAgencyRight = `JSON_BUILD_OBJECT( 'roles', users__agencies.roles, diff --git a/back/src/domains/core/authentication/inclusion-connect/adapters/oauth-gateway/HttpOAuthGateway.ts b/back/src/domains/core/authentication/inclusion-connect/adapters/oauth-gateway/HttpOAuthGateway.ts index 2f0a076d06..afc187f9a7 100644 --- a/back/src/domains/core/authentication/inclusion-connect/adapters/oauth-gateway/HttpOAuthGateway.ts +++ b/back/src/domains/core/authentication/inclusion-connect/adapters/oauth-gateway/HttpOAuthGateway.ts @@ -1,6 +1,6 @@ import { AbsoluteUrl, - OAuthProvider, + OAuthGatewayProvider, WithIdToken, WithSourcePage, decodeJwtWithoutSignatureCheck, @@ -55,9 +55,9 @@ export class HttpOAuthGateway implements OAuthGateway { public async getLoginUrl( { nonce, page, state }: GetLoginUrlParams, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { - const uriByProvider: Record = { + const uriByProvider: Record = { InclusionConnect: this.#makeInclusionConnectAuthorizeUri(), ProConnect: this.#makeProConnectAuthorizeUri(), }; @@ -201,7 +201,7 @@ export class HttpOAuthGateway implements OAuthGateway { public async getAccessToken( { code, page }: GetAccessTokenParams, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { return provider === "InclusionConnect" ? this.#getAccessTokenInclusionConnect({ code, page }) @@ -210,7 +210,7 @@ export class HttpOAuthGateway implements OAuthGateway { public async getLogoutUrl( params: WithIdToken, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { const uri: AbsoluteUrl = provider === "InclusionConnect" @@ -234,7 +234,7 @@ export class HttpOAuthGateway implements OAuthGateway { } async #getTokenWithPayload( - provider: OAuthProvider, + provider: OAuthGatewayProvider, inclusionConnectAccessTokenBody: InclusionConnectAccessTokenResponse, ): Promise { if (provider === "InclusionConnect") diff --git a/back/src/domains/core/authentication/inclusion-connect/adapters/oauth-gateway/InMemoryOAuthGateway.ts b/back/src/domains/core/authentication/inclusion-connect/adapters/oauth-gateway/InMemoryOAuthGateway.ts index d725b077ee..c0c461d056 100644 --- a/back/src/domains/core/authentication/inclusion-connect/adapters/oauth-gateway/InMemoryOAuthGateway.ts +++ b/back/src/domains/core/authentication/inclusion-connect/adapters/oauth-gateway/InMemoryOAuthGateway.ts @@ -1,6 +1,6 @@ import { AbsoluteUrl, - OAuthProvider, + OAuthGatewayProvider, WithIdToken, queryParamsAsString, } from "shared"; @@ -28,9 +28,9 @@ export class InMemoryOAuthGateway implements OAuthGateway { public async getLoginUrl( params: GetLoginUrlParams, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { - const loginUri: Record = { + const loginUri: Record = { InclusionConnect: `${this.providerConfig.providerBaseUri}/login-inclusion-connect`, ProConnect: `${this.providerConfig.providerBaseUri}/login-pro-connect`, }; @@ -39,7 +39,7 @@ export class InMemoryOAuthGateway implements OAuthGateway { public async getAccessToken( _: GetAccessTokenParams, - __: OAuthProvider, + __: OAuthGatewayProvider, ): Promise { if (this.#getAccessTokenResult) return this.#getAccessTokenResult; throw new Error("No access token provided (in memory)"); @@ -47,11 +47,11 @@ export class InMemoryOAuthGateway implements OAuthGateway { public async getLogoutUrl( params: WithIdToken, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise { - const logoutUri: Record = { + const logoutUri: Record = { InclusionConnect: `${this.providerConfig.providerBaseUri}/logout-inclusion-connect`, - ProConnect: `${this.providerConfig.providerBaseUri}/logout-pro-connect`, // TODO + ProConnect: `${this.providerConfig.providerBaseUri}/logout-pro-connect`, }; return `${logoutUri[provider]}?${queryParamsAsString({ diff --git a/back/src/domains/core/authentication/inclusion-connect/port/OAuthGateway.ts b/back/src/domains/core/authentication/inclusion-connect/port/OAuthGateway.ts index a7b45ddb23..0ca9ddd1b7 100644 --- a/back/src/domains/core/authentication/inclusion-connect/port/OAuthGateway.ts +++ b/back/src/domains/core/authentication/inclusion-connect/port/OAuthGateway.ts @@ -4,7 +4,7 @@ import { ExternalId, FeatureFlags, IdToken, - OAuthProvider, + OAuthGatewayProvider, WithIdToken, WithSourcePage, } from "shared"; @@ -35,20 +35,22 @@ export type GetLoginUrlParams = WithSourcePage & { state: string; }; -export const oAuthModeByFeatureFlags = (flags: FeatureFlags): OAuthProvider => +export const oAuthProviderByFeatureFlags = ( + flags: FeatureFlags, +): OAuthGatewayProvider => flags.enableProConnect.isActive ? "ProConnect" : "InclusionConnect"; export interface OAuthGateway { getLoginUrl( params: GetLoginUrlParams, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise; getAccessToken: ( params: GetAccessTokenParams, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ) => Promise; getLogoutUrl( params: WithIdToken, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise; } diff --git a/back/src/domains/core/authentication/inclusion-connect/port/UserRepository.ts b/back/src/domains/core/authentication/inclusion-connect/port/UserRepository.ts index 54c831318b..89c1d10333 100644 --- a/back/src/domains/core/authentication/inclusion-connect/port/UserRepository.ts +++ b/back/src/domains/core/authentication/inclusion-connect/port/UserRepository.ts @@ -3,7 +3,7 @@ import { AgencyRight, Email, InclusionConnectedUser, - OAuthProvider, + OAuthGatewayProvider, User, UserId, WithAgencyRole, @@ -16,19 +16,22 @@ export type InclusionConnectedFilters = Partial & { export interface UserRepository { delete(id: UserId): Promise; - save(user: User, provider: OAuthProvider): Promise; + save(user: User, provider: OAuthGatewayProvider): Promise; findByExternalId( externalId: string, - provider: OAuthProvider, + provider: OAuthGatewayProvider, + ): Promise; + findByEmail( + email: Email, + provider: OAuthGatewayProvider, ): Promise; - findByEmail(email: Email, provider: OAuthProvider): Promise; getWithFilter( filters: InclusionConnectedFilters, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise; getById( userId: string, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ): Promise; updateAgencyRights(params: { userId: UserId; diff --git a/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.integration.test.ts b/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.integration.test.ts index 1265048a74..afe3b34c19 100644 --- a/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.integration.test.ts +++ b/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.integration.test.ts @@ -1,9 +1,9 @@ import { Pool } from "pg"; import { AbsoluteUrl, - OAuthProvider, + OAuthGatewayProvider, expectObjectsToMatch, - oAuthProviders, + oAuthGatewayProviders, } from "shared"; import { KyselyDb, @@ -67,7 +67,7 @@ describe("AuthenticateWithInclusionCode use case", () => { await pool.end(); }); - describe.each(oAuthProviders)( + describe.each(oAuthGatewayProviders)( "when user had never connected before with mode '%s'", (mode) => { beforeEach(async () => { @@ -124,7 +124,7 @@ describe("AuthenticateWithInclusionCode use case", () => { ); const makeSuccessfulAuthenticationConditions = async ( - provider: OAuthProvider, + provider: OAuthGatewayProvider, expectedIcIdTokenPayload = defaultExpectedIcIdTokenPayload, ) => { const initialOngoingOAuth: OngoingOAuth = { diff --git a/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.ts b/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.ts index 8afda054ee..557c314f1b 100644 --- a/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.ts +++ b/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.ts @@ -5,7 +5,7 @@ import { AuthenticatedUserQueryParams, IdentityProvider, OAuthCode, - OAuthProvider, + OAuthGatewayProvider, User, WithSourcePage, authenticateWithOAuthCodeSchema, @@ -26,7 +26,7 @@ import { OngoingOAuth } from "../entities/OngoingOAuth"; import { GetAccessTokenPayload, OAuthGateway, - oAuthModeByFeatureFlags, + oAuthProviderByFeatureFlags, } from "../port/OAuthGateway"; type ConnectedRedirectUrl = AbsoluteUrl; @@ -71,7 +71,7 @@ export class AuthenticateWithInclusionCode extends TransactionalUseCase< { code, page, state }: AuthenticateWithOAuthCodeParams, uow: UnitOfWork, ): Promise { - const mode = oAuthModeByFeatureFlags( + const mode = oAuthProviderByFeatureFlags( await uow.featureFlagRepository.getAll(), ); const identityProvider: IdentityProvider = @@ -93,7 +93,7 @@ export class AuthenticateWithInclusionCode extends TransactionalUseCase< async #onOngoingOAuth( uow: UnitOfWork, - provider: OAuthProvider, + provider: OAuthGatewayProvider, { code, page }: WithSourcePage & { code: OAuthCode }, existingOngoingOAuth: OngoingOAuth, ): Promise { @@ -190,7 +190,7 @@ export class AuthenticateWithInclusionCode extends TransactionalUseCase< async #makeExistingUser( uow: UnitOfWork, - provider: OAuthProvider, + provider: OAuthGatewayProvider, existingInclusionConnectedUser: User | undefined, userWithSameEmail: User | undefined, ): Promise { @@ -239,7 +239,7 @@ export class AuthenticateWithInclusionCode extends TransactionalUseCase< async #updateUserAgencyRights( uow: UnitOfWork, - provider: OAuthProvider, + provider: OAuthGatewayProvider, conflictingUser: User, userToKeep: User, ): Promise { diff --git a/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.unit.test.ts b/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.unit.test.ts index d488739b42..f1b95c4360 100644 --- a/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.unit.test.ts +++ b/back/src/domains/core/authentication/inclusion-connect/use-cases/AuthenticateWithInclusionCode.unit.test.ts @@ -3,7 +3,7 @@ import { AgencyDtoBuilder, AuthenticateWithOAuthCodeParams, IdToken, - OAuthProvider, + OAuthGatewayProvider, User, allowedStartInclusionConnectLoginPages, errors, @@ -11,7 +11,7 @@ import { expectPromiseToFailWithError, expectToEqual, frontRoutes, - oAuthProviders, + oAuthGatewayProviders, } from "shared"; import { v4 as uuid } from "uuid"; import { makeCreateNewEvent } from "../../../events/ports/EventBus"; @@ -47,331 +47,339 @@ describe("AuthenticateWithInclusionCode use case", () => { let uuidGenerator: TestUuidGenerator; let authenticateWithInclusionCode: AuthenticateWithInclusionCode; - describe.each(oAuthProviders)("With OAuthGateway mode '%s'", (mode) => { - beforeEach(() => { - uow = createInMemoryUow(); - uuidGenerator = new TestUuidGenerator(); - const timeGateway = new CustomTimeGateway(); - inclusionConnectGateway = new InMemoryOAuthGateway(fakeProviderConfig); - authenticateWithInclusionCode = new AuthenticateWithInclusionCode( - new InMemoryUowPerformer(uow), - makeCreateNewEvent({ - timeGateway: new CustomTimeGateway(), + describe.each(oAuthGatewayProviders)( + "With OAuthGateway provider '%s'", + (provider) => { + beforeEach(() => { + uow = createInMemoryUow(); + uuidGenerator = new TestUuidGenerator(); + const timeGateway = new CustomTimeGateway(); + inclusionConnectGateway = new InMemoryOAuthGateway(fakeProviderConfig); + authenticateWithInclusionCode = new AuthenticateWithInclusionCode( + new InMemoryUowPerformer(uow), + makeCreateNewEvent({ + timeGateway: new CustomTimeGateway(), + uuidGenerator, + }), + inclusionConnectGateway, uuidGenerator, - }), - inclusionConnectGateway, - uuidGenerator, - () => correctToken, - immersionBaseUrl, - timeGateway, - ); - - uow.featureFlagRepository.update({ - flagName: "enableProConnect", - featureFlag: { kind: "boolean", isActive: mode === "ProConnect" }, - }); - }); - - describe("right paths", () => { - describe("when user had never connected before", () => { - it("saves the user as Authenticated user", async () => { - const { initialOngoingOAuth, userId } = - makeSuccessfulAuthenticationConditions(mode); - - await authenticateWithInclusionCode.execute({ - code: "my-inclusion-code", - state: initialOngoingOAuth.state, - page: "agencyDashboard", - }); + () => correctToken, + immersionBaseUrl, + timeGateway, + ); - expectObjectInArrayToMatch(uow.userRepository.users, [ - { - id: userId, - firstName: defaultExpectedIcIdTokenPayload.firstName, - lastName: defaultExpectedIcIdTokenPayload.lastName, - email: defaultExpectedIcIdTokenPayload.email, - externalId: defaultExpectedIcIdTokenPayload.sub, - }, - ]); + uow.featureFlagRepository.update({ + flagName: "enableProConnect", + featureFlag: { kind: "boolean", isActive: provider === "ProConnect" }, }); + }); - it("updates ongoingOAuth with userId, accessToken and externalId", async () => { - const { accessToken, initialOngoingOAuth, userId } = - makeSuccessfulAuthenticationConditions(mode); + describe("right paths", () => { + describe("when user had never connected before", () => { + it("saves the user as Authenticated user", async () => { + const { initialOngoingOAuth, userId } = + makeSuccessfulAuthenticationConditions(provider); - await authenticateWithInclusionCode.execute({ - code: "my-inclusion-code", - state: initialOngoingOAuth.state, - page: "agencyDashboard", - }); + await authenticateWithInclusionCode.execute({ + code: "my-inclusion-code", + state: initialOngoingOAuth.state, + page: "agencyDashboard", + }); - expectToEqual(uow.ongoingOAuthRepository.ongoingOAuths, [ - { - ...initialOngoingOAuth, - accessToken, - userId, - externalId: defaultExpectedIcIdTokenPayload.sub, - }, - ]); - }); + expectObjectInArrayToMatch(uow.userRepository.users, [ + { + id: userId, + firstName: defaultExpectedIcIdTokenPayload.firstName, + lastName: defaultExpectedIcIdTokenPayload.lastName, + email: defaultExpectedIcIdTokenPayload.email, + externalId: defaultExpectedIcIdTokenPayload.sub, + }, + ]); + }); - it("saves UserConnectedSuccessfully event with relevant data", async () => { - const { initialOngoingOAuth, userId } = - makeSuccessfulAuthenticationConditions(mode); + it("updates ongoingOAuth with userId, accessToken and externalId", async () => { + const { accessToken, initialOngoingOAuth, userId } = + makeSuccessfulAuthenticationConditions(provider); - await authenticateWithInclusionCode.execute({ - code: "my-inclusion-code", - state: initialOngoingOAuth.state, - page: "agencyDashboard", - }); + await authenticateWithInclusionCode.execute({ + code: "my-inclusion-code", + state: initialOngoingOAuth.state, + page: "agencyDashboard", + }); - expectObjectInArrayToMatch(uow.outboxRepository.events, [ - { - topic: "UserAuthenticatedSuccessfully", - payload: { - provider: initialOngoingOAuth.provider, + expectToEqual(uow.ongoingOAuthRepository.ongoingOAuths, [ + { + ...initialOngoingOAuth, + accessToken, userId, - codeSafir: null, - triggeredBy: { - kind: "inclusion-connected", - userId, - }, + externalId: defaultExpectedIcIdTokenPayload.sub, }, - }, - ]); - }); - }); - - describe("when user has already exists as an Authenticated User", () => { - it("updates the user as Authenticated user", async () => { - const { initialOngoingOAuth } = - makeSuccessfulAuthenticationConditions(mode); - const { alreadyExistingUser } = - addAlreadyExistingAuthenticatedUserInRepo(); - - expectObjectInArrayToMatch(uow.userRepository.users, [ - { - id: alreadyExistingUser.id, - email: alreadyExistingUser.email, - firstName: alreadyExistingUser.firstName, - lastName: alreadyExistingUser.lastName, - externalId: alreadyExistingUser.externalId, - }, - ]); - - await authenticateWithInclusionCode.execute({ - code: "my-inclusion-code", - state: initialOngoingOAuth.state, - page: "agencyDashboard", + ]); }); - expectObjectInArrayToMatch(uow.userRepository.users, [ - { - id: alreadyExistingUser.id, - email: defaultExpectedIcIdTokenPayload.email, - firstName: defaultExpectedIcIdTokenPayload.firstName, - lastName: defaultExpectedIcIdTokenPayload.lastName, - externalId: alreadyExistingUser.externalId, - }, - ]); - }); - it("also work if the existing user was not inclusion connected (no externalId)", async () => { - const { alreadyExistingUser } = - addAlreadyExistingAuthenticatedUserInRepo({ - externalId: null, - }); - const { initialOngoingOAuth } = - makeSuccessfulAuthenticationConditions(mode, { - email: alreadyExistingUser.email, - }); + it("saves UserConnectedSuccessfully event with relevant data", async () => { + const { initialOngoingOAuth, userId } = + makeSuccessfulAuthenticationConditions(provider); - expectObjectInArrayToMatch(uow.userRepository.users, [ - { - id: alreadyExistingUser.id, - email: alreadyExistingUser.email, - firstName: alreadyExistingUser.firstName, - lastName: alreadyExistingUser.lastName, - externalId: null, - }, - ]); + await authenticateWithInclusionCode.execute({ + code: "my-inclusion-code", + state: initialOngoingOAuth.state, + page: "agencyDashboard", + }); - await authenticateWithInclusionCode.execute({ - code: "my-inclusion-code", - state: initialOngoingOAuth.state, - page: "agencyDashboard", + expectObjectInArrayToMatch(uow.outboxRepository.events, [ + { + topic: "UserAuthenticatedSuccessfully", + payload: { + provider: initialOngoingOAuth.provider, + userId, + codeSafir: null, + triggeredBy: { + kind: "inclusion-connected", + userId, + }, + }, + }, + ]); }); - - expectObjectInArrayToMatch(uow.userRepository.users, [ - { - id: alreadyExistingUser.id, - email: alreadyExistingUser.email, - firstName: defaultExpectedIcIdTokenPayload.firstName, - lastName: defaultExpectedIcIdTokenPayload.lastName, - externalId: defaultExpectedIcIdTokenPayload.sub, - }, - ]); }); - it("when user change its email on inclusion connect", async () => { - const externalId = uuid(); - - const initialUser: User = { - id: uuid(), - email: "initial@mail.com", - externalId, - firstName: "Billy", - lastName: "Idol", - createdAt: new Date().toISOString(), - }; - - const previousMigrationUserWithUpdatedEmail: User = { - id: uuid(), - email: "updated@mail.com", - externalId: null, - firstName: "", - lastName: "", - createdAt: new Date().toISOString(), - }; - - uow.userRepository.users = [ - initialUser, - previousMigrationUserWithUpdatedEmail, - ]; - - const agency1 = new AgencyDtoBuilder().withId(uuid()).build(); - const agency2 = new AgencyDtoBuilder().withId(uuid()).build(); + describe("when user has already exists as an Authenticated User", () => { + it("updates the user as Authenticated user", async () => { + const { initialOngoingOAuth } = + makeSuccessfulAuthenticationConditions(provider); + const { alreadyExistingUser } = + addAlreadyExistingAuthenticatedUserInRepo(); - uow.userRepository.agencyRightsByUserId = { - [initialUser.id]: [ - { - agency: agency1, - isNotifiedByEmail: false, - roles: ["counsellor"], - }, - ], - [previousMigrationUserWithUpdatedEmail.id]: [ - { - agency: agency1, - isNotifiedByEmail: true, - roles: ["validator"], - }, + expectObjectInArrayToMatch(uow.userRepository.users, [ { - agency: agency2, - isNotifiedByEmail: true, - roles: ["counsellor"], + id: alreadyExistingUser.id, + email: alreadyExistingUser.email, + firstName: alreadyExistingUser.firstName, + lastName: alreadyExistingUser.lastName, + externalId: alreadyExistingUser.externalId, }, - ], - }; + ]); - const updatedUser: User = { - id: initialUser.id, - email: previousMigrationUserWithUpdatedEmail.email, - firstName: "Martine", - lastName: "Duflot", - externalId, - createdAt: initialUser.createdAt, - }; + await authenticateWithInclusionCode.execute({ + code: "my-inclusion-code", + state: initialOngoingOAuth.state, + page: "agencyDashboard", + }); - await authenticateWithInclusionCode.execute({ - code: "my-inclusion-code", - state: makeSuccessfulAuthenticationConditions(mode, { - email: updatedUser.email, - firstName: updatedUser.firstName, - lastName: updatedUser.lastName, - sub: externalId, - }).initialOngoingOAuth.state, - page: "agencyDashboard", + expectObjectInArrayToMatch(uow.userRepository.users, [ + { + id: alreadyExistingUser.id, + email: defaultExpectedIcIdTokenPayload.email, + firstName: defaultExpectedIcIdTokenPayload.firstName, + lastName: defaultExpectedIcIdTokenPayload.lastName, + externalId: alreadyExistingUser.externalId, + }, + ]); }); + it("also work if the existing user was not inclusion connected (no externalId)", async () => { + const { alreadyExistingUser } = + addAlreadyExistingAuthenticatedUserInRepo({ + externalId: null, + }); + const { initialOngoingOAuth } = + makeSuccessfulAuthenticationConditions(provider, { + email: alreadyExistingUser.email, + }); - expectObjectInArrayToMatch(uow.userRepository.users, [updatedUser]); - expectToEqual(uow.userRepository.agencyRightsByUserId, { - [initialUser.id]: [ + expectObjectInArrayToMatch(uow.userRepository.users, [ { - agency: agency1, - isNotifiedByEmail: true, - roles: ["counsellor", "validator"], + id: alreadyExistingUser.id, + email: alreadyExistingUser.email, + firstName: alreadyExistingUser.firstName, + lastName: alreadyExistingUser.lastName, + externalId: null, }, + ]); + + await authenticateWithInclusionCode.execute({ + code: "my-inclusion-code", + state: initialOngoingOAuth.state, + page: "agencyDashboard", + }); + + expectObjectInArrayToMatch(uow.userRepository.users, [ { - agency: agency2, - isNotifiedByEmail: true, - roles: ["counsellor"], + id: alreadyExistingUser.id, + email: alreadyExistingUser.email, + firstName: defaultExpectedIcIdTokenPayload.firstName, + lastName: defaultExpectedIcIdTokenPayload.lastName, + externalId: defaultExpectedIcIdTokenPayload.sub, }, - ], + ]); }); - }); - }); - - describe("handle dynamic login pages", () => { - it.each(allowedStartInclusionConnectLoginPages)( - "generates an app token and returns a redirection url which includes token and user data for %s", - async (page) => { - const { initialOngoingOAuth } = - makeSuccessfulAuthenticationConditions(mode); - const redirectedUrl = await authenticateWithInclusionCode.execute({ + it("when user change its email on inclusion connect", async () => { + const externalId = uuid(); + + const initialUser: User = { + id: uuid(), + email: "initial@mail.com", + externalId, + firstName: "Billy", + lastName: "Idol", + createdAt: new Date().toISOString(), + }; + + const previousMigrationUserWithUpdatedEmail: User = { + id: uuid(), + email: "updated@mail.com", + externalId: null, + firstName: "", + lastName: "", + createdAt: new Date().toISOString(), + }; + + uow.userRepository.users = [ + initialUser, + previousMigrationUserWithUpdatedEmail, + ]; + + const agency1 = new AgencyDtoBuilder().withId(uuid()).build(); + const agency2 = new AgencyDtoBuilder().withId(uuid()).build(); + + uow.userRepository.agencyRightsByUserId = { + [initialUser.id]: [ + { + agency: agency1, + isNotifiedByEmail: false, + roles: ["counsellor"], + }, + ], + [previousMigrationUserWithUpdatedEmail.id]: [ + { + agency: agency1, + isNotifiedByEmail: true, + roles: ["validator"], + }, + { + agency: agency2, + isNotifiedByEmail: true, + roles: ["counsellor"], + }, + ], + }; + + const updatedUser: User = { + id: initialUser.id, + email: previousMigrationUserWithUpdatedEmail.email, + firstName: "Martine", + lastName: "Duflot", + externalId, + createdAt: initialUser.createdAt, + }; + + await authenticateWithInclusionCode.execute({ code: "my-inclusion-code", - state: initialOngoingOAuth.state, - page, + state: makeSuccessfulAuthenticationConditions(provider, { + email: updatedUser.email, + firstName: updatedUser.firstName, + lastName: updatedUser.lastName, + sub: externalId, + }).initialOngoingOAuth.state, + page: "agencyDashboard", }); - expect(redirectedUrl).toBe( - `${immersionBaseUrl}/${frontRoutes[page]}?token=${correctToken}&firstName=John&lastName=Doe&email=john.doe@inclusion.com&idToken=inclusion-connect-id-token`, - ); - }, - ); - }); - }); + expectObjectInArrayToMatch(uow.userRepository.users, [updatedUser]); + expectToEqual(uow.userRepository.agencyRightsByUserId, { + [initialUser.id]: [ + { + agency: agency1, + isNotifiedByEmail: true, + roles: ["counsellor", "validator"], + }, + { + agency: agency2, + isNotifiedByEmail: true, + roles: ["counsellor"], + }, + ], + }); + }); + }); - describe("wrong paths", () => { - it("rejects the connection if no state match the provided one in DB", async () => { - const params: AuthenticateWithOAuthCodeParams = { - code: "my-inclusion-code", - state: "my-state", - page: "agencyDashboard", - }; - await expectPromiseToFailWithError( - authenticateWithInclusionCode.execute(params), - errors.inclusionConnect.missingOAuth({ - state: params.state, - identityProvider: - mode === "InclusionConnect" ? "inclusionConnect" : "proConnect", - }), - ); - }); + describe("handle dynamic login pages", () => { + it.each(allowedStartInclusionConnectLoginPages)( + "generates an app token and returns a redirection url which includes token and user data for %s", + async (page) => { + const { initialOngoingOAuth } = + makeSuccessfulAuthenticationConditions(provider); + + const redirectedUrl = await authenticateWithInclusionCode.execute( + { + code: "my-inclusion-code", + state: initialOngoingOAuth.state, + page, + }, + ); - it("should raise a Forbidden error if the nonce does not match", async () => { - const existingNonce = "existing-nonce"; - const initialOngoingOAuth: OngoingOAuth = { - provider: mode === "ProConnect" ? "proConnect" : "inclusionConnect", - state: "my-state", - nonce: existingNonce, - }; - uow.ongoingOAuthRepository.ongoingOAuths = [initialOngoingOAuth]; - - const accessToken = "inclusion-access-token"; - const idToken: IdToken = "inclusion-connect-id-token"; - - inclusionConnectGateway.setAccessTokenResponse({ - expire: 60, - payload: defaultExpectedIcIdTokenPayload, - accessToken, - idToken, + expect(redirectedUrl).toBe( + `${immersionBaseUrl}/${frontRoutes[page]}?token=${correctToken}&firstName=John&lastName=Doe&email=john.doe@inclusion.com&idToken=inclusion-connect-id-token`, + ); + }, + ); }); + }); - await expectPromiseToFailWithError( - authenticateWithInclusionCode.execute({ + describe("wrong paths", () => { + it("rejects the connection if no state match the provided one in DB", async () => { + const params: AuthenticateWithOAuthCodeParams = { code: "my-inclusion-code", state: "my-state", page: "agencyDashboard", - }), - errors.inclusionConnect.nonceMismatch(), - ); + }; + await expectPromiseToFailWithError( + authenticateWithInclusionCode.execute(params), + errors.inclusionConnect.missingOAuth({ + state: params.state, + identityProvider: + provider === "InclusionConnect" + ? "inclusionConnect" + : "proConnect", + }), + ); + }); + + it("should raise a Forbidden error if the nonce does not match", async () => { + const existingNonce = "existing-nonce"; + const initialOngoingOAuth: OngoingOAuth = { + provider: + provider === "ProConnect" ? "proConnect" : "inclusionConnect", + state: "my-state", + nonce: existingNonce, + }; + uow.ongoingOAuthRepository.ongoingOAuths = [initialOngoingOAuth]; + + const accessToken = "inclusion-access-token"; + const idToken: IdToken = "inclusion-connect-id-token"; + + inclusionConnectGateway.setAccessTokenResponse({ + expire: 60, + payload: defaultExpectedIcIdTokenPayload, + accessToken, + idToken, + }); + + await expectPromiseToFailWithError( + authenticateWithInclusionCode.execute({ + code: "my-inclusion-code", + state: "my-state", + page: "agencyDashboard", + }), + errors.inclusionConnect.nonceMismatch(), + ); + }); }); - }); - }); + }, + ); const makeSuccessfulAuthenticationConditions = ( - mode: OAuthProvider, + provider: OAuthGatewayProvider, params?: Partial, ) => { const expectedIcIdTokenPayload = { @@ -379,7 +387,8 @@ describe("AuthenticateWithInclusionCode use case", () => { ...params, }; const initialOngoingOAuth: OngoingOAuth = { - provider: mode === "InclusionConnect" ? "inclusionConnect" : "proConnect", + provider: + provider === "InclusionConnect" ? "inclusionConnect" : "proConnect", state: "my-state", nonce: "nounce", // matches the one in the payload of the token }; diff --git a/back/src/domains/core/authentication/inclusion-connect/use-cases/GetInclusionConnectLogoutUrl.ts b/back/src/domains/core/authentication/inclusion-connect/use-cases/GetInclusionConnectLogoutUrl.ts index 16c9847c59..ecc177cc02 100644 --- a/back/src/domains/core/authentication/inclusion-connect/use-cases/GetInclusionConnectLogoutUrl.ts +++ b/back/src/domains/core/authentication/inclusion-connect/use-cases/GetInclusionConnectLogoutUrl.ts @@ -2,7 +2,10 @@ import { AbsoluteUrl, WithIdToken, withIdTokenSchema } from "shared"; import { TransactionalUseCase } from "../../../UseCase"; import { UnitOfWork } from "../../../unit-of-work/ports/UnitOfWork"; import { UnitOfWorkPerformer } from "../../../unit-of-work/ports/UnitOfWorkPerformer"; -import { OAuthGateway, oAuthModeByFeatureFlags } from "../port/OAuthGateway"; +import { + OAuthGateway, + oAuthProviderByFeatureFlags, +} from "../port/OAuthGateway"; export class GetInclusionConnectLogoutUrl extends TransactionalUseCase< WithIdToken, @@ -12,7 +15,7 @@ export class GetInclusionConnectLogoutUrl extends TransactionalUseCase< constructor( uowPerformer: UnitOfWorkPerformer, - private inclusionConnectGateway: OAuthGateway, + private oAuthGateway: OAuthGateway, ) { super(uowPerformer); } @@ -21,9 +24,9 @@ export class GetInclusionConnectLogoutUrl extends TransactionalUseCase< params: WithIdToken, uow: UnitOfWork, ): Promise { - return this.inclusionConnectGateway.getLogoutUrl( + return this.oAuthGateway.getLogoutUrl( params, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); } } diff --git a/back/src/domains/core/authentication/inclusion-connect/use-cases/GetInclusionConnectLogoutUrl.unit.test.ts b/back/src/domains/core/authentication/inclusion-connect/use-cases/GetInclusionConnectLogoutUrl.unit.test.ts index 32a94aefff..700c6e0759 100644 --- a/back/src/domains/core/authentication/inclusion-connect/use-cases/GetInclusionConnectLogoutUrl.unit.test.ts +++ b/back/src/domains/core/authentication/inclusion-connect/use-cases/GetInclusionConnectLogoutUrl.unit.test.ts @@ -1,4 +1,8 @@ -import { expectToEqual, oAuthProviders, queryParamsAsString } from "shared"; +import { + expectToEqual, + oAuthGatewayProviders, + queryParamsAsString, +} from "shared"; import { InMemoryUowPerformer } from "../../../unit-of-work/adapters/InMemoryUowPerformer"; import { InMemoryUnitOfWork, @@ -11,40 +15,43 @@ import { import { GetInclusionConnectLogoutUrl } from "./GetInclusionConnectLogoutUrl"; describe("GetInclusionConnectLogoutUrl", () => { - describe.each(oAuthProviders)("With OAuthGateway mode '%s'", (provider) => { - let uow: InMemoryUnitOfWork; - let getInclusionConnectLogoutUrl: GetInclusionConnectLogoutUrl; + describe.each(oAuthGatewayProviders)( + "With OAuthGateway provider '%s'", + (provider) => { + let uow: InMemoryUnitOfWork; + let getInclusionConnectLogoutUrl: GetInclusionConnectLogoutUrl; - beforeEach(() => { - uow = createInMemoryUow(); - getInclusionConnectLogoutUrl = new GetInclusionConnectLogoutUrl( - new InMemoryUowPerformer(uow), - new InMemoryOAuthGateway(fakeProviderConfig), - ); + beforeEach(() => { + uow = createInMemoryUow(); + getInclusionConnectLogoutUrl = new GetInclusionConnectLogoutUrl( + new InMemoryUowPerformer(uow), + new InMemoryOAuthGateway(fakeProviderConfig), + ); - uow.featureFlagRepository.update({ - flagName: "enableProConnect", - featureFlag: { isActive: provider === "ProConnect", kind: "boolean" }, + uow.featureFlagRepository.update({ + flagName: "enableProConnect", + featureFlag: { isActive: provider === "ProConnect", kind: "boolean" }, + }); }); - }); - it("returns the inclusion connect logout url from %s", async () => { - const logoutSuffixe = - provider === "ProConnect" ? "pro-connect" : "inclusion-connect"; - const idToken = "fake-id-token"; - expectToEqual( - await getInclusionConnectLogoutUrl.execute({ - idToken, - }), - `${ - fakeProviderConfig.providerBaseUri - }/logout-${logoutSuffixe}?${queryParamsAsString({ - postLogoutRedirectUrl: - fakeProviderConfig.immersionRedirectUri.afterLogout, - clientId: fakeProviderConfig.clientId, - idToken, - })}`, - ); - }); - }); + it("returns the inclusion connect logout url from %s", async () => { + const logoutSuffixe = + provider === "ProConnect" ? "pro-connect" : "inclusion-connect"; + const idToken = "fake-id-token"; + expectToEqual( + await getInclusionConnectLogoutUrl.execute({ + idToken, + }), + `${ + fakeProviderConfig.providerBaseUri + }/logout-${logoutSuffixe}?${queryParamsAsString({ + postLogoutRedirectUrl: + fakeProviderConfig.immersionRedirectUri.afterLogout, + clientId: fakeProviderConfig.clientId, + idToken, + })}`, + ); + }); + }, + ); }); diff --git a/back/src/domains/core/authentication/inclusion-connect/use-cases/InitiateInclusionConnect.ts b/back/src/domains/core/authentication/inclusion-connect/use-cases/InitiateInclusionConnect.ts index 348c2aea2c..964b837797 100644 --- a/back/src/domains/core/authentication/inclusion-connect/use-cases/InitiateInclusionConnect.ts +++ b/back/src/domains/core/authentication/inclusion-connect/use-cases/InitiateInclusionConnect.ts @@ -3,7 +3,10 @@ import { TransactionalUseCase } from "../../../UseCase"; import { UnitOfWork } from "../../../unit-of-work/ports/UnitOfWork"; import { UnitOfWorkPerformer } from "../../../unit-of-work/ports/UnitOfWorkPerformer"; import { UuidGenerator } from "../../../uuid-generator/ports/UuidGenerator"; -import { OAuthGateway, oAuthModeByFeatureFlags } from "../port/OAuthGateway"; +import { + OAuthGateway, + oAuthProviderByFeatureFlags, +} from "../port/OAuthGateway"; export class InitiateInclusionConnect extends TransactionalUseCase< WithSourcePage, @@ -26,7 +29,7 @@ export class InitiateInclusionConnect extends TransactionalUseCase< const nonce = this.uuidGenerator.new(); const state = this.uuidGenerator.new(); - const provider = oAuthModeByFeatureFlags( + const provider = oAuthProviderByFeatureFlags( await uow.featureFlagRepository.getAll(), ); diff --git a/back/src/domains/core/authentication/inclusion-connect/use-cases/InitiateInclusionConnect.unit.test.ts b/back/src/domains/core/authentication/inclusion-connect/use-cases/InitiateInclusionConnect.unit.test.ts index 351b96b5a6..cbe67321b0 100644 --- a/back/src/domains/core/authentication/inclusion-connect/use-cases/InitiateInclusionConnect.unit.test.ts +++ b/back/src/domains/core/authentication/inclusion-connect/use-cases/InitiateInclusionConnect.unit.test.ts @@ -2,7 +2,7 @@ import { WithSourcePage, allowedStartInclusionConnectLoginPages, expectToEqual, - oAuthProviders, + oAuthGatewayProviders, queryParamsAsString, } from "shared"; import { InMemoryUowPerformer } from "../../../unit-of-work/adapters/InMemoryUowPerformer"; @@ -15,64 +15,67 @@ import { import { InitiateInclusionConnect } from "./InitiateInclusionConnect"; describe("InitiateInclusionConnect usecase", () => { - describe.each(oAuthProviders)("With OAuthGateway mode '%s'", (provider) => { - it.each(allowedStartInclusionConnectLoginPages)( - "construct redirect url for %s with expected query params, and stores nounce and state in ongoingOAuth", - async (page) => { - const state = "my-state"; - const nonce = "my-nonce"; - const uow = createInMemoryUow(); - const uuidGenerator = new TestUuidGenerator(); - const useCase = new InitiateInclusionConnect( - new InMemoryUowPerformer(uow), - uuidGenerator, - new InMemoryOAuthGateway(fakeProviderConfig), - ); - await uow.featureFlagRepository.update({ - flagName: "enableProConnect", - featureFlag: { - isActive: provider === "ProConnect", - kind: "boolean", - }, - }); + describe.each(oAuthGatewayProviders)( + "With OAuthGateway mode '%s'", + (provider) => { + it.each(allowedStartInclusionConnectLoginPages)( + "construct redirect url for %s with expected query params, and stores nounce and state in ongoingOAuth", + async (page) => { + const state = "my-state"; + const nonce = "my-nonce"; + const uow = createInMemoryUow(); + const uuidGenerator = new TestUuidGenerator(); + const useCase = new InitiateInclusionConnect( + new InMemoryUowPerformer(uow), + uuidGenerator, + new InMemoryOAuthGateway(fakeProviderConfig), + ); + await uow.featureFlagRepository.update({ + flagName: "enableProConnect", + featureFlag: { + isActive: provider === "ProConnect", + kind: "boolean", + }, + }); - uuidGenerator.setNextUuids([nonce, state]); + uuidGenerator.setNextUuids([nonce, state]); - const sourcePage: WithSourcePage = { - page, - }; - const redirectUrl = await useCase.execute(sourcePage); - const loginEndpoint = - provider === "InclusionConnect" - ? "login-inclusion-connect" - : "login-pro-connect"; + const sourcePage: WithSourcePage = { + page, + }; + const redirectUrl = await useCase.execute(sourcePage); + const loginEndpoint = + provider === "InclusionConnect" + ? "login-inclusion-connect" + : "login-pro-connect"; - expectToEqual( - redirectUrl, - encodeURI( - `${ - fakeProviderConfig.providerBaseUri - }/${loginEndpoint}?${queryParamsAsString({ - page, + expectToEqual( + redirectUrl, + encodeURI( + `${ + fakeProviderConfig.providerBaseUri + }/${loginEndpoint}?${queryParamsAsString({ + page, + nonce, + state, + })}`, + ), + ); + + expectToEqual(uow.ongoingOAuthRepository.ongoingOAuths, [ + { nonce, state, - })}`, - ), - ); - - expectToEqual(uow.ongoingOAuthRepository.ongoingOAuths, [ - { - nonce, - state, - provider: - provider === "InclusionConnect" - ? "inclusionConnect" - : "proConnect", - externalId: undefined, - accessToken: undefined, - }, - ]); - }, - ); - }); + provider: + provider === "InclusionConnect" + ? "inclusionConnect" + : "proConnect", + externalId: undefined, + accessToken: undefined, + }, + ]); + }, + ); + }, + ); }); diff --git a/back/src/domains/establishment/use-cases/EditFormEstablishment.ts b/back/src/domains/establishment/use-cases/EditFormEstablishment.ts index 23180f5177..6aae830526 100644 --- a/back/src/domains/establishment/use-cases/EditFormEstablishment.ts +++ b/back/src/domains/establishment/use-cases/EditFormEstablishment.ts @@ -7,7 +7,7 @@ import { formEstablishmentSchema, } from "shared"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { CreateNewEvent } from "../../core/events/ports/EventBus"; import { UnitOfWork } from "../../core/unit-of-work/ports/UnitOfWork"; import { UnitOfWorkPerformer } from "../../core/unit-of-work/ports/UnitOfWorkPerformer"; @@ -75,7 +75,7 @@ export class EditFormEstablishment extends TransactionalUseCase< if ("userId" in jwtPayload) { const user = await uow.userRepository.getById( jwtPayload.userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!user) throw errors.user.notFound({ userId: jwtPayload.userId }); diff --git a/back/src/domains/establishment/use-cases/RetrieveFormEstablishmentFromAggregates.ts b/back/src/domains/establishment/use-cases/RetrieveFormEstablishmentFromAggregates.ts index 6e74b5a175..f0b95a723c 100644 --- a/back/src/domains/establishment/use-cases/RetrieveFormEstablishmentFromAggregates.ts +++ b/back/src/domains/establishment/use-cases/RetrieveFormEstablishmentFromAggregates.ts @@ -9,7 +9,7 @@ import { siretSchema, } from "shared"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { UnitOfWork } from "../../core/unit-of-work/ports/UnitOfWork"; import { EstablishmentAggregate } from "../entities/EstablishmentEntity"; @@ -43,7 +43,7 @@ export class RetrieveFormEstablishmentFromAggregates extends TransactionalUseCas if (isValidIcJwtPayload) { const currentUser = await uow.userRepository.getById( jwtPayload.userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!currentUser) throw errors.user.notFound({ userId: jwtPayload.userId }); diff --git a/back/src/domains/establishment/use-cases/discussions/GetDiscussionByIdForEstablishment.ts b/back/src/domains/establishment/use-cases/discussions/GetDiscussionByIdForEstablishment.ts index 1b0307117a..63c17837c2 100644 --- a/back/src/domains/establishment/use-cases/discussions/GetDiscussionByIdForEstablishment.ts +++ b/back/src/domains/establishment/use-cases/discussions/GetDiscussionByIdForEstablishment.ts @@ -6,7 +6,7 @@ import { errors, } from "shared"; import { TransactionalUseCase } from "../../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../../core/authentication/inclusion-connect/port/OAuthGateway"; import { UnitOfWork } from "../../../core/unit-of-work/ports/UnitOfWork"; export class GetDiscussionByIdForEstablishment extends TransactionalUseCase< @@ -24,7 +24,7 @@ export class GetDiscussionByIdForEstablishment extends TransactionalUseCase< const user = await uow.userRepository.getById( jwtPayload.userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!user) throw errors.user.notFound({ userId: jwtPayload.userId }); diff --git a/back/src/domains/inclusion-connected-users/helpers/throwIfIcUserNotBackofficeAdmin.ts b/back/src/domains/inclusion-connected-users/helpers/throwIfIcUserNotBackofficeAdmin.ts index a7dd1ddd22..e0e7bfbddd 100644 --- a/back/src/domains/inclusion-connected-users/helpers/throwIfIcUserNotBackofficeAdmin.ts +++ b/back/src/domains/inclusion-connected-users/helpers/throwIfIcUserNotBackofficeAdmin.ts @@ -5,7 +5,7 @@ import { errors, } from "shared"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { UnitOfWork } from "../../core/unit-of-work/ports/UnitOfWork"; export const throwIfIcUserNotBackofficeAdmin = async ( @@ -23,7 +23,7 @@ export const getIcUserOrThrow = async ( ): Promise => { const user = await uow.userRepository.getById( userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!user) throw errors.user.notFound({ userId }); return user; diff --git a/back/src/domains/inclusion-connected-users/use-cases/CreateUserForAgency.ts b/back/src/domains/inclusion-connected-users/use-cases/CreateUserForAgency.ts index 76395252d1..0982ef2ca0 100644 --- a/back/src/domains/inclusion-connected-users/use-cases/CreateUserForAgency.ts +++ b/back/src/domains/inclusion-connected-users/use-cases/CreateUserForAgency.ts @@ -6,7 +6,7 @@ import { userParamsForAgencySchema, } from "shared"; import { createTransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { DomainEvent } from "../../core/events/events"; import { CreateNewEvent } from "../../core/events/ports/EventBus"; import { TimeGateway } from "../../core/time-gateway/ports/TimeGateway"; @@ -36,7 +36,7 @@ export const makeCreateUserForAgency = createTransactionalUseCase< role: "validator", }); - const provider = oAuthModeByFeatureFlags( + const provider = oAuthProviderByFeatureFlags( await uow.featureFlagRepository.getAll(), ); const existingUser = ( diff --git a/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.ts b/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.ts index 733c8d678a..06c6d4aa5f 100644 --- a/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.ts +++ b/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUser.ts @@ -12,7 +12,7 @@ import { } from "shared"; import { z } from "zod"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { DashboardGateway } from "../../core/dashboard/port/DashboardGateway"; import { TimeGateway } from "../../core/time-gateway/ports/TimeGateway"; import { UnitOfWork } from "../../core/unit-of-work/ports/UnitOfWork"; @@ -49,7 +49,7 @@ export class GetInclusionConnectedUser extends TransactionalUseCase< const { userId } = jwtPayload; const user = await uow.userRepository.getById( userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!user) throw errors.user.notFound({ userId }); const establishments = await this.#withEstablishments(uow, user); diff --git a/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUsers.ts b/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUsers.ts index e3df4f44c7..87476a5fe0 100644 --- a/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUsers.ts +++ b/back/src/domains/inclusion-connected-users/use-cases/GetInclusionConnectedUsers.ts @@ -4,7 +4,7 @@ import { withUserFiltersSchema, } from "shared"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { UnitOfWork } from "../../core/unit-of-work/ports/UnitOfWork"; import { throwIfNotAdmin } from "../helpers/throwIfIcUserNotBackofficeAdmin"; @@ -23,7 +23,7 @@ export class GetInclusionConnectedUsers extends TransactionalUseCase< throwIfNotAdmin(currentUser); return uow.userRepository.getWithFilter( filters, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); } } diff --git a/back/src/domains/inclusion-connected-users/use-cases/LinkFranceTravailUsersToTheirAgencies.ts b/back/src/domains/inclusion-connected-users/use-cases/LinkFranceTravailUsersToTheirAgencies.ts index ec483127e4..7518c8be06 100644 --- a/back/src/domains/inclusion-connected-users/use-cases/LinkFranceTravailUsersToTheirAgencies.ts +++ b/back/src/domains/inclusion-connected-users/use-cases/LinkFranceTravailUsersToTheirAgencies.ts @@ -10,7 +10,7 @@ import { } from "shared"; import { z } from "zod"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { UserAuthenticatedPayload } from "../../core/events/events"; import { UnitOfWork } from "../../core/unit-of-work/ports/UnitOfWork"; @@ -30,7 +30,7 @@ export class LinkFranceTravailUsersToTheirAgencies extends TransactionalUseCase< if (!codeSafir) return; const icUser = await uow.userRepository.getById( userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!icUser) throw errors.user.notFound({ userId }); diff --git a/back/src/domains/inclusion-connected-users/use-cases/RejectIcUserForAgency.ts b/back/src/domains/inclusion-connected-users/use-cases/RejectIcUserForAgency.ts index 34bbad217c..46f72d05b0 100644 --- a/back/src/domains/inclusion-connected-users/use-cases/RejectIcUserForAgency.ts +++ b/back/src/domains/inclusion-connected-users/use-cases/RejectIcUserForAgency.ts @@ -5,7 +5,7 @@ import { rejectIcUserRoleForAgencyParamsSchema, } from "shared"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { DomainEvent } from "../../core/events/events"; import { CreateNewEvent } from "../../core/events/ports/EventBus"; import { UnitOfWork } from "../../core/unit-of-work/ports/UnitOfWork"; @@ -39,7 +39,7 @@ export class RejectIcUserForAgency extends TransactionalUseCase< const icUser = await uow.userRepository.getById( params.userId, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); if (!icUser) throw errors.user.notFound({ userId: params.userId }); diff --git a/back/src/domains/inclusion-connected-users/use-cases/UpdateUserForAgency.ts b/back/src/domains/inclusion-connected-users/use-cases/UpdateUserForAgency.ts index 20fcd26b04..4bb64cb4e3 100644 --- a/back/src/domains/inclusion-connected-users/use-cases/UpdateUserForAgency.ts +++ b/back/src/domains/inclusion-connected-users/use-cases/UpdateUserForAgency.ts @@ -3,14 +3,14 @@ import { AgencyRight, Email, InclusionConnectedUser, + OAuthGatewayProvider, UserParamsForAgency, - OAuthProvider, errors, replaceElementWhere, userParamsForAgencySchema, } from "shared"; import { TransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { UserRepository } from "../../core/authentication/inclusion-connect/port/UserRepository"; import { DomainEvent } from "../../core/events/events"; import { CreateNewEvent } from "../../core/events/ports/EventBus"; @@ -22,7 +22,7 @@ const rejectIfAgencyWontHaveValidators = async ( uow: UnitOfWork, params: UserParamsForAgency, agency: AgencyDto, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ) => { if ( (!params.roles.includes("validator") || !params.isNotifiedByEmail) && @@ -68,7 +68,7 @@ const rejectIfAgencyWithRefersToWontHaveCounsellors = async ( uow: UnitOfWork, params: UserParamsForAgency, agency: AgencyDto, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ) => { if ( (!params.roles.includes("counsellor") || !params.isNotifiedByEmail) && @@ -99,7 +99,7 @@ const makeAgencyRights = async ( uow: UnitOfWork, params: UserParamsForAgency, userToUpdate: InclusionConnectedUser, - provider: OAuthProvider, + provider: OAuthGatewayProvider, ) => { const agency = await uow.agencyRepository.getById(params.agencyId); @@ -185,7 +185,7 @@ export class UpdateUserForAgency extends TransactionalUseCase< currentUser: InclusionConnectedUser, ): Promise { throwIfNotAdmin(currentUser); - const mode = oAuthModeByFeatureFlags( + const mode = oAuthProviderByFeatureFlags( await uow.featureFlagRepository.getAll(), ); const userToUpdate = await uow.userRepository.getById(params.userId, mode); diff --git a/back/src/domains/marketing/use-cases/UpdateMarketingEstablishmentContactsList.ts b/back/src/domains/marketing/use-cases/UpdateMarketingEstablishmentContactsList.ts index e0f62491fe..231aa234f5 100644 --- a/back/src/domains/marketing/use-cases/UpdateMarketingEstablishmentContactsList.ts +++ b/back/src/domains/marketing/use-cases/UpdateMarketingEstablishmentContactsList.ts @@ -7,7 +7,7 @@ import { withSiretSchema, } from "shared"; import { createTransactionalUseCase } from "../../core/UseCase"; -import { oAuthModeByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; +import { oAuthProviderByFeatureFlags } from "../../core/authentication/inclusion-connect/port/OAuthGateway"; import { TimeGateway } from "../../core/time-gateway/ports/TimeGateway"; import { UnitOfWork } from "../../core/unit-of-work/ports/UnitOfWork"; import { EstablishmentAggregate } from "../../establishment/entities/EstablishmentEntity"; @@ -147,7 +147,7 @@ const onEstablishment = async ( const user = await uow.userRepository.findByEmail( marketingContact.email, - oAuthModeByFeatureFlags(await uow.featureFlagRepository.getAll()), + oAuthProviderByFeatureFlags(await uow.featureFlagRepository.getAll()), ); const hasIcAccount = !!user?.externalId; diff --git a/front/src/app/routes/InclusionConnectedPrivateRoute.tsx b/front/src/app/routes/InclusionConnectedPrivateRoute.tsx index f51b2da18f..78d93a88c7 100644 --- a/front/src/app/routes/InclusionConnectedPrivateRoute.tsx +++ b/front/src/app/routes/InclusionConnectedPrivateRoute.tsx @@ -9,7 +9,7 @@ import { } from "react-design-system"; import { useDispatch } from "react-redux"; import { - OAuthProvider, + OAuthGatewayProvider, domElementIds, inclusionConnectImmersionRoutes, queryParamsAsString, @@ -36,7 +36,7 @@ type InclusionConnectedPrivateRouteProps = { }; const providers: Record< - OAuthProvider, + OAuthGatewayProvider, { name: string; baseline: string; diff --git a/shared/src/oauth/oauth.dto.ts b/shared/src/oauth/oauth.dto.ts index b1c8487b6b..2abb2e9fe3 100644 --- a/shared/src/oauth/oauth.dto.ts +++ b/shared/src/oauth/oauth.dto.ts @@ -1,2 +1,5 @@ -export const oAuthProviders = ["InclusionConnect", "ProConnect"] as const; -export type OAuthProvider = (typeof oAuthProviders)[number]; +export const oAuthGatewayProviders = [ + "InclusionConnect", + "ProConnect", +] as const; +export type OAuthGatewayProvider = (typeof oAuthGatewayProviders)[number];