From: Michael Tremer Date: Tue, 3 Mar 2026 15:41:46 +0000 (+0000) Subject: api: Generate a RSS feed with the latest reports X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=55ad404f933c767c4aa3ec0478858491ef3412ee;p=dbl.git api: Generate a RSS feed with the latest reports Signed-off-by: Michael Tremer --- diff --git a/configure.ac b/configure.ac index 56965f8..220725b 100644 --- a/configure.ac +++ b/configure.ac @@ -57,6 +57,7 @@ AX_PYTHON_MODULE([babel], [fatal]) AX_PYTHON_MODULE([fastapi], [fatal]) AX_PYTHON_MODULE([httpx], [fatal]) AX_PYTHON_MODULE([ldap], [fatal]) +AX_PYTHON_MODULE([lxml], [fatal]) AX_PYTHON_MODULE([publicsuffix2], [fatal]) AX_PYTHON_MODULE([rich], [fatal]) AX_PYTHON_MODULE([sqlmodel], [fatal]) diff --git a/src/dbl/api/reports.py b/src/dbl/api/reports.py index f6bee18..3fb57d1 100644 --- a/src/dbl/api/reports.py +++ b/src/dbl/api/reports.py @@ -18,7 +18,9 @@ # # ############################################################################### +import datetime import fastapi +import lxml.etree import pydantic import typing import uuid @@ -183,5 +185,60 @@ async def submit_comment( # Create the comment return await report.comment(comment=comment.comment, reporter=user) + +""" + RSS +""" +@router.get(".rss") +async def rss( + open: bool | None = None, + limit: int = 100, +): + # Fetch the current time + now = datetime.datetime.utcnow() + + # Atom Feed namespace + ATOM_NS = "http://www.w3.org/2005/Atom" + + # Create a new XML object + root = lxml.etree.Element("rss", version="2.0", nsmap={ "atom" : ATOM_NS }) + + # Meta information + channel = lxml.etree.SubElement(root, "channel") + lxml.etree.SubElement(channel, "title").text = "IPFire DBL - Reports Feed" + lxml.etree.SubElement(channel, "link").text = "https://www.ipfire.org/dbl" + lxml.etree.SubElement(channel, "description").text = "Latest Reports" + lxml.etree.SubElement(channel, "lastBuildDate").text = now.strftime("%a, %d %b %Y %H:%M:%S +0000") + + # Atom link to itself + atom_link = lxml.etree.SubElement(channel, "{%s}link" % ATOM_NS) + atom_link.set("href", "https://api.dbl.ipfire.org/reports.rss") + atom_link.set("rel", "self") + atom_link.set("type", "application/rss+xml") + + # Fetch the latest reports + async for report in backend.reports.get(open=open, limit=limit): + # Create a new item + item = lxml.etree.SubElement(channel, "item") + + # Title + lxml.etree.SubElement(item, "title").text = report.title + + # Set the URL has target link and GUID + lxml.etree.SubElement(item, "link").text = report.url + lxml.etree.SubElement(item, "guid").text = report.url + + # Set the date + lxml.etree.SubElement(item, "pubDate").text = \ + report.reported_at.strftime("%a, %d %b %Y %H:%M:%S +0000") + + # Serialize the XML document + content = lxml.etree.tostring(root, + pretty_print=True, xml_declaration=True, encoding="UTF-8") + + # Send it to the client + return fastapi.Response(content=content, media_type="application/rss+xml") + + # Include our endpoints app.include_router(router) diff --git a/src/dbl/reports.py b/src/dbl/reports.py index 74c0c9a..67801b8 100644 --- a/src/dbl/reports.py +++ b/src/dbl/reports.py @@ -303,6 +303,18 @@ class Report(sqlmodel.SQLModel, database.BackendMixin, table=True): # Accepted? accepted : bool = False + # Title + + @property + def title(self): + """ + A brief one-liner to summarize the report + """ + if self.block: + return "[BLOCK] %s" % self.name + else: + return "[ALLOW] %s" % self.name + # Permissions check async def has_perm(self, user, accept=False): """