diff --git a/src/db/index.js b/src/db/index.js index 9f3e335..fe6ad3d 100644 --- a/src/db/index.js +++ b/src/db/index.js @@ -178,7 +178,6 @@ export async function populateAgreements() { agreementUuid, ]); const agreement = { - "@context": json["@context"] || 'https://protocol.jlinc.org/context/jlinc-v7.jsonld', uri: `${config.publicCoreUrl}/agreements/${hash}`, purposes: json.purposes || [], prohibitions: json.prohibitions || [], diff --git a/src/db/migrations/000011 - context.sql b/src/db/migrations/000011 - context.sql new file mode 100644 index 0000000..a7ad38d --- /dev/null +++ b/src/db/migrations/000011 - context.sql @@ -0,0 +1 @@ +ALTER TABLE public.agreement ALTER COLUMN context SET DEFAULT NULL; \ No newline at end of file diff --git a/src/db/migrations/000012 - references.sql b/src/db/migrations/000012 - references.sql new file mode 100644 index 0000000..ff22522 --- /dev/null +++ b/src/db/migrations/000012 - references.sql @@ -0,0 +1,29 @@ +-- DROP TABLE IF EXISTS public.reference CASCADE; +CREATE TABLE public.reference ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT NOT NULL REFERENCES public.user(id), + uri TEXT NOT NULL UNIQUE, + created_ts TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_ts TIMESTAMPTZ NOT NULL DEFAULT NOW() +); +CREATE INDEX idx__public__reference__user_id ON public.reference (user_id); +CREATE INDEX idx__public__reference__created_ts ON public.reference (created_ts); +CREATE INDEX idx__public__reference__updated_ts ON public.reference (updated_ts); + +-- DROP TABLE IF EXISTS public.agreement_reference CASCADE; +CREATE TABLE public.agreement_reference ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT NOT NULL REFERENCES public.user(id), + agreement_id BIGINT NOT NULL REFERENCES public.agreement(id), + reference_id BIGINT NOT NULL REFERENCES public.reference(id), + created_ts TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_ts TIMESTAMPTZ NOT NULL DEFAULT NOW(), + CONSTRAINT uniq__agreement_reference_id UNIQUE (user_id, agreement_id, reference_id) +); +CREATE INDEX idx__public__agreement_reference__user_id ON public.agreement_reference (user_id); +CREATE INDEX idx__public__agreement_reference__agreement_id ON public.agreement_reference (agreement_id); +CREATE INDEX idx__public__agreement_reference__reference_id ON public.agreement_reference (reference_id); +CREATE INDEX idx__public__agreement_reference__created_ts ON public.agreement_reference (created_ts); +CREATE INDEX idx__public__agreement_reference__updated_ts ON public.agreement_reference (updated_ts); + +ALTER TABLE public.agreement ALTER COLUMN parent DROP NOT NULL; \ No newline at end of file diff --git a/src/modules/core/agreement.js b/src/modules/core/agreement.js index 816cff9..5d26135 100644 --- a/src/modules/core/agreement.js +++ b/src/modules/core/agreement.js @@ -3,10 +3,6 @@ const { JlincAgreement } = pkg; async function create(input) { - if (data.caveats) { - data.prohibitions = data.caveats; - delete data.caveats; - } const data = await JlincAgreement.create(input); const message = data?.agreementId; return { diff --git a/src/modules/core/data/agreement.js b/src/modules/core/data/agreement.js index 06b80ec..4be13e0 100644 --- a/src/modules/core/data/agreement.js +++ b/src/modules/core/data/agreement.js @@ -13,6 +13,18 @@ async function getAgreement(client, userId, id, key) { 'version', a.version, '@context', a.context, 'parent', a.parent, + 'references', ( + SELECT JSON_AGG(r.uri ORDER BY r.uri) + FROM reference r + INNER JOIN agreement_reference ar + ON r.id = ar.reference_id + AND ar.agreement_id = a.id + AND ( + (r.user_id = a.user_id AND ar.user_id = a.user_id) + OR + (r.user_id IS NULL AND ar.user_id IS NULL AND a.user_id IS NULL) + ) + ), 'agreementId', a.agreement_id_uuid, 'created', a.created, 'ids', ( @@ -54,7 +66,7 @@ async function getAgreement(client, userId, id, key) { (r.user_id = ar.user_id AND ar.user_id = a.user_id) OR (r.user_id IS NULL AND ar.user_id IS NULL AND a.user_id IS NULL) - ) + ) ) ) AS record FROM agreement a @@ -74,6 +86,16 @@ async function getAgreement(client, userId, id, key) { if (!ret.purposes) ret.purposes = []; if (!ret.prohibitions) ret.prohibitions = []; if (!ret.validRoles) ret.validRoles = []; + if (ret.version == 1) { + delete ret.references; + } else { + delete ret["@context"]; + delete ret.parent; + ret.permitted = ret.purposes; + delete ret.purposes; + ret.prohibited = ret.prohibitions; + delete ret.prohibitions; + } return ret; } return null; @@ -193,7 +215,44 @@ async function save(client, userId, agreement) { id, ]); } - for (const purpose of agreement.purposes) { + if (agreement.references) { + for (const reference of agreement.references) { + await client.query(` + INSERT INTO reference ( + user_id, + uri + ) VALUES ( + $1, + $2 + ) ON CONFLICT DO NOTHING; + `, [ + userId, + reference, + ]); + await client.query(` + INSERT INTO agreement_reference ( + user_id, + agreement_id, + reference_id + ) VALUES ( + $1, + $2, + ( + SELECT id + FROM reference + WHERE uri = $3 + AND user_id ${userId ? `= $1` : `IS NULL`} + ) + ); + `, [ + userId, + res.rows[0].id, + reference, + ]); + } + } + const purposes = agreement.version == 1 ? agreement.purposes : agreement.permitted; + for (const purpose of purposes) { await client.query(` INSERT INTO purpose ( user_id, @@ -227,7 +286,8 @@ async function save(client, userId, agreement) { purpose, ]); } - for (const prohibition of agreement.prohibitions) { + const prohibitions = agreement.version == 1 ? agreement.prohibitions : agreement.prohibited; + for (const prohibition of prohibitions) { await client.query(` INSERT INTO prohibition ( user_id,