From 84c9e15e490ca37ff8c195c127ce47100e62da8b Mon Sep 17 00:00:00 2001 From: Douglas Duteil Date: Wed, 26 Jun 2024 09:47:43 +0200 Subject: [PATCH] feat(moderation): only list email of user with the same family name (#342) --- .../src/__snapshots__/indext.test.tsx.snap | 10 +- packages/hono-slotify/src/indext.test.tsx | 2 +- .../infra/moncomptepro/database/src/index.ts | 13 +-- .../moncomptepro/database/src/seed/delete.ts | 38 +++--- .../moncomptepro/database/src/seed/insert.ts | 72 ++++++------ .../moncomptepro/database/src/seed/unicorn.ts | 72 ++++++++++++ .../database/src/testing/index.ts | 7 ++ .../already_signed.test.tsx.snap | 25 +++- .../src/:id/responses/already_signed.test.tsx | 109 ++++++++++-------- .../api/src/:id/responses/already_signed.tsx | 1 + .../src/get_emails_by_organization_id.test.ts | 54 +++++---- .../src/get_emails_by_organization_id.ts | 23 +++- 12 files changed, 271 insertions(+), 155 deletions(-) create mode 100644 packages/~/infra/moncomptepro/database/src/seed/unicorn.ts diff --git a/packages/hono-slotify/src/__snapshots__/indext.test.tsx.snap b/packages/hono-slotify/src/__snapshots__/indext.test.tsx.snap index 10ea35a0..9f5e312d 100644 --- a/packages/hono-slotify/src/__snapshots__/indext.test.tsx.snap +++ b/packages/hono-slotify/src/__snapshots__/indext.test.tsx.snap @@ -1,17 +1,11 @@ // Bun Snapshot v1, https://goo.gl/fbAQLP -exports[`Basic render 1`] = `"
beforecomponent
beforeslot IN_SLOT afterslot; ownChildren: BEFORE_SLOTAFTER_SLOT
aftercomponent
"`; - -exports[`Renderer undefined childs 1`] = `"
beforecomponent
beforeslot undefined afterslot; ownChildren: BEFORE_SLOTAFTER_SLOT
aftercomponent
"`; - exports[`render basic slot 1`] = `"
beforecomponent
beforeslot IN_SLOT afterslot; ownChildren: BEFORE_SLOTAFTER_SLOT
aftercomponent
"`; -exports[`eender undefined childs 1`] = `"
beforecomponent
beforeslot undefined afterslot; ownChildren: BEFORE_SLOTAFTER_SLOT
aftercomponent
"`; - exports[`render undefined childs 1`] = `"
beforecomponent
beforeslot undefined afterslot; ownChildren: BEFORE_SLOTAFTER_SLOT
aftercomponent
"`; exports[`render default content if slot is not used 1`] = `"
beforecomponent
beforeslotDEFAULT_SLOT_CONTENTafterslot; ownChildren: Slot not used
aftercomponent
"`; -exports[`pass default children to function 1`] = `"
foo=DEFAULT_SLOT_CONTENT
"`; - exports[`pass parameters 1`] = `"
foo=bar
"`; + +exports[`pass default children to function 1`] = `"
foo=DEFAULT_SLOT_CONTENT
"`; diff --git a/packages/hono-slotify/src/indext.test.tsx b/packages/hono-slotify/src/indext.test.tsx index c10815da..5f0b3e93 100644 --- a/packages/hono-slotify/src/indext.test.tsx +++ b/packages/hono-slotify/src/indext.test.tsx @@ -31,7 +31,7 @@ test("render basic slot", () => { ).toMatchSnapshot(); }); -test("eender undefined childs", () => { +test("render undefined childs", () => { const TestSlot = createSlot(); const Component: FC = ({ children }) => { return ( diff --git a/packages/~/infra/moncomptepro/database/src/index.ts b/packages/~/infra/moncomptepro/database/src/index.ts index 0c657b04..dfa665e3 100644 --- a/packages/~/infra/moncomptepro/database/src/index.ts +++ b/packages/~/infra/moncomptepro/database/src/index.ts @@ -1,21 +1,16 @@ // -import type { NodePgDatabase } from "drizzle-orm/node-postgres"; -import type { PgliteDatabase } from "drizzle-orm/pglite"; +import type { PgDatabase, QueryResultHKT } from "drizzle-orm/pg-core"; import Pg from "pg"; import * as schema from "./drizzle/relations"; // -export { drizzle, type NodePgClient } from "drizzle-orm/node-postgres"; +export { drizzle } from "drizzle-orm/node-postgres"; export { schema }; -export type MonComptePro_NodePgDatabase = NodePgDatabase; -export type MonComptePro_PgliteDatabase = PgliteDatabase; -export type MonComptePro_PgDatabase = - | MonComptePro_NodePgDatabase - | MonComptePro_PgliteDatabase; + +export type MonComptePro_PgDatabase = PgDatabase; export const Pool = Pg.Pool; -export type { NodePgDatabase }; // diff --git a/packages/~/infra/moncomptepro/database/src/seed/delete.ts b/packages/~/infra/moncomptepro/database/src/seed/delete.ts index b42e8865..00a1bbef 100644 --- a/packages/~/infra/moncomptepro/database/src/seed/delete.ts +++ b/packages/~/infra/moncomptepro/database/src/seed/delete.ts @@ -2,47 +2,45 @@ import consola from "consola"; import { sql } from "drizzle-orm"; -import type { MonComptePro_NodePgDatabase } from "../index"; +import type { MonComptePro_PgDatabase } from "../index"; import { schema } from "../index"; // -export async function delete_database(db: MonComptePro_NodePgDatabase) { +export async function delete_database(db: MonComptePro_PgDatabase) { try { - const users_organizations = await db.delete(schema.users_organizations); + const users_organizations = await db + .delete(schema.users_organizations) + .returning(); consola.verbose( - `🚮 ${users_organizations.command} ${users_organizations.rowCount} users_organizations`, + `🚮 DELETE ${users_organizations.length} users_organizations`, ); - const users_oidc_clients = await db.delete(schema.users_oidc_clients); + const users_oidc_clients = await db + .delete(schema.users_oidc_clients) + .returning(); await db.execute( sql`ALTER SEQUENCE users_oidc_clients_id_seq RESTART WITH 1`, ); consola.verbose( - `🚮 ${users_oidc_clients.command} ${users_oidc_clients.rowCount} users_oidc_clients`, + `🚮 DELETE ${users_oidc_clients.length} users_oidc_clients`, ); - const oidc_clients = await db.delete(schema.oidc_clients); + const oidc_clients = await db.delete(schema.oidc_clients).returning(); await db.execute(sql`ALTER SEQUENCE oidc_clients_id_seq RESTART WITH 1`); - consola.verbose( - `🚮 ${oidc_clients.command} ${oidc_clients.rowCount} oidc_clients`, - ); + consola.verbose(`🚮 DELETE ${oidc_clients.length} oidc_clients`); - const users = await db.delete(schema.users); + const users = await db.delete(schema.users).returning(); await db.execute(sql`ALTER SEQUENCE users_id_seq RESTART WITH 1`); - consola.verbose(`🚮 ${users.command} ${users.rowCount} users`); + consola.verbose(`🚮 DELETE ${users.length} users`); - const organizations = await db.delete(schema.organizations); + const organizations = await db.delete(schema.organizations).returning(); await db.execute(sql`ALTER SEQUENCE organizations_id_seq RESTART WITH 1`); - consola.verbose( - `🚮 ${organizations.command} ${organizations.rowCount} organizations`, - ); + consola.verbose(`🚮 DELETE ${organizations.length} organizations`); - const moderations = await db.delete(schema.moderations); + const moderations = await db.delete(schema.moderations).returning(); await db.execute(sql`ALTER SEQUENCE moderations_id_seq RESTART WITH 1`); - consola.verbose( - `🚮 ${moderations.command} ${moderations.rowCount} moderations`, - ); + consola.verbose(`🚮 DELETE ${moderations.length} moderations`); } catch (err) { console.error("Something went wrong..."); console.error(err); diff --git a/packages/~/infra/moncomptepro/database/src/seed/insert.ts b/packages/~/infra/moncomptepro/database/src/seed/insert.ts index 6db67294..6b6a7458 100644 --- a/packages/~/infra/moncomptepro/database/src/seed/insert.ts +++ b/packages/~/infra/moncomptepro/database/src/seed/insert.ts @@ -1,13 +1,13 @@ // import consola from "consola"; -import type { MonComptePro_NodePgDatabase } from "../index"; +import type { MonComptePro_PgDatabase } from "../index"; import { schema } from "../index"; import type { MCP_Moderation } from "../moncomptepro"; // -export async function insert_database(db: MonComptePro_NodePgDatabase) { +export async function insert_database(db: MonComptePro_PgDatabase) { try { const raphael = await insert_raphael(db); consola.verbose( @@ -55,98 +55,98 @@ export async function insert_database(db: MonComptePro_NodePgDatabase) { // - const raphael_dinum = await insert_users_organizations(db, { + await insert_users_organizations(db, { organization_id: dinum.id, user_id: raphael.id, }); consola.verbose( - `🌱 ${raphael_dinum.command} ${raphael_dinum.rowCount} ${raphael.given_name} join ${dinum.cached_libelle}`, + `🌱 INSERT ${raphael.given_name} join ${dinum.cached_libelle} `, ); - const marie_bon_join_bosch_rexroth = await insert_users_organizations(db, { + await insert_users_organizations(db, { organization_id: bosch_rexroth.id, user_id: marie_bon.id, }); consola.verbose( - `🌱 ${marie_bon_join_bosch_rexroth.command} ${marie_bon_join_bosch_rexroth.rowCount} ${marie_bon.given_name} join ${bosch_rexroth.cached_libelle}`, + `🌱 INSERT ${marie_bon.given_name} join ${bosch_rexroth.cached_libelle}`, ); // - const jeanbon_dinum = await insert_moderation(db, { + await insert_moderation(db, { created_at: new Date("2011-11-11 11:11:11").toISOString(), organization_id: dinum.id, type: "organization_join_block" as MCP_Moderation["type"], user_id: jean_bon.id, }); consola.verbose( - `🌱 ${jeanbon_dinum.command} ${jeanbon_dinum.rowCount} ${jean_bon.given_name} wants to join ${dinum.cached_libelle}`, + `🌱 INSERT ${jean_bon.given_name} wants to join ${dinum.cached_libelle}`, ); - const jeanbon_abracadabra = await insert_moderation(db, { + await insert_moderation(db, { created_at: new Date("2011-11-11 00:02:59").toISOString(), organization_id: abracadabra.id, type: "organization_join_block" as MCP_Moderation["type"], user_id: jean_bon.id, }); consola.verbose( - `🌱 ${jeanbon_abracadabra.command} ${jeanbon_abracadabra.rowCount} ${jean_bon.given_name} wants to join ${abracadabra.cached_libelle}`, + `🌱 INSERT ${jean_bon.given_name} wants to join ${abracadabra.cached_libelle}`, ); - const pierrebon_aldp = await insert_moderation(db, { + await insert_moderation(db, { organization_id: aldp.id, type: "big_organization_join" as MCP_Moderation["type"], user_id: pierre_bon.id, }); consola.verbose( - `🌱 ${pierrebon_aldp.command} ${pierrebon_aldp.rowCount} ${pierre_bon.family_name} wants to join ${aldp.cached_libelle}`, + `🌱 INSERT ${pierre_bon.family_name} wants to join ${aldp.cached_libelle}`, ); - const richard_bon_dengi = await insert_moderation(db, { + await insert_moderation(db, { organization_id: dengi.id, type: "organization_join_block" as MCP_Moderation["type"], user_id: richard_bon.id, moderated_at: new Date("2023-06-22 14:34:34").toISOString(), }); consola.verbose( - `🌱 ${richard_bon_dengi.command} ${richard_bon_dengi.rowCount} ${richard_bon.given_name} wants to join ${dengi.cached_nom_complet}`, + `🌱 INSERT ${richard_bon.given_name} wants to join ${dengi.cached_nom_complet}`, ); - const richard_bon_dengi_bis = await insert_moderation(db, { + await insert_moderation(db, { organization_id: dengi.id, type: "organization_join_block" as MCP_Moderation["type"], user_id: richard_bon.id, }); consola.verbose( - `🌱 ${richard_bon_dengi_bis.command} ${richard_bon_dengi_bis.rowCount} ${richard_bon.given_name} wants to join ${dengi.cached_nom_complet} again...`, + `🌱 INSERT ${richard_bon.given_name} wants to join ${dengi.cached_nom_complet} again...`, ); - const marie_bon_bosch_france = await insert_moderation(db, { + await insert_moderation(db, { organization_id: bosch_france.id, type: "non_verified_domain" as MCP_Moderation["type"], user_id: marie_bon.id, }); consola.verbose( - `🌱 ${marie_bon_bosch_france.command} ${marie_bon_bosch_france.rowCount} ${marie_bon.given_name} wants to join ${bosch_france.cached_nom_complet} again...`, + `🌱 INSERT ${marie_bon.given_name} wants to join ${bosch_france.cached_nom_complet} again...`, ); - const marie_bon_bosch_rexroth = await insert_moderation(db, { + await insert_moderation(db, { organization_id: bosch_rexroth.id, type: "non_verified_domain" as MCP_Moderation["type"], user_id: marie_bon.id, moderated_at: new Date("2023-06-22 14:34:34").toISOString(), }); consola.verbose( - `🌱 ${marie_bon_bosch_rexroth.command} ${marie_bon_bosch_rexroth.rowCount} ${marie_bon.given_name} wants to join ${bosch_rexroth.cached_nom_complet} again...`, + `🌱 INSERT ${marie_bon.given_name} wants to join ${bosch_rexroth.cached_nom_complet} again...`, ); - const raphael_alpha_dinum = await insert_moderation(db, { + await insert_moderation(db, { organization_id: dinum.id, type: "non_verified_domain" as MCP_Moderation["type"], user_id: raphael_alpha.id, moderated_at: new Date("2023-06-22 14:34:34").toISOString(), }); consola.verbose( - `🌱 ${raphael_alpha_dinum.command} ${raphael_alpha_dinum.rowCount} ${raphael_alpha.given_name} wants to join ${dinum.cached_nom_complet} again...`, + `🌱 INSERT ${raphael_alpha.given_name} wants to join ${dinum.cached_nom_complet} again...`, ); } catch (err) { console.error("Something went wrong..."); @@ -157,14 +157,14 @@ export async function insert_database(db: MonComptePro_NodePgDatabase) { // function insert_moderation( - db: MonComptePro_NodePgDatabase, + db: MonComptePro_PgDatabase, insert_moderation: typeof schema.moderations.$inferInsert, ) { return db.insert(schema.moderations).values(insert_moderation); } function insert_users_organizations( - db: MonComptePro_NodePgDatabase, + db: MonComptePro_PgDatabase, insert_users_organizations: typeof schema.users_organizations.$inferInsert, ) { return db @@ -172,7 +172,7 @@ function insert_users_organizations( .values(insert_users_organizations); } -async function insert_jeanbon(db: MonComptePro_NodePgDatabase) { +async function insert_jeanbon(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.users) .values({ @@ -190,7 +190,7 @@ async function insert_jeanbon(db: MonComptePro_NodePgDatabase) { return insert.at(0)!; } -async function insert_pierrebon(db: MonComptePro_NodePgDatabase) { +async function insert_pierrebon(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.users) .values({ @@ -209,7 +209,7 @@ async function insert_pierrebon(db: MonComptePro_NodePgDatabase) { return insert.at(0)!; } -async function insert_richardbon(db: MonComptePro_NodePgDatabase) { +async function insert_richardbon(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.users) .values({ @@ -228,7 +228,7 @@ async function insert_richardbon(db: MonComptePro_NodePgDatabase) { return insert.at(0)!; } -async function insert_mariebon(db: MonComptePro_NodePgDatabase) { +async function insert_mariebon(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.users) .values({ @@ -247,7 +247,7 @@ async function insert_mariebon(db: MonComptePro_NodePgDatabase) { return insert.at(0)!; } -async function insert_raphael(db: MonComptePro_NodePgDatabase) { +async function insert_raphael(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.users) .values({ @@ -265,7 +265,7 @@ async function insert_raphael(db: MonComptePro_NodePgDatabase) { return insert.at(0)!; } -async function insert_raphael_alpha(db: MonComptePro_NodePgDatabase) { +async function insert_raphael_alpha(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.users) .values({ @@ -285,7 +285,7 @@ async function insert_raphael_alpha(db: MonComptePro_NodePgDatabase) { // -async function insert_abracadabra(db: MonComptePro_NodePgDatabase) { +async function insert_abracadabra(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.organizations) .values({ @@ -313,7 +313,7 @@ async function insert_abracadabra(db: MonComptePro_NodePgDatabase) { return insert.at(0)!; } -async function insert_aldp(db: MonComptePro_NodePgDatabase) { +async function insert_aldp(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.organizations) .values({ @@ -338,7 +338,7 @@ async function insert_aldp(db: MonComptePro_NodePgDatabase) { return insert.at(0)!; } -async function insert_dinum(db: MonComptePro_NodePgDatabase) { +async function insert_dinum(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.organizations) .values({ @@ -362,7 +362,7 @@ async function insert_dinum(db: MonComptePro_NodePgDatabase) { return insert.at(0)!; } -async function insert_dengi(db: MonComptePro_NodePgDatabase) { +async function insert_dengi(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.organizations) .values({ @@ -386,7 +386,7 @@ async function insert_dengi(db: MonComptePro_NodePgDatabase) { return insert.at(0)!; } -async function insert_bosch_france(db: MonComptePro_NodePgDatabase) { +async function insert_bosch_france(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.organizations) .values({ @@ -412,7 +412,7 @@ async function insert_bosch_france(db: MonComptePro_NodePgDatabase) { return insert.at(0)!; } -async function insert_bosch_rexroth(db: MonComptePro_NodePgDatabase) { +async function insert_bosch_rexroth(db: MonComptePro_PgDatabase) { const insert = await db .insert(schema.organizations) .values({ diff --git a/packages/~/infra/moncomptepro/database/src/seed/unicorn.ts b/packages/~/infra/moncomptepro/database/src/seed/unicorn.ts new file mode 100644 index 00000000..33eab85c --- /dev/null +++ b/packages/~/infra/moncomptepro/database/src/seed/unicorn.ts @@ -0,0 +1,72 @@ +// + +import { schema, type MonComptePro_PgDatabase } from ".."; + +// + +// Uses https://magicalunicornlife.com/the-best-unicorn-names/ + +// +export async function create_unicorn_organization(pg: MonComptePro_PgDatabase) { + const [{ id: organization_id }] = await pg + .insert(schema.organizations) + .values({ + authorized_email_domains: [], + cached_libelle: "🦄 libelle", + external_authorized_email_domains: [], + siret: "🦄 siret", + trackdechets_email_domains: [], + verified_email_domains: [], + }) + .returning({ id: schema.organizations.id }); + + return organization_id; +} + +// +export async function create_adora_pony_user(pg: MonComptePro_PgDatabase) { + const [{ id: user_id }] = await pg + .insert(schema.users) + .values({ + created_at: new Date().toISOString(), + email: "adora.pony@uni.corn", + family_name: "Pony", + given_name: "Adora", + updated_at: new Date().toISOString(), + }) + .returning({ id: schema.users.id }); + + return user_id; +} + +// + +export async function create_pink_diamond_user(pg: MonComptePro_PgDatabase) { + const [{ id: user_id }] = await pg + .insert(schema.users) + .values({ + created_at: new Date().toISOString(), + email: "pink.diamond@uni.corn", + family_name: "Diamond", + given_name: "Pink", + updated_at: new Date().toISOString(), + }) + .returning({ id: schema.users.id }); + + return user_id; +} + +export async function create_red_diamond_user(pg: MonComptePro_PgDatabase) { + const [{ id: user_id }] = await pg + .insert(schema.users) + .values({ + created_at: new Date().toISOString(), + email: "red.diamond@uni.corn", + family_name: "Diamond", + given_name: "Red", + updated_at: new Date().toISOString(), + }) + .returning({ id: schema.users.id }); + + return user_id; +} diff --git a/packages/~/infra/moncomptepro/database/src/testing/index.ts b/packages/~/infra/moncomptepro/database/src/testing/index.ts index 53a23939..5a615409 100644 --- a/packages/~/infra/moncomptepro/database/src/testing/index.ts +++ b/packages/~/infra/moncomptepro/database/src/testing/index.ts @@ -1,6 +1,7 @@ // import { PGlite } from "@electric-sql/pglite"; +import type { PgInsertValue } from "drizzle-orm/pg-core"; import { drizzle } from "drizzle-orm/pglite"; import { migrate as pglite_migrate } from "drizzle-orm/pglite/migrator"; import path from "node:path"; @@ -26,3 +27,9 @@ export function migrate() { migrationsFolder: path.resolve(import.meta.dirname, "../drizzle"), }); } + +export async function add_user_to_organization( + value: PgInsertValue, +) { + return pg.insert(schema.users_organizations).values(value); +} diff --git a/packages/~/moderations/api/src/:id/responses/__snapshots__/already_signed.test.tsx.snap b/packages/~/moderations/api/src/:id/responses/__snapshots__/already_signed.test.tsx.snap index a1be20d1..ee82ef78 100644 --- a/packages/~/moderations/api/src/:id/responses/__snapshots__/already_signed.test.tsx.snap +++ b/packages/~/moderations/api/src/:id/responses/__snapshots__/already_signed.test.tsx.snap @@ -1,14 +1,33 @@ // Bun Snapshot v1, https://goo.gl/fbAQLP -exports[`returns signed member emails 1`] = ` +exports[`returns all members 1`] = ` "Bonjour, Votre demande pour rejoindre l'organisation « 🦄 » a été prise en compte sur https://app.moncomptepro.beta.gouv.fr. Vous possédez déjà un compte MonComptePro : -- adora@uni.corn -- bella@uni.corn +- adora.pony@uni.corn +- pink.diamond@uni.corn +- red.diamond@uni.corn + +Merci de bien vouloir vous connecter avec le compte déjà existant. + +Je reste à votre disposition pour tout complément d'information. + +Excellente journée, +L’équipe MonComptePro." +`; + +exports[`returns Diamond members 1`] = ` +"Bonjour, + +Votre demande pour rejoindre l'organisation « 🦄 » a été prise en compte sur https://app.moncomptepro.beta.gouv.fr. + +Vous possédez déjà un compte MonComptePro : + +- pink.diamond@uni.corn +- red.diamond@uni.corn Merci de bien vouloir vous connecter avec le compte déjà existant. diff --git a/packages/~/moderations/api/src/:id/responses/already_signed.test.tsx b/packages/~/moderations/api/src/:id/responses/already_signed.test.tsx index 8b0e7a4c..d944eefa 100644 --- a/packages/~/moderations/api/src/:id/responses/already_signed.test.tsx +++ b/packages/~/moderations/api/src/:id/responses/already_signed.test.tsx @@ -1,8 +1,18 @@ // import { set_moncomptepro_pg } from "@~/app.middleware/set_moncomptepro_pg"; -import { schema } from "@~/moncomptepro.database"; -import { empty_database, migrate, pg } from "@~/moncomptepro.database/testing"; +import { + create_adora_pony_user, + create_pink_diamond_user, + create_red_diamond_user, + create_unicorn_organization, +} from "@~/moncomptepro.database/seed/unicorn"; +import { + add_user_to_organization, + empty_database, + migrate, + pg, +} from "@~/moncomptepro.database/testing"; import { beforeAll, beforeEach, expect, test } from "bun:test"; import { Hono } from "hono"; import { jsxRenderer } from "hono/jsx-renderer"; @@ -15,60 +25,41 @@ import already_signed from "./already_signed"; // -let unicorn_organization_id: number; - -// - beforeAll(migrate); beforeEach(empty_database); -beforeEach(async function create_unicorn_organization() { - const [{ id: organization_id }] = await pg - .insert(schema.organizations) - .values({ - authorized_email_domains: [], - external_authorized_email_domains: [], - siret: "", - trackdechets_email_domains: [], - verified_email_domains: [], - }) - .returning({ id: schema.organizations.id }); - unicorn_organization_id = organization_id; -}); +test("returns all members", async () => { + const unicorn_organization_id = await given_unicorn_organization(); -beforeEach(async function create_adora_user() { - const [{ id: user_id }] = await pg - .insert(schema.users) - .values({ - created_at: new Date().toISOString(), - email: "adora@uni.corn", - updated_at: new Date().toISOString(), - }) - .returning({ id: schema.users.id }); - - await pg.insert(schema.users_organizations).values({ - organization_id: unicorn_organization_id, - user_id, - }); -}); + const app = new Hono() + .use("*", jsxRenderer()) + .use("*", set_moncomptepro_pg(pg)) + .get("/already_signed", ({ render }) => { + const domain = "uni.corn"; + const moderation = { + organization: { cached_libelle: "🦄", id: unicorn_organization_id }, + user: { family_name: "🧟" }, + } as get_moderation_dto; + const organization_member = {} as get_organization_member_dto; -beforeEach(async function create_bella_user() { - const [{ id: user_id }] = await pg - .insert(schema.users) - .values({ - created_at: new Date().toISOString(), - email: "bella@uni.corn", - updated_at: new Date().toISOString(), - }) - .returning({ id: schema.users.id }); + return render( + + + , + ); + }); - await pg.insert(schema.users_organizations).values({ - organization_id: unicorn_organization_id, - user_id, - }); + const res = await app.fetch( + new Request("http://localhost:3000/already_signed"), + ); + expect(res.status).toBe(200); + expect(await res.text()).toMatchSnapshot(); }); +test("returns Diamond members", async () => { + const unicorn_organization_id = await given_unicorn_organization(); -test("returns signed member emails", async () => { const app = new Hono() .use("*", jsxRenderer()) .use("*", set_moncomptepro_pg(pg)) @@ -76,6 +67,7 @@ test("returns signed member emails", async () => { const domain = "uni.corn"; const moderation = { organization: { cached_libelle: "🦄", id: unicorn_organization_id }, + user: { family_name: "Diamond" }, } as get_moderation_dto; const organization_member = {} as get_organization_member_dto; @@ -87,6 +79,7 @@ test("returns signed member emails", async () => { , ); }); + const res = await app.fetch( new Request("http://localhost:3000/already_signed"), ); @@ -94,6 +87,26 @@ test("returns signed member emails", async () => { expect(await res.text()).toMatchSnapshot(); }); +async function given_unicorn_organization() { + const unicorn_organization_id = await create_unicorn_organization(pg); + const adora_pony_user_id = await create_adora_pony_user(pg); + await add_user_to_organization({ + organization_id: unicorn_organization_id, + user_id: adora_pony_user_id, + }); + const pink_diamond_user_id = await create_pink_diamond_user(pg); + await add_user_to_organization({ + organization_id: unicorn_organization_id, + user_id: pink_diamond_user_id, + }); + const red_diamond_user_id = await create_red_diamond_user(pg); + await add_user_to_organization({ + organization_id: unicorn_organization_id, + user_id: red_diamond_user_id, + }); + return unicorn_organization_id; +} + async function AlreadySigned() { return <>{await already_signed()}; } diff --git a/packages/~/moderations/api/src/:id/responses/already_signed.tsx b/packages/~/moderations/api/src/:id/responses/already_signed.tsx index ff0b7491..6e058e73 100644 --- a/packages/~/moderations/api/src/:id/responses/already_signed.tsx +++ b/packages/~/moderations/api/src/:id/responses/already_signed.tsx @@ -18,6 +18,7 @@ export default async function template() { const members_email = await get_emails_by_organization_id(moncomptepro_pg, { organization_id: moderation.organization.id, + family_name: moderation.user.family_name ?? "", }); return dedent` diff --git a/packages/~/users/repository/src/get_emails_by_organization_id.test.ts b/packages/~/users/repository/src/get_emails_by_organization_id.test.ts index 0aeb628c..d1a014dc 100644 --- a/packages/~/users/repository/src/get_emails_by_organization_id.test.ts +++ b/packages/~/users/repository/src/get_emails_by_organization_id.test.ts @@ -1,7 +1,16 @@ // -import { schema } from "@~/moncomptepro.database"; -import { empty_database, migrate, pg } from "@~/moncomptepro.database/testing"; +import { + create_pink_diamond_user, + create_red_diamond_user, + create_unicorn_organization, +} from "@~/moncomptepro.database/seed/unicorn"; +import { + add_user_to_organization, + empty_database, + migrate, + pg, +} from "@~/moncomptepro.database/testing"; import { beforeAll, beforeEach, expect, test } from "bun:test"; import { get_emails_by_organization_id } from "./get_emails_by_organization_id"; @@ -10,37 +19,26 @@ import { get_emails_by_organization_id } from "./get_emails_by_organization_id"; beforeAll(migrate); beforeEach(empty_database); -test("returns test@example.com", async () => { - const [{ id: user_id }] = await pg - .insert(schema.users) - .values({ - created_at: new Date().toISOString(), - email: "test@example.com", - updated_at: new Date().toISOString(), - }) - .returning({ id: schema.users.id }); - const [{ id: organization_id }] = await pg - .insert(schema.organizations) - .values({ - authorized_email_domains: [], - external_authorized_email_domains: [], - siret: "", - trackdechets_email_domains: [], - verified_email_domains: [], - }) - .returning({ id: schema.organizations.id }); - await pg.insert(schema.users_organizations).values({ - organization_id, - user_id, +test("returns pink diamond", async () => { + const unicorn_organization_id = await create_unicorn_organization(pg); + const pink_diamond_user_id = await create_pink_diamond_user(pg); + await add_user_to_organization({ + organization_id: unicorn_organization_id, + user_id: pink_diamond_user_id, + }); + const red_diamond_user_id = await create_red_diamond_user(pg); + await add_user_to_organization({ + organization_id: unicorn_organization_id, + user_id: red_diamond_user_id, }); const emails = await get_emails_by_organization_id(pg, { - organization_id, + organization_id: unicorn_organization_id, + family_name: "Diamond", }); expect(emails).toEqual([ - { - email: "test@example.com", - }, + { email: "pink.diamond@uni.corn" }, + { email: "red.diamond@uni.corn" }, ]); }); diff --git a/packages/~/users/repository/src/get_emails_by_organization_id.ts b/packages/~/users/repository/src/get_emails_by_organization_id.ts index 1c929fe6..edf390b9 100644 --- a/packages/~/users/repository/src/get_emails_by_organization_id.ts +++ b/packages/~/users/repository/src/get_emails_by_organization_id.ts @@ -1,14 +1,33 @@ // import { schema, type MonComptePro_PgDatabase } from "@~/moncomptepro.database"; -import { eq } from "drizzle-orm"; +import { and, eq, ilike } from "drizzle-orm"; // export async function get_emails_by_organization_id( pg: MonComptePro_PgDatabase, - { organization_id }: { organization_id: number }, + { + family_name, + organization_id, + }: { family_name: string; organization_id: number }, ) { + const same_family_name_members = await pg + .select({ email: schema.users.email }) + .from(schema.users) + .innerJoin( + schema.users_organizations, + eq(schema.users.id, schema.users_organizations.user_id), + ) + .where( + and( + eq(schema.users_organizations.organization_id, organization_id), + ilike(schema.users.family_name, family_name), + ), + ); + + if (same_family_name_members.length > 0) return same_family_name_members; + return pg .select({ email: schema.users.email }) .from(schema.users)