From 19a64c7f93374313bfce1c6986258bf1b616f0b5 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sat, 23 May 2020 09:41:50 +0000
Subject: [PATCH] Support rss version 3.0 blog feeds
---
blog.py | 84 ++++++++++++++++++++++++++++++++++++++++++---
daemon.py | 34 ++++++++++++++++++
img/icons/rss3.png | Bin 0 -> 5439 bytes
3 files changed, 114 insertions(+), 4 deletions(-)
create mode 100644 img/icons/rss3.png
diff --git a/blog.py b/blog.py
index a4e4ed50..067487a8 100644
--- a/blog.py
+++ b/blog.py
@@ -295,6 +295,29 @@ def htmlBlogPostRSS2(authorized: bool,
return rssStr
+def htmlBlogPostRSS3(authorized: bool,
+ baseDir: str, httpPrefix: str, translate: {},
+ nickname: str, domain: str, domainFull: str,
+ postJsonObject: {},
+ handle: str, restrictToDomain: bool) -> str:
+ """Returns the RSS version 3 feed for a single blog post
+ """
+ messageLink = ''
+ if postJsonObject['object'].get('id'):
+ messageLink = postJsonObject['object']['id'].replace('/statuses/', '/')
+ if not restrictToDomain or \
+ (restrictToDomain and '/' + domain in messageLink):
+ if postJsonObject['object'].get('summary'):
+ published = postJsonObject['object']['published']
+ pubDate = datetime.strptime(published, "%Y-%m-%dT%H:%M:%SZ")
+ titleStr = postJsonObject['object']['summary']
+ rssDateStr = pubDate.strftime("%a, %d %b %Y %H:%M:%S UT")
+ rssStr = 'title: ' + titleStr + '\n'
+ rssStr += 'link: ' + messageLink + '\n'
+ rssStr += 'created: ' + rssDateStr + '\n\n'
+ return rssStr
+
+
def htmlBlogPost(authorized: bool,
baseDir: str, httpPrefix: str, translate: {},
nickname: str, domain: str, domainFull: str,
@@ -317,14 +340,21 @@ def htmlBlogPost(authorized: bool,
domainFull, postJsonObject,
None, False)
- # show rss link
+ # show rss links
iconsDir = getIconsDir(baseDir)
blogStr += ''
+ blogStr += ''
+
+ blogStr += ''
+ blogStr += ''
+
+ blogStr += '
'
return blogStr + htmlFooter()
return None
@@ -479,6 +509,52 @@ def htmlBlogPageRSS2(authorized: bool, session,
return blogRSS2 + rss2Footer()
+def htmlBlogPageRSS3(authorized: bool, session,
+ baseDir: str, httpPrefix: str, translate: {},
+ nickname: str, domain: str, port: int,
+ noOfItems: int, pageNumber: int) -> str:
+ """Returns an RSS version 3 feed containing posts
+ """
+ if ' ' in nickname or '@' in nickname or \
+ '\n' in nickname or '\r' in nickname:
+ return None
+
+ domainFull = domain
+ if port:
+ if port != 80 and port != 443:
+ domainFull = domain + ':' + str(port)
+
+ blogRSS3 = ''
+
+ blogsIndex = baseDir + '/accounts/' + \
+ nickname + '@' + domain + '/tlblogs.index'
+ if not os.path.isfile(blogsIndex):
+ return blogRSS3
+
+ timelineJson = createBlogsTimeline(session, baseDir,
+ nickname, domain, port,
+ httpPrefix,
+ noOfItems, False, False,
+ pageNumber)
+
+ if not timelineJson:
+ return blogRSS3
+
+ if pageNumber is not None:
+ for item in timelineJson['orderedItems']:
+ if item['type'] != 'Create':
+ continue
+
+ blogRSS3 += \
+ htmlBlogPostRSS3(authorized, baseDir,
+ httpPrefix, translate,
+ nickname, domain,
+ domainFull, item,
+ None, True)
+
+ return blogRSS3
+
+
def getBlogIndexesForAccounts(baseDir: str) -> {}:
""" Get the index files for blogs for each account
and add them to a dict
diff --git a/daemon.py b/daemon.py
index 4b6afc1f..4cc452c2 100644
--- a/daemon.py
+++ b/daemon.py
@@ -95,6 +95,7 @@ from config import getConfigParam
from roles import setRole
from roles import clearModeratorStatus
from blog import htmlBlogPageRSS2
+from blog import htmlBlogPageRSS3
from blog import htmlBlogView
from blog import htmlBlogPage
from blog import htmlBlogPost
@@ -1128,6 +1129,7 @@ class PubServer(BaseHTTPRequestHandler):
self._benchmarkGETtimings(GETstartTime, GETtimings, 8)
+ # RSS 2.0
if self.path.startswith('/blog/') and \
self.path.endswith('/rss.xml'):
nickname = self.path.split('/blog/')[1]
@@ -1159,6 +1161,38 @@ class PubServer(BaseHTTPRequestHandler):
self._404()
return
+ # RSS 3.0
+ if self.path.startswith('/blog/') and \
+ self.path.endswith('/rss.txt'):
+ nickname = self.path.split('/blog/')[1]
+ if '/' in nickname:
+ nickname = nickname.split('/')[0]
+ if not nickname.startswith('rss.'):
+ if os.path.isdir(self.server.baseDir +
+ '/accounts/' + nickname +
+ '@' + self.server.domain):
+ if not self.server.session:
+ self.server.session = \
+ createSession(self.server.useTor)
+ msg = \
+ htmlBlogPageRSS3(authorized,
+ self.server.session,
+ self.server.baseDir,
+ self.server.httpPrefix,
+ self.server.translate,
+ nickname,
+ self.server.domain,
+ self.server.port,
+ maxPostsInRSSFeed, 1)
+ if msg is not None:
+ msg = msg.encode()
+ self._set_headers('text/plain; charset=utf-8',
+ len(msg), cookie, callingDomain)
+ self._write(msg)
+ return
+ self._404()
+ return
+
# show the main blog page
if htmlGET and (self.path == '/blog' or
self.path == '/blog/' or
diff --git a/img/icons/rss3.png b/img/icons/rss3.png
new file mode 100644
index 0000000000000000000000000000000000000000..83521cd1b479624e85a4eca787b8c757e03b7854
GIT binary patch
literal 5439
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
literal 0
HcmV?d00001