Improve GVL explorer usability and evidence workflows
Dieser Commit ist enthalten in:
@@ -29,6 +29,22 @@ async function handleVendorGetMessage(message, sender) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (message.type === "export_gvl_evidence_json") {
|
||||
return handleExportGvlEvidenceJsonMessage();
|
||||
}
|
||||
|
||||
if (message.type === "export_gvl_revision_evidence_json") {
|
||||
return handleExportGvlRevisionEvidenceJsonMessage(message);
|
||||
}
|
||||
|
||||
if (message.type === "verify_gvl_revision_evidence_json") {
|
||||
return handleVerifyGvlRevisionEvidenceJsonMessage(message);
|
||||
}
|
||||
|
||||
if (message.type === "import_gvl_evidence_json") {
|
||||
return handleImportGvlEvidenceJsonMessage(message);
|
||||
}
|
||||
|
||||
if (message.type === "gvl_import_json") {
|
||||
return handleGvlImportJsonMessage(message);
|
||||
}
|
||||
@@ -196,6 +212,59 @@ async function handleExportEvidenceJsonMessage() {
|
||||
};
|
||||
}
|
||||
|
||||
async function handleExportGvlEvidenceJsonMessage() {
|
||||
return {
|
||||
success: true,
|
||||
export: await exportVendorGetGvlEvidenceJson()
|
||||
};
|
||||
}
|
||||
|
||||
async function handleExportGvlRevisionEvidenceJsonMessage(message) {
|
||||
try {
|
||||
return {
|
||||
success: true,
|
||||
export: await exportVendorGetGvlRevisionEvidenceJson(
|
||||
message?.payload?.snapshotSha256 ?? null
|
||||
)
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error?.message ?? String(error)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function handleVerifyGvlRevisionEvidenceJsonMessage(message) {
|
||||
try {
|
||||
return {
|
||||
success: true,
|
||||
verification: await verifyVendorGetGvlRevisionEvidenceJson(
|
||||
message?.payload?.export ?? null
|
||||
)
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error?.message ?? String(error)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function handleImportGvlEvidenceJsonMessage(message) {
|
||||
try {
|
||||
return {
|
||||
success: true,
|
||||
import: await importVendorGetGvlEvidenceJson(message?.payload?.export)
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error?.message ?? String(error)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function handleGetLatestGvlUpdateStatusMessage() {
|
||||
const db = await openVendorGetDb();
|
||||
const latestSnapshot = await getLatestGvlSnapshotByVendorListVersion(db);
|
||||
@@ -445,11 +514,13 @@ async function handleGetGvlVendorDetailMessage(message) {
|
||||
const rawEvidence = rawGvlSha256
|
||||
? await getGvlRawEvidenceBySha256(db, rawGvlSha256)
|
||||
: null;
|
||||
const gvlInfo = await getGvlVendorDetailGvlInfo(db, vendorRecord);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
vendorDetail: {
|
||||
vendor: vendorRecord,
|
||||
gvlInfo,
|
||||
snapshot: buildGvlVendorDetailSnapshotSummary(snapshot, snapshotSha256),
|
||||
rawEvidence: buildGvlVendorDetailRawEvidenceSummary(
|
||||
rawEvidence,
|
||||
@@ -459,6 +530,255 @@ async function handleGetGvlVendorDetailMessage(message) {
|
||||
};
|
||||
}
|
||||
|
||||
async function getGvlVendorDetailGvlInfo(db, vendorRecord) {
|
||||
const vendorListVersion = vendorRecord?.vendorListVersion ?? null;
|
||||
const vendorId = vendorRecord?.vendorId ?? null;
|
||||
|
||||
if (vendorListVersion === null || vendorId === null) {
|
||||
return buildEmptyGvlVendorDetailGvlInfo();
|
||||
}
|
||||
|
||||
const relationships = await getGvlVendorRelationshipsForVendor(
|
||||
db,
|
||||
vendorListVersion,
|
||||
vendorId
|
||||
);
|
||||
const catalogs = await getGvlVendorDetailCatalogs(db, vendorListVersion);
|
||||
const rawVendor = vendorRecord?.rawVendor ?? {};
|
||||
|
||||
return {
|
||||
purposes: buildGvlVendorDetailCatalogList(
|
||||
rawVendor.purposes,
|
||||
relationships.purpose,
|
||||
catalogs.purposes
|
||||
),
|
||||
legIntPurposes: buildGvlVendorDetailCatalogList(
|
||||
rawVendor.legIntPurposes,
|
||||
relationships.legIntPurpose,
|
||||
catalogs.purposes
|
||||
),
|
||||
flexiblePurposes: buildGvlVendorDetailCatalogList(
|
||||
rawVendor.flexiblePurposes,
|
||||
relationships.flexiblePurpose,
|
||||
catalogs.purposes
|
||||
),
|
||||
specialPurposes: buildGvlVendorDetailCatalogList(
|
||||
rawVendor.specialPurposes,
|
||||
relationships.specialPurpose,
|
||||
catalogs.specialPurposes
|
||||
),
|
||||
features: buildGvlVendorDetailCatalogList(
|
||||
rawVendor.features,
|
||||
relationships.feature,
|
||||
catalogs.features
|
||||
),
|
||||
specialFeatures: buildGvlVendorDetailCatalogList(
|
||||
rawVendor.specialFeatures,
|
||||
relationships.specialFeature,
|
||||
catalogs.specialFeatures
|
||||
),
|
||||
dataDeclaration: buildGvlVendorDetailCatalogList(
|
||||
rawVendor.dataDeclaration,
|
||||
[],
|
||||
catalogs.dataCategories
|
||||
),
|
||||
dataCategoriesTextAvailable: catalogs.dataCategories.size > 0,
|
||||
dataRetention: rawVendor.dataRetention ?? null,
|
||||
overflow: rawVendor.overflow ?? null
|
||||
};
|
||||
}
|
||||
|
||||
function buildEmptyGvlVendorDetailGvlInfo() {
|
||||
return {
|
||||
purposes: [],
|
||||
legIntPurposes: [],
|
||||
flexiblePurposes: [],
|
||||
specialPurposes: [],
|
||||
features: [],
|
||||
specialFeatures: [],
|
||||
dataDeclaration: [],
|
||||
dataCategoriesTextAvailable: false,
|
||||
dataRetention: null,
|
||||
overflow: null
|
||||
};
|
||||
}
|
||||
|
||||
function getGvlVendorRelationshipsForVendor(db, vendorListVersion, vendorId) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const storeName = VENDORGET_STORE_NAMES.gvlVendorRelationships;
|
||||
const tx = db.transaction([storeName], "readonly");
|
||||
const relationshipsStore = tx.objectStore(storeName);
|
||||
const vendorIdIndex = relationshipsStore.index("vendorId");
|
||||
const cursorRequest = vendorIdIndex.openCursor(IDBKeyRange.only(vendorId));
|
||||
const relationships = {};
|
||||
|
||||
cursorRequest.onerror = () => reject(cursorRequest.error);
|
||||
cursorRequest.onsuccess = () => {
|
||||
const cursor = cursorRequest.result;
|
||||
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const record = cursor.value;
|
||||
|
||||
if (record?.vendorListVersion === vendorListVersion) {
|
||||
const relationshipType = record.relationshipType ?? "unknown";
|
||||
|
||||
if (!relationships[relationshipType]) {
|
||||
relationships[relationshipType] = [];
|
||||
}
|
||||
|
||||
relationships[relationshipType].push(record.relatedId);
|
||||
}
|
||||
|
||||
cursor.continue();
|
||||
};
|
||||
|
||||
tx.onerror = () => reject(tx.error);
|
||||
tx.onabort = () => reject(tx.error);
|
||||
tx.oncomplete = () => resolve(relationships);
|
||||
});
|
||||
}
|
||||
|
||||
async function getGvlVendorDetailCatalogs(db, vendorListVersion) {
|
||||
const [
|
||||
purposes,
|
||||
specialPurposes,
|
||||
features,
|
||||
specialFeatures,
|
||||
dataCategories
|
||||
] = await Promise.all([
|
||||
getGvlCatalogMapForVersion(
|
||||
db,
|
||||
VENDORGET_STORE_NAMES.gvlPurposes,
|
||||
vendorListVersion
|
||||
),
|
||||
getGvlCatalogMapForVersion(
|
||||
db,
|
||||
VENDORGET_STORE_NAMES.gvlSpecialPurposes,
|
||||
vendorListVersion
|
||||
),
|
||||
getGvlCatalogMapForVersion(
|
||||
db,
|
||||
VENDORGET_STORE_NAMES.gvlFeatures,
|
||||
vendorListVersion
|
||||
),
|
||||
getGvlCatalogMapForVersion(
|
||||
db,
|
||||
VENDORGET_STORE_NAMES.gvlSpecialFeatures,
|
||||
vendorListVersion
|
||||
),
|
||||
getGvlCatalogMapForVersion(
|
||||
db,
|
||||
VENDORGET_STORE_NAMES.gvlDataCategories,
|
||||
vendorListVersion
|
||||
)
|
||||
]);
|
||||
|
||||
return {
|
||||
purposes,
|
||||
specialPurposes,
|
||||
features,
|
||||
specialFeatures,
|
||||
dataCategories
|
||||
};
|
||||
}
|
||||
|
||||
function getGvlCatalogMapForVersion(db, storeName, vendorListVersion) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const tx = db.transaction([storeName], "readonly");
|
||||
const catalogStore = tx.objectStore(storeName);
|
||||
const vendorListVersionIndex = catalogStore.index("vendorListVersion");
|
||||
const cursorRequest = vendorListVersionIndex.openCursor(
|
||||
IDBKeyRange.only(vendorListVersion)
|
||||
);
|
||||
const catalogMap = new Map();
|
||||
|
||||
cursorRequest.onerror = () => reject(cursorRequest.error);
|
||||
cursorRequest.onsuccess = () => {
|
||||
const cursor = cursorRequest.result;
|
||||
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const record = cursor.value;
|
||||
const catalogId = getGvlCatalogRecordId(record);
|
||||
|
||||
if (catalogId !== null) {
|
||||
catalogMap.set(catalogId, record);
|
||||
}
|
||||
|
||||
cursor.continue();
|
||||
};
|
||||
|
||||
tx.onerror = () => reject(tx.error);
|
||||
tx.onabort = () => reject(tx.error);
|
||||
tx.oncomplete = () => resolve(catalogMap);
|
||||
});
|
||||
}
|
||||
|
||||
function getGvlCatalogRecordId(record) {
|
||||
const catalogId =
|
||||
record?.catalogId ??
|
||||
record?.purposeId ??
|
||||
record?.specialPurposeId ??
|
||||
record?.featureId ??
|
||||
record?.specialFeatureId ??
|
||||
record?.dataCategoryId ??
|
||||
null;
|
||||
|
||||
if (catalogId === null || catalogId === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const numericId = Number(catalogId);
|
||||
|
||||
return Number.isFinite(numericId) ? numericId : null;
|
||||
}
|
||||
|
||||
function buildGvlVendorDetailCatalogList(rawIds, relationshipIds, catalogMap) {
|
||||
const ids = mergeGvlVendorDetailIds(rawIds, relationshipIds);
|
||||
|
||||
return ids.map((id) => {
|
||||
const catalogRecord = catalogMap.get(id) ?? null;
|
||||
|
||||
return {
|
||||
id,
|
||||
name: catalogRecord?.name ?? null,
|
||||
description: catalogRecord?.description ?? null,
|
||||
descriptionLegal: catalogRecord?.descriptionLegal ?? null,
|
||||
illustrations: catalogRecord?.illustrations ?? null,
|
||||
rawCatalog: catalogRecord?.rawCatalog ?? null
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function mergeGvlVendorDetailIds(...sources) {
|
||||
const ids = [];
|
||||
const seen = new Set();
|
||||
|
||||
sources.forEach((source) => {
|
||||
if (!Array.isArray(source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
source.forEach((value) => {
|
||||
const id = Number(value);
|
||||
|
||||
if (!Number.isFinite(id) || seen.has(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
seen.add(id);
|
||||
ids.push(id);
|
||||
});
|
||||
});
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
function parseGvlVendorDetailId(value) {
|
||||
const vendorId = Number(value);
|
||||
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren