epicyon/webapp_timeline.py

1079 lines
46 KiB
Python
Raw Normal View History

2020-11-09 22:44:03 +00:00
__filename__ = "webapp_timeline.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.1.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
import os
import time
2020-12-01 21:44:27 +00:00
from utils import isEditor
2020-11-09 22:44:03 +00:00
from utils import removeIdEnding
from follow import followerApprovalActive
from person import isPersonSnoozed
2020-11-14 13:03:09 +00:00
from webapp_utils import getIconsWebPath
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
2020-12-01 17:23:34 +00:00
def logTimelineTiming(enableTimingLog: bool, timelineStartTime,
boxName: str, debugId: str) -> None:
"""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))
2020-11-10 15:12:07 +00:00
def htmlTimeline(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int,
itemsPerPage: int, session, baseDir: str,
wfRequest: {}, personCache: {},
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,
authorized: bool) -> str:
"""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
2020-11-10 15:12:07 +00:00
accountDir = baseDir + '/accounts/' + 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
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
# directory where icons are found
# This changes depending upon theme
2020-11-14 13:08:34 +00:00
iconsPath = getIconsWebPath(baseDir)
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
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
2020-11-09 22:44:03 +00:00
2020-12-01 17:23:34 +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
2020-12-01 17:23:34 +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'
sentButton = 'button'
sharesButton = 'button'
if newShare:
sharesButton = 'buttonhighlighted'
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'
elif boxName == 'tlbookmarks' or boxName == 'bookmarks':
bookmarksButton = 'buttonselected'
elif boxName == 'tlevents':
eventsButton = '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
fullDomain = domain
if port != 80 and port != 443:
if ':' not in domain:
fullDomain = domain + ':' + str(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 = \
baseDir + '/accounts/' + \
nickname + '@' + domain + '/followrequests.txt'
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 + \
2020-11-10 15:12:07 +00:00
'/followers#buttonheader">' + \
'<img loading="lazy" ' + \
'class="timelineicon" alt="' + \
translate['Approve follow requests'] + \
'" title="' + translate['Approve follow requests'] + \
2020-11-14 13:08:34 +00:00
'" src="/' + iconsPath + '/person.png"/></a>\n'
2020-11-10 15:12:07 +00:00
break
2020-11-09 22:44:03 +00:00
2020-12-01 17:23:34 +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 = ''
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>'
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
2020-11-10 15:12:07 +00:00
eventsButtonStr = \
'<a href="' + usersPath + '/tlevents"><button class="' + \
eventsButton + '"><span>' + translate['Events'] + \
'</span></button></a>'
2020-11-09 22:44:03 +00:00
tlStr = htmlHeaderWithExternalStyle(cssFilename)
2020-11-10 15:12:07 +00:00
2020-12-01 17:23:34 +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
if boxName == 'dm':
if not iconsAsButtons:
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newdm"><img loading="lazy" src="/' + \
2020-11-14 13:08:34 +00:00
iconsPath + '/newpost.png" title="' + \
2020-11-10 15:12:07 +00:00
translate['Create a new DM'] + \
'" alt="| ' + translate['Create a new DM'] + \
2020-11-09 22:44:03 +00:00
'" class="timelineicon"/></a>\n'
else:
2020-11-10 15:12:07 +00:00
newPostButtonStr += \
'<a href="' + usersPath + '/newdm">' + \
'<button class="button"><span>' + \
translate['Post'] + ' </span></button></a>'
2020-11-27 13:03:17 +00:00
elif (boxName == 'tlblogs' or
boxName == 'tlnews' or
boxName == 'tlfeatures'):
2020-11-09 22:44:03 +00:00
if not iconsAsButtons:
2020-11-10 15:12:07 +00:00
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newblog"><img loading="lazy" src="/' + \
2020-11-14 13:08:34 +00:00
iconsPath + '/newpost.png" title="' + \
2020-11-10 15:12:07 +00:00
translate['Create a new post'] + '" alt="| ' + \
translate['Create a new post'] + \
2020-11-09 22:44:03 +00:00
'" class="timelineicon"/></a>\n'
else:
2020-11-10 15:12:07 +00:00
newPostButtonStr += \
'<a href="' + usersPath + '/newblog">' + \
'<button class="button"><span>' + \
translate['Post'] + '</span></button></a>'
elif boxName == 'tlevents':
if not iconsAsButtons:
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newevent"><img loading="lazy" src="/' + \
2020-11-14 13:08:34 +00:00
iconsPath + '/newpost.png" title="' + \
2020-11-10 15:12:07 +00:00
translate['Create a new event'] + '" alt="| ' + \
translate['Create a new event'] + \
'" class="timelineicon"/></a>\n'
else:
newPostButtonStr += \
'<a href="' + usersPath + '/newevent">' + \
'<button class="button"><span>' + \
translate['Post'] + '</span></button></a>'
elif boxName == 'tlshares':
if not iconsAsButtons:
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newshare"><img loading="lazy" src="/' + \
iconsPath + '/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">' + \
'<button class="button"><span>' + \
translate['Post'] + '</span></button></a>'
2020-11-10 15:12:07 +00:00
else:
if not manuallyApproveFollowers:
if not iconsAsButtons:
newPostButtonStr += \
'<a class="imageAnchor" href="' + usersPath + \
'/newpost"><img loading="lazy" src="/' + \
2020-11-14 13:08:34 +00:00
iconsPath + '/newpost.png" title="' + \
2020-11-10 15:12:07 +00:00
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="/' + \
2020-11-14 13:08:34 +00:00
iconsPath + '/newpost.png" title="' + \
2020-11-10 15:12:07 +00:00
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>'
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# This creates a link to the profile page when viewed
# in lynx, but should be invisible in a graphical web browser
tlStr += \
'<div class="transparent"><label class="transparent">' + \
'<a href="/users/' + nickname + '">' + \
translate['Switch to profile view'] + '</a></label></div>\n'
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# banner and row of buttons
tlStr += \
'<a href="/users/' + nickname + '" title="' + \
translate['Switch to profile view'] + '" alt="' + \
translate['Switch to profile view'] + '">\n'
tlStr += '<img loading="lazy" class="timeline-banner" src="' + \
usersPath + '/' + bannerFile + '" /></a>\n'
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,
sharesButtonStr, bookmarksButtonStr,
eventsButtonStr, moderationButtonStr,
newPostButtonStr, baseDir, nickname,
2020-11-14 13:08:34 +00:00
domain, iconsPath, timelineStartTime,
2020-11-10 15:12:07 +00:00
newCalendarEvent, calendarPath,
calendarImage, followApprovals,
iconsAsButtons)
# start the timeline
tlStr += '<table class="timeline">\n'
tlStr += ' <colgroup>\n'
tlStr += ' <col span="1" class="column-left">\n'
tlStr += ' <col span="1" class="column-center">\n'
tlStr += ' <col span="1" class="column-right">\n'
tlStr += ' </colgroup>\n'
tlStr += ' <tbody>\n'
tlStr += ' <tr>\n'
domainFull = domain
if port:
if port != 80 and port != 443:
domainFull = domain + ':' + str(port)
# left column
leftColumnStr = \
getLeftColumnContent(baseDir, nickname, domainFull,
2020-11-14 13:08:34 +00:00
httpPrefix, translate, iconsPath,
2020-11-10 15:12:07 +00:00
editor, False, None, rssIconAtTop,
True, False)
tlStr += ' <td valign="top" class="col-left">' + \
leftColumnStr + ' </td>\n'
# center column containing posts
tlStr += ' <td valign="top" class="col-center">\n'
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,
sharesButtonStr, bookmarksButtonStr,
eventsButtonStr, moderationButtonStr,
newPostButtonStr, baseDir, nickname,
2020-11-14 13:08:34 +00:00
domain, iconsPath, timelineStartTime,
2020-11-10 15:12:07 +00:00
newCalendarEvent, calendarPath,
calendarImage, followApprovals,
iconsAsButtons)
2020-11-09 22:44:03 +00:00
2020-11-18 18:22:05 +00:00
tlStr += ' <div class="timeline-posts">\n'
2020-11-10 15:12:07 +00:00
# second row of buttons for moderator actions
if moderator and boxName == 'moderation':
2020-11-09 22:44:03 +00:00
tlStr += \
2020-11-10 15:12:07 +00:00
'<form method="POST" action="/users/' + \
nickname + '/moderationaction">'
tlStr += '<div class="container">\n'
idx = 'Nickname or URL. Block using *@domain or nickname@domain'
2020-11-09 22:44:03 +00:00
tlStr += \
2020-11-10 15:12:07 +00:00
' <b>' + translate[idx] + '</b><br>\n'
tlStr += ' <input type="text" ' + \
'name="moderationAction" value="" autofocus><br>\n'
2020-11-09 22:44:03 +00:00
tlStr += \
2020-11-10 15:12:07 +00:00
' <input type="submit" title="' + \
translate['Remove the above item'] + \
'" name="submitRemove" value="' + \
translate['Remove'] + '">\n'
tlStr += \
' <input type="submit" title="' + \
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'] + \
'" name="submitUnsuspend" value="' + \
translate['Unsuspend'] + '">\n'
tlStr += \
' <input type="submit" title="' + \
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'] + \
'" name="submitUnblock" value="' + translate['Unblock'] + '">\n'
tlStr += \
' <input type="submit" title="' + \
translate['Information about current blocks/suspensions'] + \
'" name="submitInfo" value="' + translate['Info'] + '">\n'
tlStr += '</div>\n</form>\n'
2020-11-09 22:44:03 +00:00
2020-12-01 17:23:34 +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) +
htmlFooter())
2020-11-09 22:44:03 +00:00
2020-12-01 17:23:34 +00:00
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '7')
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# page up arrow
if pageNumber > 1:
tlStr += \
' <center>\n' + \
' <a href="' + usersPath + '/' + boxName + \
'?page=' + str(pageNumber - 1) + \
'"><img loading="lazy" class="pageicon" src="/' + \
2020-11-14 13:08:34 +00:00
iconsPath + '/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 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 \
item['type'] == 'Announce' or \
item['type'] == 'Update':
# is the actor who sent this post snoozed?
if isPersonSnoozed(baseDir, nickname, domain, item['actor']):
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 = \
preparePostFromHtmlCache(currTlStr,
boxName,
pageNumber)
2020-12-01 17:23:34 +00:00
logTimelineTiming(enableTimingLog,
timelineStartTime,
boxName, '10')
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
if not currTlStr:
2020-12-01 17:23:34 +00:00
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(False, recentPostsCache,
maxRecentPosts,
2020-11-14 13:08:34 +00:00
iconsPath, translate, pageNumber,
2020-11-10 15:12:07 +00:00
baseDir, session, wfRequest,
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,
boxName != 'dm',
showIndividualPostIcons,
manuallyApproveFollowers,
False, True)
2020-12-01 17:23:34 +00:00
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
2020-11-18 19:28:33 +00:00
tlStr += currTlStr
2020-11-10 15:12:07 +00:00
if separatorStr:
tlStr += separatorStr
if boxName == 'tlmedia':
tlStr += '</div>\n'
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# page down arrow
if itemCtr > 2:
tlStr += \
' <center>\n' + \
' <a href="' + usersPath + '/' + boxName + '?page=' + \
str(pageNumber + 1) + \
'"><img loading="lazy" class="pageicon" src="/' + \
2020-11-14 13:08:34 +00:00
iconsPath + '/pagedown.png" title="' + \
2020-11-10 15:12:07 +00:00
translate['Page down'] + '" alt="' + \
translate['Page down'] + '"></a>\n' + \
' </center>\n'
2020-11-18 18:22:05 +00:00
# end of timeline-posts
tlStr += ' </div>\n'
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
# end of column-center
tlStr += ' </td>\n'
# right column
rightColumnStr = getRightColumnContent(baseDir, nickname, domainFull,
2020-11-14 13:08:34 +00:00
httpPrefix, translate, iconsPath,
2020-11-10 15:12:07 +00:00
moderator, editor,
newswire, positiveVoting,
False, None, True,
showPublishAsIcon,
rssIconAtTop, publishButtonAtTop,
authorized, True)
tlStr += ' <td valign="top" class="col-right">' + \
rightColumnStr + ' </td>\n'
tlStr += ' </tr>\n'
2020-12-01 17:23:34 +00:00
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '9')
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
tlStr += ' </tbody>\n'
tlStr += '</table>\n'
tlStr += htmlFooter()
return tlStr
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
def htmlIndividualShare(actor: str, item: {}, translate: {},
showContact: bool, removeButton: bool) -> str:
"""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'
profileStr += '<p>' + item['summary'] + '</p>\n'
profileStr += \
'<p><b>' + translate['Type'] + ':</b> ' + item['itemType'] + ' '
profileStr += \
'<b>' + translate['Category'] + ':</b> ' + item['category'] + ' '
profileStr += \
'<b>' + translate['Location'] + ':</b> ' + item['location'] + '</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'
if removeButton:
profileStr += \
' <a href="' + actor + '?rmshare=' + sharedesc + \
'"><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
2020-11-10 15:12:07 +00:00
def htmlSharesTimeline(translate: {}, pageNumber: int, itemsPerPage: int,
baseDir: str, actor: str,
nickname: str, domain: str, port: int,
maxSharesPerAccount: int, httpPrefix: str) -> str:
"""Show shared items timeline as html
"""
sharesJson, lastPage = \
sharesTimelineJson(actor, pageNumber, itemsPerPage,
baseDir, maxSharesPerAccount)
domainFull = domain
2020-11-09 22:44:03 +00:00
if port != 80 and port != 443:
if ':' not in domain:
2020-11-10 15:12:07 +00:00
domainFull = domain + ':' + str(port)
actor = httpPrefix + '://' + domainFull + '/users/' + nickname
timelineStr = ''
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
if pageNumber > 1:
2020-11-14 13:08:34 +00:00
iconsPath = getIconsWebPath(baseDir)
2020-11-10 15:12:07 +00:00
timelineStr += \
' <center>\n' + \
' <a href="' + actor + '/tlshares?page=' + \
str(pageNumber - 1) + \
'"><img loading="lazy" class="pageicon" src="/' + \
2020-11-14 13:08:34 +00:00
iconsPath + '/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)
for published, item in sharesJson.items():
showContactButton = False
if item['actor'] != actor:
showContactButton = True
showRemoveButton = False
if item['actor'] == actor:
showRemoveButton = True
2020-11-18 19:28:33 +00:00
timelineStr += \
2020-11-10 15:12:07 +00:00
htmlIndividualShare(actor, item, translate,
showContactButton, showRemoveButton)
2020-11-18 19:28:33 +00:00
timelineStr += separatorStr
2020-11-09 22:44:03 +00:00
2020-11-10 15:12:07 +00:00
if not lastPage:
2020-11-14 13:08:34 +00:00
iconsPath = getIconsWebPath(baseDir)
2020-11-10 15:12:07 +00:00
timelineStr += \
' <center>\n' + \
' <a href="' + actor + '/tlshares?page=' + \
str(pageNumber + 1) + \
'"><img loading="lazy" class="pageicon" src="/' + \
2020-11-14 13:08:34 +00:00
iconsPath + '/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, wfRequest: {}, 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) -> str:
"""Show the shares timeline as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir, wfRequest, personCache,
nickname, domain, port, None,
'tlshares', allowDeletion,
httpPrefix, projectVersion, manuallyApproveFollowers,
False, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized)
def htmlInbox(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str, wfRequest: {}, personCache: {},
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,
authorized: bool) -> str:
"""Show the inbox as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir, wfRequest, personCache,
nickname, domain, port, inboxJson,
'inbox', allowDeletion,
httpPrefix, projectVersion, manuallyApproveFollowers,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized)
def htmlBookmarks(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str, wfRequest: {}, personCache: {},
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,
authorized: bool) -> str:
"""Show the bookmarks as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir, wfRequest, personCache,
nickname, domain, port, bookmarksJson,
'tlbookmarks', allowDeletion,
httpPrefix, projectVersion, manuallyApproveFollowers,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized)
def htmlEvents(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str, wfRequest: {}, personCache: {},
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,
authorized: bool) -> str:
"""Show the events as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir, wfRequest, personCache,
nickname, domain, port, bookmarksJson,
'tlevents', allowDeletion,
httpPrefix, projectVersion, manuallyApproveFollowers,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized)
def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str, wfRequest: {}, personCache: {},
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,
authorized: bool) -> str:
"""Show the DM timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir, wfRequest, personCache,
nickname, domain, port, inboxJson, 'dm', allowDeletion,
httpPrefix, projectVersion, False, minimal,
YTReplacementDomain, showPublishedDateOnly,
newswire, False, False, positiveVoting,
showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized)
def htmlInboxReplies(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str, wfRequest: {}, personCache: {},
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,
authorized: bool) -> str:
"""Show the replies timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir, wfRequest, personCache,
nickname, domain, port, inboxJson, 'tlreplies',
allowDeletion, httpPrefix, projectVersion, False,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized)
def htmlInboxMedia(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str, wfRequest: {}, personCache: {},
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,
authorized: bool) -> str:
"""Show the media timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir, wfRequest, personCache,
nickname, domain, port, inboxJson, 'tlmedia',
allowDeletion, httpPrefix, projectVersion, False,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized)
def htmlInboxBlogs(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str, wfRequest: {}, personCache: {},
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,
authorized: bool) -> str:
"""Show the blogs timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir, wfRequest, personCache,
nickname, domain, port, inboxJson, 'tlblogs',
allowDeletion, httpPrefix, projectVersion, False,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized)
2020-11-27 11:22:47 +00:00
def htmlInboxFeatures(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str, wfRequest: {}, personCache: {},
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,
authorized: bool) -> str:
"""Show the features timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir, wfRequest, 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)
2020-11-09 22:44:03 +00:00
def htmlInboxNews(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str, wfRequest: {}, personCache: {},
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,
authorized: bool) -> str:
"""Show the news timeline as html
"""
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir, wfRequest, personCache,
nickname, domain, port, inboxJson, 'tlnews',
allowDeletion, httpPrefix, projectVersion, False,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, moderator, editor,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized)
def htmlOutbox(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str, wfRequest: {}, personCache: {},
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,
authorized: bool) -> str:
"""Show the Outbox as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir, wfRequest, personCache,
nickname, domain, port, outboxJson, 'outbox',
allowDeletion, httpPrefix, projectVersion,
manuallyApproveFollowers, minimal,
YTReplacementDomain, showPublishedDateOnly,
newswire, False, False, positiveVoting,
showPublishAsIcon, fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized)