epicyon/webapp_timeline.py

1576 lines
68 KiB
Python
Raw Normal View History

2020-11-09 22:44:03 +00:00
__filename__ = "webapp_timeline.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
2021-01-26 10:07:42 +00:00
__version__ = "1.2.0"
2020-11-09 22:44:03 +00:00
__maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
2021-06-15 15:08:12 +00:00
__module_group__ = "Timeline"
2020-11-09 22:44:03 +00:00
import os
import time
from shutil import copyfile
from utils import dangerousMarkup
2021-01-11 19:46:21 +00:00
from utils import getConfigParam
2020-12-16 11:19:16 +00:00
from utils import getFullDomain
2020-12-01 21:44:27 +00:00
from utils import isEditor
2020-11-09 22:44:03 +00:00
from utils import removeIdEnding
2021-07-13 21:59:53 +00:00
from utils import acctDir
2021-07-25 13:09:39 +00:00
from utils import isfloat
2021-08-14 11:13:39 +00:00
from utils import localActorUrl
2020-11-09 22:44:03 +00:00
from follow import followerApprovalActive
from person import isPersonSnoozed
from markdown import markdownToHtml
2021-02-05 17:05:53 +00:00
from webapp_utils import htmlKeyboardNavigation
2021-02-06 10:35:47 +00:00
from webapp_utils import htmlHideFromScreenReader
2020-11-09 22:44:03 +00:00
from webapp_utils import htmlPostSeparator
from webapp_utils import getBannerFile
2020-11-10 15:12:07 +00:00
from webapp_utils import htmlHeaderWithExternalStyle
2020-11-09 22:44:03 +00:00
from webapp_utils import htmlFooter
from webapp_utils import sharesTimelineJson
2020-11-17 20:40:36 +00:00
from webapp_utils import htmlHighlightLabel
2020-11-09 22:44:03 +00:00
from webapp_post import preparePostFromHtmlCache
from webapp_post import individualPostAsHtml
from webapp_column_left import getLeftColumnContent
from webapp_column_right import getRightColumnContent
2020-11-17 20:40:36 +00:00
from webapp_headerbuttons import headerButtonsTimeline
2020-11-09 22:44:03 +00:00
from posts import isModerator
from announce import isSelfAnnounce
2020-11-09 22:44:03 +00:00
def _logTimelineTiming(enableTimingLog: bool, timelineStartTime,
boxName: str, debugId: str) -> None:
2020-12-01 17:23:34 +00:00
"""Create a log of timings for performance tuning
"""
if not enableTimingLog:
return
timeDiff = int((time.time() - timelineStartTime) * 1000)
if timeDiff > 100:
print('TIMELINE TIMING ' +
boxName + ' ' + debugId + ' = ' + str(timeDiff))
def _getHelpForTimeline(baseDir: str, boxName: str) -> str:
"""Shows help text for the given timeline
"""
# get the filename for help for this timeline
helpFilename = baseDir + '/accounts/help_' + boxName + '.md'
if not os.path.isfile(helpFilename):
language = \
getConfigParam(baseDir, 'language')
2021-02-26 12:24:55 +00:00
if not language:
language = 'en'
2021-02-27 10:10:05 +00:00
themeName = \
getConfigParam(baseDir, 'theme')
defaultFilename = None
if themeName:
defaultFilename = \
baseDir + '/theme/' + themeName + '/welcome/' + \
'help_' + boxName + '_' + language + '.md'
if not os.path.isfile(defaultFilename):
defaultFilename = None
if not defaultFilename:
defaultFilename = \
baseDir + '/defaultwelcome/' + \
'help_' + boxName + '_' + language + '.md'
if not os.path.isfile(defaultFilename):
defaultFilename = \
baseDir + '/defaultwelcome/help_' + boxName + '_en.md'
if os.path.isfile(defaultFilename):
copyfile(defaultFilename, helpFilename)
# show help text
if os.path.isfile(helpFilename):
instanceTitle = \
getConfigParam(baseDir, 'instanceTitle')
if not instanceTitle:
instanceTitle = 'Epicyon'
with open(helpFilename, 'r') as helpFile:
helpText = helpFile.read()
if dangerousMarkup(helpText, False):
return ''
helpText = helpText.replace('INSTANCE', instanceTitle)
2021-02-26 12:29:42 +00:00
return '<div class="container">\n' + \
markdownToHtml(helpText) + '\n' + \
2021-02-26 12:42:29 +00:00
'</div>\n'
return ''
2021-06-27 21:40:12 +00:00
def _htmlTimelineNewPost(manuallyApproveFollowers: bool,
boxName: str, iconsAsButtons: bool,
usersPath: str, translate: {}) -> str:
"""Returns html for the new post button
"""
newPostButtonStr = ''
if boxName == 'dm':
if not iconsAsButtons:
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newdm?nodropdown"><img loading="lazy" src="/' + \
'icons/newpost.png" title="' + \
translate['Create a new DM'] + \
'" alt="| ' + translate['Create a new DM'] + \
'" class="timelineicon"/></a>\n'
else:
newPostButtonStr += \
'<a href="' + usersPath + '/newdm?nodropdown">' + \
'<button class="button"><span>' + \
translate['Post'] + ' </span></button></a>'
elif (boxName == 'tlblogs' or
boxName == 'tlnews' or
boxName == 'tlfeatures'):
if not iconsAsButtons:
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newblog"><img loading="lazy" src="/' + \
'icons/newpost.png" title="' + \
translate['Create a new post'] + '" alt="| ' + \
translate['Create a new post'] + \
'" class="timelineicon"/></a>\n'
else:
newPostButtonStr += \
'<a href="' + usersPath + '/newblog">' + \
'<button class="button"><span>' + \
translate['Post'] + '</span></button></a>'
elif boxName == 'tlshares':
if not iconsAsButtons:
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newshare?nodropdown"><img loading="lazy" src="/' + \
'icons/newpost.png" title="' + \
translate['Create a new shared item'] + '" alt="| ' + \
translate['Create a new shared item'] + \
'" class="timelineicon"/></a>\n'
else:
newPostButtonStr += \
'<a href="' + usersPath + '/newshare?nodropdown">' + \
'<button class="button"><span>' + \
translate['Post'] + '</span></button></a>'
2021-08-09 18:41:05 +00:00
elif boxName == 'tlwanted':
if not iconsAsButtons:
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newwanted?nodropdown"><img loading="lazy" src="/' + \
'icons/newpost.png" title="' + \
translate['Create a new wanted item'] + '" alt="| ' + \
translate['Create a new wanted item'] + \
'" class="timelineicon"/></a>\n'
else:
newPostButtonStr += \
'<a href="' + usersPath + '/newwanted?nodropdown">' + \
'<button class="button"><span>' + \
translate['Post'] + '</span></button></a>'
2021-06-27 21:40:12 +00:00
else:
if not manuallyApproveFollowers:
if not iconsAsButtons:
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newpost"><img loading="lazy" src="/' + \
'icons/newpost.png" title="' + \
translate['Create a new post'] + '" alt="| ' + \
translate['Create a new post'] + \
'" class="timelineicon"/></a>\n'
else:
newPostButtonStr += \
'<a href="' + usersPath + '/newpost">' + \
'<button class="button"><span>' + \
translate['Post'] + '</span></button></a>'
else:
if not iconsAsButtons:
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newfollowers"><img loading="lazy" src="/' + \
'icons/newpost.png" title="' + \
translate['Create a new post'] + \
'" alt="| ' + translate['Create a new post'] + \
'" class="timelineicon"/></a>\n'
else:
newPostButtonStr += \
'<a href="' + usersPath + '/newfollowers">' + \
'<button class="button"><span>' + \
translate['Post'] + '</span></button></a>'
return newPostButtonStr
2021-06-27 22:01:58 +00:00
def _htmlTimelineModerationButtons(moderator: bool, boxName: str,
nickname: str, moderationActionStr: str,
translate: {}) -> str:
"""Returns html for the moderation screen buttons
"""
tlStr = ''
if moderator and boxName == 'moderation':
tlStr += \
'<form id="modtimeline" method="POST" action="/users/' + \
nickname + '/moderationaction">'
tlStr += '<div class="container">\n'
idx = 'Nickname or URL. Block using *@domain or nickname@domain'
tlStr += \
' <b>' + translate[idx] + '</b><br>\n'
if moderationActionStr:
tlStr += ' <input type="text" ' + \
'name="moderationAction" value="' + \
moderationActionStr + '" autofocus><br>\n'
else:
tlStr += ' <input type="text" ' + \
'name="moderationAction" value="" autofocus><br>\n'
tlStr += \
' <input type="submit" title="' + \
translate['Information about current blocks/suspensions'] + \
'" alt="' + \
translate['Information about current blocks/suspensions'] + \
' | " ' + \
'name="submitInfo" value="' + translate['Info'] + '">\n'
tlStr += \
' <input type="submit" title="' + \
translate['Remove the above item'] + '" ' + \
'alt="' + translate['Remove the above item'] + ' | " ' + \
'name="submitRemove" value="' + \
translate['Remove'] + '">\n'
tlStr += \
' <input type="submit" title="' + \
translate['Suspend the above account nickname'] + '" ' + \
'alt="' + \
translate['Suspend the above account nickname'] + ' | " ' + \
'name="submitSuspend" value="' + translate['Suspend'] + '">\n'
tlStr += \
' <input type="submit" title="' + \
translate['Remove a suspension for an account nickname'] + '" ' + \
'alt="' + \
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'] + '" ' + \
'alt="' + \
translate['Block an account on another instance'] + ' | " ' + \
'name="submitBlock" value="' + translate['Block'] + '">\n'
tlStr += \
' <input type="submit" title="' + \
translate['Unblock an account on another instance'] + '" ' + \
'alt="' + \
translate['Unblock an account on another instance'] + ' | " ' + \
'name="submitUnblock" value="' + translate['Unblock'] + '">\n'
tlStr += \
' <input type="submit" title="' + \
translate['Filter out words'] + '" ' + \
'alt="' + \
translate['Filter out words'] + ' | " ' + \
'name="submitFilter" value="' + translate['Filter'] + '">\n'
tlStr += \
' <input type="submit" title="' + \
translate['Unfilter words'] + '" ' + \
'alt="' + \
translate['Unfilter words'] + ' | " ' + \
'name="submitUnfilter" value="' + translate['Unfilter'] + '">\n'
tlStr += '</div>\n</form>\n'
return tlStr
2021-06-27 22:14:48 +00:00
def _htmlTimelineKeyboard(moderator: bool, textModeBanner: str, usersPath: str,
nickname: str, newCalendarEvent: bool,
2021-08-09 18:41:05 +00:00
newDM: bool, newReply: bool,
newShare: bool, newWanted: bool,
2021-06-27 22:14:48 +00:00
followApprovals: bool,
accessKeys: {}, translate: {}) -> str:
"""Returns html for timeline keyboard navigation
"""
calendarStr = translate['Calendar']
if newCalendarEvent:
calendarStr = '<strong>' + calendarStr + '</strong>'
dmStr = translate['DM']
if newDM:
dmStr = '<strong>' + dmStr + '</strong>'
repliesStr = translate['Replies']
if newReply:
repliesStr = '<strong>' + repliesStr + '</strong>'
sharesStr = translate['Shares']
if newShare:
sharesStr = '<strong>' + sharesStr + '</strong>'
2021-08-09 18:41:05 +00:00
wantedStr = translate['Wanted']
if newWanted:
wantedStr = '<strong>' + wantedStr + '</strong>'
2021-06-27 22:14:48 +00:00
menuProfile = \
htmlHideFromScreenReader('👤') + ' ' + \
translate['Switch to profile view']
menuInbox = \
htmlHideFromScreenReader('📥') + ' ' + translate['Inbox']
menuOutbox = \
htmlHideFromScreenReader('📤') + ' ' + translate['Sent']
menuSearch = \
htmlHideFromScreenReader('🔍') + ' ' + \
translate['Search and follow']
menuCalendar = \
htmlHideFromScreenReader('📅') + ' ' + calendarStr
menuDM = \
htmlHideFromScreenReader('📩') + ' ' + dmStr
menuReplies = \
htmlHideFromScreenReader('📨') + ' ' + repliesStr
menuBookmarks = \
htmlHideFromScreenReader('🔖') + ' ' + translate['Bookmarks']
menuShares = \
htmlHideFromScreenReader('🤝') + ' ' + sharesStr
2021-08-09 18:41:05 +00:00
menuWanted = \
htmlHideFromScreenReader('') + ' ' + wantedStr
2021-06-27 22:14:48 +00:00
menuBlogs = \
htmlHideFromScreenReader('📝') + ' ' + translate['Blogs']
menuNewswire = \
htmlHideFromScreenReader('📰') + ' ' + translate['Newswire']
menuLinks = \
htmlHideFromScreenReader('🔗') + ' ' + translate['Links']
menuNewPost = \
htmlHideFromScreenReader('') + ' ' + translate['Create a new post']
menuModeration = \
htmlHideFromScreenReader('⚡️') + ' ' + translate['Mod']
navLinks = {
menuProfile: '/users/' + nickname,
menuInbox: usersPath + '/inbox#timelineposts',
menuSearch: usersPath + '/search',
menuNewPost: usersPath + '/newpost',
menuCalendar: usersPath + '/calendar',
menuDM: usersPath + '/dm#timelineposts',
menuReplies: usersPath + '/tlreplies#timelineposts',
menuOutbox: usersPath + '/outbox#timelineposts',
menuBookmarks: usersPath + '/tlbookmarks#timelineposts',
menuShares: usersPath + '/tlshares#timelineposts',
2021-08-09 18:41:05 +00:00
menuWanted: usersPath + '/tlwanted#timelineposts',
2021-06-27 22:14:48 +00:00
menuBlogs: usersPath + '/tlblogs#timelineposts',
menuNewswire: usersPath + '/newswiremobile',
menuLinks: usersPath + '/linksmobile'
}
navAccessKeys = {}
for variableName, key in accessKeys.items():
if not locals().get(variableName):
continue
navAccessKeys[locals()[variableName]] = key
if moderator:
navLinks[menuModeration] = usersPath + '/moderation#modtimeline'
return htmlKeyboardNavigation(textModeBanner, navLinks, navAccessKeys,
None, usersPath, translate, followApprovals)
2021-07-28 11:26:03 +00:00
def _htmlTimelineEnd(baseDir: str, nickname: str, domainFull: str,
httpPrefix: str, translate: {},
moderator: bool, editor: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
rssIconAtTop: bool, publishButtonAtTop: bool,
authorized: bool, theme: str,
defaultTimeline: str, accessKeys: {},
boxName: str,
enableTimingLog: bool, timelineStartTime) -> str:
"""Ending of the timeline, containing the right column
"""
# end of timeline-posts
tlStr = ' </div>\n'
# end of column-center
tlStr += ' </td>\n'
# right column
rightColumnStr = getRightColumnContent(baseDir, nickname, domainFull,
httpPrefix, translate,
moderator, editor,
newswire, positiveVoting,
False, None, True,
showPublishAsIcon,
rssIconAtTop, publishButtonAtTop,
authorized, True, theme,
defaultTimeline, accessKeys)
tlStr += ' <td valign="top" class="col-right" ' + \
'id="newswire" tabindex="-1">' + \
rightColumnStr + ' </td>\n'
tlStr += ' </tr>\n'
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '9')
tlStr += ' </tbody>\n'
tlStr += '</table>\n'
return tlStr
2020-11-10 15:12:07 +00:00
def htmlTimeline(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int,
itemsPerPage: int, session, baseDir: str,
cachedWebfingers: {}, personCache: {},
2020-11-10 15:12:07 +00:00
nickname: str, domain: str, port: int, timelineJson: {},
boxName: str, allowDeletion: bool,
httpPrefix: str, projectVersion: str,
manuallyApproveFollowers: bool,
minimal: bool,
YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, moderator: bool,
editor: bool,
positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
2020-12-09 23:30:15 +00:00
authorized: bool,
2020-12-20 17:26:38 +00:00
moderationActionStr: str,
2020-12-23 23:59:49 +00:00
theme: str,
peertubeInstances: [],
2021-02-05 19:14:27 +00:00
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2020-11-10 15:12:07 +00:00
"""Show the timeline as html
2020-11-09 22:44:03 +00:00
"""
2020-12-01 17:23:34 +00:00
enableTimingLog = False
2020-11-10 15:12:07 +00:00
timelineStartTime = time.time()
2020-11-09 22:44:03 +00:00
2021-07-13 21:59:53 +00:00
accountDir = acctDir(baseDir, nickname, domain)
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# should the calendar icon be highlighted?
newCalendarEvent = False
calendarImage = 'calendar.png'
calendarPath = '/calendar'
calendarFile = accountDir + '/.newCalendar'
if os.path.isfile(calendarFile):
newCalendarEvent = True
calendarImage = 'calendar_notify.png'
with open(calendarFile, 'r') as calfile:
calendarPath = calfile.read().replace('##sent##', '')
calendarPath = calendarPath.replace('\n', '').replace('\r', '')
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# should the DM button be highlighted?
newDM = False
dmFile = accountDir + '/.newDM'
if os.path.isfile(dmFile):
newDM = True
if boxName == 'dm':
os.remove(dmFile)
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# should the Replies button be highlighted?
newReply = False
replyFile = accountDir + '/.newReply'
if os.path.isfile(replyFile):
newReply = True
if boxName == 'tlreplies':
os.remove(replyFile)
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# should the Shares button be highlighted?
newShare = False
newShareFile = accountDir + '/.newShare'
if os.path.isfile(newShareFile):
newShare = True
if boxName == 'tlshares':
os.remove(newShareFile)
2020-11-09 22:44:03 +00:00
2021-08-09 18:41:05 +00:00
# should the Wanted button be highlighted?
newWanted = False
newWantedFile = accountDir + '/.newWanted'
if os.path.isfile(newWantedFile):
newWanted = True
if boxName == 'tlwanted':
os.remove(newWantedFile)
2020-11-10 15:12:07 +00:00
# should the Moderation/reports button be highlighted?
newReport = False
newReportFile = accountDir + '/.newReport'
if os.path.isfile(newReportFile):
newReport = True
if boxName == 'moderation':
os.remove(newReportFile)
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
separatorStr = ''
if boxName != 'tlmedia':
separatorStr = htmlPostSeparator(baseDir, None)
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# the css filename
cssFilename = baseDir + '/epicyon-profile.css'
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# filename of the banner shown at the top
2020-12-20 17:29:15 +00:00
bannerFile, bannerFilename = \
getBannerFile(baseDir, nickname, domain, theme)
2020-11-09 22:44:03 +00:00
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '1')
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# is the user a moderator?
if not moderator:
moderator = isModerator(baseDir, nickname)
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# is the user a site editor?
if not editor:
editor = isEditor(baseDir, nickname)
2020-11-09 22:44:03 +00:00
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '2')
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# the appearance of buttons - highlighted or not
inboxButton = 'button'
blogsButton = 'button'
2020-11-27 12:42:51 +00:00
featuresButton = 'button'
2020-11-10 15:12:07 +00:00
newsButton = 'button'
dmButton = 'button'
if newDM:
dmButton = 'buttonhighlighted'
repliesButton = 'button'
if newReply:
repliesButton = 'buttonhighlighted'
mediaButton = 'button'
bookmarksButton = 'button'
# eventsButton = 'button'
2020-11-10 15:12:07 +00:00
sentButton = 'button'
sharesButton = 'button'
if newShare:
sharesButton = 'buttonhighlighted'
2021-08-09 18:41:05 +00:00
wantedButton = 'button'
if newWanted:
wantedButton = 'buttonhighlighted'
2020-11-10 15:12:07 +00:00
moderationButton = 'button'
if newReport:
moderationButton = 'buttonhighlighted'
if boxName == 'inbox':
inboxButton = 'buttonselected'
elif boxName == 'tlblogs':
blogsButton = 'buttonselected'
2020-11-27 12:42:51 +00:00
elif boxName == 'tlfeatures':
featuresButton = 'buttonselected'
2020-11-10 15:12:07 +00:00
elif boxName == 'tlnews':
newsButton = 'buttonselected'
elif boxName == 'dm':
dmButton = 'buttonselected'
if newDM:
dmButton = 'buttonselectedhighlighted'
elif boxName == 'tlreplies':
repliesButton = 'buttonselected'
if newReply:
repliesButton = 'buttonselectedhighlighted'
elif boxName == 'tlmedia':
mediaButton = 'buttonselected'
elif boxName == 'outbox':
sentButton = 'buttonselected'
elif boxName == 'moderation':
moderationButton = 'buttonselected'
if newReport:
moderationButton = 'buttonselectedhighlighted'
elif boxName == 'tlshares':
sharesButton = 'buttonselected'
if newShare:
sharesButton = 'buttonselectedhighlighted'
2021-08-09 18:41:05 +00:00
elif boxName == 'tlwanted':
wantedButton = 'buttonselected'
if newWanted:
wantedButton = 'buttonselectedhighlighted'
2020-11-10 15:12:07 +00:00
elif boxName == 'tlbookmarks' or boxName == 'bookmarks':
bookmarksButton = 'buttonselected'
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# get the full domain, including any port number
2020-12-16 11:19:16 +00:00
fullDomain = getFullDomain(domain, port)
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
usersPath = '/users/' + nickname
actor = httpPrefix + '://' + fullDomain + usersPath
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
showIndividualPostIcons = True
# show an icon for new follow approvals
followApprovals = ''
followRequestsFilename = \
2021-07-13 21:59:53 +00:00
acctDir(baseDir, nickname, domain) + '/followrequests.txt'
2020-11-10 15:12:07 +00:00
if os.path.isfile(followRequestsFilename):
with open(followRequestsFilename, 'r') as f:
for line in f:
if len(line) > 0:
# show follow approvals icon
followApprovals = \
2020-11-09 22:44:03 +00:00
'<a href="' + usersPath + \
2021-04-23 12:24:34 +00:00
'/followers#buttonheader" ' + \
'accesskey="' + accessKeys['followButton'] + '">' + \
2020-11-10 15:12:07 +00:00
'<img loading="lazy" ' + \
'class="timelineicon" alt="' + \
translate['Approve follow requests'] + \
'" title="' + translate['Approve follow requests'] + \
2020-12-09 13:08:26 +00:00
'" src="/icons/person.png"/></a>\n'
2020-11-10 15:12:07 +00:00
break
2020-11-09 22:44:03 +00:00
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '3')
2020-11-10 15:12:07 +00:00
# moderation / reports button
moderationButtonStr = ''
if moderator and not minimal:
moderationButtonStr = \
2020-11-09 22:44:03 +00:00
'<a href="' + usersPath + \
2020-11-10 15:12:07 +00:00
'/moderation"><button class="' + \
moderationButton + '"><span>' + \
htmlHighlightLabel(translate['Mod'], newReport) + \
' </span></button></a>'
# shares, bookmarks and events buttons
sharesButtonStr = ''
2021-08-09 18:53:27 +00:00
wantedButtonStr = ''
2020-11-10 15:12:07 +00:00
bookmarksButtonStr = ''
eventsButtonStr = ''
if not minimal:
sharesButtonStr = \
'<a href="' + usersPath + '/tlshares"><button class="' + \
sharesButton + '"><span>' + \
htmlHighlightLabel(translate['Shares'], newShare) + \
2020-11-09 22:44:03 +00:00
'</span></button></a>'
2021-08-09 18:41:05 +00:00
wantedButtonStr = \
'<a href="' + usersPath + '/tlwanted"><button class="' + \
wantedButton + '"><span>' + \
htmlHighlightLabel(translate['Wanted'], newWanted) + \
'</span></button></a>'
2020-11-10 15:12:07 +00:00
bookmarksButtonStr = \
'<a href="' + usersPath + '/tlbookmarks"><button class="' + \
bookmarksButton + '"><span>' + translate['Bookmarks'] + \
'</span></button></a>'
2020-11-09 22:44:03 +00:00
2021-01-11 19:46:21 +00:00
instanceTitle = \
getConfigParam(baseDir, 'instanceTitle')
tlStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
2020-11-10 15:12:07 +00:00
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '4')
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# if this is a news instance and we are viewing the news timeline
newsHeader = False
2020-11-27 12:52:01 +00:00
if defaultTimeline == 'tlfeatures' and boxName == 'tlfeatures':
2020-11-10 15:12:07 +00:00
newsHeader = True
newPostButtonStr = ''
# start of headericons div
if not newsHeader:
2020-11-09 22:44:03 +00:00
if not iconsAsButtons:
2020-11-10 15:12:07 +00:00
newPostButtonStr += '<div class="headericons">'
# what screen to go to when a new post is created
2021-06-27 21:40:12 +00:00
newPostButtonStr += \
_htmlTimelineNewPost(manuallyApproveFollowers, boxName,
iconsAsButtons, usersPath, translate)
2020-11-09 22:44:03 +00:00
2021-02-05 15:30:51 +00:00
# keyboard navigation
2021-06-27 22:14:48 +00:00
tlStr += \
_htmlTimelineKeyboard(moderator, textModeBanner, usersPath, nickname,
2021-08-09 18:41:05 +00:00
newCalendarEvent, newDM, newReply,
newShare, newWanted,
2021-06-27 22:14:48 +00:00
followApprovals, accessKeys, translate)
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# banner and row of buttons
tlStr += \
2020-12-27 16:57:15 +00:00
'<header>\n' + \
2020-11-10 15:12:07 +00:00
'<a href="/users/' + nickname + '" title="' + \
translate['Switch to profile view'] + '" alt="' + \
translate['Switch to profile view'] + '">\n'
2021-02-01 18:38:08 +00:00
tlStr += '<img loading="lazy" class="timeline-banner" ' + \
2021-02-01 19:48:46 +00:00
'alt="" ' + \
2021-02-01 18:38:08 +00:00
'src="' + usersPath + '/' + bannerFile + '" /></a>\n' + \
2020-12-27 16:57:15 +00:00
'</header>\n'
2020-11-10 15:12:07 +00:00
if fullWidthTimelineButtonHeader:
2020-11-09 22:44:03 +00:00
tlStr += \
2020-11-10 15:12:07 +00:00
headerButtonsTimeline(defaultTimeline, boxName, pageNumber,
translate, usersPath, mediaButton,
2020-11-27 12:42:51 +00:00
blogsButton, featuresButton,
newsButton, inboxButton,
2020-11-10 15:12:07 +00:00
dmButton, newDM, repliesButton,
newReply, minimal, sentButton,
2021-08-09 18:41:05 +00:00
sharesButtonStr, wantedButtonStr,
bookmarksButtonStr,
2020-11-10 15:12:07 +00:00
eventsButtonStr, moderationButtonStr,
newPostButtonStr, baseDir, nickname,
2020-12-09 13:31:54 +00:00
domain, timelineStartTime,
2020-11-10 15:12:07 +00:00
newCalendarEvent, calendarPath,
calendarImage, followApprovals,
2021-04-23 12:24:34 +00:00
iconsAsButtons, accessKeys)
2020-11-10 15:12:07 +00:00
# start the timeline
2021-07-06 12:50:38 +00:00
tlStr += \
'<table class="timeline">\n' + \
' <colgroup>\n' + \
' <col span="1" class="column-left">\n' + \
' <col span="1" class="column-center">\n' + \
' <col span="1" class="column-right">\n' + \
' </colgroup>\n' + \
' <tbody>\n' + \
' <tr>\n'
2020-11-10 15:12:07 +00:00
2020-12-16 11:19:16 +00:00
domainFull = getFullDomain(domain, port)
2020-11-10 15:12:07 +00:00
# left column
leftColumnStr = \
getLeftColumnContent(baseDir, nickname, domainFull,
2020-12-09 13:31:54 +00:00
httpPrefix, translate,
2020-11-10 15:12:07 +00:00
editor, False, None, rssIconAtTop,
True, False, theme, accessKeys,
sharedItemsFederatedDomains)
2021-02-01 13:31:49 +00:00
tlStr += ' <td valign="top" class="col-left" ' + \
'id="links" tabindex="-1">' + \
2020-11-10 15:12:07 +00:00
leftColumnStr + ' </td>\n'
# center column containing posts
2021-02-15 15:21:07 +00:00
tlStr += ' <td valign="top" class="col-center">\n'
2020-11-10 15:12:07 +00:00
if not fullWidthTimelineButtonHeader:
2020-11-09 22:44:03 +00:00
tlStr += \
2020-11-10 15:12:07 +00:00
headerButtonsTimeline(defaultTimeline, boxName, pageNumber,
translate, usersPath, mediaButton,
2020-11-27 12:42:51 +00:00
blogsButton, featuresButton,
newsButton, inboxButton,
2020-11-10 15:12:07 +00:00
dmButton, newDM, repliesButton,
newReply, minimal, sentButton,
2021-08-09 18:41:05 +00:00
sharesButtonStr, wantedButtonStr,
bookmarksButtonStr,
2020-11-10 15:12:07 +00:00
eventsButtonStr, moderationButtonStr,
newPostButtonStr, baseDir, nickname,
2020-12-09 13:31:54 +00:00
domain, timelineStartTime,
2020-11-10 15:12:07 +00:00
newCalendarEvent, calendarPath,
calendarImage, followApprovals,
2021-04-23 12:24:34 +00:00
iconsAsButtons, accessKeys)
2020-11-09 22:44:03 +00:00
2021-02-15 15:21:07 +00:00
tlStr += ' <div id="timelineposts" class="timeline-posts">\n'
2020-11-18 18:22:05 +00:00
2020-11-10 15:12:07 +00:00
# second row of buttons for moderator actions
2021-06-27 22:01:58 +00:00
tlStr += \
_htmlTimelineModerationButtons(moderator, boxName, nickname,
moderationActionStr, translate)
2020-11-09 22:44:03 +00:00
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '6')
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
if boxName == 'tlshares':
maxSharesPerAccount = itemsPerPage
return (tlStr +
_htmlSharesTimeline(translate, pageNumber, itemsPerPage,
baseDir, actor, nickname, domain, port,
maxSharesPerAccount, httpPrefix,
sharedItemsFederatedDomains, 'shares') +
2021-07-28 11:26:03 +00:00
_htmlTimelineEnd(baseDir, nickname, domainFull,
httpPrefix, translate,
moderator, editor,
newswire, positiveVoting,
showPublishAsIcon,
rssIconAtTop, publishButtonAtTop,
authorized, theme,
defaultTimeline, accessKeys,
boxName,
enableTimingLog, timelineStartTime) +
2020-11-10 15:12:07 +00:00
htmlFooter())
2021-08-09 18:41:05 +00:00
elif boxName == 'tlwanted':
maxSharesPerAccount = itemsPerPage
return (tlStr +
_htmlSharesTimeline(translate, pageNumber, itemsPerPage,
baseDir, actor, nickname, domain, port,
maxSharesPerAccount, httpPrefix,
sharedItemsFederatedDomains, 'wanted') +
_htmlTimelineEnd(baseDir, nickname, domainFull,
httpPrefix, translate,
moderator, editor,
newswire, positiveVoting,
showPublishAsIcon,
rssIconAtTop, publishButtonAtTop,
authorized, theme,
defaultTimeline, accessKeys,
boxName,
enableTimingLog, timelineStartTime) +
htmlFooter())
2020-11-09 22:44:03 +00:00
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '7')
2020-11-09 22:44:03 +00:00
2021-02-07 21:45:31 +00:00
# separator between posts which only appears in shell browsers
# such as Lynx and is not read by screen readers
if boxName != 'tlmedia':
textModeSeparator = \
'<div class="transparent"><hr></div>'
2021-02-18 20:10:26 +00:00
else:
textModeSeparator = ''
2021-02-07 21:45:31 +00:00
2020-11-10 15:12:07 +00:00
# page up arrow
if pageNumber > 1:
2021-02-07 21:45:31 +00:00
tlStr += textModeSeparator
2020-11-10 15:12:07 +00:00
tlStr += \
' <center>\n' + \
' <a href="' + usersPath + '/' + boxName + \
'?page=' + str(pageNumber - 1) + \
2021-04-23 13:20:28 +00:00
'" accesskey="' + accessKeys['Page up'] + '">' + \
'<img loading="lazy" class="pageicon" src="/' + \
2020-12-09 13:08:26 +00:00
'icons/pageup.png" title="' + \
2020-11-10 15:12:07 +00:00
translate['Page up'] + '" alt="' + \
translate['Page up'] + '"></a>\n' + \
' </center>\n'
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# show the posts
itemCtr = 0
if timelineJson:
if 'orderedItems' not in timelineJson:
2021-08-01 19:43:20 +00:00
print('ERROR: no orderedItems in timeline for '
+ boxName + ' ' + str(timelineJson))
return ''
useCacheOnly = False
if boxName == 'inbox':
useCacheOnly = True
2020-11-10 15:12:07 +00:00
if timelineJson:
# if this is the media timeline then add an extra gallery container
if boxName == 'tlmedia':
if pageNumber > 1:
tlStr += '<br>'
tlStr += '<div class="galleryContainer">\n'
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# show each post in the timeline
for item in timelineJson['orderedItems']:
if item['type'] == 'Create' or \
2021-03-05 15:45:03 +00:00
item['type'] == 'Announce':
2020-11-10 15:12:07 +00:00
# is the actor who sent this post snoozed?
if isPersonSnoozed(baseDir, nickname, domain, item['actor']):
continue
if isSelfAnnounce(item):
continue
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# is the post in the memory cache of recent ones?
currTlStr = None
if boxName != 'tlmedia' and \
recentPostsCache.get('index'):
postId = \
removeIdEnding(item['id']).replace('/', '#')
if postId in recentPostsCache['index']:
if not item.get('muted'):
if recentPostsCache['html'].get(postId):
currTlStr = recentPostsCache['html'][postId]
currTlStr = \
2021-02-02 21:08:33 +00:00
preparePostFromHtmlCache(nickname,
currTlStr,
2020-11-10 15:12:07 +00:00
boxName,
pageNumber)
_logTimelineTiming(enableTimingLog,
timelineStartTime,
boxName, '10')
2021-03-05 15:48:37 +00:00
else:
print('Muted post in timeline ' + boxName)
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
if not currTlStr:
_logTimelineTiming(enableTimingLog,
timelineStartTime,
boxName, '11')
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# read the post from disk
currTlStr = \
individualPostAsHtml(signingPrivateKeyPem,
False, recentPostsCache,
2020-11-10 15:12:07 +00:00
maxRecentPosts,
2020-12-09 13:31:54 +00:00
translate, pageNumber,
baseDir, session,
cachedWebfingers,
2020-11-10 15:12:07 +00:00
personCache,
nickname, domain, port,
2020-11-10 15:12:07 +00:00
item, None, True,
allowDeletion,
httpPrefix, projectVersion,
boxName,
2020-11-10 15:12:07 +00:00
YTReplacementDomain,
showPublishedDateOnly,
2020-12-23 23:59:49 +00:00
peertubeInstances,
allowLocalNetworkAccess,
theme, systemLanguage,
maxLikeCount,
2020-11-10 15:12:07 +00:00
boxName != 'dm',
showIndividualPostIcons,
manuallyApproveFollowers,
False, True, useCacheOnly)
_logTimelineTiming(enableTimingLog,
timelineStartTime, boxName, '12')
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
if currTlStr:
itemCtr += 1
2021-02-07 21:27:20 +00:00
tlStr += textModeSeparator + currTlStr
2020-11-10 15:12:07 +00:00
if separatorStr:
tlStr += separatorStr
2020-11-10 15:12:07 +00:00
if boxName == 'tlmedia':
tlStr += '</div>\n'
2020-11-09 22:44:03 +00:00
if itemCtr < 3:
print('Items added to html timeline ' + boxName + ': ' +
str(itemCtr) + ' ' + str(timelineJson['orderedItems']))
2020-11-10 15:12:07 +00:00
# page down arrow
2021-04-29 20:16:48 +00:00
if itemCtr > 0:
2021-02-07 21:41:57 +00:00
tlStr += textModeSeparator
2020-11-10 15:12:07 +00:00
tlStr += \
' <center>\n' + \
' <a href="' + usersPath + '/' + boxName + '?page=' + \
str(pageNumber + 1) + \
2021-04-23 13:20:28 +00:00
'" accesskey="' + accessKeys['Page down'] + '">' + \
'<img loading="lazy" class="pageicon" src="/' + \
2020-12-09 13:08:26 +00:00
'icons/pagedown.png" title="' + \
2020-11-10 15:12:07 +00:00
translate['Page down'] + '" alt="' + \
translate['Page down'] + '"></a>\n' + \
' </center>\n'
2021-02-07 21:41:57 +00:00
tlStr += textModeSeparator
elif itemCtr == 0:
tlStr += _getHelpForTimeline(baseDir, boxName)
2020-11-18 18:22:05 +00:00
2021-07-28 11:26:03 +00:00
tlStr += \
_htmlTimelineEnd(baseDir, nickname, domainFull,
httpPrefix, translate,
moderator, editor,
newswire, positiveVoting,
showPublishAsIcon,
rssIconAtTop, publishButtonAtTop,
authorized, theme,
defaultTimeline, accessKeys,
boxName,
enableTimingLog, timelineStartTime)
2020-11-10 15:12:07 +00:00
tlStr += htmlFooter()
return tlStr
2020-11-09 22:44:03 +00:00
def htmlIndividualShare(domain: str, shareId: str,
actor: str, item: {}, translate: {},
2021-08-09 20:05:14 +00:00
showContact: bool, removeButton: bool,
sharesFileType: str) -> str:
2020-11-10 15:12:07 +00:00
"""Returns an individual shared item as html
"""
profileStr = '<div class="container">\n'
profileStr += '<p class="share-title">' + item['displayName'] + '</p>\n'
if item.get('imageUrl'):
profileStr += '<a href="' + item['imageUrl'] + '">\n'
profileStr += \
'<img loading="lazy" src="' + item['imageUrl'] + \
'" alt="' + translate['Item image'] + '">\n</a>\n'
2021-07-24 11:34:05 +00:00
profileStr += '<p>' + item['summary'] + '</p>\n<p>'
if item.get('itemQty'):
2021-07-27 20:31:14 +00:00
if item['itemQty'] > 1:
profileStr += \
'<b>' + translate['Quantity'] + ':</b> ' + \
str(item['itemQty']) + '<br>'
2021-07-24 11:30:46 +00:00
profileStr += \
2021-07-27 20:29:29 +00:00
'<b>' + translate['Type'] + ':</b> ' + item['itemType'] + '<br>'
2020-11-10 15:12:07 +00:00
profileStr += \
2021-07-27 20:29:29 +00:00
'<b>' + translate['Category'] + ':</b> ' + item['category'] + '<br>'
2021-07-27 19:23:55 +00:00
if item.get('location'):
profileStr += \
2021-07-27 20:29:29 +00:00
'<b>' + translate['Location'] + ':</b> ' + \
item['location'] + '<br>'
2021-07-24 22:08:11 +00:00
if item.get('itemPrice') and item.get('itemCurrency'):
2021-07-25 13:09:39 +00:00
if isfloat(item['itemPrice']):
2021-07-24 22:08:11 +00:00
if float(item['itemPrice']) > 0:
profileStr += ' ' + \
'<b>' + translate['Price'] + ':</b> ' + \
item['itemPrice'] + ' ' + item['itemCurrency']
profileStr += '</p>\n'
sharedesc = item['displayName']
if '<' not in sharedesc and '?' not in sharedesc:
if showContact:
contactActor = item['actor']
profileStr += \
'<p>' + \
'<a href="' + actor + \
'?replydm=sharedesc:' + sharedesc + \
'?mention=' + contactActor + '"><button class="button">' + \
translate['Contact'] + '</button></a>\n'
profileStr += \
'<a href="' + contactActor + '"><button class="button">' + \
translate['View'] + '</button></a>\n'
if removeButton and domain in shareId:
2021-08-09 20:05:14 +00:00
if sharesFileType == 'shares':
profileStr += \
' <a href="' + actor + '?rmshare=' + shareId + \
'"><button class="button">' + \
translate['Remove'] + '</button></a>\n'
else:
profileStr += \
' <a href="' + actor + '?rmwanted=' + shareId + \
'"><button class="button">' + \
translate['Remove'] + '</button></a>\n'
2020-11-10 15:12:07 +00:00
profileStr += '</div>\n'
return profileStr
2020-11-09 22:44:03 +00:00
def _htmlSharesTimeline(translate: {}, pageNumber: int, itemsPerPage: int,
baseDir: str, actor: str,
nickname: str, domain: str, port: int,
maxSharesPerAccount: int, httpPrefix: str,
sharedItemsFederatedDomains: [],
sharesFileType: str) -> str:
2020-11-10 15:12:07 +00:00
"""Show shared items timeline as html
"""
sharesJson, lastPage = \
sharesTimelineJson(actor, pageNumber, itemsPerPage,
baseDir, domain, nickname, maxSharesPerAccount,
sharedItemsFederatedDomains, sharesFileType)
2020-12-16 11:19:16 +00:00
domainFull = getFullDomain(domain, port)
2021-08-14 11:13:39 +00:00
actor = localActorUrl(httpPrefix, nickname, domainFull)
adminNickname = getConfigParam(baseDir, 'admin')
adminActor = ''
if adminNickname:
adminActor = \
2021-08-14 11:13:39 +00:00
localActorUrl(httpPrefix, adminNickname, domainFull)
2020-11-10 15:12:07 +00:00
timelineStr = ''
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
if pageNumber > 1:
timelineStr += \
' <center>\n' + \
' <a href="' + actor + '/tl' + sharesFileType + '?page=' + \
2020-11-10 15:12:07 +00:00
str(pageNumber - 1) + \
'"><img loading="lazy" class="pageicon" src="/' + \
2020-12-09 13:08:26 +00:00
'icons/pageup.png" title="' + translate['Page up'] + \
2020-11-10 15:12:07 +00:00
'" alt="' + translate['Page up'] + '"></a>\n' + \
' </center>\n'
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
separatorStr = htmlPostSeparator(baseDir, None)
2021-02-26 13:31:31 +00:00
ctr = 0
isAdminAccount = False
if adminActor and actor == adminActor:
isAdminAccount = True
isModeratorAccount = False
if isModerator(baseDir, nickname):
isModeratorAccount = True
2020-11-10 15:12:07 +00:00
for published, item in sharesJson.items():
showContactButton = False
if item['actor'] != actor:
showContactButton = True
showRemoveButton = False
if '___' + domain in item['shareId']:
if item['actor'] == actor or isAdminAccount or isModeratorAccount:
showRemoveButton = True
2020-11-18 19:28:33 +00:00
timelineStr += \
htmlIndividualShare(domain, item['shareId'],
actor, item, translate,
2021-08-09 20:05:14 +00:00
showContactButton, showRemoveButton,
sharesFileType)
2020-11-18 19:28:33 +00:00
timelineStr += separatorStr
2021-02-26 13:31:31 +00:00
ctr += 1
if ctr == 0:
timelineStr += _getHelpForTimeline(baseDir, 'tl' + sharesFileType)
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
if not lastPage:
timelineStr += \
' <center>\n' + \
' <a href="' + actor + '/tl' + sharesFileType + '?page=' + \
2020-11-10 15:12:07 +00:00
str(pageNumber + 1) + \
'"><img loading="lazy" class="pageicon" src="/' + \
2020-12-09 13:08:26 +00:00
'icons/pagedown.png" title="' + translate['Page down'] + \
2020-11-10 15:12:07 +00:00
'" alt="' + translate['Page down'] + '"></a>\n' + \
' </center>\n'
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
return timelineStr
2020-11-09 22:44:03 +00:00
def htmlShares(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
2020-11-09 22:44:03 +00:00
nickname: str, domain: str, port: int,
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
2020-12-23 23:59:49 +00:00
authorized: bool, theme: str,
peertubeInstances: [],
2021-02-05 19:14:27 +00:00
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2020-11-09 22:44:03 +00:00
"""Show the shares timeline as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
2020-11-09 22:44:03 +00:00
nickname, domain, port, None,
'tlshares', allowDeletion,
httpPrefix, projectVersion, manuallyApproveFollowers,
False, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
2021-08-09 18:41:05 +00:00
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains, signingPrivateKeyPem)
2021-08-09 18:41:05 +00:00
def htmlWanted(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
nickname: str, domain: str, port: int,
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
authorized: bool, theme: str,
peertubeInstances: [],
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2021-08-09 18:41:05 +00:00
"""Show the wanted timeline as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
nickname, domain, port, None,
'tlwanted', allowDeletion,
httpPrefix, projectVersion, manuallyApproveFollowers,
False, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains, signingPrivateKeyPem)
2020-11-09 22:44:03 +00:00
def htmlInbox(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
2020-11-09 22:44:03 +00:00
nickname: str, domain: str, port: int, inboxJson: {},
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
minimal: bool, YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
2020-12-23 23:59:49 +00:00
authorized: bool, theme: str,
peertubeInstances: [],
2021-02-05 19:14:27 +00:00
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2020-11-09 22:44:03 +00:00
"""Show the inbox as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
2020-11-09 22:44:03 +00:00
nickname, domain, port, inboxJson,
'inbox', allowDeletion,
httpPrefix, projectVersion, manuallyApproveFollowers,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains, signingPrivateKeyPem)
2020-11-09 22:44:03 +00:00
def htmlBookmarks(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
2020-11-09 22:44:03 +00:00
nickname: str, domain: str, port: int, bookmarksJson: {},
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
minimal: bool, YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
2020-12-23 23:59:49 +00:00
authorized: bool, theme: str,
peertubeInstances: [],
2021-02-05 19:14:27 +00:00
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2020-11-09 22:44:03 +00:00
"""Show the bookmarks as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
2020-11-09 22:44:03 +00:00
nickname, domain, port, bookmarksJson,
'tlbookmarks', allowDeletion,
httpPrefix, projectVersion, manuallyApproveFollowers,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains, signingPrivateKeyPem)
2020-11-09 22:44:03 +00:00
def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
2020-11-09 22:44:03 +00:00
nickname: str, domain: str, port: int, inboxJson: {},
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
minimal: bool, YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
2020-12-23 23:59:49 +00:00
authorized: bool, theme: str,
peertubeInstances: [],
2021-02-05 19:14:27 +00:00
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2020-11-09 22:44:03 +00:00
"""Show the DM timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
2020-11-09 22:44:03 +00:00
nickname, domain, port, inboxJson, 'dm', allowDeletion,
httpPrefix, projectVersion, False, minimal,
YTReplacementDomain, showPublishedDateOnly,
newswire, False, False, positiveVoting,
showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains, signingPrivateKeyPem)
2020-11-09 22:44:03 +00:00
def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
2020-11-09 22:44:03 +00:00
nickname: str, domain: str, port: int, inboxJson: {},
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
minimal: bool, YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
2020-12-23 23:59:49 +00:00
authorized: bool, theme: str,
peertubeInstances: [],
2021-02-05 19:14:27 +00:00
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2020-11-09 22:44:03 +00:00
"""Show the replies timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
2020-11-09 22:44:03 +00:00
nickname, domain, port, inboxJson, 'tlreplies',
allowDeletion, httpPrefix, projectVersion, False,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains, signingPrivateKeyPem)
2020-11-09 22:44:03 +00:00
def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
2020-11-09 22:44:03 +00:00
nickname: str, domain: str, port: int, inboxJson: {},
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
minimal: bool, YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
2020-12-23 23:59:49 +00:00
authorized: bool, theme: str,
peertubeInstances: [],
2021-02-05 19:14:27 +00:00
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2020-11-09 22:44:03 +00:00
"""Show the media timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
2020-11-09 22:44:03 +00:00
nickname, domain, port, inboxJson, 'tlmedia',
allowDeletion, httpPrefix, projectVersion, False,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains, signingPrivateKeyPem)
2020-11-09 22:44:03 +00:00
def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
2020-11-09 22:44:03 +00:00
nickname: str, domain: str, port: int, inboxJson: {},
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
minimal: bool, YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
2020-12-23 23:59:49 +00:00
authorized: bool, theme: str,
peertubeInstances: [],
2021-02-05 19:14:27 +00:00
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2020-11-09 22:44:03 +00:00
"""Show the blogs timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
2020-11-09 22:44:03 +00:00
nickname, domain, port, inboxJson, 'tlblogs',
allowDeletion, httpPrefix, projectVersion, False,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains, signingPrivateKeyPem)
2020-11-09 22:44:03 +00:00
2020-11-27 11:22:47 +00:00
def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
2020-11-27 11:22:47 +00:00
nickname: str, domain: str, port: int, inboxJson: {},
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
minimal: bool, YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
2020-12-20 17:26:38 +00:00
authorized: bool,
2020-12-23 23:59:49 +00:00
theme: str,
peertubeInstances: [],
2021-02-05 19:14:27 +00:00
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2020-11-27 11:22:47 +00:00
"""Show the features timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
2020-11-27 15:05:22 +00:00
nickname, domain, port, inboxJson, 'tlfeatures',
2020-11-27 11:22:47 +00:00
allowDeletion, httpPrefix, projectVersion, False,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains, signingPrivateKeyPem)
2020-11-27 11:22:47 +00:00
2020-11-09 22:44:03 +00:00
def htmlInboxNews(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
2020-11-09 22:44:03 +00:00
nickname: str, domain: str, port: int, inboxJson: {},
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
minimal: bool, YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, moderator: bool, editor: bool,
positiveVoting: bool, showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
2020-12-23 23:59:49 +00:00
authorized: bool, theme: str,
peertubeInstances: [],
2021-02-05 19:14:27 +00:00
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2020-11-09 22:44:03 +00:00
"""Show the news timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
2020-11-09 22:44:03 +00:00
nickname, domain, port, inboxJson, 'tlnews',
allowDeletion, httpPrefix, projectVersion, False,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, moderator, editor,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains, signingPrivateKeyPem)
2020-11-09 22:44:03 +00:00
def htmlOutbox(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, personCache: {},
2020-11-09 22:44:03 +00:00
nickname: str, domain: str, port: int, outboxJson: {},
allowDeletion: bool,
httpPrefix: str, projectVersion: str,
minimal: bool, YTReplacementDomain: str,
showPublishedDateOnly: bool,
newswire: {}, positiveVoting: bool,
showPublishAsIcon: bool,
fullWidthTimelineButtonHeader: bool,
iconsAsButtons: bool,
rssIconAtTop: bool,
publishButtonAtTop: bool,
2020-12-23 23:59:49 +00:00
authorized: bool, theme: str,
peertubeInstances: [],
2021-02-05 19:14:27 +00:00
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}, systemLanguage: str,
maxLikeCount: int,
sharedItemsFederatedDomains: [],
signingPrivateKeyPem: str) -> str:
2020-11-09 22:44:03 +00:00
"""Show the Outbox as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
2020-11-09 22:44:03 +00:00
nickname, domain, port, outboxJson, 'outbox',
allowDeletion, httpPrefix, projectVersion,
manuallyApproveFollowers, minimal,
YTReplacementDomain, showPublishedDateOnly,
newswire, False, False, positiveVoting,
showPublishAsIcon, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys, systemLanguage, maxLikeCount,
sharedItemsFederatedDomains, signingPrivateKeyPem)