diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..231d650 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.pyc +**/venv +**/.env +**/.idea +**/__pycache__ +build +dist +*.egg-info +**/.vscode +**/*.mo +locale/__init__.py diff --git a/govstack_test_harness_api/__pycache__/__init__.cpython-38.pyc b/govstack_test_harness_api/__pycache__/__init__.cpython-38.pyc deleted file mode 100644 index c46d404..0000000 Binary files a/govstack_test_harness_api/__pycache__/__init__.cpython-38.pyc and /dev/null differ diff --git a/govstack_test_harness_api/__pycache__/admin.cpython-38.pyc b/govstack_test_harness_api/__pycache__/admin.cpython-38.pyc deleted file mode 100644 index eddaa4a..0000000 Binary files a/govstack_test_harness_api/__pycache__/admin.cpython-38.pyc and /dev/null differ diff --git a/govstack_test_harness_api/__pycache__/apps.cpython-38.pyc b/govstack_test_harness_api/__pycache__/apps.cpython-38.pyc deleted file mode 100644 index c7ddc07..0000000 Binary files a/govstack_test_harness_api/__pycache__/apps.cpython-38.pyc and /dev/null differ diff --git a/govstack_test_harness_api/__pycache__/models.cpython-38.pyc b/govstack_test_harness_api/__pycache__/models.cpython-38.pyc deleted file mode 100644 index 9fbfeb4..0000000 Binary files a/govstack_test_harness_api/__pycache__/models.cpython-38.pyc and /dev/null differ diff --git a/govstack_test_harness_api/apps.py b/govstack_test_harness_api/apps.py index cd58dc4..ecb7636 100644 --- a/govstack_test_harness_api/apps.py +++ b/govstack_test_harness_api/apps.py @@ -4,3 +4,21 @@ class TestHarnessApiConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'govstack_test_harness_api' + + IM_CLIENT = 'eGovStack/GOV/90000009/digitalregistries' + + digital_registry = { + "birth_registry": { + "1": { + 'ID': 'ID' + } + }, + "registryname": { + "111": { + 'ID': 'chfId', + 'FirstName': 'otherNames', + 'LastName': 'lastName', + 'BirthCertificateID': 'json_ext' + } + } + } \ No newline at end of file diff --git a/govstack_test_harness_api/building_blocks/__init__.py b/govstack_test_harness_api/building_blocks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/__init__.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/controllers/__init__.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/controllers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/controllers/record_exists_controller.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/controllers/record_exists_controller.py new file mode 100644 index 0000000..30c1710 --- /dev/null +++ b/govstack_test_harness_api/building_blocks/bb-digital-registries/controllers/record_exists_controller.py @@ -0,0 +1,12 @@ +from ..services.record_exists_service import RecordExistsService +from ..services.services import get_query_content_values, login_with_env_variables + + +def check_if_record_exists(data, jwt, context): + content_values = get_query_content_values(data['query']['content'], data['registryname'], data['versionnumber']) + service = RecordExistsService( + jwt, + context=context, + validated_data=data, + ) + return service.execute() \ No newline at end of file diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/gql/__init__.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/gql/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/gql/gql_queries.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/gql/gql_queries.py new file mode 100644 index 0000000..c6c34e7 --- /dev/null +++ b/govstack_test_harness_api/building_blocks/bb-digital-registries/gql/gql_queries.py @@ -0,0 +1,96 @@ +def get_record_exists_query(registry_name, version_number, uuid, field): + query = f""" + {{ + recordExists(registryName: "{registry_name}", versionNumber: "{version_number}", uuid: "{uuid}", field: "{field}") {{ + edges {{ + node {{ + id + {field} + }} + }} + }} + }} + """ + return query + + +def get_update_registry_query(uuid="", chf_id="", update_fields="") -> str: + query = f''' + mutation {{ + updateInsuree( + input: {{ + clientMutationId: "552f8e55-ed5a-4e1e-a159-ea8f8cec0560" + clientMutationLabel: "Update insuree" + uuid: "{uuid}" + chfId: "{chf_id}" + {update_fields} + genderId: "F" + head: true + dob: "1974-06-11" + cardIssued:false + familyId: 1 + relationshipId: 4 + }} + ) {{ + clientMutationId + internalId + }} + }} + ''' + return query + + +def get_insurees_query(variable_values: str = "", fetched_fields: str = "") -> str: + return f''' + query GetInsurees {{ + insurees({variable_values}) {{ + edges{{ + node{{ + {fetched_fields} + }} + }} + }} + }} + ''' + + +def create_insurees_query(variables: dict) -> str: + return f''' + mutation {{ + createInsuree( + input: {{ + clientMutationLabel: "{variables['clientMutationLabel']}" + chfId: "{variables['chfId']}" + lastName: "{variables['lastName']}" + otherNames: "{variables['otherNames']}" + genderId: "{variables['genderId']}" + dob: "{variables['dob']}" + head: {str(variables['head']).lower()} + cardIssued: {str(variables['cardIssued']).lower()} + jsonExt: "{variables['jsonExt']}" + familyId: 1 + }} + ) {{ + clientMutationId + internalId + }} + }} + ''' + + +def delete_insuree_query(uuid): + return f'''mutation + {{ + deleteInsurees( + input: {{ + clientMutationId: "c164412c-45a6-4f3f-8a2b-4290739751e2" + clientMutationLabel: "Delete insuree" + + uuid: "{uuid}", uuids: ["{uuid}"] + }} + ) {{ + clientMutationId + internalId + }} + }} + ''' diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/gql/graphene_client.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/gql/graphene_client.py new file mode 100644 index 0000000..7ae2e59 --- /dev/null +++ b/govstack_test_harness_api/building_blocks/bb-digital-registries/gql/graphene_client.py @@ -0,0 +1,46 @@ +import graphene +from graphene.test import Client +# from gql import gql, Client +# from gql.transport.requests import RequestsHTTPTransport +from insuree.schema import Query, Mutation +from graphene import Schema + + +class GrapheneClient: + def __init__(self): + self._client = Client(Schema(query=Query, mutation=Mutation)) + + def execute_query(self, query, context, variables=None): + print("context: ", context) + + if variables is None: + variables = {} + print("variables: ", variables) + return self._client.execute(query, context=context, variables=variables) + + def execute_mutation(self, mutation, variables=None): + if variables is None: + variables = {} + + return self._client.execute(mutation, variables=variables) + + +# class GrapheneClient: +# def __init__(self, url, headers=None): +# if headers is None: +# headers = {} +# print(url) +# self._transport = RequestsHTTPTransport(url=url, headers=headers, use_json=True) +# self._client = Client(transport=self._transport, fetch_schema_from_transport=True) +# +# def execute_query(self, query, variables=None): +# if variables is None: +# variables = {} +# +# return self._client.execute(gql(query), variable_values=variables) +# +# def execute_mutation(self, mutation, variables=None): +# if variables is None: +# variables = {} +# +# return self._client.execute(gql(mutation), variable_values=variables) diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/serializers/__init__.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/serializers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/serializers/record_exists_serializer.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/serializers/record_exists_serializer.py new file mode 100644 index 0000000..44ef31a --- /dev/null +++ b/govstack_test_harness_api/building_blocks/bb-digital-registries/serializers/record_exists_serializer.py @@ -0,0 +1,7 @@ +from rest_framework import serializers + + +class RecordExistsSerializer(serializers.Serializer): + query = serializers.JSONField() + registryname = serializers.CharField(max_length=200) + versionnumber = serializers.IntegerField() diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/services/__init__.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/services/record_exists_service.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/services/record_exists_service.py new file mode 100644 index 0000000..692535e --- /dev/null +++ b/govstack_test_harness_api/building_blocks/bb-digital-registries/services/record_exists_service.py @@ -0,0 +1,30 @@ +# W pliku record_exists_service.py +from graphene import Schema + +from ..gql.graphene_client import GrapheneClient +from ..gql.gql_queries import get_record_exists_query, get_insurees_query +from .services import get_client, get_values_for_insurees, get_search_insurees_arguments +from insuree.schema import Query, Mutation +from django.conf import global_settings + + +class RecordExistsService: + def __init__(self, jwt_token, context, validated_data): + self.context = context + self.validated_data = validated_data + # self.headers = {"Authorization": "Bearer " + jwt_token} + self.client = GrapheneClient() + + def execute(self): + variables = get_values_for_insurees( + self.validated_data['query']['content'], + self.validated_data["registryname"], + self.validated_data["versionnumber"] + ) + variable_values = get_search_insurees_arguments( + self.validated_data['query']['content'], + self.validated_data["registryname"], + self.validated_data["versionnumber"] + ) + query = get_insurees_query(variable_values, "lastName") + return self.client.execute_query(query, self.context, variables) diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/services/services.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/services/services.py new file mode 100644 index 0000000..34fb990 --- /dev/null +++ b/govstack_test_harness_api/building_blocks/bb-digital-registries/services/services.py @@ -0,0 +1,96 @@ +import os +from types import SimpleNamespace +from django.contrib.auth.models import AnonymousUser +from graphene import Schema +from graphene.test import Client +from unittest import mock +from core.schema import Query as CoreQuery, Mutation as CoreMutation +from django.apps import apps + +app_config = apps.get_app_config('govstack_test_harness_api') + + +def get_client(schema, query, mutation): + return Client(schema=schema(query=query, mutation=mutation)) + + +def create_base_context(): + user = mock.Mock(is_anonymous=False) + user.has_perm = mock.MagicMock(return_value=False) + return SimpleNamespace(user=user) + + +def get_context(request): + if request.user.is_authenticated: + context = create_base_context() + context.user = request.user + else: + context = SimpleNamespace(user=request.user) + return context + + +def get_query_content_values(query_content: dict, registry_name: str, version: str) -> dict: + content_values = {} + if not query_content: + return {} + + json_mapping = app_config.digital_registry.get(registry_name, {}).get(version, {}) + for input_key, output_key in json_mapping.items(): + content_values[output_key] = query_content.get(input_key, "") + return content_values + + +def get_values_for_insurees(content_values: dict, registry_name: str, version: str) -> dict: + json_mapping = app_config.digital_registry.get(registry_name, {}).get(version, {}) + mapped_values = {json_mapping[key]: value for key, value in content_values.items() if key in json_mapping} + return { + 'clientMutationLabel': f"Create insuree - {mapped_values.get('chfId', '')}", + 'chfId': f"{mapped_values.get('chfId', '')}", + 'lastName': f"{mapped_values.get('lastName', '')}", + 'otherNames': f"{mapped_values.get('otherNames', '')}", + 'genderId': mapped_values.get('Gender', 'M'), + 'dob': mapped_values.get('BirthDate', '2000-06-20'), + 'head': mapped_values.get('Head', True), + 'cardIssued': False, + 'jsonExt': '{}', + } + + +def get_search_insurees_arguments(query_content: dict, registry_name: str, version: str) -> str: + insurees_arguments = "" + json_mapping = app_config.digital_registry.get(registry_name, {}).get(str(version), {}) + for key, value in json_mapping.items(): + if key in query_content: + insurees_arguments += f'{value}: "{query_content[key]}",' + + if insurees_arguments.endswith(','): + return insurees_arguments[:-1] + return insurees_arguments + + +def get_update_fields(write_values) -> str: + field_mapping = { + "LastName": "lastName", + "FirstName": "otherNames" + } + return "".join(f'{field_mapping[key]}: "{value}" ' + for key, value in write_values.items() + if value and key in field_mapping) + + +def login_with_env_variables(request): + client = get_client(Schema, CoreQuery, CoreMutation) + username = os.getenv('login_openIMIS') + password = os.getenv('password_openIMIS') + + mutation = f''' + mutation {{ + tokenAuth(username: "{username}", password: "{password}") {{ + token + refreshExpiresIn + }} + }} + ''' + context = get_context(request) + client.execute(mutation, context=context) + return context diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/swaggers_schema.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/swaggers_schema.py new file mode 100644 index 0000000..7cabcf7 --- /dev/null +++ b/govstack_test_harness_api/building_blocks/bb-digital-registries/swaggers_schema.py @@ -0,0 +1,256 @@ +# swagger_schemas.py +from drf_yasg import openapi + +# definition of requests and responses + +create_request_body = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'write': openapi.Schema(type=openapi.TYPE_OBJECT, properties={ + 'content': openapi.Schema(type=openapi.TYPE_OBJECT, description='Content to be saved') + }) + }, + required=['write'] +) + +create_response_body = openapi.Response('response description', openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'write': openapi.Schema(type=openapi.TYPE_OBJECT, properties={ + 'content': openapi.Schema(type=openapi.TYPE_OBJECT, description='Content to be saved') + }) + }, + required=['write'] +)) + +read_value_response_body = openapi.Response('response description', openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'value': openapi.Schema(type=openapi.TYPE_STRING, description='Value of the specified field') + }, + required=['value'] +)) + +content_schema = openapi.Schema(type=openapi.TYPE_OBJECT, ref='#/components/schemas/Example') + +query_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'query': openapi.Schema(type=openapi.TYPE_OBJECT, properties={'content': content_schema}, required=['content']), + }, + required=['query'] +) + +responses_schema = { + '200': openapi.Response( + description='', + schema=openapi.Schema(type=openapi.TYPE_OBJECT, properties={'content': content_schema}), + ), + '404': openapi.Response( + description='Record not found', + schema=openapi.Schema(type=openapi.TYPE_OBJECT, properties={'detail': openapi.Schema(type=openapi.TYPE_STRING, enum=['no record found'])}), + ), +} + +read_record_schema = { + 'method': 'post', + 'operation_description': 'Searches and returns one record.', + 'request_body': query_schema, + 'responses': responses_schema, + 'security': [{'apiKey': []}], +} + +info_mediator_client = openapi.Parameter( + 'Information-Mediator-Client', + openapi.IN_HEADER, + description="Format is: INSTANCE/CLASS/MEMBER/SUBSYSTEM", + type=openapi.TYPE_STRING, + required=True +) + +exists_request_body = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'query': openapi.Schema(type=openapi.TYPE_OBJECT, properties={ + 'content': openapi.Schema(type=openapi.TYPE_OBJECT, description='Search content') + }), + }, + required=['query'] +) + +exists_response_body = openapi.Response('response description', openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'answer': openapi.Schema(type=openapi.TYPE_OBJECT, properties={ + 'status': openapi.Schema(type=openapi.TYPE_BOOLEAN, description='Example object found in database'), + 'message': openapi.Schema(type=openapi.TYPE_STRING, description='More information about the object') + }) + }, + required=['answer'] +)) + +delete_response = openapi.Response(description='No content') + +create_or_update_response = { + 200: openapi.Response( + 'Successful update or creation of record', + openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'content': openapi.Schema( + type=openapi.TYPE_OBJECT, + description='Updated or newly created object', + ), + }, + required=['content'], + ), + ), + 400: 'Bad request', + 500: 'Internal server error', +} + +content_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={}, + description='Example object' +) + +query_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={'content': content_schema}, + required=['content'], + description='Search object that needs to be updated' +) + +write_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={'content': content_schema}, + required=['content'], + description='Update found object with the following data' +) + +request_body_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'query': query_schema, + 'write': write_schema, + }, + required=['write'], + description='' +) + +update_record_schema = { + 'method': 'put', + 'operation_description': "Updates one existing record in the registry database.", + 'request_body': request_body_schema, + 'responses': {200: openapi.Response(description='')} +} + +# Parameters + +search_parameter = openapi.Parameter( + name='search', + in_=openapi.IN_QUERY, + description='Search word', + type=openapi.TYPE_STRING, +) + +filter_parameter = openapi.Parameter( + name='filter', + in_=openapi.IN_QUERY, + description='Result filter', + type=openapi.TYPE_STRING, +) + +ordering_parameter = openapi.Parameter( + name='ordering', + in_=openapi.IN_QUERY, + description='Sort type', + type=openapi.TYPE_STRING, +) + +page_parameter = openapi.Parameter( + name='page', + in_=openapi.IN_QUERY, + description='Page number', + type=openapi.TYPE_INTEGER, +) + +page_size_parameter = openapi.Parameter( + name='page_size', + in_=openapi.IN_QUERY, + description='Number of results per page', + type=openapi.TYPE_INTEGER, +) + +query_fieldname_parameter = openapi.Parameter( + name='query.', + in_=openapi.IN_QUERY, + description='Query based on field name', + type=openapi.TYPE_STRING, +) + +get_multiple_records_from_registry_parameters = [ + search_parameter, + filter_parameter, + ordering_parameter, + page_parameter, + page_size_parameter, + query_fieldname_parameter, +] + +registryname_parameter = openapi.Parameter( + name='registryname', + in_=openapi.IN_PATH, + description='Registry name', + type=openapi.TYPE_STRING, +) + +versionnumber_parameter = openapi.Parameter( + name='versionnumber', + in_=openapi.IN_PATH, + description='Version number', + type=openapi.TYPE_STRING, +) + +uuid_parameter = openapi.Parameter( + name='uuid', + in_=openapi.IN_PATH, + description='Primary key', + type=openapi.TYPE_STRING, +) + +id_parameter = openapi.Parameter( + name='ID', + in_=openapi.IN_PATH, + description='Primary key', + type=openapi.TYPE_STRING, +) + +field_parameter = openapi.Parameter( + name='field', + in_=openapi.IN_PATH, + description='Field name', + type=openapi.TYPE_STRING, +) + +ext_parameter = openapi.Parameter( + name='ext', + in_=openapi.IN_PATH, + description='Data extension', + type=openapi.TYPE_STRING, +) + +read_value_parameters = [ + registryname_parameter, + versionnumber_parameter, + uuid_parameter, + field_parameter, + ext_parameter, +] + +delete_parameters = [ + registryname_parameter, + versionnumber_parameter, + id_parameter +] \ No newline at end of file diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/urls.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/urls.py new file mode 100644 index 0000000..9823480 --- /dev/null +++ b/govstack_test_harness_api/building_blocks/bb-digital-registries/urls.py @@ -0,0 +1,7 @@ +from django.urls import path +from .views.check_if_record_exists_in_registry import check_if_record_exists_in_registry + + +urlpatterns = [ + path('data///exists', check_if_record_exists_in_registry) +] \ No newline at end of file diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/views/__init__.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/views/check_if_record_exists_in_registry.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/views/check_if_record_exists_in_registry.py new file mode 100644 index 0000000..2c7c58e --- /dev/null +++ b/govstack_test_harness_api/building_blocks/bb-digital-registries/views/check_if_record_exists_in_registry.py @@ -0,0 +1,33 @@ +from django.http import JsonResponse +from rest_framework.decorators import api_view +from ..serializers.record_exists_serializer import RecordExistsSerializer +from drf_yasg.utils import swagger_auto_schema +from .swaggers_schema import exists_request_body, exists_response_body +from ..swaggers_schema import info_mediator_client +from ..services.services import login_with_env_variables +from ..controllers.record_exists_controller import check_if_record_exists + + +@swagger_auto_schema( + method='post', + operation_description="Searches records based on input parameters and returns boolean answer (true/false).", + manual_parameters=[info_mediator_client], + request_body=exists_request_body, + responses={200: exists_response_body}, +) +@api_view(['POST']) +def check_if_record_exists_in_registry(request, registryname, versionnumber): + # This is controller logic: receiving the request and validating input + data = request.data + data.update({"registryname": registryname, "versionnumber": versionnumber}) + serializer = RecordExistsSerializer(data=data) + if serializer.is_valid(): + context = login_with_env_variables(request) + response_data = check_if_record_exists( + serializer.validated_data, + request.COOKIES.get('JWT'), + context + ) + return JsonResponse(response_data) + else: + return JsonResponse(serializer.errors, status=400) diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/views/login_view.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/views/login_view.py new file mode 100644 index 0000000..e69de29 diff --git a/govstack_test_harness_api/building_blocks/bb-digital-registries/views/swaggers_schema.py b/govstack_test_harness_api/building_blocks/bb-digital-registries/views/swaggers_schema.py new file mode 100644 index 0000000..f667ea6 --- /dev/null +++ b/govstack_test_harness_api/building_blocks/bb-digital-registries/views/swaggers_schema.py @@ -0,0 +1,249 @@ +# swagger_schemas.py +from drf_yasg import openapi + +# definition of requests and responses + +create_request_body = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'write': openapi.Schema(type=openapi.TYPE_OBJECT, properties={ + 'content': openapi.Schema(type=openapi.TYPE_OBJECT, description='Content to be saved') + }) + }, + required=['write'] +) + +create_response_body = openapi.Response('response description', openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'write': openapi.Schema(type=openapi.TYPE_OBJECT, properties={ + 'content': openapi.Schema(type=openapi.TYPE_OBJECT, description='Content to be saved') + }) + }, + required=['write'] +)) + +read_value_response_body = openapi.Response('response description', openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'value': openapi.Schema(type=openapi.TYPE_STRING, description='Value of the specified field') + }, + required=['value'] +)) + +content_schema = openapi.Schema(type=openapi.TYPE_OBJECT, ref='#/components/schemas/Example') + +query_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'query': openapi.Schema(type=openapi.TYPE_OBJECT, properties={'content': content_schema}, required=['content']), + }, + required=['query'] +) + +responses_schema = { + '200': openapi.Response( + description='', + schema=openapi.Schema(type=openapi.TYPE_OBJECT, properties={'content': content_schema}), + ), + '404': openapi.Response( + description='Record not found', + schema=openapi.Schema(type=openapi.TYPE_OBJECT, properties={'detail': openapi.Schema(type=openapi.TYPE_STRING, enum=['no record found'])}), + ), +} + +read_record_schema = { + 'method': 'post', + 'operation_description': 'Searches and returns one record.', + 'request_body': query_schema, + 'responses': responses_schema, + 'security': [{'apiKey': []}], +} + + +exists_request_body = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'query': openapi.Schema(type=openapi.TYPE_OBJECT, properties={ + 'content': openapi.Schema(type=openapi.TYPE_OBJECT, description='Search content') + }), + }, + required=['query'] +) + +exists_response_body = openapi.Response('response description', openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'answer': openapi.Schema(type=openapi.TYPE_OBJECT, properties={ + 'status': openapi.Schema(type=openapi.TYPE_BOOLEAN, description='Example object found in database'), + 'message': openapi.Schema(type=openapi.TYPE_STRING, description='More information about the object') + }) + }, + required=['answer'] +)) + +delete_response = openapi.Response(description='No content') + +create_or_update_response = { + 200: openapi.Response( + 'Successful update or creation of record', + openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'content': openapi.Schema( + type=openapi.TYPE_OBJECT, + description='Updated or newly created object', + ), + }, + required=['content'], + ), + ), + 400: 'Bad request', + 500: 'Internal server error', +} + +content_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={}, + description='Example object' +) + +query_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={'content': content_schema}, + required=['content'], + description='Search object that needs to be updated' +) + +write_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={'content': content_schema}, + required=['content'], + description='Update found object with the following data' +) + +request_body_schema = openapi.Schema( + type=openapi.TYPE_OBJECT, + properties={ + 'query': query_schema, + 'write': write_schema, + }, + required=['write'], + description='' +) + +update_record_schema = { + 'method': 'put', + 'operation_description': "Updates one existing record in the registry database.", + 'request_body': request_body_schema, + 'responses': {200: openapi.Response(description='')} +} + +# Parameters + +search_parameter = openapi.Parameter( + name='search', + in_=openapi.IN_QUERY, + description='Search word', + type=openapi.TYPE_STRING, +) + +filter_parameter = openapi.Parameter( + name='filter', + in_=openapi.IN_QUERY, + description='Result filter', + type=openapi.TYPE_STRING, +) + +ordering_parameter = openapi.Parameter( + name='ordering', + in_=openapi.IN_QUERY, + description='Sort type', + type=openapi.TYPE_STRING, +) + +page_parameter = openapi.Parameter( + name='page', + in_=openapi.IN_QUERY, + description='Page number', + type=openapi.TYPE_INTEGER, +) + +page_size_parameter = openapi.Parameter( + name='page_size', + in_=openapi.IN_QUERY, + description='Number of results per page', + type=openapi.TYPE_INTEGER, +) + +query_fieldname_parameter = openapi.Parameter( + name='query.', + in_=openapi.IN_QUERY, + description='Query based on field name', + type=openapi.TYPE_STRING, +) + +get_multiple_records_from_registry_parameters = [ + search_parameter, + filter_parameter, + ordering_parameter, + page_parameter, + page_size_parameter, + query_fieldname_parameter, +] + +registryname_parameter = openapi.Parameter( + name='registryname', + in_=openapi.IN_PATH, + description='Registry name', + type=openapi.TYPE_STRING, +) + +versionnumber_parameter = openapi.Parameter( + name='versionnumber', + in_=openapi.IN_PATH, + description='Version number', + type=openapi.TYPE_STRING, +) + +uuid_parameter = openapi.Parameter( + name='uuid', + in_=openapi.IN_PATH, + description='Primary key', + type=openapi.TYPE_STRING, +) + +id_parameter = openapi.Parameter( + name='ID', + in_=openapi.IN_PATH, + description='Primary key', + type=openapi.TYPE_STRING, +) + +field_parameter = openapi.Parameter( + name='field', + in_=openapi.IN_PATH, + description='Field name', + type=openapi.TYPE_STRING, +) + +ext_parameter = openapi.Parameter( + name='ext', + in_=openapi.IN_PATH, + description='Data extension', + type=openapi.TYPE_STRING, +) + +read_value_parameters = [ + registryname_parameter, + versionnumber_parameter, + uuid_parameter, + field_parameter, + ext_parameter, +] + +delete_parameters = [ + registryname_parameter, + versionnumber_parameter, + id_parameter +] \ No newline at end of file diff --git a/govstack_test_harness_api/middleware.py b/govstack_test_harness_api/middleware.py new file mode 100644 index 0000000..5a6a98a --- /dev/null +++ b/govstack_test_harness_api/middleware.py @@ -0,0 +1,16 @@ +from django.http import HttpResponse +from django.conf import settings +from django.apps import apps + + +class InformationMediatorMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + config = apps.get_app_config('govstack_test_harness_api') + im_client = config.IM_CLIENT + im_header = request.META.get('HTTP_INFORMATION_MEDIATOR_CLIENT') + if im_header != im_client: + return HttpResponse('Unauthorized', status=401) + return self.get_response(request) diff --git a/govstack_test_harness_api/urls.py b/govstack_test_harness_api/urls.py index 2012ebe..e900858 100644 --- a/govstack_test_harness_api/urls.py +++ b/govstack_test_harness_api/urls.py @@ -1 +1,7 @@ -urlpatterns = [] \ No newline at end of file +from django.urls import path, include +from . import views +import govstack_test_harness_api + +urlpatterns = [ + path('', include('govstack_test_harness_api.building_blocks.bb-digital-registries.urls')), +] \ No newline at end of file diff --git a/govstack_test_harness_api/views.py b/govstack_test_harness_api/views.py index 91ea44a..8b13789 100644 --- a/govstack_test_harness_api/views.py +++ b/govstack_test_harness_api/views.py @@ -1,3 +1 @@ -from django.shortcuts import render -# Create your views here. diff --git a/openimis_be_test_harness_api.egg-info/PKG-INFO b/openimis_be_test_harness_api.egg-info/PKG-INFO deleted file mode 100644 index b1dd24b..0000000 --- a/openimis_be_test_harness_api.egg-info/PKG-INFO +++ /dev/null @@ -1,48 +0,0 @@ -Metadata-Version: 2.1 -Name: openimis-be-test-harness-api -Version: 1.0.0rc1 -Summary: The openIMIS API for test harness. -Home-page: https://openimis.org/ -Author: Ɓukasz Ruzicki -Author-email: lruzicki@soldevelo.com -License: GNU AGPL v3 -Classifier: Environment :: Web Environment -Classifier: Framework :: Django -Classifier: Framework :: Django :: 2.1 -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: GNU Affero General Public License v3 -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Description-Content-Type: text/markdown - -# openIMIS Backend Report reference module -This repository holds the files of the openIMIS Backend Core reference module. -It is a required module of [openimis-be_py](https://github.com/openimis/openimis-be_py). - -[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) - -## ORM mapping: -* report_ReportDefinition > ReportDefinition - -## Listened Django Signals -None - -## Services -* ReportService: process (ReportBro engine) named report - -## Reports (template can be overloaded via report.ReportDefinition) -None - -## GraphQL Queries -None - -## GraphQL Mutations - each mutation emits default signals and return standard error lists (cfr. openimis-be-core_py) -None - -## Configuration options (can be changed via core.ModuleConfiguration) -None - -## openIMIS Modules Dependencies -* core.models.UUIDModel diff --git a/openimis_be_test_harness_api.egg-info/SOURCES.txt b/openimis_be_test_harness_api.egg-info/SOURCES.txt deleted file mode 100644 index 93fac8c..0000000 --- a/openimis_be_test_harness_api.egg-info/SOURCES.txt +++ /dev/null @@ -1,15 +0,0 @@ -README.md -setup.py -openimis_be_test_harness_api.egg-info/PKG-INFO -openimis_be_test_harness_api.egg-info/SOURCES.txt -openimis_be_test_harness_api.egg-info/dependency_links.txt -openimis_be_test_harness_api.egg-info/requires.txt -openimis_be_test_harness_api.egg-info/top_level.txt -test_harness_api/__init__.py -test_harness_api/admin.py -test_harness_api/apps.py -test_harness_api/models.py -test_harness_api/tests.py -test_harness_api/urls.py -test_harness_api/views.py -test_harness_api/migrations/__init__.py \ No newline at end of file diff --git a/openimis_be_test_harness_api.egg-info/dependency_links.txt b/openimis_be_test_harness_api.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/openimis_be_test_harness_api.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/openimis_be_test_harness_api.egg-info/requires.txt b/openimis_be_test_harness_api.egg-info/requires.txt deleted file mode 100644 index 22ddbd9..0000000 --- a/openimis_be_test_harness_api.egg-info/requires.txt +++ /dev/null @@ -1,8 +0,0 @@ -django -django-db-signals -djangorestframework -openimis-be-core -openimis-be-location -openimis-be-payment -openimis-be-policy -openimis-be-insuree diff --git a/openimis_be_test_harness_api.egg-info/top_level.txt b/openimis_be_test_harness_api.egg-info/top_level.txt deleted file mode 100644 index 4fb9577..0000000 --- a/openimis_be_test_harness_api.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -test_harness_api diff --git a/setup.py b/setup.py index 0d745a7..35fa37a 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) setup( - name='openimis-be-govstack_test_harness_api_py', + name='openimis-be-govstack_test_harness_api', version='1.0.0.rc1', packages=find_packages(), include_package_data=True, @@ -27,7 +27,8 @@ 'openimis-be-location', 'openimis-be-payment', 'openimis-be-policy', - 'openimis-be-insuree' + 'openimis-be-insuree', + 'graphqlclient' ], classifiers=[ 'Environment :: Web Environment',