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:
parent
d1f1edbaca
commit
694c8bb489
4 changed files with 87 additions and 28 deletions
|
@ -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;
|
||||||
|
|
|
@ -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,16 +152,10 @@ 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:
|
xml_atom = error_message(text)
|
||||||
link = 'xmpp:{pubsub}'.format(pubsub=pubsub)
|
result = append_stylesheet(
|
||||||
xml_opml = generate_opml(iq)
|
xml_atom, 'atom.xsl', namespace='http://www.w3.org/2005/Atom')
|
||||||
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')
|
|
||||||
elif node:
|
elif node:
|
||||||
text = 'PubSub parameter is missing.'
|
text = 'PubSub parameter is missing.'
|
||||||
xml_atom = error_message(text)
|
xml_atom = error_message(text)
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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');
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue