Set pathname /opml as a pathname for OPML;

Add a message to be displayed upon empty content;
Add more error handlings;
Fix error related to Markdown parsing;
Fix error related to Atom Syndication Format;
Thank you roughnecks.
This commit is contained in:
Schimon Jehudah, Adv. 2024-07-12 16:50:59 +03:00
parent d1f1edbaca
commit 694c8bb489
4 changed files with 87 additions and 28 deletions

View file

@ -18,6 +18,13 @@ img, video {
height: auto;
}
.notice.no-entry {
margin: auto;
/* margin-left: 2%; */
/* margin-top: 2%; */
text-align: center;
}
h1#title, h2#subtitle, #actions, #references {
text-align: center;
text-transform: uppercase;
@ -75,6 +82,15 @@ h1#title, h2#subtitle, #actions, #references {
width: 20%;
}
#journal {
margin: auto;
}
#articles > ul {
margin: auto;
margin-top: 2%;
}
#articles #journal ol,
#articles #journal ul {
/* height: 500px; */
@ -157,7 +173,6 @@ h1#title, h2#subtitle, #actions, #references {
}
#articles #journal {
margin-left: unset;
margin-right: unset;
min-width: unset;
width: unset;

View file

@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
import datetime
from dateutil import parser
from fastapi import FastAPI, Request, Response
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
@ -39,8 +38,59 @@ app.mount("/xsl", StaticFiles(directory="xsl"), name="xsl")
async def favicon():
return FileResponse('favicon.ico')
@app.get('/opml')
async def view_pubsub_nodes(request: Request):
global xmpp
if not xmpp:
credentials = get_configuration('account')
xmpp = XmppInstance(credentials['xmpp'], credentials['pass'])
# xmpp.connect()
pubsub = request.query_params.get('pubsub', '')
settings = get_configuration('settings')
result = None
if settings['service']:
if settings['include'] in pubsub or not settings['include']:
if pubsub:
iq = await get_nodes(pubsub)
if iq:
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
xml_opml = generate_opml(iq)
result = append_stylesheet(xml_opml, 'opml.xsl')
else:
text = 'Please check that PubSub Jabber ID is valid and accessible.'
xml_atom = error_message(text)
result = append_stylesheet(
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
else:
text = 'The given domain {} is not allowed.'.format(pubsub)
xml_atom = error_message(text)
result = append_stylesheet(
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
default = get_configuration('default')
if not result:
if default['pubsub']:
if not pubsub:
pubsub = default['pubsub']
iq = await get_nodes(pubsub)
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
xml_opml = generate_opml(iq)
result = append_stylesheet(xml_opml, 'opml.xsl')
elif not settings['service']:
pubsub = default['pubsub']
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
xml_opml = generate_opml(iq)
result = append_stylesheet(xml_opml, 'opml.xsl')
else:
text = 'Please contact the administrator and ask him to set default PubSub and Node ID.'
xml_atom = error_message(text)
result = append_stylesheet(
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
response = Response(content=result, media_type="application/xml")
return response
@app.get('/atom')
async def view_pubsub(request: Request):
async def view_node_items(request: Request):
global xmpp
if not xmpp:
credentials = get_configuration('account')
@ -102,13 +152,7 @@ async def view_pubsub(request: Request):
result = append_stylesheet(
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
elif pubsub:
iq = await get_nodes(pubsub)
if iq:
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
xml_opml = generate_opml(iq)
result = append_stylesheet(xml_opml, 'opml.xsl')
else:
text = 'Please check that PubSub Jabber ID is valid and accessible.'
text = 'Node parameter is missing.'
xml_atom = error_message(text)
result = append_stylesheet(
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
@ -133,7 +177,7 @@ async def view_pubsub(request: Request):
node = default['nodeid']
iq = await get_node_items(pubsub, node)
link = form_a_node_link(pubsub, node)
xml_atom = generate_rfc_4287(iq, link)
xml_atom = generate_atom(iq, link)
result = append_stylesheet(
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
elif not settings['service']:
@ -141,7 +185,7 @@ async def view_pubsub(request: Request):
node = default['nodeid']
iq = await get_node_items(pubsub, node)
link = form_a_node_link(pubsub, node)
xml_atom = generate_rfc_4287(iq, link)
xml_atom = generate_atom(iq, link)
result = append_stylesheet(
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
else:
@ -202,7 +246,7 @@ def error_message(text):
ET.SubElement(feed, 'subtitle', {'type': 'text'}).text = subtitle
ET.SubElement(feed, 'author', {'name':'XMPP Journal Publisher','email':'xjp@schimon.i2p'})
ET.SubElement(feed, 'generator', {
'uri': 'https://git.xmpp-it.net/sch/XMPPJournalPublisher',
'uri': 'https://git.xmpp-it.net/sch/XJP',
'version': '0.1'}).text = 'XMPP Journal Publisher (XJP)'
ET.SubElement(feed, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
entry = ET.SubElement(feed, 'entry')
@ -222,7 +266,8 @@ def generate_atom(iq, link):
title = node
link = link
# link = form_a_node_link(pubsub, node)
subtitle = 'XMPP PubSub Syndication Feed'
# subtitle = 'XMPP PubSub Syndication Feed'
subtitle = pubsub
description = ('This is a syndication feed generated with XMPP Journal '
'Publisher, which conveys XEP-0060: Publish-Subscribe '
'nodes to standard RFC 4287: The Atom Syndication Format.')
@ -234,7 +279,7 @@ def generate_atom(iq, link):
ET.SubElement(feed, 'subtitle', {'type': 'text'}).text = subtitle
ET.SubElement(feed, 'link', {'rel': 'self', 'href': link})
ET.SubElement(feed, 'generator', {
'uri': 'https://git.xmpp-it.net/sch/XMPPJournalPublisher',
'uri': 'https://git.xmpp-it.net/sch/XJP',
'version': '0.1'}).text = 'XMPP Journal Publisher (XJP)'
ET.SubElement(feed, 'updated').text = datetime.datetime.now(datetime.UTC).isoformat()
for item in items:
@ -249,17 +294,17 @@ def generate_atom(iq, link):
if not title_text or not link_href: continue
content = item_payload.find(namespace + 'content')
content_text = 'No content' if content == None else content.text
if content.attrib:
if content:
content_type = content.attrib['type'] if 'type' in content.attrib else 'text'
content_type_text = 'html' if 'html' in content_type else 'text'
else:
content_type_text = 'text'
published = item_payload.find(namespace + 'published')
published_text = None if published == None else published.text
if published: published_dt = parser.parse(published_text)
updated = item_payload.find(namespace + 'updated')
updated_text = None if updated == None else updated.text
author = item_payload.find(namespace + 'author')
if author and author.attrib: print(author.attrib)
author_text = 'None' if author == None else author.text
identifier = item_payload.find(namespace + 'id')
if identifier and identifier.attrib: print(identifier.attrib)
identifier_text = 'None' if identifier == None else identifier.text
@ -284,7 +329,7 @@ def generate_json(iq):
item_payload = entry['payload']
namespace = '{http://www.w3.org/2005/Atom}'
title = item_payload.find(namespace + 'title')
title_text = None if title == None else title.text
title_text = '*** No Title ***' if title == None else title.text
# updated = item.find(namespace + 'updated')
# updated = None if updated == None else updated.text
# if updated: updated = datetime.datetime.fromisoformat(updated)
@ -338,9 +383,8 @@ def generate_opml(iq):
ET.SubElement(head, "title").text = pubsub
ET.SubElement(head, "description").text = (
"PubSub Nodes of {}").format(pubsub)
ET.SubElement(head, "generator").text = "XMPP Journal Publisher (XJP)"
ET.SubElement(head, "urlPublic").text = (
"https://git.xmpp-it.net/sch/XMPPJournalPublisher")
ET.SubElement(head, "generator").text = 'XMPP Journal Publisher (XJP)'
ET.SubElement(head, "urlPublic").text = 'https://git.xmpp-it.net/sch/XJP'
time_stamp = datetime.datetime.now(datetime.UTC).isoformat()
ET.SubElement(head, "dateCreated").text = time_stamp
ET.SubElement(head, "dateModified").text = time_stamp

View file

@ -23,7 +23,7 @@ window.onload = async function(){
element.textContent = timeStamp.toUTCString();
}
// Parse Markdown
for (let element of document.querySelectorAll('#articles > ul > li > div > p[type="text"]')) {
for (let element of document.querySelectorAll('#articles div[type="text"]')) {
let markDown = element.textContent
element.innerHTML = marked.parse(markDown);
}
@ -64,7 +64,7 @@ window.onload = async function(){
{'text' : 'Browse the journal.',
'href' : `atom?pubsub=${pubsub}&node=${node}`},
{'text' : 'Browse the portal.',
'href' : `atom?pubsub=${pubsub}`}
'href' : `opml?pubsub=${pubsub}`}
]
for (let link of links) {
let elementLi = document.createElement('li');

View file

@ -399,7 +399,7 @@ xmlns:atom='http://www.w3.org/2005/Atom'>
</ul>
</xsl:when>
<xsl:otherwise>
<div class='notice no-entry'></div>
<h3 class='notice no-entry'>No content.</h3>
</xsl:otherwise>
</xsl:choose>
</div>