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

View file

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

View file

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

View file

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