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

GeoJSON Previewer #216

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* This file is part of Invenio.
* Copyright (C) 2015-2024 CERN.
*
* Invenio is free software; you can redistribute it and/or modify it
* under the terms of the MIT License; see LICENSE file for more details.
*/

import L from "leaflet"
import "leaflet/dist/leaflet.css";

document.addEventListener("DOMContentLoaded", () => {
const mapElement = document.getElementById('map')
const fileUri = mapElement.getAttribute('data-file-uri')
const fileUrl = new URL(fileUri, window.location.href);

const map = L.map('map').setView([0, 0], 13);

L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);

fetch(fileUrl.href).then(res => res.json()).then(data => {
const geoJsonLayer = L.geoJson(data, {
style: {
color: "#3399ff",
weight: 2,
opacity: 0.5
},
pointToLayer: (feature, latlng) => L.circleMarker(latlng, {
radius: 4,
fillColor: "#3399ff",
color: "#3399ff",
weight: 2,
opacity: 1,
fillOpacity: 0.8
})
})
geoJsonLayer.addTo(map);
map.fitBounds(geoJsonLayer.getBounds());
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* This file is part of Invenio.
* Copyright (C) 2015-2018 CERN.
*
* Invenio is free software; you can redistribute it and/or modify it
* under the terms of the MIT License; see LICENSE file for more details.
*/

@import "leaflet/dist/leaflet.css";

#map {
width: 100%;
height: 480px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* This file is part of Invenio.
* Copyright (C) 2015-2024 CERN.
*
* Invenio is free software; you can redistribute it and/or modify it
* under the terms of the MIT License; see LICENSE file for more details.
*/

import L from "leaflet"
import "leaflet/dist/leaflet.css";

document.addEventListener("DOMContentLoaded", () => {
const mapElement = document.getElementById('map')
const fileUri = mapElement.getAttribute('data-file-uri')
const fileUrl = new URL(fileUri, window.location.href);

const map = L.map('map').setView([0, 0], 13);

L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);

fetch(fileUrl.href).then(res => res.json()).then(data => {
const geoJsonLayer = L.geoJson(data, {
style: {
color: "#3399ff",
weight: 2,
opacity: 0.5
},
pointToLayer: (feature, latlng) => L.circleMarker(latlng, {
radius: 4,
fillColor: "#3399ff",
color: "#3399ff",
weight: 2,
opacity: 1,
fillOpacity: 0.8
})
})
geoJsonLayer.addTo(map);
map.fitBounds(geoJsonLayer.getBounds());
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* This file is part of Invenio.
* Copyright (C) 2015-2020 CERN.
*
* Invenio is free software; you can redistribute it and/or modify it
* under the terms of the MIT License; see LICENSE file for more details.
*/

@import "leaflet/dist/leaflet.css";

#map {
width: 100%;
height: 480px;
}
58 changes: 48 additions & 10 deletions invenio_previewer/extensions/json_prismjs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@
# Invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""Previews a JSON file."""
"""Previews a JSON or GeoJSON file."""

import json
from collections import OrderedDict
from operator import truediv

from flask import current_app, render_template

from ..proxies import current_previewer
from ..utils import detect_encoding

previewable_extensions = ["json"]
previewable_extensions = ["json", "geojson"]


def render(file):
Expand Down Expand Up @@ -46,15 +47,52 @@ def validate_json(file):

def can_preview(file):
"""Determine if the given file can be previewed."""
return file.is_local() and file.has_extensions(".json") and validate_json(file)
return (
file.is_local()
and file.has_extensions(".json", ".geojson")
and validate_json(file)
)


def is_geojson(file):
"""Determine if the given file is a GeoJSON file."""
if file.has_extensions(".geojson"):
return True

with file.open() as fp:
encoding = detect_encoding(fp, default="utf-8")
file_content = fp.read().decode(encoding)
json_data = json.loads(file_content)

valid_types = [
"Feature",
"FeatureCollection",
"GeometryCollection",
"Point",
"MultiPoint",
"LineString",
"MultiLineString",
"Polygon",
"MultiPolygon",
]

return json_data.get("type", None) in valid_types


def preview(file):
"""Render the appropriate template with embed flag."""
return render_template(
"invenio_previewer/json_prismjs.html",
file=file,
content=render(file),
js_bundles=current_previewer.js_bundles + ["prism_js.js"],
css_bundles=["prism_css.css"],
)
if is_geojson(file):
return render_template(
"invenio_previewer/geojson.html",
file=file,
js_bundles=current_previewer.js_bundles + ["geojson_js.js"],
css_bundles=["geojson_css.css"],
)
else:
return render_template(
"invenio_previewer/json_prismjs.html",
file=file,
content=render(file),
js_bundles=current_previewer.js_bundles + ["prism_js.js"],
css_bundles=["prism_css.css"],
)
14 changes: 14 additions & 0 deletions invenio_previewer/templates/invenio_previewer/geojson.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{# -*- coding: utf-8 -*-

This file is part of Invenio.
Copyright (C) 2016-2024 CERN.

Invenio is free software; you can redistribute it and/or modify it
under the terms of the MIT License; see LICENSE file for more details.
#}

{%- extends config.PREVIEWER_ABSTRACT_TEMPLATE %}

{% block panel %}
<div id="map" data-file-uri="{{ file.uri }}"></div>
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{# -*- coding: utf-8 -*-

This file is part of Invenio.
Copyright (C) 2016-2024 CERN.

Invenio is free software; you can redistribute it and/or modify it
under the terms of the MIT License; see LICENSE file for more details.
#}

{%- extends config.PREVIEWER_ABSTRACT_TEMPLATE %}

{% block panel %}
<div id="map" data-file-uri="{{ file.uri }}"></div>
{% endblock %}
6 changes: 6 additions & 0 deletions invenio_previewer/webpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
themes={
"bootstrap3": dict(
entry={
"geojson_js": "./js/invenio_previewer/geojson.js",
"geojson_css": "./scss/invenio_previewer/geojson.scss",
"papaparse_csv": "./js/invenio_previewer/csv_previewer/init.js",
"previewer_theme": "./js/invenio_previewer/previewer_theme.js",
"prism_js": "./js/invenio_previewer/prismjs.js",
Expand All @@ -43,6 +45,7 @@
},
dependencies={
"bootstrap-sass": "~3.3.5",
"leaflet": "^1.9.4",
"papaparse": "^5.4.1",
"flightjs": "~1.5.1",
"font-awesome": "~4.5.0",
Expand Down Expand Up @@ -71,6 +74,8 @@
),
"semantic-ui": dict(
entry={
"geojson_js": "./js/invenio_previewer/geojson.js",
"geojson_css": "./scss/invenio_previewer/geojson.scss",
"papaparse_csv": "./js/invenio_previewer/csv_previewer/init.js",
"previewer_theme": "./js/invenio_previewer/previewer_theme.js",
"prism_js": "./js/invenio_previewer/prismjs.js",
Expand All @@ -88,6 +93,7 @@
"flightjs": "~1.5.1",
"font-awesome": "~4.5.0",
"jquery": "^3.3.1",
"leaflet": "^1.9.4",
"papaparse": "^5.4.1",
"prismjs": "^1.15.0",
"video.js": "^8.6.1",
Expand Down
30 changes: 30 additions & 0 deletions tests/test_macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,36 @@ def test_zip_extension(testapp, webassets, record, zip_fp):
assert "Zipfile is not previewable" in res.get_data(as_text=True)


def test_json_extension_valid_geojson_file(testapp, webassets, record):
"""Test view with GeoJSON files."""
json_data = (
'{"type": "FeatureCollection","features":'
'[{"type":"Feature","geometry": {"type": "Point",'
'"coordinates": [102.0, 0.5]},"properties":{}}]}'
)
create_file(record, "geo.geojson", BytesIO(b(json_data)))

with testapp.test_client() as client:
res = client.get(preview_url(record["control_number"], "geo.geojson"))

assert '<div id="map" data-file-uri' in res.get_data(as_text=True)


def test_json_extension_valid_geojson_file2(testapp, webassets, record):
"""Test view with GeoJSON files."""
json_data = (
'{"type": "FeatureCollection","features":'
'[{"type":"Feature","geometry": {"type": "Point",'
'"coordinates": [102.0, 0.5]},"properties":{}}]}'
)
create_file(record, "geo.json", BytesIO(b(json_data)))

with testapp.test_client() as client:
res = client.get(preview_url(record["control_number"], "geo.json"))

assert '<div id="map" data-file-uri' in res.get_data(as_text=True)


def test_json_extension_valid_file(testapp, webassets, record):
"""Test view with JSON files."""
json_data = (
Expand Down