Skip to content

Commit

Permalink
Add QR image url, update dependencies
Browse files Browse the repository at this point in the history
Signed-off-by: Stephan Bruijnis <[email protected]>
  • Loading branch information
stephanbruijnis committed Jan 16, 2025
1 parent 2c5d351 commit 2722852
Show file tree
Hide file tree
Showing 128 changed files with 1,181 additions and 731 deletions.
Binary file modified Connector_Paradym.mpr
Binary file not shown.
48 changes: 8 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Introduction

Paradym is a workflow builder for developers that provides the actions, workflows and infrastructure you need to use verifiable credentials in your solution.
With Paradym, you can set up digital identity infrastructure in minutes, so you can focus on integrating it into your application. The Paradym connector allows you to easily and quickly connect with the Paradym API for issuing, verifying and other identity actions in Mendix.

This Paradym connector enables the usage of most of the Paradym API resources described in API documentation https://paradym.id/reference?full
This Paradym connector enables the usage of most of the Paradym API resources described in API documentation https://paradym.id/reference?full and is up to date with [Changelog December 19, 2024](https://paradym.id/changelog)

# Development

The `connector_paradym` requires at least Mendix version [9.24.18](https://marketplace.mendix.com/link/studiopro/9.24.18).
The connector_paradym module requires at least Mendix version [9.24.18](https://marketplace.mendix.com/link/studiopro/9.24.18).

## Maintenance

Expand All @@ -27,12 +27,7 @@ Please report any issues with the Paradym connector on [GitHub](https://github.c

This module supports [Paradym API v1](https://paradym.id/reference?full)

Note: Paradym offered two ways of managing your digital identity infrastructure:

- API and Dashboard: Use Paradym to issue and verify credentials (SD-JWT over OpenID4VC and DIDComm based)
- Workflow builder *Deprecated*: Build custom workflows to automate your back-end.

Since the Workflow builder has been deprecated this module will no longer enhance/develop features for the Workflow builder, instead, we are adding more support for the API endpoints exposed by Paradym.

## Configuration

Expand All @@ -45,27 +40,10 @@ Please start with the Paradym documentation to get familiar with concepts of dig
1. Add logic to create/edit/delete APISettings by using theA PISettingsHelper and open the APISettings_Edit (it's up to you to decide how to determine the _IDs)
1. Add logic to create Projects (optional, can also be done via the Paradym dashboard)
1. Run the application, sign in and go to the Paradym settings page
1. Create APISettings, enter your API key and start syncing data from Paradym (at this point there won't be much data, but if you are connection with an existing API key you can retrieve existing projects, workflows, mediators, etc.)
1. Start building with the components of connector_paradym (create workflows in Paradym, execute workflows, process the response from the webhooks)

To further test and work with Paradym workflows (and executions) it is recommended to use a gateway that can forward the webhook events to your local development machine (e.g. hookdeck, ngrok).

## Migration from v1 to v2 [!]

When upgrading the Connector_Paradym module in your project from version 1.x to version 2.x make sure to read and follow these steps. As it contains a few breaking changes

**Before importing** the v2 in your application:

1. Rename the entity `WebhookExecutionEvent` to `Event`. This will ensure that data will not be lost when importing and deploying v2

**During deployment** of your application containing the v2 module set these Constants:
1. Create APISettings, enter your API key and start syncing data from Paradym (at this point there won't be much data, but if you are connection with an existing API key you can retrieve existing projects, mediators, etc.)
1. Start building with the components of connector_paradym

1. `Connector_Paradym.MicroflowProcessWorkflowExecutionEvents` (this used to be `Connector_Paradym.MicroflowProcessWebhooks`)
1. `Connector_Paradym.MicroflowProcessEvents` (new)

**Runtime configuration** after your application has started

1. Update webhook endpoints for each project. Existing webhook endpoints no longer work. Delete the existing webhooks and create new webhooks using the following pattern `https://your-application-url.com/rest/paradym/event`
To further test and work with Paradym API actions it is recommended to use a gateway that can forward the webhook events to your local development machine (e.g. hookdeck, ngrok).

## Security

Expand All @@ -74,17 +52,7 @@ This module tries to follow the principle of least privilege, in which a user is
- Module roles: Administrator role for configuring the Paradym connector and debugging information. No other users should have access to logic or data from this module.
- Encryption: always store sensitive and personal information encrypted (e.g. ApiKey, proof-presentations, messages).

## Limitations

### General

- The API uses JSON:API 1.1 specification for requesting a list of entities. From this specification query parameters: filter[], sort are supported. Paradym also supports Cursor Pagination Profile for pagination with page[size], page[before] and page[after]. These filter options are not implemented in this connector.

### Workflows

- Action: AttributesJSON is currently not correctly saved on the entity
- Payload: For both Input & Actions the attributes and predicates are not fully imported in the presentationExchange and possibly also missing from credentialExchange

# References

- [Farmworker Wallet OS](https://tac.openwallet.foundation/projects/fwos/) ecosystem. Although `connector_paradym` is not part of the Farmworker Wallet OS it is used in the reference projects to demonstrate how a Cloud Agent implementation with Mendix could be developed
- [Paradym default workflows](https://github.com/Entidad/paradym-default-workflows). The Paradym documentation contains some example workflows, this repository contains the workflows definitions used as starting point for Entidad projects implementing Paradym
- [Paradym default workflows](https://github.com/Entidad/paradym-default-workflows). The Paradym documentation contains some example workflows, this repository contains the workflows definitions used as starting point for Entidad projects implementing Paradym (archived)
91 changes: 47 additions & 44 deletions javascriptsource/datawidgets/actions/Export_To_Excel.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,54 +26,57 @@ export async function Export_To_Excel(datagridName, fileName, sheetName, include
return false;
}

return new Promise((resolve, reject) => {
const stream =
window[window.DATAGRID_DATA_EXPORT][datagridName].create();
const REGISTRY_NAME = "com.mendix.widgets.web.datagrid.export";
const registry = window[REGISTRY_NAME];
const controller = registry.get(datagridName);

let worksheet;
let headers;
const streamOptions = { limit: chunkSize };
stream.process((msg) => {
if (!msg) {
return;
}
if (controller === undefined) {
return false;
}

return new Promise((resolve) => {
function handler(req) {
let worksheet;
let headers;

switch (msg.type) {
case "columns":
headers = msg.payload.map(column => column.name);
if (includeColumnHeaders) {
worksheet = utils.aoa_to_sheet([headers]);
}
break;
case "data":
if (worksheet === undefined) {
worksheet = utils.aoa_to_sheet(msg.payload)
} else {
utils.sheet_add_aoa(worksheet, msg.payload, { origin: -1 });
}
break;
case "end":
if (worksheet) {
// Set character width for each column
// https://docs.sheetjs.com/docs/csf/sheet#worksheet-object
worksheet["!cols"] = headers.map(header => ({
wch: header.length + 10
}));
const workbook = utils.book_new();
utils.book_append_sheet(workbook, worksheet, sheetName === "" ? "Data" : sheetName);
writeFileXLSX(workbook, `${fileName}.xlsx`);
resolve(true);
} else {
resolve(false);
}
break;
case "aborted":
req.on("headers", (hds) => {
headers = hds.map(header => header.name);
if (includeColumnHeaders) {
worksheet = utils.aoa_to_sheet([headers]);
}
});

req.on("data", (data) => {
if (worksheet === undefined) {
worksheet = utils.aoa_to_sheet(data)
} else {
utils.sheet_add_aoa(worksheet, data, { origin: -1 });
}
});

req.on("end", () => {
if (worksheet) {
// Set character width for each column
// https://docs.sheetjs.com/docs/csf/sheet#worksheet-object
worksheet["!cols"] = headers.map(header => ({
wch: header.length + 10
}));
const workbook = utils.book_new();
utils.book_append_sheet(workbook, worksheet, sheetName === "" ? "Data" : sheetName);
writeFileXLSX(workbook, `${fileName}.xlsx`);
resolve(true);
} else {
resolve(false);
break;
}
}, streamOptions);
}
});

req.on("abort", () => resolve(false));
}

stream.start();
controller.exportData(handler, {
withHeaders: true,
limit: chunkSize.toNumber()
})
});
// END USER CODE
}
5 changes: 3 additions & 2 deletions javascriptsource/datawidgets/actions/Reset_All_Filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import "mx-global";

/**
* @param {string} targetName - Name of the widget for which filters should be reset. Valid targets are: Data grid 2, Gallery. You can find filter name in widget settings in the "Common" group (Properties>Common>Name).
* @param {boolean} setToDefault - Set to default value
* @returns {Promise.<void>}
*/
export async function Reset_All_Filters(targetName) {
export async function Reset_All_Filters(targetName, setToDefault) {
// BEGIN USER CODE
const plugin = window["com.mendix.widgets.web.plugin.externalEvents"];
if (plugin) {
plugin.emit(targetName, "reset.filters");
plugin.emit(targetName, "reset.filters", setToDefault);
}
// END USER CODE
}
5 changes: 3 additions & 2 deletions javascriptsource/datawidgets/actions/Reset_Filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import { Big } from "big.js";

/**
* @param {string} targetName - Name of the filter to reset. Valid targets are: Number filter, Date filter, Text filter, Drop-down filter. You can find filter name in widget settings in the "Common" group (Properties>Common>Name).
* @param {boolean} setToDefault - Set to default value
* @returns {Promise.<void>}
*/
export async function Reset_Filter(targetName) {
export async function Reset_Filter(targetName, setToDefault) {
// BEGIN USER CODE
const plugin = window["com.mendix.widgets.web.plugin.externalEvents"];
if (plugin) {
plugin.emit(targetName, "reset.value");
plugin.emit(targetName, "reset.value", setToDefault);
}
// END USER CODE
}
34 changes: 34 additions & 0 deletions javascriptsource/datawidgets/actions/Set_Filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// This file was generated by Mendix Studio Pro.
//
// WARNING: Only the following code will be retained when actions are regenerated:
// - the import list
// - the code between BEGIN USER CODE and END USER CODE
// - the code between BEGIN EXTRA CODE and END EXTRA CODE
// Other code you write will be lost the next time you deploy the project.
import "mx-global";
import { Big } from "big.js";

// BEGIN EXTRA CODE
// END EXTRA CODE

/**
* @param {string} targetName - Name of the filter to set. Valid targets are: Number filter, Date filter, Text filter, Drop-down filter. You can find filter name in widget settings in the "Common" group (Properties>Common>Name).
* @param {boolean} useDefaultValue - Determine the use of default value provided by the filter component itself.
If true, "Value" section will be ignored
* @param {"DataWidgets.Filter_Operators.contains"|"DataWidgets.Filter_Operators.startsWith"|"DataWidgets.Filter_Operators.endsWith"|"DataWidgets.Filter_Operators.between"|"DataWidgets.Filter_Operators.greater"|"DataWidgets.Filter_Operators.greaterEqual"|"DataWidgets.Filter_Operators.equal"|"DataWidgets.Filter_Operators.notEqual"|"DataWidgets.Filter_Operators.smaller"|"DataWidgets.Filter_Operators.smallerEqual"|"DataWidgets.Filter_Operators.empty"|"DataWidgets.Filter_Operators.notEmpty"} operators - Selected operators value. If filter has operators, this value will be applied.
* @param {string} stringValue - Value set for dropdown filter or text filter. Choose empty if not use.
* @param {Big} numberValue - Number value for number filter. Choose empty if not use.
* @param {Date} dateTimeValue - Date time value for date filter, can also be use as "start date". Choose empty if not use.
* @param {Date} dateTimeValue_2 - End date time value for range filter. Choose empty if not use.
* @returns {Promise.<void>}
*/
export async function Set_Filter(targetName, useDefaultValue, operators, stringValue, numberValue, dateTimeValue, dateTimeValue_2) {
// BEGIN USER CODE
const plugin = window["com.mendix.widgets.web.plugin.externalEvents"];
if (plugin) {
plugin.emit(targetName, "set.value", useDefaultValue, {
operators, stringValue, numberValue, dateTimeValue, dateTimeValue2: dateTimeValue_2
});
}
// END USER CODE
}
2 changes: 1 addition & 1 deletion javascriptsource/datawidgets/actions/xlsx-export-tools.js

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions javasource/communitycommons/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ public class StringUtils {

public static final String HASH_ALGORITHM = "SHA-256";

public static String hash(String value) throws NoSuchAlgorithmException, DigestException {
int LENGTH = 32;
return hash(value, LENGTH);
}

@Deprecated
public static String hash(String value, int length) throws NoSuchAlgorithmException, DigestException {
byte[] inBytes = value.getBytes(StandardCharsets.UTF_8);
byte[] outBytes = new byte[length];
Expand Down
2 changes: 1 addition & 1 deletion javasource/communitycommons/XPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ public T firstOrWait(long timeoutMSecs) throws CoreException, InterruptedExcepti
break;

if (loopcount % 5 == 0)
sleepamount *= 1.5;
sleepamount = (int)(sleepamount * 1.5);

// not expired, wait a bit
if (result == null)
Expand Down
4 changes: 2 additions & 2 deletions javasource/communitycommons/actions/Base64DecodeToFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
import com.mendix.webui.CustomJavaAction;

/**
* Stores an base 64 encoded string plain in the provided target file document
*
* Stores an base 64 encoded string plain in the provided target file document
*
* Note that targetFile will be committed.
*/
public class Base64DecodeToFile extends CustomJavaAction<java.lang.Boolean>
Expand Down
12 changes: 6 additions & 6 deletions javasource/communitycommons/actions/Clone.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
import com.mendix.webui.CustomJavaAction;

/**
* Clones objects
*
* - Source: the original object to copy
* - Target: the object to copy it into (should be of the same type, or a specialization)
* - includeAssociations: whether to clone associations.
*
* Clones objects
*
* - Source: the original object to copy
* - Target: the object to copy it into (should be of the same type, or a specialization)
* - includeAssociations: whether to clone associations.
*
* If associated objects need to be cloned as well, use deepClone, this function only copies the references, not the reffered objects. Target is not committed automatically.
*/
public class Clone extends CustomJavaAction<java.lang.Boolean>
Expand Down
36 changes: 18 additions & 18 deletions javasource/communitycommons/actions/DeepClone.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,24 @@
import com.mendix.webui.CustomJavaAction;

/**
* Clones objects, their associations and even referred objects.
*
* - Source: the original object to copy
* - Target: the object to copy it into (should be of the same type, or a specialization)
* - MembersToSkip: members which should not be set at all
* - MembersToKeep: references which should be set, but not cloned. (so source and target will refer to exactly the same object). If an association is not part of this property, it will be cloned.
* - ReverseAssociations: 1 - 0 assications which refer to target, which will be cloned as well. Only the reference name itself needs to be mentioned.
* - excludeEntities: entities that will not be cloned. references to these entities will refer to the same object as the source did.
* - excludeModules: modules that will have none of their enities cloned. Behaves similar to excludeEntities.
*
* members format: <membername> or <module.association> or <module.objecttype/membername>, where objecttype is the concrete type of the object being cloned.
*
* reverseAssociation:
* <module.relation>
*
* membersToSkip by automatically contains createdDate and changedDate.
* membersToKeep by automatically contains System.owner and System.changedBy
*
* Clones objects, their associations and even referred objects.
*
* - Source: the original object to copy
* - Target: the object to copy it into (should be of the same type, or a specialization)
* - MembersToSkip: members which should not be set at all
* - MembersToKeep: references which should be set, but not cloned. (so source and target will refer to exactly the same object). If an association is not part of this property, it will be cloned.
* - ReverseAssociations: 1 - 0 assications which refer to target, which will be cloned as well. Only the reference name itself needs to be mentioned.
* - excludeEntities: entities that will not be cloned. references to these entities will refer to the same object as the source did.
* - excludeModules: modules that will have none of their enities cloned. Behaves similar to excludeEntities.
*
* members format: <membername> or <module.association> or <module.objecttype/membername>, where objecttype is the concrete type of the object being cloned.
*
* reverseAssociation:
* <module.relation>
*
* membersToSkip by automatically contains createdDate and changedDate.
* membersToKeep by automatically contains System.owner and System.changedBy
*
* Note that DeepClone does commit all objects, where Clone does not.
*/
public class DeepClone extends CustomJavaAction<java.lang.Boolean>
Expand Down
4 changes: 2 additions & 2 deletions javasource/communitycommons/actions/Delay.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
import com.mendix.webui.CustomJavaAction;

/**
* Causes this request to sleep for a while. Useful to prevent brute force attacks or to simulate latency delays.
*
* Causes this request to sleep for a while. Useful to prevent brute force attacks or to simulate latency delays.
*
* Delaytime : time in ms
*/
public class Delay extends CustomJavaAction<java.lang.Boolean>
Expand Down
10 changes: 5 additions & 5 deletions javasource/communitycommons/actions/DuplicateFileDocument.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
import com.mendix.webui.CustomJavaAction;

/**
* Clones the contents of one file document into another.
* - fileToClone : the source file
* - cloneTarget : an initialized file document, in which the file will be stored.
*
* Returns true if copied, returns file if the source had no contents, throws exception in any other case.
* Clones the contents of one file document into another.
* - fileToClone : the source file
* - cloneTarget : an initialized file document, in which the file will be stored.
*
* Returns true if copied, returns file if the source had no contents, throws exception in any other case.
* Pre condition: HasContents of the 'fileToClone' need to be set to true, otherwise the action will not copy anything.
*/
public class DuplicateFileDocument extends CustomJavaAction<java.lang.Boolean>
Expand Down
Loading

0 comments on commit 2722852

Please sign in to comment.