def csw_global_dispatch(request): """pycsw wrapper""" # this view should only operate if pycsw_local is the backend # else, redirect to the URL of the non-pycsw_local backend if settings.CATALOGUE['default'][ 'ENGINE'] != 'geonode.catalogue.backends.pycsw_local': return HttpResponseRedirect(settings.CATALOGUE['default']['URL']) mdict = dict(settings.PYCSW['CONFIGURATION'], **CONFIGURATION) env = request.META.copy() env.update({ 'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri() }) 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)
def csw_view(request, catalog=None): """CSW dispatch view. Wraps the WSGI call and allows us to tweak any django settings. """ env = request.META.copy() env.update({ 'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri() }) # pycsw prefers absolute urls, let's get them from the request. url = request.build_absolute_uri() PYCSW['server']['url'] = url PYCSW['metadata:main']['provider_url'] = url csw = server.Csw(PYCSW, env) status, content = csw.dispatch_wsgi() status_code = int(status[0:3]) response = HttpResponse( content, content_type=csw.contenttype, status=status_code, ) return response
def application(env, start_response): """WSGI wrapper""" print(env['PATH_INFO']) pycsw_root = get_pycsw_root_path(os.environ, env) configuration_path = get_configuration_path(os.environ, env, pycsw_root) env['local.app_root'] = pycsw_root if 'HTTP_HOST' in env and ':' in env['HTTP_HOST']: env['HTTP_HOST'] = env['HTTP_HOST'].split(':')[0] csw = server.Csw(configuration_path, env) status, contents = csw.dispatch_wsgi() headers = { 'Content-Length': str(len(contents)), 'Content-Type': str(csw.contenttype) } if "gzip" in env.get("HTTP_ACCEPT_ENCODING", ""): try: compression_level = int( csw.config.get("server", "gzip_compresslevel")) contents, compress_headers = compress_response( contents, compression_level) headers.update(compress_headers) except configparser.NoOptionError: print( "The client requested a gzip compressed response. However, " "the server does not specify the 'gzip_compresslevel' option. " "Returning an uncompressed response...") except configparser.NoSectionError: print('Could not load user configuration %s' % configuration_path) start_response(status, list(headers.items())) return [contents]
def csw_global_dispatch_by_catalog(request, catalog_slug): """pycsw wrapper""" catalog = get_object_or_404(Catalog, slug=catalog_slug) # TODO: Implement pycsw per catalog if catalog: pass env = request.META.copy() env.update({'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri()}) csw = server.Csw(settings.PYCSW, 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] response = HttpResponse(content, content_type=csw.contenttype) response['Access-Control-Allow-Origin'] = '*' return response
def csw(request): """CSW WSGI wrapper""" # serialize settings.CSW into SafeConfigParser # object for interaction with pycsw mdict = dict(settings.CSW, **CONFIGURATION) # update server.url server_url = '%s://%s%s' % \ (request.META['wsgi.url_scheme'], request.META['HTTP_HOST'], request.META['PATH_INFO']) mdict['server']['url'] = server_url env = request.META.copy() env.update({ 'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri(), }) csw = server.Csw(mdict, env) content = csw.dispatch_wsgi() return HttpResponse(content, content_type=csw.contenttype)
def csw(request): """CSW WSGI wrapper""" # serialize settings.CSW into SafeConfigParser # object for interaction with pycsw mdict = dict(settings.CSW, **CONFIGURATION) # TODO: pass just dict when pycsw supports it config = SafeConfigParser() for section, options in mdict.iteritems(): config.add_section(section) for k, v in options.iteritems(): config.set(section, k, v) # update server.url server_url = '%s://%s%s' % \ (request.META['wsgi.url_scheme'], request.META['HTTP_HOST'], request.META['PATH_INFO']) config.set('server', 'url', server_url) env = request.META.copy() env.update({ 'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri(), }) csw = server.Csw(config, env) content = csw.dispatch_wsgi() return HttpResponse(content, content_type=csw.contenttype)
def csw_global_dispatch(request): """pycsw wrapper""" # this view should only operate if pycsw_local is the backend # else, redirect to the URL of the non-pycsw_local backend if (settings.CATALOGUE['default']['ENGINE'] != 'geonode.catalogue.backends.pycsw_local'): return HttpResponseRedirect(settings.CATALOGUE['default']['URL']) # serialize pycsw settings into SafeConfigParser # object for interaction with pycsw # TODO: pass just dict when pycsw supports it mdict = dict(settings.PYCSW['CONFIGURATION'], **CONFIGURATION) config = SafeConfigParser() for section, options in mdict.iteritems(): config.add_section(section) for option, value in options.iteritems(): config.set(section, option, value) env = request.META.copy() env.update({ 'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri(), }) csw = server.Csw(config, env) content = csw.dispatch_wsgi() return HttpResponse(content, content_type=csw.contenttype)
def application(env, start_response): """WSGI wrapper""" config = 'default.cfg' if 'PYCSW_CONFIG' in env: config = env['PYCSW_CONFIG'] if env['QUERY_STRING'].lower().find('config') != -1: for kvp in env['QUERY_STRING'].split('&'): if kvp.lower().find('config') != -1: config = kvp.split('=')[1] if not os.path.isabs(config): config = os.path.join(app_path, config) if 'HTTP_HOST' in env and ':' in env['HTTP_HOST']: env['HTTP_HOST'] = env['HTTP_HOST'].split(':')[0] env['local.app_root'] = app_path csw = server.Csw(config, env) gzip = False if ('HTTP_ACCEPT_ENCODING' in env and env['HTTP_ACCEPT_ENCODING'].find('gzip') != -1): # set for gzip compressed response gzip = True # set compression level if csw.config.has_option('server', 'gzip_compresslevel'): gzip_compresslevel = \ int(csw.config.get('server', 'gzip_compresslevel')) else: gzip_compresslevel = 0 contents = csw.dispatch_wsgi() headers = {} if gzip and gzip_compresslevel > 0: import gzip buf = StringIO() gzipfile = gzip.GzipFile(mode='wb', fileobj=buf, compresslevel=gzip_compresslevel) gzipfile.write(contents) gzipfile.close() contents = buf.getvalue() headers['Content-Encoding'] = 'gzip' headers['Content-Length'] = str(len(contents)) headers['Content-Type'] = csw.contenttype status = '200 OK' start_response(status, headers.items()) return [contents]
def test_suites(test_identifier, use_xml_canonicalisation, save_results_directory, configuration, request_method, request_data, expected_result, normalize_identifier_fields): """Test suites. This function is automatically parametrized by pytest as a result of the ``conftest:pytest_generate_tests`` function. The input parameters are thus supplied by pytest as a result of discovering and parsing the existing test suites located under ``tests/functionaltests/suites``. Parameters ---------- configuration: SafeConfigParser The configuration to use with the pycsw server instance under test request_method: str The HTTP method of the request. Either GET or POST. request_data: str Either the path to the request file, for POST requests, or the request parameters, for GET requests expected_result: str Path to the file that holds the expected result normalize_identifier_fields: bool Whether to normalize the identifier fields in responses. This parameter is used only in the 'harvesting' and 'manager' suites use_xml_canonicalisation: bool Whether to compare results with their expected values by using xml canonicalisation or simply by doing a diff. save_results_directory: str Path to a directory where to test results should be saved to. A value of ``None`` (the default) means that results will not get saved to disk. """ request_environment = _prepare_wsgi_test_environment( request_method, request_data) pycsw_server = server.Csw(rtconfig=configuration, env=request_environment) encoding = "utf-8" status, raw_contents = pycsw_server.dispatch_wsgi() contents = raw_contents.decode(encoding) with codecs.open(expected_result, encoding=encoding) as fh: expected = fh.read() normalized_result = _normalize( contents, normalize_identifiers=normalize_identifier_fields) if use_xml_canonicalisation: print("Comparing results using XML canonicalization...") matches_expected = _compare_with_xml_canonicalisation( normalized_result, expected) else: print("Comparing results using diffs...") matches_expected = _compare_without_xml_canonicalisation( normalized_result, expected) if not matches_expected and use_xml_canonicalisation: print("expected: {0}".format(expected)) print("response: {0}".format(normalized_result)) if save_results_directory is not None: _save_test_result(save_results_directory, normalized_result, test_identifier, encoding) assert matches_expected
def csw_global_dispatch(request, url=None, catalog_id=None): """pycsw wrapper""" msg = None # test for authentication and authorization if any(word in request.body for word in ['Harvest ', 'Transaction ']): if not _is_authenticated(): msg = 'Not authenticated' if not _is_authorized(): msg = 'Not authorized' if msg is not None: template = loader.get_template('search/csw-2.0.2-exception.xml') context = RequestContext(request, {'exception_text': msg}) return HttpResponseForbidden(template.render(context), content_type='application/xml') env = request.META.copy() # TODO: remove this workaround # HH should be able to pass env['wsgi.input'] without hanging # details at https://github.com/cga-harvard/HHypermap/issues/94 if request.method == 'POST': from StringIO import StringIO env['wsgi.input'] = StringIO(request.body) env.update({ 'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri() }) # if this is a catalog based CSW, then update settings if url is not None: settings.REGISTRY_PYCSW['server']['url'] = url if catalog_id is not None: settings.REGISTRY_PYCSW['repository'][ 'filter'] = 'catalog_id = %d' % catalog_id csw = server.Csw(settings.REGISTRY_PYCSW, env) 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] response = HttpResponse(content, content_type=csw.contenttype) # TODO: Fix before 1.0 release. CORS should not be enabled blindly like this. response['Access-Control-Allow-Origin'] = '*' return response
def _csw_local_dispatch(self, keywords=None, start=0, limit=10, bbox=None, identifier=None): """ HTTP-less CSW """ # serialize pycsw settings into SafeConfigParser # object for interaction with pycsw mdict = dict(settings.PYCSW['CONFIGURATION'], **CONFIGURATION) config = SafeConfigParser() for section, options in mdict.iteritems(): config.add_section(section) for option, value in options.iteritems(): config.set(section, option, value) # fake HTTP environment variable os.environ['QUERY_STRING'] = '' # init pycsw csw = server.Csw(config) # fake HTTP method csw.requesttype = 'POST' # fake HTTP request parameters if identifier is None: # it's a GetRecords request formats = [] for f in self.catalogue.formats: formats.append(METADATA_FORMATS[f][0]) csw.kvp = { 'elementsetname': 'full', 'typenames': formats, 'resulttype': 'results', 'constraintlanguage': 'CQL_TEXT', 'constraint': 'csw:AnyText like "%%%s%%"' % keywords, 'outputschema': 'http://www.isotc211.org/2005/gmd', 'constraint': None, 'startposition': start, 'maxrecords': limit } response = csw.getrecords() else: # it's a GetRecordById request csw.kvp = { 'id': [identifier], 'outputschema': 'http://www.isotc211.org/2005/gmd', } # FIXME(Ariel): Remove this try/except block when pycsw deals with # empty geometry fields better. # https://gist.github.com/ingenieroariel/717bb720a201030e9b3a try: response = csw.getrecordbyid() except ReadingError: return [] return etree.tostring(response)
def test_suites(configuration, request_method, request_data, expected_result, normalize_identifier_fields): """Test suites. This function is automatically parametrized by pytest as a result of the ``conftest:pytest_generate_tests`` function. The input parameters are thus supplied by pytest as a result of discovering and parsing the existing test suites located under ``tests/functionaltests/suites``. Parameters ---------- configuration: SafeConfigParser The configuration to use with the pycsw server instance under test request_method: str The HTTP method of the request. Either GET or POST. request_data: str Either the path to the request file, for POST requests, or the request parameters, for GET requests expected_result: str Path to the file that holds the expected result normalize_identifier_fields: bool Whether to normalize the identifier fields in responses. This parameter is used only in the 'harvesting' and 'manager' suites """ request_environment = _prepare_wsgi_test_environment(request_method, request_data) pycsw_server = server.Csw(rtconfig=configuration, env=request_environment) encoding = "utf-8" status, raw_contents = pycsw_server.dispatch_wsgi() contents = raw_contents.decode(encoding) with codecs.open(expected_result, encoding=encoding) as fh: expected = fh.read() normalized_result = _normalize( contents, normalize_identifiers=normalize_identifier_fields ) try: matches_expected = _test_xml_result(normalized_result, expected) except etree.XMLSyntaxError: # the file is either not XML (perhaps JSON?) or malformed matches_expected = _test_json_result(normalized_result, expected) except etree.C14NError: print("XML canonicalization has failed. Trying to compare result " "with expected using difflib") matches_expected = _test_xml_diff(normalized_result, expected) if not matches_expected: #print("expected: {0}".format(expected.encode(encoding))) #print("response: {0}".format(normalized_result.encode(encoding))) print("expected: {0}".format(expected)) print("response: {0}".format(normalized_result)) assert matches_expected
def post_response(self, request_body): """ Utility function to retrieve POST response from PyCSW Keyword Parameters: request_body -- Bytes representing the body of the HTTP POST Exceptions: TempRepoLocked -- raised when PyCSW repo is under construction by another thread or process & is not available for this call. """ pycsw_config = self.get_config() self._build_repo_if_missing() csw = server.Csw(pycsw_config, self.env) csw.requesttype = 'POST' csw.request = request_body return csw.dispatch()
def csw_global_dispatch(request, url=None, catalog_id=None): """pycsw wrapper""" if request.user.is_authenticated(): # turn on CSW-T settings.REGISTRY_PYCSW['manager']['transactions'] = 'true' env = request.META.copy() # TODO: remove this workaround # HH should be able to pass env['wsgi.input'] without hanging # details at https://github.com/cga-harvard/HHypermap/issues/94 if request.method == 'POST': from StringIO import StringIO env['wsgi.input'] = StringIO(request.body) env.update({ 'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri() }) # if this is a catalog based CSW, then update settings if url is not None: settings.REGISTRY_PYCSW['server']['url'] = url if catalog_id is not None: settings.REGISTRY_PYCSW['repository'][ 'filter'] = 'catalog_id = %d' % catalog_id csw = server.Csw(settings.REGISTRY_PYCSW, env) 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] response = HttpResponse(content, content_type=csw.contenttype) # TODO: Fix before 1.0 release. CORS should not be enabled blindly like this. response['Access-Control-Allow-Origin'] = '*' return response
def csw_global_dispatch(request): """pycsw wrapper""" # this view should only operate if pycsw_local is the backend # else, redirect to the URL of the non-pycsw_local backend if settings.CATALOGUE['default']['ENGINE'] != 'geonode.catalogue.backends.pycsw_local': return HttpResponseRedirect(settings.CATALOGUE['default']['URL']) mdict = dict(settings.PYCSW['CONFIGURATION'], **CONFIGURATION) env = request.META.copy() env.update({'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri()}) csw = server.Csw(mdict, env) content = csw.dispatch_wsgi() return HttpResponse(content, content_type=csw.contenttype)
def csw_view(request, catalog=None): """CSW dispatch view. Wraps the WSGI call and allows us to tweak any django settings. """ # PUT creates catalog, DELETE removes catalog. # GET and POST are managed by pycsw. if catalog and request.META['REQUEST_METHOD'] == 'PUT': message = create_index(catalog) return HttpResponse(message, status=200) if catalog and request.META['REQUEST_METHOD'] == 'DELETE': message, status = delete_index(catalog) return HttpResponse(message, status=status) env = request.META.copy() env.update({ 'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri() }) # pycsw prefers absolute urls, let's get them from the request. url = request.build_absolute_uri() PYCSW['server']['url'] = url PYCSW['metadata:main']['provider_url'] = url # Enable CSW-T when a catalog is defined in the if catalog: PYCSW['manager']['transactions'] = 'true' csw = server.Csw(PYCSW, env) status, content = csw.dispatch_wsgi() status_code = int(status[0:3]) response = HttpResponse( content, content_type=csw.contenttype, status=status_code, ) return response
def get_response(self, request_url, query_string_parameters): """ Utility function to retrieve GET response from PyCSW Keyword Parameters: request_url -- String representation of the full-URL for this HTTP GET request query_string_parameters -- Dictionary, representing the 'request_url' query string key/value pairs Exceptions: TempRepoLocked -- raised when PyCSW repo is under construction by another thread or process & is not available for this call. """ pycsw_config = self.get_config() self._build_repo_if_missing() csw = server.Csw(pycsw_config, self.env) csw.requesttype = 'GET' csw.request = request_url csw.kvp = query_string_parameters return csw.dispatch()
def csw_global_dispatch(request): """pycsw wrapper""" msg = None # test for authentication and authorization if any(word in request.body for word in ['Harvest ', 'Transaction ']): if not _is_authenticated(): msg = 'Not authenticated' if not _is_authorized(): msg = 'Not authorized' if msg is not None: template = loader.get_template('search/csw-2.0.2-exception.xml') context = RequestContext(request, { 'exception_text': msg }) return HttpResponseForbidden(template.render(context), content_type='application/xml') env = request.META.copy() env.update({'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': request.build_absolute_uri()}) csw = server.Csw(settings.PYCSW, 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] response = HttpResponse(content, content_type=csw.contenttype) response['Access-Control-Allow-Origin'] = '*' return response
def csw(self, *args, **kwargs): """Wrapper around pycsw for dispatching CSW requests""" # Cycle through the CONFIGURATION dictionary and push the params into the config object config = SafeConfigParser() for section, options in CONFIGURATION.iteritems(): config.add_section(section) for k, v in options.iteritems(): config.set(section, k, v) # Calculate and insert the server URL into the config server_url = 'http://%s%s' % \ (kwargs["environ"]['HTTP_HOST'], kwargs["environ"]['PATH_INFO']) config.set('server', 'url', server_url) # Make a copy of the WSGI request environment and add parameters env = kwargs["environ"].copy() query = kwargs["environ"]["QUERY_STRING"] if query != "": absolute_uri = "%s?%s" % (server_url, query) else: absolute_uri = server_url env.update({ 'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': absolute_uri }) # Create an instance of pycsw's CSW class to handle the request csw = server.Csw(config, env) # Run the request content = csw.dispatch_wsgi() # Set the response Content-type, and return the result kwargs["pylons"].response.content_type = csw.contenttype return content
def csw_global_dispatch(request): """pycsw wrapper""" # this view should only operate if pycsw_local is the backend # else, redirect to the URL of the non-pycsw_local backend if settings.CATALOGUE['default']['ENGINE'] != 'geonode.catalogue.backends.pycsw_local': return HttpResponseRedirect(settings.CATALOGUE['default']['URL']) mdict = dict(settings.PYCSW['CONFIGURATION'], **CONFIGURATION) access_token = None if request and request.user: access_token = get_or_create_token(request.user) if access_token and access_token.is_expired(): access_token = None absolute_uri = ('%s' % request.build_absolute_uri()) query_string = ('%s' % request.META['QUERY_STRING']) env = request.META.copy() if access_token and not access_token.is_expired(): env.update({'access_token': access_token.token}) if 'access_token' not in query_string: absolute_uri = ('%s&access_token=%s' % (absolute_uri, access_token.token)) query_string = ('%s&access_token=%s' % (query_string, access_token.token)) env.update({'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': absolute_uri, 'QUERY_STRING': query_string}) # Save original filter before doing anything mdict_filter = mdict['repository']['filter'] try: # Filter out Layers not accessible to the User authorized_ids = [] if request.user: profiles = Profile.objects.filter(username=str(request.user)) else: profiles = Profile.objects.filter(username="******") if profiles: authorized = list( get_objects_for_user( profiles[0], 'base.view_resourcebase').values('id')) layers = ResourceBase.objects.filter( id__in=[d['id'] for d in authorized]) if layers: authorized_ids = [d['id'] for d in authorized] if len(authorized_ids) > 0: authorized_layers = "(" + (", ".join(str(e) for e in authorized_ids)) + ")" authorized_layers_filter = "id IN " + authorized_layers mdict['repository']['filter'] += " AND " + authorized_layers_filter if request.user and request.user.is_authenticated: mdict['repository']['filter'] = "({}) OR ({})".format(mdict['repository']['filter'], authorized_layers_filter) else: authorized_layers_filter = "id = -9999" mdict['repository']['filter'] += " AND " + authorized_layers_filter # Filter out Documents and Maps if 'ALTERNATES_ONLY' in settings.CATALOGUE['default'] and settings.CATALOGUE['default']['ALTERNATES_ONLY']: mdict['repository']['filter'] += " AND alternate IS NOT NULL" # Filter out Layers belonging to specific Groups is_admin = False if request.user: is_admin = request.user.is_superuser if request.user else False if not is_admin and settings.GROUP_PRIVATE_RESOURCES: groups_ids = [] if request.user and request.user.is_authenticated: for group in request.user.groups.all(): groups_ids.append(group.id) group_list_all = [] try: group_list_all = request.user.group_list_all().values('group') except BaseException: pass for group in group_list_all: if isinstance(group, dict): if 'group' in group: groups_ids.append(group['group']) else: groups_ids.append(group.id) public_groups = GroupProfile.objects.exclude( access="private").values('group') for group in public_groups: if isinstance(group, dict): if 'group' in group: groups_ids.append(group['group']) else: groups_ids.append(group.id) if len(groups_ids) > 0: groups = "(" + (", ".join(str(e) for e in groups_ids)) + ")" groups_filter = "(group_id IS NULL OR group_id IN " + groups + ")" mdict['repository']['filter'] += " AND " + groups_filter else: groups_filter = "group_id IS NULL" mdict['repository']['filter'] += " AND " + groups_filter 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] spaces = {'csw': 'http://www.opengis.net/cat/csw/2.0.2', 'dc': 'http://purl.org/dc/elements/1.1/', 'dct': 'http://purl.org/dc/terms/', 'gmd': 'http://www.isotc211.org/2005/gmd', 'gml': 'http://www.opengis.net/gml', 'ows': 'http://www.opengis.net/ows', 'xs': 'http://www.w3.org/2001/XMLSchema', 'xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'ogc': 'http://www.opengis.net/ogc', 'gco': 'http://www.isotc211.org/2005/gco', 'gmi': 'http://www.isotc211.org/2005/gmi'} for prefix, uri in spaces.items(): ET.register_namespace(prefix, uri) if access_token and not access_token.is_expired(): tree = dlxml.fromstring(content) for online_resource in tree.findall( '*//gmd:CI_OnlineResource', spaces): try: linkage = online_resource.find('gmd:linkage', spaces) for url in linkage.findall('gmd:URL', spaces): if url.text: if '?' not in url.text: url.text += "?" else: url.text += "&" url.text += ("access_token=%s" % (access_token.token)) url.set('updated', 'yes') except BaseException: pass content = ET.tostring(tree, encoding='utf8', method='xml') finally: # Restore original filter before doing anything mdict['repository']['filter'] = mdict_filter return HttpResponse(content, content_type=csw.contenttype)
def csw_global_dispatch(request, layer_filter=None, config_updater=None): """pycsw wrapper""" # this view should only operate if pycsw_local is the backend # else, redirect to the URL of the non-pycsw_local backend if settings.CATALOGUE['default'][ 'ENGINE'] != 'geonode.catalogue.backends.pycsw_local': return HttpResponseRedirect(settings.CATALOGUE['default']['URL']) mdict = dict(settings.PYCSW['CONFIGURATION'], **CONFIGURATION) mdict = config_updater(mdict) if config_updater else mdict access_token = None if request and request.user: access_token = get_or_create_token(request.user) if access_token and access_token.is_expired(): access_token = None absolute_uri = f'{request.build_absolute_uri()}' query_string = f"{request.META['QUERY_STRING']}" env = request.META.copy() if access_token and not access_token.is_expired(): env.update({'access_token': access_token.token}) if 'access_token' not in query_string: absolute_uri = f'{absolute_uri}&access_token={access_token.token}' query_string = f'{query_string}&access_token={access_token.token}' env.update({ 'local.app_root': os.path.dirname(__file__), 'REQUEST_URI': absolute_uri, 'QUERY_STRING': query_string }) # Save original filter before doing anything mdict_filter = mdict['repository']['filter'] try: # Filter out Layers not accessible to the User authorized_ids = [] if request.user: profiles = get_user_model().objects.filter( username=str(request.user)) else: profiles = get_user_model().objects.filter( username="******") if profiles: authorized = list( get_objects_for_user(profiles[0], 'base.view_resourcebase').values('id')) layers = ResourceBase.objects.filter( id__in=[d['id'] for d in authorized]) if layer_filter and layers: layers = layer_filter(layers) if layers: authorized_ids = [d.id for d in layers] if len(authorized_ids) > 0: authorized_layers = "(" + (", ".join( str(e) for e in authorized_ids)) + ")" authorized_layers_filter = "id IN " + authorized_layers mdict['repository']['filter'] += " AND " + authorized_layers_filter if request.user and request.user.is_authenticated: mdict['repository'][ 'filter'] = f"({mdict['repository']['filter']}) OR ({authorized_layers_filter})" else: authorized_layers_filter = "id = -9999" mdict['repository']['filter'] += " AND " + authorized_layers_filter # Filter out Documents and Maps if 'ALTERNATES_ONLY' in settings.CATALOGUE[ 'default'] and settings.CATALOGUE['default']['ALTERNATES_ONLY']: mdict['repository']['filter'] += " AND alternate IS NOT NULL" # Filter out Layers belonging to specific Groups is_admin = False if request.user: is_admin = request.user.is_superuser if request.user else False if not is_admin and settings.GROUP_PRIVATE_RESOURCES: groups_ids = [] if request.user and request.user.is_authenticated: for group in request.user.groups.all(): groups_ids.append(group.id) group_list_all = [] try: group_list_all = request.user.group_list_all().values( 'group') except Exception: pass for group in group_list_all: if isinstance(group, dict): if 'group' in group: groups_ids.append(group['group']) else: groups_ids.append(group.id) public_groups = GroupProfile.objects.exclude( access="private").values('group') for group in public_groups: if isinstance(group, dict): if 'group' in group: groups_ids.append(group['group']) else: groups_ids.append(group.id) if len(groups_ids) > 0: groups = "(" + (", ".join(str(e) for e in groups_ids)) + ")" groups_filter = "(group_id IS NULL OR group_id IN " + groups + ")" mdict['repository']['filter'] += " AND " + groups_filter else: groups_filter = "group_id IS NULL" mdict['repository']['filter'] += " AND " + groups_filter 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] finally: # Restore original filter before doing anything mdict['repository']['filter'] = mdict_filter return HttpResponse(content, content_type=csw.contenttype)
GZIP = False if os.environ.has_key('PYCSW_CONFIG'): CONFIG = os.environ['PYCSW_CONFIG'] if os.environ['QUERY_STRING'].lower().find('config') != -1: for kvp in os.environ['QUERY_STRING'].split('&'): if kvp.lower().find('config') != -1: CONFIG = kvp.split('=')[1] if (os.environ.has_key('HTTP_ACCEPT_ENCODING') and os.environ['HTTP_ACCEPT_ENCODING'].find('gzip') != -1): # set for gzip compressed response GZIP = True # get runtime configuration CSW = server.Csw(CONFIG) # set compression level if CSW.config.has_option('server', 'gzip_compresslevel'): GZIP_COMPRESSLEVEL = \ int(CSW.config.get('server', 'gzip_compresslevel')) else: GZIP_COMPRESSLEVEL = 0 # go! OUTP = CSW.dispatch_cgi() sys.stdout.write("Content-Type:%s\r\n" % CSW.contenttype) if GZIP and GZIP_COMPRESSLEVEL > 0: import gzip
def _csw_local_dispatch(self, keywords=None, start=0, limit=10, bbox=None, identifier=None): """ HTTP-less CSW """ # serialize pycsw settings into SafeConfigParser # object for interaction with pycsw mdict = dict(settings.PYCSW['CONFIGURATION'], **CONFIGURATION) if 'server' in settings.PYCSW['CONFIGURATION']: # override server system defaults with user specified directives mdict['server'].update(settings.PYCSW['CONFIGURATION']['server']) config = SafeConfigParser() for section, options in mdict.iteritems(): config.add_section(section) for option, value in options.iteritems(): config.set(section, option, value) # fake HTTP environment variable os.environ['QUERY_STRING'] = '' # init pycsw csw = server.Csw(config, version='2.0.2') # fake HTTP method csw.requesttype = 'GET' # fake HTTP request parameters if identifier is None: # it's a GetRecords request formats = [] for f in self.catalogue.formats: formats.append(METADATA_FORMATS[f][0]) csw.kvp = { 'service': 'CSW', 'version': '2.0.2', 'elementsetname': 'full', 'typenames': formats, 'resulttype': 'results', 'constraintlanguage': 'CQL_TEXT', 'outputschema': 'http://www.isotc211.org/2005/gmd', 'constraint': None, 'startposition': start, 'maxrecords': limit } response = csw.getrecords() else: # it's a GetRecordById request csw.kvp = { '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 # empty geometry fields better. # https://gist.github.com/ingenieroariel/717bb720a201030e9b3a try: response = csw.dispatch() except ReadingError: return [] if isinstance(response, list): # pycsw 2.0+ response = response[1] return response