From e2d0a20b45b00d4ed6df3660254697771768da35 Mon Sep 17 00:00:00 2001 From: Jalil Arfaoui Date: Tue, 17 Feb 2026 00:16:21 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20v=C3=A9rifier=20que=20la=20page=20Wikip?= =?UTF-8?q?edia=20existe=20et=20est=20une=20biographie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Appel à l'API MediaWiki pour valider que la page existe et possède la catégorie « Wikipédia:Article biographique ». Interface WikipediaValidator dans domain/services (port hexagonal), implémentation dans infra/. --- .../create-public-figure-with-statement.ts | 2 + domain/services/wikipedia-validator.ts | 8 ++++ infra/wikipedia/wikipedia-validator.ts | 46 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 domain/services/wikipedia-validator.ts create mode 100644 infra/wikipedia/wikipedia-validator.ts diff --git a/app/actions/create-public-figure-with-statement.ts b/app/actions/create-public-figure-with-statement.ts index 3d8c056..ba5817a 100644 --- a/app/actions/create-public-figure-with-statement.ts +++ b/app/actions/create-public-figure-with-statement.ts @@ -11,6 +11,7 @@ import { createPublicFigureWithStatementUseCase, FieldErrors, } from '../../domain/use-cases/create-public-figure-with-statement' +import { createWikipediaValidator } from '../../infra/wikipedia/wikipedia-validator' import { getAuthenticatedContributor } from './get-authenticated-contributor' export type ActionResult = @@ -41,6 +42,7 @@ export async function createPublicFigureWithStatementAction( subjectRepo: createSubjectRepository(supabase), publicFigureRepo: createPublicFigureRepository(supabase), reputationRepo: createReputationRepository(supabase), + wikipediaValidator: createWikipediaValidator(), }) if (Either.isLeft(result)) { diff --git a/domain/services/wikipedia-validator.ts b/domain/services/wikipedia-validator.ts new file mode 100644 index 0000000..580bba9 --- /dev/null +++ b/domain/services/wikipedia-validator.ts @@ -0,0 +1,8 @@ +export interface WikipediaValidationResult { + exists: boolean + isBiography: boolean +} + +export interface WikipediaValidator { + validatePage(url: string): Promise +} diff --git a/infra/wikipedia/wikipedia-validator.ts b/infra/wikipedia/wikipedia-validator.ts new file mode 100644 index 0000000..c2cde8e --- /dev/null +++ b/infra/wikipedia/wikipedia-validator.ts @@ -0,0 +1,46 @@ +import { + WikipediaValidator, + WikipediaValidationResult, +} from '../../domain/services/wikipedia-validator' + +const BIOGRAPHY_CATEGORY = 'Catégorie:Wikipédia:Article biographique' + +function extractLangAndTitle(url: string): { lang: string; title: string } | null { + const match = url.match(/^https:\/\/(fr|en)\.wikipedia\.org\/wiki\/(.+)$/) + if (!match) return null + return { lang: match[1], title: match[2] } +} + +export function createWikipediaValidator(): WikipediaValidator { + return { + async validatePage(url: string): Promise { + const parsed = extractLangAndTitle(url) + if (!parsed) return { exists: false, isBiography: false } + + const apiUrl = + `https://${parsed.lang}.wikipedia.org/w/api.php` + + `?action=query&format=json&prop=categories&titles=${encodeURIComponent(parsed.title)}&cllimit=50` + + const response = await fetch(apiUrl, { + headers: { 'User-Agent': 'Debats.co/1.0 (https://debats.co)' }, + }) + + if (!response.ok) return { exists: false, isBiography: false } + + const data = await response.json() + const pages = data.query?.pages + if (!pages) return { exists: false, isBiography: false } + + const page = Object.values(pages)[0] as { missing?: string; categories?: { title: string }[] } + + if ('missing' in page) { + return { exists: false, isBiography: false } + } + + const categories = page.categories ?? [] + const isBiography = categories.some((c) => c.title === BIOGRAPHY_CATEGORY) + + return { exists: true, isBiography } + }, + } +}