Mark dormant followed accounts on profile

alt-html-css
Bob Mottram 2020-12-13 12:44:17 +00:00
parent 9ba729c6fd
commit d6e60ff3d3
5 changed files with 76 additions and 13 deletions

View File

@ -6491,6 +6491,7 @@ class PubServer(BaseHTTPRequestHandler):
YTReplacementDomain, YTReplacementDomain,
self.server.showPublishedDateOnly, self.server.showPublishedDateOnly,
self.server.newswire, self.server.newswire,
self.server.dormantMonths,
actorJson['roles'], actorJson['roles'],
None, None) None, None)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
@ -6570,6 +6571,7 @@ class PubServer(BaseHTTPRequestHandler):
YTReplacementDomain, YTReplacementDomain,
showPublishedDateOnly, showPublishedDateOnly,
self.server.newswire, self.server.newswire,
self.server.dormantMonths,
actorJson['skills'], actorJson['skills'],
None, None) None, None)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
@ -8258,6 +8260,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain, self.server.YTReplacementDomain,
self.server.showPublishedDateOnly, self.server.showPublishedDateOnly,
self.server.newswire, self.server.newswire,
self.server.dormantMonths,
shares, shares,
pageNumber, sharesPerPage) pageNumber, sharesPerPage)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
@ -8349,6 +8352,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain, self.server.YTReplacementDomain,
self.server.showPublishedDateOnly, self.server.showPublishedDateOnly,
self.server.newswire, self.server.newswire,
self.server.dormantMonths,
following, following,
pageNumber, pageNumber,
followsPerPage).encode('utf-8') followsPerPage).encode('utf-8')
@ -8440,6 +8444,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain, self.server.YTReplacementDomain,
self.server.showPublishedDateOnly, self.server.showPublishedDateOnly,
self.server.newswire, self.server.newswire,
self.server.dormantMonths,
followers, followers,
pageNumber, pageNumber,
followsPerPage).encode('utf-8') followsPerPage).encode('utf-8')
@ -8506,6 +8511,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.YTReplacementDomain, self.server.YTReplacementDomain,
self.server.showPublishedDateOnly, self.server.showPublishedDateOnly,
self.server.newswire, self.server.newswire,
self.server.dormantMonths,
None, None).encode('utf-8') None, None).encode('utf-8')
self._set_headers('text/html', len(msg), self._set_headers('text/html', len(msg),
cookie, callingDomain) cookie, callingDomain)
@ -12926,7 +12932,8 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
tokensLookup[token] = nickname tokensLookup[token] = nickname
def runDaemon(maxNewswirePosts: int, def runDaemon(dormantMonths: int,
maxNewswirePosts: int,
allowLocalNetworkAccess: bool, allowLocalNetworkAccess: bool,
maxFeedItemSizeKb: int, maxFeedItemSizeKb: int,
publishButtonAtTop: bool, publishButtonAtTop: bool,
@ -13120,6 +13127,10 @@ def runDaemon(maxNewswirePosts: int,
# maximum size of a hashtag category, in K # maximum size of a hashtag category, in K
httpd.maxCategoriesFeedItemSizeKb = 1024 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': if registration == 'open':
httpd.registration = True httpd.registration = True
else: else:

View File

@ -116,6 +116,11 @@ parser.add_argument('--postsPerSource',
dest='maxNewswirePostsPerSource', type=int, dest='maxNewswirePostsPerSource', type=int,
default=4, default=4,
help='Maximum newswire posts per feed or account') 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', parser.add_argument('--maxNewswirePosts',
dest='maxNewswirePosts', type=int, dest='maxNewswirePosts', type=int,
default=20, default=20,
@ -2080,7 +2085,8 @@ if setTheme(baseDir, themeName, domain, args.allowLocalNetworkAccess):
print('Theme set to ' + themeName) print('Theme set to ' + themeName)
if __name__ == "__main__": if __name__ == "__main__":
runDaemon(args.maxNewswirePosts, runDaemon(args.dormantMonths,
args.maxNewswirePosts,
args.allowLocalNetworkAccess, args.allowLocalNetworkAccess,
args.maxFeedItemSizeKb, args.maxFeedItemSizeKb,
args.publishButtonAtTop, args.publishButtonAtTop,

View File

@ -296,8 +296,10 @@ def createServerAlice(path: str, domain: str, port: int,
i2pDomain = None i2pDomain = None
allowLocalNetworkAccess = True allowLocalNetworkAccess = True
maxNewswirePosts = 20 maxNewswirePosts = 20
dormantMonths = 3
print('Server running: Alice') print('Server running: Alice')
runDaemon(maxNewswirePosts, allowLocalNetworkAccess, runDaemon(dormantMonths, maxNewswirePosts,
allowLocalNetworkAccess,
2048, False, True, False, False, True, 10, False, 2048, False, True, False, False, True, 10, False,
0, 100, 1024, 5, False, 0, 100, 1024, 5, False,
0, False, 1, False, False, False, 0, False, 1, False, False, False,
@ -364,8 +366,10 @@ def createServerBob(path: str, domain: str, port: int,
i2pDomain = None i2pDomain = None
allowLocalNetworkAccess = True allowLocalNetworkAccess = True
maxNewswirePosts = 20 maxNewswirePosts = 20
dormantMonths = 3
print('Server running: Bob') print('Server running: Bob')
runDaemon(maxNewswirePosts, allowLocalNetworkAccess, runDaemon(dormantMonths, maxNewswirePosts,
allowLocalNetworkAccess,
2048, False, True, False, False, True, 10, False, 2048, False, True, False, False, True, 10, False,
0, 100, 1024, 5, False, 0, 0, 100, 1024, 5, False, 0,
False, 1, False, False, False, False, 1, False, False, False,
@ -406,8 +410,10 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
i2pDomain = None i2pDomain = None
allowLocalNetworkAccess = True allowLocalNetworkAccess = True
maxNewswirePosts = 20 maxNewswirePosts = 20
dormantMonths = 3
print('Server running: Eve') print('Server running: Eve')
runDaemon(maxNewswirePosts, allowLocalNetworkAccess, runDaemon(dormantMonths, maxNewswirePosts,
allowLocalNetworkAccess,
2048, False, True, False, False, True, 10, False, 2048, False, True, False, False, True, 10, False,
0, 100, 1024, 5, False, 0, 0, 100, 1024, 5, False, 0,
False, 1, False, False, False, False, 1, False, False, False,

View File

@ -19,6 +19,33 @@ from calendar import monthrange
from followingCalendar import addPersonToCalendar 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: def getHashtagCategory(baseDir: str, hashtag: str) -> str:
"""Returns the category for the hashtag """Returns the category for the hashtag
""" """

View File

@ -8,6 +8,7 @@ __status__ = "Production"
import os import os
from pprint import pprint from pprint import pprint
from utils import isDormant
from utils import getNicknameFromActor from utils import getNicknameFromActor
from utils import getDomainFromActor from utils import getDomainFromActor
from utils import isSystemAccount from utils import isSystemAccount
@ -364,8 +365,9 @@ def htmlProfile(rssIconAtTop: bool,
session, wfRequest: {}, personCache: {}, session, wfRequest: {}, personCache: {},
YTReplacementDomain: str, YTReplacementDomain: str,
showPublishedDateOnly: bool, showPublishedDateOnly: bool,
newswire: {}, extraJson=None, newswire: {}, dormantMonths: int,
pageNumber=None, maxItemsPerPage=None) -> str: extraJson=None, pageNumber=None,
maxItemsPerPage=None) -> str:
"""Show the profile page as html """Show the profile page as html
""" """
nickname = profileJson['preferredUsername'] nickname = profileJson['preferredUsername']
@ -628,7 +630,8 @@ def htmlProfile(rssIconAtTop: bool,
domain, port, session, domain, port, session,
wfRequest, personCache, extraJson, wfRequest, personCache, extraJson,
projectVersion, ["unfollow"], selected, projectVersion, ["unfollow"], selected,
usersPath, pageNumber, maxItemsPerPage) usersPath, pageNumber, maxItemsPerPage,
dormantMonths)
elif selected == 'followers': elif selected == 'followers':
profileStr += \ profileStr += \
htmlProfileFollowing(translate, baseDir, httpPrefix, htmlProfileFollowing(translate, baseDir, httpPrefix,
@ -637,7 +640,7 @@ def htmlProfile(rssIconAtTop: bool,
wfRequest, personCache, extraJson, wfRequest, personCache, extraJson,
projectVersion, ["block"], projectVersion, ["block"],
selected, usersPath, pageNumber, selected, usersPath, pageNumber,
maxItemsPerPage) maxItemsPerPage, dormantMonths)
elif selected == 'roles': elif selected == 'roles':
profileStr += \ profileStr += \
htmlProfileRoles(translate, nickname, domainFull, htmlProfileRoles(translate, nickname, domainFull,
@ -719,7 +722,8 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
buttons: [], buttons: [],
feedName: str, actor: str, feedName: str, actor: str,
pageNumber: int, pageNumber: int,
maxItemsPerPage: int) -> str: maxItemsPerPage: int,
dormantMonths: int) -> str:
"""Shows following on the profile screen """Shows following on the profile screen
""" """
profileStr = '' profileStr = ''
@ -737,12 +741,18 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
translate['Page up'] + '"></a>\n' + \ translate['Page up'] + '"></a>\n' + \
' </center>\n' ' </center>\n'
for item in followingJson['orderedItems']: for followingActor in followingJson['orderedItems']:
dormant = False
if feedName == 'following':
dormant = \
isDormant(baseDir, nickname, domain, followingActor,
dormantMonths)
profileStr += \ profileStr += \
individualFollowAsHtml(translate, baseDir, session, individualFollowAsHtml(translate, baseDir, session,
wfRequest, personCache, wfRequest, personCache,
domain, item, authorized, nickname, domain, followingActor,
httpPrefix, projectVersion, authorized, nickname,
httpPrefix, projectVersion, dormant,
buttons) buttons)
if authorized and maxItemsPerPage and pageNumber: if authorized and maxItemsPerPage and pageNumber:
if len(followingJson['orderedItems']) >= maxItemsPerPage: if len(followingJson['orderedItems']) >= maxItemsPerPage:
@ -1436,12 +1446,15 @@ def individualFollowAsHtml(translate: {},
actorNickname: str, actorNickname: str,
httpPrefix: str, httpPrefix: str,
projectVersion: str, projectVersion: str,
dormant: bool,
buttons=[]) -> str: buttons=[]) -> str:
"""An individual follow entry on the profile screen """An individual follow entry on the profile screen
""" """
nickname = getNicknameFromActor(followUrl) nickname = getNicknameFromActor(followUrl)
domain, port = getDomainFromActor(followUrl) domain, port = getDomainFromActor(followUrl)
titleStr = '@' + nickname + '@' + domain titleStr = '@' + nickname + '@' + domain
if dormant:
titleStr += '💤'
avatarUrl = getPersonAvatarUrl(baseDir, followUrl, personCache, True) avatarUrl = getPersonAvatarUrl(baseDir, followUrl, personCache, True)
if not avatarUrl: if not avatarUrl:
avatarUrl = followUrl + '/avatar.png' avatarUrl = followUrl + '/avatar.png'