diff --git a/src/lib/aggregates.ts b/src/lib/aggregates.ts
index dce814b..5d09d6d 100644
--- a/src/lib/aggregates.ts
+++ b/src/lib/aggregates.ts
@@ -1,23 +1,36 @@
import type {
Article,
+ DossierLegislatif,
+ Idcc,
+ Jo,
SectionTa,
Textekali,
Textelr,
TexteVersion,
+ Versions,
} from "$lib/legal"
export interface Aggregate {
article?: { [id: string]: Article }
+ dossier_legislatif?: { [id: string]: DossierLegislatif }
id?: string
+ idcc?: { [id: string]: Idcc }
ids?: string[]
+ jo?: { [id: string]: Jo }
section_ta?: { [id: string]: SectionTa }
texte_version?: { [id: string]: TexteVersion }
textekali?: { [id: string]: Textekali }
textelr?: { [id: string]: Textelr }
+ versions?: { [eli: string]: Versions }
}
export type Follow = typeof allFollows[number]
+export interface GetArticleResult extends Aggregate {
+ follow: Follow[]
+ id: string
+}
+
export interface GetRechercheResult extends Aggregate {
follow: Follow[]
id?: string
diff --git a/src/lib/components/ArticleView.svelte b/src/lib/components/ArticleView.svelte
index 090267c..91e8e57 100644
--- a/src/lib/components/ArticleView.svelte
+++ b/src/lib/components/ArticleView.svelte
@@ -1,12 +1,20 @@
@@ -17,3 +25,13 @@
{/if}
{@html article.BLOC_TEXTUEL.CONTENU}
+
+{#if ciblesCreation.length > 0}
+
+ {#each liens as lien}
+ -
+
+
+ {/each}
+
+{/if}
diff --git a/src/lib/components/LienView.svelte b/src/lib/components/LienView.svelte
new file mode 100644
index 0000000..8c416e5
--- /dev/null
+++ b/src/lib/components/LienView.svelte
@@ -0,0 +1,92 @@
+
+
+{#if componentAndProperties === undefined}
+
+{:else}
+
+
+ {lien["#text"]}
+
+ {#if open}
+
+
+
+ {/if}
+{/if}
diff --git a/src/lib/components/SectionTaView.svelte b/src/lib/components/SectionTaView.svelte
index 20aca86..1f661ac 100644
--- a/src/lib/components/SectionTaView.svelte
+++ b/src/lib/components/SectionTaView.svelte
@@ -28,7 +28,7 @@
{#each [...iterArrayOrSingleton(sectionTa.STRUCTURE_TA.LIEN_ART)] as lienArt}
{@const article = data.article?.[lienArt["@id"]]}
{#if article !== undefined}
-
+
{/if}
{/each}
{:else if sectionTa.STRUCTURE_TA.LIEN_ART !== undefined}
diff --git a/src/lib/components/TextelrView.svelte b/src/lib/components/TextelrView.svelte
index 389dd10..ff4c2d9 100644
--- a/src/lib/components/TextelrView.svelte
+++ b/src/lib/components/TextelrView.svelte
@@ -16,7 +16,7 @@
{#each [...iterArrayOrSingleton(textelr.STRUCT.LIEN_ART)] as lienArt}
{@const article = data.article?.[lienArt["@id"]]}
{#if article !== undefined}
-
+
{/if}
{/each}
{:else if textelr.STRUCT.LIEN_ART !== undefined}
diff --git a/src/lib/legal.ts b/src/lib/legal.ts
index 5af66a1..7c502b2 100644
--- a/src/lib/legal.ts
+++ b/src/lib/legal.ts
@@ -395,6 +395,9 @@ export function pathnameFromLegalId(id: string): string | undefined {
if (rootType === undefined) {
return undefined
}
+ if (rootType === "article") {
+ return `/articles/${id}`
+ }
if (["texte_version", "textekali", "textelr"].includes(rootType)) {
return `/textes/${id}`
}
@@ -407,7 +410,8 @@ export function pathnameFromLegalObject(
): string {
switch (type) {
case "article":
- return `/article/${(object as Article).META.META_COMMUN.ID}`
+ // return `/article/${(object as Article).META.META_COMMUN.ID}`
+ return `/articles/${(object as Article).META.META_COMMUN.ID}`
case "dossier_legislatif":
return `/dossier_legislatif/${
(object as DossierLegislatif).META.META_COMMUN.ID
@@ -442,7 +446,8 @@ export function pathnameFromLegalObjectId(
): string {
switch (type) {
case "article":
- return `/article/${id}`
+ // return `/article/${id}`
+ return `/articles/${id}`
case "dossier_legislatif":
return `/dossier_legislatif/${id}`
case "id":
diff --git a/src/routes/api/articles/[id]/+server.ts b/src/routes/api/articles/[id]/+server.ts
new file mode 100644
index 0000000..c569cfd
--- /dev/null
+++ b/src/routes/api/articles/[id]/+server.ts
@@ -0,0 +1,91 @@
+import { type Audit, auditSetNullish, cleanAudit } from "@auditors/core"
+import { error } from "@sveltejs/kit"
+
+import { auditFollowSearchParams } from "$lib/auditors/search_params"
+
+import type { Follow } from "$lib/aggregates"
+import type { Article } from "$lib/legal"
+import { Aggregator } from "$lib/server/aggregates"
+import { db } from "$lib/server/database"
+
+import type { RequestHandler } from "./$types"
+
+export function auditSearchParams(
+ audit: Audit,
+ query: URLSearchParams,
+): [unknown, unknown] {
+ if (query == null) {
+ return [query, null]
+ }
+ if (!(query instanceof URLSearchParams)) {
+ return audit.unexpectedType(query, "URLSearchParams")
+ }
+
+ const data: { [key: string]: unknown } = {}
+ for (const [key, value] of query.entries()) {
+ let values = data[key] as string[] | undefined
+ if (values === undefined) {
+ values = data[key] = []
+ }
+ values.push(value)
+ }
+ const errors: { [key: string]: unknown } = {}
+ const remainingKeys = new Set(Object.keys(data))
+
+ auditFollowSearchParams(audit, data, errors, remainingKeys)
+
+ return audit.reduceRemaining(data, errors, remainingKeys, auditSetNullish({}))
+}
+
+export const GET: RequestHandler = async ({ params, url }) => {
+ const [query, queryError] = auditSearchParams(
+ cleanAudit,
+ url.searchParams,
+ ) as [
+ {
+ follow: Set
+ },
+ unknown,
+ ]
+ if (queryError !== null) {
+ console.error(
+ `Error in ${url.pathname} query:\n${JSON.stringify(
+ query,
+ null,
+ 2,
+ )}\n\nError:\n${JSON.stringify(queryError, null, 2)}`,
+ )
+ throw error(400, JSON.stringify(queryError, null, 2))
+ }
+ const { follow } = query
+ const article = (
+ await db<{ data: Article }[]>`
+ SELECT data FROM article
+ WHERE ID = ${params.id}
+ `
+ ).map(({ data }) => data)[0]
+ if (article === undefined) {
+ throw error(404, `ARTICLE ${params.id} non trouvé`)
+ }
+
+ const aggregator = new Aggregator(follow)
+ aggregator.addArticle(article)
+ await aggregator.getAll()
+
+ return new Response(
+ JSON.stringify(
+ {
+ ...aggregator.toJson(),
+ follow: [...follow],
+ id: params.id,
+ },
+ null,
+ 2,
+ ),
+ {
+ headers: {
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ },
+ )
+}
diff --git a/src/routes/articles/[id]/+page.svelte b/src/routes/articles/[id]/+page.svelte
new file mode 100644
index 0000000..7e3c1fa
--- /dev/null
+++ b/src/routes/articles/[id]/+page.svelte
@@ -0,0 +1,44 @@
+
+
+
+
+
+ Articles
+ {#if summary !== undefined}
+
+
+
+ {/if}
+
+
+
+
+{#if showRawData}
+
+{:else}
+
+{/if}
diff --git a/src/routes/articles/[id]/+page.ts b/src/routes/articles/[id]/+page.ts
new file mode 100644
index 0000000..25101e2
--- /dev/null
+++ b/src/routes/articles/[id]/+page.ts
@@ -0,0 +1,78 @@
+import { error } from "@sveltejs/kit"
+import { type Audit, auditSetNullish, cleanAudit } from "@auditors/core"
+
+import type { Follow, GetArticleResult } from "$lib/aggregates"
+import { auditFollowWithFalseSearchParams } from "$lib/auditors/search_params"
+import { urlFromUrlAndQuery } from "$lib/urls"
+
+import type { PageLoad } from "./$types"
+
+export function auditSearchParams(
+ audit: Audit,
+ query: URLSearchParams,
+): [unknown, unknown] {
+ if (query == null) {
+ return [query, null]
+ }
+ if (!(query instanceof URLSearchParams)) {
+ return audit.unexpectedType(query, "URLSearchParams")
+ }
+
+ const data: { [key: string]: unknown } = {}
+ for (const [key, value] of query.entries()) {
+ let values = data[key] as string[] | undefined
+ if (values === undefined) {
+ values = data[key] = []
+ }
+ values.push(value)
+ }
+ const errors: { [key: string]: unknown } = {}
+ const remainingKeys = new Set(Object.keys(data))
+
+ auditFollowWithFalseSearchParams(audit, data, errors, remainingKeys)
+
+ return audit.reduceRemaining(data, errors, remainingKeys, auditSetNullish({}))
+}
+
+export const load: PageLoad = async ({ fetch, url }) => {
+ const [query, queryError] = auditSearchParams(
+ cleanAudit,
+ url.searchParams,
+ ) as [
+ {
+ follow: Set
+ },
+ unknown,
+ ]
+ if (queryError !== null) {
+ console.error(
+ `Error in ${url.pathname} query:\n${JSON.stringify(
+ query,
+ null,
+ 2,
+ )}\n\nError:\n${JSON.stringify(queryError, null, 2)}`,
+ )
+ throw error(400, JSON.stringify(queryError, null, 2))
+ }
+ const { follow: requestedFollow } = query
+
+ let follow = new Set(requestedFollow)
+ const followFalse = follow.delete("false")
+ if (follow.size === 0 && !followFalse) {
+ // Set default follow
+ follow = new Set(["LIENS.LIEN[@sens=cible,@typelien=CREATION].@id"])
+ }
+
+ const apiUrl = urlFromUrlAndQuery(`/api${url.pathname}`, { follow })
+ const response = await fetch(apiUrl, {
+ headers: { Accept: "application/json" },
+ })
+ if (!response.ok) {
+ const text = await response.text()
+ console.error(
+ `Error in ${url.pathname} while calling ${apiUrl}:\n${response.status} ${response.statusText}\n\n${text}`,
+ )
+ throw error(response.status, text)
+ }
+ return (await response.json()) as GetArticleResult
+}