diff --git a/.gitignore b/.gitignore index db9dd30..2e8e623 100644 --- a/.gitignore +++ b/.gitignore @@ -161,3 +161,6 @@ cython_debug/ # Mac .DS_Store + +# Project-specific ignores +local_settings.py \ No newline at end of file diff --git a/dgpf1/dgpf1/facet_modifiers.py b/dgpf1/dgpf1/facet_modifiers.py index 18719ad..e7abfdb 100644 --- a/dgpf1/dgpf1/facet_modifiers.py +++ b/dgpf1/dgpf1/facet_modifiers.py @@ -18,3 +18,17 @@ def lookup_replace_provider_id(facets: dict) -> dict: "added to the database!") bucket["custom_display_value"] = "Other" return facets + + +def combine_info_group(facets: list) -> list: + """Collapse Info_GroupID and Info_GroupName into a single 'Resource Group' + facet that filters by name. Drops the raw ID facet from display.""" + combined = [] + for facet in facets: + if facet["field_name"] == "Info_GroupID": + continue + if facet["field_name"] == "Info_GroupName": + facet = dict(facet) + facet["name"] = "Resource Group" + combined.append(facet) + return combined diff --git a/dgpf1/dgpf1/fields.py b/dgpf1/dgpf1/fields.py index 3d57b00..b87c6f6 100644 --- a/dgpf1/dgpf1/fields.py +++ b/dgpf1/dgpf1/fields.py @@ -5,6 +5,10 @@ def title(result): return result[0]['Title'] +def software_title(result): + return result[0].get('Name', 'Software Detail') + + def general_info(result): """Return all basic information in the first gmeta entry""" return result[0] @@ -48,3 +52,41 @@ def detail_result_display_fields(result): # If the date cannot be parsed, just leave it. pass return display_fields + + +def software_detail_result_display_fields(result): + possible_date_fields = ["CreationTime"] + info = general_info(result) + leading_fields = [ + {"field_name": "Name"}, + {"field_name": "Category"}, + {"field_name": "Keywords"}, + {"field_name": "SupportStatus", "display_name": "Support Status"}, + {"field_name": "Version"}, + {"field_name": "URL"}, + {"field_name": "Organization_Name", "display_name": "Organization Name"}, + {"field_name": "Organization_ID", "display_name": "Organization ID"}, + {"field_name": "Info_GroupName", "display_name": "Resource Group"}, + {"field_name": "Info_GroupID", "display_name": "Resource Group ID"}, + {"field_name": "Info_ResourceName", "display_name": "Resource Name"}, + {"field_name": "Info_ResourceID", "display_name": "Resource ID"}, + ] + trailing_fields = [ + {"field_name": "HandleKey", "display_name": "Handle Key"}, + {"field_name": "HandleType", "display_name": "Handle Type"}, + {"field_name": "CreationTime", "display_name": "Creation Time"}, + ] + known_field_names = [fl["field_name"] for fl in leading_fields + trailing_fields] + other_fields = [{"field_name": f} for f in info if f not in known_field_names] + display_fields = leading_fields + other_fields + trailing_fields + for item in display_fields: + item["display_name"] = item.get("display_name", item["field_name"].replace("_", " ")) + item["value"] = info.get(item["field_name"]) + item["is_list"] = isinstance(item["value"], list) + if item["field_name"] in possible_date_fields: + try: + item["value"] = datetime.datetime.fromisoformat(item["value"].replace("Z", "+00:00")).strftime("%b %d %Y %H:%M:%S %Z%z") + item["is_list"] = False + except Exception: + pass + return display_fields diff --git a/dgpf1/dgpf1/settings.py b/dgpf1/dgpf1/settings.py index 6879fa8..d6d9332 100644 --- a/dgpf1/dgpf1/settings.py +++ b/dgpf1/dgpf1/settings.py @@ -19,7 +19,7 @@ import json import os import sys -from dgpf1.fields import title, general_info, detail_result_display_fields +from dgpf1.fields import title, general_info, detail_result_display_fields, software_title, software_detail_result_display_fields #import pdb #pdb.set_trace() @@ -79,8 +79,10 @@ 'DIRS': [BASE_DIR / 'templates'], 'APP_DIRS': True, 'OPTIONS': { + 'debug': DEBUG, 'libraries': { 'settings_value': 'templatetags.get_settings', + 'urldecode': 'templatetags.custom_tags', }, 'context_processors': [ 'django.template.context_processors.debug', @@ -102,20 +104,21 @@ 'default': { 'USER': CONF['DJANGO_USER'], 'PASSWORD': CONF['DJANGO_PASS'], - 'HOST': os.environ.get('PGHOST', CONF.get('DB_HOSTNAME_WRITE', 'localhost')), + 'HOST': os.environ.get('PGHOST', CONF.get('DB_HOSTNAME_WRITE', 'db')), + }, + 'sqlite3': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', } -# 'sqlite3': { -# 'ENGINE': 'django.db.backends.sqlite3', -# 'NAME': BASE_DIR / 'db.sqlite3', -# } } for db in DATABASES: - DATABASES[db]['NAME'] = CONF['DB_DATABASE'] - DATABASES[db]['ENGINE'] = 'django.db.backends.postgresql' - DATABASES[db]['PORT'] = os.environ.get('PGPORT', CONF.get('DB_PORT', '5432')) - DATABASES[db]['CONN_MAX_AGE'] = 600 # Persist DB connections - DATABASES[db]['OPTIONS'] = {'options': '-c search_path=ed_dgpf1,public'} + if db == "default": + DATABASES[db]['NAME'] = CONF['DB_DATABASE'] + DATABASES[db]['ENGINE'] = 'django.db.backends.postgresql' + DATABASES[db]['PORT'] = os.environ.get('PGPORT', CONF.get('DB_PORT', '5432')) + DATABASES[db]['CONN_MAX_AGE'] = 600 # Persist DB connections + DATABASES[db]['OPTIONS'] = {'options': '-c search_path=ed_dgpf1,public'} # Password validation # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators @@ -167,7 +170,8 @@ # https://docs.djangoproject.com/en/4.2/howto/static-files/ STATIC_URL = 'static/' -STATIC_ROOT = CONF['STATIC_ROOT'] + +STATIC_ROOT = BASE_DIR / 'static' STATICFILES_DIRS = [BASE_DIR / 'staticfiles'] # Default primary key field type @@ -289,8 +293,30 @@ ('general_info', general_info), ('detail_result_display_fields', detail_result_display_fields), ], + }, + 'access-software-v4': { + 'name': 'ACCESS Software Catalog - Beta catalog v4', + 'uuid': '3cc4aeec-55a5-4cd6-96d1-8531aef88e83', + 'facets': [ + {'name': 'Category', 'field_name': 'Category'}, + {'name': 'Keywords', 'field_name': 'Keywords'}, + {'name': 'Support Status', 'field_name': 'SupportStatus'}, + {'name': 'Organization', 'field_name': 'Organization_Name'}, + {'name': 'Resource Group', 'field_name': 'Info_GroupName'}, + {'name': 'Resource', 'field_name': 'Info_ResourceName'}, + ], + 'facet_modifiers': [ + 'globus_portal_framework.modifiers.facets.drop_empty', + # 'dgpf1.facet_modifiers.combine_info_group', + ], + 'fields': [ + ('title', software_title), + ('general_info', general_info), + ('detail_result_display_fields', software_detail_result_display_fields), + ], + 'template_override_dir': 'access-software-v4', } } PROJECT_TITLE = 'Search Pilot' -APP_VERSION = CONF.get('APP_VERSION', '') +APP_VERSION = CONF.get('APP_VERSION', '') \ No newline at end of file diff --git a/dgpf1/templates/access-software-v4/globus-portal-framework/v2/components/search-results.html b/dgpf1/templates/access-software-v4/globus-portal-framework/v2/components/search-results.html new file mode 100644 index 0000000..f8bbd6a --- /dev/null +++ b/dgpf1/templates/access-software-v4/globus-portal-framework/v2/components/search-results.html @@ -0,0 +1,37 @@ + +{% load static %} +{% load urldecode %} +{% block headextras %}{% endblock %} + +
+
+

Results + {% if search.total %} + + + + {% endif %} +

+ + {% if search.total %} +
{{search.total}} software items found
+ {% endif %} +
+
+ +
+ {% for result in search.search_results %} +
+ +
+ {% if result.general_info.Description %} +

{{ result.general_info.Description }}

+ {% endif %} +
+
+ {% endfor %} +
diff --git a/dgpf1/templates/access-software-v4/globus-portal-framework/v2/detail-overview.html b/dgpf1/templates/access-software-v4/globus-portal-framework/v2/detail-overview.html new file mode 100644 index 0000000..ee50c15 --- /dev/null +++ b/dgpf1/templates/access-software-v4/globus-portal-framework/v2/detail-overview.html @@ -0,0 +1,50 @@ +{% extends 'globus-portal-framework/v2/detail-base.html' %} + + +{% block breadcrumb_items %} + + + +{% endblock %} + + +{% block detail_body %} + +
+
+ + {% block detail_search_content %} +

{{ title|default:'Software' }} — Properties

+ + {% load urldecode %} + + + {% for item in detail_result_display_fields %} + {% if item.value %} + + + + + {% endif %} + {% endfor %} + +
{{ item.display_name }} + {% if item.field_name == "URL" %} + {{ item.value }} + {% elif item.is_list %} +
    + {% for v in item.value %}
  • {{ v }}
  • {% endfor %} +
+ {% else %} + {{ item.value }} + {% endif %} +
+ +
Globus Search Metadata
+ {% include 'globus-portal-framework/v2/components/detail-globus-search-metadata.html' %} + {% endblock %} + +
+
+ +{% endblock %} diff --git a/dgpf1/templates/globus-portal-framework/v2/components/detail-general-metadata.html b/dgpf1/templates/globus-portal-framework/v2/components/detail-general-metadata.html index 300d4d5..28232ef 100644 --- a/dgpf1/templates/globus-portal-framework/v2/components/detail-general-metadata.html +++ b/dgpf1/templates/globus-portal-framework/v2/components/detail-general-metadata.html @@ -1,6 +1,8 @@ +{% load urldecode %} {% block detail_general_metadata %} + {{ request.path|urldecode }} {% for item in detail_result_display_fields %} diff --git a/dgpf1/templates/globus-portal-framework/v2/components/detail-globus-search-metadata.html b/dgpf1/templates/globus-portal-framework/v2/components/detail-globus-search-metadata.html index b8a8d6d..880a1b5 100644 --- a/dgpf1/templates/globus-portal-framework/v2/components/detail-globus-search-metadata.html +++ b/dgpf1/templates/globus-portal-framework/v2/components/detail-globus-search-metadata.html @@ -1,9 +1,9 @@ - +{% load urldecode %}
{{item.display_name}}
- +
subject{{ subject }}{{ subject|urldecode }}
diff --git a/dgpf1/templates/globus-portal-framework/v2/components/search-results.html b/dgpf1/templates/globus-portal-framework/v2/components/search-results.html index 5af7984..dd9a66b 100644 --- a/dgpf1/templates/globus-portal-framework/v2/components/search-results.html +++ b/dgpf1/templates/globus-portal-framework/v2/components/search-results.html @@ -1,5 +1,6 @@ -{% load static %} +{% load static %} +{% load urldecode %} {% block headextras %}{% endblock %}
@@ -23,14 +24,14 @@
{{search.total}} training items found
- {{result.all.0.Abstract|safe}} + {{result.all.0.Abstract|default:result.all.0.Description|safe}} diff --git a/dgpf1/templatetags/custom_tags.py b/dgpf1/templatetags/custom_tags.py new file mode 100644 index 0000000..58b4ad2 --- /dev/null +++ b/dgpf1/templatetags/custom_tags.py @@ -0,0 +1,10 @@ +from django import template +from urllib.parse import unquote + +register = template.Library() + +@register.filter +def urldecode(value): + if value is None: + return value + return unquote(value) \ No newline at end of file