Date: Thu, 8 Oct 2020 17:39:30 +0100
Subject: [PATCH 106/263] Displaying votes on newswire
---
webinterface.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/webinterface.py b/webinterface.py
index 778921dd8..f69a680bd 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -5384,7 +5384,12 @@ def htmlNewswire(newswire: str, nickname: str, moderator: bool,
if 'vote:' in line:
totalVotes += 1
if totalVotes > 0:
- totalVotesStr = ' +' + str(totalVotes)
+ totalVotesStr = ' '
+ for v in range(totalVotes):
+ if positiveVoting:
+ totalVotesStr += '✓'
+ else:
+ totalVotesStr += '✗'
htmlStr += '' + \
'' + item[0] + '' + \
From c5ecdaf5c3887657964929ac7820fc2b31202118 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 18:05:01 +0100
Subject: [PATCH 107/263] Tidying
---
webinterface.py | 56 ++++++++++++++++++++++++++++---------------------
1 file changed, 32 insertions(+), 24 deletions(-)
diff --git a/webinterface.py b/webinterface.py
index f69a680bd..93be55b57 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -5367,6 +5367,30 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
return htmlStr
+def votesOnNewswireItem(status: []) -> int:
+ """Returns the number of votes on a newswire item
+ """
+ totalVotes = 0
+ for line in status:
+ if 'vote:' in line:
+ totalVotes += 1
+ return totalVotes
+
+
+def votesIndicator(totalVotes: int, positiveVoting: bool) -> str:
+ """Returns an indicator of the number of votes on a newswire item
+ """
+ if totalVotes <= 0:
+ return ''
+ totalVotesStr = ' '
+ for v in range(totalVotes):
+ if positiveVoting:
+ totalVotesStr += '✓'
+ else:
+ totalVotesStr += '✗'
+ return totalVotesStr
+
+
def htmlNewswire(newswire: str, nickname: str, moderator: bool,
translate: {}, positiveVoting: bool) -> str:
"""Converts a newswire dict into html
@@ -5377,19 +5401,11 @@ def htmlNewswire(newswire: str, nickname: str, moderator: bool,
dateStrLink = dateStrLink.replace('+00:00', '')
if 'vote:' + nickname in item[2]:
totalVotesStr = ''
+ totalVotes = 0
if moderator:
- # count the total votes for this item
- totalVotes = 0
- for line in item[2]:
- if 'vote:' in line:
- totalVotes += 1
- if totalVotes > 0:
- totalVotesStr = ' '
- for v in range(totalVotes):
- if positiveVoting:
- totalVotesStr += '✓'
- else:
- totalVotesStr += '✗'
+ totalVotes = votesOnNewswireItem(item[2])
+ totalVotesStr = \
+ votesIndicator(totalVotes, positiveVoting)
htmlStr += '' + \
'' + item[0] + '' + \
@@ -5407,21 +5423,13 @@ def htmlNewswire(newswire: str, nickname: str, moderator: bool,
htmlStr += dateStr.replace('+00:00', '') + '
'
else:
totalVotesStr = ''
+ totalVotes = 0
if moderator:
- # count the total votes for this item
- totalVotes = 0
- for line in item[2]:
- if 'vote:' in line:
- totalVotes += 1
+ totalVotes = votesOnNewswireItem(item[2])
# show a number of ticks or crosses for how many
# votes for or against
- if totalVotes > 0:
- totalVotesStr = ' '
- for v in range(totalVotes):
- if positiveVoting:
- totalVotesStr += '✓'
- else:
- totalVotesStr += '✗'
+ totalVotesStr = \
+ votesIndicator(totalVotes, positiveVoting)
htmlStr += '' + \
'' + item[0] + '' + \
From b0839c4c3266e903cb75eedbe966cc1197632887 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 18:18:13 +0100
Subject: [PATCH 108/263] Better terminology
---
epicyon-profile.css | 4 ++--
webinterface.py | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/epicyon-profile.css b/epicyon-profile.css
index 8a59c6386..4e797fce8 100644
--- a/epicyon-profile.css
+++ b/epicyon-profile.css
@@ -232,7 +232,7 @@ a:focus {
line-height: var(--line-spacing-newswire);
}
-.newswireItemApproved {
+.newswireItemVotedOn {
font-size: var(--font-size-newswire);
font-weight: bold;
color: var(--column-right-fg-color-approved);
@@ -245,7 +245,7 @@ a:focus {
float: right;
}
-.newswireDateApproved {
+.newswireDateVotedOn {
font-size: var(--font-size-newswire);
font-weight: bold;
color: var(--newswire-date-color);
diff --git a/webinterface.py b/webinterface.py
index 93be55b57..37c5bf1ca 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -5407,7 +5407,7 @@ def htmlNewswire(newswire: str, nickname: str, moderator: bool,
totalVotesStr = \
votesIndicator(totalVotes, positiveVoting)
- htmlStr += '' + \
+ htmlStr += '
' + \
'' + item[0] + '' + \
totalVotesStr
if moderator:
@@ -5416,10 +5416,10 @@ def htmlNewswire(newswire: str, nickname: str, moderator: bool,
'' + \
- '
'
else:
- htmlStr += ' '
+ htmlStr += ' '
htmlStr += dateStr.replace('+00:00', '') + '
'
else:
totalVotesStr = ''
From af7c8f3d9f809d4130730409c06cea4f52a45522 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 18:22:10 +0100
Subject: [PATCH 109/263] Change newswire background on voted items
---
epicyon-profile.css | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/epicyon-profile.css b/epicyon-profile.css
index 4e797fce8..8d04869e4 100644
--- a/epicyon-profile.css
+++ b/epicyon-profile.css
@@ -77,6 +77,7 @@
--column-left-icon-size: 20%;
--column-right-icon-size: 20%;
--newswire-date-color: white;
+ --newswire-voted-background-color: black;
}
@font-face {
@@ -232,6 +233,10 @@ a:focus {
line-height: var(--line-spacing-newswire);
}
+.newswireItemVotedOn a:link {
+ background: var(--newswire-voted-background-color);
+}
+
.newswireItemVotedOn {
font-size: var(--font-size-newswire);
font-weight: bold;
From 7902ece1b6173daa1697b68fdbb37f5955df6159 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 18:30:07 +0100
Subject: [PATCH 110/263] Extra label
---
webinterface.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/webinterface.py b/webinterface.py
index 37c5bf1ca..badd4785c 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -5408,8 +5408,9 @@ def htmlNewswire(newswire: str, nickname: str, moderator: bool,
votesIndicator(totalVotes, positiveVoting)
htmlStr += '' + \
- '' + item[0] + '' + \
- totalVotesStr
+ '' + \
+ '' + item[0] + \
+ '' + totalVotesStr
if moderator:
htmlStr += \
' ' + \
From 04e8cfd9f39e0eedf294d55f12241de2e0b39504 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 18:34:43 +0100
Subject: [PATCH 111/263] Vote color
---
epicyon-profile.css | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/epicyon-profile.css b/epicyon-profile.css
index 8d04869e4..0c1c63b6b 100644
--- a/epicyon-profile.css
+++ b/epicyon-profile.css
@@ -15,7 +15,7 @@
--main-fg-color: #dddddd;
--column-left-fg-color: #dddddd;
--column-right-fg-color: #dddddd;
- --column-right-fg-color-approved: yellow;
+ --column-right-fg-color-voted-on: red;
--main-link-color: #999;
--main-link-color-hover: #bbb;
--main-visited-color: #888;
@@ -240,7 +240,7 @@ a:focus {
.newswireItemVotedOn {
font-size: var(--font-size-newswire);
font-weight: bold;
- color: var(--column-right-fg-color-approved);
+ color: var(--column-right-fg-color-voted-on);
line-height: var(--line-spacing-newswire);
}
From 23519bea5425f71dd5cbbd1b7205383f0849803e Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 18:35:51 +0100
Subject: [PATCH 112/263] Vote color
---
epicyon-profile.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/epicyon-profile.css b/epicyon-profile.css
index 0c1c63b6b..fd329615e 100644
--- a/epicyon-profile.css
+++ b/epicyon-profile.css
@@ -253,7 +253,7 @@ a:focus {
.newswireDateVotedOn {
font-size: var(--font-size-newswire);
font-weight: bold;
- color: var(--newswire-date-color);
+ color: var(--column-right-fg-color-voted-on);
float: right;
}
From 72b5db2d9ed1a365438c8d1724d0a268227fc854 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 18:49:03 +0100
Subject: [PATCH 113/263] Newswire votes threshold
---
daemon.py | 4 ++++
epicyon.py | 5 +++++
tests.py | 6 +++---
3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/daemon.py b/daemon.py
index ebe93ad56..81cc167da 100644
--- a/daemon.py
+++ b/daemon.py
@@ -11356,6 +11356,7 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
def runDaemon(positiveVoting: bool,
+ newswireVotesThreshold: int,
newsInstance: bool,
blogsInstance: bool,
mediaInstance: bool,
@@ -11466,6 +11467,9 @@ def runDaemon(positiveVoting: bool,
# on the newswire, whether moderators vote positively for items
# or against them (veto)
httpd.positiveVoting = positiveVoting
+ # number of votes needed to remove a newswire item from the news timeline
+ # or if positive voting is anabled to add the item to the news timeline
+ httpd.newswireVotesThreshold = newswireVotesThreshold
if registration == 'open':
httpd.registration = True
diff --git a/epicyon.py b/epicyon.py
index ea13307d2..4c89797b9 100644
--- a/epicyon.py
+++ b/epicyon.py
@@ -256,6 +256,10 @@ parser.add_argument('--archiveweeks', dest='archiveWeeks', type=str,
parser.add_argument('--maxposts', dest='archiveMaxPosts', type=str,
default=None,
help='Maximum number of posts in in/outbox')
+parser.add_argument('--minimumVotes', dest='minimumVotes', type=str,
+ default=None,
+ help='Minimum number of votes to remove or add' +
+ ' a newswire item')
parser.add_argument('--message', dest='message', type=str,
default=None,
help='Message content')
@@ -1916,6 +1920,7 @@ if setTheme(baseDir, themeName):
if __name__ == "__main__":
runDaemon(args.positivevoting,
+ args.minimumVotes,
args.newsinstance,
args.blogsinstance, args.mediainstance,
args.maxRecentPosts,
diff --git a/tests.py b/tests.py
index 8a8989e0c..0de1c0c6d 100644
--- a/tests.py
+++ b/tests.py
@@ -287,7 +287,7 @@ def createServerAlice(path: str, domain: str, port: int,
onionDomain = None
i2pDomain = None
print('Server running: Alice')
- runDaemon(False, False, False, False,
+ runDaemon(False, 1, False, False, False,
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
@@ -350,7 +350,7 @@ def createServerBob(path: str, domain: str, port: int,
onionDomain = None
i2pDomain = None
print('Server running: Bob')
- runDaemon(False, False, False, False,
+ runDaemon(False, 1, False, False, False,
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
@@ -387,7 +387,7 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
onionDomain = None
i2pDomain = None
print('Server running: Eve')
- runDaemon(False, False, False, False,
+ runDaemon(False, 1, False, False, False,
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
From cc642557f46d87e88bb0426d9403b59d808c3475 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 20:47:23 +0100
Subject: [PATCH 114/263] Apply voting threshold to timeline
---
daemon.py | 67 ++++++++++++++++++++++++++++++++++---------------
person.py | 4 ++-
posts.py | 47 +++++++++++++++++++++++++++-------
utils.py | 35 +++++++++++++++++++++++++-
webinterface.py | 13 ++--------
5 files changed, 124 insertions(+), 42 deletions(-)
diff --git a/daemon.py b/daemon.py
index 81cc167da..6b1d6ca1f 100644
--- a/daemon.py
+++ b/daemon.py
@@ -5990,7 +5990,9 @@ class PubServer(BaseHTTPRequestHandler):
path,
httpPrefix,
maxPostsInFeed, 'inbox',
- authorized)
+ authorized,
+ 0,
+ self.server.positiveVoting)
if inboxFeed:
if GETstartTime:
self._benchmarkGETtimings(GETstartTime, GETtimings,
@@ -6018,7 +6020,9 @@ class PubServer(BaseHTTPRequestHandler):
path + '?page=1',
httpPrefix,
maxPostsInFeed, 'inbox',
- authorized)
+ authorized,
+ 0,
+ self.server.positiveVoting)
if GETstartTime:
self._benchmarkGETtimings(GETstartTime,
GETtimings,
@@ -6106,7 +6110,8 @@ class PubServer(BaseHTTPRequestHandler):
path,
httpPrefix,
maxPostsInFeed, 'dm',
- authorized)
+ authorized,
+ 0, self.server.positiveVoting)
if inboxDMFeed:
if self._requestHTTP():
nickname = path.replace('/users/', '')
@@ -6130,7 +6135,9 @@ class PubServer(BaseHTTPRequestHandler):
path + '?page=1',
httpPrefix,
maxPostsInFeed, 'dm',
- authorized)
+ authorized,
+ 0,
+ self.server.positiveVoting)
msg = \
htmlInboxDMs(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6207,7 +6214,8 @@ class PubServer(BaseHTTPRequestHandler):
path,
httpPrefix,
maxPostsInFeed, 'tlreplies',
- True)
+ True,
+ 0, self.server.positiveVoting)
if not inboxRepliesFeed:
inboxRepliesFeed = []
if self._requestHTTP():
@@ -6232,7 +6240,8 @@ class PubServer(BaseHTTPRequestHandler):
path + '?page=1',
httpPrefix,
maxPostsInFeed, 'tlreplies',
- True)
+ True,
+ 0, self.server.positiveVoting)
msg = \
htmlInboxReplies(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6309,7 +6318,8 @@ class PubServer(BaseHTTPRequestHandler):
path,
httpPrefix,
maxPostsInMediaFeed, 'tlmedia',
- True)
+ True,
+ 0, self.server.positiveVoting)
if not inboxMediaFeed:
inboxMediaFeed = []
if self._requestHTTP():
@@ -6334,7 +6344,8 @@ class PubServer(BaseHTTPRequestHandler):
path + '?page=1',
httpPrefix,
maxPostsInMediaFeed, 'tlmedia',
- True)
+ True,
+ 0, self.server.positiveVoting)
msg = \
htmlInboxMedia(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6411,7 +6422,8 @@ class PubServer(BaseHTTPRequestHandler):
path,
httpPrefix,
maxPostsInBlogsFeed, 'tlblogs',
- True)
+ True,
+ 0, self.server.positiveVoting)
if not inboxBlogsFeed:
inboxBlogsFeed = []
if self._requestHTTP():
@@ -6436,7 +6448,8 @@ class PubServer(BaseHTTPRequestHandler):
path + '?page=1',
httpPrefix,
maxPostsInBlogsFeed, 'tlblogs',
- True)
+ True,
+ 0, self.server.positiveVoting)
msg = \
htmlInboxBlogs(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6514,7 +6527,9 @@ class PubServer(BaseHTTPRequestHandler):
path,
httpPrefix,
maxPostsInNewsFeed, 'tlnews',
- True)
+ True,
+ self.server.newswireVotesThreshold,
+ self.server.positiveVoting)
if not inboxNewsFeed:
inboxNewsFeed = []
if self._requestHTTP():
@@ -6540,7 +6555,9 @@ class PubServer(BaseHTTPRequestHandler):
path + '?page=1',
httpPrefix,
maxPostsInBlogsFeed, 'tlnews',
- True)
+ True,
+ self.server.newswireVotesThreshold,
+ self.server.positiveVoting)
currNickname = path.split('/users/')[1]
if '/' in currNickname:
currNickname = currNickname.split('/')[0]
@@ -6686,7 +6703,8 @@ class PubServer(BaseHTTPRequestHandler):
path,
httpPrefix,
maxPostsInFeed, 'tlbookmarks',
- authorized)
+ authorized,
+ 0, self.server.positiveVoting)
if bookmarksFeed:
if self._requestHTTP():
nickname = path.replace('/users/', '')
@@ -6712,7 +6730,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInFeed,
'tlbookmarks',
- authorized)
+ authorized,
+ 0, self.server.positiveVoting)
msg = \
htmlBookmarks(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6791,7 +6810,8 @@ class PubServer(BaseHTTPRequestHandler):
path,
httpPrefix,
maxPostsInFeed, 'tlevents',
- authorized)
+ authorized,
+ 0, self.server.positiveVoting)
print('eventsFeed: ' + str(eventsFeed))
if eventsFeed:
if self._requestHTTP():
@@ -6817,7 +6837,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInFeed,
'tlevents',
- authorized)
+ authorized,
+ 0, self.server.positiveVoting)
msg = \
htmlEvents(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6888,7 +6909,9 @@ class PubServer(BaseHTTPRequestHandler):
port, path,
httpPrefix,
maxPostsInFeed, 'outbox',
- authorized)
+ authorized,
+ self.server.newswireVotesThreshold,
+ self.server.positiveVoting)
if outboxFeed:
if self._requestHTTP():
nickname = \
@@ -6912,7 +6935,9 @@ class PubServer(BaseHTTPRequestHandler):
path + '?page=1',
httpPrefix,
maxPostsInFeed, 'outbox',
- authorized)
+ authorized,
+ self.server.newswireVotesThreshold,
+ self.server.positiveVoting)
msg = \
htmlOutbox(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6976,7 +7001,8 @@ class PubServer(BaseHTTPRequestHandler):
path,
httpPrefix,
maxPostsInFeed, 'moderation',
- True)
+ True,
+ 0, self.server.positiveVoting)
if moderationFeed:
if self._requestHTTP():
nickname = path.replace('/users/', '')
@@ -7000,7 +7026,8 @@ class PubServer(BaseHTTPRequestHandler):
path + '?page=1',
httpPrefix,
maxPostsInFeed, 'moderation',
- True)
+ True,
+ 0, self.server.positiveVoting)
msg = \
htmlModeration(self.server.defaultTimeline,
self.server.recentPostsCache,
diff --git a/person.py b/person.py
index bea86e265..d58064a17 100644
--- a/person.py
+++ b/person.py
@@ -595,7 +595,8 @@ def personLookup(domain: str, path: str, baseDir: str) -> {}:
def personBoxJson(recentPostsCache: {},
session, baseDir: str, domain: str, port: int, path: str,
httpPrefix: str, noOfItems: int, boxname: str,
- authorized: bool) -> {}:
+ authorized: bool,
+ newswireVotesThreshold: int, positiveVoting: bool) -> {}:
"""Obtain the inbox/outbox/moderation feed for the given person
"""
if boxname != 'inbox' and boxname != 'dm' and \
@@ -671,6 +672,7 @@ def personBoxJson(recentPostsCache: {},
elif boxname == 'tlnews':
return createNewsTimeline(session, baseDir, nickname, domain, port,
httpPrefix, noOfItems, headerOnly,
+ newswireVotesThreshold, positiveVoting,
pageNumber)
elif boxname == 'tlblogs':
return createBlogsTimeline(session, baseDir, nickname, domain, port,
diff --git a/posts.py b/posts.py
index e8cb1fc11..b94dc1c0a 100644
--- a/posts.py
+++ b/posts.py
@@ -46,6 +46,8 @@ from utils import locatePost
from utils import loadJson
from utils import saveJson
from utils import getConfigParam
+from utils import locateNewsVotes
+from utils import votesOnNewswireItem
from media import attachMedia
from media import replaceYouTube
from content import removeHtml
@@ -2477,7 +2479,7 @@ def createInbox(recentPostsCache: {},
session, baseDir, 'inbox',
nickname, domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
- pageNumber)
+ 0, False, pageNumber)
def createBookmarksTimeline(session, baseDir: str, nickname: str, domain: str,
@@ -2486,7 +2488,7 @@ def createBookmarksTimeline(session, baseDir: str, nickname: str, domain: str,
return createBoxIndexed({}, session, baseDir, 'tlbookmarks',
nickname, domain,
port, httpPrefix, itemsPerPage, headerOnly,
- True, pageNumber)
+ True, 0, False, pageNumber)
def createEventsTimeline(recentPostsCache: {},
@@ -2496,7 +2498,7 @@ def createEventsTimeline(recentPostsCache: {},
return createBoxIndexed(recentPostsCache, session, baseDir, 'tlevents',
nickname, domain,
port, httpPrefix, itemsPerPage, headerOnly,
- True, pageNumber)
+ True, 0, False, pageNumber)
def createDMTimeline(recentPostsCache: {},
@@ -2506,7 +2508,7 @@ def createDMTimeline(recentPostsCache: {},
return createBoxIndexed(recentPostsCache,
session, baseDir, 'dm', nickname,
domain, port, httpPrefix, itemsPerPage,
- headerOnly, True, pageNumber)
+ headerOnly, True, 0, False, pageNumber)
def createRepliesTimeline(recentPostsCache: {},
@@ -2516,7 +2518,7 @@ def createRepliesTimeline(recentPostsCache: {},
return createBoxIndexed(recentPostsCache, session, baseDir, 'tlreplies',
nickname, domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
- pageNumber)
+ 0, False, pageNumber)
def createBlogsTimeline(session, baseDir: str, nickname: str, domain: str,
@@ -2525,7 +2527,7 @@ def createBlogsTimeline(session, baseDir: str, nickname: str, domain: str,
return createBoxIndexed({}, session, baseDir, 'tlblogs', nickname,
domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
- pageNumber)
+ 0, False, pageNumber)
def createMediaTimeline(session, baseDir: str, nickname: str, domain: str,
@@ -2534,15 +2536,17 @@ def createMediaTimeline(session, baseDir: str, nickname: str, domain: str,
return createBoxIndexed({}, session, baseDir, 'tlmedia', nickname,
domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
- pageNumber)
+ 0, False, pageNumber)
def createNewsTimeline(session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str, itemsPerPage: int,
- headerOnly: bool, pageNumber=None) -> {}:
+ headerOnly: bool, newswireVotesThreshold: int,
+ positiveVoting: bool, pageNumber=None) -> {}:
return createBoxIndexed({}, session, baseDir, 'outbox', 'news',
domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
+ newswireVotesThreshold, positiveVoting,
pageNumber)
@@ -2553,7 +2557,7 @@ def createOutbox(session, baseDir: str, nickname: str, domain: str,
return createBoxIndexed({}, session, baseDir, 'outbox',
nickname, domain, port, httpPrefix,
itemsPerPage, headerOnly, authorized,
- pageNumber)
+ 0, False, pageNumber)
def createModeration(baseDir: str, nickname: str, domain: str, port: int,
@@ -2846,6 +2850,7 @@ def createBoxIndexed(recentPostsCache: {},
session, baseDir: str, boxname: str,
nickname: str, domain: str, port: int, httpPrefix: str,
itemsPerPage: int, headerOnly: bool, authorized: bool,
+ newswireVotesThreshold: int, positiveVoting: bool,
pageNumber=None) -> {}:
"""Constructs the box feed for a person with the given nickname
"""
@@ -2915,6 +2920,30 @@ def createBoxIndexed(recentPostsCache: {},
if not postFilename:
break
+ # apply votes within this timeline
+ if newswireVotesThreshold > 0:
+ # if there a votes file for this post?
+ votesFilename = \
+ locateNewsVotes(baseDir, domain, postFilename)
+ if votesFilename:
+ # load the votes file and count the votes
+ votesJson = loadJson(votesFilename, 0, 2)
+ if votesJson:
+ if not positiveVoting:
+ if votesOnNewswireItem >= \
+ newswireVotesThreshold:
+ # Too many veto votes.
+ # Continue without incrementing the
+ # posts counter
+ continue
+ else:
+ if votesOnNewswireItem < \
+ newswireVotesThreshold:
+ # Not enough votes.
+ # Continue without incrementing the
+ # posts counter
+ continue
+
# Skip through any posts previous to the current page
if postsCtr < int((pageNumber - 1) * itemsPerPage):
postsCtr += 1
diff --git a/utils.py b/utils.py
index e91091d6a..c83b22432 100644
--- a/utils.py
+++ b/utils.py
@@ -500,6 +500,39 @@ def followPerson(baseDir: str, nickname: str, domain: str,
return True
+def votesOnNewswireItem(status: []) -> int:
+ """Returns the number of votes on a newswire item
+ """
+ totalVotes = 0
+ for line in status:
+ if 'vote:' in line:
+ totalVotes += 1
+ return totalVotes
+
+
+def locateNewsVotes(baseDir: str, domain: str,
+ postUrl: str) -> str:
+ """Returns the votes filename for a news post
+ within the news user account
+ """
+ postUrl = \
+ postUrl.strip().replace('\n', '').replace('\r', '')
+
+ # if this post in the shared inbox?
+ postUrl = removeIdEnding(postUrl.strip()).replace('/', '#')
+
+ if postUrl.endswith('.json'):
+ postUrl = postUrl + '.votes'
+ else:
+ postUrl = postUrl + '.json.votes'
+
+ accountDir = baseDir + '/accounts/news' + '@' + domain + '/'
+ postFilename = accountDir + 'outbox/' + postUrl
+ if os.path.isfile(postFilename):
+ return postFilename
+ return None
+
+
def locatePost(baseDir: str, nickname: str, domain: str,
postUrl: str, replies=False) -> str:
"""Returns the filename for the given status post url
@@ -525,7 +558,7 @@ def locatePost(baseDir: str, nickname: str, domain: str,
# check news posts
accountDir = baseDir + '/accounts/news' + '@' + domain + '/'
- postFilename = accountDir + boxName + '/' + postUrl
+ postFilename = accountDir + 'outbox/' + postUrl
if os.path.isfile(postFilename):
return postFilename
diff --git a/webinterface.py b/webinterface.py
index badd4785c..a3b43a31d 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -43,6 +43,7 @@ from utils import getCachedPostDirectory
from utils import getCachedPostFilename
from utils import loadJson
from utils import getConfigParam
+from utils import votesOnNewswireItem
from follow import isFollowingActor
from webfinger import webfingerHandle
from posts import isDM
@@ -2861,7 +2862,7 @@ def htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
str(currPage),
httpPrefix,
10, 'outbox',
- authorized)
+ authorized, 0, False)
if not outboxFeed:
break
if len(outboxFeed['orderedItems']) == 0:
@@ -5367,16 +5368,6 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
return htmlStr
-def votesOnNewswireItem(status: []) -> int:
- """Returns the number of votes on a newswire item
- """
- totalVotes = 0
- for line in status:
- if 'vote:' in line:
- totalVotes += 1
- return totalVotes
-
-
def votesIndicator(totalVotes: int, positiveVoting: bool) -> str:
"""Returns an indicator of the number of votes on a newswire item
"""
From b1b9656cb6981ec5fcf252639e8a7b3e2605e0a8 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 20:50:07 +0100
Subject: [PATCH 115/263] Remove debug
---
posts.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/posts.py b/posts.py
index b94dc1c0a..6c9c19571 100644
--- a/posts.py
+++ b/posts.py
@@ -724,9 +724,7 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
eventStatus=None, ticketUrl=None) -> {}:
"""Creates a message
"""
- print("Subject 1: " + str(subject))
subject = addAutoCW(baseDir, nickname, domain, subject, content)
- print("Subject 2: " + str(subject))
mentionedRecipients = \
getMentionedPeople(baseDir, httpPrefix, content, domain, False)
@@ -770,7 +768,6 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
if subject:
summary = validContentWarning(subject)
sensitive = True
- print("Subject 3: " + str(summary))
toRecipients = []
toCC = []
From 3430924d5e87c0f2c57dc597584760bcef53f5e2 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 20:53:30 +0100
Subject: [PATCH 116/263] Default minimum votes
---
epicyon.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/epicyon.py b/epicyon.py
index 4c89797b9..3ece2fe69 100644
--- a/epicyon.py
+++ b/epicyon.py
@@ -256,8 +256,8 @@ parser.add_argument('--archiveweeks', dest='archiveWeeks', type=str,
parser.add_argument('--maxposts', dest='archiveMaxPosts', type=str,
default=None,
help='Maximum number of posts in in/outbox')
-parser.add_argument('--minimumVotes', dest='minimumVotes', type=str,
- default=None,
+parser.add_argument('--minimumvotes', dest='minimumvotes', type=int,
+ default=1,
help='Minimum number of votes to remove or add' +
' a newswire item')
parser.add_argument('--message', dest='message', type=str,
@@ -1920,7 +1920,7 @@ if setTheme(baseDir, themeName):
if __name__ == "__main__":
runDaemon(args.positivevoting,
- args.minimumVotes,
+ args.minimumvotes,
args.newsinstance,
args.blogsinstance, args.mediainstance,
args.maxRecentPosts,
From 4abd59d30faa1e25ae782fc97022c1083e551d1f Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 20:57:30 +0100
Subject: [PATCH 117/263] Missing argument
---
posts.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/posts.py b/posts.py
index 6c9c19571..648fbde60 100644
--- a/posts.py
+++ b/posts.py
@@ -2927,7 +2927,7 @@ def createBoxIndexed(recentPostsCache: {},
votesJson = loadJson(votesFilename, 0, 2)
if votesJson:
if not positiveVoting:
- if votesOnNewswireItem >= \
+ if votesOnNewswireItem(votesJson) >= \
newswireVotesThreshold:
# Too many veto votes.
# Continue without incrementing the
From 10e7fadd0cd99bac69ccec81d6755e20d5283574 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Thu, 8 Oct 2020 22:31:32 +0100
Subject: [PATCH 118/263] Remove hacky replacements
---
daemon.py | 7 -------
1 file changed, 7 deletions(-)
diff --git a/daemon.py b/daemon.py
index 6b1d6ca1f..68894c865 100644
--- a/daemon.py
+++ b/daemon.py
@@ -6543,7 +6543,6 @@ class PubServer(BaseHTTPRequestHandler):
pageNumber = int(pageNumber)
else:
pageNumber = 1
- nickname = 'news'
if 'page=' not in path:
# if no page was specified then show the first
inboxNewsFeed = \
@@ -6583,12 +6582,6 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain,
self.server.newswire, moderator,
self.server.positiveVoting)
- msg = msg.replace('/news/', '/' + currNickname + '/')
- msg = msg.replace('/users/news"',
- '/users/' + currNickname + '"')
- msg = msg.replace('/users/news?',
- '/users/' + currNickname + '?')
- msg = msg.replace('/banner.webp', '/banner.png')
msg = msg.encode('utf-8')
self._set_headers('text/html', len(msg),
cookie, callingDomain)
From 6e77cf7f6b1031a8a5e86f764703bd1d216390c7 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 09:40:41 +0100
Subject: [PATCH 119/263] More obvious what list entries mean
---
newswire.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/newswire.py b/newswire.py
index d97969677..e814dfeb3 100644
--- a/newswire.py
+++ b/newswire.py
@@ -81,7 +81,11 @@ def xml2StrToDict(xmlStr: str) -> {}:
try:
publishedDate = \
datetime.strptime(pubDate, "%a, %d %b %Y %H:%M:%S %z")
- result[str(publishedDate)] = [title, link, [], '', description]
+ postFilename = ''
+ votesStatus = []
+ result[str(publishedDate)] = [title, link,
+ votesStatus, postFilename,
+ description]
parsed = True
except BaseException:
pass
From 344617f8c904233a1daf07f76b7e1572e5ee09ab Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 10:02:01 +0100
Subject: [PATCH 120/263] Preserve votes between rss updates
---
newsdaemon.py | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/newsdaemon.py b/newsdaemon.py
index a7245c007..4792732d4 100644
--- a/newsdaemon.py
+++ b/newsdaemon.py
@@ -11,6 +11,7 @@ import time
from collections import OrderedDict
from newswire import getDictFromNewswire
from posts import createNewsPost
+from utils import loadJson
from utils import saveJson
from utils import getStatusNumber
@@ -128,11 +129,25 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
newswire[originalDateStr][3] = filename
+def mergeWithPreviousNewswire(oldNewswire: {}, newNewswire: {}) -> None:
+ """Preserve any votes or generated activitypub post filename
+ as rss feeds are updated
+ """
+ for published, fields in oldNewswire.items():
+ if not newNewswire.get(published):
+ continue
+ newNewswire[published][1] = fields[1]
+ newNewswire[published][2] = fields[2]
+ newNewswire[published][3] = fields[3]
+
+
def runNewswireDaemon(baseDir: str, httpd,
httpPrefix: str, domain: str, port: int,
translate: {}) -> None:
"""Periodically updates RSS feeds
"""
+ newswireFilename = baseDir + '/accounts/.currentnewswire.json'
+
# initial sleep to allow the system to start up
time.sleep(50)
while True:
@@ -151,7 +166,14 @@ def runNewswireDaemon(baseDir: str, httpd,
time.sleep(120)
continue
+ if not httpd.newswire:
+ if os.path.isfile(newswireFilename):
+ httpd.newswire = loadJson(newswireFilename)
+
+ mergeWithPreviousNewswire(httpd.newswire, newNewswire)
+
httpd.newswire = newNewswire
+ saveJson(httpd.newswire, newswireFilename)
print('Newswire updated')
convertRSStoActivityPub(baseDir,
From f405dbead3a25698b8615a3f374f697552e7c8fa Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 10:13:16 +0100
Subject: [PATCH 121/263] Save newswire state at time of vote changes
---
daemon.py | 12 ++++++++++++
newsdaemon.py | 8 ++++----
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/daemon.py b/daemon.py
index 68894c865..df0cd6016 100644
--- a/daemon.py
+++ b/daemon.py
@@ -4721,6 +4721,12 @@ class PubServer(BaseHTTPRequestHandler):
if 'vote:' + nickname not in newswire[dateStr][2]:
newswire[dateStr][2].append('vote:' + nickname)
filename = newswire[dateStr][3]
+ try:
+ newswireStateFilename = \
+ baseDir + '/accounts/.newswirestate.json'
+ saveJson(newswire, newswireStateFilename)
+ except Exception as e:
+ print('ERROR saving newswire state, ' + str(e))
if filename:
saveJson(newswire[dateStr][2],
filename + '.votes')
@@ -4762,6 +4768,12 @@ class PubServer(BaseHTTPRequestHandler):
if 'vote:' + nickname in newswire[dateStr][2]:
newswire[dateStr][2].remove('vote:' + nickname)
filename = newswire[dateStr][3]
+ try:
+ newswireStateFilename = \
+ baseDir + '/accounts/.newswirestate.json'
+ saveJson(newswire, newswireStateFilename)
+ except Exception as e:
+ print('ERROR saving newswire state, ' + str(e))
if filename:
saveJson(newswire[dateStr][2],
filename + '.votes')
diff --git a/newsdaemon.py b/newsdaemon.py
index 4792732d4..47d4a24c9 100644
--- a/newsdaemon.py
+++ b/newsdaemon.py
@@ -146,7 +146,7 @@ def runNewswireDaemon(baseDir: str, httpd,
translate: {}) -> None:
"""Periodically updates RSS feeds
"""
- newswireFilename = baseDir + '/accounts/.currentnewswire.json'
+ newswireStateFilename = baseDir + '/accounts/.newswirestate.json'
# initial sleep to allow the system to start up
time.sleep(50)
@@ -167,13 +167,13 @@ def runNewswireDaemon(baseDir: str, httpd,
continue
if not httpd.newswire:
- if os.path.isfile(newswireFilename):
- httpd.newswire = loadJson(newswireFilename)
+ if os.path.isfile(newswireStateFilename):
+ httpd.newswire = loadJson(newswireStateFilename)
mergeWithPreviousNewswire(httpd.newswire, newNewswire)
httpd.newswire = newNewswire
- saveJson(httpd.newswire, newswireFilename)
+ saveJson(httpd.newswire, newswireStateFilename)
print('Newswire updated')
convertRSStoActivityPub(baseDir,
From b79ce4321f599ef6b44e5f280f657c3c307efb8c Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 10:43:34 +0100
Subject: [PATCH 122/263] Function name change
---
newsdaemon.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/newsdaemon.py b/newsdaemon.py
index 47d4a24c9..b4162e3b7 100644
--- a/newsdaemon.py
+++ b/newsdaemon.py
@@ -16,7 +16,7 @@ from utils import saveJson
from utils import getStatusNumber
-def updateFeedsIndex(baseDir: str, domain: str, postId: str) -> None:
+def updateFeedsOutboxIndex(baseDir: str, domain: str, postId: str) -> None:
"""Updates the index used for imported RSS feeds
"""
basePath = baseDir + '/accounts/news@' + domain
@@ -121,7 +121,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
# save the post and update the index
if saveJson(blog, filename):
- updateFeedsIndex(baseDir, domain, postId + '.json')
+ updateFeedsOutboxIndex(baseDir, domain, postId + '.json')
# set the url
newswire[originalDateStr][1] = \
'/users/news/statuses/' + statusNumber
From 105daa49e88be2d6ff4cbdc11d88400c55ff2be2 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 11:05:01 +0100
Subject: [PATCH 123/263] Record the time when rss posts arrived
---
newsdaemon.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/newsdaemon.py b/newsdaemon.py
index b4162e3b7..c7567bbe8 100644
--- a/newsdaemon.py
+++ b/newsdaemon.py
@@ -8,6 +8,7 @@ __status__ = "Production"
import os
import time
+import datetime
from collections import OrderedDict
from newswire import getDictFromNewswire
from posts import createNewsPost
@@ -53,6 +54,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
if not os.path.isdir(basePath):
os.mkdir(basePath)
+ # oldest items first
newswireReverse = \
OrderedDict(sorted(newswire.items(), reverse=False))
@@ -62,6 +64,8 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
dateStr = dateStr.replace(' ', 'T')
dateStr = dateStr.replace('+00:00', 'Z')
+ # pubDate = datetime.strptime(dateStr, "%Y-%m-%dT%H:%M:%SZ")
+
statusNumber, published = getStatusNumber(dateStr)
newPostId = \
httpPrefix + '://' + domain + \
@@ -107,6 +111,11 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
httpPrefix + '://' + domain + '/users/news' + \
'/statuses/' + statusNumber + '/replies'
blog['news'] = True
+
+ # note the time of arrival
+ currTime = datetime.datetime.utcnow()
+ blog['object']['arrived'] = currTime.strftime("%Y-%m-%dT%H:%M:%SZ")
+
blog['object']['replies']['id'] = idStr
blog['object']['replies']['first']['partOf'] = idStr
From 5d4fff9398b3f378a52297181147121904b0423f Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 11:08:01 +0100
Subject: [PATCH 124/263] Comments
---
newsdaemon.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/newsdaemon.py b/newsdaemon.py
index c7567bbe8..d6c222b41 100644
--- a/newsdaemon.py
+++ b/newsdaemon.py
@@ -99,6 +99,9 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
followersOnly = False
useBlurhash = False
+ # NOTE: the id when the post is created will not be
+ # consistent (it's based on the current time, not the
+ # published time), so we change that later
blog = createNewsPost(baseDir,
domain, port, httpPrefix,
rssDescription, followersOnly, False,
@@ -116,6 +119,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
currTime = datetime.datetime.utcnow()
blog['object']['arrived'] = currTime.strftime("%Y-%m-%dT%H:%M:%SZ")
+ # change the id, based upon the published time
blog['object']['replies']['id'] = idStr
blog['object']['replies']['first']['partOf'] = idStr
From 8bc9e2f9c7bc583c4e61ced483d82bdd862e715c Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 11:12:02 +0100
Subject: [PATCH 125/263] Longer description
---
translations/en.json | 2 +-
translations/oc.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/translations/en.json b/translations/en.json
index c8bb47660..7aa266745 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -295,7 +295,7 @@
"Right column image": "Right column image",
"RSS feed for this site": "RSS feed for this site",
"Edit newswire": "Edit newswire",
- "Add RSS feed links below.": "Add RSS feed links below.",
+ "Add RSS feed links below.": "RSS feed links below. Add a * at the beginning or end to indicate that a feed should be moderated.",
"Newswire RSS Feed": "Newswire RSS Feed",
"Nicknames whose blog entries appear on the newswire.": "Nicknames whose blog entries appear on the newswire.",
"Posts to be approved": "Posts to be approved",
diff --git a/translations/oc.json b/translations/oc.json
index 23780037b..55d94dda9 100644
--- a/translations/oc.json
+++ b/translations/oc.json
@@ -291,7 +291,7 @@
"Right column image": "Right column image",
"RSS feed for this site": "RSS feed for this site",
"Edit newswire": "Edit newswire",
- "Add RSS feed links below.": "Add RSS feed links below.",
+ "Add RSS feed links below.": "RSS feed links below. Add a * at the beginning or end to indicate that a feed should be moderated.",
"Newswire RSS Feed": "Newswire RSS Feed",
"Nicknames whose blog entries appear on the newswire.": "Nicknames whose blog entries appear on the newswire.",
"Posts to be approved": "Posts to be approved",
From 85162673f55af51eca7ceff3992a9b052f9bb5fa Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 11:33:06 +0100
Subject: [PATCH 126/263] Add a moderated flag to newswire entries
---
newsdaemon.py | 2 +-
newswire.py | 38 ++++++++++++++++++++++++++++++--------
2 files changed, 31 insertions(+), 9 deletions(-)
diff --git a/newsdaemon.py b/newsdaemon.py
index d6c222b41..36602fa73 100644
--- a/newsdaemon.py
+++ b/newsdaemon.py
@@ -95,7 +95,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
rssDescription += \
'\n\n' + translate['Read more...'] + '\n' + url
else:
- rssDescription = url
+ rssDescription = translate['Read more...'] + '\n' + url
followersOnly = False
useBlurhash = False
diff --git a/newswire.py b/newswire.py
index e814dfeb3..5e80e2551 100644
--- a/newswire.py
+++ b/newswire.py
@@ -47,7 +47,7 @@ def rss2Footer() -> str:
return rssStr
-def xml2StrToDict(xmlStr: str) -> {}:
+def xml2StrToDict(xmlStr: str, moderated: bool) -> {}:
"""Converts an xml 2.0 string to a dictionary
"""
if '- ' not in xmlStr:
@@ -85,7 +85,7 @@ def xml2StrToDict(xmlStr: str) -> {}:
votesStatus = []
result[str(publishedDate)] = [title, link,
votesStatus, postFilename,
- description]
+ description, moderated]
parsed = True
except BaseException:
pass
@@ -101,15 +101,15 @@ def xml2StrToDict(xmlStr: str) -> {}:
return result
-def xmlStrToDict(xmlStr: str) -> {}:
+def xmlStrToDict(xmlStr: str, moderated: bool) -> {}:
"""Converts an xml string to a dictionary
"""
if 'rss version="2.0"' in xmlStr:
- return xml2StrToDict(xmlStr)
+ return xml2StrToDict(xmlStr, moderated)
return {}
-def getRSS(session, url: str) -> {}:
+def getRSS(session, url: str, moderated: bool) -> {}:
"""Returns an RSS url as a dict
"""
if not isinstance(url, str):
@@ -132,7 +132,7 @@ def getRSS(session, url: str) -> {}:
print('WARN: no session specified for getRSS')
try:
result = session.get(url, headers=sessionHeaders, params=sessionParams)
- return xmlStrToDict(result.text)
+ return xmlStrToDict(result.text, moderated)
except requests.exceptions.RequestException as e:
print('ERROR: getRSS failed\nurl: ' + str(url) + '\n' +
'headers: ' + str(sessionHeaders) + '\n' +
@@ -204,6 +204,16 @@ def addAccountBlogsToNewswire(baseDir: str, nickname: str, domain: str,
"""
if not os.path.isfile(indexFilename):
return
+ # local blog entries are unmoderated by default
+ moderated = False
+
+ # local blogs can potentially be moderated
+ moderatedFilename = \
+ baseDir + '/accounts/' + nickname + '@' + domain + \
+ '/.newswiremoderated'
+ if os.path.isfile(moderatedFilename):
+ moderated = True
+
with open(indexFilename, 'r') as indexFile:
postFilename = 'start'
ctr = 0
@@ -242,10 +252,11 @@ def addAccountBlogsToNewswire(baseDir: str, nickname: str, domain: str,
votes = []
if os.path.isfile(fullPostFilename + '.votes'):
votes = loadJson(fullPostFilename + '.votes')
+ description = ''
newswire[published] = \
[postJsonObject['object']['summary'],
postJsonObject['object']['url'], votes,
- fullPostFilename]
+ fullPostFilename, description, moderated]
ctr += 1
if ctr >= maxBlogsPerAccount:
@@ -312,11 +323,22 @@ def getDictFromNewswire(session, baseDir: str) -> {}:
result = {}
for url in rssFeed:
url = url.strip()
+
+ # Does this contain a url?
if '://' not in url:
continue
+
+ # is this a comment?
if url.startswith('#'):
continue
- itemsList = getRSS(session, url)
+
+ # should this feed be moderated?
+ moderated = False
+ if '*' in url:
+ moderated = True
+ url = url.replace('*', '').strip()
+
+ itemsList = getRSS(session, url, moderated)
for dateStr, item in itemsList.items():
result[dateStr] = item
From 5a946e4446ada113194a351aee702b7c8f99ed83 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 11:38:29 +0100
Subject: [PATCH 127/263] Also remove newswire state
---
scripts/clearnewswire | 3 +++
1 file changed, 3 insertions(+)
diff --git a/scripts/clearnewswire b/scripts/clearnewswire
index 1815e9015..8ecee1f0f 100755
--- a/scripts/clearnewswire
+++ b/scripts/clearnewswire
@@ -2,3 +2,6 @@
rm accounts/news@*/outbox/*
rm accounts/news@*/postcache/*
rm accounts/news@*/outbox.index
+if [ -f accounts/newswirestate.json ]; then
+ rm accounts/newswirestate.json
+fi
From 85a31ccd72859e56facc0cfd9ce072d60fa63556 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 11:39:13 +0100
Subject: [PATCH 128/263] Dotfile
---
scripts/clearnewswire | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/clearnewswire b/scripts/clearnewswire
index 8ecee1f0f..5fa01c627 100755
--- a/scripts/clearnewswire
+++ b/scripts/clearnewswire
@@ -2,6 +2,6 @@
rm accounts/news@*/outbox/*
rm accounts/news@*/postcache/*
rm accounts/news@*/outbox.index
-if [ -f accounts/newswirestate.json ]; then
- rm accounts/newswirestate.json
+if [ -f accounts/.newswirestate.json ]; then
+ rm accounts/.newswirestate.json
fi
From 947a13fba235316c17b1dfd3514ee49c29789c64 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 13:15:20 +0100
Subject: [PATCH 129/263] Voting time period
---
daemon.py | 66 ++++++++++++++++++++++++++++--------------
epicyon.py | 6 +++-
newsdaemon.py | 24 +++++++++++++--
person.py | 5 ++--
posts.py | 77 +++++++++++++++++++++++++++++--------------------
tests.py | 6 ++--
utils.py | 32 +++++++++++++++++++-
webinterface.py | 2 +-
8 files changed, 155 insertions(+), 63 deletions(-)
diff --git a/daemon.py b/daemon.py
index df0cd6016..fec45f864 100644
--- a/daemon.py
+++ b/daemon.py
@@ -6004,7 +6004,8 @@ class PubServer(BaseHTTPRequestHandler):
maxPostsInFeed, 'inbox',
authorized,
0,
- self.server.positiveVoting)
+ self.server.positiveVoting,
+ self.server.votingTimeMins)
if inboxFeed:
if GETstartTime:
self._benchmarkGETtimings(GETstartTime, GETtimings,
@@ -6034,7 +6035,8 @@ class PubServer(BaseHTTPRequestHandler):
maxPostsInFeed, 'inbox',
authorized,
0,
- self.server.positiveVoting)
+ self.server.positiveVoting,
+ self.server.votingTimeMins)
if GETstartTime:
self._benchmarkGETtimings(GETstartTime,
GETtimings,
@@ -6123,7 +6125,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInFeed, 'dm',
authorized,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
if inboxDMFeed:
if self._requestHTTP():
nickname = path.replace('/users/', '')
@@ -6149,7 +6152,8 @@ class PubServer(BaseHTTPRequestHandler):
maxPostsInFeed, 'dm',
authorized,
0,
- self.server.positiveVoting)
+ self.server.positiveVoting,
+ self.server.votingTimeMins)
msg = \
htmlInboxDMs(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6227,7 +6231,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInFeed, 'tlreplies',
True,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
if not inboxRepliesFeed:
inboxRepliesFeed = []
if self._requestHTTP():
@@ -6253,7 +6258,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInFeed, 'tlreplies',
True,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
msg = \
htmlInboxReplies(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6331,7 +6337,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInMediaFeed, 'tlmedia',
True,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
if not inboxMediaFeed:
inboxMediaFeed = []
if self._requestHTTP():
@@ -6357,7 +6364,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInMediaFeed, 'tlmedia',
True,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
msg = \
htmlInboxMedia(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6435,7 +6443,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInBlogsFeed, 'tlblogs',
True,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
if not inboxBlogsFeed:
inboxBlogsFeed = []
if self._requestHTTP():
@@ -6461,7 +6470,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInBlogsFeed, 'tlblogs',
True,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
msg = \
htmlInboxBlogs(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6541,7 +6551,8 @@ class PubServer(BaseHTTPRequestHandler):
maxPostsInNewsFeed, 'tlnews',
True,
self.server.newswireVotesThreshold,
- self.server.positiveVoting)
+ self.server.positiveVoting,
+ self.server.votingTimeMins)
if not inboxNewsFeed:
inboxNewsFeed = []
if self._requestHTTP():
@@ -6568,7 +6579,8 @@ class PubServer(BaseHTTPRequestHandler):
maxPostsInBlogsFeed, 'tlnews',
True,
self.server.newswireVotesThreshold,
- self.server.positiveVoting)
+ self.server.positiveVoting,
+ self.server.votingTimeMins)
currNickname = path.split('/users/')[1]
if '/' in currNickname:
currNickname = currNickname.split('/')[0]
@@ -6709,7 +6721,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInFeed, 'tlbookmarks',
authorized,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
if bookmarksFeed:
if self._requestHTTP():
nickname = path.replace('/users/', '')
@@ -6736,7 +6749,8 @@ class PubServer(BaseHTTPRequestHandler):
maxPostsInFeed,
'tlbookmarks',
authorized,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
msg = \
htmlBookmarks(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6816,7 +6830,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInFeed, 'tlevents',
authorized,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
print('eventsFeed: ' + str(eventsFeed))
if eventsFeed:
if self._requestHTTP():
@@ -6843,7 +6858,8 @@ class PubServer(BaseHTTPRequestHandler):
maxPostsInFeed,
'tlevents',
authorized,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
msg = \
htmlEvents(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -6916,7 +6932,8 @@ class PubServer(BaseHTTPRequestHandler):
maxPostsInFeed, 'outbox',
authorized,
self.server.newswireVotesThreshold,
- self.server.positiveVoting)
+ self.server.positiveVoting,
+ self.server.votingTimeMins)
if outboxFeed:
if self._requestHTTP():
nickname = \
@@ -6942,7 +6959,8 @@ class PubServer(BaseHTTPRequestHandler):
maxPostsInFeed, 'outbox',
authorized,
self.server.newswireVotesThreshold,
- self.server.positiveVoting)
+ self.server.positiveVoting,
+ self.server.votingTimeMins)
msg = \
htmlOutbox(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -7007,7 +7025,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInFeed, 'moderation',
True,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
if moderationFeed:
if self._requestHTTP():
nickname = path.replace('/users/', '')
@@ -7032,7 +7051,8 @@ class PubServer(BaseHTTPRequestHandler):
httpPrefix,
maxPostsInFeed, 'moderation',
True,
- 0, self.server.positiveVoting)
+ 0, self.server.positiveVoting,
+ self.server.votingTimeMins)
msg = \
htmlModeration(self.server.defaultTimeline,
self.server.recentPostsCache,
@@ -11387,7 +11407,8 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
tokensLookup[token] = nickname
-def runDaemon(positiveVoting: bool,
+def runDaemon(votingTimeMins: int,
+ positiveVoting: bool,
newswireVotesThreshold: int,
newsInstance: bool,
blogsInstance: bool,
@@ -11496,6 +11517,9 @@ def runDaemon(positiveVoting: bool,
print('ERROR: no translations loaded from ' + translationsFile)
sys.exit()
+ # For moderated newswire feeds this is the amount of time allowed
+ # for voting after the post arrives
+ httpd.votingTimeMins = votingTimeMins
# on the newswire, whether moderators vote positively for items
# or against them (veto)
httpd.positiveVoting = positiveVoting
diff --git a/epicyon.py b/epicyon.py
index 3ece2fe69..bdafac365 100644
--- a/epicyon.py
+++ b/epicyon.py
@@ -260,6 +260,9 @@ parser.add_argument('--minimumvotes', dest='minimumvotes', type=int,
default=1,
help='Minimum number of votes to remove or add' +
' a newswire item')
+parser.add_argument('--votingtime', dest='votingtime', type=int,
+ default=1440,
+ help='Time to vote on newswire items in minutes')
parser.add_argument('--message', dest='message', type=str,
default=None,
help='Message content')
@@ -1919,7 +1922,8 @@ if setTheme(baseDir, themeName):
print('Theme set to ' + themeName)
if __name__ == "__main__":
- runDaemon(args.positivevoting,
+ runDaemon(args.votingtime,
+ args.positivevoting,
args.minimumvotes,
args.newsinstance,
args.blogsinstance, args.mediainstance,
diff --git a/newsdaemon.py b/newsdaemon.py
index 36602fa73..45053a9e2 100644
--- a/newsdaemon.py
+++ b/newsdaemon.py
@@ -41,6 +41,15 @@ def updateFeedsOutboxIndex(baseDir: str, domain: str, postId: str) -> None:
feedsFile.close()
+def saveArrivedTime(baseDir: str, postFilename: str, arrived: str) -> None:
+ """Saves the time when an rss post arrived to a file
+ """
+ arrivedFile = open(postFilename + '.arrived', 'w+')
+ if arrivedFile:
+ arrivedFile.write(arrived)
+ arrivedFile.close()
+
+
def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
domain: str, port: int,
newswire: {},
@@ -87,8 +96,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
rssDescription = ''
# get the rss description if it exists
- if len(item) >= 5:
- rssDescription = item[4]
+ rssDescription = item[4]
# add the off-site link to the description
if rssDescription:
@@ -132,9 +140,21 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
postId = newPostId.replace('/', '#')
+ moderated = item[5]
+
# save the post and update the index
if saveJson(blog, filename):
updateFeedsOutboxIndex(baseDir, domain, postId + '.json')
+
+ # Save a file containing the time when the post arrived
+ # this can then later be used to construct the news timeline
+ # excluding items during the voting period
+ if moderated:
+ saveArrivedTime(baseDir, filename, blog['object']['arrived'])
+ else:
+ if os.path.isfile(filename + '.arrived'):
+ os.remove(filename + '.arrived')
+
# set the url
newswire[originalDateStr][1] = \
'/users/news/statuses/' + statusNumber
diff --git a/person.py b/person.py
index d58064a17..e0ee43e7a 100644
--- a/person.py
+++ b/person.py
@@ -596,7 +596,8 @@ def personBoxJson(recentPostsCache: {},
session, baseDir: str, domain: str, port: int, path: str,
httpPrefix: str, noOfItems: int, boxname: str,
authorized: bool,
- newswireVotesThreshold: int, positiveVoting: bool) -> {}:
+ newswireVotesThreshold: int, positiveVoting: bool,
+ votingTimeMins: int) -> {}:
"""Obtain the inbox/outbox/moderation feed for the given person
"""
if boxname != 'inbox' and boxname != 'dm' and \
@@ -673,7 +674,7 @@ def personBoxJson(recentPostsCache: {},
return createNewsTimeline(session, baseDir, nickname, domain, port,
httpPrefix, noOfItems, headerOnly,
newswireVotesThreshold, positiveVoting,
- pageNumber)
+ votingTimeMins, pageNumber)
elif boxname == 'tlblogs':
return createBlogsTimeline(session, baseDir, nickname, domain, port,
httpPrefix, noOfItems, headerOnly,
diff --git a/posts.py b/posts.py
index 648fbde60..75282a232 100644
--- a/posts.py
+++ b/posts.py
@@ -47,6 +47,7 @@ from utils import loadJson
from utils import saveJson
from utils import getConfigParam
from utils import locateNewsVotes
+from utils import locateNewsArrival
from utils import votesOnNewswireItem
from media import attachMedia
from media import replaceYouTube
@@ -2476,7 +2477,7 @@ def createInbox(recentPostsCache: {},
session, baseDir, 'inbox',
nickname, domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
- 0, False, pageNumber)
+ 0, False, 0, pageNumber)
def createBookmarksTimeline(session, baseDir: str, nickname: str, domain: str,
@@ -2485,7 +2486,7 @@ def createBookmarksTimeline(session, baseDir: str, nickname: str, domain: str,
return createBoxIndexed({}, session, baseDir, 'tlbookmarks',
nickname, domain,
port, httpPrefix, itemsPerPage, headerOnly,
- True, 0, False, pageNumber)
+ True, 0, False, 0, pageNumber)
def createEventsTimeline(recentPostsCache: {},
@@ -2495,7 +2496,7 @@ def createEventsTimeline(recentPostsCache: {},
return createBoxIndexed(recentPostsCache, session, baseDir, 'tlevents',
nickname, domain,
port, httpPrefix, itemsPerPage, headerOnly,
- True, 0, False, pageNumber)
+ True, 0, False, 0, pageNumber)
def createDMTimeline(recentPostsCache: {},
@@ -2505,7 +2506,7 @@ def createDMTimeline(recentPostsCache: {},
return createBoxIndexed(recentPostsCache,
session, baseDir, 'dm', nickname,
domain, port, httpPrefix, itemsPerPage,
- headerOnly, True, 0, False, pageNumber)
+ headerOnly, True, 0, False, 0, pageNumber)
def createRepliesTimeline(recentPostsCache: {},
@@ -2515,7 +2516,7 @@ def createRepliesTimeline(recentPostsCache: {},
return createBoxIndexed(recentPostsCache, session, baseDir, 'tlreplies',
nickname, domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
- 0, False, pageNumber)
+ 0, False, 0, pageNumber)
def createBlogsTimeline(session, baseDir: str, nickname: str, domain: str,
@@ -2524,7 +2525,7 @@ def createBlogsTimeline(session, baseDir: str, nickname: str, domain: str,
return createBoxIndexed({}, session, baseDir, 'tlblogs', nickname,
domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
- 0, False, pageNumber)
+ 0, False, 0, pageNumber)
def createMediaTimeline(session, baseDir: str, nickname: str, domain: str,
@@ -2533,18 +2534,19 @@ def createMediaTimeline(session, baseDir: str, nickname: str, domain: str,
return createBoxIndexed({}, session, baseDir, 'tlmedia', nickname,
domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
- 0, False, pageNumber)
+ 0, False, 0, pageNumber)
def createNewsTimeline(session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str, itemsPerPage: int,
headerOnly: bool, newswireVotesThreshold: int,
- positiveVoting: bool, pageNumber=None) -> {}:
+ positiveVoting: bool, votingTimeMins: int,
+ pageNumber=None) -> {}:
return createBoxIndexed({}, session, baseDir, 'outbox', 'news',
domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
newswireVotesThreshold, positiveVoting,
- pageNumber)
+ votingTimeMins, pageNumber)
def createOutbox(session, baseDir: str, nickname: str, domain: str,
@@ -2554,7 +2556,7 @@ def createOutbox(session, baseDir: str, nickname: str, domain: str,
return createBoxIndexed({}, session, baseDir, 'outbox',
nickname, domain, port, httpPrefix,
itemsPerPage, headerOnly, authorized,
- 0, False, pageNumber)
+ 0, False, 0, pageNumber)
def createModeration(baseDir: str, nickname: str, domain: str, port: int,
@@ -2848,7 +2850,7 @@ def createBoxIndexed(recentPostsCache: {},
nickname: str, domain: str, port: int, httpPrefix: str,
itemsPerPage: int, headerOnly: bool, authorized: bool,
newswireVotesThreshold: int, positiveVoting: bool,
- pageNumber=None) -> {}:
+ votingTimeMins: int, pageNumber=None) -> {}:
"""Constructs the box feed for a person with the given nickname
"""
if not authorized or not pageNumber:
@@ -2919,27 +2921,38 @@ def createBoxIndexed(recentPostsCache: {},
# apply votes within this timeline
if newswireVotesThreshold > 0:
- # if there a votes file for this post?
- votesFilename = \
- locateNewsVotes(baseDir, domain, postFilename)
- if votesFilename:
- # load the votes file and count the votes
- votesJson = loadJson(votesFilename, 0, 2)
- if votesJson:
- if not positiveVoting:
- if votesOnNewswireItem(votesJson) >= \
- newswireVotesThreshold:
- # Too many veto votes.
- # Continue without incrementing the
- # posts counter
- continue
- else:
- if votesOnNewswireItem < \
- newswireVotesThreshold:
- # Not enough votes.
- # Continue without incrementing the
- # posts counter
- continue
+ # note that the presence of an arrival file also indicates
+ # that this post is moderated
+ arrivalDate = \
+ locateNewsArrival(baseDir, domain, postFilename)
+ if arrivalDate:
+ # how long has elapsed since this post arrived?
+ currDate = datetime.datetime.now()
+ timeDiffMins = \
+ int((currDate - arrivalDate).total_seconds() / 60)
+ # has the voting time elapsed?
+ if timeDiffMins > votingTimeMins:
+ # if there a votes file for this post?
+ votesFilename = \
+ locateNewsVotes(baseDir, domain, postFilename)
+ if votesFilename:
+ # load the votes file and count the votes
+ votesJson = loadJson(votesFilename, 0, 2)
+ if votesJson:
+ if not positiveVoting:
+ if votesOnNewswireItem(votesJson) >= \
+ newswireVotesThreshold:
+ # Too many veto votes.
+ # Continue without incrementing
+ # the posts counter
+ continue
+ else:
+ if votesOnNewswireItem < \
+ newswireVotesThreshold:
+ # Not enough votes.
+ # Continue without incrementing
+ # the posts counter
+ continue
# Skip through any posts previous to the current page
if postsCtr < int((pageNumber - 1) * itemsPerPage):
diff --git a/tests.py b/tests.py
index 0de1c0c6d..ea93839e1 100644
--- a/tests.py
+++ b/tests.py
@@ -287,7 +287,7 @@ def createServerAlice(path: str, domain: str, port: int,
onionDomain = None
i2pDomain = None
print('Server running: Alice')
- runDaemon(False, 1, False, False, False,
+ runDaemon(0, False, 1, False, False, False,
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
@@ -350,7 +350,7 @@ def createServerBob(path: str, domain: str, port: int,
onionDomain = None
i2pDomain = None
print('Server running: Bob')
- runDaemon(False, 1, False, False, False,
+ runDaemon(0, False, 1, False, False, False,
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
@@ -387,7 +387,7 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
onionDomain = None
i2pDomain = None
print('Server running: Eve')
- runDaemon(False, 1, False, False, False,
+ runDaemon(0, False, 1, False, False, False,
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
diff --git a/utils.py b/utils.py
index c83b22432..933c875e8 100644
--- a/utils.py
+++ b/utils.py
@@ -526,10 +526,40 @@ def locateNewsVotes(baseDir: str, domain: str,
else:
postUrl = postUrl + '.json.votes'
- accountDir = baseDir + '/accounts/news' + '@' + domain + '/'
+ accountDir = baseDir + '/accounts/news@' + domain + '/'
postFilename = accountDir + 'outbox/' + postUrl
if os.path.isfile(postFilename):
return postFilename
+
+ return None
+
+
+def locateNewsArrival(baseDir: str, domain: str,
+ postUrl: str) -> str:
+ """Returns the arrival time for a news post
+ within the news user account
+ """
+ postUrl = \
+ postUrl.strip().replace('\n', '').replace('\r', '')
+
+ # if this post in the shared inbox?
+ postUrl = removeIdEnding(postUrl.strip()).replace('/', '#')
+
+ if postUrl.endswith('.json'):
+ postUrl = postUrl + '.arrival'
+ else:
+ postUrl = postUrl + '.json.arrival'
+
+ accountDir = baseDir + '/accounts/news@' + domain + '/'
+ postFilename = accountDir + 'outbox/' + postUrl
+ if os.path.isfile(postFilename):
+ with open(postFilename, 'r') as arrivalFile:
+ arrival = arrivalFile.read()
+ if arrival:
+ arrivalDate = \
+ datetime.strptime(arrival, "%Y-%m-%dT%H:%M:%SZ")
+ return arrivalDate
+
return None
diff --git a/webinterface.py b/webinterface.py
index a3b43a31d..136722db4 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -2862,7 +2862,7 @@ def htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
str(currPage),
httpPrefix,
10, 'outbox',
- authorized, 0, False)
+ authorized, 0, False, 0)
if not outboxFeed:
break
if len(outboxFeed['orderedItems']) == 0:
From 9a341cd7932a3d265f81defa225b0272de0c479b Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 13:25:24 +0100
Subject: [PATCH 130/263] utc
---
posts.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/posts.py b/posts.py
index 75282a232..a23012e8b 100644
--- a/posts.py
+++ b/posts.py
@@ -2927,7 +2927,7 @@ def createBoxIndexed(recentPostsCache: {},
locateNewsArrival(baseDir, domain, postFilename)
if arrivalDate:
# how long has elapsed since this post arrived?
- currDate = datetime.datetime.now()
+ currDate = datetime.datetime.utcnow()
timeDiffMins = \
int((currDate - arrivalDate).total_seconds() / 60)
# has the voting time elapsed?
From 3ceb900e69373644f8d1270eb5f76cc07eb294f3 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 13:27:20 +0100
Subject: [PATCH 131/263] Debug
---
posts.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/posts.py b/posts.py
index a23012e8b..142ca2d4c 100644
--- a/posts.py
+++ b/posts.py
@@ -2926,10 +2926,13 @@ def createBoxIndexed(recentPostsCache: {},
arrivalDate = \
locateNewsArrival(baseDir, domain, postFilename)
if arrivalDate:
+ print('Arrival: ' + str(arrivalDate))
# how long has elapsed since this post arrived?
currDate = datetime.datetime.utcnow()
timeDiffMins = \
int((currDate - arrivalDate).total_seconds() / 60)
+ print('Arrival: mins ' + \
+ str(timeDiffMins) + ' ' + str(votingTimeMins))
# has the voting time elapsed?
if timeDiffMins > votingTimeMins:
# if there a votes file for this post?
From 0aa5ce374b684a8fe01a0a5d992983602f2420bb Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 13:31:14 +0100
Subject: [PATCH 132/263] Debug
---
posts.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/posts.py b/posts.py
index 142ca2d4c..11f4f7b19 100644
--- a/posts.py
+++ b/posts.py
@@ -2925,8 +2925,9 @@ def createBoxIndexed(recentPostsCache: {},
# that this post is moderated
arrivalDate = \
locateNewsArrival(baseDir, domain, postFilename)
+ print('Arrival: ' + str(arrivalDate))
if arrivalDate:
- print('Arrival: ' + str(arrivalDate))
+ print('Arrival: date ' + str(arrivalDate))
# how long has elapsed since this post arrived?
currDate = datetime.datetime.utcnow()
timeDiffMins = \
From fe9047929f3513467ffdc32925293cfe99c54799 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 13:35:37 +0100
Subject: [PATCH 133/263] Debug
---
utils.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/utils.py b/utils.py
index 933c875e8..224549974 100644
--- a/utils.py
+++ b/utils.py
@@ -552,9 +552,11 @@ def locateNewsArrival(baseDir: str, domain: str,
accountDir = baseDir + '/accounts/news@' + domain + '/'
postFilename = accountDir + 'outbox/' + postUrl
+ print('Arrival: ' + str(postFilename))
if os.path.isfile(postFilename):
with open(postFilename, 'r') as arrivalFile:
arrival = arrivalFile.read()
+ print('Arrival: content ' + str(arrival))
if arrival:
arrivalDate = \
datetime.strptime(arrival, "%Y-%m-%dT%H:%M:%SZ")
From 31bc48df9e31505d6cc8d527a30235e64bb407c7 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 13:38:58 +0100
Subject: [PATCH 134/263] Arrived
---
utils.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/utils.py b/utils.py
index 224549974..4d82a3b0c 100644
--- a/utils.py
+++ b/utils.py
@@ -546,9 +546,9 @@ def locateNewsArrival(baseDir: str, domain: str,
postUrl = removeIdEnding(postUrl.strip()).replace('/', '#')
if postUrl.endswith('.json'):
- postUrl = postUrl + '.arrival'
+ postUrl = postUrl + '.arrived'
else:
- postUrl = postUrl + '.json.arrival'
+ postUrl = postUrl + '.json.arrived'
accountDir = baseDir + '/accounts/news@' + domain + '/'
postFilename = accountDir + 'outbox/' + postUrl
From 9a7a6db47b5ecce691a498de9e461b985ad310cf Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 13:41:32 +0100
Subject: [PATCH 135/263] Double date
---
utils.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/utils.py b/utils.py
index 4d82a3b0c..5f78de871 100644
--- a/utils.py
+++ b/utils.py
@@ -559,7 +559,8 @@ def locateNewsArrival(baseDir: str, domain: str,
print('Arrival: content ' + str(arrival))
if arrival:
arrivalDate = \
- datetime.strptime(arrival, "%Y-%m-%dT%H:%M:%SZ")
+ datetime.datetime.strptime(arrival,
+ "%Y-%m-%dT%H:%M:%SZ")
return arrivalDate
return None
From 53ed0774e63f3063c853b4328eb3c049f2373a37 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 13:48:13 +0100
Subject: [PATCH 136/263] Voting logic
---
posts.py | 47 +++++++++++++++++++++++++----------------------
1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/posts.py b/posts.py
index 11f4f7b19..2a05687ab 100644
--- a/posts.py
+++ b/posts.py
@@ -2935,28 +2935,31 @@ def createBoxIndexed(recentPostsCache: {},
print('Arrival: mins ' + \
str(timeDiffMins) + ' ' + str(votingTimeMins))
# has the voting time elapsed?
- if timeDiffMins > votingTimeMins:
- # if there a votes file for this post?
- votesFilename = \
- locateNewsVotes(baseDir, domain, postFilename)
- if votesFilename:
- # load the votes file and count the votes
- votesJson = loadJson(votesFilename, 0, 2)
- if votesJson:
- if not positiveVoting:
- if votesOnNewswireItem(votesJson) >= \
- newswireVotesThreshold:
- # Too many veto votes.
- # Continue without incrementing
- # the posts counter
- continue
- else:
- if votesOnNewswireItem < \
- newswireVotesThreshold:
- # Not enough votes.
- # Continue without incrementing
- # the posts counter
- continue
+ if timeDiffMins < votingTimeMins:
+ # voting is still happening, so don't add this
+ # post to the timeline
+ continue
+ # if there a votes file for this post?
+ votesFilename = \
+ locateNewsVotes(baseDir, domain, postFilename)
+ if votesFilename:
+ # load the votes file and count the votes
+ votesJson = loadJson(votesFilename, 0, 2)
+ if votesJson:
+ if not positiveVoting:
+ if votesOnNewswireItem(votesJson) >= \
+ newswireVotesThreshold:
+ # Too many veto votes.
+ # Continue without incrementing
+ # the posts counter
+ continue
+ else:
+ if votesOnNewswireItem < \
+ newswireVotesThreshold:
+ # Not enough votes.
+ # Continue without incrementing
+ # the posts counter
+ continue
# Skip through any posts previous to the current page
if postsCtr < int((pageNumber - 1) * itemsPerPage):
From 513d0784e4f112eb6534c58c9bcad9d1b4eb94b0 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 13:52:56 +0100
Subject: [PATCH 137/263] Remove debug
---
posts.py | 4 ----
utils.py | 2 --
2 files changed, 6 deletions(-)
diff --git a/posts.py b/posts.py
index 2a05687ab..e67503dfc 100644
--- a/posts.py
+++ b/posts.py
@@ -2925,15 +2925,11 @@ def createBoxIndexed(recentPostsCache: {},
# that this post is moderated
arrivalDate = \
locateNewsArrival(baseDir, domain, postFilename)
- print('Arrival: ' + str(arrivalDate))
if arrivalDate:
- print('Arrival: date ' + str(arrivalDate))
# how long has elapsed since this post arrived?
currDate = datetime.datetime.utcnow()
timeDiffMins = \
int((currDate - arrivalDate).total_seconds() / 60)
- print('Arrival: mins ' + \
- str(timeDiffMins) + ' ' + str(votingTimeMins))
# has the voting time elapsed?
if timeDiffMins < votingTimeMins:
# voting is still happening, so don't add this
diff --git a/utils.py b/utils.py
index 5f78de871..4ae804ddf 100644
--- a/utils.py
+++ b/utils.py
@@ -552,11 +552,9 @@ def locateNewsArrival(baseDir: str, domain: str,
accountDir = baseDir + '/accounts/news@' + domain + '/'
postFilename = accountDir + 'outbox/' + postUrl
- print('Arrival: ' + str(postFilename))
if os.path.isfile(postFilename):
with open(postFilename, 'r') as arrivalFile:
arrival = arrivalFile.read()
- print('Arrival: content ' + str(arrival))
if arrival:
arrivalDate = \
datetime.datetime.strptime(arrival,
From e0ec134810a0820cb1cb4ce96cd2ad675b12f8a3 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 13:57:45 +0100
Subject: [PATCH 138/263] Delete arrived files
---
utils.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/utils.py b/utils.py
index 4ae804ddf..68f207f85 100644
--- a/utils.py
+++ b/utils.py
@@ -712,6 +712,11 @@ def deletePost(baseDir: str, httpPrefix: str,
if os.path.isfile(votesFilename):
os.remove(votesFilename)
+ # remove any arrived file
+ arrivedFilename = postFilename + '.arrived'
+ if os.path.isfile(arrivedFilename):
+ os.remove(arrivedFilename)
+
# remove cached html version of the post
cachedPostFilename = \
getCachedPostFilename(baseDir, nickname, domain, postJsonObject)
From 1a284f35673b2e48a38e8a80008eb40ee56f9f2d Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 14:08:06 +0100
Subject: [PATCH 139/263] Show moderatable newswire items in a different color
---
epicyon-profile.css | 15 +++++++++++++++
webinterface.py | 15 ++++++++++-----
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/epicyon-profile.css b/epicyon-profile.css
index fd329615e..700031b95 100644
--- a/epicyon-profile.css
+++ b/epicyon-profile.css
@@ -68,6 +68,8 @@
--quote-font-size: 120%;
--line-spacing: 130%;
--line-spacing-newswire: 100%;
+ --newswire-item-moderated-color: green;
+ --newswire-date-moderated-color: lightgreen;
--column-left-width: 10vw;
--column-center-width: 80vw;
--column-right-width: 10vw;
@@ -233,6 +235,19 @@ a:focus {
line-height: var(--line-spacing-newswire);
}
+.newswireItemModerated {
+ font-size: var(--font-size-newswire);
+ color: var(--newswire-item-moderated-color);
+ line-height: var(--line-spacing-newswire);
+}
+
+.newswireDateModerated {
+ font-size: var(--font-size-newswire);
+ font-weight: bold;
+ color: var(--newswire-date-moderated-color);
+ float: right;
+}
+
.newswireItemVotedOn a:link {
background: var(--newswire-voted-background-color);
}
diff --git a/webinterface.py b/webinterface.py
index 136722db4..b6b0ab4ca 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -5416,25 +5416,30 @@ def htmlNewswire(newswire: str, nickname: str, moderator: bool,
else:
totalVotesStr = ''
totalVotes = 0
+ moderatedItem = False
if moderator:
+ moderatedItem = item[5]
totalVotes = votesOnNewswireItem(item[2])
# show a number of ticks or crosses for how many
# votes for or against
totalVotesStr = \
votesIndicator(totalVotes, positiveVoting)
- htmlStr += '
' + \
- '' + item[0] + '' + \
- totalVotesStr
- if moderator:
+ if moderator and moderatedItem:
+ htmlStr += '
' + \
+ '' + item[0] + '' + \
+ totalVotesStr
htmlStr += \
' ' + \
'' + \
- ''
+ ''
htmlStr += dateStr.replace('+00:00', '') + '
'
else:
+ htmlStr += '' + \
+ '' + item[0] + '' + \
+ totalVotesStr
htmlStr += ' '
htmlStr += dateStr.replace('+00:00', '') + '
'
return htmlStr
From d60aad0659dd6c13f85a027d3ffecf2ab4eece0f Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 14:13:51 +0100
Subject: [PATCH 140/263] Newswire item colors
---
webinterface.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/webinterface.py b/webinterface.py
index b6b0ab4ca..0baba49a3 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -5427,8 +5427,9 @@ def htmlNewswire(newswire: str, nickname: str, moderator: bool,
if moderator and moderatedItem:
htmlStr += '' + \
- '' + item[0] + '' + \
- totalVotesStr
+ '' + \
+ '' + \
+ item[0] + '' + totalVotesStr
htmlStr += \
' ' + \
'' + \
- '' + item[0] + '' + \
+ '' + \
+ '' + \
+ item[0] + '' + \
totalVotesStr
htmlStr += ' '
htmlStr += dateStr.replace('+00:00', '') + '
'
From 19a420f758ab24e0a170283ca23b1110d3ca6770 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 14:20:45 +0100
Subject: [PATCH 141/263] Avoid lookups if not needed
---
webinterface.py | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/webinterface.py b/webinterface.py
index 0baba49a3..4819d8523 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -5419,11 +5419,12 @@ def htmlNewswire(newswire: str, nickname: str, moderator: bool,
moderatedItem = False
if moderator:
moderatedItem = item[5]
- totalVotes = votesOnNewswireItem(item[2])
- # show a number of ticks or crosses for how many
- # votes for or against
- totalVotesStr = \
- votesIndicator(totalVotes, positiveVoting)
+ if moderatedItem:
+ totalVotes = votesOnNewswireItem(item[2])
+ # show a number of ticks or crosses for how many
+ # votes for or against
+ totalVotesStr = \
+ votesIndicator(totalVotes, positiveVoting)
if moderator and moderatedItem:
htmlStr += '' + \
From 4dbbb3a9fa173defc3312762fe2db908ca1053e7 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Fri, 9 Oct 2020 14:26:59 +0100
Subject: [PATCH 142/263] span instead of label
---
webinterface.py | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/webinterface.py b/webinterface.py
index 4819d8523..ab08c07fa 100644
--- a/webinterface.py
+++ b/webinterface.py
@@ -5400,19 +5400,19 @@ def htmlNewswire(newswire: str, nickname: str, moderator: bool,
htmlStr += '' + \
'' + \
- '' + item[0] + \
- '' + totalVotesStr
+ '' + item[0] + \
+ '