Example #1
0
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)
Example #2
0
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
Example #3
0
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]
Example #4
0
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
Example #5
0
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)
Example #6
0
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)
Example #7
0
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)
Example #8
0
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
Example #10
0
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)
Example #12
0
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
Example #13
0
    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()
Example #14
0
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
Example #15
0
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)
Example #16
0
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
Example #17
0
    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()
Example #18
0
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
Example #19
0
    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
Example #20
0
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)
Example #21
0
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)
Example #22
0
File: csw.py Project: drwelby/pycsw
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
Example #23
0
    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