diff --git a/dogconfig/dogproject/settings.py b/dogconfig/dogproject/settings.py index 0b4630a..1c012db 100644 --- a/dogconfig/dogproject/settings.py +++ b/dogconfig/dogproject/settings.py @@ -63,7 +63,8 @@ INTERNAL_IPS += [".".join(ip.split(".")[:-1] + ["1"]) for ip in ips] - +DTR_ENABLED = True +VERIFY_SSL = False # Application definition INSTALLED_APPS = [ @@ -86,11 +87,10 @@ # local 'dogapi', 'dogui' - ] -DTR_ENABLED = False - +if DTR_ENABLED: + INSTALLED_APPS += ['dogdtr'] REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': [ @@ -100,14 +100,10 @@ 'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema', } -VERIFY_SSL = False - - - SPECTACULAR_SETTINGS = { 'TITLE': 'Digital Object Gate', 'DESCRIPTION': 'DOG API resolving referenced resources in the metadata', - 'VERSION': '1.0.3', + 'VERSION': VERSION, 'SERVE_INCLUDE_SCHEMA': False, # OTHER SETTINGS } @@ -143,6 +139,9 @@ }, ] +if DTR_ENABLED: + TEMPLATES[0]['DIRS'] += [join(BASE_DIR, './../dogdtr/dogdtr/templates')] + DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', diff --git a/dogconfig/dogproject/urls.py b/dogconfig/dogproject/urls.py index 74dd770..02eabe5 100644 --- a/dogconfig/dogproject/urls.py +++ b/dogconfig/dogproject/urls.py @@ -7,7 +7,7 @@ from dogapi.views_api import (fetch, identify, sniff, is_pid, get_all_repositories, get_repositories_status) -from dogdtr.views_api import expand_datatype +from dogdtr.views_api import expand_datatype_view from dogdtr.views_ui import dtr from dogui.views_ui import about, contact, home @@ -24,13 +24,13 @@ path('api/v1/ispid/', is_pid, name='is pid'), path('__debug__/', include('debug_toolbar.urls')), - path('api/v1/expanddatatype/', expand_datatype, name='expand data type'), + path('api/v1/expanddatatype/', expand_datatype_view, name='expand data type'), path('api/v1/allregrepo/', get_all_repositories, name='get all repositories'), path('api/v1/repostatus/', get_repositories_status, name='get repositories status'), # UI path('', home, name='main'), - path('about', about, name='about'), - path('contact', contact, name='contact'), - path('dtr', dtr, name='contact') + path('about/', about, name='about'), + path('contact/', contact, name='contact'), + path('dtr/', dtr, name='dtr'), ] diff --git a/dogui/dogui/templates/UI/_.html b/dogconfig/templates/UI/_.html similarity index 100% rename from dogui/dogui/templates/UI/_.html rename to dogconfig/templates/UI/_.html diff --git a/dogui/dogui/templates/UI/_about.html b/dogconfig/templates/UI/_about.html similarity index 100% rename from dogui/dogui/templates/UI/_about.html rename to dogconfig/templates/UI/_about.html diff --git a/dogui/dogui/templates/UI/_contact.html b/dogconfig/templates/UI/_contact.html similarity index 100% rename from dogui/dogui/templates/UI/_contact.html rename to dogconfig/templates/UI/_contact.html diff --git a/dogui/dogui/templates/UI/_navbar.html b/dogconfig/templates/UI/_navbar.html similarity index 100% rename from dogui/dogui/templates/UI/_navbar.html rename to dogconfig/templates/UI/_navbar.html diff --git a/dogdtr/dogdtr/dtr.py b/dogdtr/dogdtr/dtr.py index 1814f08..27ee245 100644 --- a/dogdtr/dogdtr/dtr.py +++ b/dogdtr/dogdtr/dtr.py @@ -1,8 +1,12 @@ - import json +import urllib from requests import RequestException from requests import get +from typing import List, Tuple, Union + + +from .utils import MIMEType class DataTypeNotFoundException(Exception): @@ -10,11 +14,14 @@ def __init__(self, message): self.message = message -def expand_datatype(data_type: str) -> dict: +def expand_datatype(data_type: Union[str, List[str]]) -> List[dict]: """ Wrapper for DTR datatype taxonomy discovery """ - return get_dtr_taxonomy_by_type(data_type) + if isinstance(data_type, str): + return [get_dtr_taxonomy_by_type(data_type)] + elif isinstance(data_type, list): + return [get_dtr_taxonomy_by_type(dt) for dt in data_type] def get_dtr_taxonomy_by_type(data_type: str) -> dict: @@ -24,61 +31,50 @@ def get_dtr_taxonomy_by_type(data_type: str) -> dict: :param data_type: str, MIME type, e.g. 'text/xml' :return: dict, a dictionary representation of the type's taxonomy """ - dtr_type_search_endpoint = f"http://typeapi.lab.pidconsortium.net/v1/taxonomy/search?query={data_type}&name={data_type}" + dtr_taxonomy_search_endpoint = f"http://typeapi.lab.pidconsortium.net/v1/taxonomy/search?query={data_type}&name={data_type}" + data_type = urllib.parse.quote(data_type, safe='') try: - url, dtr_taxonomy_search_response, header = get(dtr_type_search_endpoint) + dtr_taxonomy_search_response = get(dtr_taxonomy_search_endpoint) except RequestException as error: - raise DataTypeNotFoundException(f"DataType <{data_type}> doesn't exist in the DTR taxonomy") from error + raise DataTypeNotFoundException(f"Failed to reach DTR to query for taxonomy") from error + except ValueError as error: + raise DataTypeNotFoundException(f"Failed to unpack DTR response. Most probably {data_type} is not registered") from error - dtr_taxonomy_json = json.loads(dtr_taxonomy_search_response) - print("get_dtr_taxonomy_by_type: TAXONOMY") - print(dtr_taxonomy_json) try: - dtr_type_id = dtr_taxonomy_json[0]["id"] - except (IndexError, KeyError) as error: - raise DataTypeNotFoundException(f"DataType <{data_type}> doesn't exist in the DTR taxonomy") from error - parents = dtr_taxonomy_json[0]["parents"] - if parents: - for parent_id, parent_name in parents.items(): - dtr_type_id = get_taxonomy_root_node_by_id(parent_id) - return get_taxonomy_subtree_from_root_id(dtr_type_id) + dtr_taxonomy_search_json = dtr_taxonomy_search_response.json() + type_taxonomy_id = dtr_taxonomy_search_json[0]["id"] + except IndexError as error: + raise DataTypeNotFoundException(f"Failed to resolve {data_type} taxonomy. Most probably it doesn't exist.") -def get_taxonomy_root_node_by_id(data_type_id: str) -> str: - """ - Returns an ID of the root type of the taxonomy for the given data_type_id + root_taxonomy_id = retrieve_root(type_taxonomy_id) + taxonomy_tree = retrieve_taxonomy_tree(root_taxonomy_id) + return taxonomy_tree - :param data_type_id: str, DTR MIME type PID, e.g. 21.T11969/f33c32fa8246e2ca6d5c - :return: dict, a dictionary representation of the type's taxonomy - """ - dtr_taxonomy_endpoint = f"http://typeapi.lab.pidconsortium.net/v1/taxonomy/{data_type_id}" - url, dtr_taxonomy_node_response, header = get(dtr_taxonomy_endpoint) - dtr_taxonomy_json = json.loads(dtr_taxonomy_node_response) - try: - dtr_type_id = dtr_taxonomy_json["id"] - except (IndexError, KeyError) as error: - raise DataTypeNotFoundException(f"DataType with id <{data_type_id}> doesn't exist in the DTR taxonomy") from error - parents = dtr_taxonomy_json["parents"] - # Assumption of single parent - taxonomy_root_id = dtr_type_id - if parents: - for parent_id, parent_name in parents.items(): - taxonomy_root_id = get_taxonomy_root_node_by_id(parent_id) - return taxonomy_root_id - - -def get_taxonomy_subtree_from_root_id(root_id: str) -> dict: - """ - Get a subtree from the root ID +def retrieve_root(taxonomy_id: str) -> Tuple[str, str]: + dtr_taxonomy_endpoint = f"http://typeapi.lab.pidconsortium.net/v1/taxonomy/{taxonomy_id}" + taxonomy_response = get(dtr_taxonomy_endpoint) + taxonomy_json = taxonomy_response.json() - :param root_id: str, the root node ID - :return: dict, MIME type taxonomy - """ - dtr_taxonomy_subtree_endpoint = f"http://typeapi.lab.pidconsortium.net/v1/taxonomy/{root_id}/subtree" - url, dtr_taxonomy_subtree_response, header = get(dtr_taxonomy_subtree_endpoint) - dtr_taxonomy_subtree_json = json.loads(dtr_taxonomy_subtree_response) - return dtr_taxonomy_subtree_json + # Recurse until no parent under "parents" key + for parent_id, parent_name in taxonomy_json["parents"].items(): + return retrieve_root(parent_id) + taxonomy_id = taxonomy_json["id"] + return taxonomy_id + + +def retrieve_taxonomy_tree(taxonomy_id: str): + dtr_taxonomy_endpoint = f"http://typeapi.lab.pidconsortium.net/v1/taxonomy/{taxonomy_id}" + dtr_taxonomy_response = get(dtr_taxonomy_endpoint) + dtr_taxonomy_json = dtr_taxonomy_response.json() + + taxonomy_name = dtr_taxonomy_json["name"] + + children = [] + for child_id, child_name in dtr_taxonomy_json["children"].items(): + children.append(retrieve_taxonomy_tree(child_id)) + return {taxonomy_name: {"id": taxonomy_id, "children": children}} """ diff --git a/dogdtr/dogdtr/forms.py b/dogdtr/dogdtr/forms.py index af54942..1d31eb6 100644 --- a/dogdtr/dogdtr/forms.py +++ b/dogdtr/dogdtr/forms.py @@ -34,9 +34,10 @@ class MIMETypeForm(forms.Form): """ Input form for inserting MIMEtype """ - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.fields["mimetype"].label = "" mimetype_field: MIMETypeField = MIMETypeField(required=True, widget=forms.TextInput(attrs={'required': 'True'})) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["mimetype_field"].label = "" diff --git a/dogdtr/dogdtr/templates/UI/_dtr.html b/dogdtr/dogdtr/templates/UI/_dtr.html index da825e0..066db53 100644 --- a/dogdtr/dogdtr/templates/UI/_dtr.html +++ b/dogdtr/dogdtr/templates/UI/_dtr.html @@ -1,4 +1,18 @@ {% extends 'UI/_.html' %} {% block content %} -

PLACEHOLDER

-

PLUGGABLE DTR UI TBD Q4 2024

+
+

DOG Data Type Registry plugin

+

DOG subservice allowing MIMEtype taxonomy expansion based on Data Type Registry

+ + Type a MIMEtype (e.g. `application/json`) into the box + + {% block mimetype %} + {% if mimetype_form %} + {% include 'UI/_form_mimetype.html' with form=mimetype_form %} + {% endif %} + {% endblock mimetype %} + + {% block result %} + {% endblock result %} +
+{% endblock content %} diff --git a/dogdtr/dogdtr/templates/UI/_expanddatatype.html b/dogdtr/dogdtr/templates/UI/_expanddatatype.html index bbd8875..5ee194b 100644 --- a/dogdtr/dogdtr/templates/UI/_expanddatatype.html +++ b/dogdtr/dogdtr/templates/UI/_expanddatatype.html @@ -1,9 +1,12 @@ -{% extends 'UI/_content.html' %} -{% load dogui_extras %} +{% extends 'UI/_dtr.html' %} +{{ taxonomies }} {% block result %} - -{% endblock result %} \ No newline at end of file + {% for input_type, taxonomy in taxonomies.items %} + + {% endfor %} +{% endblock result %} diff --git a/dogdtr/dogdtr/templates/UI/_form_mimetype.html b/dogdtr/dogdtr/templates/UI/_form_mimetype.html index 5be1617..9ff15bb 100644 --- a/dogdtr/dogdtr/templates/UI/_form_mimetype.html +++ b/dogdtr/dogdtr/templates/UI/_form_mimetype.html @@ -1,5 +1,5 @@
-
+ {{ form }} diff --git a/dogdtr/dogdtr/templates/UI/_tree_node_view.html b/dogdtr/dogdtr/templates/UI/_tree_node_view.html deleted file mode 100644 index d1f2e0e..0000000 --- a/dogdtr/dogdtr/templates/UI/_tree_node_view.html +++ /dev/null @@ -1,12 +0,0 @@ -
  • - {{ node.name }} - {% if node.has_children %} -
      - {% for child in node.children %} - {% with node=child template_name="UI/tree/_tree_node_view.html" %} - {% include template_name %} - {% endwith %} - {% endfor %} -
    - {% endif %} -
  • \ No newline at end of file diff --git a/dogdtr/dogdtr/templates/UI/tree/_tree_node_view.html b/dogdtr/dogdtr/templates/UI/tree/_tree_node_view.html new file mode 100644 index 0000000..8597b24 --- /dev/null +++ b/dogdtr/dogdtr/templates/UI/tree/_tree_node_view.html @@ -0,0 +1,16 @@ +{% extends 'UI/_expanddatatype.html' %} +{% block node %} + {% for input_type_name, data in node.items %} + {% if data.children %} + {% for child in data.children %} + +
  • + {% with node=child template_name="UI/tree/_tree_node_view.html" %} + {% include template_name %} + {% endwith %} +
  • + + {% endfor %} + {% endif %} + {% endfor %} +{% endblock node %} \ No newline at end of file diff --git a/dogdtr/dogdtr/utils.py b/dogdtr/dogdtr/utils.py index e4363ae..94e84e1 100644 --- a/dogdtr/dogdtr/utils.py +++ b/dogdtr/dogdtr/utils.py @@ -1,6 +1,16 @@ from dogapi.utils import parse_queryparam +from typing import List + + + +class MIMEType: + name: str + id: str + children: List + + class TaxonomyTree: def __init__(self, taxonomy_dict: dict): self.name = next(iter(taxonomy_dict.keys())) diff --git a/dogdtr/dogdtr/views_api.py b/dogdtr/dogdtr/views_api.py index 7f52ea0..3a3b647 100644 --- a/dogdtr/dogdtr/views_api.py +++ b/dogdtr/dogdtr/views_api.py @@ -26,13 +26,13 @@ ) @permission_classes([AllowAny]) @api_view(['GET']) -def expand_datatype(request: Request) -> Response: - data_types = parse_queryparam(request, 'data_type') +def expand_datatype_view(request: Request) -> Response: + mime_types = parse_queryparam(request, 'mimetype') expanded_datatypes: dict = {} - for data_type in data_types: + for data_type in mime_types: expanded_datatypes[data_type] = expand_datatype(data_type) if expanded_datatypes: return Response(expanded_datatypes, status=200) else: - return Response(f"MIME data type(s) {data_types} is either not correct or has been not recognised", + return Response(f"MIME data type(s) {mime_types} is either not correct or has been not recognised", status=400) diff --git a/dogdtr/dogdtr/views_ui.py b/dogdtr/dogdtr/views_ui.py index 259ba3a..557484e 100644 --- a/dogdtr/dogdtr/views_ui.py +++ b/dogdtr/dogdtr/views_ui.py @@ -5,6 +5,8 @@ import logging.config +import requests + from .utils import TaxonomyTree from .forms import MIMETypeForm @@ -17,17 +19,23 @@ def dtr(request: HttpRequest) -> HttpResponse: context: RequestContext = RequestContext(request) - mimetype_form: MIMETypeForm = MIMETypeForm(request.GET) + mimetype_form: MIMETypeForm = MIMETypeForm(request.GET, use_required_attribute=False) - if pid_form.is_valid(): + context.push({"view": "dtr"}) + context.push({"DTR_ENABLED": DTR_ENABLED}) + + if mimetype_form.is_valid(): context.push({"mimetype_form": mimetype_form}) - pids = mimetype_form.cleaned_data['mimetype_field'] - api_url = API_NETLOC + f'/expanddatatype/?data_type={",".join(pids)}' + mimetypes = mimetype_form.cleaned_data['mimetype_field'] - api_response = requests.get(api_url, verify=VERIFY_SSL) + api_url = API_NETLOC + f'/expanddatatype/?mimetype={",".join(mimetypes)}' + api_response = requests.get(api_url, verify=VERIFY_SSL) - context: RequestContext = RequestContext(request) - context.push({"view": "dtr"}) - context.push({"DTR_ENABLED": DTR_ENABLED}) - return render(request, "UI/_dtr.html", context.flatten()) + print(api_response.json()) + context.push({f"taxonomies": api_response.json()}) + return render(request, f"UI/_expanddatatype.html", context.flatten()) + else: + context.push({"mimetype_form": mimetype_form}) + context.push({"view": "dtr"}) + return render(request, "UI/_dtr.html", context.flatten()) diff --git a/dogui/dogui/context_processors.py b/dogui/dogui/context_processors.py index 4d76b2a..5a76879 100644 --- a/dogui/dogui/context_processors.py +++ b/dogui/dogui/context_processors.py @@ -1,6 +1,14 @@ from django.conf import settings +import re + def version(request): # pylint: disable=unused-argument - return {'VERSION': settings.VERSION} + version = settings.VERSION + alpha_regex = re.compile(r"[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+") + beta_regex = re.compile(r"[0-9]+\.[0-9]+\.[0-9]+") + if alpha_regex.match(version): + return {"VERSION": version, "INSTANCE": "ALPHA"} + elif beta_regex.match(version): + return {'VERSION': version, "INSTANCE": "BETA"} diff --git a/dogui/dogui/forms.py b/dogui/dogui/forms.py index 610d1b1..bc8061a 100644 --- a/dogui/dogui/forms.py +++ b/dogui/dogui/forms.py @@ -34,10 +34,6 @@ class PIDForm(forms.Form): """ Input form for inserting PID and operation to perform """ - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.fields["pid_field"].label = "" - self.fields["functionality_field"].label = "" FUNCTIONALITIES: List[tuple] = [ ('sniff', 'sniff'), @@ -51,3 +47,8 @@ def __init__(self, *args, **kwargs): widget=forms.RadioSelect( attrs={'class': 'form-check-inline', 'required': 'True'}), ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields["pid_field"].label = "" + self.fields["functionality_field"].label = "" \ No newline at end of file diff --git a/dogui/dogui/templates/UI/_content.html b/dogui/dogui/templates/UI/_content.html index 4bd2c32..8c5533c 100644 --- a/dogui/dogui/templates/UI/_content.html +++ b/dogui/dogui/templates/UI/_content.html @@ -20,7 +20,7 @@
    Source code for DOGapp avaiable here -

    BETA Digital Object Gateway

    +

    {{ INSTANCE }} Digital Object Gateway

    {% block pid_form %} {% if pid_form %} diff --git a/dogui/dogui/templates/UI/_expanddatatype.html b/dogui/dogui/templates/UI/_expanddatatype.html deleted file mode 100644 index bbd8875..0000000 --- a/dogui/dogui/templates/UI/_expanddatatype.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends 'UI/_content.html' %} -{% load dogui_extras %} -{% block result %} - -{% endblock result %} \ No newline at end of file diff --git a/dogui/dogui/templates/UI/tree/_tree_node_view.html b/dogui/dogui/templates/UI/tree/_tree_node_view.html deleted file mode 100644 index d1f2e0e..0000000 --- a/dogui/dogui/templates/UI/tree/_tree_node_view.html +++ /dev/null @@ -1,12 +0,0 @@ -
  • - {{ node.name }} - {% if node.has_children %} -
      - {% for child in node.children %} - {% with node=child template_name="UI/tree/_tree_node_view.html" %} - {% include template_name %} - {% endwith %} - {% endfor %} -
    - {% endif %} -
  • \ No newline at end of file