Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ace5ee0
Changes for testing warnings with js
BharatVe Mar 24, 2025
e987387
Update APi to API&Data
BharatVe Mar 26, 2025
7c145c0
Merge branch 'main' into enhancement/Download_all_geometries_and_meta…
nuest Mar 31, 2025
ba487d4
Addition of GeoPackage + Dynamic Size Calculation ( GeoPackage needs …
Apr 2, 2025
af50835
Upadted implemntation for Geopackage download
Apr 7, 2025
83cc473
Updated test file
Apr 9, 2025
699e78b
Merge remote-tracking branch 'origin/main' into enhancement/Download_…
Apr 9, 2025
1cc2193
Merge remote-tracking branch 'origin/main' into enhancement/Download_…
Apr 9, 2025
b21233d
update test( with pygdal)
Apr 9, 2025
823ad18
Update test_geo_data.py
BharatVe Apr 9, 2025
bcec9a1
Update requirements.txt
BharatVe Apr 9, 2025
aca2962
updated views.py, requirements.txt using fiona and shapely (vs osgeo)
Apr 10, 2025
7869a82
Changes for updated pull request. (Work in progress)
Apr 20, 2025
17965b0
Update tasks.py, minor updates
BharatVe Apr 20, 2025
988b5e1
Completed implemeentation with recommeded changes(final check needed)
Apr 22, 2025
c4cc194
Minor corrections tasks.py
BharatVe Apr 23, 2025
f135ef3
updated test
Apr 23, 2025
052c42f
Update data.html
BharatVe Apr 23, 2025
acfe536
Updated data message
BharatVe Apr 23, 2025
30cb5f1
now to timezone (Fix unittest issue)
Apr 23, 2025
9d24d63
add logos and colours to README, closes #33
nuest Apr 9, 2025
fc02e9b
Updated scripts- changed time fomats, modified test added humanize time
Apr 28, 2025
daed800
Merge branch 'main' into enhancement/Download_all_geometries_and_meta…
BharatVe Apr 28, 2025
a9f7a8d
fixed tests, removed fiona and updated requirements.txt
Apr 28, 2025
939e0b8
install GDAL package form PyPI
nuest Apr 29, 2025
e7d9701
fix test
nuest Apr 29, 2025
a2f829f
Updated links, changed URLs, corrected footer, added automated cache …
May 5, 2025
479e10e
Updated apps and tests
May 6, 2025
0e4b16b
Update apps.py
BharatVe May 6, 2025
6c072ed
Use Humanize, added checks for link validity.
May 12, 2025
100dc2a
added humanize
May 12, 2025
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
12 changes: 8 additions & 4 deletions publications/templates/data.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ <h2 class="py-2">OpenAPI UI</h2>

<h2 class="py-2">Download Publication Data</h2>
<ul class="list-unstyled mb-4">
{% if geojson_size %}
<li class="mb-3">
<div class="d-flex align-items-center">
<a class="btn btn-primary btn-sm" href="{% url 'optimap:download_geojson' %}">
Expand All @@ -47,22 +48,25 @@ <h2 class="py-2">Download Publication Data</h2>
(<a href="https://geojson.org/" target="_blank" class="ms-2 small">GeoJSON spec</a>)
</div>
<div class="small text-muted mt-1">
File size: {{ geojson_size|filesizeformat }}
File size: {{ geojson_size }}
</div>
</li>
{% endif %}

{% if geopackage_size %}
<li>
<div class="d-flex align-items-center">
<a class="btn btn-primary btn-sm" href="{% url 'optimap:download_geopackage' %}">
Download GeoPackage
</a>
</a>
(<a href="https://www.geopackage.org/" target="_blank" class="ms-2 small">GeoPackage spec</a>)
</div>
<div class="small text-muted mt-1">
File size: {{ geopackage_size|filesizeformat }}
File size: {{ geopackage_size }}
</div>
</li>
{% endif %}
</ul>

<p class="small text-muted text-center mb-0">
Data dumps run every {{ interval }} hour{{ interval|pluralize }}.<br>
Last updated: {{ last_updated|naturaltime }}
Expand Down
41 changes: 16 additions & 25 deletions publications/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,24 @@
import imaplib
import time
from math import floor
from django.utils.timezone import make_aware, get_default_timezone, localtime
from datetime import datetime
from urllib.parse import unquote
from django.core.serializers import serialize
from django.conf import settings
from django.core.serializers import serialize
from publications.models import BlockedEmail, BlockedDomain, Subscription, UserProfile, Publication
from django.contrib.auth import get_user_model
User = get_user_model()
import tempfile, os
from publications.tasks import regenerate_geojson_cache, regenerate_geopackage_cache
from osgeo import ogr, osr
ogr.UseExceptions()
#osr.UseExceptions()
import humanize

LOGIN_TOKEN_LENGTH = 32
LOGIN_TOKEN_TIMEOUT_SECONDS = 10 * 60
EMAIL_CONFIRMATION_TIMEOUT_SECONDS = 10 * 60
ACCOUNT_DELETE_TOKEN_TIMEOUT_SECONDS = 10 * 60
USER_DELETE_TOKEN_PREFIX = "user_delete_token"

def format_file_size(num_bytes):
if num_bytes < 1024:
return f"{num_bytes} B"
elif num_bytes < 1024 * 1024:
return f"{num_bytes / 1024:.2f} KB"
else:
return f"{num_bytes / (1024 * 1024):.2f} MB"

# ------------------------------
# Download Endpoints
# ------------------------------
Expand Down Expand Up @@ -86,47 +76,37 @@ def generate_geopackage():
os.makedirs(cache_dir, exist_ok=True)
gpkg_path = os.path.join(cache_dir, "publications.gpkg")

# Delete old file so driver can re-create it
driver = ogr.GetDriverByName("GPKG")
if os.path.exists(gpkg_path):
driver.DeleteDataSource(gpkg_path)

# Create data source & layer
ds = driver.CreateDataSource(gpkg_path)
srs = osr.SpatialReference()
srs.ImportFromEPSG(4326)
layer = ds.CreateLayer("publications", srs, ogr.wkbUnknown)

# Define fields
for name in ("title", "abstract", "doi", "source"):
field_defn = ogr.FieldDefn(name, ogr.OFTString)
field_defn.SetWidth(255)
layer.CreateField(field_defn)

# Populate features
layer_defn = layer.GetLayerDefn()
for pub in Publication.objects.all():
feat = ogr.Feature(layer_defn)
feat.SetField("title", pub.title or "")
feat.SetField("abstract", pub.abstract or "")
feat.SetField("doi", pub.doi or "")
feat.SetField("source", pub.source or "")

if pub.geometry:
# Use the GEOSGeometry WKB directly
wkb = pub.geometry.wkb # bytes
geom = ogr.CreateGeometryFromWkb(wkb)
geom.AssignSpatialReference(srs)
feat.SetGeometry(geom)

layer.CreateFeature(feat)
feat = None

# Clean up
ds = None
return gpkg_path


@require_GET
def download_geopackage(request):
"""
Expand All @@ -142,9 +122,11 @@ def download_geopackage(request):
filename="publications.gpkg"
)


def main(request):
return render(request, "main.html")


def loginres(request):
email = request.POST.get('email', False)
if is_email_blocked(email):
Expand Down Expand Up @@ -199,9 +181,11 @@ def loginres(request):
}
})


def privacy(request):
return render(request, 'privacy.html')


@never_cache
def data(request):
cache_dir = os.path.join(tempfile.gettempdir(), "optimap_cache")
Expand All @@ -212,13 +196,19 @@ def data(request):
if not os.path.exists(json_path) or not os.path.exists(gpkg_path):
regenerate_geopackage_cache()

geojson_size = os.path.getsize(json_path)
geopackage_size = os.path.getsize(gpkg_path)
if os.path.exists(json_path):
geojson_size = humanize.naturalsize(os.path.getsize(json_path), binary=True)
else:
geojson_size = None

if os.path.exists(gpkg_path):
geopackage_size = humanize.naturalsize(os.path.getsize(gpkg_path), binary=True)
else:
geopackage_size = None
ts = os.path.getmtime(json_path)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You only take the time of one format here, which is fine because all files should be created at he same time. However, what if they are not?

Please load the times of all files here and compare them that they are about the same time, within an hour is fine. Add a log statement here with level warning if the difference is more than an hour.
The code can then proceed as it is, but at least we have a hint in the logs that something may be wrong.

tz = get_default_timezone()
last_updated = datetime.fromtimestamp(ts, tz)


return render(request, 'data.html', {
'geojson_size': geojson_size,
'geopackage_size': geopackage_size,
Expand All @@ -229,6 +219,7 @@ def data(request):
def Confirmationlogin(request):
return render(request, 'confirmation_login.html')


def login_user(request, user):
login(request, user, backend='django.contrib.auth.backends.ModelBackend')
user.save()
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ whitenoise==6.8.2
psycopg2-binary==2.9.10
packaging==21.3
pycryptodome==3.21.0
humanize==4.10.0
18 changes: 18 additions & 0 deletions tests/test_geo_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,21 @@ def test_download_geopackage(self):
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/geopackage+sqlite3')
self.assertIn('publications.gpkg', response['Content-Disposition'])

def test_data_page_hides_links_when_missing_cache(self):
# Ensure cache is cleared
cache_dir = os.path.join(tempfile.gettempdir(), 'optimap_cache')
for fname in ('geojson_cache.json', 'publications.gpkg'):
path = os.path.join(cache_dir, fname)
if os.path.exists(path):
os.remove(path)

response = self.client.get(reverse('optimap:data'))
content = response.content.decode()
self.assertNotIn('Download GeoJSON', content)
self.assertNotIn('Download GeoPackage', content)
regenerate_geojson_cache()
response = self.client.get(reverse('optimap:data'))
content = response.content.decode()
self.assertIn('Download GeoJSON', content)
self.assertNotIn('Download GeoPackage', content)