Example #1
0
def render_j2_template(config, template, data, locale_=None):
    """
    render Jinja2 template

    :param config: dict of configuration
    :param template: template (relative path)
    :param data: dict of data
    :param locale_: the requested output Locale

    :returns: string of rendered template
    """

    custom_templates = False
    try:
        templates_path = config['server']['templates']['path']
        env = Environment(loader=FileSystemLoader(templates_path),
                          extensions=['jinja2.ext.i18n',
                                      'jinja2.ext.autoescape'],
                          autoescape=select_autoescape(['html', 'xml']))
        custom_templates = True
        LOGGER.debug('using custom templates: {}'.format(templates_path))
    except (KeyError, TypeError):
        env = Environment(loader=FileSystemLoader(TEMPLATES),
                          extensions=['jinja2.ext.i18n',
                                      'jinja2.ext.autoescape'],
                          autoescape=select_autoescape(['html', 'xml']))
        LOGGER.debug('using default templates: {}'.format(TEMPLATES))

    env.filters['to_json'] = to_json
    env.filters['format_datetime'] = format_datetime
    env.filters['format_duration'] = format_duration
    env.filters['human_size'] = human_size
    env.globals.update(to_json=to_json)

    env.filters['get_path_basename'] = get_path_basename
    env.globals.update(get_path_basename=get_path_basename)

    env.filters['get_breadcrumbs'] = get_breadcrumbs
    env.globals.update(get_breadcrumbs=get_breadcrumbs)

    env.filters['filter_dict_by_key_value'] = filter_dict_by_key_value
    env.globals.update(filter_dict_by_key_value=filter_dict_by_key_value)

    translations = Translations.load('locale', [locale_])
    env.install_gettext_translations(translations)

    try:
        template = env.get_template(template)
    except TemplateNotFound as err:
        if custom_templates:
            LOGGER.debug(err)
            LOGGER.debug('Custom template not found; using default')
            env = Environment(loader=FileSystemLoader(TEMPLATES),
                              extensions=['jinja2.ext.i18n'])
            template = env.get_template(template)
        else:
            raise

    return template.render(config=l10n.translate_struct(config, locale_, True),
                           data=data, locale=locale_, version=__version__)
Example #2
0
def test_translatedict(config, locale_):
    cfg = l10n.translate_struct(config, locale_, True)
    assert cfg['metadata']['identification'][
        'title'] == 'pygeoapi default instance'  # noqa
    assert cfg['metadata']['identification']['keywords'] == [
        'geospatial', 'data', 'api'
    ]  # noqa

    # test full equality (must come from cache)
    cfg2 = l10n.translate_struct(config, locale_, True)
    assert cfg is cfg2

    # missing locale_ should return the same dict
    assert l10n.translate_struct(config, None) is config  # noqa

    # missing or empty dict should return an empty dict
    assert l10n.translate_struct(None, locale_) == {}  # noqa

    # test custom dict (translate from level 0, do not cache)
    test_dict = {'level0': {'en': 'test value', 'fr': 'valeur de test'}}
    tr_dict = l10n.translate_struct(test_dict, locale_)
    assert tr_dict['level0'] == 'test value'
    tr_dict2 = l10n.translate_struct(test_dict, locale_)
    assert tr_dict == tr_dict2
    assert tr_dict is not tr_dict2

    # test mixed structure
    test_input = [{
        'test': {
            'en': 'test value',
            'fr': 'valeur de test'
        }
    }, 'some string', {
        'item1': 1
    }, {
        'item2a': [
            'list_item1', 'list_item2', {
                'en': 'list value',
                'fr': 'valeur de liste'
            }
        ],
        'item2b': {
            'en': 'test value',
            'fr': 'valeur de test'
        }
    }]
    test_output = [{
        'test': 'test value'
    }, 'some string', {
        'item1': 1
    }, {
        'item2a': ['list_item1', 'list_item2', 'list value'],
        'item2b': 'test value'
    }]
    assert l10n.translate_struct(test_input, locale_) == test_output
Example #3
0
    def _to_geojson(self, json_obj, skip_geometry=False, single_feature=False):
        """ Turns a regular geoCore JSON object into GeoJSON. """
        features = []
        num_matched = None

        for item in json_obj.get('Items', []):
            feature = {'type': 'Feature', 'geometry': None}

            # Get ID and validate it
            id_ = item.pop('id', None)
            if id_ is None:
                LOGGER.warning(f'skipped record without ID')
                continue
            feature['id'] = id_
            item['externalId'] = id_

            # Pop 'total' value for numberMatched property (for paging)
            num_matched = int(item.pop('total', 0))

            # Rename and set/fix date properties
            date_created = self._asisodate(item.get('created'))
            date_updated = self._asisodate(item.pop('published', None))
            item['record-created'] = date_created
            item['record-updated'] = date_updated
            item['created'] = date_created
            item['updated'] = date_updated

            # Convert keywords to an array
            item['keywords'] = self._aslist(item.get('keywords'))

            # Get coordinates and set geometry and extent
            coords = self._getcoords(item)
            if coords:
                if skip_geometry:
                    LOGGER.debug('skipped geometry')
                else:
                    # Add Polygon geometry to feature
                    feature['geometry'] = {
                        'type': 'Polygon',
                        'coordinates': coords
                    }

                # Add extent object to feature
                item['extent'] = self._getextent(
                    coords, item.pop('temporalExtent', None))
            else:
                LOGGER.debug('record has no coordinates: '
                             'cannot set geometry and extent')

            # Remove options and convert to associations
            options = item.pop('options', [])
            for opt in options:
                opt = l10n.translate_struct(opt, self.locale)
                url = opt.get('url')
                title = opt.get('name')
                type_ = opt.get('protocol')
                rel = 'item'
                i18n = self.locale
                desc = opt.get('description')
                if desc and desc.count(';') == 2:
                    # TODO: retrieve mime type from URL or lookup
                    rel, type_, i18n = desc.split(';')
                if not (type_ and url):
                    # Do not add links without a type or URL
                    continue
                lnk = {
                    'href':
                    url,
                    'type':
                    type_,
                    'rel':
                    rel,
                    'title':
                    title,
                    'hreflang':
                    l10n.locale2str(i18n)
                    if isinstance(i18n, l10n.Locale) else i18n
                }
                item.setdefault('associations', []).append(lnk)

            # Remove graphicOverview and promote/set first thumbnailUrl
            try:
                url = item.pop('graphicOverview')[0].get('overviewfilename')
                item['thumbnailUrl'] = url
            except (KeyError, IndexError, AttributeError):
                LOGGER.warning('could not find overview thumbnail')

            # Translate contacts, credits and distributors lists
            for prop in ('contact', 'credits', 'distributor'):
                values = item.get(prop, [])
                if values:
                    item[prop] = l10n.translate_struct(values, self.locale)

            # Translate known concatenated "en; fr" values
            # TODO: add more props if needed, improve on geoCore side
            for prop in ('spatialRepresentation', 'type', 'status',
                         'maintenance', 'accessConstraints', 'characterSet'):
                values = [v.strip() for v in item.get(prop, '').split(';')]
                if len(values) != 2:
                    continue
                item[prop] = values[0 if self.locale.language == 'en' else 1]

            # Set properties and add to feature list
            feature['properties'] = item
            features.append(feature)

        if features and single_feature == 1:
            LOGGER.debug('returning single feature')
            return features[0]

        LOGGER.debug('returning feature collection')
        collection = {
            'type': 'FeatureCollection',
            'features': features,
            'numberReturned': len(features)
        }
        LOGGER.debug(f'provider said there are {num_matched} matches')
        if num_matched:
            collection['numberMatched'] = num_matched
        return collection