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,
|
||||
projectVersion, httpPrefix,
|
||||
fromNickname, fromDomain,
|
||||
postToBox)
|
||||
postToBox, 73528)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
|
|
@ -123,7 +123,7 @@ def sendAvailabilityViaServer(baseDir: str, session,
|
|||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache, projectVersion,
|
||||
httpPrefix, nickname,
|
||||
domain, postToBox)
|
||||
domain, postToBox, 57262)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
|
|
@ -441,7 +441,7 @@ def sendBookmarkViaServer(baseDir: str, session,
|
|||
fromPersonId, sharedInbox, avatarUrl,
|
||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
||||
projectVersion, httpPrefix, fromNickname,
|
||||
fromDomain, postToBox)
|
||||
fromDomain, postToBox, 72483)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
@ -518,7 +518,7 @@ def sendUndoBookmarkViaServer(baseDir: str, session,
|
|||
fromPersonId, sharedInbox, avatarUrl,
|
||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
||||
projectVersion, httpPrefix, fromNickname,
|
||||
fromDomain, postToBox)
|
||||
fromDomain, postToBox, 72528)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
|
251
daemon.py
251
daemon.py
|
@ -239,6 +239,8 @@ from newswire import loadHashtagCategories
|
|||
from newsdaemon import runNewswireWatchdog
|
||||
from newsdaemon import runNewswireDaemon
|
||||
from filters import isFiltered
|
||||
from filters import addGlobalFilter
|
||||
from filters import removeGlobalFilter
|
||||
import os
|
||||
|
||||
|
||||
|
@ -1012,7 +1014,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
print('Waiting for previous outbox thread to end')
|
||||
waitCtr = 0
|
||||
thName = accountOutboxThreadName
|
||||
while self.server.outboxThread[thName].isAlive() and waitCtr < 8:
|
||||
while self.server.outboxThread[thName].is_alive() and waitCtr < 8:
|
||||
time.sleep(1)
|
||||
waitCtr += 1
|
||||
if waitCtr >= 8:
|
||||
|
@ -1506,6 +1508,10 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
moderationButton = 'block'
|
||||
elif moderationStr.startswith('submitUnblock'):
|
||||
moderationButton = 'unblock'
|
||||
elif moderationStr.startswith('submitFilter'):
|
||||
moderationButton = 'filter'
|
||||
elif moderationStr.startswith('submitUnfilter'):
|
||||
moderationButton = 'unfilter'
|
||||
elif moderationStr.startswith('submitSuspend'):
|
||||
moderationButton = 'suspend'
|
||||
elif moderationStr.startswith('submitUnsuspend'):
|
||||
|
@ -1526,6 +1532,10 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
suspendAccount(baseDir, nickname, domain)
|
||||
if moderationButton == 'unsuspend':
|
||||
unsuspendAccount(baseDir, nickname)
|
||||
if moderationButton == 'filter':
|
||||
addGlobalFilter(baseDir, moderationText)
|
||||
if moderationButton == 'unfilter':
|
||||
removeGlobalFilter(baseDir, moderationText)
|
||||
if moderationButton == 'block':
|
||||
fullBlockDomain = None
|
||||
if moderationText.startswith('http') or \
|
||||
|
@ -1939,7 +1949,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
domain,
|
||||
domainFull,
|
||||
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),
|
||||
cookie, callingDomain)
|
||||
self._write(msg)
|
||||
|
@ -2032,7 +2043,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
domain,
|
||||
domainFull,
|
||||
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),
|
||||
cookie, callingDomain)
|
||||
self._write(msg)
|
||||
|
@ -3772,20 +3784,42 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
# which isn't implemented in Epicyon
|
||||
actorJson['discoverable'] = False
|
||||
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
|
||||
uploads = profileMediaTypesUploaded.items()
|
||||
for mType, lastPart in uploads:
|
||||
repStr = '/' + lastPart
|
||||
if mType == 'avatar':
|
||||
lastPartOfUrl = \
|
||||
actorJson['icon']['url'].split('/')[-1]
|
||||
actorUrl = actorJson['icon']['url']
|
||||
lastPartOfUrl = actorUrl.split('/')[-1]
|
||||
srchStr = '/' + lastPartOfUrl
|
||||
actorJson['icon']['url'] = \
|
||||
actorJson['icon']['url'].replace(srchStr,
|
||||
repStr)
|
||||
if '.' in actorJson['icon']['url']:
|
||||
imgExt = \
|
||||
actorJson['icon']['url'].split('.')[-1]
|
||||
actorUrl = actorUrl.replace(srchStr, repStr)
|
||||
actorJson['icon']['url'] = actorUrl
|
||||
print('actorUrl: ' + actorUrl)
|
||||
if '.' in actorUrl:
|
||||
imgExt = actorUrl.split('.')[-1]
|
||||
if imgExt == 'jpg':
|
||||
imgExt = 'jpeg'
|
||||
actorJson['icon']['mediaType'] = \
|
||||
|
@ -3814,6 +3848,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
if not skillName:
|
||||
skillCtr += 1
|
||||
continue
|
||||
if isFiltered(baseDir, nickname, domain, skillName):
|
||||
skillCtr += 1
|
||||
continue
|
||||
skillValue = \
|
||||
fields.get('skillValue' + str(skillCtr))
|
||||
if not skillValue:
|
||||
|
@ -3826,6 +3863,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
int(skillValue):
|
||||
actorChanged = True
|
||||
newSkills[skillName] = int(skillValue)
|
||||
skillsStr = self.server.translate['Skills']
|
||||
setHashtagCategory(baseDir, skillName,
|
||||
skillsStr.lower())
|
||||
skillCtr += 1
|
||||
if len(actorJson['skills'].items()) != \
|
||||
len(newSkills.items()):
|
||||
|
@ -3847,8 +3887,14 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
# change displayed name
|
||||
if fields.get('displayNickname'):
|
||||
if fields['displayNickname'] != actorJson['name']:
|
||||
actorJson['name'] = \
|
||||
displayName = \
|
||||
removeHtml(fields['displayNickname'])
|
||||
if not isFiltered(baseDir,
|
||||
nickname, domain,
|
||||
displayName):
|
||||
actorJson['name'] = displayName
|
||||
else:
|
||||
actorJson['name'] = nickname
|
||||
actorChanged = True
|
||||
|
||||
# change media instance status
|
||||
|
@ -4136,18 +4182,20 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
if fields.get('bio'):
|
||||
if fields['bio'] != actorJson['summary']:
|
||||
bioStr = removeHtml(fields['bio'])
|
||||
actorTags = {}
|
||||
actorJson['summary'] = \
|
||||
addHtmlTags(baseDir,
|
||||
httpPrefix,
|
||||
nickname,
|
||||
domainFull,
|
||||
bioStr, [], actorTags)
|
||||
if actorTags:
|
||||
actorJson['tag'] = []
|
||||
for tagName, tag in actorTags.items():
|
||||
actorJson['tag'].append(tag)
|
||||
actorChanged = True
|
||||
if not isFiltered(baseDir,
|
||||
nickname, domain, bioStr):
|
||||
actorTags = {}
|
||||
actorJson['summary'] = \
|
||||
addHtmlTags(baseDir,
|
||||
httpPrefix,
|
||||
nickname,
|
||||
domainFull,
|
||||
bioStr, [], actorTags)
|
||||
if actorTags:
|
||||
actorJson['tag'] = []
|
||||
for tagName, tag in actorTags.items():
|
||||
actorJson['tag'].append(tag)
|
||||
actorChanged = True
|
||||
else:
|
||||
if actorJson['summary']:
|
||||
actorJson['summary'] = ''
|
||||
|
@ -5030,6 +5078,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
cookie: str, debug: bool) -> None:
|
||||
"""Show person options screen
|
||||
"""
|
||||
backToPath = ''
|
||||
optionsStr = path.split('?options=')[1]
|
||||
originPathStr = path.split('?options=')[0]
|
||||
if ';' in optionsStr and '/users/news/' not in path:
|
||||
|
@ -5038,6 +5087,14 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
optionsActor = optionsList[0]
|
||||
optionsPageNumber = optionsList[1]
|
||||
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():
|
||||
pageNumber = int(optionsPageNumber)
|
||||
optionsLink = None
|
||||
|
@ -5083,7 +5140,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
toxAddress, jamiAddress,
|
||||
PGPpubKey, PGPfingerprint,
|
||||
emailAddress,
|
||||
self.server.dormantMonths).encode('utf-8')
|
||||
self.server.dormantMonths,
|
||||
backToPath).encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
self._write(msg)
|
||||
|
@ -6605,6 +6663,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
YTReplacementDomain,
|
||||
self.server.showPublishedDateOnly,
|
||||
self.server.newswire,
|
||||
self.server.themeName,
|
||||
self.server.dormantMonths,
|
||||
actorJson['roles'],
|
||||
None, None)
|
||||
|
@ -6685,6 +6744,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
YTReplacementDomain,
|
||||
showPublishedDateOnly,
|
||||
self.server.newswire,
|
||||
self.server.themeName,
|
||||
self.server.dormantMonths,
|
||||
actorJson['skills'],
|
||||
None, None)
|
||||
|
@ -7046,7 +7106,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.iconsAsButtons,
|
||||
self.server.rssIconAtTop,
|
||||
self.server.publishButtonAtTop,
|
||||
authorized)
|
||||
authorized,
|
||||
self.server.themeName)
|
||||
if GETstartTime:
|
||||
self._benchmarkGETtimings(GETstartTime, GETtimings,
|
||||
'show status done',
|
||||
|
@ -7169,7 +7230,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.iconsAsButtons,
|
||||
self.server.rssIconAtTop,
|
||||
self.server.publishButtonAtTop,
|
||||
authorized)
|
||||
authorized, self.server.themeName)
|
||||
msg = msg.encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -7285,7 +7346,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.iconsAsButtons,
|
||||
self.server.rssIconAtTop,
|
||||
self.server.publishButtonAtTop,
|
||||
authorized)
|
||||
authorized, self.server.themeName)
|
||||
msg = msg.encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -7401,7 +7462,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.iconsAsButtons,
|
||||
self.server.rssIconAtTop,
|
||||
self.server.publishButtonAtTop,
|
||||
authorized)
|
||||
authorized,
|
||||
self.server.themeName)
|
||||
msg = msg.encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -7517,7 +7579,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.iconsAsButtons,
|
||||
self.server.rssIconAtTop,
|
||||
self.server.publishButtonAtTop,
|
||||
authorized)
|
||||
authorized,
|
||||
self.server.themeName)
|
||||
msg = msg.encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -7642,7 +7705,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.iconsAsButtons,
|
||||
self.server.rssIconAtTop,
|
||||
self.server.publishButtonAtTop,
|
||||
authorized)
|
||||
authorized,
|
||||
self.server.themeName)
|
||||
msg = msg.encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -7763,7 +7827,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.iconsAsButtons,
|
||||
self.server.rssIconAtTop,
|
||||
self.server.publishButtonAtTop,
|
||||
authorized)
|
||||
authorized,
|
||||
self.server.themeName)
|
||||
msg = msg.encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -7847,7 +7912,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.iconsAsButtons,
|
||||
self.server.rssIconAtTop,
|
||||
self.server.publishButtonAtTop,
|
||||
authorized)
|
||||
authorized, self.server.themeName)
|
||||
msg = msg.encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -7947,7 +8012,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.iconsAsButtons,
|
||||
self.server.rssIconAtTop,
|
||||
self.server.publishButtonAtTop,
|
||||
authorized)
|
||||
authorized,
|
||||
self.server.themeName)
|
||||
msg = msg.encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -8066,7 +8132,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.iconsAsButtons,
|
||||
self.server.rssIconAtTop,
|
||||
self.server.publishButtonAtTop,
|
||||
authorized)
|
||||
authorized,
|
||||
self.server.themeName)
|
||||
msg = msg.encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -8177,7 +8244,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.iconsAsButtons,
|
||||
self.server.rssIconAtTop,
|
||||
self.server.publishButtonAtTop,
|
||||
authorized)
|
||||
authorized,
|
||||
self.server.themeName)
|
||||
msg = msg.encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -8374,6 +8442,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.YTReplacementDomain,
|
||||
self.server.showPublishedDateOnly,
|
||||
self.server.newswire,
|
||||
self.server.themeName,
|
||||
self.server.dormantMonths,
|
||||
shares,
|
||||
pageNumber, sharesPerPage)
|
||||
|
@ -8466,6 +8535,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.YTReplacementDomain,
|
||||
self.server.showPublishedDateOnly,
|
||||
self.server.newswire,
|
||||
self.server.themeName,
|
||||
self.server.dormantMonths,
|
||||
following,
|
||||
pageNumber,
|
||||
|
@ -8558,6 +8628,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.YTReplacementDomain,
|
||||
self.server.showPublishedDateOnly,
|
||||
self.server.newswire,
|
||||
self.server.themeName,
|
||||
self.server.dormantMonths,
|
||||
followers,
|
||||
pageNumber,
|
||||
|
@ -8625,6 +8696,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.YTReplacementDomain,
|
||||
self.server.showPublishedDateOnly,
|
||||
self.server.newswire,
|
||||
self.server.themeName,
|
||||
self.server.dormantMonths,
|
||||
None, None).encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
|
@ -8870,9 +8942,9 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self._404()
|
||||
return True
|
||||
|
||||
def _columImage(self, side: str, callingDomain: str, path: str,
|
||||
baseDir: str, domain: str, port: int,
|
||||
GETstartTime, GETtimings: {}) -> bool:
|
||||
def _columnImage(self, side: str, callingDomain: str, path: str,
|
||||
baseDir: str, domain: str, port: int,
|
||||
GETstartTime, GETtimings: {}) -> bool:
|
||||
"""Shows an image at the top of the left/right column
|
||||
"""
|
||||
nickname = getNicknameFromActor(path)
|
||||
|
@ -8999,10 +9071,10 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self._404()
|
||||
return True
|
||||
|
||||
def _showAvatarOrBackground(self, callingDomain: str, path: str,
|
||||
baseDir: str, domain: str,
|
||||
GETstartTime, GETtimings: {}) -> bool:
|
||||
"""Shows an avatar or profile background image
|
||||
def _showAvatarOrBanner(self, callingDomain: str, path: str,
|
||||
baseDir: str, domain: str,
|
||||
GETstartTime, GETtimings: {}) -> bool:
|
||||
"""Shows an avatar or banner or profile background image
|
||||
"""
|
||||
if '/users/' in path:
|
||||
if self._pathIsImage(path):
|
||||
|
@ -9010,11 +9082,20 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
if '/' in avatarStr and '.temp.' not in path:
|
||||
avatarNickname = avatarStr.split('/')[0]
|
||||
avatarFile = avatarStr.split('/')[1]
|
||||
avatarFileExt = avatarFile.split('.')[-1]
|
||||
# remove any numbers, eg. avatar123.png becomes avatar.png
|
||||
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'):
|
||||
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 = \
|
||||
baseDir + '/accounts/' + \
|
||||
avatarNickname + '@' + domain + '/' + avatarFile
|
||||
|
@ -9138,7 +9219,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
nickname, domain,
|
||||
domainFull,
|
||||
self.server.defaultTimeline,
|
||||
self.server.newswire).encode('utf-8')
|
||||
self.server.newswire,
|
||||
self.server.themeName).encode('utf-8')
|
||||
if not msg:
|
||||
print('Error replying to ' + inReplyToUrl)
|
||||
self._404()
|
||||
|
@ -9167,7 +9249,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
path, domain,
|
||||
port,
|
||||
httpPrefix,
|
||||
self.server.defaultTimeline).encode('utf-8')
|
||||
self.server.defaultTimeline,
|
||||
self.server.themeName).encode('utf-8')
|
||||
if msg:
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -9181,7 +9264,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
def _editLinks(self, callingDomain: str, path: str,
|
||||
translate: {}, baseDir: str,
|
||||
httpPrefix: str, domain: str, port: int,
|
||||
cookie: str) -> bool:
|
||||
cookie: str, theme: str) -> bool:
|
||||
"""Show the links from the left column
|
||||
"""
|
||||
if '/users/' in path and path.endswith('/editlinks'):
|
||||
|
@ -9191,7 +9274,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
path, domain,
|
||||
port,
|
||||
httpPrefix,
|
||||
self.server.defaultTimeline).encode('utf-8')
|
||||
self.server.defaultTimeline,
|
||||
theme).encode('utf-8')
|
||||
if msg:
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -9215,7 +9299,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
path, domain,
|
||||
port,
|
||||
httpPrefix,
|
||||
self.server.defaultTimeline).encode('utf-8')
|
||||
self.server.defaultTimeline,
|
||||
self.server.themeName).encode('utf-8')
|
||||
if msg:
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
|
@ -9992,19 +10077,19 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
return
|
||||
|
||||
if self.path.endswith('/left_col_image.png'):
|
||||
if self._columImage('left', callingDomain, self.path,
|
||||
self.server.baseDir,
|
||||
self.server.domain,
|
||||
self.server.port,
|
||||
GETstartTime, GETtimings):
|
||||
if self._columnImage('left', callingDomain, self.path,
|
||||
self.server.baseDir,
|
||||
self.server.domain,
|
||||
self.server.port,
|
||||
GETstartTime, GETtimings):
|
||||
return
|
||||
|
||||
if self.path.endswith('/right_col_image.png'):
|
||||
if self._columImage('right', callingDomain, self.path,
|
||||
self.server.baseDir,
|
||||
self.server.domain,
|
||||
self.server.port,
|
||||
GETstartTime, GETtimings):
|
||||
if self._columnImage('right', callingDomain, self.path,
|
||||
self.server.baseDir,
|
||||
self.server.domain,
|
||||
self.server.port,
|
||||
GETstartTime, GETtimings):
|
||||
return
|
||||
|
||||
self._benchmarkGETtimings(GETstartTime, GETtimings,
|
||||
|
@ -10082,10 +10167,10 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
|
||||
# show avatar or background image
|
||||
# Note that this comes before the busy flag to avoid conflicts
|
||||
if self._showAvatarOrBackground(callingDomain, self.path,
|
||||
self.server.baseDir,
|
||||
self.server.domain,
|
||||
GETstartTime, GETtimings):
|
||||
if self._showAvatarOrBanner(callingDomain, self.path,
|
||||
self.server.baseDir,
|
||||
self.server.domain,
|
||||
GETstartTime, GETtimings):
|
||||
return
|
||||
|
||||
self._benchmarkGETtimings(GETstartTime, GETtimings,
|
||||
|
@ -10208,7 +10293,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
authorized,
|
||||
rssIconAtTop,
|
||||
iconsAsButtons,
|
||||
defaultTimeline).encode('utf-8')
|
||||
defaultTimeline,
|
||||
self.server.themeName).encode('utf-8')
|
||||
self._set_headers('text/html', len(msg),
|
||||
cookie, callingDomain)
|
||||
self._write(msg)
|
||||
|
@ -10239,7 +10325,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
authorized,
|
||||
self.server.rssIconAtTop,
|
||||
iconsAsButtons,
|
||||
defaultTimeline).encode('utf-8')
|
||||
defaultTimeline,
|
||||
self.server.themeName).encode('utf-8')
|
||||
self._set_headers('text/html', len(msg), cookie, callingDomain)
|
||||
self._write(msg)
|
||||
self.server.GETbusy = False
|
||||
|
@ -10307,7 +10394,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.translate,
|
||||
self.server.baseDir, self.path,
|
||||
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._write(msg)
|
||||
self.server.GETbusy = False
|
||||
|
@ -10321,7 +10409,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
msg = htmlSearchHashtagCategory(self.server.cssCache,
|
||||
self.server.translate,
|
||||
self.server.baseDir, self.path,
|
||||
self.server.domain)
|
||||
self.server.domain,
|
||||
self.server.themeName)
|
||||
if msg:
|
||||
msg = msg.encode('utf-8')
|
||||
self._set_headers('text/html', len(msg), cookie, callingDomain)
|
||||
|
@ -10813,7 +10902,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.httpPrefix,
|
||||
self.server.domain,
|
||||
self.server.port,
|
||||
cookie):
|
||||
cookie,
|
||||
self.server.themeName):
|
||||
return
|
||||
|
||||
# edit newswire from the right column of the timeline
|
||||
|
@ -11643,7 +11733,8 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
fields['subject'],
|
||||
fields['message'],
|
||||
filename, attachmentMediaType,
|
||||
fields['imageDescription'])
|
||||
fields['imageDescription'],
|
||||
self.server.themeName)
|
||||
if messageJson:
|
||||
messageJson = messageJson.encode('utf-8')
|
||||
self._set_headers('text/html',
|
||||
|
@ -12087,7 +12178,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
if self.server.newPostThread.get(newPostThreadName):
|
||||
print('Waiting for previous new post thread to end')
|
||||
waitCtr = 0
|
||||
while (self.server.newPostThread[newPostThreadName].isAlive() and
|
||||
while (self.server.newPostThread[newPostThreadName].is_alive() and
|
||||
waitCtr < 8):
|
||||
time.sleep(1)
|
||||
waitCtr += 1
|
||||
|
@ -12980,12 +13071,13 @@ class EpicyonServer(ThreadingHTTPServer):
|
|||
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
|
||||
"""
|
||||
while True:
|
||||
time.sleep(1)
|
||||
removeDormantThreads(baseDir, sendThreads, debug)
|
||||
removeDormantThreads(baseDir, sendThreads, debug, timeoutMins)
|
||||
|
||||
|
||||
def runSharesExpire(versionNumber: str, baseDir: str) -> None:
|
||||
|
@ -13004,7 +13096,7 @@ def runPostsWatchdog(projectVersion: str, httpd) -> None:
|
|||
httpd.thrPostsQueue.start()
|
||||
while True:
|
||||
time.sleep(20)
|
||||
if not httpd.thrPostsQueue.isAlive():
|
||||
if not httpd.thrPostsQueue.is_alive():
|
||||
httpd.thrPostsQueue.kill()
|
||||
httpd.thrPostsQueue = postsQueueOriginal.clone(runPostsQueue)
|
||||
httpd.thrPostsQueue.start()
|
||||
|
@ -13019,7 +13111,7 @@ def runSharesExpireWatchdog(projectVersion: str, httpd) -> None:
|
|||
httpd.thrSharesExpire.start()
|
||||
while True:
|
||||
time.sleep(20)
|
||||
if not httpd.thrSharesExpire.isAlive():
|
||||
if not httpd.thrSharesExpire.is_alive():
|
||||
httpd.thrSharesExpire.kill()
|
||||
httpd.thrSharesExpire = sharesExpireOriginal.clone(runSharesExpire)
|
||||
httpd.thrSharesExpire.start()
|
||||
|
@ -13048,7 +13140,8 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
|
|||
break
|
||||
|
||||
|
||||
def runDaemon(dormantMonths: int,
|
||||
def runDaemon(sendThreadsTimeoutMins: int,
|
||||
dormantMonths: int,
|
||||
maxNewswirePosts: int,
|
||||
allowLocalNetworkAccess: bool,
|
||||
maxFeedItemSizeKb: int,
|
||||
|
@ -13343,10 +13436,14 @@ def runDaemon(dormantMonths: int,
|
|||
httpd.maxPostsInBox), daemon=True)
|
||||
httpd.thrCache.start()
|
||||
|
||||
# number of mins after which sending posts or updates will expire
|
||||
httpd.sendThreadsTimeoutMins = sendThreadsTimeoutMins
|
||||
|
||||
print('Creating posts queue')
|
||||
httpd.thrPostsQueue = \
|
||||
threadWithTrace(target=runPostsQueue,
|
||||
args=(baseDir, httpd.sendThreads, debug), daemon=True)
|
||||
args=(baseDir, httpd.sendThreads, debug,
|
||||
httpd.sendThreadsTimeoutMins), daemon=True)
|
||||
if not unitTest:
|
||||
httpd.thrPostsWatchdog = \
|
||||
threadWithTrace(target=runPostsWatchdog,
|
||||
|
|
|
@ -136,7 +136,7 @@ def sendDeleteViaServer(baseDir: str, session,
|
|||
fromPersonId, sharedInbox, avatarUrl,
|
||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
||||
projectVersion, httpPrefix, fromNickname,
|
||||
fromDomain, postToBox)
|
||||
fromDomain, postToBox, 53036)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
--options-bg-color: #282c37;
|
||||
--options-link-bg-color: transparent;
|
||||
--options-fg-color: #dddddd;
|
||||
--main-link-color: #999;
|
||||
--main-visited-color: #888;
|
||||
--options-main-link-color: #999;
|
||||
--options-main-visited-color: #888;
|
||||
--border-color: #505050;
|
||||
--font-size-header: 18px;
|
||||
--font-color-header: #ccc;
|
||||
|
@ -34,7 +34,7 @@
|
|||
--follow-text-entry-width: 90%;
|
||||
--focus-color: white;
|
||||
--petname-width-chars: 16ch;
|
||||
--main-link-color-hover: #bbb;
|
||||
--options-main-link-color-hover: #bbb;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
@ -73,25 +73,25 @@ a, u {
|
|||
}
|
||||
|
||||
a:visited{
|
||||
color: var(--main-visited-color);
|
||||
color: var(--options-main-visited-color);
|
||||
background: var(--options-link-bg-color);
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: var(--main-link-color);
|
||||
color: var(--options-main-link-color);
|
||||
background: var(--options-link-bg-color);
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:link:hover {
|
||||
color: var(--main-link-color-hover);
|
||||
color: var(--options-main-link-color-hover);
|
||||
}
|
||||
|
||||
a:visited:hover {
|
||||
color: var(--main-link-color-hover);
|
||||
color: var(--options-main-link-color-hover);
|
||||
}
|
||||
|
||||
a:focus {
|
||||
|
@ -116,12 +116,12 @@ a:focus {
|
|||
|
||||
.imText {
|
||||
font-size: var(--font-size4);
|
||||
color: var(--main-link-color);
|
||||
color: var(--options-main-link-color);
|
||||
}
|
||||
|
||||
.pgp {
|
||||
font-size: var(--font-size5);
|
||||
color: var(--main-link-color);
|
||||
color: var(--options-main-link-color);
|
||||
background: var(--options-link-bg-color);
|
||||
}
|
||||
|
||||
|
|
|
@ -950,6 +950,14 @@ div.container {
|
|||
font-size: var(--font-size);
|
||||
color: var(--title-color);
|
||||
}
|
||||
.accountsTable {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
}
|
||||
.accountsTableCol {
|
||||
width: 20%;
|
||||
text-align: center;
|
||||
}
|
||||
.containerHeader {
|
||||
border: var(--border-width-header) solid var(--border-color);
|
||||
background-color: var(--header-bg-color);
|
||||
|
@ -1601,6 +1609,14 @@ div.container {
|
|||
font-size: var(--font-size-mobile);
|
||||
color: var(--title-color);
|
||||
}
|
||||
.accountsTable {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
}
|
||||
.accountsTableCol {
|
||||
width: 20%;
|
||||
text-align: center;
|
||||
}
|
||||
.containerHeader {
|
||||
border: var(--border-width-header) solid var(--border-color);
|
||||
background-color: var(--header-bg-color);
|
||||
|
|
13
epicyon.py
13
epicyon.py
|
@ -122,6 +122,11 @@ parser.add_argument('--dormantMonths',
|
|||
default=3,
|
||||
help='How many months does a followed account need to ' +
|
||||
'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',
|
||||
dest='maxNewswirePosts', type=int,
|
||||
default=20,
|
||||
|
@ -2035,6 +2040,11 @@ dormantMonths = \
|
|||
if dormantMonths is not None:
|
||||
args.dormantMonths = int(dormantMonths)
|
||||
|
||||
sendThreadsTimeoutMins = \
|
||||
getConfigParam(baseDir, 'sendThreadsTimeoutMins')
|
||||
if sendThreadsTimeoutMins is not None:
|
||||
args.sendThreadsTimeoutMins = int(sendThreadsTimeoutMins)
|
||||
|
||||
allowNewsFollowers = \
|
||||
getConfigParam(baseDir, 'allowNewsFollowers')
|
||||
if allowNewsFollowers is not None:
|
||||
|
@ -2083,7 +2093,8 @@ if setTheme(baseDir, themeName, domain, args.allowLocalNetworkAccess):
|
|||
print('Theme set to ' + themeName)
|
||||
|
||||
if __name__ == "__main__":
|
||||
runDaemon(args.dormantMonths,
|
||||
runDaemon(args.sendThreadsTimeoutMins,
|
||||
args.dormantMonths,
|
||||
args.maxNewswirePosts,
|
||||
args.allowLocalNetworkAccess,
|
||||
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
|
||||
|
||||
|
||||
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,
|
||||
words: str) -> bool:
|
||||
"""Removes a word filter
|
||||
|
@ -43,6 +61,24 @@ def removeFilter(baseDir: str, nickname: str, domain: str,
|
|||
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:
|
||||
"""Returns true if the given post content is a retweet or twitter crosspost
|
||||
"""
|
||||
|
@ -53,12 +89,45 @@ def isTwitterPost(content: str) -> bool:
|
|||
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:
|
||||
"""Should the given content be filtered out?
|
||||
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
|
||||
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
|
||||
removeTwitter = baseDir + '/accounts/' + \
|
||||
nickname + '@' + domain + '/.removeTwitter'
|
||||
|
@ -66,19 +135,6 @@ def isFiltered(baseDir: str, nickname: str, domain: str, content: str) -> bool:
|
|||
if isTwitterPost(content):
|
||||
return True
|
||||
|
||||
filtersFilename = baseDir + '/accounts/' + \
|
||||
accountFiltersFilename = baseDir + '/accounts/' + \
|
||||
nickname + '@' + domain + '/filters.txt'
|
||||
if os.path.isfile(filtersFilename):
|
||||
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
|
||||
return isFilteredBase(accountFiltersFilename, content)
|
||||
|
|
|
@ -995,7 +995,7 @@ def sendFollowRequestViaServer(baseDir: str, session,
|
|||
fromPersonId, sharedInbox, avatarUrl,
|
||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
||||
projectVersion, httpPrefix, fromNickname,
|
||||
fromDomain, postToBox)
|
||||
fromDomain, postToBox, 52025)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
@ -1086,7 +1086,8 @@ def sendUnfollowRequestViaServer(baseDir: str, session,
|
|||
wfRequest, personCache,
|
||||
projectVersion, httpPrefix,
|
||||
fromNickname,
|
||||
fromDomain, postToBox)
|
||||
fromDomain, postToBox,
|
||||
76536)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
|
14
inbox.py
14
inbox.py
|
@ -173,9 +173,19 @@ def inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int,
|
|||
avatarUrl = None
|
||||
if boxname != 'tlevents' and boxname != 'outbox':
|
||||
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,
|
||||
translate, pageNumber,
|
||||
baseDir, session, cachedWebfingers, personCache,
|
||||
baseDir, session, wfRequest, personCache,
|
||||
nickname, domain, port, postJsonObject,
|
||||
avatarUrl, True, allowDeletion,
|
||||
httpPrefix, __version__, boxname, None,
|
||||
|
@ -2456,7 +2466,7 @@ def runInboxQueueWatchdog(projectVersion: str, httpd) -> None:
|
|||
httpd.thrInboxQueue.start()
|
||||
while True:
|
||||
time.sleep(20)
|
||||
if not httpd.thrInboxQueue.isAlive() or httpd.restartInboxQueue:
|
||||
if not httpd.thrInboxQueue.is_alive() or httpd.restartInboxQueue:
|
||||
httpd.restartInboxQueueInProgress = True
|
||||
httpd.thrInboxQueue.kill()
|
||||
httpd.thrInboxQueue = inboxQueueOriginal.clone(runInboxQueue)
|
||||
|
|
5
like.py
5
like.py
|
@ -257,7 +257,7 @@ def sendLikeViaServer(baseDir: str, session,
|
|||
personCache,
|
||||
projectVersion, httpPrefix,
|
||||
fromNickname, fromDomain,
|
||||
postToBox)
|
||||
postToBox, 72873)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
@ -335,7 +335,8 @@ def sendUndoLikeViaServer(baseDir: str, session,
|
|||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache, projectVersion,
|
||||
httpPrefix, fromNickname,
|
||||
fromDomain, postToBox)
|
||||
fromDomain, postToBox,
|
||||
72625)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
|
|
@ -752,7 +752,7 @@ def runNewswireWatchdog(projectVersion: str, httpd) -> None:
|
|||
httpd.thrNewswireDaemon.start()
|
||||
while True:
|
||||
time.sleep(50)
|
||||
if not httpd.thrNewswireDaemon.isAlive():
|
||||
if not httpd.thrNewswireDaemon.is_alive():
|
||||
httpd.thrNewswireDaemon.kill()
|
||||
httpd.thrNewswireDaemon = \
|
||||
newswireOriginal.clone(runNewswireDaemon)
|
||||
|
|
|
@ -110,7 +110,7 @@ def addNewswireDictEntry(baseDir: str, domain: str,
|
|||
allText = title + ' ' + description
|
||||
|
||||
# check that none of the text is filtered against
|
||||
if isFiltered(baseDir, 'news', domain, allText):
|
||||
if isFiltered(baseDir, None, None, allText):
|
||||
return
|
||||
|
||||
if tags is None:
|
||||
|
|
|
@ -191,7 +191,13 @@ def getDefaultPersonContext() -> str:
|
|||
'fingerprintKey': {'@id': 'toot:fingerprintKey', '@type': '@id'},
|
||||
'messageFranking': 'toot:messageFranking',
|
||||
'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)
|
||||
|
||||
|
||||
def getUserUrl(wfRequest: {}) -> str:
|
||||
if wfRequest.get('links'):
|
||||
for link in wfRequest['links']:
|
||||
if link.get('type') and link.get('href'):
|
||||
if link['type'] == 'application/activity+json':
|
||||
if not ('/users/' in link['href'] or
|
||||
'/accounts/' in link['href'] or
|
||||
'/profile/' in link['href'] or
|
||||
'/channel/' in link['href']):
|
||||
print('Webfinger activity+json contains ' +
|
||||
'single user instance actor')
|
||||
return link['href']
|
||||
def getUserUrl(wfRequest: {}, sourceId=0) -> str:
|
||||
"""Gets the actor url from a webfinger request
|
||||
"""
|
||||
print('getUserUrl: ' + str(sourceId) + ' ' + str(wfRequest))
|
||||
if not wfRequest.get('links'):
|
||||
print('getUserUrl webfinger activity+json contains no links ' +
|
||||
str(sourceId) + ' ' + str(wfRequest))
|
||||
return None
|
||||
for link in wfRequest['links']:
|
||||
if not (link.get('type') and link.get('href')):
|
||||
continue
|
||||
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
|
||||
|
||||
|
||||
|
@ -198,13 +207,14 @@ def getPersonBox(baseDir: str, session, wfRequest: {},
|
|||
personCache: {},
|
||||
projectVersion: str, httpPrefix: 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'
|
||||
asHeader = {
|
||||
'Accept': 'application/activity+json; profile="' + profileStr + '"'
|
||||
}
|
||||
if not wfRequest.get('errors'):
|
||||
personUrl = getUserUrl(wfRequest)
|
||||
personUrl = getUserUrl(wfRequest, sourceId)
|
||||
else:
|
||||
if nickname == 'dev':
|
||||
# try single user instance
|
||||
|
@ -1174,7 +1184,7 @@ def postIsAddressedToFollowers(baseDir: str,
|
|||
postJsonObject: {}) -> bool:
|
||||
"""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'):
|
||||
return False
|
||||
|
@ -1192,7 +1202,7 @@ def postIsAddressedToFollowers(baseDir: str,
|
|||
if postJsonObject.get('cc'):
|
||||
ccList = postJsonObject['cc']
|
||||
|
||||
followersUrl = httpPrefix + '://' + domain + '/users/' + \
|
||||
followersUrl = httpPrefix + '://' + domainFull + '/users/' + \
|
||||
nickname + '/followers'
|
||||
|
||||
# does the followers url exist in 'to' or 'cc' lists?
|
||||
|
@ -1765,7 +1775,8 @@ def sendPost(projectVersion: str,
|
|||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache,
|
||||
projectVersion, httpPrefix,
|
||||
nickname, domain, postToBox)
|
||||
nickname, domain, postToBox,
|
||||
72533)
|
||||
|
||||
if not inboxUrl:
|
||||
return 3
|
||||
|
@ -1880,7 +1891,8 @@ def sendPostViaServer(projectVersion: str,
|
|||
personCache,
|
||||
projectVersion, httpPrefix,
|
||||
fromNickname,
|
||||
fromDomain, postToBox)
|
||||
fromDomain, postToBox,
|
||||
82796)
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
print('DEBUG: No ' + postToBox + ' was found for ' + handle)
|
||||
|
@ -2079,7 +2091,8 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str,
|
|||
displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache,
|
||||
projectVersion, httpPrefix,
|
||||
nickname, domain, postToBox)
|
||||
nickname, domain, postToBox,
|
||||
30873)
|
||||
|
||||
print("inboxUrl: " + str(inboxUrl))
|
||||
print("toPersonId: " + str(toPersonId))
|
||||
|
@ -2342,14 +2355,40 @@ def sendToNamedAddresses(session, baseDir: str,
|
|||
|
||||
def hasSharedInbox(session, httpPrefix: str, domain: str) -> bool:
|
||||
"""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,
|
||||
httpPrefix, {},
|
||||
None, __version__)
|
||||
if wfRequest:
|
||||
if isinstance(wfRequest, dict):
|
||||
if not wfRequest.get('errors'):
|
||||
return True
|
||||
tryHandles = [
|
||||
domain + '@' + domain,
|
||||
'inbox@' + domain
|
||||
]
|
||||
for handle in tryHandles:
|
||||
wfRequest = webfingerHandle(session, handle,
|
||||
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
|
||||
|
||||
|
||||
|
@ -2388,24 +2427,35 @@ def sendToFollowers(session, baseDir: str,
|
|||
clientToServer = False
|
||||
|
||||
# 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():
|
||||
print('Sending post to followers progress ' +
|
||||
str(int(sendingCtr * 100 / len(grouped.items()))) + '% ' +
|
||||
followerDomain)
|
||||
sendingCtr += 1
|
||||
|
||||
if debug:
|
||||
print('DEBUG: follower handles for ' + followerDomain)
|
||||
pprint(followerHandles)
|
||||
|
||||
# check that the follower's domain is active
|
||||
followerDomainUrl = httpPrefix + '://' + followerDomain
|
||||
if not siteIsActive(followerDomainUrl):
|
||||
print('Domain is inactive: ' + followerDomainUrl)
|
||||
print('Sending post to followers domain is inactive: ' +
|
||||
followerDomainUrl)
|
||||
continue
|
||||
print('Domain is active: ' + followerDomainUrl)
|
||||
print('Sending post to followers domain is active: ' +
|
||||
followerDomainUrl)
|
||||
|
||||
withSharedInbox = hasSharedInbox(session, httpPrefix, followerDomain)
|
||||
if debug:
|
||||
if withSharedInbox:
|
||||
print(followerDomain + ' has shared inbox')
|
||||
else:
|
||||
print(followerDomain + ' does not have a shared inbox')
|
||||
if not withSharedInbox:
|
||||
print('Sending post to followers, ' + followerDomain +
|
||||
' does not have a shared inbox')
|
||||
|
||||
toPort = port
|
||||
index = 0
|
||||
|
@ -2438,22 +2488,14 @@ def sendToFollowers(session, baseDir: str,
|
|||
toNickname = 'inbox'
|
||||
|
||||
if toNickname != 'inbox' and postJsonObject.get('type'):
|
||||
if postJsonObject['type'] == 'Update':
|
||||
if postJsonObject.get('object'):
|
||||
if isinstance(postJsonObject['object'], dict):
|
||||
if postJsonObject['object'].get('type'):
|
||||
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 sendingProfileUpdate(postJsonObject):
|
||||
print('Sending post to followers ' +
|
||||
'shared inbox of ' + toDomain)
|
||||
toNickname = 'inbox'
|
||||
|
||||
if debug:
|
||||
print('DEBUG: Sending from ' + nickname + '@' + domain +
|
||||
' to ' + toNickname + '@' + toDomain)
|
||||
print('Sending post to followers from ' +
|
||||
nickname + '@' + domain +
|
||||
' to ' + toNickname + '@' + toDomain)
|
||||
|
||||
sendSignedJson(postJsonObject, session, baseDir,
|
||||
nickname, fromDomain, port,
|
||||
|
@ -2465,19 +2507,17 @@ def sendToFollowers(session, baseDir: str,
|
|||
else:
|
||||
# send to individual followers without using a shared inbox
|
||||
for handle in followerHandles:
|
||||
if debug:
|
||||
print('DEBUG: Sending to ' + handle)
|
||||
print('Sending post to followers ' + handle)
|
||||
toNickname = handle.split('@')[0]
|
||||
|
||||
if debug:
|
||||
if postJsonObject['type'] != 'Update':
|
||||
print('DEBUG: Sending from ' +
|
||||
nickname + '@' + domain + ' to ' +
|
||||
toNickname + '@' + toDomain)
|
||||
else:
|
||||
print('DEBUG: Sending profile update from ' +
|
||||
nickname + '@' + domain + ' to ' +
|
||||
toNickname + '@' + toDomain)
|
||||
if postJsonObject['type'] != 'Update':
|
||||
print('Sending post to followers from ' +
|
||||
nickname + '@' + domain + ' to ' +
|
||||
toNickname + '@' + toDomain)
|
||||
else:
|
||||
print('Sending post to followers profile update from ' +
|
||||
nickname + '@' + domain + ' to ' +
|
||||
toNickname + '@' + toDomain)
|
||||
|
||||
sendSignedJson(postJsonObject, session, baseDir,
|
||||
nickname, fromDomain, port,
|
||||
|
@ -2492,6 +2532,10 @@ def sendToFollowers(session, baseDir: str,
|
|||
if debug:
|
||||
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,
|
||||
nickname: str,
|
||||
|
@ -3357,7 +3401,8 @@ def getPublicPostsOfPerson(baseDir: str, nickname: str, domain: str,
|
|||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache,
|
||||
projectVersion, httpPrefix,
|
||||
nickname, domain, 'outbox')
|
||||
nickname, domain, 'outbox',
|
||||
62524)
|
||||
maxMentions = 10
|
||||
maxEmoji = 10
|
||||
maxAttachments = 5
|
||||
|
@ -3398,7 +3443,8 @@ def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str,
|
|||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache,
|
||||
projectVersion, httpPrefix,
|
||||
nickname, domain, 'outbox')
|
||||
nickname, domain, 'outbox',
|
||||
92522)
|
||||
maxMentions = 99
|
||||
maxEmoji = 99
|
||||
maxAttachments = 5
|
||||
|
@ -3441,7 +3487,8 @@ def getPublicPostInfo(session, baseDir: str, nickname: str, domain: str,
|
|||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache,
|
||||
projectVersion, httpPrefix,
|
||||
nickname, domain, 'outbox')
|
||||
nickname, domain, 'outbox',
|
||||
13863)
|
||||
maxMentions = 99
|
||||
maxEmoji = 99
|
||||
maxAttachments = 5
|
||||
|
@ -3956,7 +4003,7 @@ def sendBlockViaServer(baseDir: str, session,
|
|||
displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache,
|
||||
projectVersion, httpPrefix, fromNickname,
|
||||
fromDomain, postToBox)
|
||||
fromDomain, postToBox, 72652)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
@ -4038,7 +4085,7 @@ def sendUndoBlockViaServer(baseDir: str, session,
|
|||
fromPersonId, sharedInbox, avatarUrl,
|
||||
displayName) = getPersonBox(baseDir, session, wfRequest, personCache,
|
||||
projectVersion, httpPrefix, fromNickname,
|
||||
fromDomain, postToBox)
|
||||
fromDomain, postToBox, 53892)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
|
3
roles.py
3
roles.py
|
@ -316,7 +316,8 @@ def sendRoleViaServer(baseDir: str, session,
|
|||
wfRequest, personCache,
|
||||
projectVersion, httpPrefix,
|
||||
delegatorNickname,
|
||||
delegatorDomain, postToBox)
|
||||
delegatorDomain, postToBox,
|
||||
765672)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
|
|
@ -158,7 +158,7 @@ def runPostScheduleWatchdog(projectVersion: str, httpd) -> None:
|
|||
httpd.thrPostSchedule.start()
|
||||
while True:
|
||||
time.sleep(20)
|
||||
if not httpd.thrPostSchedule.isAlive():
|
||||
if not httpd.thrPostSchedule.is_alive():
|
||||
httpd.thrPostSchedule.kill()
|
||||
httpd.thrPostSchedule = \
|
||||
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') -> {}:
|
||||
if not isinstance(url, str):
|
||||
print('url: ' + str(url))
|
||||
print('ERROR: getJson url should be a string')
|
||||
print('ERROR: getJson failed, url should be a string')
|
||||
return None
|
||||
sessionParams = {}
|
||||
sessionHeaders = {}
|
||||
|
@ -71,23 +71,23 @@ def getJson(session, url: str, headers: {}, params: {},
|
|||
sessionHeaders['User-Agent'] += \
|
||||
'; +' + httpPrefix + '://' + domain + '/'
|
||||
if not session:
|
||||
print('WARN: no session specified for getJson')
|
||||
print('WARN: getJson failed, no session specified for getJson')
|
||||
try:
|
||||
result = session.get(url, headers=sessionHeaders, params=sessionParams)
|
||||
return result.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
print('ERROR: getJson failed\nurl: ' + str(url) + '\n' +
|
||||
'headers: ' + str(sessionHeaders) + '\n' +
|
||||
'params: ' + str(sessionParams) + '\n')
|
||||
print('ERROR: getJson failed\nurl: ' + str(url) + ' ' +
|
||||
'headers: ' + str(sessionHeaders) + ' ' +
|
||||
'params: ' + str(sessionParams))
|
||||
print(e)
|
||||
except ValueError as e:
|
||||
print('ERROR: getJson failed\nurl: ' + str(url) + '\n' +
|
||||
'headers: ' + str(sessionHeaders) + '\n' +
|
||||
'params: ' + str(sessionParams) + '\n')
|
||||
print('ERROR: getJson failed\nurl: ' + str(url) + ' ' +
|
||||
'headers: ' + str(sessionHeaders) + ' ' +
|
||||
'params: ' + str(sessionParams) + ' ')
|
||||
print(e)
|
||||
except SocketError as e:
|
||||
if e.errno == errno.ECONNRESET:
|
||||
print('WARN: connection was reset during getJson')
|
||||
print('WARN: getJson failed, connection was reset during getJson')
|
||||
print(e)
|
||||
return None
|
||||
|
||||
|
|
|
@ -376,7 +376,8 @@ def sendShareViaServer(baseDir, session,
|
|||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache, projectVersion,
|
||||
httpPrefix, fromNickname,
|
||||
fromDomain, postToBox)
|
||||
fromDomain, postToBox,
|
||||
83653)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
@ -474,7 +475,8 @@ def sendUndoShareViaServer(baseDir: str, session,
|
|||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache, projectVersion,
|
||||
httpPrefix, fromNickname,
|
||||
fromDomain, postToBox)
|
||||
fromDomain, postToBox,
|
||||
12663)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
|
|
@ -152,7 +152,7 @@ def sendSkillViaServer(baseDir: str, session, nickname: str, password: str,
|
|||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache, projectVersion,
|
||||
httpPrefix, nickname, domain,
|
||||
postToBox)
|
||||
postToBox, 86725)
|
||||
|
||||
if not inboxUrl:
|
||||
if debug:
|
||||
|
|
|
@ -65,7 +65,8 @@ def instancesGraph(baseDir: str, handles: str,
|
|||
avatarUrl, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache,
|
||||
projectVersion, httpPrefix,
|
||||
nickname, domain, 'outbox')
|
||||
nickname, domain, 'outbox',
|
||||
27261)
|
||||
postDomains = \
|
||||
getPostDomains(session, personUrl, 64, maxMentions, maxEmoji,
|
||||
maxAttachments, federationList,
|
||||
|
|
52
tests.py
52
tests.py
|
@ -236,11 +236,11 @@ def testThreads():
|
|||
args=('test',),
|
||||
daemon=True)
|
||||
thr.start()
|
||||
assert thr.isAlive() is True
|
||||
assert thr.is_alive() is True
|
||||
time.sleep(1)
|
||||
thr.kill()
|
||||
thr.join()
|
||||
assert thr.isAlive() is False
|
||||
assert thr.is_alive() is False
|
||||
|
||||
|
||||
def createServerAlice(path: str, domain: str, port: int,
|
||||
|
@ -296,8 +296,10 @@ def createServerAlice(path: str, domain: str, port: int,
|
|||
allowLocalNetworkAccess = True
|
||||
maxNewswirePosts = 20
|
||||
dormantMonths = 3
|
||||
sendThreadsTimeoutMins = 30
|
||||
print('Server running: Alice')
|
||||
runDaemon(dormantMonths, maxNewswirePosts,
|
||||
runDaemon(sendThreadsTimeoutMins,
|
||||
dormantMonths, maxNewswirePosts,
|
||||
allowLocalNetworkAccess,
|
||||
2048, False, True, False, False, True, 10, False,
|
||||
0, 100, 1024, 5, False,
|
||||
|
@ -366,8 +368,10 @@ def createServerBob(path: str, domain: str, port: int,
|
|||
allowLocalNetworkAccess = True
|
||||
maxNewswirePosts = 20
|
||||
dormantMonths = 3
|
||||
sendThreadsTimeoutMins = 30
|
||||
print('Server running: Bob')
|
||||
runDaemon(dormantMonths, maxNewswirePosts,
|
||||
runDaemon(sendThreadsTimeoutMins,
|
||||
dormantMonths, maxNewswirePosts,
|
||||
allowLocalNetworkAccess,
|
||||
2048, False, True, False, False, True, 10, False,
|
||||
0, 100, 1024, 5, False, 0,
|
||||
|
@ -410,8 +414,10 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
|
|||
allowLocalNetworkAccess = True
|
||||
maxNewswirePosts = 20
|
||||
dormantMonths = 3
|
||||
sendThreadsTimeoutMins = 30
|
||||
print('Server running: Eve')
|
||||
runDaemon(dormantMonths, maxNewswirePosts,
|
||||
runDaemon(sendThreadsTimeoutMins,
|
||||
dormantMonths, maxNewswirePosts,
|
||||
allowLocalNetworkAccess,
|
||||
2048, False, True, False, False, True, 10, False,
|
||||
0, 100, 1024, 5, False, 0,
|
||||
|
@ -456,7 +462,7 @@ def testPostMessageBetweenServers():
|
|||
|
||||
global thrAlice
|
||||
if thrAlice:
|
||||
while thrAlice.isAlive():
|
||||
while thrAlice.is_alive():
|
||||
thrAlice.stop()
|
||||
time.sleep(1)
|
||||
thrAlice.kill()
|
||||
|
@ -470,7 +476,7 @@ def testPostMessageBetweenServers():
|
|||
|
||||
global thrBob
|
||||
if thrBob:
|
||||
while thrBob.isAlive():
|
||||
while thrBob.is_alive():
|
||||
thrBob.stop()
|
||||
time.sleep(1)
|
||||
thrBob.kill()
|
||||
|
@ -484,8 +490,8 @@ def testPostMessageBetweenServers():
|
|||
|
||||
thrAlice.start()
|
||||
thrBob.start()
|
||||
assert thrAlice.isAlive() is True
|
||||
assert thrBob.isAlive() is True
|
||||
assert thrAlice.is_alive() is True
|
||||
assert thrBob.is_alive() is True
|
||||
|
||||
# wait for both servers to be running
|
||||
while not (testServerAliceRunning and testServerBobRunning):
|
||||
|
@ -684,11 +690,11 @@ def testPostMessageBetweenServers():
|
|||
# stop the servers
|
||||
thrAlice.kill()
|
||||
thrAlice.join()
|
||||
assert thrAlice.isAlive() is False
|
||||
assert thrAlice.is_alive() is False
|
||||
|
||||
thrBob.kill()
|
||||
thrBob.join()
|
||||
assert thrBob.isAlive() is False
|
||||
assert thrBob.is_alive() is False
|
||||
|
||||
os.chdir(baseDir)
|
||||
shutil.rmtree(aliceDir)
|
||||
|
@ -727,7 +733,7 @@ def testFollowBetweenServers():
|
|||
|
||||
global thrAlice
|
||||
if thrAlice:
|
||||
while thrAlice.isAlive():
|
||||
while thrAlice.is_alive():
|
||||
thrAlice.stop()
|
||||
time.sleep(1)
|
||||
thrAlice.kill()
|
||||
|
@ -741,7 +747,7 @@ def testFollowBetweenServers():
|
|||
|
||||
global thrBob
|
||||
if thrBob:
|
||||
while thrBob.isAlive():
|
||||
while thrBob.is_alive():
|
||||
thrBob.stop()
|
||||
time.sleep(1)
|
||||
thrBob.kill()
|
||||
|
@ -755,8 +761,8 @@ def testFollowBetweenServers():
|
|||
|
||||
thrAlice.start()
|
||||
thrBob.start()
|
||||
assert thrAlice.isAlive() is True
|
||||
assert thrBob.isAlive() is True
|
||||
assert thrAlice.is_alive() is True
|
||||
assert thrBob.is_alive() is True
|
||||
|
||||
# wait for all servers to be running
|
||||
ctr = 0
|
||||
|
@ -856,11 +862,11 @@ def testFollowBetweenServers():
|
|||
# stop the servers
|
||||
thrAlice.kill()
|
||||
thrAlice.join()
|
||||
assert thrAlice.isAlive() is False
|
||||
assert thrAlice.is_alive() is False
|
||||
|
||||
thrBob.kill()
|
||||
thrBob.join()
|
||||
assert thrBob.isAlive() is False
|
||||
assert thrBob.is_alive() is False
|
||||
|
||||
# queue item removed
|
||||
time.sleep(4)
|
||||
|
@ -1284,7 +1290,7 @@ def testClientToServer():
|
|||
|
||||
global thrAlice
|
||||
if thrAlice:
|
||||
while thrAlice.isAlive():
|
||||
while thrAlice.is_alive():
|
||||
thrAlice.stop()
|
||||
time.sleep(1)
|
||||
thrAlice.kill()
|
||||
|
@ -1298,7 +1304,7 @@ def testClientToServer():
|
|||
|
||||
global thrBob
|
||||
if thrBob:
|
||||
while thrBob.isAlive():
|
||||
while thrBob.is_alive():
|
||||
thrBob.stop()
|
||||
time.sleep(1)
|
||||
thrBob.kill()
|
||||
|
@ -1312,8 +1318,8 @@ def testClientToServer():
|
|||
|
||||
thrAlice.start()
|
||||
thrBob.start()
|
||||
assert thrAlice.isAlive() is True
|
||||
assert thrBob.isAlive() is True
|
||||
assert thrAlice.is_alive() is True
|
||||
assert thrBob.is_alive() is True
|
||||
|
||||
# wait for both servers to be running
|
||||
ctr = 0
|
||||
|
@ -1608,11 +1614,11 @@ def testClientToServer():
|
|||
# stop the servers
|
||||
thrAlice.kill()
|
||||
thrAlice.join()
|
||||
assert thrAlice.isAlive() is False
|
||||
assert thrAlice.is_alive() is False
|
||||
|
||||
thrBob.kill()
|
||||
thrBob.join()
|
||||
assert thrBob.isAlive() is False
|
||||
assert thrBob.is_alive() is False
|
||||
|
||||
os.chdir(baseDir)
|
||||
# shutil.rmtree(aliceDir)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"today-circle": "#03a494",
|
||||
"options-main-link-color-hover": "white",
|
||||
"main-link-color-hover": "blue",
|
||||
"font-size-newswire-mobile": "32px",
|
||||
"newswire-date-color": "#00a594",
|
||||
|
@ -58,8 +59,10 @@
|
|||
"border-width": "1px",
|
||||
"border-width-header": "1px",
|
||||
"main-link-color": "darkblue",
|
||||
"options-main-link-color": "lightgrey",
|
||||
"title-color": "#2a2c37",
|
||||
"main-visited-color": "#232c37",
|
||||
"options-main-visited-color": "#ccc",
|
||||
"text-entry-foreground": "#111",
|
||||
"text-entry-background": "white",
|
||||
"font-color-header": "black",
|
||||
|
|
|
@ -24,8 +24,11 @@
|
|||
"border-color": "#035103",
|
||||
"main-link-color": "#2fff2f",
|
||||
"main-link-color-hover": "#afff2f",
|
||||
"options-main-link-color": "#2fff2f",
|
||||
"options-main-link-color-hover": "#afff2f",
|
||||
"title-color": "#2fff2f",
|
||||
"main-visited-color": "#3c8234",
|
||||
"options-main-visited-color": "#3c8234",
|
||||
"button-selected": "#063200",
|
||||
"button-background-hover": "#a62200",
|
||||
"button-text-hover": "#00ff00",
|
||||
|
|
|
@ -29,8 +29,11 @@
|
|||
"link-bg-color": "#383335",
|
||||
"main-link-color": "white",
|
||||
"main-link-color-hover": "#ddd",
|
||||
"options-main-link-color": "white",
|
||||
"options-main-link-color-hover": "#ddd",
|
||||
"title-color": "white",
|
||||
"main-visited-color": "#e1c4bc",
|
||||
"options-main-visited-color": "#e1c4bc",
|
||||
"main-fg-color": "white",
|
||||
"options-fg-color": "white",
|
||||
"column-left-fg-color": "white",
|
||||
|
|
|
@ -40,7 +40,10 @@
|
|||
"link-bg-color": "black",
|
||||
"main-link-color": "#ff9900",
|
||||
"main-link-color-hover": "#d09338",
|
||||
"options-main-link-color": "#ff9900",
|
||||
"options-main-link-color-hover": "#d09338",
|
||||
"main-visited-color": "#ffb900",
|
||||
"options-main-visited-color": "#ffb900",
|
||||
"main-fg-color": "white",
|
||||
"login-fg-color": "white",
|
||||
"options-fg-color": "white",
|
||||
|
|
|
@ -105,8 +105,11 @@
|
|||
"border-color": "#c0cdd9",
|
||||
"main-link-color": "#25408f",
|
||||
"main-link-color-hover": "#10408f",
|
||||
"options-main-link-color": "#25408f",
|
||||
"options-main-link-color-hover": "#10408f",
|
||||
"title-color": "#2a2c37",
|
||||
"main-visited-color": "#25408f",
|
||||
"options-main-visited-color": "#25408f",
|
||||
"text-entry-foreground": "#111",
|
||||
"text-entry-background": "white",
|
||||
"font-color-header": "black",
|
||||
|
|
|
@ -30,8 +30,11 @@
|
|||
"border-width-header": "5px",
|
||||
"main-link-color": "#9fb42b",
|
||||
"main-link-color-hover": "#cfb42b",
|
||||
"options-main-link-color": "#9fb42b",
|
||||
"options-main-link-color-hover": "#cfb42b",
|
||||
"title-color": "#9fb42b",
|
||||
"main-visited-color": "#9fb42b",
|
||||
"options-main-visited-color": "#9fb42b",
|
||||
"button-selected": "black",
|
||||
"button-highlighted": "green",
|
||||
"button-background-hover": "#a3390d",
|
||||
|
|
|
@ -39,8 +39,11 @@
|
|||
"border-color": "#c0cdd9",
|
||||
"main-link-color": "#2a2c37",
|
||||
"main-link-color-hover": "#aa2c37",
|
||||
"options-main-link-color": "#2a2c37",
|
||||
"options-main-link-color-hover": "#aa2c37",
|
||||
"title-color": "#2a2c37",
|
||||
"main-visited-color": "#232c37",
|
||||
"options-main-visited-color": "#232c37",
|
||||
"text-entry-foreground": "#111",
|
||||
"text-entry-background": "white",
|
||||
"font-color-header": "black",
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"rss-icon-at-top": "True",
|
||||
"publish-button-at-top": "False",
|
||||
"main-visited-color": "#0481f5",
|
||||
"options-main-visited-color": "#0481f5",
|
||||
"post-separator-margin-top": "9%",
|
||||
"post-separator-margin-bottom": "9%",
|
||||
"post-separator-width": "80%",
|
||||
|
@ -30,6 +31,8 @@
|
|||
"link-bg-color": "#0f0d10",
|
||||
"main-link-color": "#6481f5",
|
||||
"main-link-color-hover": "#d09338",
|
||||
"options-main-link-color": "#6481f5",
|
||||
"options-main-link-color-hover": "#d09338",
|
||||
"main-fg-color": "#0481f5",
|
||||
"login-fg-color": "#0481f5",
|
||||
"options-fg-color": "#0481f5",
|
||||
|
|
|
@ -30,8 +30,11 @@
|
|||
"border-color": "#3f2145",
|
||||
"main-link-color": "#ff42a0",
|
||||
"main-link-color-hover": "white",
|
||||
"options-main-link-color": "#ff42a0",
|
||||
"options-main-link-color-hover": "white",
|
||||
"title-color": "white",
|
||||
"main-visited-color": "#f93bb0",
|
||||
"options-main-visited-color": "#f93bb0",
|
||||
"button-selected": "#c042a0",
|
||||
"button-background-hover": "#af42a0",
|
||||
"button-text-hover": "#f98bb0",
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"rss-icon-at-top": "True",
|
||||
"publish-button-at-top": "False",
|
||||
"main-visited-color": "#46eed5",
|
||||
"options-main-visited-color": "#46eed5",
|
||||
"post-separator-margin-top": "9%",
|
||||
"post-separator-margin-bottom": "9%",
|
||||
"post-separator-width": "80%",
|
||||
|
@ -51,6 +52,8 @@
|
|||
"link-bg-color": "#0f0d10",
|
||||
"main-link-color": "#05b9ec",
|
||||
"main-link-color-hover": "#46eed5",
|
||||
"options-main-link-color": "#05b9ec",
|
||||
"options-main-link-color-hover": "#46eed5",
|
||||
"main-fg-color": "white",
|
||||
"login-fg-color": "white",
|
||||
"options-fg-color": "white",
|
||||
|
|
|
@ -47,8 +47,11 @@
|
|||
"border-color": "#c0cdd9",
|
||||
"main-link-color": "#2a2c37",
|
||||
"main-link-color-hover": "#aa2c37",
|
||||
"options-main-link-color": "#2a2c37",
|
||||
"options-main-link-color-hover": "#aa2c37",
|
||||
"title-color": "#2a2c37",
|
||||
"main-visited-color": "#232c37",
|
||||
"options-main-visited-color": "#232c37",
|
||||
"text-entry-foreground": "#111",
|
||||
"text-entry-background": "white",
|
||||
"font-color-header": "black",
|
||||
|
|
|
@ -28,8 +28,11 @@
|
|||
"link-bg-color": "#0f0d10",
|
||||
"main-link-color": "#ffc4bc",
|
||||
"main-link-color-hover": "white",
|
||||
"options-main-link-color": "#ffc4bc",
|
||||
"options-main-link-color-hover": "white",
|
||||
"title-color": "#ffc4bc",
|
||||
"main-visited-color": "#e1c4bc",
|
||||
"options-main-visited-color": "#e1c4bc",
|
||||
"main-fg-color": "#ffc4bc",
|
||||
"login-fg-color": "#ffc4bc",
|
||||
"options-fg-color": "#ffc4bc",
|
||||
|
|
|
@ -24,8 +24,11 @@
|
|||
"border-width-header": "7px",
|
||||
"main-link-color": "#dddddd",
|
||||
"main-link-color-hover": "white",
|
||||
"options-main-link-color": "#dddddd",
|
||||
"options-main-link-color-hover": "white",
|
||||
"title-color": "#dddddd",
|
||||
"main-visited-color": "#dddddd",
|
||||
"options-main-visited-color": "#dddddd",
|
||||
"button-background-hover": "#a63b35",
|
||||
"publish-button-background": "#463b35",
|
||||
"button-background": "#463b35",
|
||||
|
|
|
@ -69,12 +69,14 @@ class threadWithTrace(threading.Thread):
|
|||
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
|
||||
"""
|
||||
if len(threadsList) == 0:
|
||||
return
|
||||
|
||||
timeoutSecs = int(timeoutMins * 60)
|
||||
dormantThreads = []
|
||||
currTime = datetime.datetime.utcnow()
|
||||
changed = False
|
||||
|
@ -92,13 +94,13 @@ def removeDormantThreads(baseDir: str, threadsList: [], debug: bool) -> None:
|
|||
'thread is not alive ten seconds after start')
|
||||
removeThread = True
|
||||
# timeout for started threads
|
||||
if (currTime - th.startTime).total_seconds() > 600:
|
||||
if (currTime - th.startTime).total_seconds() > timeoutSecs:
|
||||
if debug:
|
||||
print('DEBUG: started thread timed out')
|
||||
removeThread = True
|
||||
else:
|
||||
# timeout for threads which havn't been started
|
||||
if (currTime - th.startTime).total_seconds() > 600:
|
||||
if (currTime - th.startTime).total_seconds() > timeoutSecs:
|
||||
if debug:
|
||||
print('DEBUG: unstarted thread timed out')
|
||||
removeThread = True
|
||||
|
|
|
@ -342,5 +342,10 @@
|
|||
"Ask about a shared item.": "اسأل عن عنصر مشترك.",
|
||||
"Account Information": "معلومات الحساب",
|
||||
"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.",
|
||||
"Account Information": "Informació del compte",
|
||||
"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.",
|
||||
"Account Information": "Gwybodaeth Gyfrif",
|
||||
"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.",
|
||||
"Account Information": "Kontoinformationen",
|
||||
"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.",
|
||||
"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"
|
||||
"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.",
|
||||
"Account Information": "Información de la cuenta",
|
||||
"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é.",
|
||||
"Account Information": "Information sur le compte",
|
||||
"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.",
|
||||
"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",
|
||||
"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.": "एक साझा आइटम के बारे में पूछें।",
|
||||
"Account Information": "खाते की जानकारी",
|
||||
"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.",
|
||||
"Account Information": "Informazioni account",
|
||||
"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.": "共有アイテムについて質問します。",
|
||||
"Account Information": "口座情報",
|
||||
"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.",
|
||||
"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"
|
||||
"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.",
|
||||
"Account Information": "Informação da conta",
|
||||
"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.": "Спросите об общем элементе.",
|
||||
"Account Information": "Информация об аккаунте",
|
||||
"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.": "询问共享项目。",
|
||||
"Account Information": "帐户信息",
|
||||
"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"
|
||||
|
||||
import os
|
||||
from shutil import copyfile
|
||||
from utils import getConfigParam
|
||||
from utils import getNicknameFromActor
|
||||
from utils import isEditor
|
||||
from webapp_utils import sharesTimelineJson
|
||||
from webapp_utils import htmlPostSeparator
|
||||
from webapp_utils import getLeftImageFile
|
||||
from webapp_utils import getImageFile
|
||||
from webapp_utils import headerButtonsFrontScreen
|
||||
from webapp_utils import htmlHeaderWithExternalStyle
|
||||
from webapp_utils import htmlFooter
|
||||
|
@ -70,7 +68,7 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
|
|||
editor: bool,
|
||||
showBackButton: bool, timelinePath: str,
|
||||
rssIconAtTop: bool, showHeaderImage: bool,
|
||||
frontPage: bool) -> str:
|
||||
frontPage: bool, theme: str) -> str:
|
||||
"""Returns html content for the left column
|
||||
"""
|
||||
htmlStr = ''
|
||||
|
@ -83,23 +81,7 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
|
|||
editImageClass = ''
|
||||
if showHeaderImage:
|
||||
leftImageFile, leftColumnImageFilename = \
|
||||
getLeftImageFile(baseDir, nickname, domain)
|
||||
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
|
||||
getLeftImageFile(baseDir, nickname, domain, theme)
|
||||
|
||||
# show the image at the top of the column
|
||||
editImageClass = 'leftColEdit'
|
||||
|
@ -255,7 +237,8 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
|||
timelinePath: str, authorized: bool,
|
||||
rssIconAtTop: bool,
|
||||
iconsAsButtons: bool,
|
||||
defaultTimeline: str) -> str:
|
||||
defaultTimeline: str,
|
||||
theme: str) -> str:
|
||||
"""Show the left column links within mobile view
|
||||
"""
|
||||
htmlStr = ''
|
||||
|
@ -276,7 +259,8 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
|||
domain = domain.split(':')[0]
|
||||
|
||||
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
|
||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
||||
bannerFile, bannerFilename = \
|
||||
getBannerFile(baseDir, nickname, domain, theme)
|
||||
htmlStr += \
|
||||
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
|
||||
'<img loading="lazy" class="timeline-banner" ' + \
|
||||
|
@ -293,7 +277,8 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
|||
httpPrefix, translate,
|
||||
editor,
|
||||
False, timelinePath,
|
||||
rssIconAtTop, False, False)
|
||||
rssIconAtTop, False, False,
|
||||
theme)
|
||||
else:
|
||||
if editor:
|
||||
htmlStr += '<br><br><br>\n'
|
||||
|
@ -310,7 +295,7 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
|||
|
||||
def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||
domain: str, port: int, httpPrefix: str,
|
||||
defaultTimeline: str) -> str:
|
||||
defaultTimeline: str, theme: str) -> str:
|
||||
"""Shows the edit links screen
|
||||
"""
|
||||
if '/users/' not in path:
|
||||
|
@ -331,7 +316,8 @@ def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
|
|||
cssFilename = baseDir + '/links.css'
|
||||
|
||||
# filename of the banner shown at the top
|
||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
||||
bannerFile, bannerFilename = \
|
||||
getBannerFile(baseDir, nickname, domain, theme)
|
||||
|
||||
editLinksForm = htmlHeaderWithExternalStyle(cssFilename)
|
||||
|
||||
|
|
|
@ -8,18 +8,15 @@ __status__ = "Production"
|
|||
|
||||
import os
|
||||
from datetime import datetime
|
||||
from shutil import copyfile
|
||||
from content import removeLongWords
|
||||
from utils import removeHtml
|
||||
from utils import locatePost
|
||||
from utils import loadJson
|
||||
from utils import getConfigParam
|
||||
from utils import votesOnNewswireItem
|
||||
from utils import getNicknameFromActor
|
||||
from utils import isEditor
|
||||
from posts import isModerator
|
||||
from webapp_utils import getRightImageFile
|
||||
from webapp_utils import getImageFile
|
||||
from webapp_utils import htmlHeaderWithExternalStyle
|
||||
from webapp_utils import htmlFooter
|
||||
from webapp_utils import getBannerFile
|
||||
|
@ -51,7 +48,8 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
|
|||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool,
|
||||
showHeaderImage: bool) -> str:
|
||||
showHeaderImage: bool,
|
||||
theme: str) -> str:
|
||||
"""Returns html content for the right column
|
||||
"""
|
||||
htmlStr = ''
|
||||
|
@ -84,23 +82,7 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
|
|||
editImageClass = ''
|
||||
if showHeaderImage:
|
||||
rightImageFile, rightColumnImageFilename = \
|
||||
getRightImageFile(baseDir, nickname, domain)
|
||||
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
|
||||
getRightImageFile(baseDir, nickname, domain, theme)
|
||||
|
||||
# show the image at the top of the column
|
||||
editImageClass = 'rightColEdit'
|
||||
|
@ -297,7 +279,8 @@ def htmlCitations(baseDir: str, nickname: str, domain: str,
|
|||
blogTitle: str, blogContent: str,
|
||||
blogImageFilename: str,
|
||||
blogImageAttachmentMediaType: str,
|
||||
blogImageDescription: str) -> str:
|
||||
blogImageDescription: str,
|
||||
theme: str) -> str:
|
||||
"""Show the citations screen when creating a blog
|
||||
"""
|
||||
htmlStr = ''
|
||||
|
@ -329,7 +312,8 @@ def htmlCitations(baseDir: str, nickname: str, domain: str,
|
|||
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
|
||||
|
||||
# top banner
|
||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
||||
bannerFile, bannerFilename = \
|
||||
getBannerFile(baseDir, nickname, domain, theme)
|
||||
htmlStr += \
|
||||
'<a href="/users/' + nickname + '/newblog" title="' + \
|
||||
translate['Go Back'] + '" alt="' + \
|
||||
|
@ -412,7 +396,8 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str,
|
|||
authorized: bool,
|
||||
rssIconAtTop: bool,
|
||||
iconsAsButtons: bool,
|
||||
defaultTimeline: str) -> str:
|
||||
defaultTimeline: str,
|
||||
theme: str) -> str:
|
||||
"""Shows the mobile version of the newswire right column
|
||||
"""
|
||||
htmlStr = ''
|
||||
|
@ -436,7 +421,8 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str,
|
|||
|
||||
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
|
||||
|
||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
||||
bannerFile, bannerFilename = \
|
||||
getBannerFile(baseDir, nickname, domain, theme)
|
||||
htmlStr += \
|
||||
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
|
||||
'<img loading="lazy" class="timeline-banner" ' + \
|
||||
|
@ -456,7 +442,7 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str,
|
|||
newswire, positiveVoting,
|
||||
False, timelinePath, showPublishButton,
|
||||
showPublishAsIcon, rssIconAtTop, False,
|
||||
authorized, False)
|
||||
authorized, False, theme)
|
||||
else:
|
||||
if editor:
|
||||
htmlStr += '<br><br><br>\n'
|
||||
|
@ -472,7 +458,7 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str,
|
|||
|
||||
def htmlEditNewswire(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||
domain: str, port: int, httpPrefix: str,
|
||||
defaultTimeline: str) -> str:
|
||||
defaultTimeline: str, theme: str) -> str:
|
||||
"""Shows the edit newswire screen
|
||||
"""
|
||||
if '/users/' not in path:
|
||||
|
@ -493,7 +479,8 @@ def htmlEditNewswire(cssCache: {}, translate: {}, baseDir: str, path: str,
|
|||
cssFilename = baseDir + '/links.css'
|
||||
|
||||
# filename of the banner shown at the top
|
||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
||||
bannerFile, bannerFilename = \
|
||||
getBannerFile(baseDir, nickname, domain, theme)
|
||||
|
||||
editNewswireForm = htmlHeaderWithExternalStyle(cssFilename)
|
||||
|
||||
|
|
|
@ -169,7 +169,8 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
|
|||
reportUrl: str, pageNumber: int,
|
||||
nickname: str, domain: str,
|
||||
domainFull: str,
|
||||
defaultTimeline: str, newswire: {}) -> str:
|
||||
defaultTimeline: str, newswire: {},
|
||||
theme: str) -> str:
|
||||
"""New post screen
|
||||
"""
|
||||
replyStr = ''
|
||||
|
@ -178,7 +179,8 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
|
|||
messageBoxHeight = 400
|
||||
|
||||
# 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('/newreport'):
|
||||
|
|
|
@ -83,7 +83,7 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
|||
session, wfRequest: {}, personCache: {},
|
||||
YTReplacementDomain: str,
|
||||
showPublishedDateOnly: bool,
|
||||
newswire: {}, extraJson=None,
|
||||
newswire: {}, theme: str, extraJson=None,
|
||||
pageNumber=None, maxItemsPerPage=None) -> str:
|
||||
"""Show the news instance front screen
|
||||
"""
|
||||
|
@ -104,7 +104,8 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
|||
iconsAsButtons)
|
||||
|
||||
# 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 = \
|
||||
'<img loading="lazy" class="timeline-banner" ' + \
|
||||
'src="/users/' + nickname + '/' + bannerFile + '" />\n'
|
||||
|
@ -124,7 +125,7 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
|||
getLeftColumnContent(baseDir, 'news', domainFull,
|
||||
httpPrefix, translate,
|
||||
False, False, None, rssIconAtTop, True,
|
||||
True)
|
||||
True, theme)
|
||||
profileHeaderStr += ' </td>\n'
|
||||
profileHeaderStr += ' <td valign="top" class="col-center">\n'
|
||||
|
||||
|
@ -136,7 +137,7 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
|||
|
||||
licenseStr = ''
|
||||
bannerFile, bannerFilename = \
|
||||
getBannerFile(baseDir, nickname, domain)
|
||||
getBannerFile(baseDir, nickname, domain, theme)
|
||||
profileStr += \
|
||||
htmlFrontScreenPosts(recentPostsCache, maxRecentPosts,
|
||||
translate,
|
||||
|
@ -155,7 +156,7 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
|||
httpPrefix, translate,
|
||||
False, False, newswire, False,
|
||||
False, None, False, False,
|
||||
False, True, authorized, True)
|
||||
False, True, authorized, True, theme)
|
||||
profileFooterStr += ' </td>\n'
|
||||
profileFooterStr += ' </tr>\n'
|
||||
profileFooterStr += ' </tbody>\n'
|
||||
|
|
|
@ -9,12 +9,10 @@ __status__ = "Production"
|
|||
import os
|
||||
from shutil import copyfile
|
||||
from datetime import datetime
|
||||
from utils import getConfigParam
|
||||
from utils import getNicknameFromActor
|
||||
from utils import getHashtagCategories
|
||||
from utils import getHashtagCategory
|
||||
from webapp_utils import getSearchBannerFile
|
||||
from webapp_utils import getImageFile
|
||||
from webapp_utils import getContentWarningButton
|
||||
from webapp_utils import htmlHeaderWithExternalStyle
|
||||
from webapp_utils import htmlFooter
|
||||
|
@ -231,7 +229,8 @@ def htmlHashTagSwarm(baseDir: str, actor: str, translate: {}) -> str:
|
|||
|
||||
|
||||
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
|
||||
"""
|
||||
actor = path.split('/category/')[0]
|
||||
|
@ -251,24 +250,7 @@ def htmlSearchHashtagCategory(cssCache: {}, translate: {},
|
|||
|
||||
# show a banner above the search box
|
||||
searchBannerFile, searchBannerFilename = \
|
||||
getSearchBannerFile(baseDir, searchNickname, domain)
|
||||
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
|
||||
getSearchBannerFile(baseDir, searchNickname, domain, theme)
|
||||
|
||||
if os.path.isfile(searchBannerFilename):
|
||||
htmlStr += '<a href="' + actor + '/search">\n'
|
||||
|
|
|
@ -7,10 +7,14 @@ __email__ = "bob@freedombone.net"
|
|||
__status__ = "Production"
|
||||
|
||||
import os
|
||||
from utils import isEditor
|
||||
from utils import loadJson
|
||||
from utils import getNicknameFromActor
|
||||
from utils import getDomainFromActor
|
||||
from posts import getPublicPostInfo
|
||||
from posts import isModerator
|
||||
from webapp_timeline import htmlTimeline
|
||||
# from webapp_utils import getPersonAvatarUrl
|
||||
from webapp_utils import getContentWarningButton
|
||||
from webapp_utils import htmlHeaderWithExternalStyle
|
||||
from webapp_utils import htmlFooter
|
||||
|
@ -152,11 +156,73 @@ def htmlModerationInfo(cssCache: {}, translate: {},
|
|||
'</a></h1></center><br>'
|
||||
|
||||
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'
|
||||
if os.path.isfile(suspendedFilename):
|
||||
with open(suspendedFilename, "r") as f:
|
||||
suspendedStr = f.read()
|
||||
infoForm += '<div class="container">'
|
||||
infoForm += '<div class="container">\n'
|
||||
infoForm += ' <br><b>' + \
|
||||
translate['Suspended accounts'] + '</b>'
|
||||
infoForm += ' <br>' + \
|
||||
|
@ -164,15 +230,15 @@ def htmlModerationInfo(cssCache: {}, translate: {},
|
|||
infoForm += \
|
||||
' <textarea id="message" ' + \
|
||||
'name="suspended" style="height:200px">' + \
|
||||
suspendedStr + '</textarea>'
|
||||
infoForm += '</div>'
|
||||
suspendedStr + '</textarea>\n'
|
||||
infoForm += '</div>\n'
|
||||
infoShown = True
|
||||
|
||||
blockingFilename = baseDir + '/accounts/blocking.txt'
|
||||
if os.path.isfile(blockingFilename):
|
||||
with open(blockingFilename, "r") as f:
|
||||
blockedStr = f.read()
|
||||
infoForm += '<div class="container">'
|
||||
infoForm += '<div class="container">\n'
|
||||
infoForm += \
|
||||
' <br><b>' + \
|
||||
translate['Blocked accounts and hashtags'] + '</b>'
|
||||
|
@ -182,13 +248,29 @@ def htmlModerationInfo(cssCache: {}, translate: {},
|
|||
infoForm += \
|
||||
' <textarea id="message" ' + \
|
||||
'name="blocked" style="height:700px">' + \
|
||||
blockedStr + '</textarea>'
|
||||
infoForm += '</div>'
|
||||
blockedStr + '</textarea>\n'
|
||||
infoForm += '</div>\n'
|
||||
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:
|
||||
infoForm += \
|
||||
'<center><p>' + \
|
||||
translate[msgStr2] + \
|
||||
'</p></center>'
|
||||
'</p></center>\n'
|
||||
infoForm += htmlFooter()
|
||||
return infoForm
|
||||
|
|
|
@ -43,7 +43,8 @@ def htmlPersonOptions(defaultTimeline: str,
|
|||
PGPpubKey: str,
|
||||
PGPfingerprint: str,
|
||||
emailAddress: str,
|
||||
dormantMonths: int) -> str:
|
||||
dormantMonths: int,
|
||||
backToPath: str) -> str:
|
||||
"""Show options for a person: view/follow/block/report
|
||||
"""
|
||||
optionsDomain, optionsPort = getDomainFromActor(optionsActor)
|
||||
|
@ -225,6 +226,8 @@ def htmlPersonOptions(defaultTimeline: str,
|
|||
backPath = '/'
|
||||
if nickname:
|
||||
backPath = '/users/' + nickname + '/' + defaultTimeline
|
||||
if 'moderation' in backToPath:
|
||||
backPath = '/users/' + nickname + '/moderation'
|
||||
optionsStr += \
|
||||
' <a href="' + backPath + '"><button type="button" ' + \
|
||||
'class="buttonIcon" name="submitBack">' + translate['Go Back'] + \
|
||||
|
|
|
@ -47,6 +47,7 @@ from content import getMentionsFromHtml
|
|||
from content import switchWords
|
||||
from person import isPersonSnoozed
|
||||
from announce import announcedByPerson
|
||||
from webapp_utils import getAvatarImageUrl
|
||||
from webapp_utils import getPersonAvatarUrl
|
||||
from webapp_utils import updateAvatarImageCache
|
||||
from webapp_utils import loadIndividualPostAsHtmlFromCache
|
||||
|
@ -177,32 +178,6 @@ def getPostFromRecentCache(session,
|
|||
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,
|
||||
nickname: str, domainFull: str,
|
||||
avatarUrl: str, postActor: str,
|
||||
|
@ -1179,7 +1154,8 @@ def individualPostAsHtml(allowDownloads: bool,
|
|||
avatarUrl2, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache,
|
||||
projectVersion, httpPrefix,
|
||||
nickname, domain, 'outbox')
|
||||
nickname, domain, 'outbox',
|
||||
72367)
|
||||
logPostTiming(enableTimingLog, postStartTime, '6')
|
||||
|
||||
if avatarUrl2:
|
||||
|
|
|
@ -34,6 +34,7 @@ from pgp import getPGPfingerprint
|
|||
from pgp import getPGPpubKey
|
||||
from tox import getToxAddress
|
||||
from jami import getJamiAddress
|
||||
from filters import isFiltered
|
||||
from webapp_frontscreen import htmlFrontScreen
|
||||
from webapp_utils import scheduledPostsExist
|
||||
from webapp_utils import getPersonAvatarUrl
|
||||
|
@ -259,10 +260,20 @@ def htmlProfileAfterSearch(cssCache: {},
|
|||
continue
|
||||
if not item.get('object'):
|
||||
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 += \
|
||||
individualPostAsHtml(True, recentPostsCache, maxRecentPosts,
|
||||
translate, None, baseDir,
|
||||
session, cachedWebfingers, personCache,
|
||||
session, wfRequest, personCache,
|
||||
nickname, domain, port,
|
||||
item, avatarUrl, False, False,
|
||||
httpPrefix, projectVersion, 'inbox',
|
||||
|
@ -282,7 +293,8 @@ def getProfileHeader(baseDir: str, nickname: str, domain: str,
|
|||
displayName: str,
|
||||
avatarDescription: str,
|
||||
profileDescriptionShort: str,
|
||||
loginButton: str, avatarUrl: str) -> str:
|
||||
loginButton: str, avatarUrl: str,
|
||||
theme: str) -> str:
|
||||
"""The header of the profile screen, containing background
|
||||
image and avatar
|
||||
"""
|
||||
|
@ -291,7 +303,7 @@ def getProfileHeader(baseDir: str, nickname: str, domain: str,
|
|||
nickname + '/' + defaultTimeline + '" title="' + \
|
||||
translate['Switch to timeline view'] + '">\n'
|
||||
htmlStr += ' <img class="profileBackground" ' + \
|
||||
'src="/users/' + nickname + '/image.png" /></a>\n'
|
||||
'src="/users/' + nickname + '/image_' + theme + '.png" /></a>\n'
|
||||
htmlStr += ' <figcaption>\n'
|
||||
htmlStr += \
|
||||
' <a href="/users/' + \
|
||||
|
@ -359,7 +371,7 @@ def htmlProfile(rssIconAtTop: bool,
|
|||
session, wfRequest: {}, personCache: {},
|
||||
YTReplacementDomain: str,
|
||||
showPublishedDateOnly: bool,
|
||||
newswire: {}, dormantMonths: int,
|
||||
newswire: {}, theme: str, dormantMonths: int,
|
||||
extraJson=None, pageNumber=None,
|
||||
maxItemsPerPage=None) -> str:
|
||||
"""Show the profile page as html
|
||||
|
@ -378,7 +390,7 @@ def htmlProfile(rssIconAtTop: bool,
|
|||
session, wfRequest, personCache,
|
||||
YTReplacementDomain,
|
||||
showPublishedDateOnly,
|
||||
newswire, extraJson,
|
||||
newswire, theme, extraJson,
|
||||
pageNumber, maxItemsPerPage)
|
||||
|
||||
domain, port = getDomainFromActor(profileJson['id'])
|
||||
|
@ -561,7 +573,7 @@ def htmlProfile(rssIconAtTop: bool,
|
|||
defaultTimeline, displayName,
|
||||
avatarDescription,
|
||||
profileDescriptionShort,
|
||||
loginButton, avatarUrl)
|
||||
loginButton, avatarUrl, theme)
|
||||
|
||||
profileStr = profileHeaderStr + donateSection
|
||||
profileStr += '<div class="container" id="buttonheader">\n'
|
||||
|
@ -819,7 +831,7 @@ def htmlProfileShares(actor: str, translate: {},
|
|||
|
||||
def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||
domain: str, port: int, httpPrefix: str,
|
||||
defaultTimeline: str) -> str:
|
||||
defaultTimeline: str, theme: str) -> str:
|
||||
"""Shows the edit profile screen
|
||||
"""
|
||||
imageFormats = getImageFormats()
|
||||
|
@ -836,7 +848,8 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
|||
return ''
|
||||
|
||||
# filename of the banner shown at the top
|
||||
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
|
||||
bannerFile, bannerFilename = \
|
||||
getBannerFile(baseDir, nickname, domain, theme)
|
||||
|
||||
isBot = ''
|
||||
isGroup = ''
|
||||
|
@ -872,10 +885,13 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
|||
PGPpubKey = getPGPpubKey(actorJson)
|
||||
PGPfingerprint = getPGPfingerprint(actorJson)
|
||||
if actorJson.get('name'):
|
||||
displayNickname = actorJson['name']
|
||||
if not isFiltered(baseDir, nickname, domain, actorJson['name']):
|
||||
displayNickname = actorJson['name']
|
||||
if actorJson.get('summary'):
|
||||
bioStr = \
|
||||
actorJson['summary'].replace('<p>', '').replace('</p>', '')
|
||||
if isFiltered(baseDir, nickname, domain, bioStr):
|
||||
bioStr = ''
|
||||
if actorJson.get('manuallyApprovesFollowers'):
|
||||
if actorJson['manuallyApprovesFollowers']:
|
||||
manuallyApprovesFollowers = 'checked'
|
||||
|
@ -982,6 +998,8 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
|||
skillCtr = 1
|
||||
if skills:
|
||||
for skillDesc, skillValue in skills.items():
|
||||
if isFiltered(baseDir, nickname, domain, skillDesc):
|
||||
continue
|
||||
skillsStr += \
|
||||
'<p><input type="text" placeholder="' + translate['Skill'] + \
|
||||
' ' + str(skillCtr) + '" name="skillName' + str(skillCtr) + \
|
||||
|
@ -1457,7 +1475,7 @@ def individualFollowAsHtml(translate: {},
|
|||
avatarUrl2, displayName) = getPersonBox(baseDir, session, wfRequest,
|
||||
personCache, projectVersion,
|
||||
httpPrefix, nickname,
|
||||
domain, 'outbox')
|
||||
domain, 'outbox', 43036)
|
||||
if avatarUrl2:
|
||||
avatarUrl = avatarUrl2
|
||||
if displayName:
|
||||
|
|
|
@ -15,7 +15,6 @@ from utils import isEditor
|
|||
from utils import loadJson
|
||||
from utils import getDomainFromActor
|
||||
from utils import getNicknameFromActor
|
||||
from utils import getConfigParam
|
||||
from utils import locatePost
|
||||
from utils import isPublicPost
|
||||
from utils import firstParagraphFromString
|
||||
|
@ -24,7 +23,6 @@ from utils import getHashtagCategory
|
|||
from feeds import rss2TagHeader
|
||||
from feeds import rss2TagFooter
|
||||
from webapp_utils import getAltPath
|
||||
from webapp_utils import getImageFile
|
||||
from webapp_utils import htmlHeaderWithExternalStyle
|
||||
from webapp_utils import htmlFooter
|
||||
from webapp_utils import getSearchBannerFile
|
||||
|
@ -312,7 +310,7 @@ def htmlSearchEmojiTextEntry(cssCache: {}, translate: {},
|
|||
|
||||
def htmlSearch(cssCache: {}, translate: {},
|
||||
baseDir: str, path: str, domain: str,
|
||||
defaultTimeline: str) -> str:
|
||||
defaultTimeline: str, theme: str) -> str:
|
||||
"""Search called from the timeline icon
|
||||
"""
|
||||
actor = path.replace('/search', '')
|
||||
|
@ -331,24 +329,7 @@ def htmlSearch(cssCache: {}, translate: {},
|
|||
|
||||
# show a banner above the search box
|
||||
searchBannerFile, searchBannerFilename = \
|
||||
getSearchBannerFile(baseDir, searchNickname, domain)
|
||||
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
|
||||
getSearchBannerFile(baseDir, searchNickname, domain, theme)
|
||||
|
||||
if os.path.isfile(searchBannerFilename):
|
||||
usersPath = '/users/' + searchNickname
|
||||
|
|
|
@ -60,7 +60,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
|||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool,
|
||||
moderationActionStr: str) -> str:
|
||||
moderationActionStr: str,
|
||||
theme: str) -> str:
|
||||
"""Show the timeline as html
|
||||
"""
|
||||
enableTimingLog = False
|
||||
|
@ -123,7 +124,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
|||
cssFilename = baseDir + '/epicyon.css'
|
||||
|
||||
# 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')
|
||||
|
||||
|
@ -404,7 +406,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
|||
getLeftColumnContent(baseDir, nickname, domainFull,
|
||||
httpPrefix, translate,
|
||||
editor, False, None, rssIconAtTop,
|
||||
True, False)
|
||||
True, False, theme)
|
||||
tlStr += ' <td valign="top" class="col-left">' + \
|
||||
leftColumnStr + ' </td>\n'
|
||||
# center column containing posts
|
||||
|
@ -444,6 +446,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
|||
else:
|
||||
tlStr += ' <input type="text" ' + \
|
||||
'name="moderationAction" value="" autofocus><br>\n'
|
||||
|
||||
tlStr += \
|
||||
' <input type="submit" title="' + \
|
||||
translate['Information about current blocks/suspensions'] + \
|
||||
|
@ -453,6 +456,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
|||
translate['Remove the above item'] + \
|
||||
'" name="submitRemove" value="' + \
|
||||
translate['Remove'] + '">\n'
|
||||
|
||||
tlStr += \
|
||||
' <input type="submit" title="' + \
|
||||
translate['Suspend the above account nickname'] + \
|
||||
|
@ -462,6 +466,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
|||
translate['Remove a suspension for an account nickname'] + \
|
||||
'" name="submitUnsuspend" value="' + \
|
||||
translate['Unsuspend'] + '">\n'
|
||||
|
||||
tlStr += \
|
||||
' <input type="submit" title="' + \
|
||||
translate['Block an account on another instance'] + \
|
||||
|
@ -470,6 +475,16 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
|||
' <input type="submit" title="' + \
|
||||
translate['Unblock an account on another instance'] + \
|
||||
'" 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'
|
||||
|
||||
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '6')
|
||||
|
@ -592,7 +607,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
|||
False, None, True,
|
||||
showPublishAsIcon,
|
||||
rssIconAtTop, publishButtonAtTop,
|
||||
authorized, True)
|
||||
authorized, True, theme)
|
||||
tlStr += ' <td valign="top" class="col-right">' + \
|
||||
rightColumnStr + ' </td>\n'
|
||||
tlStr += ' </tr>\n'
|
||||
|
@ -705,7 +720,7 @@ def htmlShares(cssCache: {}, defaultTimeline: str,
|
|||
iconsAsButtons: bool,
|
||||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool) -> str:
|
||||
authorized: bool, theme: str) -> str:
|
||||
"""Show the shares timeline as html
|
||||
"""
|
||||
manuallyApproveFollowers = \
|
||||
|
@ -724,7 +739,7 @@ def htmlShares(cssCache: {}, defaultTimeline: str,
|
|||
positiveVoting, showPublishAsIcon,
|
||||
fullWidthTimelineButtonHeader,
|
||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||
authorized, None)
|
||||
authorized, None, theme)
|
||||
|
||||
|
||||
def htmlInbox(cssCache: {}, defaultTimeline: str,
|
||||
|
@ -742,7 +757,7 @@ def htmlInbox(cssCache: {}, defaultTimeline: str,
|
|||
iconsAsButtons: bool,
|
||||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool) -> str:
|
||||
authorized: bool, theme: str) -> str:
|
||||
"""Show the inbox as html
|
||||
"""
|
||||
manuallyApproveFollowers = \
|
||||
|
@ -761,7 +776,7 @@ def htmlInbox(cssCache: {}, defaultTimeline: str,
|
|||
positiveVoting, showPublishAsIcon,
|
||||
fullWidthTimelineButtonHeader,
|
||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||
authorized, None)
|
||||
authorized, None, theme)
|
||||
|
||||
|
||||
def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
||||
|
@ -779,7 +794,7 @@ def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
|||
iconsAsButtons: bool,
|
||||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool) -> str:
|
||||
authorized: bool, theme: str) -> str:
|
||||
"""Show the bookmarks as html
|
||||
"""
|
||||
manuallyApproveFollowers = \
|
||||
|
@ -798,7 +813,7 @@ def htmlBookmarks(cssCache: {}, defaultTimeline: str,
|
|||
positiveVoting, showPublishAsIcon,
|
||||
fullWidthTimelineButtonHeader,
|
||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||
authorized, None)
|
||||
authorized, None, theme)
|
||||
|
||||
|
||||
def htmlEvents(cssCache: {}, defaultTimeline: str,
|
||||
|
@ -816,7 +831,7 @@ def htmlEvents(cssCache: {}, defaultTimeline: str,
|
|||
iconsAsButtons: bool,
|
||||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool) -> str:
|
||||
authorized: bool, theme: str) -> str:
|
||||
"""Show the events as html
|
||||
"""
|
||||
manuallyApproveFollowers = \
|
||||
|
@ -835,7 +850,7 @@ def htmlEvents(cssCache: {}, defaultTimeline: str,
|
|||
positiveVoting, showPublishAsIcon,
|
||||
fullWidthTimelineButtonHeader,
|
||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||
authorized, None)
|
||||
authorized, None, theme)
|
||||
|
||||
|
||||
def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
||||
|
@ -853,7 +868,7 @@ def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
|||
iconsAsButtons: bool,
|
||||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool) -> str:
|
||||
authorized: bool, theme: str) -> str:
|
||||
"""Show the DM timeline as html
|
||||
"""
|
||||
return htmlTimeline(cssCache, defaultTimeline,
|
||||
|
@ -867,7 +882,7 @@ def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
|
|||
showPublishAsIcon,
|
||||
fullWidthTimelineButtonHeader,
|
||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||
authorized, None)
|
||||
authorized, None, theme)
|
||||
|
||||
|
||||
def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
||||
|
@ -885,7 +900,7 @@ def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
|||
iconsAsButtons: bool,
|
||||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool) -> str:
|
||||
authorized: bool, theme: str) -> str:
|
||||
"""Show the replies timeline as html
|
||||
"""
|
||||
return htmlTimeline(cssCache, defaultTimeline,
|
||||
|
@ -900,7 +915,7 @@ def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
|
|||
positiveVoting, showPublishAsIcon,
|
||||
fullWidthTimelineButtonHeader,
|
||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||
authorized, None)
|
||||
authorized, None, theme)
|
||||
|
||||
|
||||
def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
||||
|
@ -918,7 +933,7 @@ def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
|||
iconsAsButtons: bool,
|
||||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool) -> str:
|
||||
authorized: bool, theme: str) -> str:
|
||||
"""Show the media timeline as html
|
||||
"""
|
||||
return htmlTimeline(cssCache, defaultTimeline,
|
||||
|
@ -933,7 +948,7 @@ def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
|
|||
positiveVoting, showPublishAsIcon,
|
||||
fullWidthTimelineButtonHeader,
|
||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||
authorized, None)
|
||||
authorized, None, theme)
|
||||
|
||||
|
||||
def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
||||
|
@ -951,7 +966,7 @@ def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
|||
iconsAsButtons: bool,
|
||||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool) -> str:
|
||||
authorized: bool, theme: str) -> str:
|
||||
"""Show the blogs timeline as html
|
||||
"""
|
||||
return htmlTimeline(cssCache, defaultTimeline,
|
||||
|
@ -966,7 +981,7 @@ def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
|
|||
positiveVoting, showPublishAsIcon,
|
||||
fullWidthTimelineButtonHeader,
|
||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||
authorized, None)
|
||||
authorized, None, theme)
|
||||
|
||||
|
||||
def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
||||
|
@ -984,7 +999,8 @@ def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
|||
iconsAsButtons: bool,
|
||||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool) -> str:
|
||||
authorized: bool,
|
||||
theme: str) -> str:
|
||||
"""Show the features timeline as html
|
||||
"""
|
||||
return htmlTimeline(cssCache, defaultTimeline,
|
||||
|
@ -999,7 +1015,7 @@ def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
|
|||
positiveVoting, showPublishAsIcon,
|
||||
fullWidthTimelineButtonHeader,
|
||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||
authorized, None)
|
||||
authorized, None, theme)
|
||||
|
||||
|
||||
def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
||||
|
@ -1017,7 +1033,7 @@ def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
|||
iconsAsButtons: bool,
|
||||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool) -> str:
|
||||
authorized: bool, theme: str) -> str:
|
||||
"""Show the news timeline as html
|
||||
"""
|
||||
return htmlTimeline(cssCache, defaultTimeline,
|
||||
|
@ -1032,7 +1048,7 @@ def htmlInboxNews(cssCache: {}, defaultTimeline: str,
|
|||
positiveVoting, showPublishAsIcon,
|
||||
fullWidthTimelineButtonHeader,
|
||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||
authorized, None)
|
||||
authorized, None, theme)
|
||||
|
||||
|
||||
def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
||||
|
@ -1050,7 +1066,7 @@ def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
|||
iconsAsButtons: bool,
|
||||
rssIconAtTop: bool,
|
||||
publishButtonAtTop: bool,
|
||||
authorized: bool) -> str:
|
||||
authorized: bool, theme: str) -> str:
|
||||
"""Show the Outbox as html
|
||||
"""
|
||||
manuallyApproveFollowers = \
|
||||
|
@ -1066,4 +1082,4 @@ def htmlOutbox(cssCache: {}, defaultTimeline: str,
|
|||
newswire, False, False, positiveVoting,
|
||||
showPublishAsIcon, fullWidthTimelineButtonHeader,
|
||||
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
|
||||
authorized, None)
|
||||
authorized, None, theme)
|
||||
|
|
|
@ -476,7 +476,7 @@ def postContainsPublic(postJsonObject: {}) -> bool:
|
|||
|
||||
|
||||
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
|
||||
"""
|
||||
|
@ -484,39 +484,41 @@ def getImageFile(baseDir: str, name: str, directory: str,
|
|||
bannerFile = ''
|
||||
bannerFilename = ''
|
||||
for ext in bannerExtensions:
|
||||
bannerFile = name + '.' + ext
|
||||
bannerFilename = directory + '/' + bannerFile
|
||||
if os.path.isfile(bannerFilename):
|
||||
bannerFileTest = name + '.' + ext
|
||||
bannerFilenameTest = directory + '/' + bannerFileTest
|
||||
if os.path.isfile(bannerFilenameTest):
|
||||
bannerFile = name + '_' + theme + '.' + ext
|
||||
bannerFilename = bannerFilenameTest
|
||||
break
|
||||
return bannerFile, bannerFilename
|
||||
|
||||
|
||||
def getBannerFile(baseDir: str,
|
||||
nickname: str, domain: str) -> (str, str):
|
||||
nickname: str, domain: str, theme: str) -> (str, str):
|
||||
return getImageFile(baseDir, 'banner',
|
||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||
nickname, domain)
|
||||
nickname, domain, theme)
|
||||
|
||||
|
||||
def getSearchBannerFile(baseDir: str,
|
||||
nickname: str, domain: str) -> (str, str):
|
||||
nickname: str, domain: str, theme: str) -> (str, str):
|
||||
return getImageFile(baseDir, 'search_banner',
|
||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||
nickname, domain)
|
||||
nickname, domain, theme)
|
||||
|
||||
|
||||
def getLeftImageFile(baseDir: str,
|
||||
nickname: str, domain: str) -> (str, str):
|
||||
nickname: str, domain: str, theme: str) -> (str, str):
|
||||
return getImageFile(baseDir, 'left_col_image',
|
||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||
nickname, domain)
|
||||
nickname, domain, theme)
|
||||
|
||||
|
||||
def getRightImageFile(baseDir: str,
|
||||
nickname: str, domain: str) -> (str, str):
|
||||
nickname: str, domain: str, theme: str) -> (str, str):
|
||||
return getImageFile(baseDir, 'right_col_image',
|
||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||
nickname, domain)
|
||||
nickname, domain, theme)
|
||||
|
||||
|
||||
def htmlHeaderWithExternalStyle(cssFilename: str, lang='en') -> str:
|
||||
|
@ -850,3 +852,29 @@ def htmlHighlightLabel(label: str, highlight: bool) -> str:
|
|||
if not highlight:
|
||||
return 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,
|
||||
cachedWebfingers)
|
||||
if wf:
|
||||
print('Webfinger from cache: ' + str(wf))
|
||||
return wf
|
||||
url = '{}://{}/.well-known/webfinger'.format(httpPrefix, domain)
|
||||
par = {
|
||||
|
|
Loading…
Reference in New Issue