Skip to content

Commit

Permalink
feat(moderation): remove member when reproessing a moderation
Browse files Browse the repository at this point in the history
  • Loading branch information
douglasduteil committed Oct 7, 2024
1 parent 0f8d383 commit cc33db7
Show file tree
Hide file tree
Showing 20 changed files with 288 additions and 65 deletions.
3 changes: 0 additions & 3 deletions e2e/features/moderations/jean_bon_join_dinum.feature
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,3 @@ Fonctionnalité: Moderation blockante à refuser
Quand sur la même ligne je clique sur "➡️"
Alors je vois "Jean Bon veut rejoindre l'organisation « DINUM » avec l’adresse [email protected]"

# Quand je clique sur "Sélectionner une response"
# * je sélectionne "Quel lien avec l'organisation ?"
# * je clique "🪄 Marquer comme traité"
25 changes: 25 additions & 0 deletions e2e/features/moderations/reprocess_marie_bon_bosch.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

#language: fr
Fonctionnalité: Retraiter une moderation

Contexte:
Soit une base de données nourrie au grain
Quand je navigue sur la page
* je vois "Bonjour Hyyypertool !"
* je clique sur le bouton "ProConnect"
Alors je vois "Liste des moderations"
* je clique sur "Voir les demandes traitées"
* je clique sur "Filtrer par jours"
* je tape "2011-11-12"
* je vois la ligne de table "44023386400014"
* sur la même ligne je clique sur "✅"
* je vois "Cette modération a été marqué comme traité"
* je vois "Marie Bon a rejoint une organisation avec un domain non vérifié « Bosch rexroth d.s.i. »"

@only
Scénario: Marie Bon à rejoindre l'organisation Bosch par erreur
Quand je clique sur "Retraiter"
Alors je ne vois pas "Cette modération a été marqué comme traité"

Soit le tableau sous le title "membre connu dans l’organisation"
Alors le tableau est vide
1 change: 0 additions & 1 deletion e2e/features/moderations/richard_bon_join_dengi.feature
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ Fonctionnalité: Duplicate Moderation
* sur la même ligne je vois "Richard"
* sur la même ligne je vois "[email protected]"

# Scénario:
Quand sur la même ligne je clique sur "➡️"
Alors je vois "Richard Bon veut rejoindre l'organisation « Dengi - Leclerc »"

Expand Down
1 change: 1 addition & 0 deletions packages/~/infra/moncomptepro/database/src/seed/insert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export async function insert_database(db: MonComptePro_PgDatabase) {
);

await insert_moderation(db, {
created_at: new Date("2011-11-12 11:11:12").toISOString(),
organization_id: bosch_rexroth.id,
type: "non_verified_domain" as MCP_Moderation["type"],
user_id: marie_bon.id,
Expand Down
33 changes: 15 additions & 18 deletions packages/~/moderations/api/src/:id/$procedures/reprocess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,34 @@ import { zValidator } from "@hono/zod-validator";
import type { Htmx_Header } from "@~/app.core/htmx";
import { Entity_Schema } from "@~/app.core/schema";
import type { App_Context } from "@~/app.middleware/context";
import { append_comment } from "@~/moderations.lib/comment_message";
import { MODERATION_EVENTS } from "@~/moderations.lib/event";
import { update_moderation_by_id } from "@~/moderations.repository/update_moderation_by_id";
import { schema } from "@~/moncomptepro.database";
import { eq } from "drizzle-orm";
import { ReprocessModerationById } from "@~/moderations.lib/usecase/ReprocessModerationById";
import {
GetModerationById,
RemoveUserFromOrganization,
UpdateModerationById,
} from "@~/moderations.repository";
import { Hono } from "hono";

//

export default new Hono<App_Context>().patch(
"/",
zValidator("param", Entity_Schema),
async ({ text, req, notFound, var: { moncomptepro_pg, userinfo } }) => {
async ({ text, req, var: { moncomptepro_pg, userinfo } }) => {
const { id } = req.valid("param");
const moderation = await moncomptepro_pg.query.moderations.findFirst({
columns: { comment: true },
where: eq(schema.moderations.id, id),
});
if (!moderation) return notFound();
const { comment } = moderation;

await update_moderation_by_id(moncomptepro_pg, {
comment: append_comment(comment, {
type: "REPROCESSED",
created_by: userinfo.email,
const reprocess_moderation_by_id = ReprocessModerationById({
get_moderation_by_id: GetModerationById({ pg: moncomptepro_pg }),
remove_user_from_organization: RemoveUserFromOrganization({
pg: moncomptepro_pg,
}),
moderation_id: id,
moderated_by: null,
moderated_at: null,
update_moderation_by_id: UpdateModerationById({ pg: moncomptepro_pg }),
userinfo,
});

await reprocess_moderation_by_id(id);

return text("OK", 200, {
"HX-Trigger": MODERATION_EVENTS.Enum.MODERATION_UPDATED,
} as Htmx_Header);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import {
schema,
type MonCompteProDatabaseCradle,
} from "@~/moncomptepro.database";
import type { UserOrganizationIdPair } from "@~/organizations.lib/entities/Organization";
import { and, eq } from "drizzle-orm";

//

type UserOrganizationIdPair = { user_id: number; organization_id: number };

export function IsUserExternalMember({ pg }: MonCompteProDatabaseCradle) {
return async function is_user_external_member({
organization_id,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//

import { beforeAll, expect, mock, setSystemTime, test } from "bun:test";
import { ReprocessModerationById } from "./ReprocessModerationById";

//

const userinfo = { email: "[email protected]" };

beforeAll(() => {
setSystemTime(new Date("2222-01-01T00:00:00.000Z"));
});

test("reprocess a moderation", async () => {
const get_moderation_by_id = mock().mockResolvedValueOnce({
comment: "",
organization_id: 1,
user_id: 1,
});
const update_moderation_by_id = mock();
const remove_user_from_organization = mock();

const reprocess_moderation_by_id = ReprocessModerationById({
get_moderation_by_id,
update_moderation_by_id,
remove_user_from_organization,
userinfo,
});
await reprocess_moderation_by_id(1);

expect(get_moderation_by_id).toHaveBeenLastCalledWith(1, {
columns: {
comment: true,
organization_id: true,
user_id: true,
},
});
expect(update_moderation_by_id).toHaveBeenLastCalledWith(1, {
comment: "7952342400000 [email protected] | Réouverte par [email protected]",
moderated_by: null,
moderated_at: null,
});
expect(remove_user_from_organization).toHaveBeenLastCalledWith({
organization_id: 1,
user_id: 1,
});
});
44 changes: 44 additions & 0 deletions packages/~/moderations/lib/src/usecase/ReprocessModerationById.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//

import type {
GetModerationByIdHandler,
RemoveUserFromOrganizationHandler,
UpdateModerationByIdHandler,
} from "@~/moderations.repository";
import { append_comment } from "../comment_message";

//

export function ReprocessModerationById({
get_moderation_by_id,
remove_user_from_organization,
update_moderation_by_id,
userinfo,
}: {
get_moderation_by_id: GetModerationByIdHandler;
remove_user_from_organization: RemoveUserFromOrganizationHandler;
update_moderation_by_id: UpdateModerationByIdHandler;
userinfo: { email: string };
}) {
return async function reprocess_moderation_by_id(id: number) {
const moderation = await get_moderation_by_id(id, {
columns: { comment: true, organization_id: true, user_id: true },
});

const comment = append_comment(moderation.comment, {
type: "REPROCESSED",
created_by: userinfo.email,
});

await remove_user_from_organization({
organization_id: moderation.organization_id,
user_id: moderation.user_id,
});

await update_moderation_by_id(id, {
comment,
moderated_by: null,
moderated_at: null,
});
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { NotFoundError } from "@~/app.core/error";
import { z_username } from "@~/app.core/schema/z_username";
import { create_conversation } from "@~/crisp.lib";
import { update_moderation_by_id } from "@~/moderations.repository/update_moderation_by_id";
import { UpdateModerationById } from "@~/moderations.repository";
import type {
RejectedFullMessage,
RejectedModeration_Context,
Expand Down Expand Up @@ -32,8 +32,8 @@ export async function create_and_send_email_to_user(
nickname,
});

await update_moderation_by_id(pg, {
moderation_id: moderation.id,
const update_moderation_by_id = UpdateModerationById({ pg });
await update_moderation_by_id(moderation.id, {
ticket_id: session_id,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import { z_username } from "@~/app.core/schema/z_username";
import type { AgentConnect_UserInfo } from "@~/app.middleware/session";
import { UpdateModerationById } from "@~/moderations.repository";
import type { get_moderation_dto } from "@~/moderations.repository/get_moderation";
import { update_moderation_by_id } from "@~/moderations.repository/update_moderation_by_id";
import type { MonComptePro_PgDatabase } from "@~/moncomptepro.database";
import { append_comment } from "../comment_message";

Expand All @@ -21,12 +21,12 @@ export async function mark_moderatio_as_rejected({
const { comment, id: moderation_id } = moderation;
const moderated_by = z_username.parse(userinfo);

await update_moderation_by_id(pg, {
const update_moderation_by_id = UpdateModerationById({ pg });
await update_moderation_by_id(moderation_id, {
comment: append_comment(comment, {
created_by: userinfo.email,
type: "REJECTED",
}),
moderation_id,
moderated_by,
moderated_at: new Date().toISOString(),
});
Expand Down
6 changes: 3 additions & 3 deletions packages/~/moderations/lib/src/usecase/mark_moderation_as.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { z_username } from "@~/app.core/schema/z_username";
import type { AgentConnect_UserInfo } from "@~/app.middleware/session";
import { update_moderation_by_id } from "@~/moderations.repository/update_moderation_by_id";
import { UpdateModerationById } from "@~/moderations.repository";
import type { MonComptePro_PgDatabase, schema } from "@~/moncomptepro.database";
import { append_comment, type Comment_Type } from "../comment_message";

Expand All @@ -24,12 +24,12 @@ export async function mark_moderation_as(
const username = z_username.parse(userinfo);
const moderated_by = `${username} <${userinfo.email}>`;

await update_moderation_by_id(pg, {
const update_moderation_by_id = UpdateModerationById({ pg });
await update_moderation_by_id(moderation_id, {
comment: append_comment(comment, {
created_by: userinfo.email,
type,
}),
moderation_id,
moderated_by,
moderated_at: new Date().toISOString(),
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//

import { schema } from "@~/moncomptepro.database";
import {
create_adora_pony_user,
create_unicorn_organization,
} from "@~/moncomptepro.database/seed/unicorn";
import { empty_database, migrate, pg } from "@~/moncomptepro.database/testing";
import { beforeAll, beforeEach, expect, setSystemTime, test } from "bun:test";
import { RemoveUserFromOrganization } from "./RemoveUserFromOrganization";

//

beforeAll(migrate);
beforeEach(empty_database);

beforeAll(() => {
setSystemTime(new Date("2222-01-01T00:00:00.000Z"));
});

//

test("remove adora from unicorn organization", async () => {
const unicorn_organization_id = await create_unicorn_organization(pg);
const adora_pony_user_id = await create_adora_pony_user(pg);

await pg.insert(schema.users_organizations).values({
organization_id: unicorn_organization_id,
user_id: adora_pony_user_id,
});

const remove_user_from_organization = RemoveUserFromOrganization({ pg });
const response = await remove_user_from_organization({
organization_id: unicorn_organization_id,
user_id: adora_pony_user_id,
});

expect(response).toEqual({
affectedRows: 1,
fields: [],
rows: [],
});
});

test("do nothing if adora is not a unicorn member", async () => {
const unicorn_organization_id = await create_unicorn_organization(pg);
const adora_pony_user_id = await create_adora_pony_user(pg);

const remove_user_from_organization = RemoveUserFromOrganization({ pg });
const response = await remove_user_from_organization({
organization_id: unicorn_organization_id,
user_id: adora_pony_user_id,
});

expect(response).toEqual({
affectedRows: 0,
fields: [],
rows: [],
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//

import {
schema,
type MonCompteProDatabaseCradle,
} from "@~/moncomptepro.database";
import type { UserOrganizationIdPair } from "@~/organizations.lib/entities/Organization";
import { and, eq } from "drizzle-orm";

//

export function RemoveUserFromOrganization({ pg }: MonCompteProDatabaseCradle) {
return async function remove_user_from_organization({
organization_id,
user_id,
}: UserOrganizationIdPair) {
return pg
.delete(schema.users_organizations)
.where(
and(
eq(schema.users_organizations.organization_id, organization_id),
eq(schema.users_organizations.user_id, user_id),
),
);
};
}

export type RemoveUserFromOrganizationHandler = ReturnType<
typeof RemoveUserFromOrganization
>;
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from "@~/moncomptepro.database/seed/unicorn";
import { empty_database, migrate, pg } from "@~/moncomptepro.database/testing";
import { beforeAll, expect, setSystemTime, test } from "bun:test";
import { update_moderation_by_id } from "./update_moderation_by_id";
import { UpdateModerationById } from "./UpdateModerationById";

//

Expand All @@ -18,6 +18,8 @@ beforeAll(() => {
setSystemTime(new Date("2222-01-01T00:00:00.000Z"));
});

const update_moderation_by_id = UpdateModerationById({ pg });

//

test("update a moderation", async () => {
Expand All @@ -26,8 +28,7 @@ test("update a moderation", async () => {
const moderation_id = await create_adora_pony_moderation(pg, { type: "" });

setSystemTime(new Date("2222-01-02T00:00:00.000Z"));
await update_moderation_by_id(pg, {
moderation_id,
await update_moderation_by_id(moderation_id, {
comment: "Adora is a good pony",
moderated_by: "Captain Midnight",
moderated_at: new Date().toISOString(),
Expand Down
Loading

0 comments on commit cc33db7

Please sign in to comment.