Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #35

Merged
merged 9 commits into from
Mar 4, 2024
Merged

Dev #35

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion app/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from rest_framework import serializers

from core.models import SchemaLedger, TermSet, TransformationLedger
from core.models import SchemaLedger, Term, TermSet, TransformationLedger

logger = logging.getLogger('dict_config_logger')

Expand All @@ -27,6 +27,26 @@ class Meta:
fields = ('iri', 'name', 'version', 'schema')


class TermSetJSONLDSerializer(serializers.ModelSerializer):
"""Serializes the TermSet Model"""
graph = serializers.DictField(source='json_ld')

class Meta:
model = TermSet

fields = ('graph',)


class TermJSONLDSerializer(serializers.ModelSerializer):
"""Serializes the TermSet Model"""
graph = serializers.DictField(source='json_ld')

class Meta:
model = Term

fields = ('graph',)


class TransformationLedgerSerializer(serializers.ModelSerializer):
"""Serializes the SchemaLedger Model"""

Expand Down
10 changes: 6 additions & 4 deletions app/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
app_name = 'api'

urlpatterns = [
path('schemas/', views.SchemaLedgerDataView.as_view(),
name='schemaledger'),
path('mappings/', views.TransformationLedgerDataView.as_view(),
name='transformationledger'),
path('schemas/', views.SchemaLedgerDataView.as_view(),
name='schemaledger'),
path('mappings/', views.TransformationLedgerDataView.as_view(),
name='transformationledger'),
path('json-ld/<path:pk>', views.JSONLDDataView.as_view(),
name='json-ld'),
]
88 changes: 81 additions & 7 deletions app/api/views.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import logging

from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.urls import reverse
from requests.exceptions import HTTPError
from rest_framework import status
from rest_framework.generics import GenericAPIView
from rest_framework.generics import GenericAPIView, RetrieveAPIView
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.settings import api_settings

from api.serializers import TermSetSerializer
from api.serializers import (TermJSONLDSerializer, TermSetJSONLDSerializer,
TermSetSerializer)
from core.management.utils.xss_helper import sort_version
from core.models import TermSet
from core.models import Term, TermSet

logger = logging.getLogger('dict_config_logger')

Expand All @@ -24,6 +29,65 @@ def check_status(messages, queryset):
return queryset


class JSONLDRenderer(JSONRenderer):
"""Renderer restricted to JSON-LD"""
media_type = 'application/ld+json'
format = 'jsonld'


class JSONLDDataView(RetrieveAPIView):
"""Handles HTTP requests to for JSON-LD schemas"""
renderer_classes = [JSONLDRenderer, *api_settings.DEFAULT_RENDERER_CLASSES]

def get_queryset(self):
"""
Determines if the requested object is a Term or TermSet and returns
the queryset
"""
# Due to the IRI a term has a '?' so check for a param without a value
if self.request.query_params:
for _, v in self.request.query_params.items():
if len(v) == 0:
return Term.objects.all().filter(status='published')
return TermSet.objects.all().filter(status='published')

def get_serializer_class(self):
"""
Determines if the requested object is a Term or TermSet and returns
the serializer
"""
# Due to the IRI a term has a '?' so check for a param without a value
if self.request.query_params:
for _, v in self.request.query_params.items():
if len(v) == 0:
return TermSetJSONLDSerializer
return TermJSONLDSerializer

def retrieve(self, request, *args, **kwargs):
"""
Return a JSON-LD representation of the requested object
"""
# Due to the IRI a term has a '?' so check for a param without a value
if self.request.query_params:
for k, v in self.request.query_params.items():
if len(v) == 0:
self.kwargs['pk'] = self.kwargs['pk'] + \
'?' + k
break
# get the specific object and serializer
instance = self.get_object()
serializer = self.get_serializer(instance)
# generated JSON-LD is stored as a python dict labeled 'graph'
ld_dict = serializer.data['graph']
# build the external URL to this API and add it to the context
ldss = request.build_absolute_uri(
reverse('api:json-ld', args=[1]))[:-1]
if hasattr(settings, 'BAD_HOST') and hasattr(settings, 'OVERIDE_HOST'):
ldss = ldss.replace(settings.BAD_HOST, settings.OVERIDE_HOST)
ld_dict['@context']['ldss'] = ldss
return Response(ld_dict)


class SchemaLedgerDataView(GenericAPIView):
"""Handles HTTP requests to the Schema Ledger"""

Expand Down Expand Up @@ -89,14 +153,11 @@ def get(self, request):
logger.error(messages)
return Response(errorMsg, status.HTTP_400_BAD_REQUEST)
try:
serializer_class = TermSetSerializer(queryset[0])
logger.info(queryset[0])
# only way messages gets sent is if there was
# an error serializing or in the response process.
messages.append(
"Error fetching records please check the logs.")
return Response(serializer_class.data,
status.HTTP_200_OK)
return self.handle_response(queryset)
except ObjectDoesNotExist:
errorMsg = {
"message": messages
Expand All @@ -111,6 +172,19 @@ def get(self, request):
return Response(errorMsg,
status.HTTP_500_INTERNAL_SERVER_ERROR)

def handle_response(self, queryset):
serializer_class = TermSetSerializer(queryset[0])
logger.info(queryset[0])
# could be used to add link header if needed
# if 'format' in request.query_params:
# link = '<%s>;' % request.get_full_path().replace(
# request.query_params.get('format'), 'jsonld')
# else:
# link = f'<{request.get_full_path()}>;'
# link += ' rel="alternate"; type="application/ld+json"'
return Response(serializer_class.data,
status.HTTP_200_OK)


class TransformationLedgerDataView(GenericAPIView):
"""Handles HTTP requests to the Transformation Ledger"""
Expand Down
65 changes: 65 additions & 0 deletions app/core/fixtures/admin_theme_data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
[
{
"model": "admin_interface.theme",
"pk": 1,
"fields": {
"name": "XSS Configuration Portal",
"active": true,
"title": "XSS Configuration Portal",
"title_color": "#FFFFFF",
"title_visible": true,
"logo": "admin-interface/logo/dodLogo_50.png",
"logo_color": "#FFFFFF",
"logo_max_width": 100,
"logo_max_height": 100,
"logo_visible": true,
"favicon": "admin-interface/favicon/dodLogo_50.png",
"env_name": "",
"env_color": "#077391",
"env_visible_in_header": true,
"env_visible_in_favicon": false,
"language_chooser_active": true,
"language_chooser_control": "default-select",
"language_chooser_display": "name",
"css_header_background_color": "#077391",
"css_header_text_color": "#E7F8FD",
"css_header_link_color": "#FFFFFF",
"css_header_link_hover_color": "#C9F0DD",
"css_module_background_color": "#077391",
"css_module_background_selected_color": "#B9E5F5",
"css_module_text_color": "#FFFFFF",
"css_module_link_color": "#FFFFFF",
"css_module_link_selected_color": "#FFFFFF",
"css_module_link_hover_color": "#C9F0DD",
"css_module_rounded_corners": true,
"css_generic_link_color": "#077391",
"css_generic_link_hover_color": "#09A3CE",
"css_generic_link_active_color": "#05556B",
"css_save_button_background_color": "#077391",
"css_save_button_background_hover_color": "#09A3CE",
"css_save_button_text_color": "#FFFFFF",
"css_delete_button_background_color": "#BA2121",
"css_delete_button_background_hover_color": "#A41515",
"css_delete_button_text_color": "#FFFFFF",
"related_modal_active": true,
"related_modal_background_color": "#000000",
"related_modal_background_opacity": "0.3",
"related_modal_rounded_corners": true,
"related_modal_close_button_visible": true,
"list_filter_highlight": true,
"list_filter_dropdown": true,
"list_filter_sticky": true,
"list_filter_removal_links": false,
"foldable_apps": true,
"show_fieldsets_as_tabs": false,
"show_inlines_as_tabs": false,
"collapsible_stacked_inlines": false,
"collapsible_stacked_inlines_collapsed": true,
"collapsible_tabular_inlines": false,
"collapsible_tabular_inlines_collapsed": true,
"recent_actions_visible": true,
"form_submit_sticky": false,
"form_pagination_sticky": false
}
}
]
68 changes: 67 additions & 1 deletion app/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
logger = logging.getLogger('dict_config_logger')


data_type_matching = {
'str': 'schema:Text',
'int': 'schema:Number',
'bool': 'schema:Boolean',
'datetime': 'schema:DateTime'
}
regex_check = (r'(?!(\A( \x09\x0A\x0D\x20-\x7E # ASCII '
r'| \xC2-\xDF # non-overlong 2-byte '
r'| \xE0\xA0-\xBF # excluding overlongs '
Expand Down Expand Up @@ -67,6 +73,40 @@ def export(self):
for term in self.terms.filter(status='published')}
return {**children, **terms}

def json_ld(self):
"""Generate python representation of JSON-LD"""
# create graph and context dicts
graph = {}
context = {}
# add elements to graph and context
graph['@id'] = 'ldss:' + self.iri
graph['@type'] = 'rdfs:Class'
graph['rdfs:label'] = self.name
context['rdfs'] = 'http://www.w3.org/2000/01/rdf-schema#'
if hasattr(self, 'childtermset'):
graph['schema:domainIncludes'] = {
'@id': 'ldss:' +
self.childtermset.parent_term_set.iri}
context['schema'] = 'https://schema.org/'
# iterate over child term sets and collect their graphs and contexts
children = []
for kid in self.children.filter(status='published'):
kid_ld = kid.json_ld()
children.extend(kid_ld['@graph'])
# add children's context to current context, but current has
# higher priority
context = {**kid_ld['@context'], **context}
# iterate over terms and collect their graphs and contexts
terms = []
for term in self.terms.filter(status='published'):
term_ld = term.json_ld()
terms.extend(term_ld['@graph'])
# add terms' context to current context, but current has higher
# priority
context = {**term_ld['@context'], **context}
# return the graph and context
return {'@context': context, '@graph': [graph, *children, *terms]}

def mapped_to(self, target_root):
"""Return dict of Terms mapped to anything in target_root string"""

Expand Down Expand Up @@ -152,6 +192,32 @@ def export(self):
attrs['description'] = self.description
return {**attrs}

def json_ld(self):
"""Generate python representation of JSON-LD"""
# create graph and context dicts
graph = {}
context = {}
# add elements to graph and context
graph['@id'] = 'ldss:' + self.iri
graph['@type'] = 'rdf:Property'
if self.description is not None and len(self.description.strip()) > 0:
graph['rdfs:comment'] = self.description
if self.data_type is not None and len(self.data_type.strip()) > 0 and\
self.data_type in data_type_matching:
graph['schema:rangeIncludes'] = {
'@id': data_type_matching[self.data_type]}
if self.mapping.exists():
graph['owl:equivalentProperty'] = [
{'@id': 'ldss:' + alt.iri} for alt in self.mapping.all()]
context['owl'] = 'http://www.w3.org/2002/07/owl#'
graph['rdfs:label'] = self.name
graph['schema:domainIncludes'] = {'@id': 'ldss:' + self.term_set.iri}
context['schema'] = 'https://schema.org/'
context['rdfs'] = 'http://www.w3.org/2000/01/rdf-schema#'
context['rdf'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
# return the graph and context
return {'@context': context, '@graph': [graph, ]}

def path(self):
"""Get the path of the Term"""
path = self.name
Expand Down Expand Up @@ -231,7 +297,7 @@ def clean(self):
logger.error(
'%s %s in xss:%s@%s',
issue_type, issue, self.version, self.schema_name
)
)
# only load json if no issues found
else:
# rewind buffer
Expand Down
Binary file added app/media/admin-interface/favicon/dodLogo_50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/media/admin-interface/logo/dodLogo_50.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions app/openlxp_xss_project/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
# Application definition

INSTALLED_APPS = [
"admin_interface",
"colorfield",
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
Expand Down
Loading
Loading