Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement flexible identifier schemes #162

Merged
merged 4 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
762 changes: 735 additions & 27 deletions app-config.json

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions documentation/docs/mock-apps/common/construct-ai-data.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
sidebar_position: 57
title: Construct Application Identifier Data
---

import Disclaimer from '../.././\_disclaimer.mdx';

<Disclaimer />

## Description

The `constructAiData` object defines the schema for constructing event data for getting Application Identifier (AI) data. It will be used to fetch the AI data from the JSON form or the credential object which are not explicitly defined the data model.

### Example

```json
{
"primary": {
"ai": "01",
"path": "/registeredId"
},
"qualifiers": [
{
"ai": "21",
"path": "/serialNumber"
},
{
"ai": "10",
"path": "/batchNumber"
}
]
}
```

### Definitions

| Property | Required | Description | Type |
| ---------- | :------: | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| primary | Yes | The primary AI that defines the AI code and the path for primary AI value | [AI config](/docs/mock-apps/common/construct-ai-data#ai-config) |
| qualifiers | No | The list of qualifiers that define the AI code and the path for qualifier AI value | [AI config](/docs/mock-apps/common/construct-ai-data#ai-config)[] |

#### AI config

| Property | Required | Description | Type |
| -------- | :------: | ----------------------------------------------------------------------- | ------ |
| ai | Yes | The AI code that defines the AI data | String |
| path | Yes | The JSON pointer path to extract the AI data from the credential object | String |
17 changes: 9 additions & 8 deletions documentation/docs/mock-apps/common/credential.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ import Disclaimer from '../.././\_disclaimer.mdx';
The `Credential` object defines the structure and properties of the compliant [Verifiable Credential](https://uncefact.github.io/spec-untp/docs/specification/VerifiableCredentials), including its context, rendering template, and associated metadata.

## Definition

<!-- TODO: Document the list of dlrIdentificationKeyTypes -->
| Property | Required | Description | Type |
|----------|----------|-------------|------|
| context | Yes | JSON-LD context for the Verifiable Credential | String[] |
| renderTemplate | No | Templates for rendering the Verifiable Credential | [RenderTemplate](/docs/mock-apps/common/render-template)[] |
| type | Yes | Types of the Verifiable Credential | String[] |
| dlrLinkTitle | Yes | Title for the Identity Register link | String |
| dlrIdentificationKeyType | Yes | Type of identification key for IDR. E.g. gtin | [IdentificationKeyType](#) |
| dlrVerificationPage | Yes | URL of the verification page used to verify and render the credential | String |

| Property | Required | Description | Type |
| ------------------- | -------- | --------------------------------------------------------------------- | ---------------------------------------------------------- |
| context | Yes | JSON-LD context for the Verifiable Credential | String[] |
| renderTemplate | No | Templates for rendering the Verifiable Credential | [RenderTemplate](/docs/mock-apps/common/render-template)[] |
| type | Yes | Types of the Verifiable Credential | String[] |
| dlrLinkTitle | Yes | Title for the Identity Register link | String |
| dlrVerificationPage | Yes | URL of the verification page used to verify and render the credential | String |
34 changes: 19 additions & 15 deletions documentation/docs/mock-apps/common/identifier-key-path.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import Disclaimer from '../.././\_disclaimer.mdx';

## Description

The `IdentifierKeyPath` is a property of services that interact with the data issued to get the identifier to be used for the [IDR](/docs/mock-apps/common/idr) registration. It can be a JSON path of the identifier of the data issued or an object that contains the function `concatService` and the `args` to be used to get the identifier.
The `IdentifierKeyPath` can be an object or a string that defines the path to extract the identifier data from the [Json Form component](/docs/mock-apps/components/json-form). When the `identifierKeyPath` is a string, it should be a link resolver URL. When the `identifierKeyPath` is an object, it should contain AI codes and JSON pointer paths to extract the appropriate data for identifier generation.

## Example

```json
{
"identifierKeyPath": "/eventID"
"identifierKeyPath": "/id" // Example of a link resolver URL: https://example.com/gs1/01/0123456789123/21/123456/10/123456
}
```

Expand All @@ -24,22 +24,26 @@ or
```json
{
"identifierKeyPath": {
"function": "concatService",
"args": [
{ "type": "text", "value": "(01)" },
{ "type": "path", "value": "/productIdentifier/0/identifierValue" },
{ "type": "text", "value": "(10)" },
{ "type": "path", "value": "/batchIdentifier/0/identifierValue" },
{ "type": "text", "value": "(21)" },
{ "type": "path", "value": "/itemIdentifier/0/identifierValue" }
"primary": {
"ai": "01",
"path": "/registeredId"
},
"qualifiers": [
{
"ai": "21",
"path": "/serialNumber"
},
{
"ai": "10",
"path": "/batchNumber"
}
]
}
}
```

## Definition for object
## Definition

| Property | Required | Description | Type |
| -------- | :------: | ------------------------------------------------ | ------ |
| function | Yes | The concat function supported | String |
| args | Yes | The array of object that can be `text` or `path` | Array |
| Property | Required | Description | Type |
| ----------------- | :------: | --------------------------------------- | ------------------------------------------------------------ |
| identifierKeyPath | Yes | The path to extract the identifier data | String or [AIData](/docs/mock-apps/common/construct-ai-data) |
40 changes: 28 additions & 12 deletions documentation/docs/mock-apps/components/barcode-generator.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ sidebar_position: 18
title: Barcode Generator
---

import Disclaimer from '../../_disclaimer.mdx';
import Disclaimer from '../../\_disclaimer.mdx';

<Disclaimer />

Expand All @@ -16,11 +16,12 @@ The component uses its `data` and `dataPath` props to extract the necessary info
The BarcodeGenerator is typically used as follows:

1. Passing the credential object:

- The `data` prop receives the entire credential object generated by the previous step in the process.
- This prop is usually not specified directly in the component configuration, as it's automatically populated with the credential generate in the previous step.

2. Specifying the data path:
- Use the `dataPath` prop to specify a JSON pointer path to extract barcode data from the credential object.
- Use the `dataPath` prop to specify the AI codes and JSON pointer paths to extract the appropriate data for barcode generation.

## Example

Expand All @@ -29,7 +30,22 @@ The BarcodeGenerator is typically used as follows:
"name": "BarcodeGenerator",
"type": "Result",
"props": {
"dataPath": "/credentialSubject/outputEPCList/index/name"
"dataPath": {
"primary": {
"ai": "01",
"path": "/registeredId"
},
"qualifiers": [
{
"ai": "21",
"path": "/serialNumber"
},
{
"ai": "10",
"path": "/batchNumber"
}
]
}
}
}
```
Expand All @@ -38,15 +54,15 @@ This example specifies that for each item in the `outputEPCList`, the `name` fie

## Definitions

| Property | Required | Description | Type |
|----------|----------|-------------|------|
| name | Yes | The name of the component (should be "BarcodeGenerator")| String |
| type | Yes | The type of the component (should be "Result") | [ComponentType](/docs/mock-apps/common/component-type) |
| props | Yes | The properties for the BarcodeGenerator | [Props](/docs/mock-apps/components/barcode-generator#props) |
| Property | Required | Description | Type |
| -------- | -------- | -------------------------------------------------------- | ----------------------------------------------------------- |
| name | Yes | The name of the component (should be "BarcodeGenerator") | String |
| type | Yes | The type of the component (should be "Result") | [ComponentType](/docs/mock-apps/common/component-type) |
| props | Yes | The properties for the BarcodeGenerator | [Props](/docs/mock-apps/components/barcode-generator#props) |

### Props

| Property | Required | Description | Type |
|----------|----------|-------------|------|
| data | No | The credential object containing the data for barcode generation (usually automatically provided) | Object |
| dataPath | Yes | A JSON pointer path to extract barcode data from the credential object | String |
| Property | Required | Description | Type |
| -------- | -------- | ------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| data | No | The credential object containing the data for barcode generation (usually automatically provided) | Object |
| dataPath | Yes | A JSON pointer path to extract barcode data from the credential object | [AIData](/docs/mock-apps/common/construct-ai-data) |
1 change: 0 additions & 1 deletion documentation/docs/mock-apps/services/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ graph TD
"renderTemplate": [],
"type": ["VerifiableCredential", " DigitalProductPassport"],
"dlrLinkTitle": "Steel Passport",
"dlrIdentificationKeyType": "gtin",
"dlrVerificationPage": "http://localhost:3000/verify"
},
"dlr": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ P-->>C: Return VC and resolver URL
"template": "<div><h2>Aggregation Event</h2><p>Parent: {{parentItem.epc}}</p></div>"
}
],
"dlrIdentificationKeyType": "sscc",
"dlrLinkTitle": "Aggregation Event",
"dlrVerificationPage": "https://verify.example.com"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ P-->>C: Return association event VC and resolver URL
"@type": "WebRenderingTemplate2022"
}
],
"dlrIdentificationKeyType": "gtin",
"dlrLinkTitle": "Association Event",
"dlrVerificationPage": "https://verify.example.com"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ P-->>C: Return digital conformity credential VC and resolver URL
"@type": "WebRenderingTemplate2022"
}
],
"dlrIdentificationKeyType": "gtin",
"dlrLinkTitle": "DigitalConformityCredential",
"dlrVerificationPage": "https://verify.example.com"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ P-->>C: Return digital facility record VC and resolver URL
"@type": "WebRenderingTemplate2022"
}
],
"dlrIdentificationKeyType": "gln",
"dlrLinkTitle": "DigitalFacilityRecord",
"dlrVerificationPage": "https://verify.example.com"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ P-->>C: Return digital identity anchor VC and resolver URL
"@type": "WebRenderingTemplate2022"
}
],
"dlrIdentificationKeyType": "gtin",
"dlrLinkTitle": "DigitalIdentityAnchor",
"dlrVerificationPage": "https://verify.example.com"
},
Expand Down
1 change: 0 additions & 1 deletion documentation/docs/mock-apps/services/process-dpp.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ P-->>C: Return VC and resolver URL
],
"type": ["DigitalProductPassport"],
"dlrLinkTitle": "Steel Passport",
"dlrIdentificationKeyType": "gtin",
"dlrVerificationPage": "http://localhost:3332/verify"
},
"dlr": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ P-->>C: Return object event VC and resolver URL
"@type": "WebRenderingTemplate2022"
}
],
"dlrIdentificationKeyType": "gtin",
"dlrLinkTitle": "Object Event",
"dlrVerificationPage": "https://verify.example.com"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ P-->>C: Return event VC and resolver URL
"@type": "WebRenderingTemplate2022"
}
],
"dlrIdentificationKeyType": "gtin",
"dlrLinkTitle": "Traceability Event",
"dlrVerificationPage": "https://verify.example.com"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ P-->>C: Return VC and resolver URL
"template": "<div><h2>Transaction Event</h2><p>ID: {{transactionId}}</p></div>"
}
],
"dlrIdentificationKeyType": "gtin",
"dlrLinkTitle": "Transaction Event",
"dlrVerificationPage": "https://verify.example.com"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ P-->>C: Return transformation event VC and resolver URL
"@type": "WebRenderingTemplate2022"
}
],
"dlrIdentificationKeyType": "gtin",
"dlrLinkTitle": "Transformation Event",
"dlrVerificationPage": "https://verify.example.com"
},
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
"packages/*"
],
"scripts": {
"start": "cp app-config.json packages/mock-app/src/constants/app-config.json && cd packages/mock-app && yarn start",
"build": "yarn build:services && yarn build:components && yarn build:untp-test-suite",
"copy-config": "cp app-config.json packages/mock-app/src/constants/app-config.json && cp app-config.json packages/components/src/constants/app-config.json",
"start": "yarn copy-config && cd packages/mock-app && yarn start",
"build": "yarn copy-config && yarn build:services && yarn build:components && yarn build:untp-test-suite",
"build:services": "cd packages/services && yarn run build",
"build:components": "cd packages/components && yarn run build",
"build:untp-test-suite": "cd packages/untp-test-suite && yarn run build",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { allowedIndexKeys, extractFromElementString } from '@mock-app/services';
import { extractFromElementString, constructIdentifierData, constructElementString } from '@mock-app/services';
import { Box } from '@mui/material';
import JSONPointer from 'jsonpointer';
import { useEffect, useState } from 'react';
import Barcode from 'react-barcode';
import appConfig from '../../constants/app-config.json';
import { DataCarrierType } from '../../types/common.types';
import { toastMessage, Status } from '../ToastMessage/ToastMessage';

export interface IBarcodeProps {
data?: string[];
Expand All @@ -12,27 +14,33 @@ export const BarcodeGenerator = (props: IBarcodeProps) => {
const [values, setValues] = useState<string[]>([]);
useEffect(() => {
if (props.data && props.dataPath) {
const pathIndex = props.dataPath.split('/').findIndex((key) => allowedIndexKeys.includes(key));

if (pathIndex === -1) {
setValues([constructBarcode(JSONPointer.get(props.data, props.dataPath))]);
const aiData = constructIdentifierData(props.dataPath, props.data);
if (validateData(aiData)) {
const elementString = constructElementString(aiData);
setValues([constructBarcode(elementString)]);
} else {
const headPath = props.dataPath.split('/').slice(0, pathIndex).join('/');
const tailPath = props.dataPath
.split('/')
.slice(pathIndex + 1)
.join('/');
const array = JSONPointer.get(props.data, headPath);
const values = array.map((item: any) => JSONPointer.get(item, `/${tailPath}`));
const parsedValues = values.map((item: any) => {
return constructBarcode(item);
});

setValues(parsedValues);
toastMessage({ status: Status.warning, message: 'Invalid data for barcode generation' });
}
}
}, [props.data, props.dataPath]);

const validateData = (aiData: any) => {
if (!aiData) return false;
if (!aiData.primary || !aiData.primary.ai || !aiData.primary.value) return false;
const identifierSchemesForBarcode = (appConfig.identifierSchemes || []).filter(
(scheme) => scheme.carriers && scheme.carriers.includes(DataCarrierType.Barcode),
);
if (identifierSchemesForBarcode.length === 0) return false;

return identifierSchemesForBarcode.some((scheme) => {
const regex = new RegExp(scheme.format);
if (regex.test(aiData.primary.value)) {
return true;
}
return false;
});
};

const constructBarcode = (data: string) => {
const convertToGS1String = (obj: any) => {
if (typeof obj !== 'object' || obj === null) return '';
Expand Down Expand Up @@ -66,9 +74,9 @@ export const BarcodeGenerator = (props: IBarcodeProps) => {

return (
<Box display='flex' flexDirection='column' alignItems='center' justifyContent='space-evenly'>
{values.map((item) => {
{values.map((item, idx) => {
return (
<Box>
<Box key={idx}>
<Barcode value={item} />
</Box>
);
Expand Down
Loading
Loading