diff --git a/announce.py b/announce.py
index 814728c15..92c412c5c 100644
--- a/announce.py
+++ b/announce.py
@@ -77,7 +77,7 @@ def outboxAnnounce(recentPostsCache: {},
nickname, domain, debug)
return True
elif messageJson['type'] == 'Undo':
- if not isinstance(messageJson['object'], dict):
+ if not hasObjectDict(messageJson):
return False
if not messageJson['object'].get('type'):
return False
diff --git a/inbox.py b/inbox.py
index d1f6d2450..8fbaccf50 100644
--- a/inbox.py
+++ b/inbox.py
@@ -298,7 +298,7 @@ def inboxMessageHasParams(messageJson: {}) -> bool:
return False
# object should be a dict or a string
- if not isinstance(messageJson['object'], dict):
+ if not hasObjectDict(messageJson):
if not isinstance(messageJson['object'], str):
print('WARN: object from ' + str(messageJson['actor']) +
' should be a dict or string, but is actually: ' +
diff --git a/media.py b/media.py
index 2f788117e..0206a10ba 100644
--- a/media.py
+++ b/media.py
@@ -18,6 +18,7 @@ from utils import getImageExtensions
from utils import getVideoExtensions
from utils import getAudioExtensions
from utils import getMediaExtensions
+from utils import hasObjectDict
from shutil import copyfile
from shutil import rmtree
from shutil import move
@@ -30,7 +31,7 @@ def replaceYouTube(postJsonObject: {}, replacementDomain: str) -> None:
"""
if not replacementDomain:
return
- if not isinstance(postJsonObject['object'], dict):
+ if not hasObjectDict(postJsonObject):
return
if not postJsonObject['object'].get('content'):
return
diff --git a/posts.py b/posts.py
index a213f7444..0dc9e7179 100644
--- a/posts.py
+++ b/posts.py
@@ -1296,7 +1296,7 @@ def _postIsAddressedToFollowers(baseDir: str,
toList = []
ccList = []
if postJsonObject['type'] != 'Update' and \
- isinstance(postJsonObject['object'], dict):
+ hasObjectDict(postJsonObject):
if postJsonObject['object'].get('to'):
toList = postJsonObject['object']['to']
if postJsonObject['object'].get('cc'):
@@ -2169,7 +2169,7 @@ def _addFollowersToPublicPost(postJsonObject: {}) -> None:
if postJsonObject.get('cc'):
return
postJsonObject['cc'] = postJsonObject['actor'] + '/followers'
- elif isinstance(postJsonObject['object'], dict):
+ elif hasObjectDict(postJsonObject):
if not postJsonObject['object'].get('to'):
return
if len(postJsonObject['object']['to']) > 1:
@@ -2433,7 +2433,7 @@ def sendToNamedAddresses(session, baseDir: str,
if not postJsonObject.get('object'):
return
isProfileUpdate = False
- if isinstance(postJsonObject['object'], dict):
+ if hasObjectDict(postJsonObject):
if _isProfileUpdate(postJsonObject):
# use the original object, which has a 'to'
recipientsObject = postJsonObject
diff --git a/question.py b/question.py
index 9008cbd56..60deecdc4 100644
--- a/question.py
+++ b/question.py
@@ -126,7 +126,7 @@ def isQuestion(postObjectJson: {}) -> bool:
if postObjectJson['type'] != 'Create' and \
postObjectJson['type'] != 'Update':
return False
- if not isinstance(postObjectJson['object'], dict):
+ if not hasObjectDict(postObjectJson):
return False
if not postObjectJson['object'].get('type'):
return False
diff --git a/theme.py b/theme.py
index a700d9706..46062ca8a 100644
--- a/theme.py
+++ b/theme.py
@@ -366,16 +366,12 @@ def _setThemeFromDict(baseDir: str, name: str,
with open(filename, 'w+') as cssfile:
cssfile.write(css)
- if bgParams.get('login'):
- _setBackgroundFormat(baseDir, name, 'login', bgParams['login'])
- if bgParams.get('follow'):
- _setBackgroundFormat(baseDir, name, 'follow', bgParams['follow'])
- if bgParams.get('options'):
- _setBackgroundFormat(baseDir, name, 'options', bgParams['options'])
- if bgParams.get('search'):
- _setBackgroundFormat(baseDir, name, 'search', bgParams['search'])
- if bgParams.get('welcome'):
- _setBackgroundFormat(baseDir, name, 'welcome', bgParams['welcome'])
+ screenName = (
+ 'login', 'follow', 'options', 'search', 'welcome'
+ )
+ for s in screenName:
+ if bgParams.get(s):
+ _setBackgroundFormat(baseDir, name, s, bgParams[s])
def _setBackgroundFormat(baseDir: str, name: str,
diff --git a/utils.py b/utils.py
index 6e291f1ae..9d21085f2 100644
--- a/utils.py
+++ b/utils.py
@@ -1401,7 +1401,7 @@ def deletePost(baseDir: str, httpPrefix: str,
# remove from moderation index file
if hasObject:
- if isinstance(postJsonObject['object'], dict):
+ if hasObjectDict(postJsonObject):
if postJsonObject['object'].get('moderationStatus'):
if postJsonObject.get('id'):
postId = removeIdEnding(postJsonObject['id'])
@@ -2536,3 +2536,15 @@ def getPortFromDomain(domain: str) -> int:
if portStr.isdigit():
return int(portStr)
return None
+
+
+def validUrlPrefix(url: str) -> bool:
+ """Does the given url have a valid prefix?
+ """
+ if '/' not in url:
+ return False
+ prefixes = ('https:', 'http:', 'hyper:', 'i2p:', 'gnunet:')
+ for pre in prefixes:
+ if url.startswith(pre):
+ return True
+ return False
diff --git a/webapp_calendar.py b/webapp_calendar.py
index 65cdb7de0..a01ffeb55 100644
--- a/webapp_calendar.py
+++ b/webapp_calendar.py
@@ -117,8 +117,7 @@ def _htmlCalendarDay(personCache: {}, cssCache: {}, translate: {},
if '/users/' in actor:
calActor = '/users/' + actor.split('/users/')[1]
- instanceTitle = \
- getConfigParam(baseDir, 'instanceTitle')
+ instanceTitle = getConfigParam(baseDir, 'instanceTitle')
calendarStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
calendarStr += '\n'
calendarStr += '\n'
@@ -369,20 +368,10 @@ def htmlCalendar(personCache: {}, cssCache: {}, translate: {},
calendarStr += '\n'
calendarStr += '\n'
calendarStr += '\n'
- calendarStr += ' \n'
- calendarStr += ' \n'
- calendarStr += ' \n'
- calendarStr += ' \n'
- calendarStr += ' \n'
- calendarStr += ' \n'
- calendarStr += ' \n'
+ days = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
+ for d in days:
+ calendarStr += ' \n'
calendarStr += '
\n'
calendarStr += '\n'
calendarStr += '\n'
diff --git a/webapp_column_left.py b/webapp_column_left.py
index eea4ace02..09b73f782 100644
--- a/webapp_column_left.py
+++ b/webapp_column_left.py
@@ -51,10 +51,8 @@ def _getLeftColumnShares(baseDir: str,
if '<' in sharedesc or '?' in sharedesc:
continue
contactActor = item['actor']
- shareLink = actor + \
- '?replydm=sharedesc:' + \
- sharedesc.replace(' ', '_') + \
- '?mention=' + contactActor
+ shareLink = actor + '?replydm=sharedesc:' + \
+ sharedesc.replace(' ', '_') + '?mention=' + contactActor
linksList.append(sharedesc + ' ' + shareLink)
ctr += 1
if ctr >= maxSharesInLeftColumn:
@@ -89,16 +87,14 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
if os.path.isfile(leftColumnImageFilename):
editImageClass = 'leftColEditImage'
htmlStr += \
- '\n \n' + \
- '
\n
\n' + \
' \n'
if showBackButton:
htmlStr += \
- ' ' + \
- '
' + \
+ ' ' + \
'\n'
@@ -112,14 +108,11 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
if editor:
# show the edit icon
htmlStr += \
- '
' + \
- '![' + \
- translate['Edit Links'] + ' ' + \
+ '<img class=](/' + \
- 'icons/edit.png)
\n'
+ translate['Edit Links'] + '" src="/icons/edit.png" />\n'
# RSS icon
if nickname != 'news':
@@ -134,10 +127,8 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
else:
rssTitle = translate['RSS feed for this site']
rssIconStr = \
- '
' + \
- '![' + rssTitle + \
+ ' <a href= ' + rssTitle + \
- ']()

\n'
if rssIconAtTop:
htmlStr += rssIconStr
@@ -326,8 +317,7 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
theme, accessKeys)
else:
if editor:
- htmlStr += '
\n'
- htmlStr += '
\n '
+ htmlStr += '
\n\n '
htmlStr += translate['Select the edit icon to add web links']
htmlStr += '\n\n'
@@ -376,7 +366,8 @@ def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
translate['Switch to timeline view'] + '" alt="' + \
translate['Switch to timeline view'] + '" ' + \
'accesskey="' + accessKeys['menuTimeline'] + '">\n'
- editLinksForm += '
\n' + \
'\n'
@@ -411,8 +402,7 @@ def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
'
'
editLinksForm += \
' '
+ 'style="height:80vh" spellcheck="false">' + linksStr + ''
editLinksForm += \
' '
diff --git a/webapp_column_right.py b/webapp_column_right.py
index 3ea61e1c9..731ac86bf 100644
--- a/webapp_column_right.py
+++ b/webapp_column_right.py
@@ -253,8 +253,7 @@ def _htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
if faviconUrl:
faviconLink = \
'
'
+ 'alt="" ' + _getBrokenFavSubstitute() + '/>'
moderatedItem = item[5]
htmlStr += separatorStr
if moderatedItem and 'vote:' + nickname in item[2]:
@@ -270,8 +269,7 @@ def _htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
'' + \
'' + \
- faviconLink + title + \
- '' + totalVotesStr
+ faviconLink + title + '' + totalVotesStr
if moderator:
htmlStr += \
' ' + dateShown + '
' + \
'' + \
- faviconLink + title + '' + \
- totalVotesStr
+ faviconLink + title + '' + totalVotesStr
htmlStr += '
'
htmlStr += dateShown + '\n'
diff --git a/webapp_confirm.py b/webapp_confirm.py
index 69f0cc576..fdbdc0ff5 100644
--- a/webapp_confirm.py
+++ b/webapp_confirm.py
@@ -137,8 +137,7 @@ def htmlConfirmRemoveSharedItem(cssCache: {}, translate: {}, baseDir: str,
if os.path.isfile(baseDir + '/follow.css'):
cssFilename = baseDir + '/follow.css'
- instanceTitle = \
- getConfigParam(baseDir, 'instanceTitle')
+ instanceTitle = getConfigParam(baseDir, 'instanceTitle')
sharesStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
sharesStr += '
\n'
sharesStr += '
\n'
@@ -186,8 +185,7 @@ def htmlConfirmFollow(cssCache: {}, translate: {}, baseDir: str,
if os.path.isfile(baseDir + '/follow.css'):
cssFilename = baseDir + '/follow.css'
- instanceTitle = \
- getConfigParam(baseDir, 'instanceTitle')
+ instanceTitle = getConfigParam(baseDir, 'instanceTitle')
followStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
followStr += '
\n'
followStr += '
\n'
@@ -232,8 +230,7 @@ def htmlConfirmUnfollow(cssCache: {}, translate: {}, baseDir: str,
if os.path.isfile(baseDir + '/follow.css'):
cssFilename = baseDir + '/follow.css'
- instanceTitle = \
- getConfigParam(baseDir, 'instanceTitle')
+ instanceTitle = getConfigParam(baseDir, 'instanceTitle')
followStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
followStr += '
\n'
followStr += '
\n'
@@ -279,8 +276,7 @@ def htmlConfirmUnblock(cssCache: {}, translate: {}, baseDir: str,
if os.path.isfile(baseDir + '/follow.css'):
cssFilename = baseDir + '/follow.css'
- instanceTitle = \
- getConfigParam(baseDir, 'instanceTitle')
+ instanceTitle = getConfigParam(baseDir, 'instanceTitle')
blockStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
blockStr += '
\n'
blockStr += '
\n'
diff --git a/webapp_create_post.py b/webapp_create_post.py
index 39dcd2da6..1a70401be 100644
--- a/webapp_create_post.py
+++ b/webapp_create_post.py
@@ -26,35 +26,35 @@ def _htmlFollowingDataList(baseDir: str, nickname: str,
listStr = '
\n'
return listStr
@@ -84,8 +84,7 @@ def _htmlNewPostDropDown(scopeIcon: str, scopeDescription: str,
dropDownContent += '
\n'
+ 'icons/' + scopeIcon + '"/>
' + scopeDescription + '\n'
if noDropDown:
dropDownContent += '
\n'
@@ -144,12 +143,6 @@ def _htmlNewPostDropDown(scopeIcon: str, scopeDescription: str,
'icons/scope_reminder.png"/>
' + \
translate['Reminder'] + '' + \
translate['Scheduled note to yourself'] + '\n'
- # dropDownContent += \
- # '
' + \
- # translate['Event'] + '
' + \
- # translate['Create an event'] + '\n'
dropDownContent += \
'
' + \
@@ -230,8 +223,7 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
showPublicOnDropdown = False
else:
newPostText = \
- '' + \
- translate['Write your report below.'] + '
\n'
+ '' + translate['Write your report below.'] + '
\n'
# custom report header with any additional instructions
if os.path.isfile(baseDir + '/accounts/report.txt'):
@@ -319,7 +311,6 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
translate['Subject or Content Warning (optional)'] + '...'
placeholderMentions = ''
if inReplyTo:
- # mentionsAndContent = getMentionsString(content)
placeholderMentions = \
translate['Replying to'] + '...'
placeholderMessage = translate['Write something'] + '...'
@@ -582,8 +573,7 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
dateAndLocation += '\n'
dateAndLocation += '\n'
- instanceTitle = \
- getConfigParam(baseDir, 'instanceTitle')
+ instanceTitle = getConfigParam(baseDir, 'instanceTitle')
newPostForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
newPostForm += \
@@ -711,17 +701,11 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
submitText + '" ' + \
'accesskey="' + accessKeys['submitButton'] + '">\n'
- newPostForm += ' \n'
- newPostForm += '
\n'
+ newPostForm += ' \n\n'
newPostForm += ' \n'
newPostForm += ' \n'
- # newPostForm += \
- # ' \n'
-
newPostForm += ' \n'
newPostForm += replyStr
@@ -777,14 +761,13 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
if not mediaInstance or replyStr:
newPostForm += newPostImageSection
- newPostForm += ' \n'
newPostForm += \
+ '
\n' + \
' \n'
- newPostForm += '
\n'
-
- newPostForm += '
\n'
- newPostForm += '\n'
+ submitText + '">\n' + \
+ ' \n' + \
+ ' \n' + \
+ '\n'
if not reportUrl:
newPostForm = \
diff --git a/webapp_frontscreen.py b/webapp_frontscreen.py
index 585489077..a1c575029 100644
--- a/webapp_frontscreen.py
+++ b/webapp_frontscreen.py
@@ -128,22 +128,24 @@ def htmlFrontScreen(rssIconAtTop: bool,
if loginButton:
profileHeaderStr += '' + loginButton + '\n'
- profileHeaderStr += '\n'
- profileHeaderStr += ' \n'
- profileHeaderStr += ' \n'
- profileHeaderStr += ' \n'
- profileHeaderStr += ' \n'
- profileHeaderStr += ' \n'
- profileHeaderStr += ' \n'
- profileHeaderStr += ' \n'
- profileHeaderStr += ' \n'
+ profileHeaderStr += \
+ '\n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' | \n'
profileHeaderStr += \
getLeftColumnContent(baseDir, 'news', domainFull,
httpPrefix, translate,
False, False, None, rssIconAtTop, True,
True, theme, accessKeys)
- profileHeaderStr += ' | \n'
- profileHeaderStr += ' \n'
+ profileHeaderStr += \
+ ' | \n' + \
+ ' \n'
profileStr = profileHeaderStr
@@ -177,10 +179,11 @@ def htmlFrontScreen(rssIconAtTop: bool,
False, None, False, False,
False, True, authorized, True, theme,
defaultTimeline, accessKeys)
- profileFooterStr += ' | \n'
- profileFooterStr += ' \n'
- profileFooterStr += ' \n'
- profileFooterStr += ' \n'
+ profileFooterStr += \
+ ' | \n' + \
+ '
\n' + \
+ ' \n' + \
+ '
\n'
instanceTitle = \
getConfigParam(baseDir, 'instanceTitle')
diff --git a/webapp_hashtagswarm.py b/webapp_hashtagswarm.py
index cab2af8b8..8cb784d8b 100644
--- a/webapp_hashtagswarm.py
+++ b/webapp_hashtagswarm.py
@@ -29,17 +29,19 @@ def getHashtagCategoriesFeed(baseDir: str,
if not hashtagCategories:
return None
- rssStr = "\n"
- rssStr += "\n"
- rssStr += '\n'
- rssStr += ' #categories\n'
+ rssStr = \
+ "\n" + \
+ "\n" + \
+ '\n' + \
+ ' #categories\n'
rssDateStr = \
datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S UT")
for categoryStr, hashtagList in hashtagCategories.items():
- rssStr += '- \n'
- rssStr += ' ' + categoryStr + '\n'
+ rssStr += \
+ '
- \n' + \
+ ' ' + categoryStr + '\n'
listStr = ''
for hashtag in hashtagList:
if ':' in hashtag:
@@ -47,75 +49,18 @@ def getHashtagCategoriesFeed(baseDir: str,
if '&' in hashtag:
continue
listStr += hashtag + ' '
- rssStr += ' ' + listStr.strip() + '\n'
- rssStr += ' \n'
- rssStr += ' ' + rssDateStr + '\n'
- rssStr += '
\n'
+ rssStr += \
+ ' ' + listStr.strip() + '\n' + \
+ ' \n' + \
+ ' ' + rssDateStr + '\n' + \
+ ' \n'
- rssStr += '\n'
- rssStr += '\n'
+ rssStr += \
+ '\n' + \
+ '\n'
return rssStr
-def _getHashtagDomainMax(domainHistogram: {}) -> str:
- """Returns the domain with the maximum number of hashtags
- """
- maxCount = 1
- maxDomain = None
- for domain, count in domainHistogram.items():
- if count > maxCount:
- maxDomain = domain
- maxCount = count
- return maxDomain
-
-
-def _getHashtagDomainHistogram(domainHistogram: {}, translate: {}) -> str:
- """Returns the html for a histogram of domains
- from which hashtags are coming
- """
- totalCount = 0
- for domain, count in domainHistogram.items():
- totalCount += count
- if totalCount == 0:
- return ''
-
- htmlStr = ''
- histogramHeaderStr = '
\n'
- histogramHeaderStr += ' ' + translate['Hashtag origins'] + '
\n'
- histogramHeaderStr += ' \n'
- histogramHeaderStr += ' \n'
- histogramHeaderStr += ' \n'
- histogramHeaderStr += ' \n'
- histogramHeaderStr += ' \n'
- histogramHeaderStr += ' \n'
- histogramHeaderStr += ' \n'
-
- leftColStr = ''
- rightColStr = ''
-
- for i in range(len(domainHistogram)):
- domain = _getHashtagDomainMax(domainHistogram)
- if not domain:
- break
- percent = int(domainHistogram[domain] * 100 / totalCount)
- if histogramHeaderStr:
- htmlStr += histogramHeaderStr
- histogramHeaderStr = None
- leftColStr += str(percent) + '%
'
- rightColStr += domain + '
'
- del domainHistogram[domain]
-
- if htmlStr:
- htmlStr += ' ' + leftColStr + ' | \n'
- htmlStr += ' ' + rightColStr + ' | \n'
- htmlStr += '
\n'
- htmlStr += ' \n'
- htmlStr += '
\n'
- htmlStr += '\n'
-
- return htmlStr
-
-
def htmlHashTagSwarm(baseDir: str, actor: str, translate: {}) -> str:
"""Returns a tag swarm of today's hashtags
"""
@@ -244,7 +189,6 @@ def htmlHashTagSwarm(baseDir: str, actor: str, translate: {}) -> str:
getContentWarningButton('alltags', translate, tagSwarmStr)
tagSwarmHtml = categorySwarmStr + tagSwarmStr.strip() + '\n'
- # tagSwarmHtml += _getHashtagDomainHistogram(domainHistogram, translate)
return tagSwarmHtml
@@ -279,10 +223,11 @@ def htmlSearchHashtagCategory(cssCache: {}, translate: {},
htmlStr += '
\n'
- htmlStr += ''
- htmlStr += '
'
- htmlStr += ''
+ htmlStr += \
+ '' + \
+ '
' + \
+ ''
hashtagsDict = getHashtagCategories(baseDir, True, categoryStr)
if hashtagsDict:
@@ -293,7 +238,8 @@ def htmlSearchHashtagCategory(cssCache: {}, translate: {},
'' + tagName + '\n'
- htmlStr += ''
- htmlStr += '
'
+ htmlStr += \
+ '' + \
+ '
'
htmlStr += htmlFooter()
return htmlStr
diff --git a/webapp_headerbuttons.py b/webapp_headerbuttons.py
index 99ab01290..a50e01da6 100644
--- a/webapp_headerbuttons.py
+++ b/webapp_headerbuttons.py
@@ -54,8 +54,7 @@ def headerButtonsTimeline(defaultTimeline: str,
# first button
if defaultTimeline == 'tlmedia':
tlStr += \
- '
' + \
'' + \
translate['You will become the admin of this site.'] + \
'
'
@@ -132,8 +132,7 @@ def htmlLogin(cssCache: {}, translate: {},
TOSstr = \
'' + \
- translate['About this Instance'] + '
'
- TOSstr += \
+ translate['About this Instance'] + '' + \
'' + \
translate['Terms of Service'] + '
'
@@ -153,34 +152,32 @@ def htmlLogin(cssCache: {}, translate: {},
htmlHeaderWithWebsiteMarkup(cssFilename, instanceTitle,
httpPrefix, domain,
systemLanguage)
- loginForm += '
\n'
- loginForm += '\n' + \
'' + \
'
None:
@@ -110,6 +111,8 @@ def _addEmbeddedVideoFromSites(translate: {}, content: str,
if '"https://' in content:
if peertubeInstances:
+ # only create an embedded video for a limited set of
+ # peertube sites.
peerTubeSites = peertubeInstances
else:
# A default selection of the current larger peertube sites,
@@ -160,19 +163,21 @@ def _addEmbeddedVideoFromSites(translate: {}, content: str,
else:
siteStr = 'https://' + site
siteStr = '"' + siteStr
- if siteStr in content:
- url = content.split(siteStr)[1]
- if '"' in url:
- url = url.split('"')[0].replace('/watch/', '/embed/')
- content = \
- content + "\n\n\n"
- return content
+ if siteStr not in content:
+ continue
+ url = content.split(siteStr)[1]
+ if '"' not in url:
+ continue
+ url = url.split('"')[0].replace('/watch/', '/embed/')
+ content = \
+ content + "\n\n\n"
+ return content
return content
@@ -205,19 +210,14 @@ def _addEmbeddedAudio(translate: {}, content: str) -> str:
if not w.endswith(extension):
continue
- if not (w.startswith('http') or w.startswith('dat:') or
- w.startswith('hyper:') or w.startswith('i2p:') or
- w.startswith('gnunet:') or
- '/' in w):
+ if not validUrlPrefix(w):
continue
- url = w
- content += '\n\n\n'
+ '\n\n\n'
return content
@@ -251,23 +251,17 @@ def _addEmbeddedVideo(translate: {}, content: str) -> str:
w = w[:-1]
if not w.endswith(extension):
continue
- if not (w.startswith('http') or w.startswith('dat:') or
- w.startswith('hyper:') or w.startswith('i2p:') or
- w.startswith('gnunet:') or
- '/' in w):
+ if not validUrlPrefix(w):
continue
- url = w
content += \
'\n' + \
' \n\n\n'
+ 'preload="metadata">\n' + \
+ '\n' + \
+ translate['Your browser does not support the video element.'] + \
+ '\n\n\n'
return content
diff --git a/webapp_person_options.py b/webapp_person_options.py
index 6b55aafd8..3c3309196 100644
--- a/webapp_person_options.py
+++ b/webapp_person_options.py
@@ -398,9 +398,10 @@ def htmlPersonOptions(defaultTimeline: str,
'accesskey="' + accessKeys['enterNotes'] + '">' + \
personNotes + '\n'
- optionsStr += ' \n'
- optionsStr += '\n'
- optionsStr += '\n'
- optionsStr += '\n'
+ optionsStr += \
+ ' \n' + \
+ '\n' + \
+ '\n' + \
+ '\n'
optionsStr += htmlFooter()
return optionsStr
diff --git a/webapp_post.py b/webapp_post.py
index fa1317344..3d3ff9941 100644
--- a/webapp_post.py
+++ b/webapp_post.py
@@ -22,6 +22,7 @@ from posts import postIsMuted
from posts import getPersonBox
from posts import downloadAnnounce
from posts import populateRepliesJson
+from utils import hasObjectDict
from utils import updateAnnounceCollection
from utils import isPGPEncrypted
from utils import isDM
@@ -840,8 +841,7 @@ def _getPostTitleAnnounceHtml(baseDir: str,
postJsonObject)
else:
titleStr += \
- _announceUnattributedHtml(translate,
- postJsonObject)
+ _announceUnattributedHtml(translate, postJsonObject)
else:
titleStr += \
_announceUnattributedHtml(translate, postJsonObject)
@@ -1339,7 +1339,7 @@ def individualPostAsHtml(allowDownloads: bool,
_logPostTiming(enableTimingLog, postStartTime, '8')
- if not isinstance(postJsonObject['object'], dict):
+ if not hasObjectDict(postJsonObject):
return ''
# if this post should be public then check its recipients
@@ -1762,7 +1762,7 @@ def htmlIndividualPost(cssCache: {},
messageId = removeIdEnding(postJsonObject['id'])
# show the previous posts
- if isinstance(postJsonObject['object'], dict):
+ if hasObjectDict(postJsonObject):
while postJsonObject['object'].get('inReplyTo'):
postFilename = \
locatePost(baseDir, nickname, domain,
diff --git a/webapp_profile.py b/webapp_profile.py
index eced71548..3439b834b 100644
--- a/webapp_profile.py
+++ b/webapp_profile.py
@@ -1601,64 +1601,66 @@ def _htmlEditProfileFiltering(baseDir: str, nickname: str, domain: str,
def _htmlEditProfileChangePassword(translate: {}) -> str:
"""Change password section of edit profile screen
"""
- editProfileForm = ' ' + \
- translate['Change Password'] + '
\n'
- editProfileForm += ' \n'
return editProfileForm
def _htmlEditProfileBackground(newsInstance: bool, translate: {}) -> str:
"""Background images section of edit profile screen
"""
- editProfileForm = ' ' + \
- translate['Background Images'] + '
\n'
- editProfileForm += ' \n'
+ translate['Following'] + '
\n' + \
+ ' \n'
return editProfileForm
@@ -1790,30 +1789,32 @@ def _htmlEditProfileMain(displayNickname: str, bioStr: str,
imageFormats = getImageFormats()
editProfileForm = ' \n'
- editProfileForm += ' \n'
+
editProfileForm += \
+ ' \n' + \
'
\n'
+
editProfileForm += \
- ' \n'
- editProfileForm += \
+ ' \n' + \
' \n'
+
editProfileForm += \
' \n'
- editProfileForm += \
- ' \n'
+ '\n' + \
+ ' \n'
occupationName = ''
if actorJson.get('hasOccupation'):
occupationName = getOccupationName(actorJson)
- editProfileForm += '
\n'
editProfileForm += \
+ '
\n' + \
' \n'
@@ -1827,27 +1828,29 @@ def _htmlEditProfileMain(displayNickname: str, bioStr: str,
ctr += 1
alsoKnownAsStr += altActor
- editProfileForm += '
\n'
editProfileForm += \
+ '
\n' + \
' \n'
- editProfileForm += '
\n'
editProfileForm += \
+ '
\n' + \
' \n'
- editProfileForm += '
\n'
+
editProfileForm += \
+ '
\n' + \
' \n'
- editProfileForm += '
\n'
+
editProfileForm += \
+ '
\n' + \
' \n'
- editProfileForm += '
\n'
+ blogAddress + '">\n' + \
+ ' \n'
return editProfileForm
@@ -1858,8 +1861,8 @@ def _htmlEditProfileTopBanner(baseDir: str,
"""top banner on edit profile screen
"""
editProfileForm = \
- ''
- editProfileForm += '
' + \
+ '
\n'
editProfileForm += \
@@ -2157,7 +2160,7 @@ def _individualFollowAsHtml(translate: {},
'?options=' + followUrl + \
';1;' + avatarUrl + '">' + \
translate['Block'] + '\n'
- if b == 'unfollow':
+ elif b == 'unfollow':
buttonsStr += \
'Account Suspended\n'
- suspendedForm += ' See Terms of Service
\n'
- suspendedForm += '\n'
+ suspendedForm += \
+ '\n'
suspendedForm += htmlFooter()
return suspendedForm
diff --git a/webapp_timeline.py b/webapp_timeline.py
index 2ba8e6881..3ab1800fd 100644
--- a/webapp_timeline.py
+++ b/webapp_timeline.py
@@ -600,14 +600,15 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
iconsAsButtons, accessKeys)
# start the timeline
- tlStr += '\n'
- tlStr += ' \n'
- tlStr += ' \n'
- tlStr += ' \n'
- tlStr += ' \n'
- tlStr += ' \n'
- tlStr += ' \n'
- tlStr += ' \n'
+ tlStr += \
+ '\n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n'
domainFull = getFullDomain(domain, port)
diff --git a/webapp_utils.py b/webapp_utils.py
index 5bf49b8ce..336eea016 100644
--- a/webapp_utils.py
+++ b/webapp_utils.py
@@ -452,17 +452,18 @@ def getRightImageFile(baseDir: str,
def htmlHeaderWithExternalStyle(cssFilename: str, instanceTitle: str,
lang='en') -> str:
- htmlStr = '\n'
- htmlStr += '\n'
- htmlStr += ' \n'
- htmlStr += ' \n'
cssFile = '/' + cssFilename.split('/')[-1]
- htmlStr += ' \n'
- htmlStr += ' \n'
- htmlStr += ' \n'
- htmlStr += ' ' + instanceTitle + '\n'
- htmlStr += ' \n'
- htmlStr += ' \n'
+ htmlStr = \
+ '\n' + \
+ '\n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' \n' + \
+ ' ' + instanceTitle + '\n' + \
+ ' \n' + \
+ ' \n'
return htmlStr
@@ -511,37 +512,32 @@ def htmlHeaderWithPersonMarkup(cssFilename: str, instanceTitle: str,
sk['occupationalCategory']['codeValue']
categoryUrl = \
'https://www.onetonline.org/link/summary/' + category
- skillsMarkup += ' {\n'
- skillsMarkup += ' "@type": "Role",\n'
- skillsMarkup += ' "hasOccupation": {\n'
- skillsMarkup += ' "@type": "Occupation",\n'
- skillsMarkup += ' "name": "' + roleName + '",\n'
- skillsMarkup += ' "description": ' + \
- '"Fediverse instance role",\n'
- skillsMarkup += ' "occupationLocation": {\n'
- skillsMarkup += \
- ' "@type": "City",\n'
- skillsMarkup += \
- ' "name": "' + city + '"\n'
- skillsMarkup += ' },\n'
- skillsMarkup += ' "occupationalCategory": {\n'
- skillsMarkup += ' "@type": "CategoryCode",\n'
- skillsMarkup += ' "inCodeSet": {\n'
- skillsMarkup += \
- ' "@type": "CategoryCodeSet",\n'
- skillsMarkup += ' "name": "O*Net-SOC",\n'
- skillsMarkup += ' "dateModified": "2019",\n'
skillsMarkup += \
+ ' {\n' + \
+ ' "@type": "Role",\n' + \
+ ' "hasOccupation": {\n' + \
+ ' "@type": "Occupation",\n' + \
+ ' "name": "' + roleName + '",\n' + \
+ ' "description": ' + \
+ '"Fediverse instance role",\n' + \
+ ' "occupationLocation": {\n' + \
+ ' "@type": "City",\n' + \
+ ' "name": "' + city + '"\n' + \
+ ' },\n' + \
+ ' "occupationalCategory": {\n' + \
+ ' "@type": "CategoryCode",\n' + \
+ ' "inCodeSet": {\n' + \
+ ' "@type": "CategoryCodeSet",\n' + \
+ ' "name": "O*Net-SOC",\n' + \
+ ' "dateModified": "2019",\n' + \
' ' + \
- '"url": "https://www.onetonline.org/"\n'
- skillsMarkup += ' },\n'
- skillsMarkup += \
- ' "codeValue": "' + category + '",\n'
- skillsMarkup += \
- ' "url": "' + categoryUrl + '"\n'
- skillsMarkup += ' }\n'
- skillsMarkup += ' }\n'
- skillsMarkup += ' }'
+ '"url": "https://www.onetonline.org/"\n' + \
+ ' },\n' + \
+ ' "codeValue": "' + category + '",\n' + \
+ ' "url": "' + categoryUrl + '"\n' + \
+ ' }\n' + \
+ ' }\n' + \
+ ' }'
elif skillDict['@type'] == 'Occupation':
if not firstEntry:
skillsMarkup += ',\n'
@@ -555,19 +551,18 @@ def htmlHeaderWithPersonMarkup(cssFilename: str, instanceTitle: str,
skillsListStr += ', '
skillsListStr += '"' + skillStr + '"'
skillsListStr += ']'
- skillsMarkup += ' {\n'
- skillsMarkup += ' "@type": "Occupation",\n'
- skillsMarkup += ' "name": "' + ocName + '",\n'
- skillsMarkup += ' "description": ' + \
- '"Fediverse instance occupation",\n'
- skillsMarkup += ' "occupationLocation": {\n'
- skillsMarkup += ' "@type": "City",\n'
skillsMarkup += \
- ' "name": "' + city + '"\n'
- skillsMarkup += ' },\n'
- skillsMarkup += \
- ' "skills": ' + skillsListStr + '\n'
- skillsMarkup += ' }'
+ ' {\n' + \
+ ' "@type": "Occupation",\n' + \
+ ' "name": "' + ocName + '",\n' + \
+ ' "description": ' + \
+ '"Fediverse instance occupation",\n' + \
+ ' "occupationLocation": {\n' + \
+ ' "@type": "City",\n' + \
+ ' "name": "' + city + '"\n' + \
+ ' },\n' + \
+ ' "skills": ' + skillsListStr + '\n' + \
+ ' }'
firstEntry = False
skillsMarkup += '\n ],\n'
diff --git a/webapp_welcome_final.py b/webapp_welcome_final.py
index 0b6491c47..de5940199 100644
--- a/webapp_welcome_final.py
+++ b/webapp_welcome_final.py
@@ -63,19 +63,17 @@ def htmlWelcomeFinal(baseDir: str, nickname: str, domain: str,
finalForm = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
- finalForm += '' + finalText + '
\n'
finalForm += \
+ '' + finalText + '
\n' + \
'\n'
finalForm += htmlFooter()
diff --git a/webfinger.py b/webfinger.py
index c82a5199c..6a31c5833 100644
--- a/webfinger.py
+++ b/webfinger.py
@@ -174,18 +174,19 @@ def webfingerNodeInfo(httpPrefix: str, domainFull: str) -> {}:
def webfingerMeta(httpPrefix: str, domainFull: str) -> str:
"""Return /.well-known/host-meta
"""
- metaStr = ""
- metaStr += ""
- metaStr += ""
- metaStr += "" + domainFull + ""
- metaStr += ""
- metaStr += ""
- metaStr += " Resource Descriptor"
- metaStr += " "
- metaStr += ""
+ metaStr = \
+ "" + \
+ "" + \
+ "" + \
+ "" + domainFull + "" + \
+ "" + \
+ "" + \
+ " Resource Descriptor" + \
+ " " + \
+ ""
return metaStr
@@ -264,18 +265,28 @@ def _webfingerUpdateFromProfile(wfJson: {}, actorJson: {}) -> bool:
"matrix": "matrix",
"email": "mailto",
"ssb": "ssb",
+ "briar": "briar",
+ "cwtch": "cwtch",
+ "jami": "jami",
"tox": "toxId"
}
+ aliasesNotFound = []
+ for name, alias in webfingerPropertyName.items():
+ aliasesNotFound.append(alias)
+
for propertyValue in actorJson['attachment']:
if not propertyValue.get('name'):
continue
propertyName = propertyValue['name'].lower()
- if not (propertyName.startswith('ssb') or
- propertyName.startswith('xmpp') or
- propertyName.startswith('matrix') or
- propertyName.startswith('email') or
- propertyName.startswith('tox')):
+ found = False
+ for name, alias in webfingerPropertyName.items():
+ if name == propertyName:
+ if alias in aliasesNotFound:
+ aliasesNotFound.remove(alias)
+ found = True
+ break
+ if not found:
continue
if not propertyValue.get('type'):
continue
@@ -285,6 +296,9 @@ def _webfingerUpdateFromProfile(wfJson: {}, actorJson: {}) -> bool:
continue
newValue = propertyValue['value'].strip()
+ if '://' in newValue:
+ newValue = newValue.split('://')[1]
+
aliasIndex = 0
found = False
for alias in wfJson['aliases']:
@@ -300,6 +314,17 @@ def _webfingerUpdateFromProfile(wfJson: {}, actorJson: {}) -> bool:
else:
wfJson['aliases'].append(newAlias)
changed = True
+
+ # remove any aliases which are no longer in the actor profile
+ removeAlias = []
+ for alias in aliasesNotFound:
+ for fullAlias in wfJson['aliases']:
+ if fullAlias.startswith(alias + ':'):
+ removeAlias.append(fullAlias)
+ for fullAlias in removeAlias:
+ wfJson['aliases'].remove(fullAlias)
+ changed = True
+
return changed