-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(identite): extract markDomainAsVerified function
- Loading branch information
1 parent
6ccd601
commit 6b7b7a4
Showing
50 changed files
with
784 additions
and
295 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// | ||
|
||
import { assert } from "chai"; | ||
import { getEmailDomain } from "./get-email-domain.js"; | ||
|
||
// | ||
|
||
describe(getEmailDomain.name, () => { | ||
const data = [ | ||
{ | ||
email: "[email protected]", | ||
domain: "beta.gouv.fr", | ||
}, | ||
{ | ||
email: "[email protected]", | ||
domain: "notaires.fr", | ||
}, | ||
{ | ||
email: "[email protected]", | ||
domain: "subdomain.domain.org", | ||
}, | ||
]; | ||
|
||
data.forEach(({ email, domain }) => { | ||
it("should return email domain", () => { | ||
assert.equal(getEmailDomain(email), domain); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// | ||
|
||
import { parse_host } from "tld-extract"; | ||
|
||
// | ||
|
||
export function getEmailDomain(email: string) { | ||
const parts = email.split("@"); | ||
const host = parts[parts.length - 1]; | ||
const { sub, domain } = parse_host(host, { allowDotlessTLD: true }); | ||
|
||
return [sub, domain].filter((e) => !!e).join("."); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
// | ||
|
||
export * from "./isAFreeDomain.js"; | ||
export * from "./get-email-domain.js"; | ||
export * from "./is-a-free-domain.js"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,12 @@ | ||
// | ||
|
||
declare module "tld-extract" { | ||
function parse_host(domain: string, { allowDotlessTLD: boolean }): boolean; | ||
function parse_host( | ||
domain: string, | ||
{ allowDotlessTLD: boolean }, | ||
): { | ||
tld: string; | ||
domain: string; | ||
sub: string; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion
2
...src/organization/get-organization-info.ts → ...ers/organization/get-organization-info.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/identite/src/organization/index.ts → ...entite/src/managers/organization/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
// | ||
|
||
export * from "./get-organization-info.js"; | ||
export * from "./upsert.js"; | ||
export * from "./mark-domain-as-verified.js"; |
115 changes: 115 additions & 0 deletions
115
packages/identite/src/managers/organization/mark-domain-as-verified.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { | ||
type AddDomainHandler, | ||
type FindEmailDomainsByOrganizationIdHandler, | ||
} from "#src/repositories/email-domain"; | ||
import type { | ||
FindByIdHandler, | ||
GetUsersByOrganizationHandler, | ||
} from "#src/repositories/organization"; | ||
import type { UpdateUserOrganizationLinkHandler } from "#src/repositories/user"; | ||
import type { | ||
BaseUserOrganizationLink, | ||
EmailDomain, | ||
Organization, | ||
User, | ||
UserOrganizationLink, | ||
} from "#src/types"; | ||
import * as chai from "chai"; | ||
import chaiAsPromised from "chai-as-promised"; | ||
import { mock } from "node:test"; | ||
import { markDomainAsVerifiedFactory } from "./mark-domain-as-verified.js"; | ||
// | ||
|
||
chai.use(chaiAsPromised); | ||
const assert = chai.assert; | ||
|
||
describe(markDomainAsVerifiedFactory.name, () => { | ||
it("should update organization members", async () => { | ||
const addDomain = mock.fn<AddDomainHandler>(() => | ||
Promise.resolve({} as any), | ||
); | ||
|
||
const updateUserOrganizationLink = | ||
mock.fn<UpdateUserOrganizationLinkHandler>(() => | ||
Promise.resolve({} as any), | ||
); | ||
const markDomainAsVerified = markDomainAsVerifiedFactory({ | ||
addDomain, | ||
findEmailDomainsByOrganizationId: | ||
mock.fn<FindEmailDomainsByOrganizationIdHandler>(), | ||
findOrganizationById: mock.fn<FindByIdHandler>(() => | ||
Promise.resolve({ id: 42 } as Organization), | ||
), | ||
getUsers: mock.fn<GetUsersByOrganizationHandler>(() => | ||
Promise.resolve([ | ||
{ | ||
id: 42, | ||
email: "[email protected]", | ||
verification_type: null, | ||
} as User & BaseUserOrganizationLink, | ||
]), | ||
), | ||
updateUserOrganizationLink, | ||
}); | ||
|
||
await markDomainAsVerified({ | ||
domain: "darkangels.world", | ||
domain_verification_type: "verified", | ||
organization_id: 42, | ||
}); | ||
|
||
assert.deepEqual(updateUserOrganizationLink.mock.callCount(), 1); | ||
{ | ||
const [call] = updateUserOrganizationLink.mock.calls; | ||
assert.deepEqual(call.arguments, [ | ||
42, | ||
42, | ||
{ verification_type: "domain" }, | ||
]); | ||
} | ||
|
||
assert.deepEqual(addDomain.mock.callCount(), 1); | ||
{ | ||
const [call] = addDomain.mock.calls; | ||
assert.deepEqual(call.arguments, [ | ||
{ | ||
domain: "darkangels.world", | ||
organization_id: 42, | ||
verification_type: "verified", | ||
}, | ||
]); | ||
} | ||
}); | ||
|
||
it("should add domain if organization if missing", async () => { | ||
const logs = [] as unknown[]; | ||
const updateUserOrganizationLink: UpdateUserOrganizationLinkHandler = ( | ||
...args | ||
) => { | ||
logs.push(args); | ||
return Promise.resolve({} as UserOrganizationLink); | ||
}; | ||
const markDomainAsVerified = markDomainAsVerifiedFactory({ | ||
addDomain: () => Promise.resolve({} as EmailDomain), | ||
findEmailDomainsByOrganizationId: () => Promise.resolve([]), | ||
findOrganizationById: () => Promise.resolve({ id: 42 } as Organization), | ||
getUsers: () => | ||
Promise.resolve([ | ||
{ | ||
id: 42, | ||
email: "[email protected]", | ||
verification_type: null, | ||
} as User & BaseUserOrganizationLink, | ||
]), | ||
updateUserOrganizationLink, | ||
}); | ||
|
||
await markDomainAsVerified({ | ||
domain: "darkangels.world", | ||
domain_verification_type: "verified", | ||
organization_id: 42, | ||
}); | ||
|
||
assert.deepEqual(logs, [[42, 42, { verification_type: "domain" }]]); | ||
}); | ||
}); |
84 changes: 84 additions & 0 deletions
84
packages/identite/src/managers/organization/mark-domain-as-verified.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// | ||
|
||
import type { GetUsersByOrganizationHandler } from "#src/repositories/organization"; | ||
import type { UpdateUserOrganizationLinkHandler } from "#src/repositories/user"; | ||
import { getEmailDomain } from "@gouvfr-lasuite/proconnect.core/services/email"; | ||
import type { | ||
AddDomainHandler, | ||
FindEmailDomainsByOrganizationIdHandler, | ||
} from "@gouvfr-lasuite/proconnect.identite/repositories/email-domain"; | ||
import type { FindByIdHandler } from "@gouvfr-lasuite/proconnect.identite/repositories/organization"; | ||
import type { EmailDomain } from "@gouvfr-lasuite/proconnect.identite/types"; | ||
import { InseeNotFoundError } from "@gouvfr-lasuite/proconnect.insee/errors"; | ||
import { isEmpty, some } from "lodash-es"; | ||
|
||
// | ||
|
||
type FactoryDependencies = { | ||
addDomain: AddDomainHandler; | ||
findEmailDomainsByOrganizationId: FindEmailDomainsByOrganizationIdHandler; | ||
findOrganizationById: FindByIdHandler; | ||
getUsers: GetUsersByOrganizationHandler; | ||
updateUserOrganizationLink: UpdateUserOrganizationLinkHandler; | ||
}; | ||
|
||
export function markDomainAsVerifiedFactory({ | ||
addDomain, | ||
findEmailDomainsByOrganizationId, | ||
findOrganizationById, | ||
getUsers, | ||
updateUserOrganizationLink, | ||
}: FactoryDependencies) { | ||
return async function markDomainAsVerified({ | ||
organization_id, | ||
domain, | ||
domain_verification_type, | ||
}: { | ||
organization_id: number; | ||
domain: string; | ||
domain_verification_type: EmailDomain["verification_type"]; | ||
}) { | ||
const organization = await findOrganizationById(organization_id); | ||
if (isEmpty(organization)) { | ||
throw new InseeNotFoundError(); | ||
} | ||
const emailDomains = | ||
await findEmailDomainsByOrganizationId(organization_id); | ||
|
||
if ( | ||
!some(emailDomains, { | ||
domain, | ||
verification_type: domain_verification_type, | ||
}) | ||
) { | ||
await addDomain({ | ||
organization_id, | ||
domain, | ||
verification_type: domain_verification_type, | ||
}); | ||
} | ||
const usersInOrganization = await getUsers(organization_id); | ||
|
||
await Promise.all( | ||
usersInOrganization.map( | ||
({ id, email, verification_type: link_verification_type }) => { | ||
const userDomain = getEmailDomain(email); | ||
if ( | ||
userDomain === domain && | ||
[ | ||
null, | ||
"no_verification_means_available", | ||
"no_verification_means_for_entreprise_unipersonnelle", | ||
].includes(link_verification_type) | ||
) { | ||
return updateUserOrganizationLink(organization_id, id, { | ||
verification_type: "domain", | ||
}); | ||
} | ||
|
||
return null; | ||
}, | ||
), | ||
); | ||
}; | ||
} |
33 changes: 33 additions & 0 deletions
33
packages/identite/src/repositories/email-domain/add-domain.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// | ||
|
||
import { emptyDatabase, migrate, pg } from "#testing"; | ||
import { expect } from "chai"; | ||
import { before, describe, it } from "mocha"; | ||
import { addDomainFactory } from "./add-domain.js"; | ||
|
||
// | ||
|
||
const addDomain = addDomainFactory({ pg: pg as any }); | ||
|
||
describe(addDomainFactory.name, () => { | ||
before(migrate); | ||
beforeEach(emptyDatabase); | ||
|
||
it("should add domain", async () => { | ||
await pg.sql`insert into organizations | ||
(id, siret, created_at, updated_at) | ||
values | ||
(1, '66204244933106', '4444-04-04', '4444-04-04'); | ||
`; | ||
|
||
const emailDomain = await addDomain({ | ||
domain: "darkangels.world", | ||
organization_id: 1, | ||
verification_type: "verified", | ||
}); | ||
|
||
expect(emailDomain.domain).to.equal("darkangels.world"); | ||
expect(emailDomain.verification_type).to.equal("verified"); | ||
expect(emailDomain.created_at).to.deep.equal(emailDomain.updated_at); | ||
}); | ||
}); |
48 changes: 48 additions & 0 deletions
48
packages/identite/src/repositories/email-domain/add-domain.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// | ||
|
||
import { hashToPostgresParams } from "#src/services"; | ||
import type { DatabaseContext, EmailDomain } from "#src/types"; | ||
import type { QueryResult } from "pg"; | ||
|
||
// | ||
|
||
export function addDomainFactory({ pg }: DatabaseContext) { | ||
return async function addDomain({ | ||
organization_id, | ||
domain, | ||
verification_type, | ||
}: { | ||
organization_id: number; | ||
domain: string; | ||
verification_type: EmailDomain["verification_type"]; | ||
}) { | ||
const connection = pg; | ||
|
||
const emailDomain = { | ||
organization_id, | ||
domain, | ||
verification_type, | ||
can_be_suggested: true, | ||
verified_at: new Date(), | ||
created_at: new Date(), | ||
updated_at: new Date(), | ||
}; | ||
|
||
const { paramsString, valuesString, values } = | ||
hashToPostgresParams<EmailDomain>(emailDomain); | ||
|
||
const { rows }: QueryResult<EmailDomain> = await connection.query( | ||
` | ||
INSERT INTO email_domains | ||
${paramsString} | ||
VALUES | ||
${valuesString} | ||
RETURNING *;`, | ||
values, | ||
); | ||
|
||
return rows.shift()!; | ||
}; | ||
} | ||
|
||
export type AddDomainHandler = ReturnType<typeof addDomainFactory>; |
Oops, something went wrong.