Create html for posts sent to the outbox

merge-requests/30/head
Bob Mottram 2021-09-03 12:30:23 +01:00
parent 46b8f60dfc
commit e819c28b03
6 changed files with 178 additions and 52 deletions

View File

@ -1195,7 +1195,11 @@ class PubServer(BaseHTTPRequestHandler):
self.server.sharedItemsFederatedDomains, self.server.sharedItemsFederatedDomains,
self.server.sharedItemFederationTokens, self.server.sharedItemFederationTokens,
self.server.lowBandwidth, self.server.lowBandwidth,
self.server.signingPrivateKeyPem) self.server.signingPrivateKeyPem,
self.server.peertubeInstances,
self.server.themeName,
self.server.maxLikeCount,
self.server.maxRecentPosts)
def _postToOutboxThread(self, messageJson: {}) -> bool: def _postToOutboxThread(self, messageJson: {}) -> bool:
"""Creates a thread to send a post """Creates a thread to send a post

View File

@ -2025,6 +2025,7 @@ def inboxUpdateIndex(boxname: str, baseDir: str, handle: str,
if '/' in destinationFilename: if '/' in destinationFilename:
destinationFilename = destinationFilename.split('/')[-1] destinationFilename = destinationFilename.split('/')[-1]
written = False
if os.path.isfile(indexFilename): if os.path.isfile(indexFilename):
try: try:
with open(indexFilename, 'r+') as indexFile: with open(indexFilename, 'r+') as indexFile:
@ -2032,6 +2033,7 @@ def inboxUpdateIndex(boxname: str, baseDir: str, handle: str,
if destinationFilename + '\n' not in content: if destinationFilename + '\n' not in content:
indexFile.seek(0, 0) indexFile.seek(0, 0)
indexFile.write(destinationFilename + '\n' + content) indexFile.write(destinationFilename + '\n' + content)
written = True
return True return True
except Exception as e: except Exception as e:
print('WARN: Failed to write entry to index ' + str(e)) print('WARN: Failed to write entry to index ' + str(e))
@ -2039,10 +2041,11 @@ def inboxUpdateIndex(boxname: str, baseDir: str, handle: str,
try: try:
with open(indexFilename, 'w+') as indexFile: with open(indexFilename, 'w+') as indexFile:
indexFile.write(destinationFilename + '\n') indexFile.write(destinationFilename + '\n')
written = True
except Exception as e: except Exception as e:
print('WARN: Failed to write initial entry to index ' + str(e)) print('WARN: Failed to write initial entry to index ' + str(e))
return False return written
def _updateLastSeen(baseDir: str, handle: str, actor: str) -> None: def _updateLastSeen(baseDir: str, handle: str, actor: str) -> None:

View File

@ -40,6 +40,7 @@ from inbox import inboxUpdateIndex
from announce import outboxAnnounce from announce import outboxAnnounce
from announce import outboxUndoAnnounce from announce import outboxUndoAnnounce
from follow import outboxUndoFollow from follow import outboxUndoFollow
from follow import followerApprovalActive
from skills import outboxSkills from skills import outboxSkills
from availability import outboxAvailability from availability import outboxAvailability
from like import outboxLike from like import outboxLike
@ -49,6 +50,7 @@ from bookmarks import outboxUndoBookmark
from delete import outboxDelete from delete import outboxDelete
from shares import outboxShareUpload from shares import outboxShareUpload
from shares import outboxUndoShareUpload from shares import outboxUndoShareUpload
from webapp_post import individualPostAsHtml
def _outboxPersonReceiveUpdate(recentPostsCache: {}, def _outboxPersonReceiveUpdate(recentPostsCache: {},
@ -195,7 +197,10 @@ def postMessageToOutbox(session, translate: {},
sharedItemsFederatedDomains: [], sharedItemsFederatedDomains: [],
sharedItemFederationTokens: {}, sharedItemFederationTokens: {},
lowBandwidth: bool, lowBandwidth: bool,
signingPrivateKeyPem: str) -> bool: signingPrivateKeyPem: str,
peertubeInstances: str, theme: str,
maxLikeCount: int,
maxRecentPosts: int) -> bool:
"""post is received by the outbox """post is received by the outbox
Client to server message post Client to server message post
https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery
@ -425,6 +430,36 @@ def postMessageToOutbox(session, translate: {},
inboxUpdateIndex(boxNameIndex, baseDir, inboxUpdateIndex(boxNameIndex, baseDir,
postToNickname + '@' + domain, postToNickname + '@' + domain,
savedFilename, debug) savedFilename, debug)
# regenerate the html
useCacheOnly = False
pageNumber = 1
showIndividualPostIcons = True
manuallyApproveFollowers = \
followerApprovalActive(baseDir, postToNickname, domain)
individualPostAsHtml(signingPrivateKeyPem,
False, recentPostsCache,
maxRecentPosts,
translate, pageNumber,
baseDir, session,
cachedWebfingers,
personCache,
postToNickname, domain, port,
messageJson, None, True,
allowDeletion,
httpPrefix, __version__,
boxNameIndex,
YTReplacementDomain,
showPublishedDateOnly,
peertubeInstances,
allowLocalNetworkAccess,
theme, systemLanguage,
maxLikeCount,
boxNameIndex != 'dm',
showIndividualPostIcons,
manuallyApproveFollowers,
False, True, useCacheOnly)
if outboxAnnounce(recentPostsCache, if outboxAnnounce(recentPostsCache,
baseDir, messageJson, debug): baseDir, messageJson, debug):
if debug: if debug:

View File

@ -116,7 +116,11 @@ def _updatePostSchedule(baseDir: str, handle: str, httpd,
httpd.sharedItemsFederatedDomains, httpd.sharedItemsFederatedDomains,
httpd.sharedItemFederationTokens, httpd.sharedItemFederationTokens,
httpd.lowBandwidth, httpd.lowBandwidth,
httpd.signingPrivateKeyPem): httpd.signingPrivateKeyPem,
httpd.peertubeInstances,
httpd.themeName,
httpd.maxLikeCount,
httpd.maxRecentPosts):
indexLines.remove(line) indexLines.remove(line)
os.remove(postFilename) os.remove(postFilename)
continue continue

View File

@ -2874,7 +2874,7 @@ def testClientToServer():
showTestBoxes('alice', aliceInboxPath, aliceOutboxPath) showTestBoxes('alice', aliceInboxPath, aliceOutboxPath)
showTestBoxes('bob', bobInboxPath, bobOutboxPath) showTestBoxes('bob', bobInboxPath, bobOutboxPath)
assert len([name for name in os.listdir(bobOutboxPath) assert len([name for name in os.listdir(bobOutboxPath)
if os.path.isfile(os.path.join(bobOutboxPath, name))]) == 3 if os.path.isfile(os.path.join(bobOutboxPath, name))]) == 4
assert len([name for name in os.listdir(aliceInboxPath) assert len([name for name in os.listdir(aliceInboxPath)
if os.path.isfile(os.path.join(aliceInboxPath, name))]) == 1 if os.path.isfile(os.path.join(aliceInboxPath, name))]) == 1
print('EVENT: Post repeated') print('EVENT: Post repeated')

View File

@ -245,13 +245,20 @@ def _getAvatarImageHtml(showAvatarOptions: bool,
avatarLink = '' avatarLink = ''
if '/users/news/' not in avatarUrl: if '/users/news/' not in avatarUrl:
avatarLink = ' <a class="imageAnchor" href="' + postActor + '">' avatarLink = ' <a class="imageAnchor" href="' + postActor + '">'
showProfileStr = 'Show profile'
if translate.get(showProfileStr):
showProfileStr = translate[showProfileStr]
avatarLink += \ avatarLink += \
'<img loading="lazy" src="' + avatarUrl + '" title="' + \ '<img loading="lazy" src="' + avatarUrl + '" title="' + \
translate['Show profile'] + '" alt=" "' + avatarPosition + \ showProfileStr + '" alt=" "' + avatarPosition + \
getBrokenLinkSubstitute() + '/></a>\n' getBrokenLinkSubstitute() + '/></a>\n'
if showAvatarOptions and \ if showAvatarOptions and \
domainFull + '/users/' + nickname not in postActor: domainFull + '/users/' + nickname not in postActor:
showOptionsForThisPersonStr = 'Show options for this person'
if translate.get(showOptionsForThisPersonStr):
showOptionsForThisPersonStr = \
translate[showOptionsForThisPersonStr]
if '/users/news/' not in avatarUrl: if '/users/news/' not in avatarUrl:
avatarLink = \ avatarLink = \
' <a class="imageAnchor" href="/users/' + \ ' <a class="imageAnchor" href="/users/' + \
@ -259,18 +266,18 @@ def _getAvatarImageHtml(showAvatarOptions: bool,
';' + str(pageNumber) + ';' + avatarUrl + messageIdStr + '">\n' ';' + str(pageNumber) + ';' + avatarUrl + messageIdStr + '">\n'
avatarLink += \ avatarLink += \
' <img loading="lazy" title="' + \ ' <img loading="lazy" title="' + \
translate['Show options for this person'] + '" ' + \ showOptionsForThisPersonStr + '" ' + \
'alt="👤 ' + \ 'alt="👤 ' + \
translate['Show options for this person'] + '" ' + \ showOptionsForThisPersonStr + '" ' + \
'src="' + avatarUrl + '" ' + avatarPosition + \ 'src="' + avatarUrl + '" ' + avatarPosition + \
getBrokenLinkSubstitute() + '/></a>\n' getBrokenLinkSubstitute() + '/></a>\n'
else: else:
# don't link to the person options for the news account # don't link to the person options for the news account
avatarLink += \ avatarLink += \
' <img loading="lazy" title="' + \ ' <img loading="lazy" title="' + \
translate['Show options for this person'] + '" ' + \ showOptionsForThisPersonStr + '" ' + \
'alt="👤 ' + \ 'alt="👤 ' + \
translate['Show options for this person'] + '" ' + \ showOptionsForThisPersonStr + '" ' + \
'src="' + avatarUrl + '" ' + avatarPosition + \ 'src="' + avatarUrl + '" ' + avatarPosition + \
getBrokenLinkSubstitute() + '/>\n' getBrokenLinkSubstitute() + '/>\n'
return avatarLink.strip() return avatarLink.strip()
@ -305,7 +312,9 @@ def _getReplyIconHtml(nickname: str, isPublicRepeat: bool,
replyToLink += pageNumberParam replyToLink += pageNumberParam
replyStr = '' replyStr = ''
replyToThisPostStr = translate['Reply to this post'] replyToThisPostStr = 'Reply to this post'
if translate.get(replyToThisPostStr):
replyToThisPostStr = translate[replyToThisPostStr]
conversationStr = '' conversationStr = ''
if conversationId: if conversationId:
conversationStr = '?conversationId=' + conversationId conversationStr = '?conversationId=' + conversationId
@ -363,7 +372,9 @@ def _getEditIconHtml(baseDir: str, nickname: str, domainFull: str,
return editStr return editStr
if isBlogPost(postJsonObject): if isBlogPost(postJsonObject):
editBlogPostStr = translate['Edit blog post'] editBlogPostStr = 'Edit blog post'
if translate.get(editBlogPostStr):
editBlogPostStr = translate[editBlogPostStr]
if not isNewsPost(postJsonObject): if not isNewsPost(postJsonObject):
editStr += \ editStr += \
' ' + \ ' ' + \
@ -388,7 +399,9 @@ def _getEditIconHtml(baseDir: str, nickname: str, domainFull: str,
editBlogPostStr + '" alt="' + editBlogPostStr + \ editBlogPostStr + '" alt="' + editBlogPostStr + \
' |" src="/icons/edit.png"/></a>\n' ' |" src="/icons/edit.png"/></a>\n'
elif isEvent: elif isEvent:
editEventStr = translate['Edit event'] editEventStr = 'Edit event'
if translate.get(editEventStr):
editEventStr = translate[editEventStr]
editStr += \ editStr += \
' ' + \ ' ' + \
'<a class="imageAnchor" href="/users/' + nickname + \ '<a class="imageAnchor" href="/users/' + nickname + \
@ -430,7 +443,10 @@ def _getAnnounceIconHtml(isAnnounced: bool,
announceEmoji = '' announceEmoji = ''
if not isPublicRepeat: if not isPublicRepeat:
announceLink = 'repeatprivate' announceLink = 'repeatprivate'
announceTitle = translate['Repeat this post'] repeatThisPostStr = 'Repeat this post'
if translate.get(repeatThisPostStr):
repeatThisPostStr = translate[repeatThisPostStr]
announceTitle = repeatThisPostStr
unannounceLinkStr = '' unannounceLinkStr = ''
if announcedByPerson(isAnnounced, if announcedByPerson(isAnnounced,
@ -440,7 +456,10 @@ def _getAnnounceIconHtml(isAnnounced: bool,
announceLink = 'unrepeat' announceLink = 'unrepeat'
if not isPublicRepeat: if not isPublicRepeat:
announceLink = 'unrepeatprivate' announceLink = 'unrepeatprivate'
announceTitle = translate['Undo the repeat'] undoTheRepeatStr = 'Undo the repeat'
if translate.get(undoTheRepeatStr):
undoTheRepeatStr = translate[undoTheRepeatStr]
announceTitle = undoTheRepeatStr
if announceJsonObject: if announceJsonObject:
unannounceLinkStr = '?unannounce=' + \ unannounceLinkStr = '?unannounce=' + \
removeIdEnding(announceJsonObject['id']) removeIdEnding(announceJsonObject['id'])
@ -478,7 +497,9 @@ def _getLikeIconHtml(nickname: str, domainFull: str,
if not isModerationPost and showLikeButton: if not isModerationPost and showLikeButton:
likeIcon = 'like_inactive.png' likeIcon = 'like_inactive.png'
likeLink = 'like' likeLink = 'like'
likeTitle = translate['Like this post'] likeTitle = 'Like this post'
if translate.get(likeTitle):
likeTitle = translate[likeTitle]
likeEmoji = '' likeEmoji = ''
likeCount = noOfLikes(postJsonObject) likeCount = noOfLikes(postJsonObject)
@ -496,7 +517,9 @@ def _getLikeIconHtml(nickname: str, domainFull: str,
likeCountStr = '' likeCountStr = ''
likeIcon = 'like.png' likeIcon = 'like.png'
likeLink = 'unlike' likeLink = 'unlike'
likeTitle = translate['Undo the like'] likeTitle = 'Undo the like'
if translate.get(likeTitle):
likeTitle = translate[likeTitle]
likeEmoji = '👍 ' likeEmoji = '👍 '
_logPostTiming(enableTimingLog, postStartTime, '12.2') _logPostTiming(enableTimingLog, postStartTime, '12.2')
@ -541,12 +564,16 @@ def _getBookmarkIconHtml(nickname: str, domainFull: str,
bookmarkIcon = 'bookmark_inactive.png' bookmarkIcon = 'bookmark_inactive.png'
bookmarkLink = 'bookmark' bookmarkLink = 'bookmark'
bookmarkEmoji = '' bookmarkEmoji = ''
bookmarkTitle = translate['Bookmark this post'] bookmarkTitle = 'Bookmark this post'
if translate.get(bookmarkTitle):
bookmarkTitle = translate[bookmarkTitle]
if bookmarkedByPerson(postJsonObject, nickname, domainFull): if bookmarkedByPerson(postJsonObject, nickname, domainFull):
bookmarkIcon = 'bookmark.png' bookmarkIcon = 'bookmark.png'
bookmarkLink = 'unbookmark' bookmarkLink = 'unbookmark'
bookmarkEmoji = '🔖 ' bookmarkEmoji = '🔖 '
bookmarkTitle = translate['Undo the bookmark'] bookmarkTitle = 'Undo the bookmark'
if translate.get(bookmarkTitle):
bookmarkTitle = translate[bookmarkTitle]
_logPostTiming(enableTimingLog, postStartTime, '12.6') _logPostTiming(enableTimingLog, postStartTime, '12.6')
bookmarkStr = \ bookmarkStr = \
' <a class="imageAnchor" href="/users/' + nickname + '?' + \ ' <a class="imageAnchor" href="/users/' + nickname + '?' + \
@ -581,28 +608,33 @@ def _getMuteIconHtml(isMuted: bool,
return muteStr return muteStr
if not isMuted: if not isMuted:
muteThisPostStr = 'Mute this post'
if translate.get('Mute this post'):
muteThisPostStr = translate[muteThisPostStr]
muteStr = \ muteStr = \
' <a class="imageAnchor" href="/users/' + nickname + \ ' <a class="imageAnchor" href="/users/' + nickname + \
'?mute=' + messageId + pageNumberParam + '?tl=' + boxName + \ '?mute=' + messageId + pageNumberParam + '?tl=' + boxName + \
'?bm=' + timelinePostBookmark + \ '?bm=' + timelinePostBookmark + \
'" title="' + translate['Mute this post'] + '">\n' '" title="' + muteThisPostStr + '">\n'
muteStr += \ muteStr += \
' ' + \ ' ' + \
'<img loading="lazy" alt="' + \ '<img loading="lazy" alt="' + \
translate['Mute this post'] + \ muteThisPostStr + \
' |" title="' + translate['Mute this post'] + \ ' |" title="' + muteThisPostStr + \
'" src="/icons/mute.png"/></a>\n' '" src="/icons/mute.png"/></a>\n'
else: else:
undoMuteStr = 'Undo mute'
if translate.get(undoMuteStr):
undoMuteStr = translate[undoMuteStr]
muteStr = \ muteStr = \
' <a class="imageAnchor" href="/users/' + \ ' <a class="imageAnchor" href="/users/' + \
nickname + '?unmute=' + messageId + \ nickname + '?unmute=' + messageId + \
pageNumberParam + '?tl=' + boxName + '?bm=' + \ pageNumberParam + '?tl=' + boxName + '?bm=' + \
timelinePostBookmark + '" title="' + \ timelinePostBookmark + '" title="' + undoMuteStr + '">\n'
translate['Undo mute'] + '">\n'
muteStr += \ muteStr += \
' ' + \ ' ' + \
'<img loading="lazy" alt="🔇 ' + translate['Undo mute'] + \ '<img loading="lazy" alt="🔇 ' + undoMuteStr + \
' |" title="' + translate['Undo mute'] + \ ' |" title="' + undoMuteStr + \
'" src="/icons/unmute.png"/></a>\n' '" src="/icons/unmute.png"/></a>\n'
return muteStr return muteStr
@ -622,16 +654,19 @@ def _getDeleteIconHtml(nickname: str, domainFull: str,
messageId.startswith(postActor))): messageId.startswith(postActor))):
if '/users/' + nickname + '/' in messageId: if '/users/' + nickname + '/' in messageId:
if not isNewsPost(postJsonObject): if not isNewsPost(postJsonObject):
deleteThisPostStr = 'Delete this post'
if translate.get(deleteThisPostStr):
deleteThisPostStr = translate[deleteThisPostStr]
deleteStr = \ deleteStr = \
' <a class="imageAnchor" href="/users/' + \ ' <a class="imageAnchor" href="/users/' + \
nickname + \ nickname + \
'?delete=' + messageId + pageNumberParam + \ '?delete=' + messageId + pageNumberParam + \
'" title="' + translate['Delete this post'] + '">\n' '" title="' + deleteThisPostStr + '">\n'
deleteStr += \ deleteStr += \
' ' + \ ' ' + \
'<img loading="lazy" alt="' + \ '<img loading="lazy" alt="' + \
translate['Delete this post'] + \ deleteThisPostStr + \
' |" title="' + translate['Delete this post'] + \ ' |" title="' + deleteThisPostStr + \
'" src="/icons/delete.png"/></a>\n' '" src="/icons/delete.png"/></a>\n'
return deleteStr return deleteStr
@ -699,7 +734,10 @@ def _getBlogCitationsHtml(boxName: str,
'<cite>' + tagJson['name'] + '</cite></a></li>\n' '<cite>' + tagJson['name'] + '</cite></a></li>\n'
if citationsStr: if citationsStr:
citationsStr = '<p><b>' + translate['Citations'] + ':</b></p>' + \ translatedCitationsStr = 'Citations'
if translate.get(translatedCitationsStr):
translatedCitationsStr = translate[translatedCitationsStr]
citationsStr = '<p><b>' + translatedCitationsStr + ':</b></p>' + \
'<ul>\n' + citationsStr + '</ul>\n' '<ul>\n' + citationsStr + '</ul>\n'
return citationsStr return citationsStr
@ -707,9 +745,12 @@ def _getBlogCitationsHtml(boxName: str,
def _boostOwnPostHtml(translate: {}) -> str: def _boostOwnPostHtml(translate: {}) -> str:
"""The html title for announcing your own post """The html title for announcing your own post
""" """
announcesStr = 'announces'
if translate.get(announcesStr):
announcesStr = translate[announcesStr]
return ' <img loading="lazy" title="' + \ return ' <img loading="lazy" title="' + \
translate['announces'] + \ announcesStr + \
'" alt="' + translate['announces'] + \ '" alt="' + announcesStr + \
'" src="/icons' + \ '" src="/icons' + \
'/repeat_inactive.png" class="announceOrReply"/>\n' '/repeat_inactive.png" class="announceOrReply"/>\n'
@ -719,9 +760,12 @@ def _announceUnattributedHtml(translate: {},
"""Returns the html for an announce title where there """Returns the html for an announce title where there
is no attribution on the announced post is no attribution on the announced post
""" """
announcesStr = 'announces'
if translate.get(announcesStr):
announcesStr = translate[announcesStr]
return ' <img loading="lazy" title="' + \ return ' <img loading="lazy" title="' + \
translate['announces'] + '" alt="' + \ announcesStr + '" alt="' + \
translate['announces'] + '" src="/icons' + \ announcesStr + '" src="/icons' + \
'/repeat_inactive.png" ' + \ '/repeat_inactive.png" ' + \
'class="announceOrReply"/>\n' + \ 'class="announceOrReply"/>\n' + \
' <a href="' + \ ' <a href="' + \
@ -734,9 +778,12 @@ def _announceWithDisplayNameHtml(translate: {},
announceDisplayName: str) -> str: announceDisplayName: str) -> str:
"""Returns html for an announce having a display name """Returns html for an announce having a display name
""" """
announcesStr = 'announces'
if translate.get(announcesStr):
announcesStr = translate[announcesStr]
return ' <img loading="lazy" title="' + \ return ' <img loading="lazy" title="' + \
translate['announces'] + '" alt="' + \ announcesStr + '" alt="' + \
translate['announces'] + '" src="/' + \ announcesStr + '" src="/' + \
'icons/repeat_inactive.png" ' + \ 'icons/repeat_inactive.png" ' + \
'class="announceOrReply"/>\n' + \ 'class="announceOrReply"/>\n' + \
' <a href="' + \ ' <a href="' + \
@ -825,6 +872,9 @@ def _getPostTitleAnnounceHtml(baseDir: str,
idx = 'Show options for this person' idx = 'Show options for this person'
if '/users/news/' not in announceAvatarUrl: if '/users/news/' not in announceAvatarUrl:
showOptionsForThisPersonStr = idx
if translate.get(idx):
showOptionsForThisPersonStr = translate[idx]
replyAvatarImageInPost = \ replyAvatarImageInPost = \
' <div class="timeline-avatar-reply">\n' \ ' <div class="timeline-avatar-reply">\n' \
' <a class="imageAnchor" ' + \ ' <a class="imageAnchor" ' + \
@ -832,7 +882,8 @@ def _getPostTitleAnnounceHtml(baseDir: str,
announceActor + ';' + str(pageNumber) + \ announceActor + ';' + str(pageNumber) + \
';' + announceAvatarUrl + messageIdStr + '">' \ ';' + announceAvatarUrl + messageIdStr + '">' \
'<img loading="lazy" src="' + announceAvatarUrl + '" ' + \ '<img loading="lazy" src="' + announceAvatarUrl + '" ' + \
'title="' + translate[idx] + '" alt=" "' + avatarPosition + \ 'title="' + showOptionsForThisPersonStr + \
'" alt=" "' + avatarPosition + \
getBrokenLinkSubstitute() + '/></a>\n </div>\n' getBrokenLinkSubstitute() + '/></a>\n </div>\n'
return (titleStr, replyAvatarImageInPost, return (titleStr, replyAvatarImageInPost,
@ -842,9 +893,12 @@ def _getPostTitleAnnounceHtml(baseDir: str,
def _replyToYourselfHtml(translate: {}) -> str: def _replyToYourselfHtml(translate: {}) -> str:
"""Returns html for a title which is a reply to yourself """Returns html for a title which is a reply to yourself
""" """
replyingToThemselvesStr = 'replying to themselves'
if translate.get(replyingToThemselvesStr):
replyingToThemselvesStr = translate[replyingToThemselvesStr]
return ' <img loading="lazy" title="' + \ return ' <img loading="lazy" title="' + \
translate['replying to themselves'] + \ replyingToThemselvesStr + \
'" alt="' + translate['replying to themselves'] + \ '" alt="' + replyingToThemselvesStr + \
'" src="/icons' + \ '" src="/icons' + \
'/reply.png" class="announceOrReply"/>\n' '/reply.png" class="announceOrReply"/>\n'
@ -853,9 +907,12 @@ def _replyToUnknownHtml(translate: {},
postJsonObject: {}) -> str: postJsonObject: {}) -> str:
"""Returns the html title for a reply to an unknown handle """Returns the html title for a reply to an unknown handle
""" """
replyingToStr = 'replying to'
if translate.get(replyingToStr):
replyingToStr = translate[replyingToStr]
return ' <img loading="lazy" title="' + \ return ' <img loading="lazy" title="' + \
translate['replying to'] + '" alt="' + \ replyingToStr + '" alt="' + \
translate['replying to'] + '" src="/icons' + \ replyingToStr + '" src="/icons' + \
'/reply.png" class="announceOrReply"/>\n' + \ '/reply.png" class="announceOrReply"/>\n' + \
' <a href="' + \ ' <a href="' + \
postJsonObject['object']['inReplyTo'] + \ postJsonObject['object']['inReplyTo'] + \
@ -868,9 +925,12 @@ def _replyWithUnknownPathHtml(translate: {},
"""Returns html title for a reply with an unknown path """Returns html title for a reply with an unknown path
eg. does not contain /statuses/ eg. does not contain /statuses/
""" """
replyingToStr = 'replying to'
if translate.get(replyingToStr):
replyingToStr = translate[replyingToStr]
return ' <img loading="lazy" title="' + \ return ' <img loading="lazy" title="' + \
translate['replying to'] + \ replyingToStr + \
'" alt="' + translate['replying to'] + \ '" alt="' + replyingToStr + \
'" src="/icons/reply.png" ' + \ '" src="/icons/reply.png" ' + \
'class="announceOrReply"/>\n' + \ 'class="announceOrReply"/>\n' + \
' <a href="' + \ ' <a href="' + \
@ -883,10 +943,13 @@ def _getReplyHtml(translate: {},
inReplyTo: str, replyDisplayName: str) -> str: inReplyTo: str, replyDisplayName: str) -> str:
"""Returns html title for a reply """Returns html title for a reply
""" """
replyingToStr = 'replying to'
if translate.get(replyingToStr):
replyingToStr = translate[replyingToStr]
return ' ' + \ return ' ' + \
'<img loading="lazy" title="' + \ '<img loading="lazy" title="' + \
translate['replying to'] + '" alt="' + \ replyingToStr + '" alt="' + \
translate['replying to'] + '" src="/' + \ replyingToStr + '" src="/' + \
'icons/reply.png" ' + \ 'icons/reply.png" ' + \
'class="announceOrReply"/>\n' + \ 'class="announceOrReply"/>\n' + \
' <a href="' + inReplyTo + \ ' <a href="' + inReplyTo + \
@ -987,6 +1050,9 @@ def _getPostTitleReplyHtml(baseDir: str,
_logPostTiming(enableTimingLog, postStartTime, '13.8') _logPostTiming(enableTimingLog, postStartTime, '13.8')
if replyAvatarUrl: if replyAvatarUrl:
showProfileStr = 'Show profile'
if translate.get(showProfileStr):
showProfileStr = translate[showProfileStr]
replyAvatarImageInPost = \ replyAvatarImageInPost = \
' <div class="timeline-avatar-reply">\n' + \ ' <div class="timeline-avatar-reply">\n' + \
' <a class="imageAnchor" ' + \ ' <a class="imageAnchor" ' + \
@ -994,7 +1060,7 @@ def _getPostTitleReplyHtml(baseDir: str,
';' + str(pageNumber) + ';' + replyAvatarUrl + \ ';' + str(pageNumber) + ';' + replyAvatarUrl + \
messageIdStr + '">\n' + \ messageIdStr + '">\n' + \
' <img loading="lazy" src="' + replyAvatarUrl + '" ' + \ ' <img loading="lazy" src="' + replyAvatarUrl + '" ' + \
'title="' + translate['Show profile'] + \ 'title="' + showProfileStr + \
'" alt=" "' + avatarPosition + getBrokenLinkSubstitute() + \ '" alt=" "' + avatarPosition + getBrokenLinkSubstitute() + \
'/></a>\n </div>\n' '/></a>\n </div>\n'
@ -1542,7 +1608,10 @@ def individualPostAsHtml(signingPrivateKeyPem: str,
postIsSensitive = postJsonObject['object']['sensitive'] postIsSensitive = postJsonObject['object']['sensitive']
else: else:
# add a generic summary if none is provided # add a generic summary if none is provided
postJsonObject['object']['summary'] = translate['Sensitive'] sensitiveStr = 'Sensitive'
if translate.get(sensitiveStr):
sensitiveStr = translate[sensitiveStr]
postJsonObject['object']['summary'] = sensitiveStr
# add an extra line if there is a content warning, # add an extra line if there is a content warning,
# for better vertical spacing on mobile # for better vertical spacing on mobile
@ -1594,7 +1663,10 @@ def individualPostAsHtml(signingPrivateKeyPem: str,
else: else:
objectContent = contentStr objectContent = contentStr
else: else:
objectContent = '🔒 ' + translate['Encrypted'] encryptedStr = 'Encrypted'
if translate.get(encryptedStr):
encryptedStr = translate[encryptedStr]
objectContent = '🔒 ' + encryptedStr
objectContent = '<article>' + objectContent + '</article>' objectContent = '<article>' + objectContent + '</article>'
@ -1711,9 +1783,11 @@ def htmlIndividualPost(cssCache: {},
likedByDomain, likedByPort = getDomainFromActor(likedBy) likedByDomain, likedByPort = getDomainFromActor(likedBy)
likedByDomain = getFullDomain(likedByDomain, likedByPort) likedByDomain = getFullDomain(likedByDomain, likedByPort)
likedByHandle = likedByNickname + '@' + likedByDomain likedByHandle = likedByNickname + '@' + likedByDomain
likedByStr = 'Liked by'
if translate.get(likedByStr):
likedByStr = translate[likedByStr]
postStr += \ postStr += \
'<p>' + translate['Liked by'] + \ '<p>' + likedByStr + ' <a href="' + likedBy + '">@' + \
' <a href="' + likedBy + '">@' + \
likedByHandle + '</a>\n' likedByHandle + '</a>\n'
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)
@ -1726,10 +1800,16 @@ def htmlIndividualPost(cssCache: {},
' <input type="hidden" name="searchtext" value="' + \ ' <input type="hidden" name="searchtext" value="' + \
likedByHandle + '">\n' likedByHandle + '">\n'
if not isFollowingActor(baseDir, nickname, domainFull, likedBy): if not isFollowingActor(baseDir, nickname, domainFull, likedBy):
translateFollowStr = 'Follow'
if translate.get(translateFollowStr):
translateFollowStr = translate[translateFollowStr]
followStr += ' <button type="submit" class="button" ' + \ followStr += ' <button type="submit" class="button" ' + \
'name="submitSearch">' + translate['Follow'] + '</button>\n' 'name="submitSearch">' + translateFollowStr + '</button>\n'
goBackStr = 'Go Back'
if translate.get(goBackStr):
goBackStr = translate[goBackStr]
followStr += ' <button type="submit" class="button" ' + \ followStr += ' <button type="submit" class="button" ' + \
'name="submitBack">' + translate['Go Back'] + '</button>\n' 'name="submitBack">' + goBackStr + '</button>\n'
followStr += ' </form>\n' followStr += ' </form>\n'
postStr += followStr + '</p>\n' postStr += followStr + '</p>\n'