Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions e2e/cypress/support/step_definitions/uvv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ Before(() => {
});

// Context management

Given("je vais à l'intérieur du dialogue nommé {string}", (text: string) => {
get_within_context = () => cy.findAllByLabelText(text);
});

Given("je vais à l'intérieur du tableau nommé {string}", (title: string) => {
Given("je vais à l'intérieur de l'élément nommé {string}", (title: string) => {
cy.contains(title)
.invoke("attr", "id")
.then((id) => {
Expand Down Expand Up @@ -109,7 +110,7 @@ When("je retire le focus", () => {
// Assertions
Then("je vois {string}", (text: string) => {
get_within_context().within(() => {
cy.contains(text, { timeout: 8000 }).should("be.visible");
cy.contains(text, { timeout: 8_000 }).should("be.visible");
});
});

Expand Down
4 changes: 2 additions & 2 deletions e2e/features/moderations/manage_external_domain.feature
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ Fonctionnalité: Gérer un domaine externe lors de la modération
Et je clique sur "🌐 1 domaine connu dans l’organisation"

Scénario: Domaine externe
Quand je vais à l'intérieur du tableau nommé "🌐 1 domaine connu dans l’organisation"
Quand je vais à l'intérieur de l'élément nommé "🌐 1 domaine connu dans l’organisation"
Alors je vois "yopmail.com"
Et je réinitialise le contexte
Quand je clique sur "Menu"
Et je clique sur le bouton "❎ Domaine externe"
Quand je vais à l'intérieur du tableau nommé "🌐 1 domaine connu dans l’organisation"
Quand je vais à l'intérieur de l'élément nommé "🌐 1 domaine connu dans l’organisation"
Alors je vois "❎"
8 changes: 4 additions & 4 deletions e2e/features/moderations/manage_internal_domain.feature
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ Fonctionnalité: Gérer un domaine interne lors de la modération
Et je clique sur "✅ Domaine autorisé"
Et je réinitialise le contexte
Alors je dois voir un tableau nommé "🌐 1 domaine connu dans l’organisation" et contenant
| Domain | Status |
| yopmail.com | ✅ |
| Domain | Status | Type |
| yopmail.com | ✅ | verified |

Quand je vais à l'intérieur de la rangée nommée "Domaine yopmail.com (verified)"
Quand je clique sur "Menu"
Expand All @@ -41,5 +41,5 @@ Fonctionnalité: Gérer un domaine interne lors de la modération
# TODO(douglasduteil): We should update the title when adding a domain
Et je vois "poymail.com"
Alors je dois voir un tableau nommé "🌐 1 domaine connu dans l’organisation" et contenant
| Domain | Status |
| poymail.com | ✅ |
| Domain | Status | Type |
| poymail.com | ✅ | verified |
19 changes: 10 additions & 9 deletions e2e/features/users/jean_bon.feature
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ Fonctionnalité: Page utilisateur with moderations
Quand je navigue sur la page
Et je vois "Bonjour Hyyypertool !"
Et je clique sur le bouton "ProConnect"
# Et je me connecte en tant que user@yopmail.com sur dev-agentconnect.fr

Scénario:
# Scénario: Fiche de Raphael
Quand je clique sur "Utilisateurs"
Alors je suis redirigé sur "/users"

Et je dois voir le titre de page "Liste des utilisateurs"
Et je vois "Liste des utilisateurs"
Quand je vais à l'intérieur de la rangée nommée "Utilisateur Jean Bon (jeanbon@yopmail.com)"
Et je clique sur "➡️"
Et je réinitialise le contexte

Et je dois voir le titre de page "Utilisateur Jean Bon (jeanbon@yopmail.com)"

Scénario:
Alors je vois "👨‍💻 A propos de l'utilisateur"
Et je vois "« Jean Bon »"
Et je vois "email jeanbon@yopmail.com"
Expand All @@ -27,7 +27,8 @@ Fonctionnalité: Page utilisateur with moderations
Et je vois "Dernière modification22/06/2023 16:34:34"
Et je vois "Email vérifié envoyé le22/06/2023 16:34:34"

# Scénario: Organisations de Raphael
Alors je vois "Jean est enregistré(e) dans les modérations suivantes :"
Quand je vais à l'intérieur de la rangée nommée "Modération a traiter (ID 1)"
Et je réinitialise le contexte
Alors je dois voir un tableau nommé "Liste des modérations de Jean" et contenant
| Type |
| 🕵️A traiter |

Et je vois "L'utilisateur n'a pas de MFA configurée."
55 changes: 55 additions & 0 deletions e2e/features/users/raphael_alpha.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#language: fr
Fonctionnalité: Page utilisateur avec MFA

Contexte:
Soit une base de données nourrie au grain
Quand je navigue sur la page
Et je vois "Bonjour Hyyypertool !"
Et je clique sur le bouton "ProConnect"
Quand je clique sur "Utilisateurs"

Et je dois voir le titre de page "Liste des utilisateurs"
Et je vois "Liste des utilisateurs"
Quand je vais à l'intérieur de la rangée nommée "Utilisateur Raphael Dubigny (rdubigny@alpha.gouv.fr)"
Et je clique sur "➡️"
Et je réinitialise le contexte

Et je dois voir le titre de page "Utilisateur Raphael Dubigny (rdubigny@alpha.gouv.fr)"

Scénario: La fiche de Raphael Alpha
Alors je vois "👨‍💻 A propos de l'utilisateur"
Et je vois "« Raphael Dubigny »"
Et je vois "email rdubigny@alpha.gouv.fr"
Et je vois "prénomRaphael"
Et je vois "nomDubigny"
Et je vois "téléphone0123456789"
Et je vois "Création13/07/2018 17:35:15"
Et je vois "Dernière modification22/06/2023 16:34:34"
Et je vois "Email vérifié envoyé le22/06/2023 16:34:34"

Alors je dois voir un tableau nommé "Liste des modérations de Raphael" et contenant
| Type |
| 🔓Non vérifié |
Et je réinitialise le contexte

Sachant que je vais à l'intérieur de l'élément nommé "🔓 MFA"
Alors je vois "TOTP"
Alors je vois "Passkey - 1Password"
Alors je vois "Passkey - NordPass"

Sachant que je vais à l'intérieur de l'élément nommé "TOTP"
Alors je vois "TOTP enrôlé le : 22/06/2023 16:34:34"
Alors je vois "Force la 2FA sur tous les sites : ✅"
Et je réinitialise le contexte

Sachant que je vais à l'intérieur de l'élément nommé "Passkey - 1Password"
Alors je vois "Création : 23/06/2023 03:33:33"
Alors je vois "Dernière utilisation : 24/06/2023 04:44:44"
Alors je vois "Nombre d'utilisation : 5"
Et je réinitialise le contexte

Sachant que je vais à l'intérieur de l'élément nommé "Passkey - NordPass"
Alors je vois "Création : 23/06/2023 13:33:33"
Alors je vois "Dernière utilisation : 24/06/2023 14:44:44"
Alors je vois "Nombre d'utilisation : 87"
Et je réinitialise le contexte
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ Fonctionnalité: Page utilisateur
Quand je navigue sur la page
Et je vois "Bonjour Hyyypertool !"
Et je clique sur le bouton "ProConnect"
# Et je me connecte en tant que user@yopmail.com sur dev-agentconnect.fr

Scénario:
# Scénario: Fiche de Raphael
Quand je clique sur "Utilisateurs"
Alors je suis redirigé sur "/users"

Et je dois voir le titre de page "Liste des utilisateurs"
Et je vois "Liste des utilisateurs"
Quand je vais à l'intérieur de la rangée nommée "Utilisateur Raphael Dubigny (rdubigny@beta.gouv.fr)"
Et je clique sur "➡️"
Et je réinitialise le contexte

Et je dois voir le titre de page "Utilisateur Raphael Dubigny (rdubigny@beta.gouv.fr)"

Scénario: La fiche de Raphael Beta
Alors je vois "👨‍💻 A propos de l'utilisateur"
Et je vois "« Raphael Dubigny »"
Et je vois "email rdubigny@beta.gouv.fr"
Expand All @@ -27,7 +27,6 @@ Fonctionnalité: Page utilisateur
Et je vois "Dernière modification22/06/2023 16:34:34"
Et je vois "Email vérifié envoyé le22/06/2023 16:34:34"

# Scénario: Organisations de Raphael
Alors je vois "Raphael est enregistré(e) dans les organisations suivantes "
Et je vois "DINUM"
Et je vois "13002526500013"
Alors je dois voir un tableau nommé "Liste des organisations de Raphael" et contenant
| Libellé | Siret |
| DINUM | 13002526500013 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { schema, type IdentiteProconnect_PgDatabase } from "../../index";

export function insert_nordPass_authenticator(
db: IdentiteProconnect_PgDatabase,
user_id: number,
) {
return db.insert(schema.authenticators).values({
created_at: "2023-06-23T13:33:33+02:00",
display_name: "NordPass",
last_used_at: "2023-06-24T14:44:44+02:00",
usage_count: 87,
credential_id: "2",
credential_public_key: Buffer.from("mock-credential-key-data", "utf8"),
counter: 0,
credential_backed_up: false,
user_id,
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { schema, type IdentiteProconnect_PgDatabase } from "../../index";

export function insert_1Password_authenticator(
db: IdentiteProconnect_PgDatabase,
user_id: number,
) {
return db.insert(schema.authenticators).values({
created_at: "2023-06-23T03:33:33+02:00",
display_name: "1Password",
last_used_at: "2023-06-24T04:44:44+02:00",
usage_count: 5,
credential_id: "1",
credential_public_key: Buffer.from("mock-credential-key-data", "utf8"),
counter: 0,
credential_backed_up: false,
user_id,
});
}
8 changes: 8 additions & 0 deletions sources/infra/identite-proconnect/database/src/seed/insert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type { MCP_Moderation } from "@~/identite-proconnect.lib/identite-proconn
import consola from "consola";
import type { IdentiteProconnect_PgDatabase } from "../index";
import { schema } from "../index";
import { insert_nordPass_authenticator } from "./authenticators/nordPass";
import { insert_1Password_authenticator } from "./authenticators/onePassword";
import { insert_abracadabra } from "./organizations/abracadabra";
import { insert_aldp } from "./organizations/aldp";
import { insert_bosch_france } from "./organizations/bosch_france";
Expand Down Expand Up @@ -188,6 +190,12 @@ export async function insert_database(db: IdentiteProconnect_PgDatabase) {
consola.verbose(
`🌱 INSERT ${raphael_alpha.given_name} wants to join ${dinum.cached_nom_complet} again...`,
);
await insert_1Password_authenticator(db, raphael_alpha.id);
consola.verbose(
`🌱 INSERT ${raphael_alpha.given_name} OnePassword setup...`,
);
await insert_nordPass_authenticator(db, raphael_alpha.id);
consola.verbose(`🌱 INSERT ${raphael_alpha.given_name} NordPass setup...`);
} catch (err) {
console.error("Something went wrong...");
console.error(err);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ export async function insert_raphael_alpha(db: IdentiteProconnect_PgDatabase) {
created_at: "2018-07-13T17:35:15+02:00",
email: "rdubigny@alpha.gouv.fr",
family_name: "Dubigny",
force_2fa: true,
given_name: "Raphael",
job: "Chef",
phone_number: "0123456789",
totp_key_verified_at: "2023-06-22T16:34:34+02:00",
updated_at: "2023-06-22T16:34:34+02:00",
verify_email_sent_at: "2023-06-22T16:34:34+02:00",
})
Expand Down
6 changes: 5 additions & 1 deletion sources/users/api/src/:id/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type { App_Context } from "@~/app.middleware/context";
import { urls } from "@~/app.urls";
import type { IdentiteProconnect_PgDatabase } from "@~/identite-proconnect.database";
import { GetUserById } from "@~/users.repository";
import { GetAuthenticatorByUserId, GetUserById } from "@~/users.repository";
import type { Env, InferRequestType } from "hono";
import { useRequestContext } from "hono/jsx-renderer";

Expand All @@ -29,11 +29,15 @@ export async function loadUserPageVariables(
updated_at: true,
verify_email_sent_at: true,
totp_key_verified_at: true,
force_2fa: true,
},
});

const get_authenticators_by_user_id = GetAuthenticatorByUserId(pg);

return {
user: await get_user_by_id(id),
authenticators: await get_authenticators_by_user_id(id),
};
}

Expand Down
5 changes: 3 additions & 2 deletions sources/users/api/src/:id/moderations/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import { usePageRequestContext, type ModerationList } from "./context";

export function Table() {
const {
var: { moderations },
var: { describedby, moderations },
} = usePageRequestContext();

return (
<div class="fr-table *:table!">
<table>
<table aria-describedby={describedby}>
<thead>
<tr>
<th>ID</th>
Expand Down
23 changes: 5 additions & 18 deletions sources/users/api/src/:id/moderations/context.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,36 @@
//

import type { Entity_Schema, Pagination_Schema } from "@~/app.core/schema";
import type { App_Context } from "@~/app.middleware/context";
import type { DescribedBy } from "@~/app.core/schema";
import type { IdentiteProconnect_PgDatabase } from "@~/identite-proconnect.database";
import {
GetModerationsByUserId,
type GetModerationsByUserIdHandler,
} from "@~/moderations.repository/GetModerationsByUserId";
import type { Env } from "hono";
import { useRequestContext } from "hono/jsx-renderer";
import type { z } from "zod";

//

export async function loadModerationsPageVariables(
pg: IdentiteProconnect_PgDatabase,
{ user_id }: { user_id: number },
{ describedby, user_id }: { user_id: number } & DescribedBy,
) {
const get_moderations_by_user_id = GetModerationsByUserId({ pg });
const moderations = await get_moderations_by_user_id(user_id);

return {
describedby,
moderations,
};
}

//

export type ModerationList = Awaited<ReturnType<GetModerationsByUserIdHandler>>;
export interface ContextVariablesType extends Env {
interface ContextVariablesType extends Env {
Variables: Awaited<ReturnType<typeof loadModerationsPageVariables>>;
}
export type ContextType = App_Context & ContextVariablesType;

//

type PageInputType = {
out: {
param: z.input<typeof Entity_Schema>;
query: z.input<typeof Pagination_Schema>;
};
};

export const usePageRequestContext = useRequestContext<
ContextType,
any,
PageInputType
>;
export const usePageRequestContext = useRequestContext<ContextVariablesType>;
20 changes: 13 additions & 7 deletions sources/users/api/src/:id/moderations/index.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
//

import { zValidator } from "@hono/zod-validator";
import { Entity_Schema } from "@~/app.core/schema";
import { DescribedBy_Schema, Entity_Schema } from "@~/app.core/schema";
import type { App_Context } from "@~/app.middleware/context";
import { set_variables } from "@~/app.middleware/context/set_variables";
import { Hono } from "hono";
import { jsxRenderer } from "hono/jsx-renderer";
import { loadModerationsPageVariables, type ContextType } from "./context";
import { loadModerationsPageVariables } from "./context";
import { Table } from "./Table";

//

export default new Hono<ContextType>().use("/", jsxRenderer()).get(
export default new Hono<App_Context>().use("/", jsxRenderer()).get(
"/",
zValidator("param", Entity_Schema),
zValidator("query", DescribedBy_Schema),
async function set_variables_middleware(
{ req, set, var: { identite_pg } },
next,
) {
const { id: user_id } = req.valid("param");
const variables = await loadModerationsPageVariables(identite_pg, {
user_id,
});
set_variables(set, variables);
const { describedby } = req.valid("query");
set_variables(
set,
await loadModerationsPageVariables(identite_pg, {
describedby,
user_id,
}),
);
return next();
},
async function GET({ render }) {
Expand Down
Loading