mirror of https://gitlab.com/bashrc2/epicyon
Merge branch 'main' of ssh://code.freedombone.net:2222/bashrc/epicyon into main
commit
578919b965
|
|
@ -369,7 +369,7 @@ def sendAnnounceViaServer(baseDir: str, session,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
fromNickname, fromDomain,
|
fromNickname, fromDomain,
|
||||||
postToBox)
|
postToBox, 73528)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ def sendAvailabilityViaServer(baseDir: str, session,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, nickname,
|
httpPrefix, nickname,
|
||||||
domain, postToBox)
|
domain, postToBox, 57262)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
|
|
@ -441,7 +441,7 @@ def sendBookmarkViaServer(baseDir: str, session,
|
||||||
fromPersonId, sharedInbox, avatarUrl,
|
fromPersonId, sharedInbox, avatarUrl,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
||||||
projectVersion, httpPrefix, fromNickname,
|
projectVersion, httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox)
|
fromDomain, postToBox, 72483)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -518,7 +518,7 @@ def sendUndoBookmarkViaServer(baseDir: str, session,
|
||||||
fromPersonId, sharedInbox, avatarUrl,
|
fromPersonId, sharedInbox, avatarUrl,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
||||||
projectVersion, httpPrefix, fromNickname,
|
projectVersion, httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox)
|
fromDomain, postToBox, 72528)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
251
daemon.py
251
daemon.py
|
|
@ -239,6 +239,8 @@ from newswire import loadHashtagCategories
|
||||||
from newsdaemon import runNewswireWatchdog
|
from newsdaemon import runNewswireWatchdog
|
||||||
from newsdaemon import runNewswireDaemon
|
from newsdaemon import runNewswireDaemon
|
||||||
from filters import isFiltered
|
from filters import isFiltered
|
||||||
|
from filters import addGlobalFilter
|
||||||
|
from filters import removeGlobalFilter
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1012,7 +1014,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
print('Waiting for previous outbox thread to end')
|
print('Waiting for previous outbox thread to end')
|
||||||
waitCtr = 0
|
waitCtr = 0
|
||||||
thName = accountOutboxThreadName
|
thName = accountOutboxThreadName
|
||||||
while self.server.outboxThread[thName].isAlive() and waitCtr < 8:
|
while self.server.outboxThread[thName].is_alive() and waitCtr < 8:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
waitCtr += 1
|
waitCtr += 1
|
||||||
if waitCtr >= 8:
|
if waitCtr >= 8:
|
||||||
|
|
@ -1506,6 +1508,10 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
moderationButton = 'block'
|
moderationButton = 'block'
|
||||||
elif moderationStr.startswith('submitUnblock'):
|
elif moderationStr.startswith('submitUnblock'):
|
||||||
moderationButton = 'unblock'
|
moderationButton = 'unblock'
|
||||||
|
elif moderationStr.startswith('submitFilter'):
|
||||||
|
moderationButton = 'filter'
|
||||||
|
elif moderationStr.startswith('submitUnfilter'):
|
||||||
|
moderationButton = 'unfilter'
|
||||||
elif moderationStr.startswith('submitSuspend'):
|
elif moderationStr.startswith('submitSuspend'):
|
||||||
moderationButton = 'suspend'
|
moderationButton = 'suspend'
|
||||||
elif moderationStr.startswith('submitUnsuspend'):
|
elif moderationStr.startswith('submitUnsuspend'):
|
||||||
|
|
@ -1526,6 +1532,10 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
suspendAccount(baseDir, nickname, domain)
|
suspendAccount(baseDir, nickname, domain)
|
||||||
if moderationButton == 'unsuspend':
|
if moderationButton == 'unsuspend':
|
||||||
unsuspendAccount(baseDir, nickname)
|
unsuspendAccount(baseDir, nickname)
|
||||||
|
if moderationButton == 'filter':
|
||||||
|
addGlobalFilter(baseDir, moderationText)
|
||||||
|
if moderationButton == 'unfilter':
|
||||||
|
removeGlobalFilter(baseDir, moderationText)
|
||||||
if moderationButton == 'block':
|
if moderationButton == 'block':
|
||||||
fullBlockDomain = None
|
fullBlockDomain = None
|
||||||
if moderationText.startswith('http') or \
|
if moderationText.startswith('http') or \
|
||||||
|
|
@ -1939,7 +1949,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
domain,
|
domain,
|
||||||
domainFull,
|
domainFull,
|
||||||
self.server.defaultTimeline,
|
self.server.defaultTimeline,
|
||||||
self.server.newswire).encode('utf-8')
|
self.server.newswire,
|
||||||
|
self.server.themeName).encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
self._write(msg)
|
self._write(msg)
|
||||||
|
|
@ -2032,7 +2043,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
domain,
|
domain,
|
||||||
domainFull,
|
domainFull,
|
||||||
self.server.defaultTimeline,
|
self.server.defaultTimeline,
|
||||||
self.server.newswire).encode('utf-8')
|
self.server.newswire,
|
||||||
|
self.server.themeName).encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
self._write(msg)
|
self._write(msg)
|
||||||
|
|
@ -3772,20 +3784,42 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
# which isn't implemented in Epicyon
|
# which isn't implemented in Epicyon
|
||||||
actorJson['discoverable'] = False
|
actorJson['discoverable'] = False
|
||||||
actorChanged = True
|
actorChanged = True
|
||||||
|
if not actorJson['@context'][2].get('orgSchema'):
|
||||||
|
actorJson['@context'][2]['orgSchema'] = \
|
||||||
|
'toot:orgSchema'
|
||||||
|
actorChanged = True
|
||||||
|
if not actorJson['@context'][2].get('skills'):
|
||||||
|
actorJson['@context'][2]['skills'] = 'toot:skills'
|
||||||
|
actorChanged = True
|
||||||
|
if not actorJson['@context'][2].get('shares'):
|
||||||
|
actorJson['@context'][2]['shares'] = 'toot:shares'
|
||||||
|
actorChanged = True
|
||||||
|
if not actorJson['@context'][2].get('roles'):
|
||||||
|
actorJson['@context'][2]['roles'] = 'toot:roles'
|
||||||
|
actorChanged = True
|
||||||
|
if not actorJson['@context'][2].get('availability'):
|
||||||
|
actorJson['@context'][2]['availaibility'] = \
|
||||||
|
'toot:availability'
|
||||||
|
if not actorJson['@context'][2].get('nomadicLocations'):
|
||||||
|
actorJson['@context'][2]['nomadicLocations'] = \
|
||||||
|
'toot:nomadicLocations'
|
||||||
|
actorChanged = True
|
||||||
|
if actorJson.get('capabilityAcquisitionEndpoint'):
|
||||||
|
del actorJson['capabilityAcquisitionEndpoint']
|
||||||
|
actorChanged = True
|
||||||
# update the avatar/image url file extension
|
# update the avatar/image url file extension
|
||||||
uploads = profileMediaTypesUploaded.items()
|
uploads = profileMediaTypesUploaded.items()
|
||||||
for mType, lastPart in uploads:
|
for mType, lastPart in uploads:
|
||||||
repStr = '/' + lastPart
|
repStr = '/' + lastPart
|
||||||
if mType == 'avatar':
|
if mType == 'avatar':
|
||||||
lastPartOfUrl = \
|
actorUrl = actorJson['icon']['url']
|
||||||
actorJson['icon']['url'].split('/')[-1]
|
lastPartOfUrl = actorUrl.split('/')[-1]
|
||||||
srchStr = '/' + lastPartOfUrl
|
srchStr = '/' + lastPartOfUrl
|
||||||
actorJson['icon']['url'] = \
|
actorUrl = actorUrl.replace(srchStr, repStr)
|
||||||
actorJson['icon']['url'].replace(srchStr,
|
actorJson['icon']['url'] = actorUrl
|
||||||
repStr)
|
print('actorUrl: ' + actorUrl)
|
||||||
if '.' in actorJson['icon']['url']:
|
if '.' in actorUrl:
|
||||||
imgExt = \
|
imgExt = actorUrl.split('.')[-1]
|
||||||
actorJson['icon']['url'].split('.')[-1]
|
|
||||||
if imgExt == 'jpg':
|
if imgExt == 'jpg':
|
||||||
imgExt = 'jpeg'
|
imgExt = 'jpeg'
|
||||||
actorJson['icon']['mediaType'] = \
|
actorJson['icon']['mediaType'] = \
|
||||||
|
|
@ -3814,6 +3848,9 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
if not skillName:
|
if not skillName:
|
||||||
skillCtr += 1
|
skillCtr += 1
|
||||||
continue
|
continue
|
||||||
|
if isFiltered(baseDir, nickname, domain, skillName):
|
||||||
|
skillCtr += 1
|
||||||
|
continue
|
||||||
skillValue = \
|
skillValue = \
|
||||||
fields.get('skillValue' + str(skillCtr))
|
fields.get('skillValue' + str(skillCtr))
|
||||||
if not skillValue:
|
if not skillValue:
|
||||||
|
|
@ -3826,6 +3863,9 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
int(skillValue):
|
int(skillValue):
|
||||||
actorChanged = True
|
actorChanged = True
|
||||||
newSkills[skillName] = int(skillValue)
|
newSkills[skillName] = int(skillValue)
|
||||||
|
skillsStr = self.server.translate['Skills']
|
||||||
|
setHashtagCategory(baseDir, skillName,
|
||||||
|
skillsStr.lower())
|
||||||
skillCtr += 1
|
skillCtr += 1
|
||||||
if len(actorJson['skills'].items()) != \
|
if len(actorJson['skills'].items()) != \
|
||||||
len(newSkills.items()):
|
len(newSkills.items()):
|
||||||
|
|
@ -3847,8 +3887,14 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
# change displayed name
|
# change displayed name
|
||||||
if fields.get('displayNickname'):
|
if fields.get('displayNickname'):
|
||||||
if fields['displayNickname'] != actorJson['name']:
|
if fields['displayNickname'] != actorJson['name']:
|
||||||
actorJson['name'] = \
|
displayName = \
|
||||||
removeHtml(fields['displayNickname'])
|
removeHtml(fields['displayNickname'])
|
||||||
|
if not isFiltered(baseDir,
|
||||||
|
nickname, domain,
|
||||||
|
displayName):
|
||||||
|
actorJson['name'] = displayName
|
||||||
|
else:
|
||||||
|
actorJson['name'] = nickname
|
||||||
actorChanged = True
|
actorChanged = True
|
||||||
|
|
||||||
# change media instance status
|
# change media instance status
|
||||||
|
|
@ -4136,18 +4182,20 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
if fields.get('bio'):
|
if fields.get('bio'):
|
||||||
if fields['bio'] != actorJson['summary']:
|
if fields['bio'] != actorJson['summary']:
|
||||||
bioStr = removeHtml(fields['bio'])
|
bioStr = removeHtml(fields['bio'])
|
||||||
actorTags = {}
|
if not isFiltered(baseDir,
|
||||||
actorJson['summary'] = \
|
nickname, domain, bioStr):
|
||||||
addHtmlTags(baseDir,
|
actorTags = {}
|
||||||
httpPrefix,
|
actorJson['summary'] = \
|
||||||
nickname,
|
addHtmlTags(baseDir,
|
||||||
domainFull,
|
httpPrefix,
|
||||||
bioStr, [], actorTags)
|
nickname,
|
||||||
if actorTags:
|
domainFull,
|
||||||
actorJson['tag'] = []
|
bioStr, [], actorTags)
|
||||||
for tagName, tag in actorTags.items():
|
if actorTags:
|
||||||
actorJson['tag'].append(tag)
|
actorJson['tag'] = []
|
||||||
actorChanged = True
|
for tagName, tag in actorTags.items():
|
||||||
|
actorJson['tag'].append(tag)
|
||||||
|
actorChanged = True
|
||||||
else:
|
else:
|
||||||
if actorJson['summary']:
|
if actorJson['summary']:
|
||||||
actorJson['summary'] = ''
|
actorJson['summary'] = ''
|
||||||
|
|
@ -5030,6 +5078,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
cookie: str, debug: bool) -> None:
|
cookie: str, debug: bool) -> None:
|
||||||
"""Show person options screen
|
"""Show person options screen
|
||||||
"""
|
"""
|
||||||
|
backToPath = ''
|
||||||
optionsStr = path.split('?options=')[1]
|
optionsStr = path.split('?options=')[1]
|
||||||
originPathStr = path.split('?options=')[0]
|
originPathStr = path.split('?options=')[0]
|
||||||
if ';' in optionsStr and '/users/news/' not in path:
|
if ';' in optionsStr and '/users/news/' not in path:
|
||||||
|
|
@ -5038,6 +5087,14 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
optionsActor = optionsList[0]
|
optionsActor = optionsList[0]
|
||||||
optionsPageNumber = optionsList[1]
|
optionsPageNumber = optionsList[1]
|
||||||
optionsProfileUrl = optionsList[2]
|
optionsProfileUrl = optionsList[2]
|
||||||
|
if '.' in optionsProfileUrl and \
|
||||||
|
optionsProfileUrl.startswith('/members/'):
|
||||||
|
ext = optionsProfileUrl.split('.')[-1]
|
||||||
|
optionsProfileUrl = optionsProfileUrl.split('/members/')[1]
|
||||||
|
optionsProfileUrl = optionsProfileUrl.replace('.' + ext, '')
|
||||||
|
optionsProfileUrl = \
|
||||||
|
'/users/' + optionsProfileUrl + '/avatar.' + ext
|
||||||
|
backToPath = 'moderation'
|
||||||
if optionsPageNumber.isdigit():
|
if optionsPageNumber.isdigit():
|
||||||
pageNumber = int(optionsPageNumber)
|
pageNumber = int(optionsPageNumber)
|
||||||
optionsLink = None
|
optionsLink = None
|
||||||
|
|
@ -5083,7 +5140,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
toxAddress, jamiAddress,
|
toxAddress, jamiAddress,
|
||||||
PGPpubKey, PGPfingerprint,
|
PGPpubKey, PGPfingerprint,
|
||||||
emailAddress,
|
emailAddress,
|
||||||
self.server.dormantMonths).encode('utf-8')
|
self.server.dormantMonths,
|
||||||
|
backToPath).encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
self._write(msg)
|
self._write(msg)
|
||||||
|
|
@ -6605,6 +6663,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
self.server.newswire,
|
self.server.newswire,
|
||||||
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
self.server.dormantMonths,
|
||||||
actorJson['roles'],
|
actorJson['roles'],
|
||||||
None, None)
|
None, None)
|
||||||
|
|
@ -6685,6 +6744,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
self.server.newswire,
|
self.server.newswire,
|
||||||
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
self.server.dormantMonths,
|
||||||
actorJson['skills'],
|
actorJson['skills'],
|
||||||
None, None)
|
None, None)
|
||||||
|
|
@ -7046,7 +7106,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.iconsAsButtons,
|
self.server.iconsAsButtons,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized)
|
authorized,
|
||||||
|
self.server.themeName)
|
||||||
if GETstartTime:
|
if GETstartTime:
|
||||||
self._benchmarkGETtimings(GETstartTime, GETtimings,
|
self._benchmarkGETtimings(GETstartTime, GETtimings,
|
||||||
'show status done',
|
'show status done',
|
||||||
|
|
@ -7169,7 +7230,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.iconsAsButtons,
|
self.server.iconsAsButtons,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized)
|
authorized, self.server.themeName)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -7285,7 +7346,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.iconsAsButtons,
|
self.server.iconsAsButtons,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized)
|
authorized, self.server.themeName)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -7401,7 +7462,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.iconsAsButtons,
|
self.server.iconsAsButtons,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized)
|
authorized,
|
||||||
|
self.server.themeName)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -7517,7 +7579,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.iconsAsButtons,
|
self.server.iconsAsButtons,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized)
|
authorized,
|
||||||
|
self.server.themeName)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -7642,7 +7705,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.iconsAsButtons,
|
self.server.iconsAsButtons,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized)
|
authorized,
|
||||||
|
self.server.themeName)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -7763,7 +7827,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.iconsAsButtons,
|
self.server.iconsAsButtons,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized)
|
authorized,
|
||||||
|
self.server.themeName)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -7847,7 +7912,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.iconsAsButtons,
|
self.server.iconsAsButtons,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized)
|
authorized, self.server.themeName)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -7947,7 +8012,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.iconsAsButtons,
|
self.server.iconsAsButtons,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized)
|
authorized,
|
||||||
|
self.server.themeName)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -8066,7 +8132,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.iconsAsButtons,
|
self.server.iconsAsButtons,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized)
|
authorized,
|
||||||
|
self.server.themeName)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -8177,7 +8244,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.iconsAsButtons,
|
self.server.iconsAsButtons,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
self.server.publishButtonAtTop,
|
self.server.publishButtonAtTop,
|
||||||
authorized)
|
authorized,
|
||||||
|
self.server.themeName)
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -8374,6 +8442,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.YTReplacementDomain,
|
self.server.YTReplacementDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
self.server.newswire,
|
self.server.newswire,
|
||||||
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
self.server.dormantMonths,
|
||||||
shares,
|
shares,
|
||||||
pageNumber, sharesPerPage)
|
pageNumber, sharesPerPage)
|
||||||
|
|
@ -8466,6 +8535,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.YTReplacementDomain,
|
self.server.YTReplacementDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
self.server.newswire,
|
self.server.newswire,
|
||||||
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
self.server.dormantMonths,
|
||||||
following,
|
following,
|
||||||
pageNumber,
|
pageNumber,
|
||||||
|
|
@ -8558,6 +8628,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.YTReplacementDomain,
|
self.server.YTReplacementDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
self.server.newswire,
|
self.server.newswire,
|
||||||
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
self.server.dormantMonths,
|
||||||
followers,
|
followers,
|
||||||
pageNumber,
|
pageNumber,
|
||||||
|
|
@ -8625,6 +8696,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.YTReplacementDomain,
|
self.server.YTReplacementDomain,
|
||||||
self.server.showPublishedDateOnly,
|
self.server.showPublishedDateOnly,
|
||||||
self.server.newswire,
|
self.server.newswire,
|
||||||
|
self.server.themeName,
|
||||||
self.server.dormantMonths,
|
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),
|
||||||
|
|
@ -8870,9 +8942,9 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self._404()
|
self._404()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _columImage(self, side: str, callingDomain: str, path: str,
|
def _columnImage(self, side: str, callingDomain: str, path: str,
|
||||||
baseDir: str, domain: str, port: int,
|
baseDir: str, domain: str, port: int,
|
||||||
GETstartTime, GETtimings: {}) -> bool:
|
GETstartTime, GETtimings: {}) -> bool:
|
||||||
"""Shows an image at the top of the left/right column
|
"""Shows an image at the top of the left/right column
|
||||||
"""
|
"""
|
||||||
nickname = getNicknameFromActor(path)
|
nickname = getNicknameFromActor(path)
|
||||||
|
|
@ -8999,10 +9071,10 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self._404()
|
self._404()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _showAvatarOrBackground(self, callingDomain: str, path: str,
|
def _showAvatarOrBanner(self, callingDomain: str, path: str,
|
||||||
baseDir: str, domain: str,
|
baseDir: str, domain: str,
|
||||||
GETstartTime, GETtimings: {}) -> bool:
|
GETstartTime, GETtimings: {}) -> bool:
|
||||||
"""Shows an avatar or profile background image
|
"""Shows an avatar or banner or profile background image
|
||||||
"""
|
"""
|
||||||
if '/users/' in path:
|
if '/users/' in path:
|
||||||
if self._pathIsImage(path):
|
if self._pathIsImage(path):
|
||||||
|
|
@ -9010,11 +9082,20 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
if '/' in avatarStr and '.temp.' not in path:
|
if '/' in avatarStr and '.temp.' not in path:
|
||||||
avatarNickname = avatarStr.split('/')[0]
|
avatarNickname = avatarStr.split('/')[0]
|
||||||
avatarFile = avatarStr.split('/')[1]
|
avatarFile = avatarStr.split('/')[1]
|
||||||
|
avatarFileExt = avatarFile.split('.')[-1]
|
||||||
# remove any numbers, eg. avatar123.png becomes avatar.png
|
# remove any numbers, eg. avatar123.png becomes avatar.png
|
||||||
if avatarFile.startswith('avatar'):
|
if avatarFile.startswith('avatar'):
|
||||||
avatarFile = 'avatar.' + avatarFile.split('.')[1]
|
avatarFile = 'avatar.' + avatarFileExt
|
||||||
|
elif avatarFile.startswith('banner'):
|
||||||
|
avatarFile = 'banner.' + avatarFileExt
|
||||||
|
elif avatarFile.startswith('search_banner'):
|
||||||
|
avatarFile = 'search_banner.' + avatarFileExt
|
||||||
elif avatarFile.startswith('image'):
|
elif avatarFile.startswith('image'):
|
||||||
avatarFile = 'image.' + avatarFile.split('.')[1]
|
avatarFile = 'image.' + avatarFileExt
|
||||||
|
elif avatarFile.startswith('left_col_image'):
|
||||||
|
avatarFile = 'left_col_image.' + avatarFileExt
|
||||||
|
elif avatarFile.startswith('right_col_image'):
|
||||||
|
avatarFile = 'right_col_image.' + avatarFileExt
|
||||||
avatarFilename = \
|
avatarFilename = \
|
||||||
baseDir + '/accounts/' + \
|
baseDir + '/accounts/' + \
|
||||||
avatarNickname + '@' + domain + '/' + avatarFile
|
avatarNickname + '@' + domain + '/' + avatarFile
|
||||||
|
|
@ -9138,7 +9219,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
nickname, domain,
|
nickname, domain,
|
||||||
domainFull,
|
domainFull,
|
||||||
self.server.defaultTimeline,
|
self.server.defaultTimeline,
|
||||||
self.server.newswire).encode('utf-8')
|
self.server.newswire,
|
||||||
|
self.server.themeName).encode('utf-8')
|
||||||
if not msg:
|
if not msg:
|
||||||
print('Error replying to ' + inReplyToUrl)
|
print('Error replying to ' + inReplyToUrl)
|
||||||
self._404()
|
self._404()
|
||||||
|
|
@ -9167,7 +9249,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
path, domain,
|
path, domain,
|
||||||
port,
|
port,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
self.server.defaultTimeline).encode('utf-8')
|
self.server.defaultTimeline,
|
||||||
|
self.server.themeName).encode('utf-8')
|
||||||
if msg:
|
if msg:
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -9181,7 +9264,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
def _editLinks(self, callingDomain: str, path: str,
|
def _editLinks(self, callingDomain: str, path: str,
|
||||||
translate: {}, baseDir: str,
|
translate: {}, baseDir: str,
|
||||||
httpPrefix: str, domain: str, port: int,
|
httpPrefix: str, domain: str, port: int,
|
||||||
cookie: str) -> bool:
|
cookie: str, theme: str) -> bool:
|
||||||
"""Show the links from the left column
|
"""Show the links from the left column
|
||||||
"""
|
"""
|
||||||
if '/users/' in path and path.endswith('/editlinks'):
|
if '/users/' in path and path.endswith('/editlinks'):
|
||||||
|
|
@ -9191,7 +9274,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
path, domain,
|
path, domain,
|
||||||
port,
|
port,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
self.server.defaultTimeline).encode('utf-8')
|
self.server.defaultTimeline,
|
||||||
|
theme).encode('utf-8')
|
||||||
if msg:
|
if msg:
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -9215,7 +9299,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
path, domain,
|
path, domain,
|
||||||
port,
|
port,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
self.server.defaultTimeline).encode('utf-8')
|
self.server.defaultTimeline,
|
||||||
|
self.server.themeName).encode('utf-8')
|
||||||
if msg:
|
if msg:
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
|
|
@ -9992,19 +10077,19 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.path.endswith('/left_col_image.png'):
|
if self.path.endswith('/left_col_image.png'):
|
||||||
if self._columImage('left', callingDomain, self.path,
|
if self._columnImage('left', callingDomain, self.path,
|
||||||
self.server.baseDir,
|
self.server.baseDir,
|
||||||
self.server.domain,
|
self.server.domain,
|
||||||
self.server.port,
|
self.server.port,
|
||||||
GETstartTime, GETtimings):
|
GETstartTime, GETtimings):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.path.endswith('/right_col_image.png'):
|
if self.path.endswith('/right_col_image.png'):
|
||||||
if self._columImage('right', callingDomain, self.path,
|
if self._columnImage('right', callingDomain, self.path,
|
||||||
self.server.baseDir,
|
self.server.baseDir,
|
||||||
self.server.domain,
|
self.server.domain,
|
||||||
self.server.port,
|
self.server.port,
|
||||||
GETstartTime, GETtimings):
|
GETstartTime, GETtimings):
|
||||||
return
|
return
|
||||||
|
|
||||||
self._benchmarkGETtimings(GETstartTime, GETtimings,
|
self._benchmarkGETtimings(GETstartTime, GETtimings,
|
||||||
|
|
@ -10082,10 +10167,10 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
|
|
||||||
# show avatar or background image
|
# show avatar or background image
|
||||||
# Note that this comes before the busy flag to avoid conflicts
|
# Note that this comes before the busy flag to avoid conflicts
|
||||||
if self._showAvatarOrBackground(callingDomain, self.path,
|
if self._showAvatarOrBanner(callingDomain, self.path,
|
||||||
self.server.baseDir,
|
self.server.baseDir,
|
||||||
self.server.domain,
|
self.server.domain,
|
||||||
GETstartTime, GETtimings):
|
GETstartTime, GETtimings):
|
||||||
return
|
return
|
||||||
|
|
||||||
self._benchmarkGETtimings(GETstartTime, GETtimings,
|
self._benchmarkGETtimings(GETstartTime, GETtimings,
|
||||||
|
|
@ -10208,7 +10293,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
authorized,
|
authorized,
|
||||||
rssIconAtTop,
|
rssIconAtTop,
|
||||||
iconsAsButtons,
|
iconsAsButtons,
|
||||||
defaultTimeline).encode('utf-8')
|
defaultTimeline,
|
||||||
|
self.server.themeName).encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg),
|
self._set_headers('text/html', len(msg),
|
||||||
cookie, callingDomain)
|
cookie, callingDomain)
|
||||||
self._write(msg)
|
self._write(msg)
|
||||||
|
|
@ -10239,7 +10325,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
authorized,
|
authorized,
|
||||||
self.server.rssIconAtTop,
|
self.server.rssIconAtTop,
|
||||||
iconsAsButtons,
|
iconsAsButtons,
|
||||||
defaultTimeline).encode('utf-8')
|
defaultTimeline,
|
||||||
|
self.server.themeName).encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg), cookie, callingDomain)
|
self._set_headers('text/html', len(msg), cookie, callingDomain)
|
||||||
self._write(msg)
|
self._write(msg)
|
||||||
self.server.GETbusy = False
|
self.server.GETbusy = False
|
||||||
|
|
@ -10307,7 +10394,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.translate,
|
self.server.translate,
|
||||||
self.server.baseDir, self.path,
|
self.server.baseDir, self.path,
|
||||||
self.server.domain,
|
self.server.domain,
|
||||||
self.server.defaultTimeline).encode('utf-8')
|
self.server.defaultTimeline,
|
||||||
|
self.server.themeName).encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg), cookie, callingDomain)
|
self._set_headers('text/html', len(msg), cookie, callingDomain)
|
||||||
self._write(msg)
|
self._write(msg)
|
||||||
self.server.GETbusy = False
|
self.server.GETbusy = False
|
||||||
|
|
@ -10321,7 +10409,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
msg = htmlSearchHashtagCategory(self.server.cssCache,
|
msg = htmlSearchHashtagCategory(self.server.cssCache,
|
||||||
self.server.translate,
|
self.server.translate,
|
||||||
self.server.baseDir, self.path,
|
self.server.baseDir, self.path,
|
||||||
self.server.domain)
|
self.server.domain,
|
||||||
|
self.server.themeName)
|
||||||
if msg:
|
if msg:
|
||||||
msg = msg.encode('utf-8')
|
msg = msg.encode('utf-8')
|
||||||
self._set_headers('text/html', len(msg), cookie, callingDomain)
|
self._set_headers('text/html', len(msg), cookie, callingDomain)
|
||||||
|
|
@ -10813,7 +10902,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
self.server.httpPrefix,
|
self.server.httpPrefix,
|
||||||
self.server.domain,
|
self.server.domain,
|
||||||
self.server.port,
|
self.server.port,
|
||||||
cookie):
|
cookie,
|
||||||
|
self.server.themeName):
|
||||||
return
|
return
|
||||||
|
|
||||||
# edit newswire from the right column of the timeline
|
# edit newswire from the right column of the timeline
|
||||||
|
|
@ -11643,7 +11733,8 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
fields['subject'],
|
fields['subject'],
|
||||||
fields['message'],
|
fields['message'],
|
||||||
filename, attachmentMediaType,
|
filename, attachmentMediaType,
|
||||||
fields['imageDescription'])
|
fields['imageDescription'],
|
||||||
|
self.server.themeName)
|
||||||
if messageJson:
|
if messageJson:
|
||||||
messageJson = messageJson.encode('utf-8')
|
messageJson = messageJson.encode('utf-8')
|
||||||
self._set_headers('text/html',
|
self._set_headers('text/html',
|
||||||
|
|
@ -12087,7 +12178,7 @@ class PubServer(BaseHTTPRequestHandler):
|
||||||
if self.server.newPostThread.get(newPostThreadName):
|
if self.server.newPostThread.get(newPostThreadName):
|
||||||
print('Waiting for previous new post thread to end')
|
print('Waiting for previous new post thread to end')
|
||||||
waitCtr = 0
|
waitCtr = 0
|
||||||
while (self.server.newPostThread[newPostThreadName].isAlive() and
|
while (self.server.newPostThread[newPostThreadName].is_alive() and
|
||||||
waitCtr < 8):
|
waitCtr < 8):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
waitCtr += 1
|
waitCtr += 1
|
||||||
|
|
@ -12980,12 +13071,13 @@ class EpicyonServer(ThreadingHTTPServer):
|
||||||
return HTTPServer.handle_error(self, request, client_address)
|
return HTTPServer.handle_error(self, request, client_address)
|
||||||
|
|
||||||
|
|
||||||
def runPostsQueue(baseDir: str, sendThreads: [], debug: bool) -> None:
|
def runPostsQueue(baseDir: str, sendThreads: [], debug: bool,
|
||||||
|
timeoutMins: int) -> None:
|
||||||
"""Manages the threads used to send posts
|
"""Manages the threads used to send posts
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
removeDormantThreads(baseDir, sendThreads, debug)
|
removeDormantThreads(baseDir, sendThreads, debug, timeoutMins)
|
||||||
|
|
||||||
|
|
||||||
def runSharesExpire(versionNumber: str, baseDir: str) -> None:
|
def runSharesExpire(versionNumber: str, baseDir: str) -> None:
|
||||||
|
|
@ -13004,7 +13096,7 @@ def runPostsWatchdog(projectVersion: str, httpd) -> None:
|
||||||
httpd.thrPostsQueue.start()
|
httpd.thrPostsQueue.start()
|
||||||
while True:
|
while True:
|
||||||
time.sleep(20)
|
time.sleep(20)
|
||||||
if not httpd.thrPostsQueue.isAlive():
|
if not httpd.thrPostsQueue.is_alive():
|
||||||
httpd.thrPostsQueue.kill()
|
httpd.thrPostsQueue.kill()
|
||||||
httpd.thrPostsQueue = postsQueueOriginal.clone(runPostsQueue)
|
httpd.thrPostsQueue = postsQueueOriginal.clone(runPostsQueue)
|
||||||
httpd.thrPostsQueue.start()
|
httpd.thrPostsQueue.start()
|
||||||
|
|
@ -13019,7 +13111,7 @@ def runSharesExpireWatchdog(projectVersion: str, httpd) -> None:
|
||||||
httpd.thrSharesExpire.start()
|
httpd.thrSharesExpire.start()
|
||||||
while True:
|
while True:
|
||||||
time.sleep(20)
|
time.sleep(20)
|
||||||
if not httpd.thrSharesExpire.isAlive():
|
if not httpd.thrSharesExpire.is_alive():
|
||||||
httpd.thrSharesExpire.kill()
|
httpd.thrSharesExpire.kill()
|
||||||
httpd.thrSharesExpire = sharesExpireOriginal.clone(runSharesExpire)
|
httpd.thrSharesExpire = sharesExpireOriginal.clone(runSharesExpire)
|
||||||
httpd.thrSharesExpire.start()
|
httpd.thrSharesExpire.start()
|
||||||
|
|
@ -13048,7 +13140,8 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def runDaemon(dormantMonths: int,
|
def runDaemon(sendThreadsTimeoutMins: int,
|
||||||
|
dormantMonths: int,
|
||||||
maxNewswirePosts: int,
|
maxNewswirePosts: int,
|
||||||
allowLocalNetworkAccess: bool,
|
allowLocalNetworkAccess: bool,
|
||||||
maxFeedItemSizeKb: int,
|
maxFeedItemSizeKb: int,
|
||||||
|
|
@ -13343,10 +13436,14 @@ def runDaemon(dormantMonths: int,
|
||||||
httpd.maxPostsInBox), daemon=True)
|
httpd.maxPostsInBox), daemon=True)
|
||||||
httpd.thrCache.start()
|
httpd.thrCache.start()
|
||||||
|
|
||||||
|
# number of mins after which sending posts or updates will expire
|
||||||
|
httpd.sendThreadsTimeoutMins = sendThreadsTimeoutMins
|
||||||
|
|
||||||
print('Creating posts queue')
|
print('Creating posts queue')
|
||||||
httpd.thrPostsQueue = \
|
httpd.thrPostsQueue = \
|
||||||
threadWithTrace(target=runPostsQueue,
|
threadWithTrace(target=runPostsQueue,
|
||||||
args=(baseDir, httpd.sendThreads, debug), daemon=True)
|
args=(baseDir, httpd.sendThreads, debug,
|
||||||
|
httpd.sendThreadsTimeoutMins), daemon=True)
|
||||||
if not unitTest:
|
if not unitTest:
|
||||||
httpd.thrPostsWatchdog = \
|
httpd.thrPostsWatchdog = \
|
||||||
threadWithTrace(target=runPostsWatchdog,
|
threadWithTrace(target=runPostsWatchdog,
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ def sendDeleteViaServer(baseDir: str, session,
|
||||||
fromPersonId, sharedInbox, avatarUrl,
|
fromPersonId, sharedInbox, avatarUrl,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
||||||
projectVersion, httpPrefix, fromNickname,
|
projectVersion, httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox)
|
fromDomain, postToBox, 53036)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
--options-bg-color: #282c37;
|
--options-bg-color: #282c37;
|
||||||
--options-link-bg-color: transparent;
|
--options-link-bg-color: transparent;
|
||||||
--options-fg-color: #dddddd;
|
--options-fg-color: #dddddd;
|
||||||
--main-link-color: #999;
|
--options-main-link-color: #999;
|
||||||
--main-visited-color: #888;
|
--options-main-visited-color: #888;
|
||||||
--border-color: #505050;
|
--border-color: #505050;
|
||||||
--font-size-header: 18px;
|
--font-size-header: 18px;
|
||||||
--font-color-header: #ccc;
|
--font-color-header: #ccc;
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
--follow-text-entry-width: 90%;
|
--follow-text-entry-width: 90%;
|
||||||
--focus-color: white;
|
--focus-color: white;
|
||||||
--petname-width-chars: 16ch;
|
--petname-width-chars: 16ch;
|
||||||
--main-link-color-hover: #bbb;
|
--options-main-link-color-hover: #bbb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
|
@ -73,25 +73,25 @@ a, u {
|
||||||
}
|
}
|
||||||
|
|
||||||
a:visited{
|
a:visited{
|
||||||
color: var(--main-visited-color);
|
color: var(--options-main-visited-color);
|
||||||
background: var(--options-link-bg-color);
|
background: var(--options-link-bg-color);
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:link {
|
a:link {
|
||||||
color: var(--main-link-color);
|
color: var(--options-main-link-color);
|
||||||
background: var(--options-link-bg-color);
|
background: var(--options-link-bg-color);
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:link:hover {
|
a:link:hover {
|
||||||
color: var(--main-link-color-hover);
|
color: var(--options-main-link-color-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
a:visited:hover {
|
a:visited:hover {
|
||||||
color: var(--main-link-color-hover);
|
color: var(--options-main-link-color-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
a:focus {
|
a:focus {
|
||||||
|
|
@ -116,12 +116,12 @@ a:focus {
|
||||||
|
|
||||||
.imText {
|
.imText {
|
||||||
font-size: var(--font-size4);
|
font-size: var(--font-size4);
|
||||||
color: var(--main-link-color);
|
color: var(--options-main-link-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pgp {
|
.pgp {
|
||||||
font-size: var(--font-size5);
|
font-size: var(--font-size5);
|
||||||
color: var(--main-link-color);
|
color: var(--options-main-link-color);
|
||||||
background: var(--options-link-bg-color);
|
background: var(--options-link-bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -950,6 +950,14 @@ div.container {
|
||||||
font-size: var(--font-size);
|
font-size: var(--font-size);
|
||||||
color: var(--title-color);
|
color: var(--title-color);
|
||||||
}
|
}
|
||||||
|
.accountsTable {
|
||||||
|
width: 100%;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.accountsTableCol {
|
||||||
|
width: 20%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
.containerHeader {
|
.containerHeader {
|
||||||
border: var(--border-width-header) solid var(--border-color);
|
border: var(--border-width-header) solid var(--border-color);
|
||||||
background-color: var(--header-bg-color);
|
background-color: var(--header-bg-color);
|
||||||
|
|
@ -1601,6 +1609,14 @@ div.container {
|
||||||
font-size: var(--font-size-mobile);
|
font-size: var(--font-size-mobile);
|
||||||
color: var(--title-color);
|
color: var(--title-color);
|
||||||
}
|
}
|
||||||
|
.accountsTable {
|
||||||
|
width: 100%;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
.accountsTableCol {
|
||||||
|
width: 20%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
.containerHeader {
|
.containerHeader {
|
||||||
border: var(--border-width-header) solid var(--border-color);
|
border: var(--border-width-header) solid var(--border-color);
|
||||||
background-color: var(--header-bg-color);
|
background-color: var(--header-bg-color);
|
||||||
|
|
|
||||||
13
epicyon.py
13
epicyon.py
|
|
@ -122,6 +122,11 @@ parser.add_argument('--dormantMonths',
|
||||||
default=3,
|
default=3,
|
||||||
help='How many months does a followed account need to ' +
|
help='How many months does a followed account need to ' +
|
||||||
'be unseen for before being considered dormant')
|
'be unseen for before being considered dormant')
|
||||||
|
parser.add_argument('--sendThreadsTimeoutMins',
|
||||||
|
dest='sendThreadsTimeoutMins', type=int,
|
||||||
|
default=30,
|
||||||
|
help='How many minutes before a thread to send out ' +
|
||||||
|
'posts expires')
|
||||||
parser.add_argument('--maxNewswirePosts',
|
parser.add_argument('--maxNewswirePosts',
|
||||||
dest='maxNewswirePosts', type=int,
|
dest='maxNewswirePosts', type=int,
|
||||||
default=20,
|
default=20,
|
||||||
|
|
@ -2035,6 +2040,11 @@ dormantMonths = \
|
||||||
if dormantMonths is not None:
|
if dormantMonths is not None:
|
||||||
args.dormantMonths = int(dormantMonths)
|
args.dormantMonths = int(dormantMonths)
|
||||||
|
|
||||||
|
sendThreadsTimeoutMins = \
|
||||||
|
getConfigParam(baseDir, 'sendThreadsTimeoutMins')
|
||||||
|
if sendThreadsTimeoutMins is not None:
|
||||||
|
args.sendThreadsTimeoutMins = int(sendThreadsTimeoutMins)
|
||||||
|
|
||||||
allowNewsFollowers = \
|
allowNewsFollowers = \
|
||||||
getConfigParam(baseDir, 'allowNewsFollowers')
|
getConfigParam(baseDir, 'allowNewsFollowers')
|
||||||
if allowNewsFollowers is not None:
|
if allowNewsFollowers is not None:
|
||||||
|
|
@ -2083,7 +2093,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.dormantMonths,
|
runDaemon(args.sendThreadsTimeoutMins,
|
||||||
|
args.dormantMonths,
|
||||||
args.maxNewswirePosts,
|
args.maxNewswirePosts,
|
||||||
args.allowLocalNetworkAccess,
|
args.allowLocalNetworkAccess,
|
||||||
args.maxFeedItemSizeKb,
|
args.maxFeedItemSizeKb,
|
||||||
|
|
|
||||||
86
filters.py
86
filters.py
|
|
@ -23,6 +23,24 @@ def addFilter(baseDir: str, nickname: str, domain: str, words: str) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def addGlobalFilter(baseDir: str, words: str) -> bool:
|
||||||
|
"""Adds a global filter for particular words within
|
||||||
|
the content of a incoming posts
|
||||||
|
"""
|
||||||
|
if not words:
|
||||||
|
return False
|
||||||
|
if len(words) < 2:
|
||||||
|
return False
|
||||||
|
filtersFilename = baseDir + '/accounts/filters.txt'
|
||||||
|
if os.path.isfile(filtersFilename):
|
||||||
|
if words in open(filtersFilename).read():
|
||||||
|
return False
|
||||||
|
filtersFile = open(filtersFilename, "a+")
|
||||||
|
filtersFile.write(words + '\n')
|
||||||
|
filtersFile.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def removeFilter(baseDir: str, nickname: str, domain: str,
|
def removeFilter(baseDir: str, nickname: str, domain: str,
|
||||||
words: str) -> bool:
|
words: str) -> bool:
|
||||||
"""Removes a word filter
|
"""Removes a word filter
|
||||||
|
|
@ -43,6 +61,24 @@ def removeFilter(baseDir: str, nickname: str, domain: str,
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def removeGlobalFilter(baseDir: str, words: str) -> bool:
|
||||||
|
"""Removes a global word filter
|
||||||
|
"""
|
||||||
|
filtersFilename = baseDir + '/accounts/filters.txt'
|
||||||
|
if os.path.isfile(filtersFilename):
|
||||||
|
if words in open(filtersFilename).read():
|
||||||
|
with open(filtersFilename, 'r') as fp:
|
||||||
|
with open(filtersFilename + '.new', 'w+') as fpnew:
|
||||||
|
for line in fp:
|
||||||
|
line = line.replace('\n', '')
|
||||||
|
if line != words:
|
||||||
|
fpnew.write(line + '\n')
|
||||||
|
if os.path.isfile(filtersFilename + '.new'):
|
||||||
|
os.rename(filtersFilename + '.new', filtersFilename)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def isTwitterPost(content: str) -> bool:
|
def isTwitterPost(content: str) -> bool:
|
||||||
"""Returns true if the given post content is a retweet or twitter crosspost
|
"""Returns true if the given post content is a retweet or twitter crosspost
|
||||||
"""
|
"""
|
||||||
|
|
@ -53,12 +89,45 @@ def isTwitterPost(content: str) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def isFilteredBase(filename: str, content: str) -> bool:
|
||||||
|
"""Uses the given file containing filtered words to check
|
||||||
|
the given content
|
||||||
|
"""
|
||||||
|
if not os.path.isfile(filename):
|
||||||
|
return False
|
||||||
|
|
||||||
|
with open(filename, 'r') as fp:
|
||||||
|
for line in fp:
|
||||||
|
filterStr = line.replace('\n', '').replace('\r', '')
|
||||||
|
if not filterStr:
|
||||||
|
continue
|
||||||
|
if len(filterStr) < 2:
|
||||||
|
continue
|
||||||
|
if '+' not in filterStr:
|
||||||
|
if filterStr in content:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
filterWords = filterStr.replace('"', '').split('+')
|
||||||
|
for word in filterWords:
|
||||||
|
if word not in content:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def isFiltered(baseDir: str, nickname: str, domain: str, content: str) -> bool:
|
def isFiltered(baseDir: str, nickname: str, domain: str, content: str) -> bool:
|
||||||
"""Should the given content be filtered out?
|
"""Should the given content be filtered out?
|
||||||
This is a simple type of filter which just matches words, not a regex
|
This is a simple type of filter which just matches words, not a regex
|
||||||
You can add individual words or use word1+word2 to indicate that two
|
You can add individual words or use word1+word2 to indicate that two
|
||||||
words must be present although not necessarily adjacent
|
words must be present although not necessarily adjacent
|
||||||
"""
|
"""
|
||||||
|
globalFiltersFilename = baseDir + '/accounts/filters.txt'
|
||||||
|
if isFilteredBase(globalFiltersFilename, content):
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not nickname or not domain:
|
||||||
|
return False
|
||||||
|
|
||||||
# optionally remove retweets
|
# optionally remove retweets
|
||||||
removeTwitter = baseDir + '/accounts/' + \
|
removeTwitter = baseDir + '/accounts/' + \
|
||||||
nickname + '@' + domain + '/.removeTwitter'
|
nickname + '@' + domain + '/.removeTwitter'
|
||||||
|
|
@ -66,19 +135,6 @@ def isFiltered(baseDir: str, nickname: str, domain: str, content: str) -> bool:
|
||||||
if isTwitterPost(content):
|
if isTwitterPost(content):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
filtersFilename = baseDir + '/accounts/' + \
|
accountFiltersFilename = baseDir + '/accounts/' + \
|
||||||
nickname + '@' + domain + '/filters.txt'
|
nickname + '@' + domain + '/filters.txt'
|
||||||
if os.path.isfile(filtersFilename):
|
return isFilteredBase(accountFiltersFilename, content)
|
||||||
with open(filtersFilename, 'r') as fp:
|
|
||||||
for line in fp:
|
|
||||||
filterStr = line.replace('\n', '').replace('\r', '')
|
|
||||||
if '+' not in filterStr:
|
|
||||||
if filterStr in content:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
filterWords = filterStr.replace('"', '').split('+')
|
|
||||||
for word in filterWords:
|
|
||||||
if word not in content:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
|
||||||
|
|
@ -995,7 +995,7 @@ def sendFollowRequestViaServer(baseDir: str, session,
|
||||||
fromPersonId, sharedInbox, avatarUrl,
|
fromPersonId, sharedInbox, avatarUrl,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
||||||
projectVersion, httpPrefix, fromNickname,
|
projectVersion, httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox)
|
fromDomain, postToBox, 52025)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -1086,7 +1086,8 @@ def sendUnfollowRequestViaServer(baseDir: str, session,
|
||||||
wfRequest, personCache,
|
wfRequest, personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
fromNickname,
|
fromNickname,
|
||||||
fromDomain, postToBox)
|
fromDomain, postToBox,
|
||||||
|
76536)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
14
inbox.py
14
inbox.py
|
|
@ -173,9 +173,19 @@ def inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
avatarUrl = None
|
avatarUrl = None
|
||||||
if boxname != 'tlevents' and boxname != 'outbox':
|
if boxname != 'tlevents' and boxname != 'outbox':
|
||||||
boxname = 'inbox'
|
boxname = 'inbox'
|
||||||
|
|
||||||
|
# wfRequest = {}
|
||||||
|
# requestHandle = nickname + '@' + domain
|
||||||
|
# if cachedWebfingers.get(requestHandle):
|
||||||
|
# wfRequest = cachedWebfingers[requestHandle]
|
||||||
|
# elif cachedWebfingers.get(requestHandle + ':' + str(port)):
|
||||||
|
# wfRequest = cachedWebfingers[requestHandle + ':' + str(port)]
|
||||||
|
# TODO: this may need to be changed
|
||||||
|
wfRequest = cachedWebfingers
|
||||||
|
|
||||||
individualPostAsHtml(True, recentPostsCache, maxRecentPosts,
|
individualPostAsHtml(True, recentPostsCache, maxRecentPosts,
|
||||||
translate, pageNumber,
|
translate, pageNumber,
|
||||||
baseDir, session, cachedWebfingers, personCache,
|
baseDir, session, wfRequest, personCache,
|
||||||
nickname, domain, port, postJsonObject,
|
nickname, domain, port, postJsonObject,
|
||||||
avatarUrl, True, allowDeletion,
|
avatarUrl, True, allowDeletion,
|
||||||
httpPrefix, __version__, boxname, None,
|
httpPrefix, __version__, boxname, None,
|
||||||
|
|
@ -2456,7 +2466,7 @@ def runInboxQueueWatchdog(projectVersion: str, httpd) -> None:
|
||||||
httpd.thrInboxQueue.start()
|
httpd.thrInboxQueue.start()
|
||||||
while True:
|
while True:
|
||||||
time.sleep(20)
|
time.sleep(20)
|
||||||
if not httpd.thrInboxQueue.isAlive() or httpd.restartInboxQueue:
|
if not httpd.thrInboxQueue.is_alive() or httpd.restartInboxQueue:
|
||||||
httpd.restartInboxQueueInProgress = True
|
httpd.restartInboxQueueInProgress = True
|
||||||
httpd.thrInboxQueue.kill()
|
httpd.thrInboxQueue.kill()
|
||||||
httpd.thrInboxQueue = inboxQueueOriginal.clone(runInboxQueue)
|
httpd.thrInboxQueue = inboxQueueOriginal.clone(runInboxQueue)
|
||||||
|
|
|
||||||
5
like.py
5
like.py
|
|
@ -257,7 +257,7 @@ def sendLikeViaServer(baseDir: str, session,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
fromNickname, fromDomain,
|
fromNickname, fromDomain,
|
||||||
postToBox)
|
postToBox, 72873)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -335,7 +335,8 @@ def sendUndoLikeViaServer(baseDir: str, session,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, fromNickname,
|
httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox)
|
fromDomain, postToBox,
|
||||||
|
72625)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
|
|
@ -752,7 +752,7 @@ def runNewswireWatchdog(projectVersion: str, httpd) -> None:
|
||||||
httpd.thrNewswireDaemon.start()
|
httpd.thrNewswireDaemon.start()
|
||||||
while True:
|
while True:
|
||||||
time.sleep(50)
|
time.sleep(50)
|
||||||
if not httpd.thrNewswireDaemon.isAlive():
|
if not httpd.thrNewswireDaemon.is_alive():
|
||||||
httpd.thrNewswireDaemon.kill()
|
httpd.thrNewswireDaemon.kill()
|
||||||
httpd.thrNewswireDaemon = \
|
httpd.thrNewswireDaemon = \
|
||||||
newswireOriginal.clone(runNewswireDaemon)
|
newswireOriginal.clone(runNewswireDaemon)
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ def addNewswireDictEntry(baseDir: str, domain: str,
|
||||||
allText = title + ' ' + description
|
allText = title + ' ' + description
|
||||||
|
|
||||||
# check that none of the text is filtered against
|
# check that none of the text is filtered against
|
||||||
if isFiltered(baseDir, 'news', domain, allText):
|
if isFiltered(baseDir, None, None, allText):
|
||||||
return
|
return
|
||||||
|
|
||||||
if tags is None:
|
if tags is None:
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,13 @@ def getDefaultPersonContext() -> str:
|
||||||
'fingerprintKey': {'@id': 'toot:fingerprintKey', '@type': '@id'},
|
'fingerprintKey': {'@id': 'toot:fingerprintKey', '@type': '@id'},
|
||||||
'messageFranking': 'toot:messageFranking',
|
'messageFranking': 'toot:messageFranking',
|
||||||
'publicKeyBase64': 'toot:publicKeyBase64',
|
'publicKeyBase64': 'toot:publicKeyBase64',
|
||||||
'discoverable': 'toot:discoverable'
|
'discoverable': 'toot:discoverable',
|
||||||
|
'orgSchema': 'toot:orgSchema',
|
||||||
|
'shares': 'toot:shares',
|
||||||
|
'skills': 'toot:skills',
|
||||||
|
'roles': 'toot:roles',
|
||||||
|
'availability': 'toot:availability',
|
||||||
|
'nomadicLocations': 'toot:nomadicLocations'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
171
posts.py
171
posts.py
|
|
@ -141,18 +141,27 @@ def cleanHtml(rawHtml: str) -> str:
|
||||||
return html.unescape(text)
|
return html.unescape(text)
|
||||||
|
|
||||||
|
|
||||||
def getUserUrl(wfRequest: {}) -> str:
|
def getUserUrl(wfRequest: {}, sourceId=0) -> str:
|
||||||
if wfRequest.get('links'):
|
"""Gets the actor url from a webfinger request
|
||||||
for link in wfRequest['links']:
|
"""
|
||||||
if link.get('type') and link.get('href'):
|
print('getUserUrl: ' + str(sourceId) + ' ' + str(wfRequest))
|
||||||
if link['type'] == 'application/activity+json':
|
if not wfRequest.get('links'):
|
||||||
if not ('/users/' in link['href'] or
|
print('getUserUrl webfinger activity+json contains no links ' +
|
||||||
'/accounts/' in link['href'] or
|
str(sourceId) + ' ' + str(wfRequest))
|
||||||
'/profile/' in link['href'] or
|
return None
|
||||||
'/channel/' in link['href']):
|
for link in wfRequest['links']:
|
||||||
print('Webfinger activity+json contains ' +
|
if not (link.get('type') and link.get('href')):
|
||||||
'single user instance actor')
|
continue
|
||||||
return link['href']
|
if link['type'] != 'application/activity+json':
|
||||||
|
continue
|
||||||
|
if not ('/users/' in link['href'] or
|
||||||
|
'/accounts/' in link['href'] or
|
||||||
|
'/profile/' in link['href'] or
|
||||||
|
'/channel/' in link['href']):
|
||||||
|
print('getUserUrl webfinger activity+json ' +
|
||||||
|
'contains single user instance actor ' +
|
||||||
|
str(sourceId) + ' ' + str(link))
|
||||||
|
return link['href']
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -198,13 +207,14 @@ def getPersonBox(baseDir: str, session, wfRequest: {},
|
||||||
personCache: {},
|
personCache: {},
|
||||||
projectVersion: str, httpPrefix: str,
|
projectVersion: str, httpPrefix: str,
|
||||||
nickname: str, domain: str,
|
nickname: str, domain: str,
|
||||||
boxName='inbox') -> (str, str, str, str, str, str, str, str):
|
boxName='inbox',
|
||||||
|
sourceId=0) -> (str, str, str, str, str, str, str, str):
|
||||||
profileStr = 'https://www.w3.org/ns/activitystreams'
|
profileStr = 'https://www.w3.org/ns/activitystreams'
|
||||||
asHeader = {
|
asHeader = {
|
||||||
'Accept': 'application/activity+json; profile="' + profileStr + '"'
|
'Accept': 'application/activity+json; profile="' + profileStr + '"'
|
||||||
}
|
}
|
||||||
if not wfRequest.get('errors'):
|
if not wfRequest.get('errors'):
|
||||||
personUrl = getUserUrl(wfRequest)
|
personUrl = getUserUrl(wfRequest, sourceId)
|
||||||
else:
|
else:
|
||||||
if nickname == 'dev':
|
if nickname == 'dev':
|
||||||
# try single user instance
|
# try single user instance
|
||||||
|
|
@ -1174,7 +1184,7 @@ def postIsAddressedToFollowers(baseDir: str,
|
||||||
postJsonObject: {}) -> bool:
|
postJsonObject: {}) -> bool:
|
||||||
"""Returns true if the given post is addressed to followers of the nickname
|
"""Returns true if the given post is addressed to followers of the nickname
|
||||||
"""
|
"""
|
||||||
domain = getFullDomain(domain, port)
|
domainFull = getFullDomain(domain, port)
|
||||||
|
|
||||||
if not postJsonObject.get('object'):
|
if not postJsonObject.get('object'):
|
||||||
return False
|
return False
|
||||||
|
|
@ -1192,7 +1202,7 @@ def postIsAddressedToFollowers(baseDir: str,
|
||||||
if postJsonObject.get('cc'):
|
if postJsonObject.get('cc'):
|
||||||
ccList = postJsonObject['cc']
|
ccList = postJsonObject['cc']
|
||||||
|
|
||||||
followersUrl = httpPrefix + '://' + domain + '/users/' + \
|
followersUrl = httpPrefix + '://' + domainFull + '/users/' + \
|
||||||
nickname + '/followers'
|
nickname + '/followers'
|
||||||
|
|
||||||
# does the followers url exist in 'to' or 'cc' lists?
|
# does the followers url exist in 'to' or 'cc' lists?
|
||||||
|
|
@ -1765,7 +1775,8 @@ def sendPost(projectVersion: str,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain, postToBox)
|
nickname, domain, postToBox,
|
||||||
|
72533)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
return 3
|
return 3
|
||||||
|
|
@ -1880,7 +1891,8 @@ def sendPostViaServer(projectVersion: str,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
fromNickname,
|
fromNickname,
|
||||||
fromDomain, postToBox)
|
fromDomain, postToBox,
|
||||||
|
82796)
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: No ' + postToBox + ' was found for ' + handle)
|
print('DEBUG: No ' + postToBox + ' was found for ' + handle)
|
||||||
|
|
@ -2079,7 +2091,8 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain, postToBox)
|
nickname, domain, postToBox,
|
||||||
|
30873)
|
||||||
|
|
||||||
print("inboxUrl: " + str(inboxUrl))
|
print("inboxUrl: " + str(inboxUrl))
|
||||||
print("toPersonId: " + str(toPersonId))
|
print("toPersonId: " + str(toPersonId))
|
||||||
|
|
@ -2342,14 +2355,40 @@ def sendToNamedAddresses(session, baseDir: str,
|
||||||
|
|
||||||
def hasSharedInbox(session, httpPrefix: str, domain: str) -> bool:
|
def hasSharedInbox(session, httpPrefix: str, domain: str) -> bool:
|
||||||
"""Returns true if the given domain has a shared inbox
|
"""Returns true if the given domain has a shared inbox
|
||||||
|
This tries the new and the old way of webfingering the shared inbox
|
||||||
"""
|
"""
|
||||||
wfRequest = webfingerHandle(session, domain + '@' + domain,
|
tryHandles = [
|
||||||
httpPrefix, {},
|
domain + '@' + domain,
|
||||||
None, __version__)
|
'inbox@' + domain
|
||||||
if wfRequest:
|
]
|
||||||
if isinstance(wfRequest, dict):
|
for handle in tryHandles:
|
||||||
if not wfRequest.get('errors'):
|
wfRequest = webfingerHandle(session, handle,
|
||||||
return True
|
httpPrefix, {},
|
||||||
|
None, __version__)
|
||||||
|
if wfRequest:
|
||||||
|
if isinstance(wfRequest, dict):
|
||||||
|
if not wfRequest.get('errors'):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def sendingProfileUpdate(postJsonObject: {}) -> bool:
|
||||||
|
"""Returns true if the given json is a profile update
|
||||||
|
"""
|
||||||
|
if postJsonObject['type'] != 'Update':
|
||||||
|
return False
|
||||||
|
if not postJsonObject.get('object'):
|
||||||
|
return False
|
||||||
|
if not isinstance(postJsonObject['object'], dict):
|
||||||
|
return False
|
||||||
|
if not postJsonObject['object'].get('type'):
|
||||||
|
return False
|
||||||
|
activityType = postJsonObject['object']['type']
|
||||||
|
if activityType == 'Person' or \
|
||||||
|
activityType == 'Application' or \
|
||||||
|
activityType == 'Group' or \
|
||||||
|
activityType == 'Service':
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2388,24 +2427,35 @@ def sendToFollowers(session, baseDir: str,
|
||||||
clientToServer = False
|
clientToServer = False
|
||||||
|
|
||||||
# for each instance
|
# for each instance
|
||||||
|
sendingStartTime = datetime.datetime.utcnow()
|
||||||
|
print('Sending post to followers begins ' +
|
||||||
|
sendingStartTime.strftime("%Y-%m-%dT%H:%M:%SZ"))
|
||||||
|
sendingCtr = 0
|
||||||
for followerDomain, followerHandles in grouped.items():
|
for followerDomain, followerHandles in grouped.items():
|
||||||
|
print('Sending post to followers progress ' +
|
||||||
|
str(int(sendingCtr * 100 / len(grouped.items()))) + '% ' +
|
||||||
|
followerDomain)
|
||||||
|
sendingCtr += 1
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: follower handles for ' + followerDomain)
|
|
||||||
pprint(followerHandles)
|
pprint(followerHandles)
|
||||||
|
|
||||||
# check that the follower's domain is active
|
# check that the follower's domain is active
|
||||||
followerDomainUrl = httpPrefix + '://' + followerDomain
|
followerDomainUrl = httpPrefix + '://' + followerDomain
|
||||||
if not siteIsActive(followerDomainUrl):
|
if not siteIsActive(followerDomainUrl):
|
||||||
print('Domain is inactive: ' + followerDomainUrl)
|
print('Sending post to followers domain is inactive: ' +
|
||||||
|
followerDomainUrl)
|
||||||
continue
|
continue
|
||||||
print('Domain is active: ' + followerDomainUrl)
|
print('Sending post to followers domain is active: ' +
|
||||||
|
followerDomainUrl)
|
||||||
|
|
||||||
withSharedInbox = hasSharedInbox(session, httpPrefix, followerDomain)
|
withSharedInbox = hasSharedInbox(session, httpPrefix, followerDomain)
|
||||||
if debug:
|
if debug:
|
||||||
if withSharedInbox:
|
if withSharedInbox:
|
||||||
print(followerDomain + ' has shared inbox')
|
print(followerDomain + ' has shared inbox')
|
||||||
else:
|
if not withSharedInbox:
|
||||||
print(followerDomain + ' does not have a shared inbox')
|
print('Sending post to followers, ' + followerDomain +
|
||||||
|
' does not have a shared inbox')
|
||||||
|
|
||||||
toPort = port
|
toPort = port
|
||||||
index = 0
|
index = 0
|
||||||
|
|
@ -2438,22 +2488,14 @@ def sendToFollowers(session, baseDir: str,
|
||||||
toNickname = 'inbox'
|
toNickname = 'inbox'
|
||||||
|
|
||||||
if toNickname != 'inbox' and postJsonObject.get('type'):
|
if toNickname != 'inbox' and postJsonObject.get('type'):
|
||||||
if postJsonObject['type'] == 'Update':
|
if sendingProfileUpdate(postJsonObject):
|
||||||
if postJsonObject.get('object'):
|
print('Sending post to followers ' +
|
||||||
if isinstance(postJsonObject['object'], dict):
|
'shared inbox of ' + toDomain)
|
||||||
if postJsonObject['object'].get('type'):
|
toNickname = 'inbox'
|
||||||
typ = postJsonObject['object']['type']
|
|
||||||
if typ == 'Person' or \
|
|
||||||
typ == 'Application' or \
|
|
||||||
typ == 'Group' or \
|
|
||||||
typ == 'Service':
|
|
||||||
print('Sending profile update to ' +
|
|
||||||
'shared inbox of ' + toDomain)
|
|
||||||
toNickname = 'inbox'
|
|
||||||
|
|
||||||
if debug:
|
print('Sending post to followers from ' +
|
||||||
print('DEBUG: Sending from ' + nickname + '@' + domain +
|
nickname + '@' + domain +
|
||||||
' to ' + toNickname + '@' + toDomain)
|
' to ' + toNickname + '@' + toDomain)
|
||||||
|
|
||||||
sendSignedJson(postJsonObject, session, baseDir,
|
sendSignedJson(postJsonObject, session, baseDir,
|
||||||
nickname, fromDomain, port,
|
nickname, fromDomain, port,
|
||||||
|
|
@ -2465,19 +2507,17 @@ def sendToFollowers(session, baseDir: str,
|
||||||
else:
|
else:
|
||||||
# send to individual followers without using a shared inbox
|
# send to individual followers without using a shared inbox
|
||||||
for handle in followerHandles:
|
for handle in followerHandles:
|
||||||
if debug:
|
print('Sending post to followers ' + handle)
|
||||||
print('DEBUG: Sending to ' + handle)
|
|
||||||
toNickname = handle.split('@')[0]
|
toNickname = handle.split('@')[0]
|
||||||
|
|
||||||
if debug:
|
if postJsonObject['type'] != 'Update':
|
||||||
if postJsonObject['type'] != 'Update':
|
print('Sending post to followers from ' +
|
||||||
print('DEBUG: Sending from ' +
|
nickname + '@' + domain + ' to ' +
|
||||||
nickname + '@' + domain + ' to ' +
|
toNickname + '@' + toDomain)
|
||||||
toNickname + '@' + toDomain)
|
else:
|
||||||
else:
|
print('Sending post to followers profile update from ' +
|
||||||
print('DEBUG: Sending profile update from ' +
|
nickname + '@' + domain + ' to ' +
|
||||||
nickname + '@' + domain + ' to ' +
|
toNickname + '@' + toDomain)
|
||||||
toNickname + '@' + toDomain)
|
|
||||||
|
|
||||||
sendSignedJson(postJsonObject, session, baseDir,
|
sendSignedJson(postJsonObject, session, baseDir,
|
||||||
nickname, fromDomain, port,
|
nickname, fromDomain, port,
|
||||||
|
|
@ -2492,6 +2532,10 @@ def sendToFollowers(session, baseDir: str,
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: End of sendToFollowers')
|
print('DEBUG: End of sendToFollowers')
|
||||||
|
|
||||||
|
sendingEndTime = datetime.datetime.utcnow()
|
||||||
|
sendingMins = int((sendingEndTime - sendingStartTime).total_seconds() / 60)
|
||||||
|
print('Sending post to followers ends ' + str(sendingMins) + ' mins')
|
||||||
|
|
||||||
|
|
||||||
def sendToFollowersThread(session, baseDir: str,
|
def sendToFollowersThread(session, baseDir: str,
|
||||||
nickname: str,
|
nickname: str,
|
||||||
|
|
@ -3357,7 +3401,8 @@ def getPublicPostsOfPerson(baseDir: str, nickname: str, domain: str,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain, 'outbox')
|
nickname, domain, 'outbox',
|
||||||
|
62524)
|
||||||
maxMentions = 10
|
maxMentions = 10
|
||||||
maxEmoji = 10
|
maxEmoji = 10
|
||||||
maxAttachments = 5
|
maxAttachments = 5
|
||||||
|
|
@ -3398,7 +3443,8 @@ def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain, 'outbox')
|
nickname, domain, 'outbox',
|
||||||
|
92522)
|
||||||
maxMentions = 99
|
maxMentions = 99
|
||||||
maxEmoji = 99
|
maxEmoji = 99
|
||||||
maxAttachments = 5
|
maxAttachments = 5
|
||||||
|
|
@ -3441,7 +3487,8 @@ def getPublicPostInfo(session, baseDir: str, nickname: str, domain: str,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain, 'outbox')
|
nickname, domain, 'outbox',
|
||||||
|
13863)
|
||||||
maxMentions = 99
|
maxMentions = 99
|
||||||
maxEmoji = 99
|
maxEmoji = 99
|
||||||
maxAttachments = 5
|
maxAttachments = 5
|
||||||
|
|
@ -3956,7 +4003,7 @@ def sendBlockViaServer(baseDir: str, session,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest,
|
displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix, fromNickname,
|
projectVersion, httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox)
|
fromDomain, postToBox, 72652)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -4038,7 +4085,7 @@ def sendUndoBlockViaServer(baseDir: str, session,
|
||||||
fromPersonId, sharedInbox, avatarUrl,
|
fromPersonId, sharedInbox, avatarUrl,
|
||||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
||||||
projectVersion, httpPrefix, fromNickname,
|
projectVersion, httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox)
|
fromDomain, postToBox, 53892)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
3
roles.py
3
roles.py
|
|
@ -316,7 +316,8 @@ def sendRoleViaServer(baseDir: str, session,
|
||||||
wfRequest, personCache,
|
wfRequest, personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
delegatorNickname,
|
delegatorNickname,
|
||||||
delegatorDomain, postToBox)
|
delegatorDomain, postToBox,
|
||||||
|
765672)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ def runPostScheduleWatchdog(projectVersion: str, httpd) -> None:
|
||||||
httpd.thrPostSchedule.start()
|
httpd.thrPostSchedule.start()
|
||||||
while True:
|
while True:
|
||||||
time.sleep(20)
|
time.sleep(20)
|
||||||
if not httpd.thrPostSchedule.isAlive():
|
if not httpd.thrPostSchedule.is_alive():
|
||||||
httpd.thrPostSchedule.kill()
|
httpd.thrPostSchedule.kill()
|
||||||
httpd.thrPostSchedule = \
|
httpd.thrPostSchedule = \
|
||||||
postScheduleOriginal.clone(runPostSchedule)
|
postScheduleOriginal.clone(runPostSchedule)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/bash
|
||||||
|
journalctl -u epicyon -r | grep "Sending profile update to\|a shared inbox"
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/bash
|
||||||
|
journalctl -u epicyon -r | grep "Sending post to followers"
|
||||||
18
session.py
18
session.py
|
|
@ -58,7 +58,7 @@ def getJson(session, url: str, headers: {}, params: {},
|
||||||
domain='testdomain') -> {}:
|
domain='testdomain') -> {}:
|
||||||
if not isinstance(url, str):
|
if not isinstance(url, str):
|
||||||
print('url: ' + str(url))
|
print('url: ' + str(url))
|
||||||
print('ERROR: getJson url should be a string')
|
print('ERROR: getJson failed, url should be a string')
|
||||||
return None
|
return None
|
||||||
sessionParams = {}
|
sessionParams = {}
|
||||||
sessionHeaders = {}
|
sessionHeaders = {}
|
||||||
|
|
@ -71,23 +71,23 @@ def getJson(session, url: str, headers: {}, params: {},
|
||||||
sessionHeaders['User-Agent'] += \
|
sessionHeaders['User-Agent'] += \
|
||||||
'; +' + httpPrefix + '://' + domain + '/'
|
'; +' + httpPrefix + '://' + domain + '/'
|
||||||
if not session:
|
if not session:
|
||||||
print('WARN: no session specified for getJson')
|
print('WARN: getJson failed, no session specified for getJson')
|
||||||
try:
|
try:
|
||||||
result = session.get(url, headers=sessionHeaders, params=sessionParams)
|
result = session.get(url, headers=sessionHeaders, params=sessionParams)
|
||||||
return result.json()
|
return result.json()
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
print('ERROR: getJson failed\nurl: ' + str(url) + '\n' +
|
print('ERROR: getJson failed\nurl: ' + str(url) + ' ' +
|
||||||
'headers: ' + str(sessionHeaders) + '\n' +
|
'headers: ' + str(sessionHeaders) + ' ' +
|
||||||
'params: ' + str(sessionParams) + '\n')
|
'params: ' + str(sessionParams))
|
||||||
print(e)
|
print(e)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
print('ERROR: getJson failed\nurl: ' + str(url) + '\n' +
|
print('ERROR: getJson failed\nurl: ' + str(url) + ' ' +
|
||||||
'headers: ' + str(sessionHeaders) + '\n' +
|
'headers: ' + str(sessionHeaders) + ' ' +
|
||||||
'params: ' + str(sessionParams) + '\n')
|
'params: ' + str(sessionParams) + ' ')
|
||||||
print(e)
|
print(e)
|
||||||
except SocketError as e:
|
except SocketError as e:
|
||||||
if e.errno == errno.ECONNRESET:
|
if e.errno == errno.ECONNRESET:
|
||||||
print('WARN: connection was reset during getJson')
|
print('WARN: getJson failed, connection was reset during getJson')
|
||||||
print(e)
|
print(e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -376,7 +376,8 @@ def sendShareViaServer(baseDir, session,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, fromNickname,
|
httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox)
|
fromDomain, postToBox,
|
||||||
|
83653)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
@ -474,7 +475,8 @@ def sendUndoShareViaServer(baseDir: str, session,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, fromNickname,
|
httpPrefix, fromNickname,
|
||||||
fromDomain, postToBox)
|
fromDomain, postToBox,
|
||||||
|
12663)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ def sendSkillViaServer(baseDir: str, session, nickname: str, password: str,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, nickname, domain,
|
httpPrefix, nickname, domain,
|
||||||
postToBox)
|
postToBox, 86725)
|
||||||
|
|
||||||
if not inboxUrl:
|
if not inboxUrl:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,8 @@ def instancesGraph(baseDir: str, handles: str,
|
||||||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain, 'outbox')
|
nickname, domain, 'outbox',
|
||||||
|
27261)
|
||||||
postDomains = \
|
postDomains = \
|
||||||
getPostDomains(session, personUrl, 64, maxMentions, maxEmoji,
|
getPostDomains(session, personUrl, 64, maxMentions, maxEmoji,
|
||||||
maxAttachments, federationList,
|
maxAttachments, federationList,
|
||||||
|
|
|
||||||
52
tests.py
52
tests.py
|
|
@ -236,11 +236,11 @@ def testThreads():
|
||||||
args=('test',),
|
args=('test',),
|
||||||
daemon=True)
|
daemon=True)
|
||||||
thr.start()
|
thr.start()
|
||||||
assert thr.isAlive() is True
|
assert thr.is_alive() is True
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
thr.kill()
|
thr.kill()
|
||||||
thr.join()
|
thr.join()
|
||||||
assert thr.isAlive() is False
|
assert thr.is_alive() is False
|
||||||
|
|
||||||
|
|
||||||
def createServerAlice(path: str, domain: str, port: int,
|
def createServerAlice(path: str, domain: str, port: int,
|
||||||
|
|
@ -296,8 +296,10 @@ def createServerAlice(path: str, domain: str, port: int,
|
||||||
allowLocalNetworkAccess = True
|
allowLocalNetworkAccess = True
|
||||||
maxNewswirePosts = 20
|
maxNewswirePosts = 20
|
||||||
dormantMonths = 3
|
dormantMonths = 3
|
||||||
|
sendThreadsTimeoutMins = 30
|
||||||
print('Server running: Alice')
|
print('Server running: Alice')
|
||||||
runDaemon(dormantMonths, maxNewswirePosts,
|
runDaemon(sendThreadsTimeoutMins,
|
||||||
|
dormantMonths, maxNewswirePosts,
|
||||||
allowLocalNetworkAccess,
|
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,
|
||||||
|
|
@ -366,8 +368,10 @@ def createServerBob(path: str, domain: str, port: int,
|
||||||
allowLocalNetworkAccess = True
|
allowLocalNetworkAccess = True
|
||||||
maxNewswirePosts = 20
|
maxNewswirePosts = 20
|
||||||
dormantMonths = 3
|
dormantMonths = 3
|
||||||
|
sendThreadsTimeoutMins = 30
|
||||||
print('Server running: Bob')
|
print('Server running: Bob')
|
||||||
runDaemon(dormantMonths, maxNewswirePosts,
|
runDaemon(sendThreadsTimeoutMins,
|
||||||
|
dormantMonths, maxNewswirePosts,
|
||||||
allowLocalNetworkAccess,
|
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,
|
||||||
|
|
@ -410,8 +414,10 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
|
||||||
allowLocalNetworkAccess = True
|
allowLocalNetworkAccess = True
|
||||||
maxNewswirePosts = 20
|
maxNewswirePosts = 20
|
||||||
dormantMonths = 3
|
dormantMonths = 3
|
||||||
|
sendThreadsTimeoutMins = 30
|
||||||
print('Server running: Eve')
|
print('Server running: Eve')
|
||||||
runDaemon(dormantMonths, maxNewswirePosts,
|
runDaemon(sendThreadsTimeoutMins,
|
||||||
|
dormantMonths, maxNewswirePosts,
|
||||||
allowLocalNetworkAccess,
|
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,
|
||||||
|
|
@ -456,7 +462,7 @@ def testPostMessageBetweenServers():
|
||||||
|
|
||||||
global thrAlice
|
global thrAlice
|
||||||
if thrAlice:
|
if thrAlice:
|
||||||
while thrAlice.isAlive():
|
while thrAlice.is_alive():
|
||||||
thrAlice.stop()
|
thrAlice.stop()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
thrAlice.kill()
|
thrAlice.kill()
|
||||||
|
|
@ -470,7 +476,7 @@ def testPostMessageBetweenServers():
|
||||||
|
|
||||||
global thrBob
|
global thrBob
|
||||||
if thrBob:
|
if thrBob:
|
||||||
while thrBob.isAlive():
|
while thrBob.is_alive():
|
||||||
thrBob.stop()
|
thrBob.stop()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
thrBob.kill()
|
thrBob.kill()
|
||||||
|
|
@ -484,8 +490,8 @@ def testPostMessageBetweenServers():
|
||||||
|
|
||||||
thrAlice.start()
|
thrAlice.start()
|
||||||
thrBob.start()
|
thrBob.start()
|
||||||
assert thrAlice.isAlive() is True
|
assert thrAlice.is_alive() is True
|
||||||
assert thrBob.isAlive() is True
|
assert thrBob.is_alive() is True
|
||||||
|
|
||||||
# wait for both servers to be running
|
# wait for both servers to be running
|
||||||
while not (testServerAliceRunning and testServerBobRunning):
|
while not (testServerAliceRunning and testServerBobRunning):
|
||||||
|
|
@ -684,11 +690,11 @@ def testPostMessageBetweenServers():
|
||||||
# stop the servers
|
# stop the servers
|
||||||
thrAlice.kill()
|
thrAlice.kill()
|
||||||
thrAlice.join()
|
thrAlice.join()
|
||||||
assert thrAlice.isAlive() is False
|
assert thrAlice.is_alive() is False
|
||||||
|
|
||||||
thrBob.kill()
|
thrBob.kill()
|
||||||
thrBob.join()
|
thrBob.join()
|
||||||
assert thrBob.isAlive() is False
|
assert thrBob.is_alive() is False
|
||||||
|
|
||||||
os.chdir(baseDir)
|
os.chdir(baseDir)
|
||||||
shutil.rmtree(aliceDir)
|
shutil.rmtree(aliceDir)
|
||||||
|
|
@ -727,7 +733,7 @@ def testFollowBetweenServers():
|
||||||
|
|
||||||
global thrAlice
|
global thrAlice
|
||||||
if thrAlice:
|
if thrAlice:
|
||||||
while thrAlice.isAlive():
|
while thrAlice.is_alive():
|
||||||
thrAlice.stop()
|
thrAlice.stop()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
thrAlice.kill()
|
thrAlice.kill()
|
||||||
|
|
@ -741,7 +747,7 @@ def testFollowBetweenServers():
|
||||||
|
|
||||||
global thrBob
|
global thrBob
|
||||||
if thrBob:
|
if thrBob:
|
||||||
while thrBob.isAlive():
|
while thrBob.is_alive():
|
||||||
thrBob.stop()
|
thrBob.stop()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
thrBob.kill()
|
thrBob.kill()
|
||||||
|
|
@ -755,8 +761,8 @@ def testFollowBetweenServers():
|
||||||
|
|
||||||
thrAlice.start()
|
thrAlice.start()
|
||||||
thrBob.start()
|
thrBob.start()
|
||||||
assert thrAlice.isAlive() is True
|
assert thrAlice.is_alive() is True
|
||||||
assert thrBob.isAlive() is True
|
assert thrBob.is_alive() is True
|
||||||
|
|
||||||
# wait for all servers to be running
|
# wait for all servers to be running
|
||||||
ctr = 0
|
ctr = 0
|
||||||
|
|
@ -856,11 +862,11 @@ def testFollowBetweenServers():
|
||||||
# stop the servers
|
# stop the servers
|
||||||
thrAlice.kill()
|
thrAlice.kill()
|
||||||
thrAlice.join()
|
thrAlice.join()
|
||||||
assert thrAlice.isAlive() is False
|
assert thrAlice.is_alive() is False
|
||||||
|
|
||||||
thrBob.kill()
|
thrBob.kill()
|
||||||
thrBob.join()
|
thrBob.join()
|
||||||
assert thrBob.isAlive() is False
|
assert thrBob.is_alive() is False
|
||||||
|
|
||||||
# queue item removed
|
# queue item removed
|
||||||
time.sleep(4)
|
time.sleep(4)
|
||||||
|
|
@ -1284,7 +1290,7 @@ def testClientToServer():
|
||||||
|
|
||||||
global thrAlice
|
global thrAlice
|
||||||
if thrAlice:
|
if thrAlice:
|
||||||
while thrAlice.isAlive():
|
while thrAlice.is_alive():
|
||||||
thrAlice.stop()
|
thrAlice.stop()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
thrAlice.kill()
|
thrAlice.kill()
|
||||||
|
|
@ -1298,7 +1304,7 @@ def testClientToServer():
|
||||||
|
|
||||||
global thrBob
|
global thrBob
|
||||||
if thrBob:
|
if thrBob:
|
||||||
while thrBob.isAlive():
|
while thrBob.is_alive():
|
||||||
thrBob.stop()
|
thrBob.stop()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
thrBob.kill()
|
thrBob.kill()
|
||||||
|
|
@ -1312,8 +1318,8 @@ def testClientToServer():
|
||||||
|
|
||||||
thrAlice.start()
|
thrAlice.start()
|
||||||
thrBob.start()
|
thrBob.start()
|
||||||
assert thrAlice.isAlive() is True
|
assert thrAlice.is_alive() is True
|
||||||
assert thrBob.isAlive() is True
|
assert thrBob.is_alive() is True
|
||||||
|
|
||||||
# wait for both servers to be running
|
# wait for both servers to be running
|
||||||
ctr = 0
|
ctr = 0
|
||||||
|
|
@ -1608,11 +1614,11 @@ def testClientToServer():
|
||||||
# stop the servers
|
# stop the servers
|
||||||
thrAlice.kill()
|
thrAlice.kill()
|
||||||
thrAlice.join()
|
thrAlice.join()
|
||||||
assert thrAlice.isAlive() is False
|
assert thrAlice.is_alive() is False
|
||||||
|
|
||||||
thrBob.kill()
|
thrBob.kill()
|
||||||
thrBob.join()
|
thrBob.join()
|
||||||
assert thrBob.isAlive() is False
|
assert thrBob.is_alive() is False
|
||||||
|
|
||||||
os.chdir(baseDir)
|
os.chdir(baseDir)
|
||||||
# shutil.rmtree(aliceDir)
|
# shutil.rmtree(aliceDir)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"today-circle": "#03a494",
|
"today-circle": "#03a494",
|
||||||
|
"options-main-link-color-hover": "white",
|
||||||
"main-link-color-hover": "blue",
|
"main-link-color-hover": "blue",
|
||||||
"font-size-newswire-mobile": "32px",
|
"font-size-newswire-mobile": "32px",
|
||||||
"newswire-date-color": "#00a594",
|
"newswire-date-color": "#00a594",
|
||||||
|
|
@ -58,8 +59,10 @@
|
||||||
"border-width": "1px",
|
"border-width": "1px",
|
||||||
"border-width-header": "1px",
|
"border-width-header": "1px",
|
||||||
"main-link-color": "darkblue",
|
"main-link-color": "darkblue",
|
||||||
|
"options-main-link-color": "lightgrey",
|
||||||
"title-color": "#2a2c37",
|
"title-color": "#2a2c37",
|
||||||
"main-visited-color": "#232c37",
|
"main-visited-color": "#232c37",
|
||||||
|
"options-main-visited-color": "#ccc",
|
||||||
"text-entry-foreground": "#111",
|
"text-entry-foreground": "#111",
|
||||||
"text-entry-background": "white",
|
"text-entry-background": "white",
|
||||||
"font-color-header": "black",
|
"font-color-header": "black",
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,11 @@
|
||||||
"border-color": "#035103",
|
"border-color": "#035103",
|
||||||
"main-link-color": "#2fff2f",
|
"main-link-color": "#2fff2f",
|
||||||
"main-link-color-hover": "#afff2f",
|
"main-link-color-hover": "#afff2f",
|
||||||
|
"options-main-link-color": "#2fff2f",
|
||||||
|
"options-main-link-color-hover": "#afff2f",
|
||||||
"title-color": "#2fff2f",
|
"title-color": "#2fff2f",
|
||||||
"main-visited-color": "#3c8234",
|
"main-visited-color": "#3c8234",
|
||||||
|
"options-main-visited-color": "#3c8234",
|
||||||
"button-selected": "#063200",
|
"button-selected": "#063200",
|
||||||
"button-background-hover": "#a62200",
|
"button-background-hover": "#a62200",
|
||||||
"button-text-hover": "#00ff00",
|
"button-text-hover": "#00ff00",
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,11 @@
|
||||||
"link-bg-color": "#383335",
|
"link-bg-color": "#383335",
|
||||||
"main-link-color": "white",
|
"main-link-color": "white",
|
||||||
"main-link-color-hover": "#ddd",
|
"main-link-color-hover": "#ddd",
|
||||||
|
"options-main-link-color": "white",
|
||||||
|
"options-main-link-color-hover": "#ddd",
|
||||||
"title-color": "white",
|
"title-color": "white",
|
||||||
"main-visited-color": "#e1c4bc",
|
"main-visited-color": "#e1c4bc",
|
||||||
|
"options-main-visited-color": "#e1c4bc",
|
||||||
"main-fg-color": "white",
|
"main-fg-color": "white",
|
||||||
"options-fg-color": "white",
|
"options-fg-color": "white",
|
||||||
"column-left-fg-color": "white",
|
"column-left-fg-color": "white",
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,10 @@
|
||||||
"link-bg-color": "black",
|
"link-bg-color": "black",
|
||||||
"main-link-color": "#ff9900",
|
"main-link-color": "#ff9900",
|
||||||
"main-link-color-hover": "#d09338",
|
"main-link-color-hover": "#d09338",
|
||||||
|
"options-main-link-color": "#ff9900",
|
||||||
|
"options-main-link-color-hover": "#d09338",
|
||||||
"main-visited-color": "#ffb900",
|
"main-visited-color": "#ffb900",
|
||||||
|
"options-main-visited-color": "#ffb900",
|
||||||
"main-fg-color": "white",
|
"main-fg-color": "white",
|
||||||
"login-fg-color": "white",
|
"login-fg-color": "white",
|
||||||
"options-fg-color": "white",
|
"options-fg-color": "white",
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,11 @@
|
||||||
"border-color": "#c0cdd9",
|
"border-color": "#c0cdd9",
|
||||||
"main-link-color": "#25408f",
|
"main-link-color": "#25408f",
|
||||||
"main-link-color-hover": "#10408f",
|
"main-link-color-hover": "#10408f",
|
||||||
|
"options-main-link-color": "#25408f",
|
||||||
|
"options-main-link-color-hover": "#10408f",
|
||||||
"title-color": "#2a2c37",
|
"title-color": "#2a2c37",
|
||||||
"main-visited-color": "#25408f",
|
"main-visited-color": "#25408f",
|
||||||
|
"options-main-visited-color": "#25408f",
|
||||||
"text-entry-foreground": "#111",
|
"text-entry-foreground": "#111",
|
||||||
"text-entry-background": "white",
|
"text-entry-background": "white",
|
||||||
"font-color-header": "black",
|
"font-color-header": "black",
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,11 @@
|
||||||
"border-width-header": "5px",
|
"border-width-header": "5px",
|
||||||
"main-link-color": "#9fb42b",
|
"main-link-color": "#9fb42b",
|
||||||
"main-link-color-hover": "#cfb42b",
|
"main-link-color-hover": "#cfb42b",
|
||||||
|
"options-main-link-color": "#9fb42b",
|
||||||
|
"options-main-link-color-hover": "#cfb42b",
|
||||||
"title-color": "#9fb42b",
|
"title-color": "#9fb42b",
|
||||||
"main-visited-color": "#9fb42b",
|
"main-visited-color": "#9fb42b",
|
||||||
|
"options-main-visited-color": "#9fb42b",
|
||||||
"button-selected": "black",
|
"button-selected": "black",
|
||||||
"button-highlighted": "green",
|
"button-highlighted": "green",
|
||||||
"button-background-hover": "#a3390d",
|
"button-background-hover": "#a3390d",
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,11 @@
|
||||||
"border-color": "#c0cdd9",
|
"border-color": "#c0cdd9",
|
||||||
"main-link-color": "#2a2c37",
|
"main-link-color": "#2a2c37",
|
||||||
"main-link-color-hover": "#aa2c37",
|
"main-link-color-hover": "#aa2c37",
|
||||||
|
"options-main-link-color": "#2a2c37",
|
||||||
|
"options-main-link-color-hover": "#aa2c37",
|
||||||
"title-color": "#2a2c37",
|
"title-color": "#2a2c37",
|
||||||
"main-visited-color": "#232c37",
|
"main-visited-color": "#232c37",
|
||||||
|
"options-main-visited-color": "#232c37",
|
||||||
"text-entry-foreground": "#111",
|
"text-entry-foreground": "#111",
|
||||||
"text-entry-background": "white",
|
"text-entry-background": "white",
|
||||||
"font-color-header": "black",
|
"font-color-header": "black",
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
"rss-icon-at-top": "True",
|
"rss-icon-at-top": "True",
|
||||||
"publish-button-at-top": "False",
|
"publish-button-at-top": "False",
|
||||||
"main-visited-color": "#0481f5",
|
"main-visited-color": "#0481f5",
|
||||||
|
"options-main-visited-color": "#0481f5",
|
||||||
"post-separator-margin-top": "9%",
|
"post-separator-margin-top": "9%",
|
||||||
"post-separator-margin-bottom": "9%",
|
"post-separator-margin-bottom": "9%",
|
||||||
"post-separator-width": "80%",
|
"post-separator-width": "80%",
|
||||||
|
|
@ -30,6 +31,8 @@
|
||||||
"link-bg-color": "#0f0d10",
|
"link-bg-color": "#0f0d10",
|
||||||
"main-link-color": "#6481f5",
|
"main-link-color": "#6481f5",
|
||||||
"main-link-color-hover": "#d09338",
|
"main-link-color-hover": "#d09338",
|
||||||
|
"options-main-link-color": "#6481f5",
|
||||||
|
"options-main-link-color-hover": "#d09338",
|
||||||
"main-fg-color": "#0481f5",
|
"main-fg-color": "#0481f5",
|
||||||
"login-fg-color": "#0481f5",
|
"login-fg-color": "#0481f5",
|
||||||
"options-fg-color": "#0481f5",
|
"options-fg-color": "#0481f5",
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,11 @@
|
||||||
"border-color": "#3f2145",
|
"border-color": "#3f2145",
|
||||||
"main-link-color": "#ff42a0",
|
"main-link-color": "#ff42a0",
|
||||||
"main-link-color-hover": "white",
|
"main-link-color-hover": "white",
|
||||||
|
"options-main-link-color": "#ff42a0",
|
||||||
|
"options-main-link-color-hover": "white",
|
||||||
"title-color": "white",
|
"title-color": "white",
|
||||||
"main-visited-color": "#f93bb0",
|
"main-visited-color": "#f93bb0",
|
||||||
|
"options-main-visited-color": "#f93bb0",
|
||||||
"button-selected": "#c042a0",
|
"button-selected": "#c042a0",
|
||||||
"button-background-hover": "#af42a0",
|
"button-background-hover": "#af42a0",
|
||||||
"button-text-hover": "#f98bb0",
|
"button-text-hover": "#f98bb0",
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
"rss-icon-at-top": "True",
|
"rss-icon-at-top": "True",
|
||||||
"publish-button-at-top": "False",
|
"publish-button-at-top": "False",
|
||||||
"main-visited-color": "#46eed5",
|
"main-visited-color": "#46eed5",
|
||||||
|
"options-main-visited-color": "#46eed5",
|
||||||
"post-separator-margin-top": "9%",
|
"post-separator-margin-top": "9%",
|
||||||
"post-separator-margin-bottom": "9%",
|
"post-separator-margin-bottom": "9%",
|
||||||
"post-separator-width": "80%",
|
"post-separator-width": "80%",
|
||||||
|
|
@ -51,6 +52,8 @@
|
||||||
"link-bg-color": "#0f0d10",
|
"link-bg-color": "#0f0d10",
|
||||||
"main-link-color": "#05b9ec",
|
"main-link-color": "#05b9ec",
|
||||||
"main-link-color-hover": "#46eed5",
|
"main-link-color-hover": "#46eed5",
|
||||||
|
"options-main-link-color": "#05b9ec",
|
||||||
|
"options-main-link-color-hover": "#46eed5",
|
||||||
"main-fg-color": "white",
|
"main-fg-color": "white",
|
||||||
"login-fg-color": "white",
|
"login-fg-color": "white",
|
||||||
"options-fg-color": "white",
|
"options-fg-color": "white",
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,11 @@
|
||||||
"border-color": "#c0cdd9",
|
"border-color": "#c0cdd9",
|
||||||
"main-link-color": "#2a2c37",
|
"main-link-color": "#2a2c37",
|
||||||
"main-link-color-hover": "#aa2c37",
|
"main-link-color-hover": "#aa2c37",
|
||||||
|
"options-main-link-color": "#2a2c37",
|
||||||
|
"options-main-link-color-hover": "#aa2c37",
|
||||||
"title-color": "#2a2c37",
|
"title-color": "#2a2c37",
|
||||||
"main-visited-color": "#232c37",
|
"main-visited-color": "#232c37",
|
||||||
|
"options-main-visited-color": "#232c37",
|
||||||
"text-entry-foreground": "#111",
|
"text-entry-foreground": "#111",
|
||||||
"text-entry-background": "white",
|
"text-entry-background": "white",
|
||||||
"font-color-header": "black",
|
"font-color-header": "black",
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,11 @@
|
||||||
"link-bg-color": "#0f0d10",
|
"link-bg-color": "#0f0d10",
|
||||||
"main-link-color": "#ffc4bc",
|
"main-link-color": "#ffc4bc",
|
||||||
"main-link-color-hover": "white",
|
"main-link-color-hover": "white",
|
||||||
|
"options-main-link-color": "#ffc4bc",
|
||||||
|
"options-main-link-color-hover": "white",
|
||||||
"title-color": "#ffc4bc",
|
"title-color": "#ffc4bc",
|
||||||
"main-visited-color": "#e1c4bc",
|
"main-visited-color": "#e1c4bc",
|
||||||
|
"options-main-visited-color": "#e1c4bc",
|
||||||
"main-fg-color": "#ffc4bc",
|
"main-fg-color": "#ffc4bc",
|
||||||
"login-fg-color": "#ffc4bc",
|
"login-fg-color": "#ffc4bc",
|
||||||
"options-fg-color": "#ffc4bc",
|
"options-fg-color": "#ffc4bc",
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,11 @@
|
||||||
"border-width-header": "7px",
|
"border-width-header": "7px",
|
||||||
"main-link-color": "#dddddd",
|
"main-link-color": "#dddddd",
|
||||||
"main-link-color-hover": "white",
|
"main-link-color-hover": "white",
|
||||||
|
"options-main-link-color": "#dddddd",
|
||||||
|
"options-main-link-color-hover": "white",
|
||||||
"title-color": "#dddddd",
|
"title-color": "#dddddd",
|
||||||
"main-visited-color": "#dddddd",
|
"main-visited-color": "#dddddd",
|
||||||
|
"options-main-visited-color": "#dddddd",
|
||||||
"button-background-hover": "#a63b35",
|
"button-background-hover": "#a63b35",
|
||||||
"publish-button-background": "#463b35",
|
"publish-button-background": "#463b35",
|
||||||
"button-background": "#463b35",
|
"button-background": "#463b35",
|
||||||
|
|
|
||||||
|
|
@ -69,12 +69,14 @@ class threadWithTrace(threading.Thread):
|
||||||
daemon=True)
|
daemon=True)
|
||||||
|
|
||||||
|
|
||||||
def removeDormantThreads(baseDir: str, threadsList: [], debug: bool) -> None:
|
def removeDormantThreads(baseDir: str, threadsList: [], debug: bool,
|
||||||
|
timeoutMins=30) -> None:
|
||||||
"""Removes threads whose execution has completed
|
"""Removes threads whose execution has completed
|
||||||
"""
|
"""
|
||||||
if len(threadsList) == 0:
|
if len(threadsList) == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
timeoutSecs = int(timeoutMins * 60)
|
||||||
dormantThreads = []
|
dormantThreads = []
|
||||||
currTime = datetime.datetime.utcnow()
|
currTime = datetime.datetime.utcnow()
|
||||||
changed = False
|
changed = False
|
||||||
|
|
@ -92,13 +94,13 @@ def removeDormantThreads(baseDir: str, threadsList: [], debug: bool) -> None:
|
||||||
'thread is not alive ten seconds after start')
|
'thread is not alive ten seconds after start')
|
||||||
removeThread = True
|
removeThread = True
|
||||||
# timeout for started threads
|
# timeout for started threads
|
||||||
if (currTime - th.startTime).total_seconds() > 600:
|
if (currTime - th.startTime).total_seconds() > timeoutSecs:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: started thread timed out')
|
print('DEBUG: started thread timed out')
|
||||||
removeThread = True
|
removeThread = True
|
||||||
else:
|
else:
|
||||||
# timeout for threads which havn't been started
|
# timeout for threads which havn't been started
|
||||||
if (currTime - th.startTime).total_seconds() > 600:
|
if (currTime - th.startTime).total_seconds() > timeoutSecs:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: unstarted thread timed out')
|
print('DEBUG: unstarted thread timed out')
|
||||||
removeThread = True
|
removeThread = True
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "اسأل عن عنصر مشترك.",
|
"Ask about a shared item.": "اسأل عن عنصر مشترك.",
|
||||||
"Account Information": "معلومات الحساب",
|
"Account Information": "معلومات الحساب",
|
||||||
"This account interacts with the following instances": "يتفاعل هذا الحساب مع الحالات التالية",
|
"This account interacts with the following instances": "يتفاعل هذا الحساب مع الحالات التالية",
|
||||||
"News posts are moderated": "المشاركات الإخبارية خاضعة للإشراف"
|
"News posts are moderated": "المشاركات الإخبارية خاضعة للإشراف",
|
||||||
|
"Filter": "منقي",
|
||||||
|
"Filter out words": "تصفية الكلمات",
|
||||||
|
"Unfilter": "غير مرشح",
|
||||||
|
"Unfilter words": "الكلمات غير المصفاة",
|
||||||
|
"Show Accounts": "إظهار الحسابات"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "Pregunteu sobre un element compartit.",
|
"Ask about a shared item.": "Pregunteu sobre un element compartit.",
|
||||||
"Account Information": "Informació del compte",
|
"Account Information": "Informació del compte",
|
||||||
"This account interacts with the following instances": "Aquest compte interactua amb les instàncies següents",
|
"This account interacts with the following instances": "Aquest compte interactua amb les instàncies següents",
|
||||||
"News posts are moderated": "Les publicacions de notícies es moderen"
|
"News posts are moderated": "Les publicacions de notícies es moderen",
|
||||||
|
"Filter": "Filtre",
|
||||||
|
"Filter out words": "Filtra les paraules",
|
||||||
|
"Unfilter": "Sense filtre",
|
||||||
|
"Unfilter words": "Paraules sense filtre",
|
||||||
|
"Show Accounts": "Mostra comptes"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "Gofynnwch am eitem a rennir.",
|
"Ask about a shared item.": "Gofynnwch am eitem a rennir.",
|
||||||
"Account Information": "Gwybodaeth Gyfrif",
|
"Account Information": "Gwybodaeth Gyfrif",
|
||||||
"This account interacts with the following instances": "Mae'r cyfrif hwn yn rhyngweithio â'r achosion canlynol",
|
"This account interacts with the following instances": "Mae'r cyfrif hwn yn rhyngweithio â'r achosion canlynol",
|
||||||
"News posts are moderated": "Mae swyddi newyddion yn cael eu cymedroli"
|
"News posts are moderated": "Mae swyddi newyddion yn cael eu cymedroli",
|
||||||
|
"Filter": "Hidlo",
|
||||||
|
"Filter out words": "Hidlo geiriau",
|
||||||
|
"Unfilter": "Di-hid",
|
||||||
|
"Unfilter words": "Geiriau di-hid",
|
||||||
|
"Show Accounts": "Dangos Cyfrifon"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "Fragen Sie nach einem gemeinsamen Artikel.",
|
"Ask about a shared item.": "Fragen Sie nach einem gemeinsamen Artikel.",
|
||||||
"Account Information": "Kontoinformationen",
|
"Account Information": "Kontoinformationen",
|
||||||
"This account interacts with the following instances": "Dieses Konto interagiert mit den folgenden Instanzen",
|
"This account interacts with the following instances": "Dieses Konto interagiert mit den folgenden Instanzen",
|
||||||
"News posts are moderated": "Nachrichtenbeiträge werden moderiert"
|
"News posts are moderated": "Nachrichtenbeiträge werden moderiert",
|
||||||
|
"Filter": "Filter",
|
||||||
|
"Filter out words": "Wörter herausfiltern",
|
||||||
|
"Unfilter": "Filter entfernen",
|
||||||
|
"Unfilter words": "Wörter herausfiltern",
|
||||||
|
"Show Accounts": "Konten anzeigen"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "Ask about a shared item.",
|
"Ask about a shared item.": "Ask about a shared item.",
|
||||||
"Account Information": "Account Information",
|
"Account Information": "Account Information",
|
||||||
"This account interacts with the following instances": "This account interacts with the following instances",
|
"This account interacts with the following instances": "This account interacts with the following instances",
|
||||||
"News posts are moderated": "News posts are moderated"
|
"News posts are moderated": "News posts are moderated",
|
||||||
|
"Filter": "Filter",
|
||||||
|
"Filter out words": "Filter out words",
|
||||||
|
"Unfilter": "Unfilter",
|
||||||
|
"Unfilter words": "Unfilter words",
|
||||||
|
"Show Accounts": "Show Accounts"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "Pregunte por un elemento compartido.",
|
"Ask about a shared item.": "Pregunte por un elemento compartido.",
|
||||||
"Account Information": "Información de la cuenta",
|
"Account Information": "Información de la cuenta",
|
||||||
"This account interacts with the following instances": "Esta cuenta interactúa con las siguientes instancias",
|
"This account interacts with the following instances": "Esta cuenta interactúa con las siguientes instancias",
|
||||||
"News posts are moderated": "Las publicaciones de noticias están moderadas"
|
"News posts are moderated": "Las publicaciones de noticias están moderadas",
|
||||||
|
"Filter": "Filtrar",
|
||||||
|
"Filter out words": "Filtrar palabras",
|
||||||
|
"Unfilter": "Unfilter",
|
||||||
|
"Unfilter words": "Palabras sin filtrar",
|
||||||
|
"Show Accounts": "Mostrar cuentas"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "Renseignez-vous sur un élément partagé.",
|
"Ask about a shared item.": "Renseignez-vous sur un élément partagé.",
|
||||||
"Account Information": "Information sur le compte",
|
"Account Information": "Information sur le compte",
|
||||||
"This account interacts with the following instances": "Ce compte interagit avec les instances suivantes",
|
"This account interacts with the following instances": "Ce compte interagit avec les instances suivantes",
|
||||||
"News posts are moderated": "Les articles d'actualité sont modérés"
|
"News posts are moderated": "Les articles d'actualité sont modérés",
|
||||||
|
"Filter": "Filtre",
|
||||||
|
"Filter out words": "Filtrer les mots",
|
||||||
|
"Unfilter": "Non filtrer",
|
||||||
|
"Unfilter words": "Mots non filtrés",
|
||||||
|
"Show Accounts": "Afficher les comptes"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "Fiafraigh faoi earra roinnte.",
|
"Ask about a shared item.": "Fiafraigh faoi earra roinnte.",
|
||||||
"Account Information": "Faisnéis Chuntais",
|
"Account Information": "Faisnéis Chuntais",
|
||||||
"This account interacts with the following instances": "Idirghníomhaíonn an cuntas seo leis na cásanna seo a leanas",
|
"This account interacts with the following instances": "Idirghníomhaíonn an cuntas seo leis na cásanna seo a leanas",
|
||||||
"News posts are moderated": "Déantar poist nuachta a mhodhnú"
|
"News posts are moderated": "Déantar poist nuachta a mhodhnú",
|
||||||
|
"Filter": "Scagaire",
|
||||||
|
"Filter out words": "Scag focail amach",
|
||||||
|
"Unfilter": "Neamhleithleach",
|
||||||
|
"Unfilter words": "Focail neamhleithleacha",
|
||||||
|
"Show Accounts": "Taispeáin Cuntais"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "एक साझा आइटम के बारे में पूछें।",
|
"Ask about a shared item.": "एक साझा आइटम के बारे में पूछें।",
|
||||||
"Account Information": "खाते की जानकारी",
|
"Account Information": "खाते की जानकारी",
|
||||||
"This account interacts with the following instances": "यह खाता निम्नलिखित उदाहरणों के साथ सहभागिता करता है",
|
"This account interacts with the following instances": "यह खाता निम्नलिखित उदाहरणों के साथ सहभागिता करता है",
|
||||||
"News posts are moderated": "समाचार पोस्ट संचालित होते हैं"
|
"News posts are moderated": "समाचार पोस्ट संचालित होते हैं",
|
||||||
|
"Filter": "फ़िल्टर",
|
||||||
|
"Filter out words": "शब्दों को फ़िल्टर करें",
|
||||||
|
"Unfilter": "Unfilter",
|
||||||
|
"Unfilter words": "अनफ़िल्टर शब्द",
|
||||||
|
"Show Accounts": "खाते दिखाएं"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "Chiedi informazioni su un elemento condiviso.",
|
"Ask about a shared item.": "Chiedi informazioni su un elemento condiviso.",
|
||||||
"Account Information": "Informazioni account",
|
"Account Information": "Informazioni account",
|
||||||
"This account interacts with the following instances": "Questo account interagisce con le seguenti istanze",
|
"This account interacts with the following instances": "Questo account interagisce con le seguenti istanze",
|
||||||
"News posts are moderated": "I post di notizie sono moderati"
|
"News posts are moderated": "I post di notizie sono moderati",
|
||||||
|
"Filter": "Filtro",
|
||||||
|
"Filter out words": "Filtra le parole",
|
||||||
|
"Unfilter": "Unfilter",
|
||||||
|
"Unfilter words": "Parole non filtrate",
|
||||||
|
"Show Accounts": "Mostra account"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "共有アイテムについて質問します。",
|
"Ask about a shared item.": "共有アイテムについて質問します。",
|
||||||
"Account Information": "口座情報",
|
"Account Information": "口座情報",
|
||||||
"This account interacts with the following instances": "このアカウントは、次のインスタンスと相互作用します",
|
"This account interacts with the following instances": "このアカウントは、次のインスタンスと相互作用します",
|
||||||
"News posts are moderated": "ニュース投稿はモデレートされます"
|
"News posts are moderated": "ニュース投稿はモデレートされます",
|
||||||
|
"Filter": "フィルタ",
|
||||||
|
"Filter out words": "単語を除外する",
|
||||||
|
"Unfilter": "フィルタリング解除",
|
||||||
|
"Unfilter words": "単語のフィルタリングを解除する",
|
||||||
|
"Show Accounts": "アカウントを表示する"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -338,5 +338,10 @@
|
||||||
"Ask about a shared item.": "Ask about a shared item.",
|
"Ask about a shared item.": "Ask about a shared item.",
|
||||||
"Account Information": "Account Information",
|
"Account Information": "Account Information",
|
||||||
"This account interacts with the following instances": "This account interacts with the following instances",
|
"This account interacts with the following instances": "This account interacts with the following instances",
|
||||||
"News posts are moderated": "News posts are moderated"
|
"News posts are moderated": "News posts are moderated",
|
||||||
|
"Filter": "Filter",
|
||||||
|
"Filter out words": "Filter out words",
|
||||||
|
"Unfilter": "Unfilter",
|
||||||
|
"Unfilter words": "Unfilter words",
|
||||||
|
"Show Accounts": "Show Accounts"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "Pergunte sobre um item compartilhado.",
|
"Ask about a shared item.": "Pergunte sobre um item compartilhado.",
|
||||||
"Account Information": "Informação da conta",
|
"Account Information": "Informação da conta",
|
||||||
"This account interacts with the following instances": "Esta conta interage com as seguintes instâncias",
|
"This account interacts with the following instances": "Esta conta interage com as seguintes instâncias",
|
||||||
"News posts are moderated": "Postagens de notícias são moderadas"
|
"News posts are moderated": "Postagens de notícias são moderadas",
|
||||||
|
"Filter": "Filtro",
|
||||||
|
"Filter out words": "Filtrar palavras",
|
||||||
|
"Unfilter": "Unfilter",
|
||||||
|
"Unfilter words": "Palavras sem filtro",
|
||||||
|
"Show Accounts": "Mostrar contas"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "Спросите об общем элементе.",
|
"Ask about a shared item.": "Спросите об общем элементе.",
|
||||||
"Account Information": "Информация об аккаунте",
|
"Account Information": "Информация об аккаунте",
|
||||||
"This account interacts with the following instances": "Этот аккаунт взаимодействует со следующими экземплярами",
|
"This account interacts with the following instances": "Этот аккаунт взаимодействует со следующими экземплярами",
|
||||||
"News posts are moderated": "Сообщения новостей модерируются"
|
"News posts are moderated": "Сообщения новостей модерируются",
|
||||||
|
"Filter": "Фильтр",
|
||||||
|
"Filter out words": "Отфильтровать слова",
|
||||||
|
"Unfilter": "Нефильтровать",
|
||||||
|
"Unfilter words": "Не фильтровать слова",
|
||||||
|
"Show Accounts": "Показать счета"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -342,5 +342,10 @@
|
||||||
"Ask about a shared item.": "询问共享项目。",
|
"Ask about a shared item.": "询问共享项目。",
|
||||||
"Account Information": "帐户信息",
|
"Account Information": "帐户信息",
|
||||||
"This account interacts with the following instances": "此帐户与以下实例进行交互",
|
"This account interacts with the following instances": "此帐户与以下实例进行交互",
|
||||||
"News posts are moderated": "新闻发布被审核"
|
"News posts are moderated": "新闻发布被审核",
|
||||||
|
"Filter": "过滤",
|
||||||
|
"Filter out words": "过滤掉单词",
|
||||||
|
"Unfilter": "取消过滤",
|
||||||
|
"Unfilter words": "未过滤字词",
|
||||||
|
"Show Accounts": "显示帐户"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,12 @@ __email__ = "bob@freedombone.net"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from shutil import copyfile
|
|
||||||
from utils import getConfigParam
|
from utils import getConfigParam
|
||||||
from utils import getNicknameFromActor
|
from utils import getNicknameFromActor
|
||||||
from utils import isEditor
|
from utils import isEditor
|
||||||
from webapp_utils import sharesTimelineJson
|
from webapp_utils import sharesTimelineJson
|
||||||
from webapp_utils import htmlPostSeparator
|
from webapp_utils import htmlPostSeparator
|
||||||
from webapp_utils import getLeftImageFile
|
from webapp_utils import getLeftImageFile
|
||||||
from webapp_utils import getImageFile
|
|
||||||
from webapp_utils import headerButtonsFrontScreen
|
from webapp_utils import headerButtonsFrontScreen
|
||||||
from webapp_utils import htmlHeaderWithExternalStyle
|
from webapp_utils import htmlHeaderWithExternalStyle
|
||||||
from webapp_utils import htmlFooter
|
from webapp_utils import htmlFooter
|
||||||
|
|
@ -70,7 +68,7 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
editor: bool,
|
editor: bool,
|
||||||
showBackButton: bool, timelinePath: str,
|
showBackButton: bool, timelinePath: str,
|
||||||
rssIconAtTop: bool, showHeaderImage: bool,
|
rssIconAtTop: bool, showHeaderImage: bool,
|
||||||
frontPage: bool) -> str:
|
frontPage: bool, theme: str) -> str:
|
||||||
"""Returns html content for the left column
|
"""Returns html content for the left column
|
||||||
"""
|
"""
|
||||||
htmlStr = ''
|
htmlStr = ''
|
||||||
|
|
@ -83,23 +81,7 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
editImageClass = ''
|
editImageClass = ''
|
||||||
if showHeaderImage:
|
if showHeaderImage:
|
||||||
leftImageFile, leftColumnImageFilename = \
|
leftImageFile, leftColumnImageFilename = \
|
||||||
getLeftImageFile(baseDir, nickname, domain)
|
getLeftImageFile(baseDir, nickname, domain, theme)
|
||||||
if not os.path.isfile(leftColumnImageFilename):
|
|
||||||
theme = getConfigParam(baseDir, 'theme').lower()
|
|
||||||
if theme == 'default':
|
|
||||||
theme = ''
|
|
||||||
else:
|
|
||||||
theme = '_' + theme
|
|
||||||
themeLeftImageFile, themeLeftColumnImageFilename = \
|
|
||||||
getImageFile(baseDir, 'left_col_image', baseDir + '/img',
|
|
||||||
nickname, domain)
|
|
||||||
if os.path.isfile(themeLeftColumnImageFilename):
|
|
||||||
leftColumnImageFilename = \
|
|
||||||
baseDir + '/accounts/' + \
|
|
||||||
nickname + '@' + domain + '/' + themeLeftImageFile
|
|
||||||
copyfile(themeLeftColumnImageFilename,
|
|
||||||
leftColumnImageFilename)
|
|
||||||
leftImageFile = themeLeftImageFile
|
|
||||||
|
|
||||||
# show the image at the top of the column
|
# show the image at the top of the column
|
||||||
editImageClass = 'leftColEdit'
|
editImageClass = 'leftColEdit'
|
||||||
|
|
@ -255,7 +237,8 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
||||||
timelinePath: str, authorized: bool,
|
timelinePath: str, authorized: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
defaultTimeline: str) -> str:
|
defaultTimeline: str,
|
||||||
|
theme: str) -> str:
|
||||||
"""Show the left column links within mobile view
|
"""Show the left column links within mobile view
|
||||||
"""
|
"""
|
||||||
htmlStr = ''
|
htmlStr = ''
|
||||||
|
|
@ -276,7 +259,8 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
||||||
domain = domain.split(':')[0]
|
domain = domain.split(':')[0]
|
||||||
|
|
||||||
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
|
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
|
||||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
bannerFile, bannerFilename = \
|
||||||
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
|
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
|
||||||
'<img loading="lazy" class="timeline-banner" ' + \
|
'<img loading="lazy" class="timeline-banner" ' + \
|
||||||
|
|
@ -293,7 +277,8 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
editor,
|
editor,
|
||||||
False, timelinePath,
|
False, timelinePath,
|
||||||
rssIconAtTop, False, False)
|
rssIconAtTop, False, False,
|
||||||
|
theme)
|
||||||
else:
|
else:
|
||||||
if editor:
|
if editor:
|
||||||
htmlStr += '<br><br><br>\n'
|
htmlStr += '<br><br><br>\n'
|
||||||
|
|
@ -310,7 +295,7 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
||||||
|
|
||||||
def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
|
def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||||
domain: str, port: int, httpPrefix: str,
|
domain: str, port: int, httpPrefix: str,
|
||||||
defaultTimeline: str) -> str:
|
defaultTimeline: str, theme: str) -> str:
|
||||||
"""Shows the edit links screen
|
"""Shows the edit links screen
|
||||||
"""
|
"""
|
||||||
if '/users/' not in path:
|
if '/users/' not in path:
|
||||||
|
|
@ -331,7 +316,8 @@ def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||||
cssFilename = baseDir + '/links.css'
|
cssFilename = baseDir + '/links.css'
|
||||||
|
|
||||||
# filename of the banner shown at the top
|
# filename of the banner shown at the top
|
||||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
bannerFile, bannerFilename = \
|
||||||
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
|
|
||||||
editLinksForm = htmlHeaderWithExternalStyle(cssFilename)
|
editLinksForm = htmlHeaderWithExternalStyle(cssFilename)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,15 @@ __status__ = "Production"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from shutil import copyfile
|
|
||||||
from content import removeLongWords
|
from content import removeLongWords
|
||||||
from utils import removeHtml
|
from utils import removeHtml
|
||||||
from utils import locatePost
|
from utils import locatePost
|
||||||
from utils import loadJson
|
from utils import loadJson
|
||||||
from utils import getConfigParam
|
|
||||||
from utils import votesOnNewswireItem
|
from utils import votesOnNewswireItem
|
||||||
from utils import getNicknameFromActor
|
from utils import getNicknameFromActor
|
||||||
from utils import isEditor
|
from utils import isEditor
|
||||||
from posts import isModerator
|
from posts import isModerator
|
||||||
from webapp_utils import getRightImageFile
|
from webapp_utils import getRightImageFile
|
||||||
from webapp_utils import getImageFile
|
|
||||||
from webapp_utils import htmlHeaderWithExternalStyle
|
from webapp_utils import htmlHeaderWithExternalStyle
|
||||||
from webapp_utils import htmlFooter
|
from webapp_utils import htmlFooter
|
||||||
from webapp_utils import getBannerFile
|
from webapp_utils import getBannerFile
|
||||||
|
|
@ -51,7 +48,8 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool,
|
authorized: bool,
|
||||||
showHeaderImage: bool) -> str:
|
showHeaderImage: bool,
|
||||||
|
theme: str) -> str:
|
||||||
"""Returns html content for the right column
|
"""Returns html content for the right column
|
||||||
"""
|
"""
|
||||||
htmlStr = ''
|
htmlStr = ''
|
||||||
|
|
@ -84,23 +82,7 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
editImageClass = ''
|
editImageClass = ''
|
||||||
if showHeaderImage:
|
if showHeaderImage:
|
||||||
rightImageFile, rightColumnImageFilename = \
|
rightImageFile, rightColumnImageFilename = \
|
||||||
getRightImageFile(baseDir, nickname, domain)
|
getRightImageFile(baseDir, nickname, domain, theme)
|
||||||
if not os.path.isfile(rightColumnImageFilename):
|
|
||||||
theme = getConfigParam(baseDir, 'theme').lower()
|
|
||||||
if theme == 'default':
|
|
||||||
theme = ''
|
|
||||||
else:
|
|
||||||
theme = '_' + theme
|
|
||||||
themeRightImageFile, themeRightColumnImageFilename = \
|
|
||||||
getImageFile(baseDir, 'right_col_image', baseDir + '/img',
|
|
||||||
nickname, domain)
|
|
||||||
if os.path.isfile(themeRightColumnImageFilename):
|
|
||||||
rightColumnImageFilename = \
|
|
||||||
baseDir + '/accounts/' + \
|
|
||||||
nickname + '@' + domain + '/' + themeRightImageFile
|
|
||||||
copyfile(themeRightColumnImageFilename,
|
|
||||||
rightColumnImageFilename)
|
|
||||||
rightImageFile = themeRightImageFile
|
|
||||||
|
|
||||||
# show the image at the top of the column
|
# show the image at the top of the column
|
||||||
editImageClass = 'rightColEdit'
|
editImageClass = 'rightColEdit'
|
||||||
|
|
@ -297,7 +279,8 @@ def htmlCitations(baseDir: str, nickname: str, domain: str,
|
||||||
blogTitle: str, blogContent: str,
|
blogTitle: str, blogContent: str,
|
||||||
blogImageFilename: str,
|
blogImageFilename: str,
|
||||||
blogImageAttachmentMediaType: str,
|
blogImageAttachmentMediaType: str,
|
||||||
blogImageDescription: str) -> str:
|
blogImageDescription: str,
|
||||||
|
theme: str) -> str:
|
||||||
"""Show the citations screen when creating a blog
|
"""Show the citations screen when creating a blog
|
||||||
"""
|
"""
|
||||||
htmlStr = ''
|
htmlStr = ''
|
||||||
|
|
@ -329,7 +312,8 @@ def htmlCitations(baseDir: str, nickname: str, domain: str,
|
||||||
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
|
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
|
||||||
|
|
||||||
# top banner
|
# top banner
|
||||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
bannerFile, bannerFilename = \
|
||||||
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
'<a href="/users/' + nickname + '/newblog" title="' + \
|
'<a href="/users/' + nickname + '/newblog" title="' + \
|
||||||
translate['Go Back'] + '" alt="' + \
|
translate['Go Back'] + '" alt="' + \
|
||||||
|
|
@ -412,7 +396,8 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str,
|
||||||
authorized: bool,
|
authorized: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
defaultTimeline: str) -> str:
|
defaultTimeline: str,
|
||||||
|
theme: str) -> str:
|
||||||
"""Shows the mobile version of the newswire right column
|
"""Shows the mobile version of the newswire right column
|
||||||
"""
|
"""
|
||||||
htmlStr = ''
|
htmlStr = ''
|
||||||
|
|
@ -436,7 +421,8 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str,
|
||||||
|
|
||||||
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
|
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
|
||||||
|
|
||||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
bannerFile, bannerFilename = \
|
||||||
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
|
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
|
||||||
'<img loading="lazy" class="timeline-banner" ' + \
|
'<img loading="lazy" class="timeline-banner" ' + \
|
||||||
|
|
@ -456,7 +442,7 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str,
|
||||||
newswire, positiveVoting,
|
newswire, positiveVoting,
|
||||||
False, timelinePath, showPublishButton,
|
False, timelinePath, showPublishButton,
|
||||||
showPublishAsIcon, rssIconAtTop, False,
|
showPublishAsIcon, rssIconAtTop, False,
|
||||||
authorized, False)
|
authorized, False, theme)
|
||||||
else:
|
else:
|
||||||
if editor:
|
if editor:
|
||||||
htmlStr += '<br><br><br>\n'
|
htmlStr += '<br><br><br>\n'
|
||||||
|
|
@ -472,7 +458,7 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str,
|
||||||
|
|
||||||
def htmlEditNewswire(cssCache: {}, translate: {}, baseDir: str, path: str,
|
def htmlEditNewswire(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||||
domain: str, port: int, httpPrefix: str,
|
domain: str, port: int, httpPrefix: str,
|
||||||
defaultTimeline: str) -> str:
|
defaultTimeline: str, theme: str) -> str:
|
||||||
"""Shows the edit newswire screen
|
"""Shows the edit newswire screen
|
||||||
"""
|
"""
|
||||||
if '/users/' not in path:
|
if '/users/' not in path:
|
||||||
|
|
@ -493,7 +479,8 @@ def htmlEditNewswire(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||||
cssFilename = baseDir + '/links.css'
|
cssFilename = baseDir + '/links.css'
|
||||||
|
|
||||||
# filename of the banner shown at the top
|
# filename of the banner shown at the top
|
||||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
bannerFile, bannerFilename = \
|
||||||
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
|
|
||||||
editNewswireForm = htmlHeaderWithExternalStyle(cssFilename)
|
editNewswireForm = htmlHeaderWithExternalStyle(cssFilename)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,8 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
|
||||||
reportUrl: str, pageNumber: int,
|
reportUrl: str, pageNumber: int,
|
||||||
nickname: str, domain: str,
|
nickname: str, domain: str,
|
||||||
domainFull: str,
|
domainFull: str,
|
||||||
defaultTimeline: str, newswire: {}) -> str:
|
defaultTimeline: str, newswire: {},
|
||||||
|
theme: str) -> str:
|
||||||
"""New post screen
|
"""New post screen
|
||||||
"""
|
"""
|
||||||
replyStr = ''
|
replyStr = ''
|
||||||
|
|
@ -178,7 +179,8 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
|
||||||
messageBoxHeight = 400
|
messageBoxHeight = 400
|
||||||
|
|
||||||
# filename of the banner shown at the top
|
# filename of the banner shown at the top
|
||||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
bannerFile, bannerFilename = \
|
||||||
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
|
|
||||||
if not path.endswith('/newshare'):
|
if not path.endswith('/newshare'):
|
||||||
if not path.endswith('/newreport'):
|
if not path.endswith('/newreport'):
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
||||||
session, wfRequest: {}, personCache: {},
|
session, wfRequest: {}, personCache: {},
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
newswire: {}, extraJson=None,
|
newswire: {}, theme: str, extraJson=None,
|
||||||
pageNumber=None, maxItemsPerPage=None) -> str:
|
pageNumber=None, maxItemsPerPage=None) -> str:
|
||||||
"""Show the news instance front screen
|
"""Show the news instance front screen
|
||||||
"""
|
"""
|
||||||
|
|
@ -104,7 +104,8 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
||||||
iconsAsButtons)
|
iconsAsButtons)
|
||||||
|
|
||||||
# If this is the news account then show a different banner
|
# If this is the news account then show a different banner
|
||||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
bannerFile, bannerFilename = \
|
||||||
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
profileHeaderStr = \
|
profileHeaderStr = \
|
||||||
'<img loading="lazy" class="timeline-banner" ' + \
|
'<img loading="lazy" class="timeline-banner" ' + \
|
||||||
'src="/users/' + nickname + '/' + bannerFile + '" />\n'
|
'src="/users/' + nickname + '/' + bannerFile + '" />\n'
|
||||||
|
|
@ -124,7 +125,7 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
||||||
getLeftColumnContent(baseDir, 'news', domainFull,
|
getLeftColumnContent(baseDir, 'news', domainFull,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
False, False, None, rssIconAtTop, True,
|
False, False, None, rssIconAtTop, True,
|
||||||
True)
|
True, theme)
|
||||||
profileHeaderStr += ' </td>\n'
|
profileHeaderStr += ' </td>\n'
|
||||||
profileHeaderStr += ' <td valign="top" class="col-center">\n'
|
profileHeaderStr += ' <td valign="top" class="col-center">\n'
|
||||||
|
|
||||||
|
|
@ -136,7 +137,7 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
||||||
|
|
||||||
licenseStr = ''
|
licenseStr = ''
|
||||||
bannerFile, bannerFilename = \
|
bannerFile, bannerFilename = \
|
||||||
getBannerFile(baseDir, nickname, domain)
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
profileStr += \
|
profileStr += \
|
||||||
htmlFrontScreenPosts(recentPostsCache, maxRecentPosts,
|
htmlFrontScreenPosts(recentPostsCache, maxRecentPosts,
|
||||||
translate,
|
translate,
|
||||||
|
|
@ -155,7 +156,7 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
False, False, newswire, False,
|
False, False, newswire, False,
|
||||||
False, None, False, False,
|
False, None, False, False,
|
||||||
False, True, authorized, True)
|
False, True, authorized, True, theme)
|
||||||
profileFooterStr += ' </td>\n'
|
profileFooterStr += ' </td>\n'
|
||||||
profileFooterStr += ' </tr>\n'
|
profileFooterStr += ' </tr>\n'
|
||||||
profileFooterStr += ' </tbody>\n'
|
profileFooterStr += ' </tbody>\n'
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,10 @@ __status__ = "Production"
|
||||||
import os
|
import os
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from utils import getConfigParam
|
|
||||||
from utils import getNicknameFromActor
|
from utils import getNicknameFromActor
|
||||||
from utils import getHashtagCategories
|
from utils import getHashtagCategories
|
||||||
from utils import getHashtagCategory
|
from utils import getHashtagCategory
|
||||||
from webapp_utils import getSearchBannerFile
|
from webapp_utils import getSearchBannerFile
|
||||||
from webapp_utils import getImageFile
|
|
||||||
from webapp_utils import getContentWarningButton
|
from webapp_utils import getContentWarningButton
|
||||||
from webapp_utils import htmlHeaderWithExternalStyle
|
from webapp_utils import htmlHeaderWithExternalStyle
|
||||||
from webapp_utils import htmlFooter
|
from webapp_utils import htmlFooter
|
||||||
|
|
@ -231,7 +229,8 @@ def htmlHashTagSwarm(baseDir: str, actor: str, translate: {}) -> str:
|
||||||
|
|
||||||
|
|
||||||
def htmlSearchHashtagCategory(cssCache: {}, translate: {},
|
def htmlSearchHashtagCategory(cssCache: {}, translate: {},
|
||||||
baseDir: str, path: str, domain: str) -> str:
|
baseDir: str, path: str, domain: str,
|
||||||
|
theme: str) -> str:
|
||||||
"""Show hashtags after selecting a category on the main search screen
|
"""Show hashtags after selecting a category on the main search screen
|
||||||
"""
|
"""
|
||||||
actor = path.split('/category/')[0]
|
actor = path.split('/category/')[0]
|
||||||
|
|
@ -251,24 +250,7 @@ def htmlSearchHashtagCategory(cssCache: {}, translate: {},
|
||||||
|
|
||||||
# show a banner above the search box
|
# show a banner above the search box
|
||||||
searchBannerFile, searchBannerFilename = \
|
searchBannerFile, searchBannerFilename = \
|
||||||
getSearchBannerFile(baseDir, searchNickname, domain)
|
getSearchBannerFile(baseDir, searchNickname, domain, theme)
|
||||||
if not os.path.isfile(searchBannerFilename):
|
|
||||||
# get the default search banner for the theme
|
|
||||||
theme = getConfigParam(baseDir, 'theme').lower()
|
|
||||||
if theme == 'default':
|
|
||||||
theme = ''
|
|
||||||
else:
|
|
||||||
theme = '_' + theme
|
|
||||||
themeSearchImageFile, themeSearchBannerFilename = \
|
|
||||||
getImageFile(baseDir, 'search_banner', baseDir + '/img',
|
|
||||||
searchNickname, domain)
|
|
||||||
if os.path.isfile(themeSearchBannerFilename):
|
|
||||||
searchBannerFilename = \
|
|
||||||
baseDir + '/accounts/' + \
|
|
||||||
searchNickname + '@' + domain + '/' + themeSearchImageFile
|
|
||||||
copyfile(themeSearchBannerFilename,
|
|
||||||
searchBannerFilename)
|
|
||||||
searchBannerFile = themeSearchImageFile
|
|
||||||
|
|
||||||
if os.path.isfile(searchBannerFilename):
|
if os.path.isfile(searchBannerFilename):
|
||||||
htmlStr += '<a href="' + actor + '/search">\n'
|
htmlStr += '<a href="' + actor + '/search">\n'
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,14 @@ __email__ = "bob@freedombone.net"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from utils import isEditor
|
||||||
|
from utils import loadJson
|
||||||
from utils import getNicknameFromActor
|
from utils import getNicknameFromActor
|
||||||
from utils import getDomainFromActor
|
from utils import getDomainFromActor
|
||||||
from posts import getPublicPostInfo
|
from posts import getPublicPostInfo
|
||||||
|
from posts import isModerator
|
||||||
from webapp_timeline import htmlTimeline
|
from webapp_timeline import htmlTimeline
|
||||||
|
# from webapp_utils import getPersonAvatarUrl
|
||||||
from webapp_utils import getContentWarningButton
|
from webapp_utils import getContentWarningButton
|
||||||
from webapp_utils import htmlHeaderWithExternalStyle
|
from webapp_utils import htmlHeaderWithExternalStyle
|
||||||
from webapp_utils import htmlFooter
|
from webapp_utils import htmlFooter
|
||||||
|
|
@ -152,11 +156,73 @@ def htmlModerationInfo(cssCache: {}, translate: {},
|
||||||
'</a></h1></center><br>'
|
'</a></h1></center><br>'
|
||||||
|
|
||||||
infoShown = False
|
infoShown = False
|
||||||
|
|
||||||
|
accounts = []
|
||||||
|
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
|
||||||
|
accounts.append(acct)
|
||||||
|
break
|
||||||
|
accounts.sort()
|
||||||
|
|
||||||
|
cols = 5
|
||||||
|
if len(accounts) > 10:
|
||||||
|
infoForm += '<details><summary><b>' + translate['Show Accounts']
|
||||||
|
infoForm += '</b></summary>\n'
|
||||||
|
infoForm += '<div class="container">\n'
|
||||||
|
infoForm += '<table class="accountsTable">\n'
|
||||||
|
infoForm += ' <colgroup>\n'
|
||||||
|
for col in range(cols):
|
||||||
|
infoForm += ' <col span="1" class="accountsTableCol">\n'
|
||||||
|
infoForm += ' </colgroup>\n'
|
||||||
|
infoForm += '<tr>\n'
|
||||||
|
|
||||||
|
col = 0
|
||||||
|
for acct in accounts:
|
||||||
|
acctNickname = acct.split('@')[0]
|
||||||
|
accountDir = os.path.join(baseDir + '/accounts', acct)
|
||||||
|
actorJson = loadJson(accountDir + '.json')
|
||||||
|
if not actorJson:
|
||||||
|
continue
|
||||||
|
actor = actorJson['id']
|
||||||
|
avatarUrl = ''
|
||||||
|
ext = ''
|
||||||
|
if actorJson.get('icon'):
|
||||||
|
if actorJson['icon'].get('url'):
|
||||||
|
avatarUrl = actorJson['icon']['url']
|
||||||
|
if '.' in avatarUrl:
|
||||||
|
ext = '.' + avatarUrl.split('.')[-1]
|
||||||
|
acctUrl = \
|
||||||
|
'/users/' + nickname + '?options=' + actor + ';1;' + \
|
||||||
|
'/members/' + acctNickname + ext
|
||||||
|
infoForm += '<td>\n<a href="' + acctUrl + '">'
|
||||||
|
infoForm += '<img loading="lazy" style="width:90%" '
|
||||||
|
infoForm += 'src="' + avatarUrl + '" />'
|
||||||
|
infoForm += '<br><center>'
|
||||||
|
if isModerator(baseDir, acctNickname):
|
||||||
|
infoForm += '<b><u>' + acctNickname + '</u></b>'
|
||||||
|
else:
|
||||||
|
infoForm += acctNickname
|
||||||
|
if isEditor(baseDir, acctNickname):
|
||||||
|
infoForm += ' ✍'
|
||||||
|
infoForm += '</center></a>\n</td>\n'
|
||||||
|
col += 1
|
||||||
|
if col == cols:
|
||||||
|
# new row of accounts
|
||||||
|
infoForm += '</tr>\n<tr>\n'
|
||||||
|
infoForm += '</tr>\n</table>\n'
|
||||||
|
infoForm += '</div>\n'
|
||||||
|
if len(accounts) > 10:
|
||||||
|
infoForm += '</details>\n'
|
||||||
|
|
||||||
suspendedFilename = baseDir + '/accounts/suspended.txt'
|
suspendedFilename = baseDir + '/accounts/suspended.txt'
|
||||||
if os.path.isfile(suspendedFilename):
|
if os.path.isfile(suspendedFilename):
|
||||||
with open(suspendedFilename, "r") as f:
|
with open(suspendedFilename, "r") as f:
|
||||||
suspendedStr = f.read()
|
suspendedStr = f.read()
|
||||||
infoForm += '<div class="container">'
|
infoForm += '<div class="container">\n'
|
||||||
infoForm += ' <br><b>' + \
|
infoForm += ' <br><b>' + \
|
||||||
translate['Suspended accounts'] + '</b>'
|
translate['Suspended accounts'] + '</b>'
|
||||||
infoForm += ' <br>' + \
|
infoForm += ' <br>' + \
|
||||||
|
|
@ -164,15 +230,15 @@ def htmlModerationInfo(cssCache: {}, translate: {},
|
||||||
infoForm += \
|
infoForm += \
|
||||||
' <textarea id="message" ' + \
|
' <textarea id="message" ' + \
|
||||||
'name="suspended" style="height:200px">' + \
|
'name="suspended" style="height:200px">' + \
|
||||||
suspendedStr + '</textarea>'
|
suspendedStr + '</textarea>\n'
|
||||||
infoForm += '</div>'
|
infoForm += '</div>\n'
|
||||||
infoShown = True
|
infoShown = True
|
||||||
|
|
||||||
blockingFilename = baseDir + '/accounts/blocking.txt'
|
blockingFilename = baseDir + '/accounts/blocking.txt'
|
||||||
if os.path.isfile(blockingFilename):
|
if os.path.isfile(blockingFilename):
|
||||||
with open(blockingFilename, "r") as f:
|
with open(blockingFilename, "r") as f:
|
||||||
blockedStr = f.read()
|
blockedStr = f.read()
|
||||||
infoForm += '<div class="container">'
|
infoForm += '<div class="container">\n'
|
||||||
infoForm += \
|
infoForm += \
|
||||||
' <br><b>' + \
|
' <br><b>' + \
|
||||||
translate['Blocked accounts and hashtags'] + '</b>'
|
translate['Blocked accounts and hashtags'] + '</b>'
|
||||||
|
|
@ -182,13 +248,29 @@ def htmlModerationInfo(cssCache: {}, translate: {},
|
||||||
infoForm += \
|
infoForm += \
|
||||||
' <textarea id="message" ' + \
|
' <textarea id="message" ' + \
|
||||||
'name="blocked" style="height:700px">' + \
|
'name="blocked" style="height:700px">' + \
|
||||||
blockedStr + '</textarea>'
|
blockedStr + '</textarea>\n'
|
||||||
infoForm += '</div>'
|
infoForm += '</div>\n'
|
||||||
infoShown = True
|
infoShown = True
|
||||||
|
|
||||||
|
filtersFilename = baseDir + '/accounts/filters.txt'
|
||||||
|
if os.path.isfile(filtersFilename):
|
||||||
|
with open(filtersFilename, "r") as f:
|
||||||
|
filteredStr = f.read()
|
||||||
|
infoForm += '<div class="container">\n'
|
||||||
|
infoForm += \
|
||||||
|
' <br><b>' + \
|
||||||
|
translate['Filtered words'] + '</b>'
|
||||||
|
infoForm += \
|
||||||
|
' <textarea id="message" ' + \
|
||||||
|
'name="filtered" style="height:700px">' + \
|
||||||
|
filteredStr + '</textarea>\n'
|
||||||
|
infoForm += '</div>\n'
|
||||||
|
infoShown = True
|
||||||
|
|
||||||
if not infoShown:
|
if not infoShown:
|
||||||
infoForm += \
|
infoForm += \
|
||||||
'<center><p>' + \
|
'<center><p>' + \
|
||||||
translate[msgStr2] + \
|
translate[msgStr2] + \
|
||||||
'</p></center>'
|
'</p></center>\n'
|
||||||
infoForm += htmlFooter()
|
infoForm += htmlFooter()
|
||||||
return infoForm
|
return infoForm
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,8 @@ def htmlPersonOptions(defaultTimeline: str,
|
||||||
PGPpubKey: str,
|
PGPpubKey: str,
|
||||||
PGPfingerprint: str,
|
PGPfingerprint: str,
|
||||||
emailAddress: str,
|
emailAddress: str,
|
||||||
dormantMonths: int) -> str:
|
dormantMonths: int,
|
||||||
|
backToPath: str) -> str:
|
||||||
"""Show options for a person: view/follow/block/report
|
"""Show options for a person: view/follow/block/report
|
||||||
"""
|
"""
|
||||||
optionsDomain, optionsPort = getDomainFromActor(optionsActor)
|
optionsDomain, optionsPort = getDomainFromActor(optionsActor)
|
||||||
|
|
@ -225,6 +226,8 @@ def htmlPersonOptions(defaultTimeline: str,
|
||||||
backPath = '/'
|
backPath = '/'
|
||||||
if nickname:
|
if nickname:
|
||||||
backPath = '/users/' + nickname + '/' + defaultTimeline
|
backPath = '/users/' + nickname + '/' + defaultTimeline
|
||||||
|
if 'moderation' in backToPath:
|
||||||
|
backPath = '/users/' + nickname + '/moderation'
|
||||||
optionsStr += \
|
optionsStr += \
|
||||||
' <a href="' + backPath + '"><button type="button" ' + \
|
' <a href="' + backPath + '"><button type="button" ' + \
|
||||||
'class="buttonIcon" name="submitBack">' + translate['Go Back'] + \
|
'class="buttonIcon" name="submitBack">' + translate['Go Back'] + \
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ from content import getMentionsFromHtml
|
||||||
from content import switchWords
|
from content import switchWords
|
||||||
from person import isPersonSnoozed
|
from person import isPersonSnoozed
|
||||||
from announce import announcedByPerson
|
from announce import announcedByPerson
|
||||||
|
from webapp_utils import getAvatarImageUrl
|
||||||
from webapp_utils import getPersonAvatarUrl
|
from webapp_utils import getPersonAvatarUrl
|
||||||
from webapp_utils import updateAvatarImageCache
|
from webapp_utils import updateAvatarImageCache
|
||||||
from webapp_utils import loadIndividualPostAsHtmlFromCache
|
from webapp_utils import loadIndividualPostAsHtmlFromCache
|
||||||
|
|
@ -177,32 +178,6 @@ def getPostFromRecentCache(session,
|
||||||
return postHtml
|
return postHtml
|
||||||
|
|
||||||
|
|
||||||
def getAvatarImageUrl(session,
|
|
||||||
baseDir: str, httpPrefix: str,
|
|
||||||
postActor: str, personCache: {},
|
|
||||||
avatarUrl: str, allowDownloads: bool) -> str:
|
|
||||||
"""Returns the avatar image url
|
|
||||||
"""
|
|
||||||
# get the avatar image url for the post actor
|
|
||||||
if not avatarUrl:
|
|
||||||
avatarUrl = \
|
|
||||||
getPersonAvatarUrl(baseDir, postActor, personCache,
|
|
||||||
allowDownloads)
|
|
||||||
avatarUrl = \
|
|
||||||
updateAvatarImageCache(session, baseDir, httpPrefix,
|
|
||||||
postActor, avatarUrl, personCache,
|
|
||||||
allowDownloads)
|
|
||||||
else:
|
|
||||||
updateAvatarImageCache(session, baseDir, httpPrefix,
|
|
||||||
postActor, avatarUrl, personCache,
|
|
||||||
allowDownloads)
|
|
||||||
|
|
||||||
if not avatarUrl:
|
|
||||||
avatarUrl = postActor + '/avatar.png'
|
|
||||||
|
|
||||||
return avatarUrl
|
|
||||||
|
|
||||||
|
|
||||||
def getAvatarImageHtml(showAvatarOptions: bool,
|
def getAvatarImageHtml(showAvatarOptions: bool,
|
||||||
nickname: str, domainFull: str,
|
nickname: str, domainFull: str,
|
||||||
avatarUrl: str, postActor: str,
|
avatarUrl: str, postActor: str,
|
||||||
|
|
@ -1179,7 +1154,8 @@ def individualPostAsHtml(allowDownloads: bool,
|
||||||
avatarUrl2, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl2, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache,
|
personCache,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
nickname, domain, 'outbox')
|
nickname, domain, 'outbox',
|
||||||
|
72367)
|
||||||
logPostTiming(enableTimingLog, postStartTime, '6')
|
logPostTiming(enableTimingLog, postStartTime, '6')
|
||||||
|
|
||||||
if avatarUrl2:
|
if avatarUrl2:
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ from pgp import getPGPfingerprint
|
||||||
from pgp import getPGPpubKey
|
from pgp import getPGPpubKey
|
||||||
from tox import getToxAddress
|
from tox import getToxAddress
|
||||||
from jami import getJamiAddress
|
from jami import getJamiAddress
|
||||||
|
from filters import isFiltered
|
||||||
from webapp_frontscreen import htmlFrontScreen
|
from webapp_frontscreen import htmlFrontScreen
|
||||||
from webapp_utils import scheduledPostsExist
|
from webapp_utils import scheduledPostsExist
|
||||||
from webapp_utils import getPersonAvatarUrl
|
from webapp_utils import getPersonAvatarUrl
|
||||||
|
|
@ -259,10 +260,20 @@ def htmlProfileAfterSearch(cssCache: {},
|
||||||
continue
|
continue
|
||||||
if not item.get('object'):
|
if not item.get('object'):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# wfRequest = {}
|
||||||
|
# requestHandle = nickname + '@' + domain
|
||||||
|
# if cachedWebfingers.get(requestHandle):
|
||||||
|
# wfRequest = cachedWebfingers[requestHandle]
|
||||||
|
# elif cachedWebfingers.get(requestHandle + ':' + str(port)):
|
||||||
|
# wfRequest = cachedWebfingers[requestHandle + ':' + str(port)]
|
||||||
|
# TODO: this may need to be changed
|
||||||
|
wfRequest = cachedWebfingers
|
||||||
|
|
||||||
profileStr += \
|
profileStr += \
|
||||||
individualPostAsHtml(True, recentPostsCache, maxRecentPosts,
|
individualPostAsHtml(True, recentPostsCache, maxRecentPosts,
|
||||||
translate, None, baseDir,
|
translate, None, baseDir,
|
||||||
session, cachedWebfingers, personCache,
|
session, wfRequest, personCache,
|
||||||
nickname, domain, port,
|
nickname, domain, port,
|
||||||
item, avatarUrl, False, False,
|
item, avatarUrl, False, False,
|
||||||
httpPrefix, projectVersion, 'inbox',
|
httpPrefix, projectVersion, 'inbox',
|
||||||
|
|
@ -282,7 +293,8 @@ def getProfileHeader(baseDir: str, nickname: str, domain: str,
|
||||||
displayName: str,
|
displayName: str,
|
||||||
avatarDescription: str,
|
avatarDescription: str,
|
||||||
profileDescriptionShort: str,
|
profileDescriptionShort: str,
|
||||||
loginButton: str, avatarUrl: str) -> str:
|
loginButton: str, avatarUrl: str,
|
||||||
|
theme: str) -> str:
|
||||||
"""The header of the profile screen, containing background
|
"""The header of the profile screen, containing background
|
||||||
image and avatar
|
image and avatar
|
||||||
"""
|
"""
|
||||||
|
|
@ -291,7 +303,7 @@ def getProfileHeader(baseDir: str, nickname: str, domain: str,
|
||||||
nickname + '/' + defaultTimeline + '" title="' + \
|
nickname + '/' + defaultTimeline + '" title="' + \
|
||||||
translate['Switch to timeline view'] + '">\n'
|
translate['Switch to timeline view'] + '">\n'
|
||||||
htmlStr += ' <img class="profileBackground" ' + \
|
htmlStr += ' <img class="profileBackground" ' + \
|
||||||
'src="/users/' + nickname + '/image.png" /></a>\n'
|
'src="/users/' + nickname + '/image_' + theme + '.png" /></a>\n'
|
||||||
htmlStr += ' <figcaption>\n'
|
htmlStr += ' <figcaption>\n'
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
' <a href="/users/' + \
|
' <a href="/users/' + \
|
||||||
|
|
@ -359,7 +371,7 @@ def htmlProfile(rssIconAtTop: bool,
|
||||||
session, wfRequest: {}, personCache: {},
|
session, wfRequest: {}, personCache: {},
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool,
|
showPublishedDateOnly: bool,
|
||||||
newswire: {}, dormantMonths: int,
|
newswire: {}, theme: str, dormantMonths: int,
|
||||||
extraJson=None, pageNumber=None,
|
extraJson=None, pageNumber=None,
|
||||||
maxItemsPerPage=None) -> str:
|
maxItemsPerPage=None) -> str:
|
||||||
"""Show the profile page as html
|
"""Show the profile page as html
|
||||||
|
|
@ -378,7 +390,7 @@ def htmlProfile(rssIconAtTop: bool,
|
||||||
session, wfRequest, personCache,
|
session, wfRequest, personCache,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly,
|
showPublishedDateOnly,
|
||||||
newswire, extraJson,
|
newswire, theme, extraJson,
|
||||||
pageNumber, maxItemsPerPage)
|
pageNumber, maxItemsPerPage)
|
||||||
|
|
||||||
domain, port = getDomainFromActor(profileJson['id'])
|
domain, port = getDomainFromActor(profileJson['id'])
|
||||||
|
|
@ -561,7 +573,7 @@ def htmlProfile(rssIconAtTop: bool,
|
||||||
defaultTimeline, displayName,
|
defaultTimeline, displayName,
|
||||||
avatarDescription,
|
avatarDescription,
|
||||||
profileDescriptionShort,
|
profileDescriptionShort,
|
||||||
loginButton, avatarUrl)
|
loginButton, avatarUrl, theme)
|
||||||
|
|
||||||
profileStr = profileHeaderStr + donateSection
|
profileStr = profileHeaderStr + donateSection
|
||||||
profileStr += '<div class="container" id="buttonheader">\n'
|
profileStr += '<div class="container" id="buttonheader">\n'
|
||||||
|
|
@ -819,7 +831,7 @@ def htmlProfileShares(actor: str, translate: {},
|
||||||
|
|
||||||
def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||||
domain: str, port: int, httpPrefix: str,
|
domain: str, port: int, httpPrefix: str,
|
||||||
defaultTimeline: str) -> str:
|
defaultTimeline: str, theme: str) -> str:
|
||||||
"""Shows the edit profile screen
|
"""Shows the edit profile screen
|
||||||
"""
|
"""
|
||||||
imageFormats = getImageFormats()
|
imageFormats = getImageFormats()
|
||||||
|
|
@ -836,7 +848,8 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
# filename of the banner shown at the top
|
# filename of the banner shown at the top
|
||||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
bannerFile, bannerFilename = \
|
||||||
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
|
|
||||||
isBot = ''
|
isBot = ''
|
||||||
isGroup = ''
|
isGroup = ''
|
||||||
|
|
@ -872,10 +885,13 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||||
PGPpubKey = getPGPpubKey(actorJson)
|
PGPpubKey = getPGPpubKey(actorJson)
|
||||||
PGPfingerprint = getPGPfingerprint(actorJson)
|
PGPfingerprint = getPGPfingerprint(actorJson)
|
||||||
if actorJson.get('name'):
|
if actorJson.get('name'):
|
||||||
displayNickname = actorJson['name']
|
if not isFiltered(baseDir, nickname, domain, actorJson['name']):
|
||||||
|
displayNickname = actorJson['name']
|
||||||
if actorJson.get('summary'):
|
if actorJson.get('summary'):
|
||||||
bioStr = \
|
bioStr = \
|
||||||
actorJson['summary'].replace('<p>', '').replace('</p>', '')
|
actorJson['summary'].replace('<p>', '').replace('</p>', '')
|
||||||
|
if isFiltered(baseDir, nickname, domain, bioStr):
|
||||||
|
bioStr = ''
|
||||||
if actorJson.get('manuallyApprovesFollowers'):
|
if actorJson.get('manuallyApprovesFollowers'):
|
||||||
if actorJson['manuallyApprovesFollowers']:
|
if actorJson['manuallyApprovesFollowers']:
|
||||||
manuallyApprovesFollowers = 'checked'
|
manuallyApprovesFollowers = 'checked'
|
||||||
|
|
@ -982,6 +998,8 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||||
skillCtr = 1
|
skillCtr = 1
|
||||||
if skills:
|
if skills:
|
||||||
for skillDesc, skillValue in skills.items():
|
for skillDesc, skillValue in skills.items():
|
||||||
|
if isFiltered(baseDir, nickname, domain, skillDesc):
|
||||||
|
continue
|
||||||
skillsStr += \
|
skillsStr += \
|
||||||
'<p><input type="text" placeholder="' + translate['Skill'] + \
|
'<p><input type="text" placeholder="' + translate['Skill'] + \
|
||||||
' ' + str(skillCtr) + '" name="skillName' + str(skillCtr) + \
|
' ' + str(skillCtr) + '" name="skillName' + str(skillCtr) + \
|
||||||
|
|
@ -1457,7 +1475,7 @@ def individualFollowAsHtml(translate: {},
|
||||||
avatarUrl2, displayName) = getPersonBox(baseDir, session, wfRequest,
|
avatarUrl2, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||||
personCache, projectVersion,
|
personCache, projectVersion,
|
||||||
httpPrefix, nickname,
|
httpPrefix, nickname,
|
||||||
domain, 'outbox')
|
domain, 'outbox', 43036)
|
||||||
if avatarUrl2:
|
if avatarUrl2:
|
||||||
avatarUrl = avatarUrl2
|
avatarUrl = avatarUrl2
|
||||||
if displayName:
|
if displayName:
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ from utils import isEditor
|
||||||
from utils import loadJson
|
from utils import loadJson
|
||||||
from utils import getDomainFromActor
|
from utils import getDomainFromActor
|
||||||
from utils import getNicknameFromActor
|
from utils import getNicknameFromActor
|
||||||
from utils import getConfigParam
|
|
||||||
from utils import locatePost
|
from utils import locatePost
|
||||||
from utils import isPublicPost
|
from utils import isPublicPost
|
||||||
from utils import firstParagraphFromString
|
from utils import firstParagraphFromString
|
||||||
|
|
@ -24,7 +23,6 @@ from utils import getHashtagCategory
|
||||||
from feeds import rss2TagHeader
|
from feeds import rss2TagHeader
|
||||||
from feeds import rss2TagFooter
|
from feeds import rss2TagFooter
|
||||||
from webapp_utils import getAltPath
|
from webapp_utils import getAltPath
|
||||||
from webapp_utils import getImageFile
|
|
||||||
from webapp_utils import htmlHeaderWithExternalStyle
|
from webapp_utils import htmlHeaderWithExternalStyle
|
||||||
from webapp_utils import htmlFooter
|
from webapp_utils import htmlFooter
|
||||||
from webapp_utils import getSearchBannerFile
|
from webapp_utils import getSearchBannerFile
|
||||||
|
|
@ -312,7 +310,7 @@ def htmlSearchEmojiTextEntry(cssCache: {}, translate: {},
|
||||||
|
|
||||||
def htmlSearch(cssCache: {}, translate: {},
|
def htmlSearch(cssCache: {}, translate: {},
|
||||||
baseDir: str, path: str, domain: str,
|
baseDir: str, path: str, domain: str,
|
||||||
defaultTimeline: str) -> str:
|
defaultTimeline: str, theme: str) -> str:
|
||||||
"""Search called from the timeline icon
|
"""Search called from the timeline icon
|
||||||
"""
|
"""
|
||||||
actor = path.replace('/search', '')
|
actor = path.replace('/search', '')
|
||||||
|
|
@ -331,24 +329,7 @@ def htmlSearch(cssCache: {}, translate: {},
|
||||||
|
|
||||||
# show a banner above the search box
|
# show a banner above the search box
|
||||||
searchBannerFile, searchBannerFilename = \
|
searchBannerFile, searchBannerFilename = \
|
||||||
getSearchBannerFile(baseDir, searchNickname, domain)
|
getSearchBannerFile(baseDir, searchNickname, domain, theme)
|
||||||
if not os.path.isfile(searchBannerFilename):
|
|
||||||
# get the default search banner for the theme
|
|
||||||
theme = getConfigParam(baseDir, 'theme').lower()
|
|
||||||
if theme == 'default':
|
|
||||||
theme = ''
|
|
||||||
else:
|
|
||||||
theme = '_' + theme
|
|
||||||
themeSearchImageFile, themeSearchBannerFilename = \
|
|
||||||
getImageFile(baseDir, 'search_banner', baseDir + '/img',
|
|
||||||
searchNickname, domain)
|
|
||||||
if os.path.isfile(themeSearchBannerFilename):
|
|
||||||
searchBannerFilename = \
|
|
||||||
baseDir + '/accounts/' + \
|
|
||||||
searchNickname + '@' + domain + '/' + themeSearchImageFile
|
|
||||||
copyfile(themeSearchBannerFilename,
|
|
||||||
searchBannerFilename)
|
|
||||||
searchBannerFile = themeSearchImageFile
|
|
||||||
|
|
||||||
if os.path.isfile(searchBannerFilename):
|
if os.path.isfile(searchBannerFilename):
|
||||||
usersPath = '/users/' + searchNickname
|
usersPath = '/users/' + searchNickname
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool,
|
authorized: bool,
|
||||||
moderationActionStr: str) -> str:
|
moderationActionStr: str,
|
||||||
|
theme: str) -> str:
|
||||||
"""Show the timeline as html
|
"""Show the timeline as html
|
||||||
"""
|
"""
|
||||||
enableTimingLog = False
|
enableTimingLog = False
|
||||||
|
|
@ -123,7 +124,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
cssFilename = baseDir + '/epicyon.css'
|
cssFilename = baseDir + '/epicyon.css'
|
||||||
|
|
||||||
# filename of the banner shown at the top
|
# filename of the banner shown at the top
|
||||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
bannerFile, bannerFilename = \
|
||||||
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
|
|
||||||
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '1')
|
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '1')
|
||||||
|
|
||||||
|
|
@ -404,7 +406,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
getLeftColumnContent(baseDir, nickname, domainFull,
|
getLeftColumnContent(baseDir, nickname, domainFull,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
editor, False, None, rssIconAtTop,
|
editor, False, None, rssIconAtTop,
|
||||||
True, False)
|
True, False, theme)
|
||||||
tlStr += ' <td valign="top" class="col-left">' + \
|
tlStr += ' <td valign="top" class="col-left">' + \
|
||||||
leftColumnStr + ' </td>\n'
|
leftColumnStr + ' </td>\n'
|
||||||
# center column containing posts
|
# center column containing posts
|
||||||
|
|
@ -444,6 +446,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
else:
|
else:
|
||||||
tlStr += ' <input type="text" ' + \
|
tlStr += ' <input type="text" ' + \
|
||||||
'name="moderationAction" value="" autofocus><br>\n'
|
'name="moderationAction" value="" autofocus><br>\n'
|
||||||
|
|
||||||
tlStr += \
|
tlStr += \
|
||||||
' <input type="submit" title="' + \
|
' <input type="submit" title="' + \
|
||||||
translate['Information about current blocks/suspensions'] + \
|
translate['Information about current blocks/suspensions'] + \
|
||||||
|
|
@ -453,6 +456,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
translate['Remove the above item'] + \
|
translate['Remove the above item'] + \
|
||||||
'" name="submitRemove" value="' + \
|
'" name="submitRemove" value="' + \
|
||||||
translate['Remove'] + '">\n'
|
translate['Remove'] + '">\n'
|
||||||
|
|
||||||
tlStr += \
|
tlStr += \
|
||||||
' <input type="submit" title="' + \
|
' <input type="submit" title="' + \
|
||||||
translate['Suspend the above account nickname'] + \
|
translate['Suspend the above account nickname'] + \
|
||||||
|
|
@ -462,6 +466,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
translate['Remove a suspension for an account nickname'] + \
|
translate['Remove a suspension for an account nickname'] + \
|
||||||
'" name="submitUnsuspend" value="' + \
|
'" name="submitUnsuspend" value="' + \
|
||||||
translate['Unsuspend'] + '">\n'
|
translate['Unsuspend'] + '">\n'
|
||||||
|
|
||||||
tlStr += \
|
tlStr += \
|
||||||
' <input type="submit" title="' + \
|
' <input type="submit" title="' + \
|
||||||
translate['Block an account on another instance'] + \
|
translate['Block an account on another instance'] + \
|
||||||
|
|
@ -470,6 +475,16 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
' <input type="submit" title="' + \
|
' <input type="submit" title="' + \
|
||||||
translate['Unblock an account on another instance'] + \
|
translate['Unblock an account on another instance'] + \
|
||||||
'" name="submitUnblock" value="' + translate['Unblock'] + '">\n'
|
'" name="submitUnblock" value="' + translate['Unblock'] + '">\n'
|
||||||
|
|
||||||
|
tlStr += \
|
||||||
|
' <input type="submit" title="' + \
|
||||||
|
translate['Filter out words'] + \
|
||||||
|
'" name="submitFilter" value="' + translate['Filter'] + '">\n'
|
||||||
|
tlStr += \
|
||||||
|
' <input type="submit" title="' + \
|
||||||
|
translate['Unfilter words'] + \
|
||||||
|
'" name="submitUnfilter" value="' + translate['Unfilter'] + '">\n'
|
||||||
|
|
||||||
tlStr += '</div>\n</form>\n'
|
tlStr += '</div>\n</form>\n'
|
||||||
|
|
||||||
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '6')
|
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '6')
|
||||||
|
|
@ -592,7 +607,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
False, None, True,
|
False, None, True,
|
||||||
showPublishAsIcon,
|
showPublishAsIcon,
|
||||||
rssIconAtTop, publishButtonAtTop,
|
rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, True)
|
authorized, True, theme)
|
||||||
tlStr += ' <td valign="top" class="col-right">' + \
|
tlStr += ' <td valign="top" class="col-right">' + \
|
||||||
rightColumnStr + ' </td>\n'
|
rightColumnStr + ' </td>\n'
|
||||||
tlStr += ' </tr>\n'
|
tlStr += ' </tr>\n'
|
||||||
|
|
@ -705,7 +720,7 @@ def htmlShares(cssCache: {}, defaultTimeline: str,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool) -> str:
|
authorized: bool, theme: str) -> str:
|
||||||
"""Show the shares timeline as html
|
"""Show the shares timeline as html
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
|
|
@ -724,7 +739,7 @@ def htmlShares(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None)
|
authorized, None, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlInbox(cssCache: {}, defaultTimeline: str,
|
def htmlInbox(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -742,7 +757,7 @@ def htmlInbox(cssCache: {}, defaultTimeline: str,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool) -> str:
|
authorized: bool, theme: str) -> str:
|
||||||
"""Show the inbox as html
|
"""Show the inbox as html
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
|
|
@ -761,7 +776,7 @@ def htmlInbox(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None)
|
authorized, None, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -779,7 +794,7 @@ def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool) -> str:
|
authorized: bool, theme: str) -> str:
|
||||||
"""Show the bookmarks as html
|
"""Show the bookmarks as html
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
|
|
@ -798,7 +813,7 @@ def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None)
|
authorized, None, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlEvents(cssCache: {}, defaultTimeline: str,
|
def htmlEvents(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -816,7 +831,7 @@ def htmlEvents(cssCache: {}, defaultTimeline: str,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool) -> str:
|
authorized: bool, theme: str) -> str:
|
||||||
"""Show the events as html
|
"""Show the events as html
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
|
|
@ -835,7 +850,7 @@ def htmlEvents(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None)
|
authorized, None, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -853,7 +868,7 @@ def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool) -> str:
|
authorized: bool, theme: str) -> str:
|
||||||
"""Show the DM timeline as html
|
"""Show the DM timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -867,7 +882,7 @@ def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
||||||
showPublishAsIcon,
|
showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None)
|
authorized, None, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -885,7 +900,7 @@ def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool) -> str:
|
authorized: bool, theme: str) -> str:
|
||||||
"""Show the replies timeline as html
|
"""Show the replies timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -900,7 +915,7 @@ def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None)
|
authorized, None, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -918,7 +933,7 @@ def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool) -> str:
|
authorized: bool, theme: str) -> str:
|
||||||
"""Show the media timeline as html
|
"""Show the media timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -933,7 +948,7 @@ def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None)
|
authorized, None, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -951,7 +966,7 @@ def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool) -> str:
|
authorized: bool, theme: str) -> str:
|
||||||
"""Show the blogs timeline as html
|
"""Show the blogs timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -966,7 +981,7 @@ def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None)
|
authorized, None, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -984,7 +999,8 @@ def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool) -> str:
|
authorized: bool,
|
||||||
|
theme: str) -> str:
|
||||||
"""Show the features timeline as html
|
"""Show the features timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -999,7 +1015,7 @@ def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None)
|
authorized, None, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -1017,7 +1033,7 @@ def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool) -> str:
|
authorized: bool, theme: str) -> str:
|
||||||
"""Show the news timeline as html
|
"""Show the news timeline as html
|
||||||
"""
|
"""
|
||||||
return htmlTimeline(cssCache, defaultTimeline,
|
return htmlTimeline(cssCache, defaultTimeline,
|
||||||
|
|
@ -1032,7 +1048,7 @@ def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
||||||
positiveVoting, showPublishAsIcon,
|
positiveVoting, showPublishAsIcon,
|
||||||
fullWidthTimelineButtonHeader,
|
fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None)
|
authorized, None, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
@ -1050,7 +1066,7 @@ def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
||||||
iconsAsButtons: bool,
|
iconsAsButtons: bool,
|
||||||
rssIconAtTop: bool,
|
rssIconAtTop: bool,
|
||||||
publishButtonAtTop: bool,
|
publishButtonAtTop: bool,
|
||||||
authorized: bool) -> str:
|
authorized: bool, theme: str) -> str:
|
||||||
"""Show the Outbox as html
|
"""Show the Outbox as html
|
||||||
"""
|
"""
|
||||||
manuallyApproveFollowers = \
|
manuallyApproveFollowers = \
|
||||||
|
|
@ -1066,4 +1082,4 @@ def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
||||||
newswire, False, False, positiveVoting,
|
newswire, False, False, positiveVoting,
|
||||||
showPublishAsIcon, fullWidthTimelineButtonHeader,
|
showPublishAsIcon, fullWidthTimelineButtonHeader,
|
||||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||||
authorized, None)
|
authorized, None, theme)
|
||||||
|
|
|
||||||
|
|
@ -476,7 +476,7 @@ def postContainsPublic(postJsonObject: {}) -> bool:
|
||||||
|
|
||||||
|
|
||||||
def getImageFile(baseDir: str, name: str, directory: str,
|
def getImageFile(baseDir: str, name: str, directory: str,
|
||||||
nickname: str, domain: str) -> (str, str):
|
nickname: str, domain: str, theme: str) -> (str, str):
|
||||||
"""
|
"""
|
||||||
returns the filenames for an image with the given name
|
returns the filenames for an image with the given name
|
||||||
"""
|
"""
|
||||||
|
|
@ -484,39 +484,41 @@ def getImageFile(baseDir: str, name: str, directory: str,
|
||||||
bannerFile = ''
|
bannerFile = ''
|
||||||
bannerFilename = ''
|
bannerFilename = ''
|
||||||
for ext in bannerExtensions:
|
for ext in bannerExtensions:
|
||||||
bannerFile = name + '.' + ext
|
bannerFileTest = name + '.' + ext
|
||||||
bannerFilename = directory + '/' + bannerFile
|
bannerFilenameTest = directory + '/' + bannerFileTest
|
||||||
if os.path.isfile(bannerFilename):
|
if os.path.isfile(bannerFilenameTest):
|
||||||
|
bannerFile = name + '_' + theme + '.' + ext
|
||||||
|
bannerFilename = bannerFilenameTest
|
||||||
break
|
break
|
||||||
return bannerFile, bannerFilename
|
return bannerFile, bannerFilename
|
||||||
|
|
||||||
|
|
||||||
def getBannerFile(baseDir: str,
|
def getBannerFile(baseDir: str,
|
||||||
nickname: str, domain: str) -> (str, str):
|
nickname: str, domain: str, theme: str) -> (str, str):
|
||||||
return getImageFile(baseDir, 'banner',
|
return getImageFile(baseDir, 'banner',
|
||||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||||
nickname, domain)
|
nickname, domain, theme)
|
||||||
|
|
||||||
|
|
||||||
def getSearchBannerFile(baseDir: str,
|
def getSearchBannerFile(baseDir: str,
|
||||||
nickname: str, domain: str) -> (str, str):
|
nickname: str, domain: str, theme: str) -> (str, str):
|
||||||
return getImageFile(baseDir, 'search_banner',
|
return getImageFile(baseDir, 'search_banner',
|
||||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||||
nickname, domain)
|
nickname, domain, theme)
|
||||||
|
|
||||||
|
|
||||||
def getLeftImageFile(baseDir: str,
|
def getLeftImageFile(baseDir: str,
|
||||||
nickname: str, domain: str) -> (str, str):
|
nickname: str, domain: str, theme: str) -> (str, str):
|
||||||
return getImageFile(baseDir, 'left_col_image',
|
return getImageFile(baseDir, 'left_col_image',
|
||||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||||
nickname, domain)
|
nickname, domain, theme)
|
||||||
|
|
||||||
|
|
||||||
def getRightImageFile(baseDir: str,
|
def getRightImageFile(baseDir: str,
|
||||||
nickname: str, domain: str) -> (str, str):
|
nickname: str, domain: str, theme: str) -> (str, str):
|
||||||
return getImageFile(baseDir, 'right_col_image',
|
return getImageFile(baseDir, 'right_col_image',
|
||||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||||
nickname, domain)
|
nickname, domain, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlHeaderWithExternalStyle(cssFilename: str, lang='en') -> str:
|
def htmlHeaderWithExternalStyle(cssFilename: str, lang='en') -> str:
|
||||||
|
|
@ -850,3 +852,29 @@ def htmlHighlightLabel(label: str, highlight: bool) -> str:
|
||||||
if not highlight:
|
if not highlight:
|
||||||
return label
|
return label
|
||||||
return '*' + str(label) + '*'
|
return '*' + str(label) + '*'
|
||||||
|
|
||||||
|
|
||||||
|
def getAvatarImageUrl(session,
|
||||||
|
baseDir: str, httpPrefix: str,
|
||||||
|
postActor: str, personCache: {},
|
||||||
|
avatarUrl: str, allowDownloads: bool) -> str:
|
||||||
|
"""Returns the avatar image url
|
||||||
|
"""
|
||||||
|
# get the avatar image url for the post actor
|
||||||
|
if not avatarUrl:
|
||||||
|
avatarUrl = \
|
||||||
|
getPersonAvatarUrl(baseDir, postActor, personCache,
|
||||||
|
allowDownloads)
|
||||||
|
avatarUrl = \
|
||||||
|
updateAvatarImageCache(session, baseDir, httpPrefix,
|
||||||
|
postActor, avatarUrl, personCache,
|
||||||
|
allowDownloads)
|
||||||
|
else:
|
||||||
|
updateAvatarImageCache(session, baseDir, httpPrefix,
|
||||||
|
postActor, avatarUrl, personCache,
|
||||||
|
allowDownloads)
|
||||||
|
|
||||||
|
if not avatarUrl:
|
||||||
|
avatarUrl = postActor + '/avatar.png'
|
||||||
|
|
||||||
|
return avatarUrl
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@ def webfingerHandle(session, handle: str, httpPrefix: str,
|
||||||
wf = getWebfingerFromCache(nickname + '@' + wfDomain,
|
wf = getWebfingerFromCache(nickname + '@' + wfDomain,
|
||||||
cachedWebfingers)
|
cachedWebfingers)
|
||||||
if wf:
|
if wf:
|
||||||
|
print('Webfinger from cache: ' + str(wf))
|
||||||
return wf
|
return wf
|
||||||
url = '{}://{}/.well-known/webfinger'.format(httpPrefix, domain)
|
url = '{}://{}/.well-known/webfinger'.format(httpPrefix, domain)
|
||||||
par = {
|
par = {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue