From a23f47cdf3f5d2e8628481802f0cf47e23a8fa59 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 11:27:12 +0000
Subject: [PATCH 01/25] Keep track of when people that you are following were
last seen
---
inbox.py | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/inbox.py b/inbox.py
index 8969bc4b5..c8d71b1fd 100644
--- a/inbox.py
+++ b/inbox.py
@@ -67,6 +67,7 @@ from followingCalendar import receivingCalendarEvents
from content import dangerousMarkup
from happening import saveEventPost
from delete import removeOldHashtags
+from follow import isFollowingActor
def guessHashtagCategory(tagName: str, hashtagCategories: {}) -> str:
@@ -2066,6 +2067,30 @@ def inboxUpdateIndex(boxname: str, baseDir: str, handle: str,
return False
+def updateLastSeen(baseDir: str, handle: str, actor: str) -> None:
+ """Updates the time when the given handle last saw the given actor
+ """
+ if '@' not in handle:
+ return
+ nickname = handle.split('@')[0]
+ domain = handle.split('@')[1]
+ if ':' in domain:
+ domain = domain.split(':')[0]
+ accountPath = baseDir + '/accounts/' + nickname + '@' + domain
+ if not os.path.isdir(accountPath):
+ return
+ if not isFollowingActor(baseDir, nickname, domain, actor):
+ return
+ lastSeenPath = accountPath + '/lastseen'
+ if not os.path.isdir(lastSeenPath):
+ os.mkdir(lastSeenPath)
+ lastSeenFilename = lastSeenPath + '/' + actor.replace('/', '#') + '.txt'
+ currTime = datetime.datetime.utcnow()
+ daysSinceEpoch = (currTime - datetime.datetime(1970, 1, 1)).days
+ with open(lastSeenFilename, 'w+') as lastSeenFile:
+ lastSeenFile.write(str(daysSinceEpoch))
+
+
def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
session, keyId: str, handle: str, messageJson: {},
baseDir: str, httpPrefix: str, sendThreads: [],
@@ -2086,6 +2111,8 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
if '#' in actor:
actor = keyId.split('#')[0]
+ updateLastSeen(baseDir, handle, actor)
+
isGroup = groupHandle(baseDir, handle)
if receiveLike(recentPostsCache,
From 1cf2ea73f9746399b6b314aa57ad83629adce2fb Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 11:28:23 +0000
Subject: [PATCH 02/25] Comment
---
inbox.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/inbox.py b/inbox.py
index c8d71b1fd..5a86bfb71 100644
--- a/inbox.py
+++ b/inbox.py
@@ -2069,6 +2069,7 @@ def inboxUpdateIndex(boxname: str, baseDir: str, handle: str,
def updateLastSeen(baseDir: str, handle: str, actor: str) -> None:
"""Updates the time when the given handle last saw the given actor
+ This can later be used to indicate if accounts are dormant/abandoned/moved
"""
if '@' not in handle:
return
From 9ba729c6fd9b48966e541070af5417370375ba59 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 11:31:16 +0000
Subject: [PATCH 03/25] Fix unit test
---
tests.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests.py b/tests.py
index 3af8473b3..f856cf750 100644
--- a/tests.py
+++ b/tests.py
@@ -1683,7 +1683,7 @@ def testWebLinks():
'This post has a web links https://somesite.net\n\nAnd some other text'
linkedText = addWebLinks(exampleText)
assert \
- 'https://' + \
'somesite.net
Date: Sun, 13 Dec 2020 12:44:17 +0000
Subject: [PATCH 04/25] Mark dormant followed accounts on profile
---
daemon.py | 13 ++++++++++++-
epicyon.py | 8 +++++++-
tests.py | 12 +++++++++---
utils.py | 27 +++++++++++++++++++++++++++
webapp_profile.py | 29 +++++++++++++++++++++--------
5 files changed, 76 insertions(+), 13 deletions(-)
diff --git a/daemon.py b/daemon.py
index 3789becc2..8ae2d41ab 100644
--- a/daemon.py
+++ b/daemon.py
@@ -6491,6 +6491,7 @@ class PubServer(BaseHTTPRequestHandler):
YTReplacementDomain,
self.server.showPublishedDateOnly,
self.server.newswire,
+ self.server.dormantMonths,
actorJson['roles'],
None, None)
msg = msg.encode('utf-8')
@@ -6570,6 +6571,7 @@ class PubServer(BaseHTTPRequestHandler):
YTReplacementDomain,
showPublishedDateOnly,
self.server.newswire,
+ self.server.dormantMonths,
actorJson['skills'],
None, None)
msg = msg.encode('utf-8')
@@ -8258,6 +8260,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain,
self.server.showPublishedDateOnly,
self.server.newswire,
+ self.server.dormantMonths,
shares,
pageNumber, sharesPerPage)
msg = msg.encode('utf-8')
@@ -8349,6 +8352,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain,
self.server.showPublishedDateOnly,
self.server.newswire,
+ self.server.dormantMonths,
following,
pageNumber,
followsPerPage).encode('utf-8')
@@ -8440,6 +8444,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain,
self.server.showPublishedDateOnly,
self.server.newswire,
+ self.server.dormantMonths,
followers,
pageNumber,
followsPerPage).encode('utf-8')
@@ -8506,6 +8511,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain,
self.server.showPublishedDateOnly,
self.server.newswire,
+ self.server.dormantMonths,
None, None).encode('utf-8')
self._set_headers('text/html', len(msg),
cookie, callingDomain)
@@ -12926,7 +12932,8 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
tokensLookup[token] = nickname
-def runDaemon(maxNewswirePosts: int,
+def runDaemon(dormantMonths: int,
+ maxNewswirePosts: int,
allowLocalNetworkAccess: bool,
maxFeedItemSizeKb: int,
publishButtonAtTop: bool,
@@ -13120,6 +13127,10 @@ def runDaemon(maxNewswirePosts: int,
# maximum size of a hashtag category, in K
httpd.maxCategoriesFeedItemSizeKb = 1024
+ # how many months does a followed account need to be unseen
+ # for it to be considered dormant?
+ httpd.dormantMonths = dormantMonths
+
if registration == 'open':
httpd.registration = True
else:
diff --git a/epicyon.py b/epicyon.py
index 37df367e9..a9bfef608 100644
--- a/epicyon.py
+++ b/epicyon.py
@@ -116,6 +116,11 @@ parser.add_argument('--postsPerSource',
dest='maxNewswirePostsPerSource', type=int,
default=4,
help='Maximum newswire posts per feed or account')
+parser.add_argument('--dormantMonths',
+ dest='dormantMonths', type=int,
+ default=3,
+ help='How many months does a followed account need to ' +
+ 'be unseen for before being considered dormant')
parser.add_argument('--maxNewswirePosts',
dest='maxNewswirePosts', type=int,
default=20,
@@ -2080,7 +2085,8 @@ if setTheme(baseDir, themeName, domain, args.allowLocalNetworkAccess):
print('Theme set to ' + themeName)
if __name__ == "__main__":
- runDaemon(args.maxNewswirePosts,
+ runDaemon(args.dormantMonths,
+ args.maxNewswirePosts,
args.allowLocalNetworkAccess,
args.maxFeedItemSizeKb,
args.publishButtonAtTop,
diff --git a/tests.py b/tests.py
index f856cf750..c6c087707 100644
--- a/tests.py
+++ b/tests.py
@@ -296,8 +296,10 @@ def createServerAlice(path: str, domain: str, port: int,
i2pDomain = None
allowLocalNetworkAccess = True
maxNewswirePosts = 20
+ dormantMonths = 3
print('Server running: Alice')
- runDaemon(maxNewswirePosts, allowLocalNetworkAccess,
+ runDaemon(dormantMonths, maxNewswirePosts,
+ allowLocalNetworkAccess,
2048, False, True, False, False, True, 10, False,
0, 100, 1024, 5, False,
0, False, 1, False, False, False,
@@ -364,8 +366,10 @@ def createServerBob(path: str, domain: str, port: int,
i2pDomain = None
allowLocalNetworkAccess = True
maxNewswirePosts = 20
+ dormantMonths = 3
print('Server running: Bob')
- runDaemon(maxNewswirePosts, allowLocalNetworkAccess,
+ runDaemon(dormantMonths, maxNewswirePosts,
+ allowLocalNetworkAccess,
2048, False, True, False, False, True, 10, False,
0, 100, 1024, 5, False, 0,
False, 1, False, False, False,
@@ -406,8 +410,10 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
i2pDomain = None
allowLocalNetworkAccess = True
maxNewswirePosts = 20
+ dormantMonths = 3
print('Server running: Eve')
- runDaemon(maxNewswirePosts, allowLocalNetworkAccess,
+ runDaemon(dormantMonths, maxNewswirePosts,
+ allowLocalNetworkAccess,
2048, False, True, False, False, True, 10, False,
0, 100, 1024, 5, False, 0,
False, 1, False, False, False,
diff --git a/utils.py b/utils.py
index b02b71936..b79f760a2 100644
--- a/utils.py
+++ b/utils.py
@@ -19,6 +19,33 @@ from calendar import monthrange
from followingCalendar import addPersonToCalendar
+def isDormant(baseDir: str, nickname: str, domain: str, actor: str,
+ dormantMonths=3) -> bool:
+ """Is the given followed actor dormant, from the standpoint
+ of the given account
+ """
+ lastSeenFilename = \
+ baseDir + '/accounts/' + nickname + '@' + domain + \
+ '/lastseen/' + actor.replace('/', '#') + '.txt'
+
+ if not os.path.isfile(lastSeenFilename):
+ return False
+
+ with open(lastSeenFilename, 'r') as lastSeenFile:
+ daysSinceEpochStr = lastSeenFile.read()
+ if not daysSinceEpochStr:
+ return False
+ if not daysSinceEpochStr.isdigit():
+ return False
+ currTime = datetime.datetime.utcnow()
+ currDaysSinceEpoch = (currTime - datetime.datetime(1970, 1, 1)).days
+ timeDiffMonths = \
+ int((currDaysSinceEpoch - int(daysSinceEpochStr)) / 30)
+ if timeDiffMonths >= dormantMonths:
+ return True
+ return False
+
+
def getHashtagCategory(baseDir: str, hashtag: str) -> str:
"""Returns the category for the hashtag
"""
diff --git a/webapp_profile.py b/webapp_profile.py
index a6985d1f9..b8a1eb816 100644
--- a/webapp_profile.py
+++ b/webapp_profile.py
@@ -8,6 +8,7 @@ __status__ = "Production"
import os
from pprint import pprint
+from utils import isDormant
from utils import getNicknameFromActor
from utils import getDomainFromActor
from utils import isSystemAccount
@@ -364,8 +365,9 @@ def htmlProfile(rssIconAtTop: bool,
session, wfRequest: {}, personCache: {},
YTReplacementDomain: str,
showPublishedDateOnly: bool,
- newswire: {}, extraJson=None,
- pageNumber=None, maxItemsPerPage=None) -> str:
+ newswire: {}, dormantMonths: int,
+ extraJson=None, pageNumber=None,
+ maxItemsPerPage=None) -> str:
"""Show the profile page as html
"""
nickname = profileJson['preferredUsername']
@@ -628,7 +630,8 @@ def htmlProfile(rssIconAtTop: bool,
domain, port, session,
wfRequest, personCache, extraJson,
projectVersion, ["unfollow"], selected,
- usersPath, pageNumber, maxItemsPerPage)
+ usersPath, pageNumber, maxItemsPerPage,
+ dormantMonths)
elif selected == 'followers':
profileStr += \
htmlProfileFollowing(translate, baseDir, httpPrefix,
@@ -637,7 +640,7 @@ def htmlProfile(rssIconAtTop: bool,
wfRequest, personCache, extraJson,
projectVersion, ["block"],
selected, usersPath, pageNumber,
- maxItemsPerPage)
+ maxItemsPerPage, dormantMonths)
elif selected == 'roles':
profileStr += \
htmlProfileRoles(translate, nickname, domainFull,
@@ -719,7 +722,8 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
buttons: [],
feedName: str, actor: str,
pageNumber: int,
- maxItemsPerPage: int) -> str:
+ maxItemsPerPage: int,
+ dormantMonths: int) -> str:
"""Shows following on the profile screen
"""
profileStr = ''
@@ -737,12 +741,18 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
translate['Page up'] + '">\n' + \
' \n'
- for item in followingJson['orderedItems']:
+ for followingActor in followingJson['orderedItems']:
+ dormant = False
+ if feedName == 'following':
+ dormant = \
+ isDormant(baseDir, nickname, domain, followingActor,
+ dormantMonths)
profileStr += \
individualFollowAsHtml(translate, baseDir, session,
wfRequest, personCache,
- domain, item, authorized, nickname,
- httpPrefix, projectVersion,
+ domain, followingActor,
+ authorized, nickname,
+ httpPrefix, projectVersion, dormant,
buttons)
if authorized and maxItemsPerPage and pageNumber:
if len(followingJson['orderedItems']) >= maxItemsPerPage:
@@ -1436,12 +1446,15 @@ def individualFollowAsHtml(translate: {},
actorNickname: str,
httpPrefix: str,
projectVersion: str,
+ dormant: bool,
buttons=[]) -> str:
"""An individual follow entry on the profile screen
"""
nickname = getNicknameFromActor(followUrl)
domain, port = getDomainFromActor(followUrl)
titleStr = '@' + nickname + '@' + domain
+ if dormant:
+ titleStr += '💤'
avatarUrl = getPersonAvatarUrl(baseDir, followUrl, personCache, True)
if not avatarUrl:
avatarUrl = followUrl + '/avatar.png'
From 7905c9b35dff4fc1cf796b46e85c20e62fe050e0 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 12:45:29 +0000
Subject: [PATCH 05/25] Only show dormant status if authorized
---
webapp_profile.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/webapp_profile.py b/webapp_profile.py
index b8a1eb816..b1651d278 100644
--- a/webapp_profile.py
+++ b/webapp_profile.py
@@ -743,7 +743,7 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
for followingActor in followingJson['orderedItems']:
dormant = False
- if feedName == 'following':
+ if authorized and feedName == 'following':
dormant = \
isDormant(baseDir, nickname, domain, followingActor,
dormantMonths)
From e4c34ec6ad5a0daf52176dfb952cef2c02d3258b Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 12:48:04 +0000
Subject: [PATCH 06/25] Comment
---
webapp_profile.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/webapp_profile.py b/webapp_profile.py
index b1651d278..c2c5ac9c7 100644
--- a/webapp_profile.py
+++ b/webapp_profile.py
@@ -742,11 +742,13 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
' \n'
for followingActor in followingJson['orderedItems']:
+ # is this a dormant followed account?
dormant = False
if authorized and feedName == 'following':
dormant = \
isDormant(baseDir, nickname, domain, followingActor,
dormantMonths)
+
profileStr += \
individualFollowAsHtml(translate, baseDir, session,
wfRequest, personCache,
@@ -754,6 +756,7 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
authorized, nickname,
httpPrefix, projectVersion, dormant,
buttons)
+
if authorized and maxItemsPerPage and pageNumber:
if len(followingJson['orderedItems']) >= maxItemsPerPage:
# page down arrow
From 9ed343865d3dee33e91b12dd754e70f003ba3f14 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 12:57:57 +0000
Subject: [PATCH 07/25] Show dormant status on person options screen
---
daemon.py | 3 ++-
webapp_person_options.py | 13 +++++++++++--
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/daemon.py b/daemon.py
index 8ae2d41ab..3002e21c7 100644
--- a/daemon.py
+++ b/daemon.py
@@ -4987,7 +4987,8 @@ class PubServer(BaseHTTPRequestHandler):
ssbAddress, blogAddress,
toxAddress, jamiAddress,
PGPpubKey, PGPfingerprint,
- emailAddress).encode('utf-8')
+ emailAddress,
+ self.server.dormantMonths).encode('utf-8')
self._set_headers('text/html', len(msg),
cookie, callingDomain)
self._write(msg)
diff --git a/webapp_person_options.py b/webapp_person_options.py
index aa60ed3e1..f6f098e81 100644
--- a/webapp_person_options.py
+++ b/webapp_person_options.py
@@ -11,6 +11,7 @@ from shutil import copyfile
from petnames import getPetName
from person import isPersonSnoozed
from posts import isModerator
+from utils import isDormant
from utils import removeHtml
from utils import getDomainFromActor
from utils import getNicknameFromActor
@@ -39,7 +40,8 @@ def htmlPersonOptions(defaultTimeline: str,
jamiAddress: str,
PGPpubKey: str,
PGPfingerprint: str,
- emailAddress) -> str:
+ emailAddress: str,
+ dormantMonths: int) -> str:
"""Show options for a person: view/follow/block/report
"""
optionsDomain, optionsPort = getDomainFromActor(optionsActor)
@@ -53,6 +55,7 @@ def htmlPersonOptions(defaultTimeline: str,
copyfile(baseDir + '/accounts/options-background.jpg',
baseDir + '/accounts/options-background.jpg')
+ dormant = False
followStr = 'Follow'
blockStr = 'Block'
nickname = None
@@ -66,6 +69,9 @@ def htmlPersonOptions(defaultTimeline: str,
followerDomain, followerPort = getDomainFromActor(optionsActor)
if isFollowingActor(baseDir, nickname, domain, optionsActor):
followStr = 'Unfollow'
+ dormant = \
+ isDormant(baseDir, nickname, domain, optionsActor,
+ dormantMonths)
optionsNickname = getNicknameFromActor(optionsActor)
optionsDomainFull = optionsDomain
@@ -107,9 +113,12 @@ def htmlPersonOptions(defaultTimeline: str,
optionsStr += '
\n'
handle = getNicknameFromActor(optionsActor) + '@' + optionsDomain
+ handleShown = handle
+ if dormant:
+ handleShown += '💤'
optionsStr += \
' ' + translate['Options for'] + \
- ' @' + handle + '
\n'
+ ' @' + handleShown + '
\n'
if emailAddress:
optionsStr += \
'' + translate['Email'] + \
From 2127252ca012a6fb7ee450818cba77472f108121 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 13:43:09 +0000
Subject: [PATCH 08/25] Add space
---
utils.py | 7 ++-----
webapp_person_options.py | 2 +-
webapp_profile.py | 2 +-
3 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/utils.py b/utils.py
index b79f760a2..120a02394 100644
--- a/utils.py
+++ b/utils.py
@@ -33,14 +33,11 @@ def isDormant(baseDir: str, nickname: str, domain: str, actor: str,
with open(lastSeenFilename, 'r') as lastSeenFile:
daysSinceEpochStr = lastSeenFile.read()
- if not daysSinceEpochStr:
- return False
- if not daysSinceEpochStr.isdigit():
- return False
+ daysSinceEpoch = int(daysSinceEpoch)
currTime = datetime.datetime.utcnow()
currDaysSinceEpoch = (currTime - datetime.datetime(1970, 1, 1)).days
timeDiffMonths = \
- int((currDaysSinceEpoch - int(daysSinceEpochStr)) / 30)
+ int((currDaysSinceEpoch - daysSinceEpochStr) / 30)
if timeDiffMonths >= dormantMonths:
return True
return False
diff --git a/webapp_person_options.py b/webapp_person_options.py
index f6f098e81..b18d5460a 100644
--- a/webapp_person_options.py
+++ b/webapp_person_options.py
@@ -115,7 +115,7 @@ def htmlPersonOptions(defaultTimeline: str,
handle = getNicknameFromActor(optionsActor) + '@' + optionsDomain
handleShown = handle
if dormant:
- handleShown += '💤'
+ handleShown += ' 💤'
optionsStr += \
' ' + translate['Options for'] + \
' @' + handleShown + '
\n'
diff --git a/webapp_profile.py b/webapp_profile.py
index c2c5ac9c7..21fdbc4e1 100644
--- a/webapp_profile.py
+++ b/webapp_profile.py
@@ -1457,7 +1457,7 @@ def individualFollowAsHtml(translate: {},
domain, port = getDomainFromActor(followUrl)
titleStr = '@' + nickname + '@' + domain
if dormant:
- titleStr += '💤'
+ titleStr += ' 💤'
avatarUrl = getPersonAvatarUrl(baseDir, followUrl, personCache, True)
if not avatarUrl:
avatarUrl = followUrl + '/avatar.png'
From e727cc4c22dbab326a10ca0a43590af0ebd6d509 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 13:45:06 +0000
Subject: [PATCH 09/25] String
---
utils.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/utils.py b/utils.py
index 120a02394..84c001a24 100644
--- a/utils.py
+++ b/utils.py
@@ -33,11 +33,11 @@ def isDormant(baseDir: str, nickname: str, domain: str, actor: str,
with open(lastSeenFilename, 'r') as lastSeenFile:
daysSinceEpochStr = lastSeenFile.read()
- daysSinceEpoch = int(daysSinceEpoch)
+ daysSinceEpoch = int(daysSinceEpochStr)
currTime = datetime.datetime.utcnow()
currDaysSinceEpoch = (currTime - datetime.datetime(1970, 1, 1)).days
timeDiffMonths = \
- int((currDaysSinceEpoch - daysSinceEpochStr) / 30)
+ int((currDaysSinceEpoch - daysSinceEpoch) / 30)
if timeDiffMonths >= dormantMonths:
return True
return False
From e1123279c82e8d2cf3387604b5503a76ccd274c5 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 13:49:32 +0000
Subject: [PATCH 10/25] Dormant months can be set in config file
---
epicyon.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/epicyon.py b/epicyon.py
index a9bfef608..214605140 100644
--- a/epicyon.py
+++ b/epicyon.py
@@ -2037,6 +2037,11 @@ maxFeedItemSizeKb = \
if maxFeedItemSizeKb is not None:
args.maxFeedItemSizeKb = int(maxFeedItemSizeKb)
+dormantMonths = \
+ getConfigParam(baseDir, 'dormantMonths')
+if dormantMonths is not None:
+ args.dormantMonths = int(dormantMonths)
+
allowNewsFollowers = \
getConfigParam(baseDir, 'allowNewsFollowers')
if allowNewsFollowers is not None:
From f94f6eb997e3fec2fc3dc6828405f5dc5f17ce5b Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 14:31:22 +0000
Subject: [PATCH 11/25] Don't write time to file if it hasn't changed
---
inbox.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/inbox.py b/inbox.py
index 5a86bfb71..0489aff7a 100644
--- a/inbox.py
+++ b/inbox.py
@@ -2088,6 +2088,13 @@ def updateLastSeen(baseDir: str, handle: str, actor: str) -> None:
lastSeenFilename = lastSeenPath + '/' + actor.replace('/', '#') + '.txt'
currTime = datetime.datetime.utcnow()
daysSinceEpoch = (currTime - datetime.datetime(1970, 1, 1)).days
+ # has the value changed?
+ if os.path.isfile(lastSeenFilename):
+ with open(lastSeenFilename, 'r') as lastSeenFile:
+ daysSinceEpochFile = lastSeenFile.read()
+ if int(daysSinceEpochFile) == daysSinceEpoch:
+ # value hasn't changed, so we can save writing anything to file
+ return
with open(lastSeenFilename, 'w+') as lastSeenFile:
lastSeenFile.write(str(daysSinceEpoch))
From 121a24d432fb2b10089acbc07586a3966335dda4 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 14:48:45 +0000
Subject: [PATCH 12/25] Test that css is not dangerous
---
tests.py | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/tests.py b/tests.py
index c6c087707..05cbd5b4d 100644
--- a/tests.py
+++ b/tests.py
@@ -75,6 +75,7 @@ from inbox import guessHashtagCategory
from content import htmlReplaceEmailQuote
from content import htmlReplaceQuoteMarks
from content import dangerousMarkup
+from content import dangerousCSS
from content import addWebLinks
from content import replaceEmojiFromTags
from content import addHtmlTags
@@ -1984,6 +1985,17 @@ def testRemoveHtml():
assert(removeHtml(testStr) == 'This string has html.')
+def testDangerousCSS():
+ print('testDangerousCSS')
+ baseDir = os.getcwd()
+ for subdir, dirs, files in os.walk(baseDir):
+ for f in files:
+ if not f.endswith('.css'):
+ continue
+ assert not dangerousCSS(baseDir + '/' + f, False)
+ break
+
+
def testDangerousMarkup():
print('testDangerousMarkup')
allowLocalNetworkAccess = False
@@ -2483,6 +2495,7 @@ def runAllTests():
testRemoveIdEnding()
testJsonPostAllowsComments()
runHtmlReplaceQuoteMarks()
+ testDangerousCSS()
testDangerousMarkup()
testRemoveHtml()
testSiteIsActive()
From 3872426f3583babada9b8e2d702a63c222bea3a1 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 18:24:25 +0000
Subject: [PATCH 13/25] Ensure that mentions appear in cc
---
posts.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/posts.py b/posts.py
index 01d8b9fd6..115cbf344 100644
--- a/posts.py
+++ b/posts.py
@@ -898,6 +898,16 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
if eventUUID:
postObjectType = 'Event'
+ # public posts with mentions should include the mentioned
+ # actors within CC
+ # "I think we don’t notify about mentions unless the person
+ # is also addressed in to/cc" -- gargron
+ if toRecipients and toCC and mentionedRecipients:
+ if len(toRecipients) == 1 and len(toCC) == 1:
+ if toRecipients[0].endswith('#Public') and \
+ toCC[0].endswith('/followers'):
+ toCC += mentionedRecipients
+
if not clientToServer:
actorUrl = httpPrefix + '://' + domain + '/users/' + nickname
From e9c0c4c3a97524c7bf8c0535ca0b8e2bb2900f3a Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 19:05:26 +0000
Subject: [PATCH 14/25] Unit test for getting mentions
---
posts.py | 10 ----------
tests.py | 16 ++++++++++++++++
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/posts.py b/posts.py
index 115cbf344..01d8b9fd6 100644
--- a/posts.py
+++ b/posts.py
@@ -898,16 +898,6 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
if eventUUID:
postObjectType = 'Event'
- # public posts with mentions should include the mentioned
- # actors within CC
- # "I think we don’t notify about mentions unless the person
- # is also addressed in to/cc" -- gargron
- if toRecipients and toCC and mentionedRecipients:
- if len(toRecipients) == 1 and len(toCC) == 1:
- if toRecipients[0].endswith('#Public') and \
- toCC[0].endswith('/followers'):
- toCC += mentionedRecipients
-
if not clientToServer:
actorUrl = httpPrefix + '://' + domain + '/users/' + nickname
diff --git a/tests.py b/tests.py
index 05cbd5b4d..a1befe72c 100644
--- a/tests.py
+++ b/tests.py
@@ -20,6 +20,7 @@ from cache import getPersonFromCache
from threads import threadWithTrace
from daemon import runDaemon
from session import createSession
+from posts import getMentionedPeople
from posts import validContentWarning
from posts import deleteAllPosts
from posts import createPublicPost
@@ -2479,8 +2480,23 @@ def testGuessHashtagCategory() -> None:
assert guess == "bar"
+def testGetMentionedPeople() -> None:
+ print('testGetMentionedPeople')
+ baseDir = os.getcwd()
+
+ content = "@dragon@cave.site @bat@cave.site This is a test."
+ actors = getMentionedPeople(baseDir, 'https',
+ content,
+ 'mydomain', False)
+ assert actors
+ assert len(actors) == 2
+ assert actors[0] == "https://cave.site/users/dragon"
+ assert actors[1] == "https://cave.site/users/bat"
+
+
def runAllTests():
print('Running tests...')
+ testGetMentionedPeople()
testGuessHashtagCategory()
testValidNickname()
testParseFeedDate()
From 9d176ab77dd89bd3655a7e2e4aca7d962f76bb9e Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 19:53:31 +0000
Subject: [PATCH 15/25] Unit test for reply to public post
---
tests.py | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/tests.py b/tests.py
index a1befe72c..8329152d2 100644
--- a/tests.py
+++ b/tests.py
@@ -2494,8 +2494,41 @@ def testGetMentionedPeople() -> None:
assert actors[1] == "https://cave.site/users/bat"
+def testReplyToPublicPost() -> None:
+ baseDir = os.getcwd()
+ nickname = 'test7492362'
+ domain = 'other.site'
+ port = 443
+ httpPrefix = 'https'
+ postId = httpPrefix + '://rat.site/users/ninjarodent/statuses/63746173435'
+ reply = \
+ createPublicPost(baseDir, nickname, domain, port, httpPrefix,
+ "@ninjarodent@rat.site This is a test.",
+ False, False, False, True,
+ None, None, False, postId)
+ print(str(reply))
+ assert reply['object']['content'] == \
+ '' + \
+ '@ninjarodent' + \
+ ' This is a test.
'
+ assert reply['object']['tag'][0]['type'] == 'Mention'
+ assert reply['object']['tag'][0]['name'] == '@ninjarodent@rat.site'
+ assert reply['object']['tag'][0]['href'] == \
+ 'https://rat.site/users/ninjarodent'
+ assert len(reply['object']['to']) == 1
+ assert reply['object']['to'][0].endswith('#Public')
+ assert len(reply['object']['cc']) >= 1
+ assert reply['object']['cc'][0].endswith(nickname + '/followers')
+ assert len(reply['object']['tag']) == 1
+ assert len(reply['object']['cc']) == 2
+ assert reply['object']['cc'][1] == \
+ httpPrefix + '://rat.site/users/ninjarodent'
+
+
def runAllTests():
print('Running tests...')
+ testReplyToPublicPost()
testGetMentionedPeople()
testGuessHashtagCategory()
testValidNickname()
From 88b0a6aa6f11f91a2e8d1f7836ed6fa139bbfe58 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 20:07:45 +0000
Subject: [PATCH 16/25] Check if tag already exists
---
content.py | 9 +++++++++
posts.py | 4 +++-
tests.py | 2 +-
3 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/content.py b/content.py
index 4de6effa4..be9afd3ae 100644
--- a/content.py
+++ b/content.py
@@ -508,6 +508,15 @@ def addEmoji(baseDir: str, wordStr: str,
return True
+def tagExists(tagType: str, tagName: str, tags: {}) -> bool:
+ """Returns true if a tag exists in the given dict
+ """
+ for tag in tags:
+ if tag['name'] == tagName and tag['type'] == tagType:
+ return True
+ return False
+
+
def addMention(wordStr: str, httpPrefix: str, following: str,
replaceMentions: {}, recipients: [], tags: {}) -> bool:
"""Detects mentions and adds them to the replacements dict and
diff --git a/posts.py b/posts.py
index 01d8b9fd6..0d3715013 100644
--- a/posts.py
+++ b/posts.py
@@ -52,6 +52,7 @@ from utils import votesOnNewswireItem
from utils import removeHtml
from media import attachMedia
from media import replaceYouTube
+from content import tagExists
from content import removeLongWords
from content import addHtmlTags
from content import replaceEmojiFromTags
@@ -801,7 +802,8 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
isPublic = True
break
for tagName, tag in hashtagsDict.items():
- tags.append(tag)
+ if not tagExists(tag['type'], tag['name'], tags):
+ tags.append(tag)
if isPublic:
updateHashtagsIndex(baseDir, tag, newPostId)
print('Content tags: ' + str(tags))
diff --git a/tests.py b/tests.py
index 8329152d2..fc8d9d739 100644
--- a/tests.py
+++ b/tests.py
@@ -2506,7 +2506,7 @@ def testReplyToPublicPost() -> None:
"@ninjarodent@rat.site This is a test.",
False, False, False, True,
None, None, False, postId)
- print(str(reply))
+ # print(str(reply))
assert reply['object']['content'] == \
'' + \
'
Date: Sun, 13 Dec 2020 20:30:08 +0000
Subject: [PATCH 17/25] Fix reply unit test
---
posts.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/posts.py b/posts.py
index 0d3715013..b5c3cd3b1 100644
--- a/posts.py
+++ b/posts.py
@@ -1012,6 +1012,16 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
if newPost.get('object'):
newPost['object']['cc'] = [ccUrl]
+ # if this is a public post then include any mentions in cc
+ toCC = newPost['object']['cc']
+ if len(toRecipients) == 1:
+ if toRecipients[0].endswith('#Public') and \
+ ccUrl.endswith('/followers'):
+ for tag in tags:
+ if tag['type'] == 'Mention':
+ if tag['href'] not in toCC:
+ toCC.append(tag['href'])
+
# if this is a moderation report then add a status
if isModerationReport:
# add status
From 12cccfdeb6679601aefd8efc9cffc77cfcc82260 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 22:01:10 +0000
Subject: [PATCH 18/25] Populate last seen files on startup
---
daemon.py | 3 +++
follow.py | 36 ++++++++++++++++++++++++++++++++++++
2 files changed, 39 insertions(+)
diff --git a/daemon.py b/daemon.py
index 3002e21c7..0465c4696 100644
--- a/daemon.py
+++ b/daemon.py
@@ -89,6 +89,7 @@ from inbox import getPersonPubKey
from follow import getFollowingFeed
from follow import sendFollowRequest
from follow import unfollowPerson
+from follow import createInitialLastSeen
from auth import authorize
from auth import createPassword
from auth import createBasicAuthHeader
@@ -13261,6 +13262,8 @@ def runDaemon(dormantMonths: int,
httpd.iconsCache = {}
httpd.fontsCache = {}
+ createInitialLastSeen(baseDir, httpPrefix)
+
print('Creating inbox queue')
httpd.thrInboxQueue = \
threadWithTrace(target=runInboxQueue,
diff --git a/follow.py b/follow.py
index 9403f92ea..53349f050 100644
--- a/follow.py
+++ b/follow.py
@@ -27,6 +27,42 @@ from auth import createBasicAuthHeader
from session import postJson
+def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None:
+ """Creates initial lastseen files for all follows
+ """
+ for subdir, dirs, files in os.walk(baseDir + '/accounts'):
+ for acct in dirs:
+ if '@' not in acct:
+ continue
+ if 'inbox@' in acct or 'news@' in acct:
+ continue
+ accountDir = os.path.join(baseDir + '/accounts', acct)
+ followingFilename = accountDir + '/following.txt'
+ if not os.path.isfile(followingFilename):
+ continue
+ lastSeenDir = accountDir + '/lastseen'
+ if not os.path.isdir(lastSeenDir):
+ os.mkdir(lastSeenDir)
+ with open(followingFilename, 'r') as fp:
+ followingHandles = fp.readlines()
+ for handle in followingHandles:
+ if '#' in handle:
+ continue
+ if '@' not in handle:
+ continue
+ nickname = handle.split('@')[0]
+ domain = handle.split('@')[1]
+ actor = \
+ httpPrefix + '://' + \
+ nickname + '@' + domain + '/users/' + nickname
+ lastSeenFilename = \
+ lastSeenDir + '/' + actor.replace('/', '#') + '.txt'
+ if not os.path.isfile(lastSeenFilename):
+ with open(lastSeenFilename, 'w+') as fp:
+ fp.write(str(0))
+ break
+
+
def preApprovedFollower(baseDir: str,
nickname: str, domain: str,
approveHandle: str,
From e87fd5a168f90c7edcfe998fe5067e94725c9591 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 22:13:45 +0000
Subject: [PATCH 19/25] Break after loop
---
blog.py | 4 ++++
daemon.py | 3 +++
delete.py | 1 +
devices.py | 1 +
follow.py | 1 +
inbox.py | 4 ++++
media.py | 1 +
migrate.py | 1 +
newswire.py | 1 +
posts.py | 1 +
schedule.py | 1 +
shares.py | 2 ++
theme.py | 1 +
utils.py | 6 ++++++
webapp_hashtagswarm.py | 1 +
webapp_search.py | 3 +++
webapp_utils.py | 1 +
17 files changed, 33 insertions(+)
diff --git a/blog.py b/blog.py
index 418821163..3216f9b8a 100644
--- a/blog.py
+++ b/blog.py
@@ -622,6 +622,7 @@ def getBlogIndexesForAccounts(baseDir: str) -> {}:
blogsIndex = accountDir + '/tlblogs.index'
if os.path.isfile(blogsIndex):
blogIndexes[acct] = blogsIndex
+ break
return blogIndexes
@@ -639,6 +640,7 @@ def noOfBlogAccounts(baseDir: str) -> int:
blogsIndex = accountDir + '/tlblogs.index'
if os.path.isfile(blogsIndex):
ctr += 1
+ break
return ctr
@@ -655,6 +657,7 @@ def singleBlogAccountNickname(baseDir: str) -> str:
blogsIndex = accountDir + '/tlblogs.index'
if os.path.isfile(blogsIndex):
return acct.split('@')[0]
+ break
return None
@@ -698,6 +701,7 @@ def htmlBlogView(authorized: bool,
httpPrefix + '://' + domainFull + '/blog/' + \
acct.split('@')[0] + '">' + acct + ''
blogStr += '
'
+ break
return blogStr + htmlFooter()
diff --git a/daemon.py b/daemon.py
index 0465c4696..cb8add174 100644
--- a/daemon.py
+++ b/daemon.py
@@ -4789,6 +4789,7 @@ class PubServer(BaseHTTPRequestHandler):
port,
maxPostsInRSSFeed, 1,
False)
+ break
if msg:
msg = rss2Header(httpPrefix,
'news', domainFull,
@@ -12133,6 +12134,7 @@ class PubServer(BaseHTTPRequestHandler):
contentJson = loadJson(deviceFilename)
if contentJson:
devicesList.append(contentJson)
+ break
# return the list of devices for this handle
msg = \
json.dumps(devicesList,
@@ -12932,6 +12934,7 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
continue
tokensDict[nickname] = token
tokensLookup[token] = nickname
+ break
def runDaemon(dormantMonths: int,
diff --git a/delete.py b/delete.py
index 3b195db7e..58dbd5d28 100644
--- a/delete.py
+++ b/delete.py
@@ -321,6 +321,7 @@ def removeOldHashtags(baseDir: str, maxMonths: int) -> str:
# check of the file is too old
if fileDaysSinceEpoch < maxDaysSinceEpoch:
removeHashtags.append(tagsFilename)
+ break
for removeFilename in removeHashtags:
try:
diff --git a/devices.py b/devices.py
index 69c8d2ca7..3f0ef52bc 100644
--- a/devices.py
+++ b/devices.py
@@ -152,6 +152,7 @@ def E2EEdevicesCollection(baseDir: str, nickname: str, domain: str,
devJson = loadJson(deviceFilename)
if devJson:
deviceList.append(devJson)
+ break
devicesDict = {
'id': personId + '/collections/devices',
diff --git a/follow.py b/follow.py
index 53349f050..a8b2bd89f 100644
--- a/follow.py
+++ b/follow.py
@@ -1203,6 +1203,7 @@ def getFollowersOfActor(baseDir: str, actor: str, debug: bool) -> {}:
print('DEBUG: ' + account +
' follows ' + actorHandle)
recipientsDict[account] = None
+ break
return recipientsDict
diff --git a/inbox.py b/inbox.py
index 0489aff7a..4772a763b 100644
--- a/inbox.py
+++ b/inbox.py
@@ -200,6 +200,7 @@ def validInbox(baseDir: str, nickname: str, domain: str) -> bool:
if 'postNickname' in open(filename).read():
print('queue file incorrectly saved to ' + filename)
return False
+ break
return True
@@ -224,6 +225,7 @@ def validInboxFilenames(baseDir: str, nickname: str, domain: str,
print('Expected: ' + expectedStr)
print('Invalid filename: ' + filename)
return False
+ break
return True
@@ -2471,6 +2473,7 @@ def clearQueueItems(baseDir: str, queue: []) -> None:
ctr += 1
except BaseException:
pass
+ break
if ctr > 0:
print('Removed ' + str(ctr) + ' inbox queue items')
@@ -2487,6 +2490,7 @@ def restoreQueueItems(baseDir: str, queue: []) -> None:
for queuesubdir, queuedirs, queuefiles in os.walk(queueDir):
for qfile in queuefiles:
queue.append(os.path.join(queueDir, qfile))
+ break
if len(queue) > 0:
print('Restored ' + str(len(queue)) + ' inbox queue items')
diff --git a/media.py b/media.py
index 2163820d8..df6409f78 100644
--- a/media.py
+++ b/media.py
@@ -221,3 +221,4 @@ def archiveMedia(baseDir: str, archiveDirectory: str, maxWeeks=4) -> None:
else:
# archive to /dev/null
rmtree(os.path.join(baseDir + '/media', weekDir))
+ break
diff --git a/migrate.py b/migrate.py
index 6fb8bee28..4b04d8520 100644
--- a/migrate.py
+++ b/migrate.py
@@ -51,3 +51,4 @@ def migrateAccount(baseDir: str, oldHandle: str, newHandle: str) -> None:
migrateFollows(followFilename, oldHandle, newHandle)
followFilename = accountDir + '/followers.txt'
migrateFollows(followFilename, oldHandle, newHandle)
+ break
diff --git a/newswire.py b/newswire.py
index 144e7854a..a71ee2bff 100644
--- a/newswire.py
+++ b/newswire.py
@@ -760,6 +760,7 @@ def addBlogsToNewswire(baseDir: str, domain: str, newswire: {},
addAccountBlogsToNewswire(baseDir, nickname, domain,
newswire, maxBlogsPerAccount,
blogsIndex, maxTags)
+ break
# sort the moderation dict into chronological order, latest first
sortedModerationDict = \
diff --git a/posts.py b/posts.py
index b5c3cd3b1..b35c0505b 100644
--- a/posts.py
+++ b/posts.py
@@ -3195,6 +3195,7 @@ def archivePosts(baseDir: str, httpPrefix: str, archiveDir: str,
archivePostsForPerson(httpPrefix, nickname, domain, baseDir,
'outbox', archiveSubdir,
recentPostsCache, maxPostsInBox)
+ break
def archivePostsForPerson(httpPrefix: str, nickname: str, domain: str,
diff --git a/schedule.py b/schedule.py
index 919ab2b70..c213c4ec5 100644
--- a/schedule.py
+++ b/schedule.py
@@ -146,6 +146,7 @@ def runPostSchedule(baseDir: str, httpd, maxScheduledPosts: int):
if not os.path.isfile(scheduleIndexFilename):
continue
updatePostSchedule(baseDir, account, httpd, maxScheduledPosts)
+ break
def runPostScheduleWatchdog(projectVersion: str, httpd) -> None:
diff --git a/shares.py b/shares.py
index 9c9cba297..d4b19b36e 100644
--- a/shares.py
+++ b/shares.py
@@ -167,6 +167,7 @@ def addShare(baseDir: str,
'/users/' + nickname + '/tlshares')
except BaseException:
pass
+ break
def expireShares(baseDir: str) -> None:
@@ -179,6 +180,7 @@ def expireShares(baseDir: str) -> None:
nickname = account.split('@')[0]
domain = account.split('@')[1]
expireSharesForAccount(baseDir, nickname, domain)
+ break
def expireSharesForAccount(baseDir: str, nickname: str, domain: str) -> None:
diff --git a/theme.py b/theme.py
index 4f85a9d5c..bc34fe1c3 100644
--- a/theme.py
+++ b/theme.py
@@ -557,6 +557,7 @@ def setThemeImages(baseDir: str, name: str) -> None:
os.remove(accountDir + '/right_col_image.png')
except BaseException:
pass
+ break
def setNewsAvatar(baseDir: str, name: str,
diff --git a/utils.py b/utils.py
index 84c001a24..4fd05450d 100644
--- a/utils.py
+++ b/utils.py
@@ -110,6 +110,7 @@ def getHashtagCategories(baseDir: str, recent=False, category=None) -> None:
else:
if hashtag not in hashtagCategories[categoryStr]:
hashtagCategories[categoryStr].append(hashtag)
+ break
return hashtagCategories
@@ -407,6 +408,7 @@ def getFollowersOfPerson(baseDir: str,
if account not in followers:
followers.append(account)
break
+ break
return followers
@@ -932,6 +934,7 @@ def clearFromPostCaches(baseDir: str, recentPostsCache: {},
if recentPostsCache.get('html'):
if recentPostsCache['html'].get(postId):
del recentPostsCache['html'][postId]
+ break
def locatePost(baseDir: str, nickname: str, domain: str,
@@ -1195,6 +1198,7 @@ def noOfAccounts(baseDir: str) -> bool:
if '@' in account:
if not account.startswith('inbox@'):
accountCtr += 1
+ break
return accountCtr
@@ -1217,6 +1221,7 @@ def noOfActiveAccountsMonthly(baseDir: str, months: int) -> bool:
timeDiff = (currTime - int(lastUsed))
if timeDiff < monthSeconds:
accountCtr += 1
+ break
return accountCtr
@@ -1493,6 +1498,7 @@ def searchBoxPosts(baseDir: str, nickname: str, domain: str,
res.append(filePath)
if len(res) >= maxResults:
return res
+ break
return res
diff --git a/webapp_hashtagswarm.py b/webapp_hashtagswarm.py
index 37e51060a..3dd92f54c 100644
--- a/webapp_hashtagswarm.py
+++ b/webapp_hashtagswarm.py
@@ -197,6 +197,7 @@ def htmlHashTagSwarm(baseDir: str, actor: str, translate: {}) -> str:
if categoryStr not in categorySwarm:
categorySwarm.append(categoryStr)
break
+ break
if not tagSwarm:
return ''
diff --git a/webapp_search.py b/webapp_search.py
index 378fa653d..13d8ea87a 100644
--- a/webapp_search.py
+++ b/webapp_search.py
@@ -256,6 +256,7 @@ def htmlSearchSharedItems(cssCache: {}, translate: {},
sharedItemsForm += '\n'
break
ctr = 0
+ break
if not resultsExist:
sharedItemsForm += \
'' + translate['No results'] + '
\n'
@@ -428,6 +429,7 @@ def htmlSkillsSearch(actor: str,
';' + actorJson['icon']['url']
if indexStr not in results:
results.append(indexStr)
+ break
if not instanceOnly:
# search actor cache
for subdir, dirs, files in os.walk(baseDir + '/cache/actors/'):
@@ -465,6 +467,7 @@ def htmlSkillsSearch(actor: str,
';' + actorJson['icon']['url']
if indexStr not in results:
results.append(indexStr)
+ break
results.sort(reverse=True)
diff --git a/webapp_utils.py b/webapp_utils.py
index ce54a0f49..f70d76036 100644
--- a/webapp_utils.py
+++ b/webapp_utils.py
@@ -429,6 +429,7 @@ def sharesTimelineJson(actor: str, pageNumber: int, itemsPerPage: int,
ctr += 1
if ctr >= maxSharesPerAccount:
break
+ break
# sort the shared items in descending order of publication date
sharesJson = OrderedDict(sorted(allSharesJson.items(), reverse=True))
lastPage = False
From 498d9035112ad7cedef15985f9af591c6f473920 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 22:20:28 +0000
Subject: [PATCH 20/25] Remove newlines
---
follow.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/follow.py b/follow.py
index a8b2bd89f..5fe8f9f69 100644
--- a/follow.py
+++ b/follow.py
@@ -51,7 +51,7 @@ def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None:
if '@' not in handle:
continue
nickname = handle.split('@')[0]
- domain = handle.split('@')[1]
+ domain = handle.split('@')[1].strip()
actor = \
httpPrefix + '://' + \
nickname + '@' + domain + '/users/' + nickname
From f3e0d4e17c73e5d555274fbcc55646a72296c8eb Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 22:23:39 +0000
Subject: [PATCH 21/25] Strip handle
---
follow.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/follow.py b/follow.py
index 5fe8f9f69..952c1d6f0 100644
--- a/follow.py
+++ b/follow.py
@@ -50,8 +50,9 @@ def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None:
continue
if '@' not in handle:
continue
+ handle = handle.strip()
nickname = handle.split('@')[0]
- domain = handle.split('@')[1].strip()
+ domain = handle.split('@')[1]
actor = \
httpPrefix + '://' + \
nickname + '@' + domain + '/users/' + nickname
From f1886ddd9c5912b4cbdf85d19f784e95c62c32ba Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 22:24:02 +0000
Subject: [PATCH 22/25] Remove newline
---
follow.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/follow.py b/follow.py
index 952c1d6f0..d278f85e1 100644
--- a/follow.py
+++ b/follow.py
@@ -50,7 +50,7 @@ def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None:
continue
if '@' not in handle:
continue
- handle = handle.strip()
+ handle = handle.replace('\n', '')
nickname = handle.split('@')[0]
domain = handle.split('@')[1]
actor = \
From 5fe459e656e8ea61be8ef8b7e46fe14d27aa805d Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 22:24:41 +0000
Subject: [PATCH 23/25] Debug
---
follow.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/follow.py b/follow.py
index d278f85e1..3c8389a99 100644
--- a/follow.py
+++ b/follow.py
@@ -58,6 +58,7 @@ def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None:
nickname + '@' + domain + '/users/' + nickname
lastSeenFilename = \
lastSeenDir + '/' + actor.replace('/', '#') + '.txt'
+ print('lastSeenFilename: ' + lastSeenFilename)
if not os.path.isfile(lastSeenFilename):
with open(lastSeenFilename, 'w+') as fp:
fp.write(str(0))
From a5597d1dcf03c686ea380f4fd6347ba16c3d929d Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 22:28:39 +0000
Subject: [PATCH 24/25] Non zero value
---
follow.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/follow.py b/follow.py
index 3c8389a99..1ff251852 100644
--- a/follow.py
+++ b/follow.py
@@ -61,7 +61,7 @@ def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None:
print('lastSeenFilename: ' + lastSeenFilename)
if not os.path.isfile(lastSeenFilename):
with open(lastSeenFilename, 'w+') as fp:
- fp.write(str(0))
+ fp.write(str(100))
break
From 8d29ac3cbe9ca0ede7cca91bc7b61700a17307e1 Mon Sep 17 00:00:00 2001
From: Bob Mottram
Date: Sun, 13 Dec 2020 22:32:13 +0000
Subject: [PATCH 25/25] Wrong actor url
---
follow.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/follow.py b/follow.py
index 1ff251852..bf44bc83e 100644
--- a/follow.py
+++ b/follow.py
@@ -54,8 +54,7 @@ def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None:
nickname = handle.split('@')[0]
domain = handle.split('@')[1]
actor = \
- httpPrefix + '://' + \
- nickname + '@' + domain + '/users/' + nickname
+ httpPrefix + '://' + domain + '/users/' + nickname
lastSeenFilename = \
lastSeenDir + '/' + actor.replace('/', '#') + '.txt'
print('lastSeenFilename: ' + lastSeenFilename)