From 3b8f61c2554855a3a82ec37e821a9ca7bcb0566f Mon Sep 17 00:00:00 2001 From: Tom Kralidis Date: Mon, 11 Apr 2016 23:18:00 -0400 Subject: [PATCH 1/2] implement GeoNode CSW-T backend --- geonode/base/models.py | 7 +++++++ geonode/catalogue/backends/pycsw_local.py | 13 +++++++++---- geonode/catalogue/backends/pycsw_local_mappings.py | 4 ++-- geonode/catalogue/views.py | 9 ++++++++- geonode/settings.py | 7 ++++++- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/geonode/base/models.py b/geonode/base/models.py index e20dabc05c2..e7857378af2 100644 --- a/geonode/base/models.py +++ b/geonode/base/models.py @@ -671,6 +671,13 @@ class Meta: ) +class GenericResource(ResourceBase): + remote = models.BooleanField(default=False) + +#class GenericResourceManager(ResourceBaseManager): +# def __init__(self): +# models.Manager.__init__(self) + class LinkManager(models.Manager): """Helper class to access links grouped by type """ diff --git a/geonode/catalogue/backends/pycsw_local.py b/geonode/catalogue/backends/pycsw_local.py index 011137f0ef4..09f7b610493 100644 --- a/geonode/catalogue/backends/pycsw_local.py +++ b/geonode/catalogue/backends/pycsw_local.py @@ -39,7 +39,7 @@ # 'loglevel': 'DEBUG', # 'logfile': '/tmp/pycsw.log', # 'federatedcatalogues': 'http://geo.data.gov/geoportal/csw/discovery', - # 'pretty_print': 'true', + 'pretty_print': 'true', # 'domainquerytype': 'range', 'domaincounts': 'true', 'profiles': 'apiso,ebrim', @@ -127,10 +127,10 @@ def _csw_local_dispatch(self, keywords=None, start=0, limit=10, bbox=None, ident os.environ['QUERY_STRING'] = '' # init pycsw - csw = server.Csw(config) + csw = server.Csw(config, version='2.0.2') # fake HTTP method - csw.requesttype = 'POST' + csw.requesttype = 'GET' # fake HTTP request parameters if identifier is None: # it's a GetRecords request @@ -139,6 +139,8 @@ def _csw_local_dispatch(self, keywords=None, start=0, limit=10, bbox=None, ident formats.append(METADATA_FORMATS[f][0]) csw.kvp = { + 'service': 'CSW', + 'version': '2.0.2', 'elementsetname': 'full', 'typenames': formats, 'resulttype': 'results', @@ -152,7 +154,10 @@ def _csw_local_dispatch(self, keywords=None, start=0, limit=10, bbox=None, ident response = csw.getrecords() else: # it's a GetRecordById request csw.kvp = { - 'id': [identifier], + 'service': 'CSW', + 'version': '2.0.2', + 'request': 'GetRecordById', + 'id': identifier, 'outputschema': 'http://www.isotc211.org/2005/gmd', } # FIXME(Ariel): Remove this try/except block when pycsw deals with diff --git a/geonode/catalogue/backends/pycsw_local_mappings.py b/geonode/catalogue/backends/pycsw_local_mappings.py index 9cac8345260..3047bbd7783 100644 --- a/geonode/catalogue/backends/pycsw_local_mappings.py +++ b/geonode/catalogue/backends/pycsw_local_mappings.py @@ -64,8 +64,8 @@ 'pycsw:OperatesOnIdentifier': 'operatesonidentifier', 'pycsw:OperatesOnName': 'operatesoname', 'pycsw:Degree': 'degree', - 'pycsw:AccessConstraints': 'accessconstraints', - 'pycsw:OtherConstraints': 'otherconstraints', + 'pycsw:AccessConstraints': 'restriction_code_type', + 'pycsw:OtherConstraints': 'constraints_other', 'pycsw:Classification': 'classification', 'pycsw:ConditionApplyingToAccessAndUse': 'conditionapplyingtoaccessanduse', 'pycsw:Lineage': 'lineage', diff --git a/geonode/catalogue/views.py b/geonode/catalogue/views.py index d031f510722..4047356f436 100644 --- a/geonode/catalogue/views.py +++ b/geonode/catalogue/views.py @@ -44,10 +44,17 @@ def csw_global_dispatch(request): env.update({'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri()}) - csw = server.Csw(mdict, env) + csw = server.Csw(mdict, env, version='2.0.2') content = csw.dispatch_wsgi() + # pycsw 2.0 has an API break: + # pycsw < 2.0: content = xml_response + # pycsw >= 2.0: content = [http_status_code, content] + # deal with the API break + if isinstance(content, list): # pycsw 2.0+ + content = content[1] + return HttpResponse(content, content_type=csw.contenttype) diff --git a/geonode/settings.py b/geonode/settings.py index ddabed518d7..efd1149240e 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -593,6 +593,11 @@ 'contact_name': 'Organization Name', 'contact_email': 'Email Address', 'temp_extent': 'YYYY-MM-DD/YYYY-MM-DD', + }, + 'manager': { + 'transactions': 'true', + 'allowed_ips': '127.0.0.1', + #'csw_harvest_pagesize=10', } } } @@ -932,4 +937,4 @@ } baselayers = MAP_BASELAYERS MAP_BASELAYERS = [LOCAL_GEOSERVER] - MAP_BASELAYERS.extend(baselayers) \ No newline at end of file + MAP_BASELAYERS.extend(baselayers) From d60b4e46220671449be858fdb61fe3783f6bfcf5 Mon Sep 17 00:00:00 2001 From: Tom Kralidis Date: Fri, 20 May 2016 15:14:05 -0400 Subject: [PATCH 2/2] add CSW CORS and auth scaffolding for CSW-T --- .../backends/pycsw_local_mappings.py | 2 +- .../catalogue/csw-2.0.2-exception.xml | 6 +++++ geonode/catalogue/views.py | 24 +++++++++++++++++-- geonode/settings.py | 3 ++- 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 geonode/catalogue/templates/catalogue/csw-2.0.2-exception.xml diff --git a/geonode/catalogue/backends/pycsw_local_mappings.py b/geonode/catalogue/backends/pycsw_local_mappings.py index 3047bbd7783..cf4c85e88da 100644 --- a/geonode/catalogue/backends/pycsw_local_mappings.py +++ b/geonode/catalogue/backends/pycsw_local_mappings.py @@ -35,7 +35,7 @@ 'pycsw:Keywords': 'keyword_csv', 'pycsw:KeywordType': 'keywordstype', 'pycsw:Format': 'spatial_representation_type_string', - 'pycsw:Source': 'source', + 'pycsw:Source': 'csw_mdsource', 'pycsw:Date': 'date', 'pycsw:Modified': 'date', 'pycsw:Type': 'csw_type', diff --git a/geonode/catalogue/templates/catalogue/csw-2.0.2-exception.xml b/geonode/catalogue/templates/catalogue/csw-2.0.2-exception.xml new file mode 100644 index 00000000000..fe5b33c0343 --- /dev/null +++ b/geonode/catalogue/templates/catalogue/csw-2.0.2-exception.xml @@ -0,0 +1,6 @@ + + + + {{ exception_text }} + + diff --git a/geonode/catalogue/views.py b/geonode/catalogue/views.py index 4047356f436..e7d8375804d 100644 --- a/geonode/catalogue/views.py +++ b/geonode/catalogue/views.py @@ -21,7 +21,7 @@ import json import os from django.conf import settings -from django.http import HttpResponse, HttpResponseRedirect +from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect from django.shortcuts import render_to_response from django.views.decorators.csrf import csrf_exempt from pycsw import server @@ -38,6 +38,23 @@ def csw_global_dispatch(request): if settings.CATALOGUE['default']['ENGINE'] != 'geonode.catalogue.backends.pycsw_local': return HttpResponseRedirect(settings.CATALOGUE['default']['URL']) +# TODO: add logic for authentication/authorization +# +# msg = None +# +# if any(word in request.body for word in ['Harvest ', 'Transaction ']): +# if not SOME_AUTHENTICATED_TEST: +# msg = 'Not authenticated' +# if not SOME_AUTHORIZATION_TEST: +# msg = 'Not authorized' +# +# if msg is not None: +# template = loader.get_template('catalogue/csw-2.0.2-exception.xml') +# context = RequestContext(request, { +# 'exception_text': msg +# }) +# response = HttpResponseForbidden(template.render(context), content_type='application/xml') + mdict = dict(settings.PYCSW['CONFIGURATION'], **CONFIGURATION) env = request.META.copy() @@ -55,7 +72,10 @@ def csw_global_dispatch(request): if isinstance(content, list): # pycsw 2.0+ content = content[1] - return HttpResponse(content, content_type=csw.contenttype) + response = HttpResponse(content, content_type=csw.contenttype) + + response['Access-Control-Allow-Origin'] = '*' + return response @csrf_exempt diff --git a/geonode/settings.py b/geonode/settings.py index efd1149240e..0c36375c1a3 100644 --- a/geonode/settings.py +++ b/geonode/settings.py @@ -595,8 +595,9 @@ 'temp_extent': 'YYYY-MM-DD/YYYY-MM-DD', }, 'manager': { + # authentication/authorization is handled by Django 'transactions': 'true', - 'allowed_ips': '127.0.0.1', + 'allowed_ips': '*', #'csw_harvest_pagesize=10', } }