Skip to content
Merged
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
158 changes: 139 additions & 19 deletions publications/feeds.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,142 @@
from django.contrib.gis.feeds import Feed
from django.contrib.syndication.views import Feed
from django.utils.feedgenerator import Rss201rev2Feed, Atom1Feed
from .models import Publication
from django.urls import reverse
from django.utils.feedgenerator import Atom1Feed,Rss201rev2Feed
import django.utils.feedgenerator as feedgenerator
class OptimapFeed(Feed):
title = "Latest blog"
link = ""
description = "Latest blog posts"

feed_type = Rss201rev2Feed

def geometry(self):
# Can also return: `obj.poly`, and `obj.poly.centroid`.
return Publication.objects# tuple like: (X0, Y0, X1, Y1).

def item_title(self, item):
return item.title
from datetime import datetime
from django.contrib.gis.geos import GEOSGeometry

class CustomGeoFeed(Rss201rev2Feed):
def __init__(self, *args, **kwargs):
self.feed_type_variant = kwargs.pop("feed_type_variant", "georss")
super().__init__(*args, **kwargs)

def add_root_elements(self, handler):
super().add_root_elements(handler)
handler.startPrefixMapping('georss', 'http://www.georss.org/georss')
handler.startPrefixMapping('geo', 'http://www.w3.org/2003/01/geo/wgs84_pos#')

def rss_attributes(self):
return {"version": self._version, "xmlns:atom": "http://www.w3.org/2005/Atom", "xmlns:georss": "http://www.georss.org/georss"}

def add_item_elements(self, handler, item):
super().add_item_elements(handler, item)

if self.feed_type_variant in ["georss", "geoatom"]:
if "georss_point" in item:
handler.addQuickElement("georss:point", item["georss_point"])
if "georss_polygon" in item:
handler.addQuickElement("georss:polygon", item["georss_polygon"])
if "georss_line" in item:
handler.addQuickElement("georss:line", item["georss_line"])

if self.feed_type_variant in ["w3cgeo", "geoatom"]:
if "geo_lat" in item and "geo_long" in item:
handler.addQuickElement("geo:lat", item["geo_lat"])
handler.addQuickElement("geo:long", item["geo_long"])


class CustomGeoAtomFeed(Atom1Feed):
def root_attributes(self):
attrs = super().root_attributes()
attrs['xmlns:georss'] = 'http://www.georss.org/georss'
attrs['xmlns:geo'] = 'http://www.w3.org/2003/01/geo/wgs84_pos#'
return attrs

def add_root_elements(self, handler):
super().add_root_elements(handler)
handler.startPrefixMapping('georss', 'http://www.georss.org/georss')
handler.startPrefixMapping('geo', 'http://www.w3.org/2003/01/geo/wgs84_pos#')

def add_item_elements(self, handler, item):
super().add_item_elements(handler, item)

if "georss_point" in item:
handler.addQuickElement("georss:point", item["georss_point"])
if "georss_polygon" in item:
handler.addQuickElement("georss:polygon", item["georss_polygon"])
if "georss_line" in item:
handler.addQuickElement("georss:line", item["georss_line"])
if "geo_lat" in item and "geo_long" in item:
handler.addQuickElement("geo:lat", item["geo_lat"])
handler.addQuickElement("geo:long", item["geo_long"])

def _format_georss_geometry(geometry):
georss_data = []

if geometry.geom_type == "Point":
lat, lon = geometry.y, geometry.x
georss_data.append(("georss_point", f"{lat} {lon}"))
georss_data.append(("geo_lat", str(lat)))
georss_data.append(("geo_long", str(lon)))

elif geometry.geom_type == "LineString":
coords = " ".join(f"{pt[1]} {pt[0]}" for pt in geometry.coords)
georss_data.append(("georss_line", coords))

elif geometry.geom_type == "Polygon":
coords = " ".join(f"{pt[1]} {pt[0]}" for pt in geometry.coords[0])
georss_data.append(("georss_polygon", coords))

class atomFeed(Feed):
feed_type = Atom1Feed
centroid = geometry.centroid
lat, lon = centroid.y, centroid.x
georss_data.append(("geo_lat", str(lat)))
georss_data.append(("geo_long", str(lon)))

elif geometry.geom_type == "GeometryCollection":
for geom in geometry:
georss_data.extend(_format_georss_geometry(geom))

return georss_data

class GeoFeed(Feed):
def __init__(self, feed_type_variant="georss"):
self.feed_type_variant = feed_type_variant
super().__init__()

def get_feed(self, obj, request):
if self.feed_type_variant == "geoatom":
self.feed_type = CustomGeoAtomFeed
else:
self.feed_type = lambda *args, **kwargs: CustomGeoFeed(*args, **kwargs, feed_type_variant=self.feed_type_variant)
return super().get_feed(obj, request)

def title(self):
return f"Latest Publications ({self.feed_type_variant.upper()})"

def link(self):
return f"/feeds/{self.feed_type_variant}/"

def description(self):
return f"Updates on the latest publications with geographic data using {self.feed_type_variant.upper()} format."

def items(self):
return Publication.objects.filter(status="p", geometry__isnull=False, url__isnull=False).order_by('-creationDate')[:10]

def item_title(self, item):
return item.title or "Untitled Publication"

def item_description(self, item):
return item.abstract or "No abstract available."

def item_link(self, item):
return item.url

def item_pubdate(self, item):
return datetime.combine(item.publicationDate, datetime.min.time()) if item.publicationDate else item.creationDate

def item_extra_kwargs(self, item):
georss_elements = {}

if item.geometry:
geometries = _format_georss_geometry(item.geometry)

for key, value in geometries:
if self.feed_type_variant == "w3cgeo":
if key in ["geo_lat", "geo_long"]:
georss_elements[key] = value
else:
if key in georss_elements:
georss_elements[key] += f" {value}"
else:
georss_elements[key] = value

return georss_elements
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Generated by Django 5.1.7 on 2025-03-28 14:21

import django.contrib.gis.db.models.fields
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("publications", "0001_initial"),
]

operations = [
migrations.AlterModelOptions(
name="subscription",
options={"ordering": ["name"], "verbose_name": "subscription"},
),
migrations.RemoveField(
model_name="subscription",
name="search_area",
),
migrations.RemoveField(
model_name="subscription",
name="user_name",
),
migrations.AddField(
model_name="subscription",
name="region",
field=django.contrib.gis.db.models.fields.GeometryCollectionField(
blank=True, null=True, srid=4326
),
),
migrations.AddField(
model_name="subscription",
name="subscribed",
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name="subscription",
name="user",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="subscriptions",
to=settings.AUTH_USER_MODEL,
),
),
migrations.AlterField(
model_name="subscription",
name="name",
field=models.CharField(default="default_subscription", max_length=4096),
),
]
11 changes: 7 additions & 4 deletions publications/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
from django.urls import path, include
from django.shortcuts import redirect
from publications import views
from .feeds import OptimapFeed
from .feeds import atomFeed
from .feeds import GeoFeed
from django.views.generic import RedirectView

from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView

app_name = "optimap"
Expand All @@ -19,8 +20,10 @@
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
path('api/schema/ui/sitemap', SpectacularRedocView.as_view(url_name='optimap:schema'), name='redoc'),
path("data/", views.data, name="data"),
path('feed/rss', OptimapFeed(), name="GeoRSSfeed"),
path("feed/atom", atomFeed(), name="GeoAtomfeed"),
path('feed/georss/', GeoFeed(feed_type_variant="georss"), name='georss_feed'),
path('feed/geoatom/', GeoFeed(feed_type_variant="geoatom"), name='geoatom_feed'),
path('feed/w3cgeo/', GeoFeed(feed_type_variant="w3cgeo"), name='w3cgeo_feed'),
path('feed/', RedirectView.as_view(pattern_name='optimap:georss_feed', permanent=True)),
path("loginres/", views.loginres, name="loginres"),
path("privacy/", views.privacy, name="privacy"),
path("loginconfirm/", views.Confirmationlogin, name="loginconfirm"),
Expand Down
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ helium
chromedriver-autoinstaller
pyvirtualdisplay
responses
xmldiff
2 changes: 2 additions & 0 deletions tests/reference/expected_geoatom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:georss="http://www.georss.org/georss"><title>Latest Publications (GEOATOM)</title><link href="http://testserver/feeds/geoatom/" rel="alternate"/><link href="http://testserver/feed/geoatom/" rel="self"/><id>http://testserver/feeds/geoatom/</id><updated>2023-05-20T00:00:00+00:00</updated><entry><title>LineString Test</title><link href="https://example.com/linestring" rel="alternate"/><published>2023-05-20T00:00:00+00:00</published><id>https://example.com/linestring</id><summary type="html">Publication with a linestring inside a collection.</summary><georss:line>45.0 5.0 46.0 6.0 45.5 7.0</georss:line></entry><entry><title>Polygon Test</title><link href="https://example.com/polygon" rel="alternate"/><published>2023-05-15T00:00:00+00:00</published><id>https://example.com/polygon</id><summary type="html">Publication with a polygon inside a collection.</summary><georss:polygon>50.0 10.0 51.0 11.0 50.0 12.0 50.0 10.0</georss:polygon><geo:lat>50.333333333333336</geo:lat><geo:long>11.0</geo:long></entry><entry><title>Point Test</title><link href="https://example.com/point" rel="alternate"/><published>2023-05-10T00:00:00+00:00</published><id>https://example.com/point</id><summary type="html">Publication with a single point inside a collection.</summary><georss:point>41.8902 12.4924</georss:point><geo:lat>41.8902</geo:lat><geo:long>12.4924</geo:long></entry></feed>
2 changes: 2 additions & 0 deletions tests/reference/expected_georss.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:georss="http://www.georss.org/georss"><channel><title>Latest Publications (GEORSS)</title><link>http://testserver/feeds/georss/</link><description>Updates on the latest publications with geographic data using GEORSS format.</description><atom:link href="http://testserver/feed/georss/" rel="self"/><language>en-us</language><lastBuildDate>Sat, 20 May 2023 00:00:00 +0000</lastBuildDate><item><title>LineString Test</title><link>https://example.com/linestring</link><description>Publication with a linestring inside a collection.</description><pubDate>Sat, 20 May 2023 00:00:00 +0000</pubDate><guid>https://example.com/linestring</guid><georss:line>45.0 5.0 46.0 6.0 45.5 7.0</georss:line></item><item><title>Polygon Test</title><link>https://example.com/polygon</link><description>Publication with a polygon inside a collection.</description><pubDate>Mon, 15 May 2023 00:00:00 +0000</pubDate><guid>https://example.com/polygon</guid><georss:polygon>50.0 10.0 51.0 11.0 50.0 12.0 50.0 10.0</georss:polygon></item><item><title>Point Test</title><link>https://example.com/point</link><description>Publication with a single point inside a collection.</description><pubDate>Wed, 10 May 2023 00:00:00 +0000</pubDate><guid>https://example.com/point</guid><georss:point>41.8902 12.4924</georss:point></item></channel></rss>
Loading
Loading