Merge branch 'main' of ssh://code.freedombone.net:2222/bashrc/epicyon

main
Bob Mottram 2021-07-01 23:22:31 +01:00
commit 29613d4732
12 changed files with 299 additions and 532 deletions

340
daemon.py
View File

@ -81,7 +81,6 @@ from posts import createBlogPost
from posts import createReportPost
from posts import createUnlistedPost
from posts import createFollowersOnlyPost
from posts import createEventPost
from posts import createDirectMessagePost
from posts import populateRepliesJson
from posts import addToField
@ -114,7 +113,6 @@ from threads import threadWithTrace
from threads import removeDormantThreads
from media import replaceYouTube
from media import attachMedia
from media import pathIsImage
from media import pathIsVideo
from media import pathIsAudio
from blocking import updateBlockedCache
@ -161,7 +159,6 @@ from webapp_person_options import htmlPersonOptions
from webapp_timeline import htmlShares
from webapp_timeline import htmlInbox
from webapp_timeline import htmlBookmarks
from webapp_timeline import htmlEvents
from webapp_timeline import htmlInboxDMs
from webapp_timeline import htmlInboxReplies
from webapp_timeline import htmlInboxMedia
@ -256,6 +253,7 @@ from utils import saveJson
from utils import isSuspended
from utils import dangerousMarkup
from utils import refreshNewswire
from utils import isImageFile
from manualapprove import manualDenyFollowRequest
from manualapprove import manualApproveFollowRequest
from announce import createAnnounce
@ -1724,7 +1722,7 @@ class PubServer(BaseHTTPRequestHandler):
print('moderationText: ' + moderationText)
nickname = moderationText
if nickname.startswith('http') or \
nickname.startswith('dat'):
nickname.startswith('hyper'):
nickname = getNicknameFromActor(nickname)
if '@' in nickname:
nickname = nickname.split('@')[0]
@ -1739,7 +1737,7 @@ class PubServer(BaseHTTPRequestHandler):
if moderationButton == 'block':
fullBlockDomain = None
if moderationText.startswith('http') or \
moderationText.startswith('dat'):
moderationText.startswith('hyper'):
# https://domain
blockDomain, blockPort = \
getDomainFromActor(moderationText)
@ -1757,7 +1755,7 @@ class PubServer(BaseHTTPRequestHandler):
if moderationButton == 'unblock':
fullBlockDomain = None
if moderationText.startswith('http') or \
moderationText.startswith('dat'):
moderationText.startswith('hyper'):
# https://domain
blockDomain, blockPort = \
getDomainFromActor(moderationText)
@ -5926,7 +5924,7 @@ class PubServer(BaseHTTPRequestHandler):
GETstartTime, GETtimings: {}) -> None:
"""Returns a media file
"""
if pathIsImage(path) or \
if isImageFile(path) or \
pathIsVideo(path) or \
pathIsAudio(path):
mediaStr = path.split('/media/')[1]
@ -5956,7 +5954,7 @@ class PubServer(BaseHTTPRequestHandler):
GETstartTime, GETtimings: {}) -> None:
"""Returns an emoji image
"""
if pathIsImage(path):
if isImageFile(path):
emojiStr = path.split('/emoji/')[1]
emojiFilename = baseDir + '/emoji/' + emojiStr
if os.path.isfile(emojiFilename):
@ -9043,138 +9041,6 @@ class PubServer(BaseHTTPRequestHandler):
self.server.GETbusy = False
return True
def _showEventsTimeline(self, authorized: bool,
callingDomain: str, path: str,
baseDir: str, httpPrefix: str,
domain: str, domainFull: str, port: int,
onionDomain: str, i2pDomain: str,
GETstartTime, GETtimings: {},
proxyType: str, cookie: str,
debug: str) -> bool:
"""Shows the events timeline
"""
if '/users/' in path:
if authorized:
# convert /events to /tlevents
if path.endswith('/events') or \
'/events?page=' in path:
path = path.replace('/events', '/tlevents')
eventsFeed = \
personBoxJson(self.server.recentPostsCache,
self.server.session,
baseDir,
domain,
port,
path,
httpPrefix,
maxPostsInFeed, 'tlevents',
authorized,
0, self.server.positiveVoting,
self.server.votingTimeMins)
print('eventsFeed: ' + str(eventsFeed))
if eventsFeed:
if self._requestHTTP():
nickname = path.replace('/users/', '')
nickname = nickname.replace('/tlevents', '')
pageNumber = 1
if '?page=' in nickname:
pageNumber = nickname.split('?page=')[1]
nickname = nickname.split('?page=')[0]
if pageNumber.isdigit():
pageNumber = int(pageNumber)
else:
pageNumber = 1
if 'page=' not in path:
# if no page was specified then show the first
eventsFeed = \
personBoxJson(self.server.recentPostsCache,
self.server.session,
baseDir,
domain,
port,
path + '?page=1',
httpPrefix,
maxPostsInFeed,
'tlevents',
authorized,
0, self.server.positiveVoting,
self.server.votingTimeMins)
fullWidthTimelineButtonHeader = \
self.server.fullWidthTimelineButtonHeader
minimalNick = isMinimal(baseDir, domain, nickname)
accessKeys = self.server.accessKeys
if self.server.keyShortcuts.get(nickname):
accessKeys = \
self.server.keyShortcuts[nickname]
msg = \
htmlEvents(self.server.cssCache,
self.server.defaultTimeline,
self.server.recentPostsCache,
self.server.maxRecentPosts,
self.server.translate,
pageNumber, maxPostsInFeed,
self.server.session,
baseDir,
self.server.cachedWebfingers,
self.server.personCache,
nickname,
domain,
port,
eventsFeed,
self.server.allowDeletion,
httpPrefix,
self.server.projectVersion,
minimalNick,
self.server.YTReplacementDomain,
self.server.showPublishedDateOnly,
self.server.newswire,
self.server.positiveVoting,
self.server.showPublishAsIcon,
fullWidthTimelineButtonHeader,
self.server.iconsAsButtons,
self.server.rssIconAtTop,
self.server.publishButtonAtTop,
authorized,
self.server.themeName,
self.server.peertubeInstances,
self.server.allowLocalNetworkAccess,
self.server.textModeBanner,
accessKeys)
msg = msg.encode('utf-8')
msglen = len(msg)
self._set_headers('text/html', msglen,
cookie, callingDomain)
self._write(msg)
self._benchmarkGETtimings(GETstartTime, GETtimings,
'show bookmarks 2 done',
'show events')
else:
# don't need authenticated fetch here because
# there is already the authorization check
msg = json.dumps(eventsFeed,
ensure_ascii=False)
msg = msg.encode('utf-8')
msglen = len(msg)
self._set_headers('application/json', msglen,
None, callingDomain)
self._write(msg)
self.server.GETbusy = False
return True
else:
if debug:
nickname = path.replace('/users/', '')
nickname = nickname.replace('/tlevents', '')
print('DEBUG: ' + nickname +
' was not authorized to access ' + path)
if debug:
print('DEBUG: GET access to events is unauthorized')
self.send_response(405)
self.end_headers()
self.server.GETbusy = False
return True
def _showOutboxTimeline(self, authorized: bool,
callingDomain: str, path: str,
baseDir: str, httpPrefix: str,
@ -10202,7 +10068,7 @@ class PubServer(BaseHTTPRequestHandler):
GETstartTime, GETtimings: {}) -> bool:
"""Show a shared item image
"""
if not pathIsImage(path):
if not isImageFile(path):
self._404()
return True
@ -10252,7 +10118,7 @@ class PubServer(BaseHTTPRequestHandler):
if '/accounts/avatars/' not in path:
if '/accounts/headers/' not in path:
return False
if not pathIsImage(path):
if not isImageFile(path):
return False
if '/accounts/avatars/' in path:
avatarStr = path.split('/accounts/avatars/')[1]
@ -10385,7 +10251,7 @@ class PubServer(BaseHTTPRequestHandler):
# Various types of new post in the web interface
newPostEnd = ('newpost', 'newblog', 'newunlisted',
'newfollowers', 'newdm', 'newreminder',
'newevent', 'newreport', 'newquestion',
'newreport', 'newquestion',
'newshare')
for postType in newPostEnd:
if path.endswith('/' + postType):
@ -10578,44 +10444,6 @@ class PubServer(BaseHTTPRequestHandler):
return True
return False
def _editEvent(self, callingDomain: str, path: str,
httpPrefix: str, domain: str, domainFull: str,
baseDir: str, translate: {},
mediaInstance: bool,
cookie: str) -> bool:
"""Show edit event screen
"""
messageId = path.split('?editeventpost=')[1]
if '?' in messageId:
messageId = messageId.split('?')[0]
actor = path.split('?actor=')[1]
if '?' in actor:
actor = actor.split('?')[0]
nickname = getNicknameFromActor(path)
if nickname == actor:
# postUrl = \
# httpPrefix + '://' + \
# domainFull + '/users/' + nickname + \
# '/statuses/' + messageId
msg = None
# TODO
# htmlEditEvent(mediaInstance,
# translate,
# baseDir,
# httpPrefix,
# path,
# nickname, domain,
# postUrl)
if msg:
msg = msg.encode('utf-8')
msglen = len(msg)
self._set_headers('text/html', msglen,
cookie, callingDomain)
self._write(msg)
self.server.GETbusy = False
return True
return False
def _getFollowingJson(self, baseDir: str, path: str,
callingDomain: str,
httpPrefix: str,
@ -11474,7 +11302,7 @@ class PubServer(BaseHTTPRequestHandler):
# if not authorized then show the login screen
if htmlGET and self.path != '/login' and \
not pathIsImage(self.path) and \
not isImageFile(self.path) and \
self.path != '/' and \
self.path != '/users/news/linksmobile' and \
self.path != '/users/news/newswiremobile':
@ -12498,21 +12326,6 @@ class PubServer(BaseHTTPRequestHandler):
self.server.GETbusy = False
return
# Edit an event
if authorized and \
'/tlevents' in self.path and \
'?editeventpost=' in self.path and \
'?actor=' in self.path:
if self._editEvent(callingDomain, self.path,
self.server.httpPrefix,
self.server.domain,
self.server.domainFull,
self.server.baseDir,
self.server.translate,
self.server.mediaInstance,
cookie):
return
# edit profile in web interface
if self._editProfile(callingDomain, self.path,
self.server.translate,
@ -12931,29 +12744,6 @@ class PubServer(BaseHTTPRequestHandler):
'show shares 2 done',
'show bookmarks 2 done')
# get the events for a given person
if self.path.endswith('/tlevents') or \
'/tlevents?page=' in self.path or \
self.path.endswith('/events') or \
'/events?page=' in self.path:
if self._showEventsTimeline(authorized,
callingDomain, self.path,
self.server.baseDir,
self.server.httpPrefix,
self.server.domain,
self.server.domainFull,
self.server.port,
self.server.onionDomain,
self.server.i2pDomain,
GETstartTime, GETtimings,
self.server.proxyType,
cookie, self.server.debug):
return
self._benchmarkGETtimings(GETstartTime, GETtimings,
'show bookmarks 2 done',
'show events done')
# outbox timeline
if self._showOutboxTimeline(authorized,
callingDomain, self.path,
@ -13135,7 +12925,7 @@ class PubServer(BaseHTTPRequestHandler):
fileLength = -1
if '/media/' in self.path:
if pathIsImage(self.path) or \
if isImageFile(self.path) or \
pathIsVideo(self.path) or \
pathIsAudio(self.path):
mediaStr = self.path.split('/media/')[1]
@ -13235,12 +13025,7 @@ class PubServer(BaseHTTPRequestHandler):
print('DEBUG: no media filename in POST')
if filename:
if filename.endswith('.png') or \
filename.endswith('.jpg') or \
filename.endswith('.webp') or \
filename.endswith('.avif') or \
filename.endswith('.svg') or \
filename.endswith('.gif'):
if isImageFile(filename):
postImageFilename = filename.replace('.temp', '')
print('Removing metadata from ' + postImageFilename)
city = getSpoofedCity(self.server.city,
@ -13338,11 +13123,6 @@ class PubServer(BaseHTTPRequestHandler):
else:
commentsEnabled = True
if not fields.get('privateEvent'):
privateEvent = False
else:
privateEvent = True
if postType == 'newpost':
if not fields.get('pinToProfile'):
pinToProfile = False
@ -13425,14 +13205,20 @@ class PubServer(BaseHTTPRequestHandler):
print('WARN: blog posts must have content')
return -1
# submit button on newblog screen
followersOnly = False
saveToFile = False
clientToServer = False
city = None
messageJson = \
createBlogPost(self.server.baseDir, nickname,
self.server.domain, self.server.port,
self.server.httpPrefix,
fields['message'],
False, False, False, commentsEnabled,
followersOnly, saveToFile,
clientToServer, commentsEnabled,
filename, attachmentMediaType,
fields['imageDescription'],
city,
fields['replyTo'], fields['replyTo'],
fields['subject'],
fields['schedulePost'],
@ -13545,13 +13331,17 @@ class PubServer(BaseHTTPRequestHandler):
self.server.baseDir,
nickname,
self.server.domain)
followersOnly = False
saveToFile = False
clientToServer = False
messageJson = \
createUnlistedPost(self.server.baseDir,
nickname,
self.server.domain, self.server.port,
self.server.httpPrefix,
mentionsStr + fields['message'],
False, False, False, commentsEnabled,
followersOnly, saveToFile,
clientToServer, commentsEnabled,
filename, attachmentMediaType,
fields['imageDescription'],
city,
@ -13580,6 +13370,9 @@ class PubServer(BaseHTTPRequestHandler):
self.server.baseDir,
nickname,
self.server.domain)
followersOnly = True
saveToFile = False
clientToServer = False
messageJson = \
createFollowersOnlyPost(self.server.baseDir,
nickname,
@ -13587,7 +13380,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.port,
self.server.httpPrefix,
mentionsStr + fields['message'],
True, False, False,
followersOnly, saveToFile,
clientToServer,
commentsEnabled,
filename, attachmentMediaType,
fields['imageDescription'],
@ -13612,64 +13406,6 @@ class PubServer(BaseHTTPRequestHandler):
return 1
else:
return -1
elif postType == 'newevent':
# A Mobilizon-type event is posted
# if there is no image dscription then make it the same
# as the event title
if not fields.get('imageDescription'):
fields['imageDescription'] = fields['subject']
# Events are public by default, with opt-in
# followers only status
if not fields.get('followersOnlyEvent'):
fields['followersOnlyEvent'] = False
if not fields.get('anonymousParticipationEnabled'):
anonymousParticipationEnabled = False
else:
anonymousParticipationEnabled = True
maximumAttendeeCapacity = 999999
if fields.get('maximumAttendeeCapacity'):
maximumAttendeeCapacity = \
int(fields['maximumAttendeeCapacity'])
city = getSpoofedCity(self.server.city,
self.server.baseDir,
nickname,
self.server.domain)
messageJson = \
createEventPost(self.server.baseDir,
nickname,
self.server.domain,
self.server.port,
self.server.httpPrefix,
mentionsStr + fields['message'],
privateEvent,
False, False, commentsEnabled,
filename, attachmentMediaType,
fields['imageDescription'],
city,
fields['subject'],
fields['schedulePost'],
fields['eventDate'],
fields['eventTime'],
fields['location'],
fields['category'],
fields['joinMode'],
fields['endDate'],
fields['endTime'],
maximumAttendeeCapacity,
fields['repliesModerationOption'],
anonymousParticipationEnabled,
fields['eventStatus'],
fields['ticketUrl'])
if messageJson:
if fields['schedulePost']:
return 1
if self._postToOutbox(messageJson, __version__, nickname):
return 1
else:
return -1
elif postType == 'newdm':
messageJson = None
print('A DM was posted')
@ -13678,6 +13414,9 @@ class PubServer(BaseHTTPRequestHandler):
self.server.baseDir,
nickname,
self.server.domain)
followersOnly = True
saveToFile = False
clientToServer = False
messageJson = \
createDirectMessagePost(self.server.baseDir,
nickname,
@ -13686,7 +13425,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.httpPrefix,
mentionsStr +
fields['message'],
True, False, False,
followersOnly, saveToFile,
clientToServer,
commentsEnabled,
filename, attachmentMediaType,
fields['imageDescription'],
@ -13723,6 +13463,10 @@ class PubServer(BaseHTTPRequestHandler):
self.server.baseDir,
nickname,
self.server.domain)
followersOnly = True
saveToFile = False
clientToServer = False
commentsEnabled = False
messageJson = \
createDirectMessagePost(self.server.baseDir,
nickname,
@ -13730,7 +13474,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.port,
self.server.httpPrefix,
mentionsStr + fields['message'],
True, False, False, False,
followersOnly, saveToFile,
clientToServer, commentsEnabled,
filename, attachmentMediaType,
fields['imageDescription'],
city,
@ -14172,7 +13917,6 @@ class PubServer(BaseHTTPRequestHandler):
if not self.path.endswith('confirm'):
self.path = self.path.replace('/outbox/', '/outbox')
self.path = self.path.replace('/tlblogs/', '/tlblogs')
self.path = self.path.replace('/tlevents/', '/tlevents')
self.path = self.path.replace('/inbox/', '/inbox')
self.path = self.path.replace('/shares/', '/shares')
self.path = self.path.replace('/sharedInbox/', '/sharedInbox')
@ -14510,7 +14254,7 @@ class PubServer(BaseHTTPRequestHandler):
# receive different types of post created by htmlNewPost
postTypes = ("newpost", "newblog", "newunlisted", "newfollowers",
"newdm", "newreport", "newshare", "newquestion",
"editblogpost", "newreminder", "newevent")
"editblogpost", "newreminder")
for currPostType in postTypes:
if not authorized:
if self.server.debug:
@ -14520,8 +14264,6 @@ class PubServer(BaseHTTPRequestHandler):
postRedirect = self.server.defaultTimeline
if currPostType == 'newshare':
postRedirect = 'shares'
elif currPostType == 'newevent':
postRedirect = 'tlevents'
pageNumber = \
self._receiveNewPost(currPostType, self.path,

View File

@ -1602,9 +1602,7 @@ if args.proxyPort:
setConfigParam(baseDir, 'proxyPort', proxyPort)
if args.gnunet:
httpPrefix = 'gnunet'
if args.dat:
httpPrefix = 'dat'
if args.hyper:
if args.dat or args.hyper:
httpPrefix = 'hyper'
if args.i2p:
httpPrefix = 'http'
@ -1645,7 +1643,7 @@ if args.followers:
if '/@' in args.followers or \
'/users/' in args.followers or \
args.followers.startswith('http') or \
args.followers.startswith('dat'):
args.followers.startswith('hyper'):
# format: https://domain/@nick
prefixes = getProtocolPrefixes()
for prefix in prefixes:
@ -2312,6 +2310,14 @@ if args.testdata:
testMediaType = None
testImageDescription = None
testCity = 'London, England'
testInReplyTo = None
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"like this is totally just a #test man",
@ -2320,7 +2326,11 @@ if args.testdata:
testC2S,
testCommentsEnabled,
testAttachImageFilename,
testMediaType, testImageDescription, testCity)
testMediaType, testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"Zoiks!!!",
testFollowersOnly,
@ -2328,7 +2338,11 @@ if args.testdata:
testC2S,
testCommentsEnabled,
testAttachImageFilename,
testMediaType, testImageDescription, testCity)
testMediaType, testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"Hey scoob we need like a hundred more #milkshakes",
testFollowersOnly,
@ -2336,7 +2350,11 @@ if args.testdata:
testC2S,
testCommentsEnabled,
testAttachImageFilename,
testMediaType, testImageDescription, testCity)
testMediaType, testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"Getting kinda spooky around here",
testFollowersOnly,
@ -2345,7 +2363,10 @@ if args.testdata:
testCommentsEnabled,
testAttachImageFilename,
testMediaType, testImageDescription, testCity,
'someone')
'someone', testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"And they would have gotten away with it too" +
"if it wasn't for those pesky hackers",
@ -2354,7 +2375,11 @@ if args.testdata:
testC2S,
testCommentsEnabled,
'img/logo.png', 'image/png',
'Description of image', testCity)
'Description of image', testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"man these centralized sites are like the worst!",
testFollowersOnly,
@ -2362,7 +2387,11 @@ if args.testdata:
testC2S,
testCommentsEnabled,
testAttachImageFilename,
testMediaType, testImageDescription, testCity)
testMediaType, testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"another mystery solved #test",
testFollowersOnly,
@ -2370,7 +2399,11 @@ if args.testdata:
testC2S,
testCommentsEnabled,
testAttachImageFilename,
testMediaType, testImageDescription, testCity)
testMediaType, testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"let's go bowling",
testFollowersOnly,
@ -2378,8 +2411,11 @@ if args.testdata:
testC2S,
testCommentsEnabled,
testAttachImageFilename,
testMediaType, testImageDescription, testCity)
testMediaType, testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
domainFull = domain + ':' + str(port)
clearFollows(baseDir, nickname, domain)
followPerson(baseDir, nickname, domain, 'maxboardroom', domainFull,

View File

@ -338,7 +338,7 @@ def _getNoOfFollows(baseDir: str, nickname: str, domain: str,
not line.startswith('http'):
ctr += 1
elif ((line.startswith('http') or
line.startswith('dat')) and
line.startswith('hyper')) and
hasUsersPath(line)):
ctr += 1
return ctr
@ -456,7 +456,7 @@ def getFollowingFeed(baseDir: str, domain: str, port: int, path: str,
line2.split('@')[0]
following['orderedItems'].append(url)
elif ((line.startswith('http') or
line.startswith('dat')) and
line.startswith('hyper')) and
hasUsersPath(line)):
# https://domain/users/nickname
pageCtr += 1

View File

@ -168,7 +168,7 @@ def _inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int,
"""
pageNumber = -999
avatarUrl = None
if boxname != 'tlevents' and boxname != 'outbox':
if boxname != 'outbox':
boxname = 'inbox'
individualPostAsHtml(True, recentPostsCache, maxRecentPosts,
@ -2504,9 +2504,6 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
if isBlogPost(postJsonObject):
# blogs index will be updated
updateIndexList.append('tlblogs')
elif isEventPost(postJsonObject):
# events index will be updated
updateIndexList.append('tlevents')
# get the avatar for a reply/announce
_obtainAvatarForReplyPost(session, baseDir,

View File

@ -9,6 +9,7 @@ __module_group__ = "Timeline"
import os
import datetime
import subprocess
from random import randint
from hashlib import sha1
from auth import createPassword
@ -245,6 +246,13 @@ def attachMedia(baseDir: str, httpPrefix: str,
}
if mediaType.startswith('image/'):
attachmentJson['focialPoint'] = [0.0, 0.0]
# find the dimensions of the image and add them as metadata
attachImageWidth, attachImageHeight = \
getImageDimensions(imageFilename)
if attachImageWidth and attachImageHeight:
attachmentJson['width'] = attachImageWidth
attachmentJson['height'] = attachImageHeight
postJson['attachment'] = [attachmentJson]
if baseDir:
@ -286,17 +294,6 @@ def archiveMedia(baseDir: str, archiveDirectory: str, maxWeeks=4) -> None:
break
def pathIsImage(path: str) -> bool:
if path.endswith('.png') or \
path.endswith('.jpg') or \
path.endswith('.gif') or \
path.endswith('.svg') or \
path.endswith('.avif') or \
path.endswith('.webp'):
return True
return False
def pathIsVideo(path: str) -> bool:
if path.endswith('.ogv') or \
path.endswith('.mp4'):
@ -309,3 +306,25 @@ def pathIsAudio(path: str) -> bool:
path.endswith('.mp3'):
return True
return False
def getImageDimensions(imageFilename: str) -> (int, int):
"""Returns the dimensions of an image file
"""
try:
result = subprocess.run(['identify', '-format', '"%wx%h"',
imageFilename], stdout=subprocess.PIPE)
except BaseException:
return None, None
if not result:
return None, None
dimensionsStr = result.stdout.decode('utf-8').replace('"', '')
if 'x' not in dimensionsStr:
return None, None
widthStr = dimensionsStr.split('x')[0]
if not widthStr.isdigit():
return None, None
heightStr = dimensionsStr.split('x')[1]
if not heightStr.isdigit():
return None, None
return int(widthStr), int(heightStr)

View File

@ -337,8 +337,6 @@ def postMessageToOutbox(session, translate: {},
if messageJson['object'].get('type'):
if messageJson['object']['type'] == 'Article':
outboxName = 'tlblogs'
elif messageJson['object']['type'] == 'Event':
outboxName = 'tlevents'
savedFilename = \
savePostToBox(baseDir,

View File

@ -28,7 +28,6 @@ from posts import createNewsTimeline
from posts import createBlogsTimeline
from posts import createFeaturesTimeline
from posts import createBookmarksTimeline
from posts import createEventsTimeline
from posts import createInbox
from posts import createOutbox
from posts import createModeration
@ -746,8 +745,7 @@ def personBoxJson(recentPostsCache: {},
boxname != 'tlblogs' and boxname != 'tlnews' and \
boxname != 'tlfeatures' and \
boxname != 'outbox' and boxname != 'moderation' and \
boxname != 'tlbookmarks' and boxname != 'bookmarks' and \
boxname != 'tlevents':
boxname != 'tlbookmarks' and boxname != 'bookmarks':
return None
if not '/' + boxname in path:
@ -796,12 +794,6 @@ def personBoxJson(recentPostsCache: {},
port, httpPrefix,
noOfItems, headerOnly,
pageNumber)
elif boxname == 'tlevents':
return createEventsTimeline(recentPostsCache,
session, baseDir, nickname, domain,
port, httpPrefix,
noOfItems, headerOnly,
pageNumber)
elif boxname == 'tlreplies':
return createRepliesTimeline(recentPostsCache,
session, baseDir, nickname, domain,
@ -1208,7 +1200,7 @@ def getActorJson(hostDomain: str, handle: str, http: bool, gnunet: bool,
if '/@' in handle or \
'/users/' in handle or \
handle.startswith('http') or \
handle.startswith('dat'):
handle.startswith('hyper'):
# format: https://domain/@nick
originalHandle = handle
if not hasUsersPath(originalHandle):

148
posts.py
View File

@ -14,7 +14,6 @@ import os
import shutil
import sys
import time
import uuid
import random
from socket import error as SocketError
from time import gmtime, strftime
@ -657,8 +656,7 @@ def deleteAllPosts(baseDir: str,
"""Deletes all posts for a person from inbox or outbox
"""
if boxname != 'inbox' and boxname != 'outbox' and \
boxname != 'tlblogs' and boxname != 'tlnews' and \
boxname != 'tlevents':
boxname != 'tlblogs' and boxname != 'tlnews':
return
boxDir = createPersonDir(nickname, domain, baseDir, boxname)
for deleteFilename in os.scandir(boxDir):
@ -681,7 +679,6 @@ def savePostToBox(baseDir: str, httpPrefix: str, postId: str,
"""
if boxname != 'inbox' and boxname != 'outbox' and \
boxname != 'tlblogs' and boxname != 'tlnews' and \
boxname != 'tlevents' and \
boxname != 'scheduled':
return None
originalDomain = domain
@ -1066,18 +1063,18 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
mediaType: str, imageDescription: str, city: str,
isModerationReport: bool,
isArticle: bool,
inReplyTo: str = None,
inReplyToAtomUri: str = None,
subject: str = None, schedulePost: bool = False,
eventDate: str = None, eventTime: str = None,
location: str = None,
eventUUID: str = None, category: str = None,
joinMode: str = None,
endDate: str = None, endTime: str = None,
maximumAttendeeCapacity: int = None,
repliesModerationOption: str = None,
anonymousParticipationEnabled: bool = None,
eventStatus: str = None, ticketUrl: str = None) -> {}:
inReplyTo: str,
inReplyToAtomUri: str,
subject: str, schedulePost: bool,
eventDate: str, eventTime: str,
location: str,
eventUUID: str, category: str,
joinMode: str,
endDate: str, endTime: str,
maximumAttendeeCapacity: int,
repliesModerationOption: str,
anonymousParticipationEnabled: bool,
eventStatus: str, ticketUrl: str) -> {}:
"""Creates a message
"""
content = removeInvalidChars(content)
@ -1244,9 +1241,6 @@ def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
if isArticle:
savePostToBox(baseDir, httpPrefix, newPostId,
nickname, domain, newPost, 'tlblogs')
elif eventUUID:
savePostToBox(baseDir, httpPrefix, newPostId,
nickname, domain, newPost, 'tlevents')
else:
savePostToBox(baseDir, httpPrefix, newPostId,
nickname, domain, newPost, 'outbox')
@ -1426,12 +1420,12 @@ def createPublicPost(baseDir: str,
clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str,
imageDescription: str, city: str,
inReplyTo: str = None,
inReplyToAtomUri: str = None, subject: str = None,
schedulePost: bool = False,
eventDate: str = None, eventTime: str = None,
location: str = None,
isArticle: bool = False) -> {}:
inReplyTo: str,
inReplyToAtomUri: str, subject: str,
schedulePost: bool,
eventDate: str, eventTime: str,
location: str,
isArticle: bool) -> {}:
"""Public post
"""
domainFull = getFullDomain(domain, port)
@ -1501,10 +1495,10 @@ def createBlogPost(baseDir: str,
clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str,
imageDescription: str, city: str,
inReplyTo: str = None, inReplyToAtomUri: str = None,
subject: str = None, schedulePost: bool = False,
eventDate: str = None, eventTime: str = None,
location: str = None) -> {}:
inReplyTo: str, inReplyToAtomUri: str,
subject: str, schedulePost: bool,
eventDate: str, eventTime: str,
location: str) -> {}:
blogJson = \
createPublicPost(baseDir,
nickname, domain, port, httpPrefix,
@ -1600,10 +1594,10 @@ def createUnlistedPost(baseDir: str,
clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str,
imageDescription: str, city: str,
inReplyTo: str = None, inReplyToAtomUri: str = None,
subject: str = None, schedulePost: bool = False,
eventDate: str = None, eventTime: str = None,
location: str = None) -> {}:
inReplyTo: str, inReplyToAtomUri: str,
subject: str, schedulePost: bool,
eventDate: str, eventTime: str,
location: str) -> {}:
"""Unlisted post. This has the #Public and followers links inverted.
"""
domainFull = getFullDomain(domain, port)
@ -1630,11 +1624,11 @@ def createFollowersOnlyPost(baseDir: str,
clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str,
imageDescription: str, city: str,
inReplyTo: str = None,
inReplyToAtomUri: str = None,
subject: str = None, schedulePost: bool = False,
eventDate: str = None, eventTime: str = None,
location: str = None) -> {}:
inReplyTo: str,
inReplyToAtomUri: str,
subject: str, schedulePost: bool,
eventDate: str, eventTime: str,
location: str) -> {}:
"""Followers only post
"""
domainFull = getFullDomain(domain, port)
@ -1653,57 +1647,6 @@ def createFollowersOnlyPost(baseDir: str,
None, None, None, None, None)
def createEventPost(baseDir: str,
nickname: str, domain: str, port: int,
httpPrefix: str,
content: str, followersOnly: bool,
saveToFile: bool,
clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str, mediaType: str,
imageDescription: str, city: str,
subject: str = None, schedulePost: str = False,
eventDate: str = None, eventTime: str = None,
location: str = None, category: str = None,
joinMode: str = None,
endDate: str = None, endTime: str = None,
maximumAttendeeCapacity: int = None,
repliesModerationOption: str = None,
anonymousParticipationEnabled: bool = None,
eventStatus: str = None, ticketUrl: str = None) -> {}:
"""Mobilizon-type Event post
"""
if not attachImageFilename:
print('Event has no attached image')
return None
if not category:
print('Event has no category')
return None
domainFull = getFullDomain(domain, port)
# create event uuid
eventUUID = str(uuid.uuid1())
toStr1 = 'https://www.w3.org/ns/activitystreams#Public'
toStr2 = httpPrefix + '://' + domainFull + '/users/' + \
nickname + '/followers',
if followersOnly:
toStr1 = toStr2
toStr2 = None
return _createPostBase(baseDir, nickname, domain, port,
toStr1, toStr2,
httpPrefix, content, followersOnly, saveToFile,
clientToServer, commentsEnabled,
attachImageFilename, mediaType,
imageDescription, city,
False, False, None, None, subject,
schedulePost, eventDate, eventTime, location,
eventUUID, category, joinMode,
endDate, endTime, maximumAttendeeCapacity,
repliesModerationOption,
anonymousParticipationEnabled,
eventStatus, ticketUrl)
def getMentionedPeople(baseDir: str, httpPrefix: str,
content: str, domain: str, debug: bool) -> []:
"""Extracts a list of mentioned actors from the given message content
@ -1747,12 +1690,12 @@ def createDirectMessagePost(baseDir: str,
commentsEnabled: bool,
attachImageFilename: str, mediaType: str,
imageDescription: str, city: str,
inReplyTo: str = None,
inReplyToAtomUri: str = None,
subject: str = None, debug: bool = False,
schedulePost: bool = False,
eventDate: str = None, eventTime: str = None,
location: str = None) -> {}:
inReplyTo: str,
inReplyToAtomUri: str,
subject: str, debug: bool,
schedulePost: bool,
eventDate: str, eventTime: str,
location: str) -> {}:
"""Direct Message post
"""
content = resolvePetnames(baseDir, nickname, domain, content)
@ -1825,7 +1768,7 @@ def createReportPost(baseDir: str,
if moderatorActor not in moderatorsList:
moderatorsList.append(moderatorActor)
continue
if line.startswith('http') or line.startswith('dat'):
if line.startswith('http') or line.startswith('hyper'):
# must be a local address - no remote moderators
if '://' + domainFull + '/' in line:
if line not in moderatorsList:
@ -2835,16 +2778,6 @@ def createBookmarksTimeline(session, baseDir: str, nickname: str, domain: str,
True, 0, False, 0, pageNumber)
def createEventsTimeline(recentPostsCache: {},
session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str, itemsPerPage: int,
headerOnly: bool, pageNumber: int = None) -> {}:
return _createBoxIndexed(recentPostsCache, session, baseDir, 'tlevents',
nickname, domain,
port, httpPrefix, itemsPerPage, headerOnly,
True, 0, False, 0, pageNumber)
def createDMTimeline(recentPostsCache: {},
session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str, itemsPerPage: int,
@ -3179,8 +3112,7 @@ def _createBoxIndexed(recentPostsCache: {},
boxname != 'tlblogs' and boxname != 'tlnews' and \
boxname != 'tlfeatures' and \
boxname != 'outbox' and boxname != 'tlbookmarks' and \
boxname != 'bookmarks' and \
boxname != 'tlevents':
boxname != 'bookmarks':
return None
# bookmarks and events timelines are like the inbox

View File

@ -371,7 +371,7 @@ def load_document(url):
# validate URL
pieces = urllib_parse.urlparse(url)
if (not all([pieces.scheme, pieces.netloc]) or
pieces.scheme not in ['http', 'https', 'dat'] or
pieces.scheme not in ['http', 'https', 'hyper'] or
set(pieces.netloc) > set(
string.ascii_letters + string.digits + '-.:')):
raise JsonLdError(

136
tests.py
View File

@ -86,6 +86,7 @@ from announce import sendAnnounceViaServer
from city import parseNogoString
from city import spoofGeolocation
from city import pointInNogo
from media import getImageDimensions
from media import getMediaPath
from media import getAttachmentMediaType
from delete import sendDeleteViaServer
@ -476,6 +477,14 @@ def createServerAlice(path: str, domain: str, port: int,
testMediaType = None
testImageDescription = None
testCity = 'London, England'
testInReplyTo = None
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
createPublicPost(path, nickname, domain, port, httpPrefix,
"No wise fish would go anywhere without a porpoise",
testFollowersOnly,
@ -484,7 +493,11 @@ def createServerAlice(path: str, domain: str, port: int,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription, testCity)
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
createPublicPost(path, nickname, domain, port, httpPrefix,
"Curiouser and curiouser!",
testFollowersOnly,
@ -493,7 +506,11 @@ def createServerAlice(path: str, domain: str, port: int,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription, testCity)
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
createPublicPost(path, nickname, domain, port, httpPrefix,
"In the gardens of memory, in the palace " +
"of dreams, that is where you and I shall meet",
@ -503,7 +520,11 @@ def createServerAlice(path: str, domain: str, port: int,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription, testCity)
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
global testServerAliceRunning
testServerAliceRunning = True
maxMentions = 10
@ -581,6 +602,14 @@ def createServerBob(path: str, domain: str, port: int,
testImageDescription = None
testMediaType = None
testCity = 'London, England'
testInReplyTo = None
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
createPublicPost(path, nickname, domain, port, httpPrefix,
"It's your life, live it your way.",
testFollowersOnly,
@ -589,7 +618,11 @@ def createServerBob(path: str, domain: str, port: int,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription, testCity)
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
createPublicPost(path, nickname, domain, port, httpPrefix,
"One of the things I've realised is that " +
"I am very simple",
@ -599,7 +632,11 @@ def createServerBob(path: str, domain: str, port: int,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription, testCity)
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
createPublicPost(path, nickname, domain, port, httpPrefix,
"Quantum physics is a bit of a passion of mine",
testFollowersOnly,
@ -608,7 +645,11 @@ def createServerBob(path: str, domain: str, port: int,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription, testCity)
testImageDescription, testCity,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
global testServerBobRunning
testServerBobRunning = True
maxMentions = 10
@ -792,6 +833,10 @@ def testPostMessageBetweenServers():
alicePersonCache = {}
aliceCachedWebfingers = {}
attachedImageFilename = baseDir + '/img/logo.png'
testImageWidth, testImageHeight = \
getImageDimensions(attachedImageFilename)
assert testImageWidth
assert testImageHeight
mediaType = getAttachmentMediaType(attachedImageFilename)
attachedImageDescription = 'Logo'
isArticle = False
@ -875,6 +920,20 @@ def testPostMessageBetweenServers():
assert 'Why is a mouse when it spins?' in \
receivedJson['object']['content']
assert 'यह एक परीक्षण है' in receivedJson['object']['content']
print('Check that message received from Alice contains an attachment')
assert receivedJson['object']['attachment']
assert len(receivedJson['object']['attachment']) == 1
attached = receivedJson['object']['attachment'][0]
pprint(attached)
assert attached.get('type')
assert attached.get('url')
assert attached['mediaType'] == 'image/png'
assert '/media/' in attached['url']
assert attached['url'].endswith('.png')
assert attached.get('width')
assert attached.get('height')
assert attached['width'] > 0
assert attached['height'] > 0
print('\n\n*******************************************************')
print("Bob likes Alice's post")
@ -1416,10 +1475,28 @@ def _testCreatePerson():
setBio(baseDir, nickname, domain, 'Randomly roaming in your backyard')
archivePostsForPerson(nickname, domain, baseDir, 'inbox', None, {}, 4)
archivePostsForPerson(nickname, domain, baseDir, 'outbox', None, {}, 4)
testInReplyTo = None
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
content = "G'day world!"
followersOnly = False
saveToFile = True
commentsEnabled = True
attachImageFilename = None
mediaType = None
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"G'day world!", False, True, clientToServer,
True, None, None, None, None,
'Not suitable for Vogons', 'London, England')
content, followersOnly, saveToFile, clientToServer,
commentsEnabled, attachImageFilename, mediaType,
'Not suitable for Vogons', 'London, England',
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
os.chdir(currDir)
shutil.rmtree(baseDir)
@ -2802,12 +2879,23 @@ def _testReplyToPublicPost() -> None:
mediaType = None
imageDescription = 'Some description'
city = 'London, England'
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
reply = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
content, followersOnly, saveToFile,
clientToServer, commentsEnabled,
attachImageFilename, mediaType,
imageDescription, city, postId)
imageDescription, city, postId,
testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
# print(str(reply))
assert reply['object']['content'] == \
'<p><span class=\"h-card\">' + \
@ -3365,16 +3453,30 @@ def _testLinksWithinPost() -> None:
saveToFile = False
clientToServer = False
commentsEnabled = True
attachImageFilename = None
mediaType = None
imageDescription = None
city = 'London, England'
testInReplyTo = None
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
testEventDate = None
testEventTime = None
testLocation = None
testIsArticle = False
postJsonObject = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
content, followersOnly, saveToFile,
clientToServer, commentsEnabled,
mediaType, imageDescription, city,
False, None)
attachImageFilename, mediaType,
imageDescription, city,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
assert postJsonObject['object']['content'] == \
'<p>This is a test post with links.<br><br>' + \
'<a href="ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/v4/" ' + \
@ -3400,8 +3502,14 @@ def _testLinksWithinPost() -> None:
postJsonObject = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
content,
False, False, False, True,
None, None, False, None)
False, False,
False, True,
None, None,
False, None,
testInReplyTo, testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
testIsArticle)
assert postJsonObject['object']['content'] == content

View File

@ -270,6 +270,15 @@ def getImageFormats() -> str:
return imageFormats
def isImageFile(filename: str) -> bool:
"""Is the given filename an image?
"""
for ext in getImageExtensions():
if filename.endswith('.' + ext):
return True
return False
def getMediaFormats() -> str:
"""Returns a string of permissable media formats
used when selecting an attachment for a new post
@ -1130,7 +1139,7 @@ def locatePost(baseDir: str, nickname: str, domain: str,
postUrl = postUrl + '.' + extension
# search boxes
boxes = ('inbox', 'outbox', 'tlblogs', 'tlevents')
boxes = ('inbox', 'outbox', 'tlblogs')
accountDir = baseDir + '/accounts/' + nickname + '@' + domain + '/'
for boxName in boxes:
postFilename = accountDir + boxName + '/' + postUrl
@ -1392,7 +1401,7 @@ def _isReservedName(nickname: str) -> bool:
'public', 'followers', 'category',
'channel', 'calendar',
'tlreplies', 'tlmedia', 'tlblogs',
'tlevents', 'tlblogs', 'tlfeatures',
'tlblogs', 'tlfeatures',
'moderation', 'moderationaction',
'activity', 'undo', 'pinned',
'reply', 'replies', 'question', 'like',

View File

@ -129,20 +129,6 @@ def _htmlTimelineNewPost(manuallyApproveFollowers: bool,
'<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?nodropdown"><img loading="lazy" src="/' + \
'icons/newpost.png" title="' + \
translate['Create a new event'] + '" alt="| ' + \
translate['Create a new event'] + \
'" class="timelineicon"/></a>\n'
else:
newPostButtonStr += \
'<a href="' + usersPath + '/newevent?nodropdown">' + \
'<button class="button"><span>' + \
translate['Post'] + '</span></button></a>'
elif boxName == 'tlshares':
if not iconsAsButtons:
newPostButtonStr += \
@ -500,8 +486,6 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
sharesButton = 'buttonselectedhighlighted'
elif boxName == 'tlbookmarks' or boxName == 'bookmarks':
bookmarksButton = 'buttonselected'
# elif boxName == 'tlevents':
# eventsButton = 'buttonselected'
# get the full domain, including any port number
fullDomain = getFullDomain(domain, port)
@ -559,11 +543,6 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
'<a href="' + usersPath + '/tlbookmarks"><button class="' + \
bookmarksButton + '"><span>' + translate['Bookmarks'] + \
'</span></button></a>'
#
# eventsButtonStr = \
# '<a href="' + usersPath + '/tlevents"><button class="' + \
# eventsButton + '"><span>' + translate['Events'] + \
# '</span></button></a>'
instanceTitle = \
getConfigParam(baseDir, 'instanceTitle')
@ -1054,51 +1033,6 @@ def htmlBookmarks(cssCache: {}, defaultTimeline: str,
accessKeys)
def htmlEvents(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,
session, baseDir: str,
cachedWebfingers: {}, 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, theme: str,
peertubeInstances: [],
allowLocalNetworkAccess: bool,
textModeBanner: str,
accessKeys: {}) -> str:
"""Show the events as html
"""
manuallyApproveFollowers = \
followerApprovalActive(baseDir, nickname, domain)
return htmlTimeline(cssCache, defaultTimeline,
recentPostsCache, maxRecentPosts,
translate, pageNumber,
itemsPerPage, session, baseDir,
cachedWebfingers, personCache,
nickname, domain, port, bookmarksJson,
'tlevents', allowDeletion,
httpPrefix, projectVersion, manuallyApproveFollowers,
minimal, YTReplacementDomain,
showPublishedDateOnly,
newswire, False, False,
positiveVoting, showPublishAsIcon,
fullWidthTimelineButtonHeader,
iconsAsButtons, rssIconAtTop, publishButtonAtTop,
authorized, None, theme, peertubeInstances,
allowLocalNetworkAccess, textModeBanner,
accessKeys)
def htmlInboxDMs(cssCache: {}, defaultTimeline: str,
recentPostsCache: {}, maxRecentPosts: int,
translate: {}, pageNumber: int, itemsPerPage: int,