From 87f4da99fe62bdf8167d9a224616853c200b5f4a Mon Sep 17 00:00:00 2001 From: Albin Antony Date: Fri, 15 Dec 2023 13:06:00 +0530 Subject: [PATCH] Add #9 Align Gherkin scenarios with Test Protocol and GovStack Open API spec --- .gitignore | 3 +- .../account/developer_api.feature | 22 - .../account/manage_admin.feature | 18 - .../admin_dashboard/account/view_logs.feature | 34 -- .../admin_dashboard/account/webhook.feature | 35 -- .../admin_logging/admin_logging.feature | 17 + .../create_data_agreement.feature | 45 ++ .../delete_data_agreement.feature | 13 + .../filter_data_agreements.feature | 13 + .../update_data_agreement.feature | 46 ++ .../view_data_agreement.feature | 25 + .../admin_dashboard/data_agreements.feature | 63 --- .../admin_dashboard/getting_started.feature | 13 - .../global_data_policy.feature | 13 + .../manage_users/user_access.feature | 26 - .../manage_users/user_records.feature | 38 -- .../notification/notification.feature | 17 + .../admin_dashboard/personal_data.feature | 26 - .../admin_dashboard/privacy_dashboard.feature | 15 - .../data_processing_auditor.feature | 24 + .../onboarding/individual_onboard.feature | 11 + features/onboarding/onboarding.feature | 49 ++ features/onboarding/org_admin_onboard.feature | 11 + .../individual_mobile_client.feature | 50 ++ .../individual_web_client.feature | 50 ++ steps/admin_logging.py | 26 + steps/create_data_agreement.py | 342 ++++++++++++ steps/data_agreements.py | 488 ------------------ steps/data_processing_auditor.py | 164 ++++++ steps/delete_data_agreement.py | 79 +++ steps/developer_api.py | 68 --- steps/filter_data_agreements.py | 140 +++++ steps/getting_started.py | 57 -- steps/global_data_policy.py | 66 +++ steps/individual_client.py | 258 +++++++++ steps/individual_onboard.py | 12 + steps/manage_admin.py | 67 --- steps/onboarding.py | 219 ++++++++ steps/org_admin_onboard.py | 45 ++ steps/personal_data.py | 201 -------- steps/privacy_dashboard.py | 40 -- steps/update_data_agreement.py | 252 +++++++++ steps/user_access.py | 123 ----- steps/user_records.py | 76 --- steps/view_data_agreement.py | 38 ++ steps/view_logs.py | 107 ---- steps/webhook.py | 120 ----- 47 files changed, 2027 insertions(+), 1638 deletions(-) delete mode 100644 features/admin_dashboard/account/developer_api.feature delete mode 100644 features/admin_dashboard/account/manage_admin.feature delete mode 100644 features/admin_dashboard/account/view_logs.feature delete mode 100644 features/admin_dashboard/account/webhook.feature create mode 100644 features/admin_dashboard/admin_logging/admin_logging.feature create mode 100644 features/admin_dashboard/data_agreement/create_data_agreement.feature create mode 100644 features/admin_dashboard/data_agreement/delete_data_agreement.feature create mode 100644 features/admin_dashboard/data_agreement/filter_data_agreements.feature create mode 100644 features/admin_dashboard/data_agreement/update_data_agreement.feature create mode 100644 features/admin_dashboard/data_agreement/view_data_agreement.feature delete mode 100644 features/admin_dashboard/data_agreements.feature delete mode 100644 features/admin_dashboard/getting_started.feature create mode 100644 features/admin_dashboard/global_data_policy/global_data_policy.feature delete mode 100644 features/admin_dashboard/manage_users/user_access.feature delete mode 100644 features/admin_dashboard/manage_users/user_records.feature create mode 100644 features/admin_dashboard/notification/notification.feature delete mode 100644 features/admin_dashboard/personal_data.feature delete mode 100644 features/admin_dashboard/privacy_dashboard.feature create mode 100644 features/data_processing_auditor/data_processing_auditor.feature create mode 100644 features/onboarding/individual_onboard.feature create mode 100644 features/onboarding/onboarding.feature create mode 100644 features/onboarding/org_admin_onboard.feature create mode 100644 features/privacy_dashboard/individual_mobile_client.feature create mode 100644 features/privacy_dashboard/individual_web_client.feature create mode 100644 steps/admin_logging.py create mode 100644 steps/create_data_agreement.py delete mode 100644 steps/data_agreements.py create mode 100644 steps/data_processing_auditor.py create mode 100644 steps/delete_data_agreement.py delete mode 100644 steps/developer_api.py create mode 100644 steps/filter_data_agreements.py create mode 100644 steps/global_data_policy.py create mode 100644 steps/individual_client.py create mode 100644 steps/individual_onboard.py delete mode 100644 steps/manage_admin.py create mode 100644 steps/onboarding.py create mode 100644 steps/org_admin_onboard.py delete mode 100644 steps/personal_data.py delete mode 100644 steps/privacy_dashboard.py create mode 100644 steps/update_data_agreement.py delete mode 100644 steps/user_access.py delete mode 100644 steps/user_records.py create mode 100644 steps/view_data_agreement.py delete mode 100644 steps/view_logs.py delete mode 100644 steps/webhook.py diff --git a/.gitignore b/.gitignore index 0d6144b..435542a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ api-backup.json api-dev-tests.json -temp/ \ No newline at end of file +temp/ +env \ No newline at end of file diff --git a/features/admin_dashboard/account/developer_api.feature b/features/admin_dashboard/account/developer_api.feature deleted file mode 100644 index df99f5c..0000000 --- a/features/admin_dashboard/account/developer_api.feature +++ /dev/null @@ -1,22 +0,0 @@ -Feature: Developer APIs and Credentials - - Background: - Given an organization admin for Data4Diabetes organization - And the admin is logged into the Admin dashboard - - Scenario: View Organization ID, Admin User ID, and API Base URL - When the admin views the organization ID, admin user ID, and API base URL - Then the admin should see this information - - Scenario: Create API Key with Expiry and Scopes - When the admin creates an API key with specified expiry and scopes - Then the admin should receive a one-time copyable API key - - Scenario: Update API Key to Refresh - When the admin updates an API key to refresh it - Then the admin should receive a new one-time copyable API key - - Scenario: List API Keys - When the admin views the list of API keys - Then the admin should see a paginated list of API keys - diff --git a/features/admin_dashboard/account/manage_admin.feature b/features/admin_dashboard/account/manage_admin.feature deleted file mode 100644 index d846e5e..0000000 --- a/features/admin_dashboard/account/manage_admin.feature +++ /dev/null @@ -1,18 +0,0 @@ -Feature: Manage Admin User Configurations - - Background: - Given an organization admin for Data4Diabetes organization - And the admin is logged into the Admin dashboard - - Scenario: Update Organization Admin Avatar Image - When the admin updates the organization admin's avatar image - Then the avatar image should be updated - - Scenario: Update Organization Admin Name - When the admin updates the organization admin's name - Then the admin's name should be updated - - Scenario: Reset Password - When the admin resets the organization admin's password - Then the password should be reset - diff --git a/features/admin_dashboard/account/view_logs.feature b/features/admin_dashboard/account/view_logs.feature deleted file mode 100644 index c6dad10..0000000 --- a/features/admin_dashboard/account/view_logs.feature +++ /dev/null @@ -1,34 +0,0 @@ -Feature: View Logs - - Background: - Given an organization admin for Data4Diabetes organization - And the admin is logged into the Admin dashboard - - Scenario: View List of Admin Logs - When the admin views the list of admin logs - Then the admin should see a list of logs - - Scenario: Filter Logs by Category - All - When the admin filters the logs to see all logs - Then the admin should see all logs - - Scenario: Filter Logs by Category - Security - When the admin filters the logs to see security logs - Then the admin should see security-related logs - - Scenario: Filter Logs by Category - API Calls - When the admin filters the logs to see API call logs - Then the admin should see logs related to API calls - - Scenario: Filter Logs by Category - Organisation - When the admin filters the logs to see organisation logs - Then the admin should see logs related to organisation activities - - Scenario: Filter Logs by Category - Webhooks - When the admin filters the logs to see webhook logs - Then the admin should see logs related to webhook activities - - Scenario: Filter Logs by Category - End User - When the admin filters the logs to see end user logs - Then the admin should see logs related to end user activities - diff --git a/features/admin_dashboard/account/webhook.feature b/features/admin_dashboard/account/webhook.feature deleted file mode 100644 index 6e0bc17..0000000 --- a/features/admin_dashboard/account/webhook.feature +++ /dev/null @@ -1,35 +0,0 @@ -Feature: Webhooks Management - - Background: - Given an organization admin for Data4Diabetes organization - And the admin is logged into the Admin dashboard - - Scenario: View List of Webhook Endpoints - When the admin views the list of webhook endpoints - Then the admin should see a list of webhook endpoints - - Scenario: Create Webhook Endpoint - When the admin creates a new webhook endpoint with specified details - Then the webhook endpoint should be created - - Scenario: Update Webhook Endpoint - When the admin updates an existing webhook endpoint with specified details - Then the webhook endpoint should be updated - - Scenario: Delete Webhook Endpoint - When the admin deletes an existing webhook endpoint - Then the webhook endpoint should be deleted - - Scenario: View Recent Deliveries for Webhook Endpoint - Given the admin selects a webhook endpoint - When the admin views the list of recent deliveries made to the selected webhook - Then the admin should see the delivery details - - Scenario: Webhook Endpoint Status - Up - When the admin marks a webhook endpoint as "Up" - Then the status of the webhook endpoint should be set to "Up" - - Scenario: Webhook Endpoint Status - Down - When the admin marks a webhook endpoint as "Down" - Then the status of the webhook endpoint should be set to "Down" - diff --git a/features/admin_dashboard/admin_logging/admin_logging.feature b/features/admin_dashboard/admin_logging/admin_logging.feature new file mode 100644 index 0000000..01a1783 --- /dev/null +++ b/features/admin_dashboard/admin_logging/admin_logging.feature @@ -0,0 +1,17 @@ +Feature: Admin Log Viewing + + Background: + Given an organization admin for Data4Diabetes organization + And the admin is logged into the Admin dashboard + + Scenario: View security log for admin function + When the admin clicks on the "view admin function" + Then the admin should be able to view security log functions + + Scenario: View webhook log for admin function + When the admin clicks on the "view admin function" + Then the admin should be able to view webhook log functions + + Scenario: View API log for admin function + When the admin clicks on the "view admin function" + Then the admin should be able to view API calls log functions diff --git a/features/admin_dashboard/data_agreement/create_data_agreement.feature b/features/admin_dashboard/data_agreement/create_data_agreement.feature new file mode 100644 index 0000000..902b223 --- /dev/null +++ b/features/admin_dashboard/data_agreement/create_data_agreement.feature @@ -0,0 +1,45 @@ +Feature: Data Agreement Creation + + Background: + Given an organization admin for Data4Diabetes organization + And the admin is logged into the Admin dashboard + + Scenario: Create Data Agreement with new data policy + When the admin chooses a new data policy + And creates a data agreement in draft mode + Then the data agreement should be in draft mode with version 1.0.0 + + Scenario: Create Data Agreement with existing data policy + When the admin chooses an existing data policy template + And creates a data agreement in draft mode + Then the data agreement should be in draft mode with version 1.0.0 + + Scenario: Create Data Agreement with updated data fields + When the admin chooses an existing data policy template + And updates one or two fields to create a data agreement in draft mode + Then the data agreement should be in draft mode with version 1.0.0 + + Scenario: Create a new Data Agreement + When the admin chooses a new data policy to create a data agreement + And creates a data agreement + Then the data agreement should be created with version 1.0.0 + + Scenario: Create a new Data Agreement to publish + When the admin chooses an existing data policy template + And creates a data agreement + Then the data agreement should be created with version 1.0.0 + + Scenario: Create Data Agreement to publish + When the admin chooses an existing data policy template + And updates one or two fields to create a data agreement + Then the data agreement should be created with version 1.0.0 + + Scenario: Create several Data Agreements + When the admin creates several data agreements in one transaction + And uses CLI command + Then the multiple data agreements should be created + + Scenario: Create an Agreement with non-consent basis + When the admin chooses a lawful basis other than consent + And create a data agreement + Then the data agreement should be created with version 1.0.0 diff --git a/features/admin_dashboard/data_agreement/delete_data_agreement.feature b/features/admin_dashboard/data_agreement/delete_data_agreement.feature new file mode 100644 index 0000000..f04b8bd --- /dev/null +++ b/features/admin_dashboard/data_agreement/delete_data_agreement.feature @@ -0,0 +1,13 @@ +Feature: Deleting Data Agreements + + Background: + Given an organization admin for Data4Diabetes organization + And the admin is logged into the Admin dashboard + + Scenario: Delete Data Agreement + When the admin deletes a data agreement + Then the data agreement should be deleted + + Scenario: Delete draft Data Agreement + When the admin deletes a draft data agreement + Then the data agreement should be deleted diff --git a/features/admin_dashboard/data_agreement/filter_data_agreements.feature b/features/admin_dashboard/data_agreement/filter_data_agreements.feature new file mode 100644 index 0000000..0507435 --- /dev/null +++ b/features/admin_dashboard/data_agreement/filter_data_agreements.feature @@ -0,0 +1,13 @@ +Feature: Filtering Data Agreements + + Background: + Given an organization admin for Data4Diabetes organization + And the admin is logged into the Admin dashboard + + Scenario: Filter published Data Agreement + When the admin clicks the "Published" radio button + Then the Published data agreements should be shown + + Scenario: Filter Data Agreement + When the admin clicks the "All" radio button + Then the All data agreements should be shown diff --git a/features/admin_dashboard/data_agreement/update_data_agreement.feature b/features/admin_dashboard/data_agreement/update_data_agreement.feature new file mode 100644 index 0000000..2cc238b --- /dev/null +++ b/features/admin_dashboard/data_agreement/update_data_agreement.feature @@ -0,0 +1,46 @@ +Feature: Updating Data Agreements + + Background: + Given an organization admin for Data4Diabetes organization + And the admin is logged into the Admin dashboard + + Scenario: Update Data Agreement with None mode + When the admin clicks on the update icon + And updates data agreement as none mode + And clicks publish + Then the data agreement should be updated + + Scenario: Update Data Agreement as DS + When the admin clicks on the update icon + And updates data agreement as DS + And clicks publish + Then the data agreement should be updated + + Scenario: Update Data Agreement as DUS + When the admin clicks on the update icon + And updates data agreement as DUS + And clicks publish + Then the data agreement should be updated + + Scenario: Update draft Data Agreement + When the admin clicks on the update icon + And updates only the fields permitted to change + And clicks save + Then the data agreement should be updated + + Scenario: Update new Data Agreement + When the admin clicks on the update icon + And updates only the fields permitted to change + And clicks save + Then the data agreement should be updated + + Scenario: Update Data Agreement as Draft mode + When the admin clicks on the update icon + And updates only the fields permitted to change + And clicks save + Then the data agreement should be updated + + Scenario: Update delete attribute in Data Agreement + When the admin clicks on the update icon + And deletes an attribute in data agreement + Then the data agreement should be updated diff --git a/features/admin_dashboard/data_agreement/view_data_agreement.feature b/features/admin_dashboard/data_agreement/view_data_agreement.feature new file mode 100644 index 0000000..c9f6282 --- /dev/null +++ b/features/admin_dashboard/data_agreement/view_data_agreement.feature @@ -0,0 +1,25 @@ +Feature: Data Agreement Viewing + + Background: + Given an organization admin for Data4Diabetes organization + And the admin is logged into the Admin dashboard + + Scenario: View publish Data Agreement + When the admin clicks on the eye or view icon + And views the data agreement table + Then the admin should be able to view the data agreement + + Scenario: View Data Agreement + When the admin clicks on the eye or view icon + And views the data agreement table + Then the admin should be able to view the data agreement + + Scenario: View draft Data Agreement + When the admin clicks on the eye or view icon + And views the data agreement + Then the admin should be able to view the draft data agreement + + Scenario: View revision history of Data Agreement + When the admin clicks on the version icon + And views the version for the agreements list + Then the admin should be able to view all version history for data agreement diff --git a/features/admin_dashboard/data_agreements.feature b/features/admin_dashboard/data_agreements.feature deleted file mode 100644 index 932bce4..0000000 --- a/features/admin_dashboard/data_agreements.feature +++ /dev/null @@ -1,63 +0,0 @@ -Feature: Data Agreements - - Background: - Given an organization admin for Data4Diabetes organization - And the admin is logged into the Admin dashboard - - Scenario: Create Global Policy Configuration - When the admin creates global policy configuration - Then the global policy configuration should be created - - Scenario: Update Global Policy Configuration - When the admin updates global policy configuration - Then the global policy configuration should be updated - - Scenario: Create Data Agreement - When the admin creates a data agreement - Then the data agreement should be created with version 1.0.0 - - Scenario: Read Data Agreement - When the admin reads a data agreement - Then the admin should be able to view the data agreement - - Scenario: Update Data Agreement - When the admin updates a data agreement - Then the data agreement should be updated - - Scenario: Delete Data Agreement - When the admin deletes a data agreement - Then the data agreement should be deleted - - Scenario: Create Data Agreement in Draft Mode - When the admin creates a data agreement in draft mode - Then the data agreement should be in draft mode with version 1.0.0 - - Scenario: Create Data Agreement in Publish Mode - When the admin creates a data agreement in publish mode - Then the data agreement should be in publish mode with version 1.0.0 - - Scenario: Visibility of Data Agreements - Given there are data agreements - When the admin views the list of data agreements - Then the admin should see a list of data agreements - - Scenario: Visibility of Draft Data Agreements - Given there are draft data agreements - When the admin views the list of data agreements - Then the admin should see a list of draft data agreements - - Scenario: Visibility of Published Data Agreements - Given there are published data agreements - When the admin views the list of data agreements - Then the admin should see a list of published data agreements - - Scenario: Versioning of Published Data Agreements - Given there is a published data agreement - When the admin updates the data agreement - Then the data agreement version should be incremented - - Scenario: Versioning of Draft Data Agreements - Given there is a draft data agreement - When the admin updates the data agreement - Then the data agreement version should not be incremented - diff --git a/features/admin_dashboard/getting_started.feature b/features/admin_dashboard/getting_started.feature deleted file mode 100644 index 06ef76d..0000000 --- a/features/admin_dashboard/getting_started.feature +++ /dev/null @@ -1,13 +0,0 @@ -Feature: Getting Started Page - - Background: - Given an organization admin for Data4Diabetes organization - And the admin is logged into the Admin dashboard - - Scenario: Update Organization Information - When the admin updates the organization name, description, location, and policy URL - Then the organization information should be updated - - Scenario: Update Organization Logo and Cover Image - When the admin updates the organization logo and cover image - Then the logo and cover image should be updated \ No newline at end of file diff --git a/features/admin_dashboard/global_data_policy/global_data_policy.feature b/features/admin_dashboard/global_data_policy/global_data_policy.feature new file mode 100644 index 0000000..4a57b3a --- /dev/null +++ b/features/admin_dashboard/global_data_policy/global_data_policy.feature @@ -0,0 +1,13 @@ +Feature: Global Data Policy + + Background: + Given an organization admin for Data4Diabetes organization + And the admin is logged into the Admin dashboard + + Scenario: Create Global Policy Configuration + When the admin creates global policy configuration + Then the global policy configuration should be created + + Scenario: Update Global Policy Configuration + When the admin updates global policy configuration + Then the global policy configuration should be updated \ No newline at end of file diff --git a/features/admin_dashboard/manage_users/user_access.feature b/features/admin_dashboard/manage_users/user_access.feature deleted file mode 100644 index 529b1bf..0000000 --- a/features/admin_dashboard/manage_users/user_access.feature +++ /dev/null @@ -1,26 +0,0 @@ -Feature: User Access Management - - Background: - Given an organization admin for Data4Diabetes organization - And the admin is logged into the Admin dashboard - - Scenario: Create Identity Provider Configuration - When the admin creates an identity provider configuration - Then the identity provider configuration should be created - - Scenario: Read Identity Provider Configuration - When the admin reads an identity provider configuration - Then the admin should be able to view the identity provider configuration - - Scenario: Update Identity Provider Configuration - When the admin updates an identity provider configuration - Then the identity provider configuration should be updated - - Scenario: Delete Identity Provider Configuration - When the admin deletes an identity provider configuration - Then the identity provider configuration should be deleted - - Scenario: Bulk Onboard Individuals Using CSV - When the admin bulk onboards individuals using a CSV file upload - Then the individuals should be created in the consent BB identity provider - diff --git a/features/admin_dashboard/manage_users/user_records.feature b/features/admin_dashboard/manage_users/user_records.feature deleted file mode 100644 index 8fc7d68..0000000 --- a/features/admin_dashboard/manage_users/user_records.feature +++ /dev/null @@ -1,38 +0,0 @@ -Feature: User Records Management - - Background: - Given an organization admin for Data4Diabetes organization - And the admin is logged into the Admin dashboard - - Scenario: List Consent Records with Pagination - When the admin views the list of consent records - Then the admin should see a paginated list of consent records - - Scenario: View Data Agreement from Consent Records - When the admin clicks the eye icon in the actions column of a consent record - Then the admin should be able to see the corresponding data agreement - - Scenario: Filter Consent Records - All - When the admin filters consent records to see all consent records - Then the admin should see a list of all consent records - - Scenario: Filter Consent Records - Purpose of Data Agreement - When the admin filters consent records by the purpose of the data agreement - Then the admin should see a filtered list of consent records - - Scenario: Filter Consent Records - Lawful Bases (GDPR) - When the admin filters consent records by lawful bases (GDPR) - Then the admin should see a filtered list of consent records - - Scenario: Search Consent Records by Data Agreement ID - When the admin uses the free search bar to search for consent records by Data Agreement ID - Then the admin should see the relevant consent records - - Scenario: Search Consent Records by Consent Record ID - When the admin uses the free search bar to search for consent records by Consent Record ID - Then the admin should see the relevant consent records - - Scenario: Search Consent Records by Individual ID - When the admin uses the free search bar to search for consent records by Individual ID - Then the admin should see the relevant consent records - diff --git a/features/admin_dashboard/notification/notification.feature b/features/admin_dashboard/notification/notification.feature new file mode 100644 index 0000000..8467fdb --- /dev/null +++ b/features/admin_dashboard/notification/notification.feature @@ -0,0 +1,17 @@ +Feature: Notification Subscription Changes + + Scenario: Enable Change Notification Subscription + When the admin enables change notification + Then the data agreement should be updated + + Scenario: Disable Change Notification Subscription + When the admin disables change notification + Then the data agreement should be updated + + Scenario: Enable Notification Subscription Trigger + When the admin enables change notification + Then the data agreement should be updated + + Scenario: Disable Notification Subscription Trigger + When the admin disables change notification + Then the data agreement should be updated diff --git a/features/admin_dashboard/personal_data.feature b/features/admin_dashboard/personal_data.feature deleted file mode 100644 index 6494fae..0000000 --- a/features/admin_dashboard/personal_data.feature +++ /dev/null @@ -1,26 +0,0 @@ -Feature: Personal Data Management - - Background: - Given an organization admin for Data4Diabetes organization - And the admin is logged into the Admin dashboard - - Scenario: List Data Attributes - When the admin lists the data attributes as a table - Then the admin should see a paginated list of data attributes - - Scenario: Update Data Attribute Name - When the admin updates a data attribute name - Then the data attribute name should be updated - - Scenario: Filter Data Attributes - All - When the admin filters data attributes to see all data attributes - Then the admin should see a list of all data attributes - - Scenario: Filter Data Attributes - Data Source - When the admin filters data attributes to see data attributes associated with Data Source - Then the admin should see a list of data attributes associated with Data Source - - Scenario: Filter Data Attributes - Data Using Service - When the admin filters data attributes to see data attributes associated with Data Using Service - Then the admin should see a list of data attributes associated with Data Using Service - diff --git a/features/admin_dashboard/privacy_dashboard.feature b/features/admin_dashboard/privacy_dashboard.feature deleted file mode 100644 index d7e60c9..0000000 --- a/features/admin_dashboard/privacy_dashboard.feature +++ /dev/null @@ -1,15 +0,0 @@ -Feature: Privacy Dashboard Management - - Background: - Given an organization admin for Data4Diabetes organization - And the admin is logged into the Admin dashboard - - Scenario: View Deployed Privacy Dashboard Information - When the admin views the deployed privacy dashboard information - Then the admin should see the current deployed privacy dashboard version, domain URL, and deployment status - - Scenario: Check Privacy Dashboard Configuration in Single Tenant Mode - Given Consent BB is in single tenant mode - When the admin checks the configuration of the privacy dashboard - Then the "Configure" button should be disabled - diff --git a/features/data_processing_auditor/data_processing_auditor.feature b/features/data_processing_auditor/data_processing_auditor.feature new file mode 100644 index 0000000..c7e1ebb --- /dev/null +++ b/features/data_processing_auditor/data_processing_auditor.feature @@ -0,0 +1,24 @@ +Feature: Audit Logging + + Background: + Given an organization admin for Data4Diabetes organization + And the admin is logged into the Admin dashboard + + Scenario: Audit logging + When the admin queries the consent related to an individual + Then the admin can view the Data Agreement corresponding to the consent ID + + Scenario: View Data Agreement for audit + When the admin clicks on the eye or view icon + And views the data agreement table + Then the admin should be able to view the data agreement + + Scenario: View consents for audit + When the admin clicks on the view icon + And views the data agreement + Then the admin should be able to view the consent records + + Scenario: Revision list + When the admin clicks on the view icon + And views the revision of data agreement + Then the admin should be able to view the revision of the data agreement diff --git a/features/onboarding/individual_onboard.feature b/features/onboarding/individual_onboard.feature new file mode 100644 index 0000000..2434703 --- /dev/null +++ b/features/onboarding/individual_onboard.feature @@ -0,0 +1,11 @@ +Feature: Individual Onboard + + Scenario: Login individuals via 3PP + Given a user logs in to Data4Diabetes + When the user view DA + Then the user should be able to view the data agreement + + Scenario: Login individuals + Given a user logs in to Data4Diabetes + When the user view DA + Then the user should be able to view the data agreement diff --git a/features/onboarding/onboarding.feature b/features/onboarding/onboarding.feature new file mode 100644 index 0000000..6304c28 --- /dev/null +++ b/features/onboarding/onboarding.feature @@ -0,0 +1,49 @@ +Feature: Onboarding Organisation and Users + + Background: + Given an organization admin for Data4Diabetes organization + And the admin is logged into the Admin dashboard + + Scenario: Org admin logs into Admin Dashboard + Given an organization admin for Data4Diabetes organization + When the admin enters the user id + And enters the password + Then the admin should be able to login to the system + + Scenario: Onboard user to the system + When the admin imports users to the system + Then users are successfully onboarded + + Scenario: Deploy privacy dashboard webclient + When the admin chooses the SW version + And deploys the privacy dashboard client + Then the privacy dashboard is deployed at the chosen location + + Scenario: Update administrator profile + When the admin clicks on "manage admin" to update the details + And updates the admin user password + Then the admin user password is changed + + Scenario: View Organization details + When the admin clicks on "getting started" to view details + Then the admin can view the organization details + + Scenario: Update Organization logo image + When the admin updates the organization logo image + Then the logo image should be updated + + Scenario: Update Organization Cover Image + When the admin updates the organization cover image + Then the cover image should be updated + + Scenario: Update Organization Information + When the admin updates the organization name, description, location, and policy URL + Then the organization information should be updated + + Scenario: OIDC configuration + When the admin adds OIDC configuration to the organization + Then OIDC client is configured for the organization + + Scenario: Onboard existing user to the system + When the admin onboards existing users in configured IDP + Then existing users are successfully onboarded diff --git a/features/onboarding/org_admin_onboard.feature b/features/onboarding/org_admin_onboard.feature new file mode 100644 index 0000000..d368b44 --- /dev/null +++ b/features/onboarding/org_admin_onboard.feature @@ -0,0 +1,11 @@ +Feature: Organisation Admin Onboard + + Scenario: Org admin logs into Admin Dashboard + Given an organization admin for Data4Diabetes organization + When the admin logs into the Admin dashboard with credentials + Then the admin should be able to login to the admin dashboard + + Scenario: Org admin update admin detail + Given an organization admin for Data4Diabetes organization + When the admin updates the details in user settings + Then the admin details should be updated diff --git a/features/privacy_dashboard/individual_mobile_client.feature b/features/privacy_dashboard/individual_mobile_client.feature new file mode 100644 index 0000000..fb2f4ce --- /dev/null +++ b/features/privacy_dashboard/individual_mobile_client.feature @@ -0,0 +1,50 @@ +Feature: Individual mobile client + + Background: + Given an organization admin for Data4Diabetes organization + And the admin is logged into the Admin dashboard + + Scenario: View Data Agreement for Individual + Given a user for Data4Diabetes + When the user views all data agreements + Then the user should be able to view all the data agreements + + Scenario: View single Data Agreement + Given a user for Data4Diabetes + When the user views a specific data agreement + Then the user should be able to view the data agreement + + Scenario: Give consent + Given a user for Data4Diabetes + When the user opts in to a consent + Then the user should be able to opt in to a chosen data agreement + + Scenario: Give consent to opt-in + Given a user for Data4Diabetes + When the user opts in to multiple consents + Then the user should be able to opt in to multiple data agreements + + Scenario: Withdraw consent + Given a user for Data4Diabetes + When the user opts out of consent + Then the user should be able to opt out of the data agreement + + Scenario: View data logs + Given a user for Data4Diabetes + When the user views the logged actions + Then the user can view all their actions + + Scenario: DA change notification + Given a user for Data4Diabetes + When the user modifies their consent + Then the organization IT system is notified via webhooks + + Scenario: DA change notification for opt-out + Given a user for Data4Diabetes + When the user modifies their consent to opt-out + Then the organization IT system is notified via webhooks + + Scenario: View change notification + Given a user for Data4Diabetes + When the user receives a notification from the organization + Then the user can view the data agreement change notification diff --git a/features/privacy_dashboard/individual_web_client.feature b/features/privacy_dashboard/individual_web_client.feature new file mode 100644 index 0000000..723e4f4 --- /dev/null +++ b/features/privacy_dashboard/individual_web_client.feature @@ -0,0 +1,50 @@ +Feature: Individual web client + + Background: + Given an organization admin for Data4Diabetes organization + And the admin is logged into the Admin dashboard + + Scenario: View all Data Agreement for web + Given a user for Data4Diabetes + When the user views all data agreements + Then the user should be able to view all the data agreements + + Scenario: View single Data Agreement for web + Given a user for Data4Diabetes + When the user views a specific data agreement + Then the user should be able to view the data agreement + + Scenario: Give consent for chosen DA + Given a user for Data4Diabetes + When the user opts in to a consent + Then the user should be able to opt in to a chosen data agreement + + Scenario: Give consent for web to opt-in + Given a user for Data4Diabetes + When the user opts in to multiple consents + Then the user should be able to opt in to multiple data agreements + + Scenario: Withdraw consent for web opt-out + Given a user for Data4Diabetes + When the user opts out of consent + Then the user should be able to opt out of the data agreement + + Scenario: View data logs for web + Given a user for Data4Diabetes + When the user views the logged actions + Then the user can view all their actions + + Scenario: DA change notification for web opt-in + Given a user for Data4Diabetes + When the user modifies their consent + Then the organization IT system is notified via webhooks + + Scenario: DA change notification for web opt-out + Given a user for Data4Diabetes + When the user modifies their consent to opt-out + Then the organization IT system is notified via webhooks + + Scenario: View change notification for web + Given a user for Data4Diabetes + When the user receives a notification from the organization + Then the user can view the data agreement change notification diff --git a/steps/admin_logging.py b/steps/admin_logging.py new file mode 100644 index 0000000..119adf3 --- /dev/null +++ b/steps/admin_logging.py @@ -0,0 +1,26 @@ +import json +import requests +from behave import * + +@when('the admin clicks on the "view admin function"') +def step_impl(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/audit/admin/logs" + response = requests.get(url + "/", verify=False, headers=headers) + context.response = response + + +@then('the admin should be able to view security log functions') +def step_impl(context): + assert context.response.status_code == 200 + + +@then('the admin should be able to view webhook log functions') +def step_impl(context): + assert context.response.status_code == 200 + + +@then('the admin should be able to view API calls log functions') +def step_impl(context): + assert context.response.status_code == 200 \ No newline at end of file diff --git a/steps/create_data_agreement.py b/steps/create_data_agreement.py new file mode 100644 index 0000000..2285db2 --- /dev/null +++ b/steps/create_data_agreement.py @@ -0,0 +1,342 @@ +import json +import requests +from behave import * + + +@when("the admin chooses a new data policy") +def step_impl(context): + new_policy = { + "name": "Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + } + context.policy = new_policy + +@when("creates a data agreement in draft mode") +def create_draft_data_agreement(context): + policy = context.policy + + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": policy, + "purpose": "Issue License", + "purposeDescription": "Issue License", + "lawfulBasis": "consent", + "methodOfUse": "null", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": False, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "draft", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + context.response = response + + +@then("the data agreement should be in draft mode with version 1.0.0") +def is_data_agreement_draft(context): + assert context.response.status_code == 200 + response_json = json.loads(context.response.content) + data_agreement_version = response_json["dataAgreement"]["version"] + data_agreement_id = response_json["dataAgreement"]["id"] + assert data_agreement_version == "1.0.0" + cleanup_data_agreement(context,data_agreement_id) + + +@when("the admin chooses an existing data policy template") +def step_impl(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/policies" + response = requests.get(url + "/", verify=False, headers=headers) + response_json = json.loads(response.content) + policy = response_json["policies"][0] + context.policy = policy + + +@when("updates one or two fields to create a data agreement in draft mode") +def step_impl(context): + policy = { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "Europe", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "Sweden", + "thirdPartyDataSharing": True, + } + + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": policy, + "purpose": "Issue License", + "purposeDescription": "Issue License", + "lawfulBasis": "consent", + "methodOfUse": "null", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": False, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "draft", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + context.response = response + + +@when("the admin chooses a new data policy to create a data agreement") +def step_impl(context): + new_policy = { + "name": "Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + } + context.policy = new_policy + + +@then("the data agreement should be created with version 1.0.0") +def is_data_agreement_created(context): + response_json = json.loads(context.response.content) + data_agreement_version = response_json["dataAgreement"]["version"] + data_agreement_id = response_json["dataAgreement"]["id"] + assert data_agreement_version == "1.0.0" + cleanup_data_agreement(context,data_agreement_id) + + +@when("creates a data agreement") +def create_data_agreement(context): + policy = context.policy + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": policy, + "purpose": "Issue Passports", + "purposeDescription": "Issue Passports", + "lawfulBasis": "consent", + "methodOfUse": "null", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": True, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "complete", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + context.response = response + +@when("updates one or two fields to create a data agreement") +def step_impl(context): + policy = { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "Europe", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "Sweden", + "thirdPartyDataSharing": True, + } + + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": policy, + "purpose": "Issue License", + "purposeDescription": "Issue License", + "lawfulBasis": "consent", + "methodOfUse": "null", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": False, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "draft", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + context.response = response + + +@when("the admin creates several data agreements in one transaction") +def step_impl(context): + raise NotImplementedError( + "STEP: When the admin creates several data agreements in one transaction" + ) + + +@when("uses CLI command") +def step_impl(context): + raise NotImplementedError("STEP: When uses CLI command") + + +@then("the multiple data agreements should be created") +def step_impl(context): + raise NotImplementedError( + "STEP: Then the multiple data agreements should be created" + ) + + +@when("the admin chooses a lawful basis other than consent") +def step_impl(context): + lawful_basis = "vital_interest" + context.lawful_basis = lawful_basis + + +@when("create a data agreement") +def create_data_agreement(context): + lawful_basis = context.lawful_basis + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": "Issue Passport", + "purposeDescription": "Issue Passport", + "lawfulBasis": lawful_basis, + "methodOfUse": "null", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": True, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "complete", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + context.response = response + +def cleanup_data_agreement(context, data_agreement_id): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement/" + data_agreement_id + response = requests.delete(url + "/", verify=False, headers=headers) \ No newline at end of file diff --git a/steps/data_agreements.py b/steps/data_agreements.py deleted file mode 100644 index 3abde28..0000000 --- a/steps/data_agreements.py +++ /dev/null @@ -1,488 +0,0 @@ -import json - -import requests -from behave import * - - -@when("the admin creates global policy configuration") -def create_policy(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/policies" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - response_json = json.loads(context.response.content) - policy_id = response_json["policies"][0]["id"] - url = base_url + "/config/policy/" + policy_id - response = requests.delete(url + "/", verify=False, headers=headers) - data = { - "policy": { - "name": "New Policy", - "url": "https://igrant.io/policy.html", - "jurisdiction": "London,GB", - "industrySector": "Retail", - "dataRetentionPeriodDays": 4, - "geographicRestriction": "Not restricted", - "storageLocation": "London", - "thirdPartyDataSharing": True, - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/policy" - response = requests.post(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the global policy configuration should be created") -def is_policy_created(context): - response_json = json.loads(context.response.content) - policy_id = response_json["policy"]["id"] - context.config.userdata.policy_id = policy_id - assert context.response.status_code == 200 - - -@when("the admin updates global policy configuration") -def update_policy(context): - policy_id = context.config.userdata.policy_id - data = { - "policy": { - "name": "Updated Policy", - "url": "https://igrant.io/policy.html", - "jurisdiction": "London,GB", - "industrySector": "Retail", - "dataRetentionPeriodDays": 350, - "geographicRestriction": "Not restricted", - "storageLocation": "London", - "thirdPartyDataSharing": True, - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/policy/" + policy_id - response = requests.put(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the global policy configuration should be updated") -def is_policy_updated(context): - assert context.response.status_code == 200 - - -@when("the admin creates a data agreement") -def create_data_agreement(context): - data = { - "dataAgreement": { - "controllerId": "652657969380f35fa1c30245", - "controllerUrl": "string", - "controllerName": "string", - "policy": { - "name": "Updated Policy", - "url": "https://igrant.io/policy.html", - "jurisdiction": "London,GB", - "industrySector": "Retail", - "dataRetentionPeriodDays": 350, - "geographicRestriction": "Not restricted", - "storageLocation": "London", - "thirdPartyDataSharing": True, - }, - "purpose": "Issue Passports", - "purposeDescription": "Issue Passports", - "lawfulBasis": "consent", - "methodOfUse": "null", - "dpiaDate": "2023-10-31T14:24", - "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", - "active": True, - "forgettable": False, - "compatibleWithVersionId": False, - "lifecycle": "complete", - "dataAttributes": [ - { - "id": "65410e3bd8e8336d82709824", - "name": "Name", - "description": "Name of person", - "sensitivity": False, - "category": "", - }, - { - "id": "65410e3bd8e8336d82709825", - "name": "Age", - "description": "Age of person", - "sensitivity": False, - "category": "", - }, - ], - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/data-agreement" - response = requests.post(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the data agreement should be created with version 1.0.0") -def is_data_agreement_created(context): - response_json = json.loads(context.response.content) - data_agreement_version = response_json["dataAgreement"]["version"] - data_agreement_id = response_json["dataAgreement"]["id"] - context.config.userdata.data_agreement_id = data_agreement_id - assert data_agreement_version == "1.0.0" - - -@when("the admin reads a data agreement") -def read_data_agreement(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - data_agreement_id = context.config.userdata.data_agreement_id - url = base_url + "/config/data-agreement/" + data_agreement_id - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the admin should be able to view the data agreement") -def view_data_agreement(context): - assert context.response.status_code == 200 - - -@when("the admin updates a data agreement") -def update_data_agreement(context): - data = { - "dataAgreement": { - "controllerId": "652657969380f35fa1c30245", - "controllerUrl": "string", - "controllerName": "string", - "policy": { - "name": "Updated Policy", - "url": "https://igrant.io/policy.html", - "jurisdiction": "London,GB", - "industrySector": "Retail", - "dataRetentionPeriodDays": 350, - "geographicRestriction": "Not restricted", - "storageLocation": "London", - "thirdPartyDataSharing": True, - }, - "purpose": "Issue Passports", - "purposeDescription": "Issue Passport", - "lawfulBasis": "consent", - "methodOfUse": "data_source", - "dpiaDate": "2023-10-31T14:24", - "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", - "active": True, - "forgettable": False, - "compatibleWithVersionId": False, - "lifecycle": "complete", - "dataAttributes": [ - { - "id": "65410e3bd8e8336d82709824", - "name": "Name", - "description": "Name of customer", - "sensitivity": False, - "category": "", - }, - { - "id": "65410e3bd8e8336d82709825", - "name": "Age", - "description": "Age of customer", - "sensitivity": False, - "category": "", - }, - ], - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - data_agreement_id = context.config.userdata.data_agreement_id - url = base_url + "/config/data-agreement/" + data_agreement_id - response = requests.put(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the data agreement should be updated") -def is_data_agreement_updated(context): - assert context.response.status_code == 200 - - -@when("the admin deletes a data agreement") -def delete_data_agreement(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - data_agreement_id = context.config.userdata.data_agreement_id - url = base_url + "/config/data-agreement/" + data_agreement_id - response = requests.delete(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the data agreement should be deleted") -def is_data_agreement_deleted(context): - assert context.response.status_code == 200 - - -@when("the admin creates a data agreement in draft mode") -def create_draft_data_agreement(context): - data = { - "dataAgreement": { - "controllerId": "652657969380f35fa1c30245", - "controllerUrl": "string", - "controllerName": "string", - "policy": { - "name": "Updated Policy", - "url": "https://igrant.io/policy.html", - "jurisdiction": "London,GB", - "industrySector": "Retail", - "dataRetentionPeriodDays": 350, - "geographicRestriction": "Not restricted", - "storageLocation": "London", - "thirdPartyDataSharing": True, - }, - "purpose": "Issue License", - "purposeDescription": "Issue License", - "lawfulBasis": "consent", - "methodOfUse": "null", - "dpiaDate": "2023-10-31T14:24", - "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", - "active": False, - "forgettable": False, - "compatibleWithVersionId": False, - "lifecycle": "draft", - "dataAttributes": [ - { - "id": "65410e3bd8e8336d82709824", - "name": "Name", - "description": "Name of person", - "sensitivity": False, - "category": "", - }, - { - "id": "65410e3bd8e8336d82709825", - "name": "Age", - "description": "Age of person", - "sensitivity": False, - "category": "", - }, - ], - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/data-agreement" - response = requests.post(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the data agreement should be in draft mode with version 1.0.0") -def is_data_agreement_draft(context): - assert context.response.status_code == 200 - response_json = json.loads(context.response.content) - data_agreement_version = response_json["dataAgreement"]["version"] - data_agreement_id = response_json["dataAgreement"]["id"] - context.config.userdata.draft_data_agreement_id = data_agreement_id - assert data_agreement_version == "1.0.0" - - -@when("the admin creates a data agreement in publish mode") -def create_publish_data_agreement(context): - data = { - "dataAgreement": { - "controllerId": "652657969380f35fa1c30245", - "controllerUrl": "string", - "controllerName": "string", - "policy": { - "name": "Updated Policy", - "url": "https://igrant.io/policy.html", - "jurisdiction": "London,GB", - "industrySector": "Retail", - "dataRetentionPeriodDays": 350, - "geographicRestriction": "Not restricted", - "storageLocation": "London", - "thirdPartyDataSharing": True, - }, - "purpose": "Issue Certificate", - "purposeDescription": "Issue Certificate", - "lawfulBasis": "consent", - "methodOfUse": "null", - "dpiaDate": "2023-10-31T14:24", - "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", - "active": True, - "forgettable": False, - "compatibleWithVersionId": False, - "lifecycle": "complete", - "dataAttributes": [ - { - "id": "65410e3bd8e8336d82709824", - "name": "Name", - "description": "Name of person", - "sensitivity": False, - "category": "", - }, - { - "id": "65410e3bd8e8336d82709825", - "name": "Age", - "description": "Age of person", - "sensitivity": False, - "category": "", - }, - ], - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/data-agreement" - response = requests.post(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the data agreement should be in publish mode with version 1.0.0") -def is_published_data_agreement(context): - assert context.response.status_code == 200 - response_json = json.loads(context.response.content) - data_agreement_version = response_json["dataAgreement"]["version"] - data_agreement_id = response_json["dataAgreement"]["id"] - context.config.userdata.published_data_agreement_id = data_agreement_id - assert data_agreement_version == "1.0.0" - - -@given("there are data agreements") -def data_agreements(context): - pass - - -@when("the admin views the list of data agreements") -def list_data_agreements(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/data-agreements" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the admin should see a list of data agreements") -def is_list_of_data_agreement(context): - assert context.response.status_code == 200 - - -@given("there are draft data agreements") -def draft_data_agreements(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - params = {"lifecycle": "draft"} - url = base_url + "/config/data-agreements" - response = requests.get(url + "/", verify=False, headers=headers, params=params) - context.response = response - - -@then("the admin should see a list of draft data agreements") -def list_draft_data_agreements(context): - assert context.response.status_code == 200 - - -@given("there are published data agreements") -def published_data_agreements(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - params = {"lifecycle": "complete"} - url = base_url + "/config/data-agreements" - response = requests.get(url + "/", verify=False, headers=headers, params=params) - context.response = response - - -@then("the admin should see a list of published data agreements") -def list_published_data_agreements(context): - assert context.response.status_code == 200 - - -@given("there is a published data agreement") -def published_data_agreement(context): - data_agreement_id = context.config.userdata.published_data_agreement_id - context.data_agreement_id = data_agreement_id - context.purpose = "Issue Certificate" - - -@when("the admin updates the data agreement") -def update_data_agreement(context): - purpose = context.purpose - data = { - "dataAgreement": { - "controllerId": "652657969380f35fa1c30245", - "controllerUrl": "string", - "controllerName": "string", - "policy": { - "name": "Updated Policy", - "url": "https://igrant.io/policy.html", - "jurisdiction": "London,GB", - "industrySector": "Retail", - "dataRetentionPeriodDays": 350, - "geographicRestriction": "Not restricted", - "storageLocation": "London", - "thirdPartyDataSharing": True, - }, - "purpose": purpose, - "purposeDescription": "Issue license and certificate", - "lawfulBasis": "consent", - "methodOfUse": "data_source", - "dpiaDate": "2023-10-31T14:24", - "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", - "active": True, - "forgettable": False, - "compatibleWithVersionId": False, - "lifecycle": "complete", - "dataAttributes": [ - { - "id": "65410e3bd8e8336d82709824", - "name": "Name", - "description": "Name of customer", - "sensitivity": False, - "category": "", - }, - { - "id": "65410e3bd8e8336d82709825", - "name": "Age", - "description": "Age of customer", - "sensitivity": False, - "category": "", - }, - ], - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - data_agreement_id = context.data_agreement_id - url = base_url + "/config/data-agreement/" + data_agreement_id - response = requests.put(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the data agreement version should be incremented") -def is_data_agreement_version_incremented(context): - assert context.response.status_code == 200 - response_json = json.loads(context.response.content) - data_agreement_version = response_json["dataAgreement"]["version"] - data_agreement_id = response_json["dataAgreement"]["id"] - context.published_data_agreement_id = data_agreement_id - assert data_agreement_version == "2.0.0" - - -@given("there is a draft data agreement") -def draft_data_agreement(context): - data_agreement_id = context.config.userdata.draft_data_agreement_id - context.data_agreement_id = data_agreement_id - context.purpose = "Issue Lisense" - - -@then("the data agreement version should not be incremented") -def is_data_agreement_version_same(context): - response_json = json.loads(context.response.content) - data_agreement_version = response_json["dataAgreement"]["version"] - data_agreement_id = response_json["dataAgreement"]["id"] - cleanup_data_agreement(context) - assert data_agreement_version == "1.0.0" - -def cleanup_data_agreement(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - data_agreement_id = context.config.userdata.published_data_agreement_id - url = base_url + "/config/data-agreement/" + data_agreement_id - response = requests.delete(url + "/", verify=False, headers=headers) - data_agreement_id = context.config.userdata.draft_data_agreement_id - url = base_url + "/config/data-agreement/" + data_agreement_id - response = requests.delete(url + "/", verify=False, headers=headers) diff --git a/steps/data_processing_auditor.py b/steps/data_processing_auditor.py new file mode 100644 index 0000000..a0b90de --- /dev/null +++ b/steps/data_processing_auditor.py @@ -0,0 +1,164 @@ +import json +import requests +from behave import * + +@when('the admin queries the consent related to an individual') +def step_impl(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/individuals" + response = requests.get(url + "/", verify=False, headers=headers) + response_json = json.loads(response.content) + individual_id = response_json["individuals"][0]["id"] + context.individual_id = individual_id + + params = {"id": individual_id} + url = base_url + "/audit/consent-records" + response = requests.get(url + "/", verify=False, headers=headers,params=params) + context.response = response + + +@then('the admin can view the Data Agreement corresponding to the consent ID') +def step_impl(context): + assert context.response.status_code == 200 + + +@when('the admin clicks on the eye or view icon') +def step_impl(context): + if not hasattr(context.config.userdata,"published_data_agreement"): + add_data_agreements(context) + + +@when('views the data agreement table') +def step_impl(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + data_agreement_id = context.config.userdata.published_data_agreement_id + url = base_url + "/config/data-agreement/" + data_agreement_id + response = requests.get(url + "/", verify=False, headers=headers) + context.response = response + + +@when('the admin clicks on the view icon') +def step_impl(context): + pass + + +@when('views the data agreement') +def step_impl(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + data_agreement_id = context.config.userdata.published_data_agreement_id + url = base_url + "/config/data-agreement/" + data_agreement_id + response = requests.get(url + "/", verify=False, headers=headers) + context.response = response + + +@then('the admin should be able to view the consent records') +def step_impl(context): + raise NotImplementedError(u'STEP: Then the admin should be able to view the consent records') + + +@when('views the revision of data agreement') +def step_impl(context): + raise NotImplementedError(u'STEP: When views the revision of data agreement') + + +@then('the admin should be able to view the revision of the data agreement') +def step_impl(context): + raise NotImplementedError(u'STEP: Then the admin should be able to view the revision of the data agreement') + +def add_data_agreements(context): + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": "Issue Certificate", + "purposeDescription": "Issue Certificate", + "lawfulBasis": "consent", + "methodOfUse": "null", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": True, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "complete", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + response_json = json.loads(response.content) + data_agreement_id = response_json["dataAgreement"]["id"] + context.config.userdata.published_data_agreement_id = data_agreement_id + + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": "Issue License", + "purposeDescription": "Issue License", + "lawfulBasis": "consent", + "methodOfUse": "data_source", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": False, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "draft", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + response_json = json.loads(response.content) + data_agreement_id = response_json["dataAgreement"]["id"] + context.config.userdata.draft_data_agreement_id = data_agreement_id + diff --git a/steps/delete_data_agreement.py b/steps/delete_data_agreement.py new file mode 100644 index 0000000..94448de --- /dev/null +++ b/steps/delete_data_agreement.py @@ -0,0 +1,79 @@ +import json +import requests +from behave import * + +@when('the admin deletes a data agreement') +def delete_data_agreement(context): + add_data_agreement(context,True) + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + data_agreement_id = context.data_agreement_id + url = base_url + "/config/data-agreement/" + data_agreement_id + response = requests.delete(url + "/", verify=False, headers=headers) + context.response = response + +@then('the data agreement should be deleted') +def is_data_agreement_deleted(context): + assert context.response.status_code == 200 + +@when('the admin deletes a draft data agreement') +def delete_draft_data_agreement(context): + add_data_agreement(context,False) + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + data_agreement_id = context.data_agreement_id + url = base_url + "/config/data-agreement/" + data_agreement_id + response = requests.delete(url + "/", verify=False, headers=headers) + context.response = response + +def add_data_agreement(context,active): + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": "Issue Certificate", + "purposeDescription": "Issue Certificate", + "lawfulBasis": "consent", + "methodOfUse": "null", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": active, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "complete", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + response_json = json.loads(response.content) + data_agreement_id = response_json["dataAgreement"]["id"] + context.data_agreement_id = data_agreement_id \ No newline at end of file diff --git a/steps/developer_api.py b/steps/developer_api.py deleted file mode 100644 index 1dbd508..0000000 --- a/steps/developer_api.py +++ /dev/null @@ -1,68 +0,0 @@ -import json - -import requests -from behave import * - - -@when("the admin views the organization ID, admin user ID, and API base URL") -def view_organisation(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/onboard/organisation" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the admin should see this information") -def sees_organisation(context): - assert context.response.status_code == 200 - - -@when("the admin creates an API key with specified expiry and scopes") -def create_apikey(context): - base_url = context.config.userdata.get("base_url") - data = {"apiKey": {"name": "Service", "scopes": ["service"], "expiryInDays": 30}} - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/admin/apikey" - response = requests.post(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the admin should receive a one-time copyable API key") -def is_apikey_created(context): - response_json = json.loads(context.response.content) - apikey_id = response_json["apiKey"]["id"] - context.config.userdata.apikey_id = apikey_id - assert context.response.status_code == 200 - - - -@when("the admin updates an API key to refresh it") -def update_apikey(context): - apikey_id = context.config.userdata.apikey_id - data = {"apiKey": {"name": "Service", "scopes": ["service"], "expiryInDays": 60}} - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/admin/apikey/" + apikey_id - response = requests.put(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the admin should receive a new one-time copyable API key") -def is_apikey_updated(context): - response_json = json.loads(context.response.content) - assert context.response.status_code == 200 - - -@when("the admin views the list of API keys") -def views_apikeys(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/admin/apikeys" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the admin should see a paginated list of API keys") -def is_list_of_apikeys(context): - assert context.response.status_code == 200 diff --git a/steps/filter_data_agreements.py b/steps/filter_data_agreements.py new file mode 100644 index 0000000..0077c0b --- /dev/null +++ b/steps/filter_data_agreements.py @@ -0,0 +1,140 @@ +import json +import requests +from behave import * + +@when('the admin clicks the "Published" radio button') +def step_impl(context): + add_data_agreements(context) + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreements" + params = {"lifecycle": "complete"} + response = requests.get(url + "/" , verify=False, headers=headers,params=params) + context.response = response + + +@then('the Published data agreements should be shown') +def step_impl(context): + assert context.response.status_code == 200 + cleanup_data_agreement(context=context) + + + +@when('the admin clicks the "All" radio button') +def step_impl(context): + add_data_agreements(context) + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreements" + response = requests.get(url + "/", verify=False, headers=headers) + context.response = response + + +@then('the All data agreements should be shown') +def step_impl(context): + assert context.response.status_code == 200 + cleanup_data_agreement(context=context) + +def add_data_agreements(context): + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": "Issue Certificate", + "purposeDescription": "Issue Certificate", + "lawfulBasis": "consent", + "methodOfUse": "null", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": True, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "complete", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + response_json = json.loads(response.content) + data_agreement_id = response_json["dataAgreement"]["id"] + context.published_data_agreement_id = data_agreement_id + + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": "Issue License", + "purposeDescription": "Issue License", + "lawfulBasis": "consent", + "methodOfUse": "data_source", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": False, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "draft", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + response_json = json.loads(response.content) + data_agreement_id = response_json["dataAgreement"]["id"] + context.draft_data_agreement_id = data_agreement_id + +def cleanup_data_agreement(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement/" + context.published_data_agreement_id + response = requests.delete(url + "/", verify=False, headers=headers) + + url = base_url + "/config/data-agreement/" + context.draft_data_agreement_id + response = requests.delete(url + "/", verify=False, headers=headers) + \ No newline at end of file diff --git a/steps/getting_started.py b/steps/getting_started.py index b71b6c5..7dc1d77 100644 --- a/steps/getting_started.py +++ b/steps/getting_started.py @@ -18,60 +18,3 @@ def step_impl(context): response_json = json.loads(response.content) context.access_token = response_json["accessToken"] - -@when("the admin updates the organization name, description, location, and policy URL") -def step_impl(context): - base_url = context.config.userdata.get("base_url") - data = { - "organisation": { - "name": "Retail company", - "description": "Retail electronic company", - "sector": "Retail", - "location": "Sweden", - "policyUrl": "http://localhost.com", - } - } - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/onboard/organisation" - response = requests.put(url + "/", json=data, verify=False, headers=headers) - response_json = json.loads(response.content) - context.response = response - - -@then("the organization information should be updated") -def step_impl(context): - assert context.response.status_code == 200 - - -@when("the admin updates the organization logo and cover image") -def step_impl(context): - base_url = context.config.userdata.get("base_url") - - headers = { - "Authorization": f"Bearer {context.access_token}" - } - logo_file_path = "assets/Sports.jpg" - cover_image_file_path = "assets/Default_Cover_Image.jpg" - - # update logo image - files = { - "orgimage": ("Sports.jpg", open(logo_file_path, "rb")), - } - url = base_url + "/onboard/organisation/logoimage" - response = requests.post(url + "/", files=files, verify=False, headers=headers) - context.response_logo_image = response - - # update cover image - files = { - "orgimage": ("Default_Cover_Image.jpg", open(cover_image_file_path, "rb")), - } - url = base_url + "/onboard/organisation/coverimage" - response = requests.post(url + "/", files=files, verify=False, headers=headers) - context.response_cover_image = response - - -@then("the logo and cover image should be updated") -def step_impl(context): - - assert context.response_logo_image.status_code == 200 - assert context.response_cover_image.status_code == 200 diff --git a/steps/global_data_policy.py b/steps/global_data_policy.py new file mode 100644 index 0000000..e95a56a --- /dev/null +++ b/steps/global_data_policy.py @@ -0,0 +1,66 @@ +import json +import requests +from behave import * + +@when('the admin creates global policy configuration') +def create_policy(context): + data = { + "policy": { + "name": "New Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 4, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/policy" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + context.response = response + + +@then('the global policy configuration should be created') +def is_policy_created(context): + response_json = json.loads(context.response.content) + policy_id = response_json["policy"]["id"] + context.config.userdata.policy_id = policy_id + assert context.response.status_code == 200 + + +@when('the admin updates global policy configuration') +def update_policy(context): + policy_id = context.config.userdata.policy_id + data = { + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/policy/" + policy_id #+ "/" + response = requests.put(url + "/", json=data, verify=False, headers=headers) + context.response = response + + +@then('the global policy configuration should be updated') +def is_policy_updated(context): + assert context.response.status_code == 200 + cleanup_policy(context) + +def cleanup_policy(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + policy_id = context.config.userdata.policy_id + url = base_url + "/config/policy/" + policy_id + response = requests.delete(url + "/", verify=False, headers=headers) diff --git a/steps/individual_client.py b/steps/individual_client.py new file mode 100644 index 0000000..0b76e23 --- /dev/null +++ b/steps/individual_client.py @@ -0,0 +1,258 @@ +import json +import requests +from behave import * + + +@given("a user for Data4Diabetes") +def step_impl(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/individuals" + response = requests.get(url + "/", verify=False, headers=headers) + response_json = json.loads(response.content) + individual_id = response_json["individuals"][0]["id"] + context.individual_id = individual_id + + if not hasattr(context.config.userdata, 'apikey'): + base_url = context.config.userdata.get("base_url") + data = {"apiKey": {"name": "Service", "scopes": ["service"], "expiryInDays": 30}} + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/admin/apikey" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + response_json = json.loads(response.content) + apikey = response_json["apiKey"]["apiKey"] + context.config.userdata.apikey = apikey + + +@when("the user views all data agreements") +def step_impl(context): + add_data_agreements(context) + individual_id = context.individual_id + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"ApiKey {context.config.userdata.apikey}","X-ConsentBB-IndividualId": individual_id} + url = base_url + "/service/data-agreements" + response = requests.get(url + "/", verify=False, headers=headers) + context.response = response + + + +@then("the user should be able to view all the data agreements") +def step_impl(context): + assert context.response.status_code == 200 + + +@when("the user views a specific data agreement") +def step_impl(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"ApiKey {context.config.userdata.apikey}"} + data_agreement_id = context.config.userdata.data_agreement_id + url = base_url + "/service/data-agreement/" + data_agreement_id + response = requests.get(url + "/", verify=False, headers=headers) + context.response = response + + +@then("the user should be able to view the data agreement") +def step_impl(context): + assert context.response.status_code == 200 + + +@when("the user opts in to a consent") +def step_impl(context): + base_url = context.config.userdata.get("base_url") + individual_id = context.individual_id + context.config.userdata.individual_id = individual_id + headers = {"Authorization": f"ApiKey {context.config.userdata.apikey}","X-ConsentBB-IndividualId": individual_id} + data_agreement_id = context.config.userdata.data_agreement_id + url = base_url + "/service/individual/record/data-agreement/" + data_agreement_id + response = requests.post(url + "/", verify=False, headers=headers) + context.response = response + response_json = json.loads(context.response.content) + consent_record_id = response_json["consentRecord"]["id"] + context.config.userdata.consent_record_id = consent_record_id + + + +@then("the user should be able to opt in to a chosen data agreement") +def step_impl(context): + assert context.response.status_code == 200 + + +@when("the user opts in to multiple consents") +def step_impl(context): + raise NotImplementedError("STEP: When the user opts in to multiple consents") + + +@then("the user should be able to opt in to multiple data agreements") +def step_impl(context): + raise NotImplementedError( + "STEP: Then the user should be able to opt in to multiple data agreements" + ) + + +@when("the user opts out of consent") +def step_impl(context): + base_url = context.config.userdata.get("base_url") + individual_id = context.individual_id + headers = {"Authorization": f"ApiKey {context.config.userdata.apikey}","X-ConsentBB-IndividualId": individual_id} + data_agreement_id = context.config.userdata.data_agreement_id + consent_record_id = context.config.userdata.consent_record_id + params = {"individualId": individual_id,"dataAgreementId":data_agreement_id} + url = base_url + "/service/individual/record/consent-record/" + consent_record_id + response = requests.put(url + "/", verify=False, headers=headers,params=params) + context.response = response + + +@then("the user should be able to opt out of the data agreement") +def step_impl(context): + assert context.response.status_code == 200 + + +@when("the user views the logged actions") +def step_impl(context): + base_url = context.config.userdata.get("base_url") + individual_id = context.individual_id + headers = {"Authorization": f"ApiKey {context.config.userdata.apikey}","X-ConsentBB-IndividualId": individual_id} + url = base_url + "/service/individual/record/consent-record/history" + response = requests.get(url + "/", verify=False, headers=headers) + context.response = response + + +@then("the user can view all their actions") +def step_impl(context): + assert context.response.status_code == 200 + cleanup_data_agreement(context) + + +@when("the user modifies their consent") +def step_impl(context): + raise NotImplementedError("STEP: When the user modifies their consent") + + +@then("the organization IT system is notified via webhooks") +def step_impl(context): + raise NotImplementedError( + "STEP: Then the organization IT system is notified via webhooks" + ) + + +@when("the user modifies their consent to opt-out") +def step_impl(context): + raise NotImplementedError("STEP: When the user modifies their consent to opt-out") + + +@when("the user receives a notification from the organization") +def step_impl(context): + raise NotImplementedError( + "STEP: When the user receives a notification from the organization" + ) + + +@then("the user can view the data agreement change notification") +def step_impl(context): + raise NotImplementedError( + "STEP: Then the user can view the data agreement change notification" + ) + + +def add_data_agreements(context): + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": "Issue Certificate", + "purposeDescription": "Issue Certificate", + "lawfulBasis": "consent", + "methodOfUse": "null", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": True, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "complete", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + response_json = json.loads(response.content) + data_agreement_id = response_json["dataAgreement"]["id"] + context.config.userdata.data_agreement_id = data_agreement_id + + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": "Issue License", + "purposeDescription": "Issue License", + "lawfulBasis": "consent", + "methodOfUse": "data_source", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": False, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "draft", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + response_json = json.loads(response.content) + data_agreement_id = response_json["dataAgreement"]["id"] + context.config.userdata.draft_data_agreement_id = data_agreement_id + +def cleanup_data_agreement(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement/" + context.config.userdata.data_agreement_id + response = requests.delete(url + "/", verify=False, headers=headers) + + url = base_url + "/config/data-agreement/" + context.config.userdata.draft_data_agreement_id + response = requests.delete(url + "/", verify=False, headers=headers) \ No newline at end of file diff --git a/steps/individual_onboard.py b/steps/individual_onboard.py new file mode 100644 index 0000000..7a36efa --- /dev/null +++ b/steps/individual_onboard.py @@ -0,0 +1,12 @@ +import json +import requests +from behave import * + +@given('a user logs in to Data4Diabetes') +def step_impl(context): + raise NotImplementedError(u'STEP: Given a user logs in to Data4Diabetes') + + +@when('the user view DA') +def step_impl(context): + raise NotImplementedError(u'STEP: When the user view DA') \ No newline at end of file diff --git a/steps/manage_admin.py b/steps/manage_admin.py deleted file mode 100644 index 799e073..0000000 --- a/steps/manage_admin.py +++ /dev/null @@ -1,67 +0,0 @@ -import json - -import requests -from behave import * - - -@when("the admin updates the organization admin's avatar image") -def update_admin_avatar(context): - base_url = context.config.userdata.get("base_url") - - headers = {"Authorization": f"Bearer {context.access_token}"} - avatar_image_file_path = "assets/Sports.jpg" - - # update avatarimage - files = { - "avatarimage": ("Sports.jpg", open(avatar_image_file_path, "rb")), - } - url = base_url + "/onboard/admin/avatarimage" - response = requests.put(url + "/", files=files, verify=False, headers=headers) - context.response = response - - -@then("the avatar image should be updated") -def is_admin_avatar_updated(context): - assert context.response.status_code == 200 - - -@when("the admin updates the organization admin's name") -def update_admin_name(context): - base_url = context.config.userdata.get("base_url") - data = { - "organisationAdmin": { - "name": "John", - } - } - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/onboard/admin" - response = requests.put(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the admin's name should be updated") -def is_admin_name_updated(context): - assert context.response.status_code == 200 - response_json = json.loads(context.response.content) - admin_name = response_json["organisationAdmin"]["name"] - assert admin_name == "John" - - -@when("the admin resets the organization admin's password") -def reset_admin_password(context): - base_url = context.config.userdata.get("base_url") - data = {"currentPassword": "qwerty123", "newPassword": "qwerty1234"} - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/onboard/password/reset" - response = requests.put(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the password should be reset") -def is_admin_password_reseted(context): - assert context.response.status_code == 200 - base_url = context.config.userdata.get("base_url") - data = {"currentPassword": "qwerty1234", "newPassword": "qwerty123"} - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/onboard/password/reset" - response = requests.put(url + "/", json=data, verify=False, headers=headers) diff --git a/steps/onboarding.py b/steps/onboarding.py new file mode 100644 index 0000000..7ec1efd --- /dev/null +++ b/steps/onboarding.py @@ -0,0 +1,219 @@ +import json +import requests +from behave import * + +@when('the admin enters the user id') +def step_impl(context): + user_id = context.config.userdata.get("username") + context.user_id = user_id + + +@when('enters the password') +def step_impl(context): + user_id = context.user_id + password = context.config.userdata.get("password") + base_url = context.config.userdata.get("base_url") + data = { + "username": user_id, + "password": password, + } + url = base_url + "/onboard/admin/login" + response = requests.post(url + "/", json=data,verify=False) + context.response = response + + +@then('the admin should be able to login to the system') +def step_impl(context): + assert context.response.status_code == 200 + + +@when('the admin imports users to the system') +def step_impl(context): + base_url = context.config.userdata.get("base_url") + + headers = { + "Authorization": f"Bearer {context.access_token}" + } + csv_file_path = "assets/bulk_adding_of_individuals.csv" + + files = { + "individuals": ("bulk_adding_of_individuals.csv", open(csv_file_path, "rb")), + } + url = base_url + "/config/individual/upload" + response = requests.post(url + "/", files=files, verify=False, headers=headers) + context.response = response + + +@then('users are successfully onboarded') +def step_impl(context): + assert context.response.status_code == 200 + + +@when('the admin chooses the SW version') +def step_impl(context): + raise NotImplementedError(u'STEP: When the admin chooses the SW version') + + +@when('deploys the privacy dashboard client') +def step_impl(context): + raise NotImplementedError(u'STEP: When deploys the privacy dashboard client') + + +@then('the privacy dashboard is deployed at the chosen location') +def step_impl(context): + raise NotImplementedError(u'STEP: Then the privacy dashboard is deployed at the chosen location') + + +@when('the admin clicks on "manage admin" to update the details') +def step_impl(context): + pass + + +@when('updates the admin user password') +def step_impl(context): + base_url = context.config.userdata.get("base_url") + data = {"currentPassword": "qwerty123", "newPassword": "qwerty1234"} + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/onboard/password/reset" + response = requests.put(url + "/", json=data, verify=False, headers=headers) + context.response = response + + +@then('the admin user password is changed') +def step_impl(context): + assert context.response.status_code == 200 + base_url = context.config.userdata.get("base_url") + data = {"currentPassword": "qwerty1234", "newPassword": "qwerty123"} + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/onboard/password/reset" + response = requests.put(url + "/", json=data, verify=False, headers=headers) + + +@when('the admin clicks on "getting started" to view details') +def step_impl(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/onboard/organisation" + response = requests.get(url + "/", verify=False, headers=headers) + context.response = response + + +@then('the admin can view the organization details') +def step_impl(context): + assert context.response.status_code == 200 + + +@when('the admin updates the organization logo image') +def step_impl(context): + base_url = context.config.userdata.get("base_url") + + headers = { + "Authorization": f"Bearer {context.access_token}" + } + logo_file_path = "assets/Sports.jpg" + + # update logo image + files = { + "orgimage": ("Sports.jpg", open(logo_file_path, "rb")), + } + url = base_url + "/onboard/organisation/logoimage" + response = requests.post(url + "/", files=files, verify=False, headers=headers) + context.response = response + + +@then('the logo image should be updated') +def step_impl(context): + assert context.response.status_code == 200 + +@when('the admin updates the organization cover image') +def step_impl(context): + base_url = context.config.userdata.get("base_url") + + headers = { + "Authorization": f"Bearer {context.access_token}" + } + cover_image_file_path = "assets/Default_Cover_Image.jpg" + + # update cover image + files = { + "orgimage": ("Default_Cover_Image.jpg", open(cover_image_file_path, "rb")), + } + url = base_url + "/onboard/organisation/coverimage" + response = requests.post(url + "/", files=files, verify=False, headers=headers) + context.response = response + + +@then('the cover image should be updated') +def step_impl(context): + assert context.response.status_code == 200 + +@when("the admin updates the organization name, description, location, and policy URL") +def step_impl(context): + base_url = context.config.userdata.get("base_url") + data = { + "organisation": { + "name": "Retail company", + "description": "Retail electronic company", + "sector": "Retail", + "location": "Sweden", + "policyUrl": "http://localhost.com", + } + } + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/onboard/organisation" + response = requests.put(url + "/", json=data, verify=False, headers=headers) + response_json = json.loads(response.content) + context.response = response + +@then("the organization information should be updated") +def step_impl(context): + assert context.response.status_code == 200 + + +@when('the admin adds OIDC configuration to the organization') +def step_impl(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/idp/open-ids" + response = requests.get(url + "/", verify=False, headers=headers) + response_json = json.loads(response.content) + if len(response_json["idps"]) > 0: + idp_id = response_json["idps"][0]["id"] + url = base_url + "/config/idp/open-id/" + idp_id + response = requests.delete(url + "/", verify=False, headers=headers) + data = { + "idp": { + "issuerUrl": "http://keycloak:8080/realms/3pp-application", + "authorisationUrl": "http://keycloak:8080/realms/3pp-application/protocol/openid-connect/auth", + "tokenUrl": "http://keycloak:8080/realms/3pp-application/protocol/openid-connect/token", + "logoutUrl": "http://keycloak:8080/realms/3pp-application/protocol/openid-connect/logout", + "clientId": "3pp", + "clientSecret": "0c7v1bd2M6a85MUDda2hKKY4tuZTxOrW", + "jwksUrl": "http://keycloak:8080/realms/3pp-application/protocol/openid-connect/certs", + "userInfoUrl": "http://keycloak:8080/realms/3pp-application/protocol/openid-connect/userinfo", + "defaultScope": "openid", + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/idp/open-id" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + context.response = response + + +@then('OIDC client is configured for the organization') +def step_impl(context): + response_json = json.loads(context.response.content) + idp_id = response_json["idp"]["id"] + context.config.userdata.idp_id = idp_id + assert context.response.status_code == 200 + + +@when('the admin onboards existing users in configured IDP') +def step_impl(context): + raise NotImplementedError(u'STEP: the admin onboards existing users in configured IDP') + + +@then('existing users are successfully onboarded') +def step_impl(context): + raise NotImplementedError(u'STEP: existing users are successfully onboarded') \ No newline at end of file diff --git a/steps/org_admin_onboard.py b/steps/org_admin_onboard.py new file mode 100644 index 0000000..95da1e0 --- /dev/null +++ b/steps/org_admin_onboard.py @@ -0,0 +1,45 @@ +import json +import requests +from behave import * + +@when('the admin logs into the Admin dashboard with credentials') +def step_impl(context): + username = context.config.userdata.get("username") + password = context.config.userdata.get("password") + base_url = context.config.userdata.get("base_url") + data = { + "username": username, + "password": password, + } + url = base_url + "/onboard/admin/login" + response = requests.post(url + "/", json=data,verify=False) + context.response = response + + +@then('the admin should be able to login to the admin dashboard') +def step_impl(context): + assert context.response.status_code == 200 + response_json = json.loads(context.response.content) + context.config.userdata.access_token = response_json["accessToken"] + + +@when('the admin updates the details in user settings') +def step_impl(context): + base_url = context.config.userdata.get("base_url") + data = { + "organisationAdmin": { + "name": "John", + } + } + headers = {"Authorization": f"Bearer {context.config.userdata.access_token}"} + url = base_url + "/onboard/admin" + response = requests.put(url + "/", json=data, verify=False, headers=headers) + context.response = response + + +@then('the admin details should be updated') +def step_impl(context): + assert context.response.status_code == 200 + response_json = json.loads(context.response.content) + admin_name = response_json["organisationAdmin"]["name"] + assert admin_name == "John" \ No newline at end of file diff --git a/steps/personal_data.py b/steps/personal_data.py deleted file mode 100644 index 56978c2..0000000 --- a/steps/personal_data.py +++ /dev/null @@ -1,201 +0,0 @@ -import json - -import requests -from behave import * - - -@when("the admin lists the data attributes as a table") -def list_data_attributes(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/data-agreements/data-attributes" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - response_json = json.loads(context.response.content) - - -@then("the admin should see a paginated list of data attributes") -def is_list_of_data_attributes(context): - assert context.response.status_code == 200 - - -@when("the admin updates a data attribute name") -def updates_data_attributes(context): - create_data_agreements(context) - data_attribute_id = context.config.userdata.data_attribute_id - data = { - "dataAttribute": { - "name": "Age", - "description": "Age of the customer", - "sensitivity": False, - "category": "", - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/data-agreements/data-attribute/" + data_attribute_id - response = requests.put(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the data attribute name should be updated") -def is_data_attributes_updated(context): - assert context.response.status_code == 200 - response_json = json.loads(context.response.content) - data_attribute_name = response_json["dataAttribute"]["name"] - assert data_attribute_name == "Age" - - -@when("the admin filters data attributes to see all data attributes") -def list_all_data_attributes(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/data-agreements/data-attributes" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - response_json = json.loads(context.response.content) - - -@then("the admin should see a list of all data attributes") -def is_list_of_all_data_attributes(context): - assert context.response.status_code == 200 - - -@when( - "the admin filters data attributes to see data attributes associated with Data Source" -) -def list_da_associated_with_data_source(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/data-agreements/data-attributes" - params = {"methodOfUse": "data_source"} - response = requests.get(url + "/", verify=False, headers=headers,params=params) - context.response = response - - - -@then("the admin should see a list of data attributes associated with Data Source") -def is_da_associated_with_data_source(context): - assert context.response.status_code == 200 - - - -@when( - "the admin filters data attributes to see data attributes associated with Data Using Service" -) -def list_da_associated_with_data_using_service(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/data-agreements/data-attributes" - params = {"methodOfUse": "data_using_service"} - response = requests.get(url + "/", verify=False, headers=headers,params=params) - context.response = response - - -@then( - "the admin should see a list of data attributes associated with Data Using Service" -) -def is_da_associated_with_data_using_service(context): - assert context.response.status_code == 200 - cleanup_data_agreement(context) - - -def create_data_agreements(context): - data = { - "dataAgreement": { - "controllerId": "652657969380f35fa1c30245", - "controllerUrl": "string", - "controllerName": "string", - "policy": { - "name": "Updated Policy", - "url": "https://igrant.io/policy.html", - "jurisdiction": "London,GB", - "industrySector": "Retail", - "dataRetentionPeriodDays": 350, - "geographicRestriction": "Not restricted", - "storageLocation": "London", - "thirdPartyDataSharing": True, - }, - "purpose": "Issue Certificate", - "purposeDescription": "Issue Certificate", - "lawfulBasis": "consent", - "methodOfUse": "data_source", - "dpiaDate": "2023-10-31T14:24", - "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", - "active": True, - "forgettable": False, - "compatibleWithVersionId": False, - "lifecycle": "complete", - "dataAttributes": [ - { - "name": "Age", - "description": "Age of person", - "sensitivity": False, - "category": "", - }, - ], - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/data-agreement" - response = requests.post(url + "/", json=data, verify=False, headers=headers) - context.response = response - response_json = json.loads(context.response.content) - data_source_data_agreement_id = response_json["dataAgreement"]["id"] - context.config.userdata.data_source_data_agreement_id = data_source_data_agreement_id - data = { - "dataAgreement": { - "controllerId": "652657969380f35fa1c30245", - "controllerUrl": "string", - "controllerName": "string", - "policy": { - "name": "Updated Policy", - "url": "https://igrant.io/policy.html", - "jurisdiction": "London,GB", - "industrySector": "Retail", - "dataRetentionPeriodDays": 350, - "geographicRestriction": "Not restricted", - "storageLocation": "London", - "thirdPartyDataSharing": True, - }, - "purpose": "Issue License", - "purposeDescription": "Issue License", - "lawfulBasis": "consent", - "methodOfUse": "data_using_service", - "dpiaDate": "2023-10-31T14:24", - "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", - "active": True, - "forgettable": False, - "compatibleWithVersionId": False, - "lifecycle": "complete", - "dataAttributes": [ - { - "name": "Name", - "description": "Name of person", - "sensitivity": False, - "category": "", - } - ], - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/data-agreement" - response = requests.post(url + "/", json=data, verify=False, headers=headers) - context.response = response - response_json = json.loads(context.response.content) - data_using_service_data_agreement_id = response_json["dataAgreement"]["id"] - data_attribute_id = response_json["dataAgreement"]["dataAttributes"][0]["id"] - context.config.userdata.data_attribute_id = data_attribute_id - context.config.userdata.data_using_service_data_agreement_id = data_using_service_data_agreement_id - -def cleanup_data_agreement(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - data_agreement_id = context.config.userdata.data_source_data_agreement_id - url = base_url + "/config/data-agreement/" + data_agreement_id - response = requests.delete(url + "/", verify=False, headers=headers) - data_agreement_id = context.config.userdata.data_using_service_data_agreement_id - url = base_url + "/config/data-agreement/" + data_agreement_id - response = requests.delete(url + "/", verify=False, headers=headers) \ No newline at end of file diff --git a/steps/privacy_dashboard.py b/steps/privacy_dashboard.py deleted file mode 100644 index 2aa9e19..0000000 --- a/steps/privacy_dashboard.py +++ /dev/null @@ -1,40 +0,0 @@ -import json - -import requests -from behave import * - - -@when("the admin views the deployed privacy dashboard information") -def views_privacy_dashboard(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/privacy-dashboard" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the admin should see the current deployed privacy dashboard version, domain URL, and deployment status") -def sees_privacy_dashboard(context): - response_json = json.loads(context.response.content) - assert context.response.status_code == 200 - status = response_json["statusStr"] - assert status == "Deployed" - - -@given("Consent BB is in single tenant mode") -def step_impl(context): - pass - - -@when("the admin checks the configuration of the privacy dashboard") -def step_impl(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/privacy-dashboard" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then(u'the "Configure" button should be disabled') -def step_impl(context): - pass \ No newline at end of file diff --git a/steps/update_data_agreement.py b/steps/update_data_agreement.py new file mode 100644 index 0000000..186ba16 --- /dev/null +++ b/steps/update_data_agreement.py @@ -0,0 +1,252 @@ +import json +import requests +from behave import * + +@when('the admin clicks on the update icon') +def step_impl(context): + add_data_agreement(context) + +@when('updates data agreement as none mode') +def step_impl(context): + method_of_use = "null" + context.method_of_use = method_of_use + +@when('updates data agreement as DS') +def step_impl(context): + method_of_use = "data_source" + context.method_of_use = method_of_use + + +@when('updates data agreement as DUS') +def step_impl(context): + method_of_use = "data_using_service" + context.method_of_use = method_of_use + +@when('clicks publish') +def step_impl(context): + method_of_use = context.method_of_use + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": "Issue Passports", + "purposeDescription": "Issue Passport", + "lawfulBasis": "consent", + "methodOfUse": method_of_use, + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": True, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "complete", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of customer", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of customer", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + data_agreement_id = context.data_agreement_id + url = base_url + "/config/data-agreement/" + data_agreement_id + response = requests.put(url + "/" , json=data, verify=False, headers=headers) + context.response = response + + +@then('the data agreement should be updated') +def step_impl(context): + assert context.response.status_code == 200 + response_json = json.loads(context.response.content) + data_agreement_id = response_json["dataAgreement"]["id"] + cleanup_data_agreement(context=context,data_agreement_id=data_agreement_id) + + +@when('updates only the fields permitted to change') +def update_data_agreement(context): + purpose_description = "Issue Passport" + purpose = "Issue passport" + context.purpose = purpose + context.purpose_description = purpose_description + +@when('clicks save') +def step_impl(context): + purpose = context.purpose + purpose_description = context.purpose_description + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": purpose, + "purposeDescription": purpose_description, + "lawfulBasis": "consent", + "methodOfUse": "data_source", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": False, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "draft", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of customer", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of customer", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + data_agreement_id = context.data_agreement_id + url = base_url + "/config/data-agreement/" + data_agreement_id + response = requests.put(url + "/", json=data, verify=False, headers=headers) + context.response = response + + +@when('deletes an attribute in data agreement') +def step_impl(context): + purpose_description = "Issue Passport" + purpose = "Issue passport" + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": purpose, + "purposeDescription": purpose_description, + "lawfulBasis": "consent", + "methodOfUse": "data_source", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": True, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "complete", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of customer", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + data_agreement_id = context.data_agreement_id + url = base_url + "/config/data-agreement/" + data_agreement_id + response = requests.put(url + "/", json=data, verify=False, headers=headers) + context.response = response + +def add_data_agreement(context): + data = { + "dataAgreement": { + "controllerId": "652657969380f35fa1c30245", + "controllerUrl": "string", + "controllerName": "string", + "policy": { + "name": "Updated Policy", + "url": "https://igrant.io/policy.html", + "jurisdiction": "London,GB", + "industrySector": "Retail", + "dataRetentionPeriodDays": 350, + "geographicRestriction": "Not restricted", + "storageLocation": "London", + "thirdPartyDataSharing": True, + }, + "purpose": "Issue Certificate", + "purposeDescription": "Issue Certificate", + "lawfulBasis": "consent", + "methodOfUse": "null", + "dpiaDate": "2023-10-31T14:24", + "dpiaSummaryUrl": "https://privacyant.se/dpia_results.html", + "active": True, + "forgettable": False, + "compatibleWithVersionId": False, + "lifecycle": "complete", + "dataAttributes": [ + { + "id": "65410e3bd8e8336d82709824", + "name": "Name", + "description": "Name of person", + "sensitivity": False, + "category": "", + }, + { + "id": "65410e3bd8e8336d82709825", + "name": "Age", + "description": "Age of person", + "sensitivity": False, + "category": "", + }, + ], + } + } + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement" + response = requests.post(url + "/", json=data, verify=False, headers=headers) + response_json = json.loads(response.content) + data_agreement_id = response_json["dataAgreement"]["id"] + context.data_agreement_id = data_agreement_id + +def cleanup_data_agreement(context, data_agreement_id): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement/" + data_agreement_id + response = requests.delete(url + "/", verify=False, headers=headers) \ No newline at end of file diff --git a/steps/user_access.py b/steps/user_access.py deleted file mode 100644 index 1c6229e..0000000 --- a/steps/user_access.py +++ /dev/null @@ -1,123 +0,0 @@ -import json - -import requests -from behave import * - - -@when("the admin creates an identity provider configuration") -def create_idp(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/idp/open-ids" - response = requests.get(url + "/", verify=False, headers=headers) - response_json = json.loads(response.content) - if len(response_json["idps"]) > 0: - idp_id = response_json["idps"][0]["id"] - url = base_url + "/config/idp/open-id/" + idp_id - response = requests.delete(url + "/", verify=False, headers=headers) - data = { - "idp": { - "issuerUrl": "http://keycloak:8080/realms/3pp-application", - "authorisationUrl": "http://keycloak:8080/realms/3pp-application/protocol/openid-connect/auth", - "tokenUrl": "http://keycloak:8080/realms/3pp-application/protocol/openid-connect/token", - "logoutUrl": "http://keycloak:8080/realms/3pp-application/protocol/openid-connect/logout", - "clientId": "3pp", - "clientSecret": "0c7v1bd2M6a85MUDda2hKKY4tuZTxOrW", - "jwksUrl": "http://keycloak:8080/realms/3pp-application/protocol/openid-connect/certs", - "userInfoUrl": "http://keycloak:8080/realms/3pp-application/protocol/openid-connect/userinfo", - "defaultScope": "openid", - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/idp/open-id" - response = requests.post(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the identity provider configuration should be created") -def is_idp_created(context): - response_json = json.loads(context.response.content) - idp_id = response_json["idp"]["id"] - context.config.userdata.idp_id = idp_id - assert context.response.status_code == 200 - - -@when("the admin reads an identity provider configuration") -def read_idp(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - idp_id = context.config.userdata.idp_id - url = base_url + "/config/idp/open-id/" + idp_id - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the admin should be able to view the identity provider configuration") -def view_idp(context): - assert context.response.status_code == 200 - - -@when("the admin updates an identity provider configuration") -def updates_idp(context): - data = { - "idp": { - "issuerUrl": "http://keycloak:9090/realms/3pp-application", - "authorisationUrl": "http://keycloak:9090/realms/3pp-application/protocol/openid-connect/auth", - "tokenUrl": "http://keycloak:9090/realms/3pp-application/protocol/openid-connect/token", - "logoutUrl": "http://keycloak:9090/realms/3pp-application/protocol/openid-connect/logout", - "clientId": "3pp", - "clientSecret": "0c7v1bd2M6a85MUDda2hKKY4tuZTxOrW", - "jwksUrl": "http://keycloak:9090/realms/3pp-application/protocol/openid-connect/certs", - "userInfoUrl": "http://keycloak:9090/realms/3pp-application/protocol/openid-connect/userinfo", - "defaultScope": "openid", - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - idp_id = context.config.userdata.idp_id - url = base_url + "/config/idp/open-id/" + idp_id - response = requests.put(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the identity provider configuration should be updated") -def is_idp_updated(context): - assert context.response.status_code == 200 - - -@when("the admin deletes an identity provider configuration") -def deletes_idp(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - idp_id = context.config.userdata.idp_id - url = base_url + "/config/idp/open-id/" + idp_id - response = requests.delete(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the identity provider configuration should be deleted") -def is_idp_deleted(context): - assert context.response.status_code == 200 - - -@when("the admin bulk onboards individuals using a CSV file upload") -def bulk_onboard_of_individuals(context): - base_url = context.config.userdata.get("base_url") - - headers = { - "Authorization": f"Bearer {context.access_token}" - } - csv_file_path = "assets/bulk_adding_of_individuals.csv" - - files = { - "individuals": ("bulk_adding_of_individuals.csv", open(csv_file_path, "rb")), - } - url = base_url + "/config/individual/upload" - response = requests.post(url + "/", files=files, verify=False, headers=headers) - context.response = response - - -@then("the individuals should be created in the consent BB identity provider") -def is_individuals_created(context): - assert context.response.status_code == 200 diff --git a/steps/user_records.py b/steps/user_records.py deleted file mode 100644 index edf3e8a..0000000 --- a/steps/user_records.py +++ /dev/null @@ -1,76 +0,0 @@ -import json - -import requests -from behave import * - - -@when("the admin views the list of consent records") -def list_consent_records(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/audit/consent-records" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the admin should see a paginated list of consent records") -def is_list_of_consent_records(context): - assert context.response.status_code == 200 - - -@when("the admin clicks the eye icon in the actions column of a consent record") -def step_impl(context): - pass - - -@then("the admin should be able to see the corresponding data agreement") -def step_impl(context): - pass - - -@when("the admin filters consent records to see all consent records") -def view_consent_records(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/audit/consent-records" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the admin should see a list of all consent records") -def is_list_of_consent_records(context): - assert context.response.status_code == 200 - - -@when("the admin filters consent records by the purpose of the data agreement") -def step_impl(context): - pass - - -@then("the admin should see a filtered list of consent records") -def step_impl(context): - pass - - -@when("the admin filters consent records by lawful bases (GDPR)") -def step_impl(context): - pass - - -@when("the admin uses the free search bar to search for consent records by Data Agreement ID") -def step_impl(context): - pass - -@then("the admin should see the relevant consent records") -def step_impl(context): - pass - - -@when("the admin uses the free search bar to search for consent records by Consent Record ID") -def step_impl(context): - pass - - -@when("the admin uses the free search bar to search for consent records by Individual ID") -def step_impl(context): - pass \ No newline at end of file diff --git a/steps/view_data_agreement.py b/steps/view_data_agreement.py new file mode 100644 index 0000000..9c270b9 --- /dev/null +++ b/steps/view_data_agreement.py @@ -0,0 +1,38 @@ +import json +import requests +from behave import * + +@then('the admin should be able to view the data agreement') +def step_impl(context): + assert context.response.status_code == 200 + cleanup_data_agreement(context) + + +@then('the admin should be able to view the draft data agreement') +def step_impl(context): + assert context.response.status_code == 200 + cleanup_data_agreement(context) + + +@when('the admin clicks on the version icon') +def step_impl(context): + raise NotImplementedError(u'STEP: When the admin clicks on the version icon') + + +@when('views the version for the agreements list') +def step_impl(context): + raise NotImplementedError(u'STEP: When views the version for the agreements list') + + +@then('the admin should be able to view all version history for data agreement') +def step_impl(context): + raise NotImplementedError(u'STEP: Then the admin should be able to view all version history for data agreement') + +def cleanup_data_agreement(context): + base_url = context.config.userdata.get("base_url") + headers = {"Authorization": f"Bearer {context.access_token}"} + url = base_url + "/config/data-agreement/" + context.config.userdata.published_data_agreement_id + response = requests.delete(url + "/", verify=False, headers=headers) + + url = base_url + "/config/data-agreement/" + context.config.userdata.draft_data_agreement_id + response = requests.delete(url + "/", verify=False, headers=headers) \ No newline at end of file diff --git a/steps/view_logs.py b/steps/view_logs.py deleted file mode 100644 index 420efb0..0000000 --- a/steps/view_logs.py +++ /dev/null @@ -1,107 +0,0 @@ -import json - -import requests -from behave import * - - -@when("the admin views the list of admin logs") -def list_admin_logs(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/audit/admin/logs" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the admin should see a list of logs") -def views_admin_logs(context): - assert context.response.status_code == 200 - - -@when("the admin filters the logs to see all logs") -def list_all_logs(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/audit/admin/logs" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the admin should see all logs") -def is_list_of_all_logs(context): - assert context.response.status_code == 200 - - -@when("the admin filters the logs to see security logs") -def views_security_logs(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - params = {"logType": 1} - url = base_url + "/audit/admin/logs" - response = requests.get(url + "/", verify=False, headers=headers, params=params) - context.response = response - - -@then("the admin should see security-related logs") -def is_security_logs(context): - assert context.response.status_code == 200 - - -@when("the admin filters the logs to see API call logs") -def views_api_call_logs(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - params = {"logType": 2} - url = base_url + "/audit/admin/logs" - response = requests.get(url + "/", verify=False, headers=headers, params=params) - context.response = response - - -@then("the admin should see logs related to API calls") -def is_api_call_logs(context): - assert context.response.status_code == 200 - - -@when("the admin filters the logs to see organisation logs") -def views_organisation_logs(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - params = {"logType": 3} - url = base_url + "/audit/admin/logs" - response = requests.get(url + "/", verify=False, headers=headers, params=params) - context.response = response - - -@then("the admin should see logs related to organisation activities") -def is_organisation_logs(context): - assert context.response.status_code == 200 - - -@when("the admin filters the logs to see webhook logs") -def views_webhook_logs(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - params = {"logType": 5} - url = base_url + "/audit/admin/logs" - response = requests.get(url + "/", verify=False, headers=headers, params=params) - context.response = response - - -@then("the admin should see logs related to webhook activities") -def is_webhook_logs(context): - assert context.response.status_code == 200 - - -@when("the admin filters the logs to see end user logs") -def views_end_user_logs(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - params = {"logType": 4} - url = base_url + "/audit/admin/logs" - response = requests.get(url + "/", verify=False, headers=headers, params=params) - context.response = response - - -@then("the admin should see logs related to end user activities") -def is_end_user_logs(context): - assert context.response.status_code == 200 \ No newline at end of file diff --git a/steps/webhook.py b/steps/webhook.py deleted file mode 100644 index cd7d030..0000000 --- a/steps/webhook.py +++ /dev/null @@ -1,120 +0,0 @@ -import json - -import requests -from behave import * - - -@when("the admin views the list of webhook endpoints") -def list_of_webhook_endpoints(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/webhooks" - response = requests.get(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the admin should see a list of webhook endpoints") -def is_list_of_webhook_endpoints(context): - assert context.response.status_code == 200 - - -@when("the admin creates a new webhook endpoint with specified details") -def creates_webhook_endpoint(context): - data = { - "webhook": { - "payloadUrl": "https://webhook.site/1cdcdb5c-58b8-4ecd-9cae-e55b00fa096d", - "contentType": "application/json", - "subscribedEvents": ["consent.allowed"], - "disabled": False, - "secretKey": "key", - "skipSslVerification": False, - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - url = base_url + "/config/webhook" - response = requests.post(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the webhook endpoint should be created") -def is_webhook_endpoint_created(context): - assert context.response.status_code == 200 - response_json = json.loads(context.response.content) - webhook_id = response_json["webhook"]["id"] - context.config.userdata.webhook_id = webhook_id - - -@when("the admin updates an existing webhook endpoint with specified details") -def update_webhook_endpoint(context): - data = { - "webhook": { - "payloadUrl": "https://webhook.site/1cdcdb5c-58b8-4ecd-9cae-e55b00fa096d", - "contentType": "application/json", - "subscribedEvents": ["consent.disallowed"], - "disabled": False, - "secretKey": "key", - "skipSslVerification": False, - } - } - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - webhook_id = context.config.userdata.webhook_id - url = base_url + "/config/webhook/" + webhook_id - response = requests.put(url + "/", json=data, verify=False, headers=headers) - context.response = response - - -@then("the webhook endpoint should be updated") -def is_webhook_endpoint_updated(context): - assert context.response.status_code == 200 - - -@when("the admin deletes an existing webhook endpoint") -def delete_webhook_endpoint(context): - base_url = context.config.userdata.get("base_url") - headers = {"Authorization": f"Bearer {context.access_token}"} - webhook_id = context.config.userdata.webhook_id - url = base_url + "/config/webhook/" + webhook_id - response = requests.delete(url + "/", verify=False, headers=headers) - context.response = response - - -@then("the webhook endpoint should be deleted") -def is_webhook_endpoint_deleted(context): - assert context.response.status_code == 200 - - -@given("the admin selects a webhook endpoint") -def step_impl(context): - pass - - -@when("the admin views the list of recent deliveries made to the selected webhook") -def step_impl(context): - pass - - -@then("the admin should see the delivery details") -def step_impl(context): - pass - - -@when('the admin marks a webhook endpoint as "Up"') -def step_impl(context): - pass - - -@then('the status of the webhook endpoint should be set to "Up"') -def step_impl(context): - pass - - -@when('the admin marks a webhook endpoint as "Down"') -def step_impl(context): - pass - - -@then('the status of the webhook endpoint should be set to "Down"') -def step_impl(context): - pass