From 0e7700489dc072da08f3612861e328e23be8a080 Mon Sep 17 00:00:00 2001 From: George J Padayatti Date: Wed, 7 Sep 2022 10:24:15 +0530 Subject: [PATCH] Add DDA CRUD routes Signed-off-by: George J Padayatti --- .flake8 | 6 + dexa_protocol/v1_0/routes/dda_routes.py | 168 +++++++++++++++--- dexa_protocol/v1_0/routes/maps/route_maps.py | 27 ++- dexa_protocol/v1_0/routes/openapi/__init__.py | 0 dexa_protocol/v1_0/routes/openapi/schemas.py | 105 +++++++++++ 5 files changed, 283 insertions(+), 23 deletions(-) create mode 100644 .flake8 create mode 100644 dexa_protocol/v1_0/routes/openapi/__init__.py create mode 100644 dexa_protocol/v1_0/routes/openapi/schemas.py diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..02db330 --- /dev/null +++ b/.flake8 @@ -0,0 +1,6 @@ +[flake8] +################### LINTING ################################ + +########## Options ########## +# Set the maximum length that any line (with some exceptions) may be. +max-line-length = 100 \ No newline at end of file diff --git a/dexa_protocol/v1_0/routes/dda_routes.py b/dexa_protocol/v1_0/routes/dda_routes.py index 034fdb1..3438333 100644 --- a/dexa_protocol/v1_0/routes/dda_routes.py +++ b/dexa_protocol/v1_0/routes/dda_routes.py @@ -1,30 +1,60 @@ from aiohttp import web -from aiohttp_apispec import docs, request_schema -from marshmallow import EXCLUDE - -from dexa_sdk.agreements.dda.v1_0.models import ( - DataDisclosureAgreementSchema, +from aiohttp_apispec import ( + docs, + request_schema, + querystring_schema, + match_info_schema ) +from dexa_sdk.managers.dexa_manager import DexaManager +from dexa_sdk.utils import clean_and_get_field_from_dict +from mydata_did.v1_0.utils.util import str_to_bool from .maps.tag_maps import TAGS_DDA_LABEL +from .openapi.schemas import ( + CreateDataDisclosureAgreementTemplateRequestSchema, + CreateDDATemplateRequestQueryStringSchema, + QueryDDATemplateQueryStringSchema, + UpdateDDATemplateQueryStringSchema, + DDATemplateMatchInfoSchema, + UpdateDDATemplateRequestSchema +) + + +@docs(tags=[TAGS_DDA_LABEL], summary="Create a data disclosure agreement template.") +@querystring_schema(CreateDDATemplateRequestQueryStringSchema()) +@request_schema(CreateDataDisclosureAgreementTemplateRequestSchema()) +async def create_data_disclosure_agreement_handler(request: web.BaseRequest): + """ + Request handle to create a data disclosure agreement template. + Args: + request: aiohttp request object -class WrappedDataDisclosureAgreementSchema(DataDisclosureAgreementSchema): - class Meta: - """OpenAPISchema metadata.""" + """ + context = request.app["request_context"] - # Hack to use child classes of BaseModelSchema - # as OpenAPI request schema - model_class = dict + # Fetch request body + dda = await request.json() - # Exclude unknown fields - unknown = EXCLUDE + # Fetch query string params + publish_flag = str_to_bool(clean_and_get_field_from_dict(request.query, "publish_flag")) + # Initialise DEXA manager + manager = DexaManager(context) -@docs(tags=[TAGS_DDA_LABEL], summary="Create a Data Disclosure Agreement") -@request_schema(WrappedDataDisclosureAgreementSchema()) -async def create_data_disclosure_agreement_handler(request: web.BaseRequest): + # Create and store DDA in wallet. + record = await manager.create_and_store_dda_template_in_wallet( + dda, + publish_flag=publish_flag + ) + + return web.json_response(record.serialize()) + + +@docs(tags=[TAGS_DDA_LABEL], summary="Query data disclosure agreement templates.") +@querystring_schema(QueryDDATemplateQueryStringSchema()) +async def query_dda_handler(request: web.BaseRequest): """ - Request handle to create a data disclosure agreement. + Request handle to query data disclosure agreement templates. Args: request: aiohttp request object @@ -32,9 +62,105 @@ async def create_data_disclosure_agreement_handler(request: web.BaseRequest): """ context = request.app["request_context"] - # Fetch request body - data_agreement = await request.json() + # Fetch query string params + template_id = clean_and_get_field_from_dict(request.query, "template_id") + template_version = clean_and_get_field_from_dict(request.query, "template_version") + industry_sector = clean_and_get_field_from_dict(request.query, "industry_sector") + publish_flag = clean_and_get_field_from_dict(request.query, "publish_flag") + delete_flag = clean_and_get_field_from_dict(request.query, "delete_flag") + latest_version_flag = clean_and_get_field_from_dict(request.query, "latest_version_flag") + page = clean_and_get_field_from_dict(request.query, "page") + page = int(page) if page is not None else page + page_size = clean_and_get_field_from_dict(request.query, "page_size") + page_size = int(page_size) if page_size is not None else page_size + + # Initialise DEXA manager + manager = DexaManager(context) + + # Create and store DDA in wallet. + paginationResult = await manager.query_dda_templates_in_wallet( + template_id=template_id, + template_version=template_version, + industry_sector=industry_sector, + publish_flag=publish_flag, + delete_flag=delete_flag, + latest_version_flag=latest_version_flag, + page=page if page else 1, + page_size=page_size if page_size else 10 + ) + + return web.json_response(paginationResult._asdict()) + + +@docs(tags=[TAGS_DDA_LABEL], summary="Update DDA template.") +@match_info_schema(DDATemplateMatchInfoSchema()) +@querystring_schema(UpdateDDATemplateQueryStringSchema()) +@request_schema(UpdateDDATemplateRequestSchema()) +async def update_dda_template_handler(request: web.BaseRequest): + """Update DDA template.""" + + # Request context + context = request.app["request_context"] + + # Path params + template_id = request.match_info["template_id"] + + # Request body + dda = await request.json() + + # Query string params + publish_flag = clean_and_get_field_from_dict(request.query, "publish_flag") + publish_flag = str_to_bool(publish_flag) + + # Initialise MyData DID Manager + manager = DexaManager(context=context) + + record = await manager.update_dda_template_in_wallet( + template_id=template_id, + dda=dda, + publish_flag=publish_flag + ) + + return web.json_response(record.serialize(), status=200) + + +@docs(tags=[TAGS_DDA_LABEL], summary="Delete DDA template.") +@match_info_schema(DDATemplateMatchInfoSchema()) +async def delete_dda_template_handler(request: web.BaseRequest): + """Delete DDA template in wallet""" + + # Request context + context = request.app["request_context"] - return web.json_response( - {"purposeDescription": data_agreement["purposeDescription"]} + # Path params + template_id = request.match_info["template_id"] + + # Initialise MyData DID Manager + manager = DexaManager(context=context) + + await manager.delete_dda_template_in_wallet( + template_id + ) + + return web.json_response({}, status=204) + + +@docs(tags=[TAGS_DDA_LABEL], summary="Publish DDA template.") +@match_info_schema(DDATemplateMatchInfoSchema()) +async def publish_dda_template_handler(request: web.BaseRequest): + """Publish DDA template in wallet""" + + # Request context + context = request.app["request_context"] + + # Path params + template_id = request.match_info["template_id"] + + # Initialise MyData DID Manager + manager = DexaManager(context=context) + + await manager.publish_dda_template_wallet( + template_id ) + + return web.json_response({}, status=204) diff --git a/dexa_protocol/v1_0/routes/maps/route_maps.py b/dexa_protocol/v1_0/routes/maps/route_maps.py index 0595f8e..fda54bd 100644 --- a/dexa_protocol/v1_0/routes/maps/route_maps.py +++ b/dexa_protocol/v1_0/routes/maps/route_maps.py @@ -1,10 +1,33 @@ from aiohttp import web -from ..dda_routes import create_data_disclosure_agreement_handler +from ..dda_routes import ( + create_data_disclosure_agreement_handler, + query_dda_handler, + update_dda_template_handler, + delete_dda_template_handler, + publish_dda_template_handler +) # Data Disclosure Agreement routes ROUTES_DDA = [ web.post( "/v1/data-disclosure-agreements", create_data_disclosure_agreement_handler, - ) + ), + web.get( + "/v1/data-disclosure-agreements", + query_dda_handler, + allow_head=False + ), + web.post( + "/v1/data-disclosure-agreements/{template_id}", + update_dda_template_handler + ), + web.delete( + "/v1/data-disclosure-agreements/{template_id}", + delete_dda_template_handler + ), + web.post( + "/v1/data-disclosure-agreements/{template_id}/publish", + publish_dda_template_handler + ), ] diff --git a/dexa_protocol/v1_0/routes/openapi/__init__.py b/dexa_protocol/v1_0/routes/openapi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dexa_protocol/v1_0/routes/openapi/schemas.py b/dexa_protocol/v1_0/routes/openapi/schemas.py new file mode 100644 index 0000000..73565a2 --- /dev/null +++ b/dexa_protocol/v1_0/routes/openapi/schemas.py @@ -0,0 +1,105 @@ +from aries_cloudagent.messaging.models.openapi import OpenAPISchema +from marshmallow import fields + + +class PersonalDataOpenAPISchema(OpenAPISchema): + """Personal data open api schema""" + + attribute_name = fields.Str(data_key="attributeName") + attribute_sensitive = fields.Str(data_key="attributeSensitive", required=False) + attribute_category = fields.Str(data_key="attributeCategory", required=False) + attribute_description = fields.Str(data_key="attributeDescription") + + +class DataSharingRestrictionsOpenAPISchema(OpenAPISchema): + """Data sharing restrictions open api schema""" + + policy_url = fields.Str(data_key="policyUrl") + jurisdiction = fields.Str(data_key="jurisdiction") + industry_sector = fields.Str(data_key="industrySector") + data_retention_period = fields.Int(data_key="dataRetentionPeriod") + geographic_restriction = fields.Str(data_key="geographicRestriction") + storage_location = fields.Str(data_key="storageLocation") + + +class DataControllerOpenAPISchema(OpenAPISchema): + """Data controller open api schema""" + + name = fields.Str(data_key="name") + legal_id = fields.Str(data_key="legalId") + url = fields.Str(data_key="url") + industry_sector = fields.Str(data_key="industrySector") + + +class CreateDataDisclosureAgreementTemplateRequestSchema(OpenAPISchema): + """Create data disclosure agreement template request schema""" + + language = fields.Str(data_key="language") + data_controller = fields.Nested( + DataControllerOpenAPISchema, + data_key="dataController" + ) + agreement_period = fields.Int(data_key="agreementPeriod") + data_sharing_restrictions = fields.Nested( + DataSharingRestrictionsOpenAPISchema, + data_key="dataSharingRestrictions" + ) + purpose = fields.Str(data_key="purpose") + purpose_description = fields.Str(data_key="purposeDescription") + lawful_basis = fields.Str(data_key="lawfulBasis") + personal_data = fields.List(fields.Nested(PersonalDataOpenAPISchema), data_key="personalData") + code_of_conduct = fields.Str(data_key="codeOfConduct") + + +class CreateDDATemplateRequestQueryStringSchema(OpenAPISchema): + """Create dda template query string schema""" + + publish_flag = fields.Boolean(required=True) + + +class QueryDDATemplateQueryStringSchema(OpenAPISchema): + """Query dda template query string schema.""" + + template_id = fields.Str(required=False) + template_version = fields.Str(required=False) + industry_sector = fields.Str(required=False) + publish_flag = fields.Bool(required=False) + delete_flag = fields.Bool(required=False) + latest_version_flag = fields.Bool(required=False) + page = fields.Int(required=False) + page_size = fields.Int(required=False) + + +class UpdateDDATemplateQueryStringSchema(OpenAPISchema): + """Update DDA template query string.""" + + publish_flag = fields.Boolean(required=True) + + +class UpdateDDATemplateRequestSchema(OpenAPISchema): + """Create DDA template request schema""" + + language = fields.Str(data_key="language") + data_controller = fields.Nested( + DataControllerOpenAPISchema, + data_key="dataController" + ) + agreement_period = fields.Int(data_key="agreementPeriod") + data_sharing_restrictions = fields.Nested( + DataSharingRestrictionsOpenAPISchema, + data_key="dataSharingRestrictions" + ) + purpose = fields.Str(data_key="purpose") + purpose_description = fields.Str(data_key="purposeDescription") + lawful_basis = fields.Str(data_key="lawfulBasis") + personal_data = fields.List( + fields.Nested(PersonalDataOpenAPISchema), + data_key="personalData" + ) + code_of_conduct = fields.Str(data_key="codeOfConduct") + + +class DDATemplateMatchInfoSchema(OpenAPISchema): + """DDA template match info schema""" + + template_id = fields.Str()