Merge branch 'main' of gitlab.com:bashrc2/epicyon

merge-requests/30/head
Bob Mottram 2021-11-08 21:47:20 +00:00
commit 45bae8a2e9
36 changed files with 447 additions and 147 deletions

13
blog.py
View File

@ -420,7 +420,7 @@ def htmlBlogPost(session, authorized: bool,
postJsonObject: {}, postJsonObject: {},
peertubeInstances: [], peertubeInstances: [],
systemLanguage: str, personCache: {}, systemLanguage: str, personCache: {},
debug: bool) -> str: debug: bool, contentLicenseUrl: str) -> str:
"""Returns a html blog post """Returns a html blog post
""" """
blogStr = '' blogStr = ''
@ -431,12 +431,19 @@ def htmlBlogPost(session, authorized: bool,
instanceTitle = \ instanceTitle = \
getConfigParam(baseDir, 'instanceTitle') getConfigParam(baseDir, 'instanceTitle')
published = postJsonObject['object']['published'] published = postJsonObject['object']['published']
modified = published
if postJsonObject['object'].get('updated'):
modified = postJsonObject['object']['updated']
title = postJsonObject['object']['summary'] title = postJsonObject['object']['summary']
url = ''
if postJsonObject['object'].get('url'):
url = postJsonObject['object']['url']
snippet = _getSnippetFromBlogContent(postJsonObject, systemLanguage) snippet = _getSnippetFromBlogContent(postJsonObject, systemLanguage)
blogStr = htmlHeaderWithBlogMarkup(cssFilename, instanceTitle, blogStr = htmlHeaderWithBlogMarkup(cssFilename, instanceTitle,
httpPrefix, domainFull, nickname, httpPrefix, domainFull, nickname,
systemLanguage, published, systemLanguage, published, modified,
title, snippet) title, snippet, translate, url,
contentLicenseUrl)
_htmlBlogRemoveCwButton(blogStr, translate) _htmlBlogRemoveCwButton(blogStr, translate)
blogStr += _htmlBlogPostContent(debug, session, authorized, baseDir, blogStr += _htmlBlogPostContent(debug, session, authorized, baseDir,

177
daemon.py
View File

@ -508,7 +508,8 @@ class PubServer(BaseHTTPRequestHandler):
location, False, location, False,
self.server.systemLanguage, self.server.systemLanguage,
conversationId, conversationId,
self.server.lowBandwidth) self.server.lowBandwidth,
self.server.contentLicenseUrl)
if messageJson: if messageJson:
# name field contains the answer # name field contains the answer
messageJson['object']['name'] = answer messageJson['object']['name'] = answer
@ -1281,7 +1282,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.maxLikeCount, self.server.maxLikeCount,
self.server.maxRecentPosts, self.server.maxRecentPosts,
self.server.CWlists, self.server.CWlists,
self.server.listsEnabled) self.server.listsEnabled,
self.server.contentLicenseUrl)
def _getOutboxThreadIndex(self, nickname: str, def _getOutboxThreadIndex(self, nickname: str,
maxOutboxThreadsPerAccount: int) -> int: maxOutboxThreadsPerAccount: int) -> int:
@ -4357,7 +4359,7 @@ class PubServer(BaseHTTPRequestHandler):
domain: str, domainFull: str, domain: str, domainFull: str,
onionDomain: str, i2pDomain: str, onionDomain: str, i2pDomain: str,
debug: bool, allowLocalNetworkAccess: bool, debug: bool, allowLocalNetworkAccess: bool,
systemLanguage: str) -> None: systemLanguage: str, contentLicenseUrl: str) -> None:
"""Updates your user profile after editing via the Edit button """Updates your user profile after editing via the Edit button
on the profile screen on the profile screen
""" """
@ -4504,7 +4506,8 @@ class PubServer(BaseHTTPRequestHandler):
if self.server.lowBandwidth: if self.server.lowBandwidth:
convertImageToLowBandwidth(filename) convertImageToLowBandwidth(filename)
processMetaData(baseDir, nickname, domain, processMetaData(baseDir, nickname, domain,
filename, postImageFilename, city) filename, postImageFilename, city,
contentLicenseUrl)
if os.path.isfile(postImageFilename): if os.path.isfile(postImageFilename):
print('profile update POST ' + mType + print('profile update POST ' + mType +
' image, zip or font saved to ' + ' image, zip or font saved to ' +
@ -4900,6 +4903,24 @@ class PubServer(BaseHTTPRequestHandler):
setConfigParam(baseDir, setConfigParam(baseDir,
'libretranslateApiKey', '') 'libretranslateApiKey', '')
# change instance short description
if fields.get('contentLicenseUrl'):
if fields['contentLicenseUrl'] != \
self.server.contentLicenseUrl:
licenseStr = fields['contentLicenseUrl']
setConfigParam(baseDir,
'contentLicenseUrl',
licenseStr)
self.server.contentLicenseUrl = \
licenseStr
else:
licenseStr = \
'https://creativecommons.org/licenses/by/4.0'
setConfigParam(baseDir,
'contentLicenseUrl',
licenseStr)
self.server.contentLicenseUrl = licenseStr
# change instance short description # change instance short description
currInstanceDescriptionShort = \ currInstanceDescriptionShort = \
getConfigParam(baseDir, getConfigParam(baseDir,
@ -6049,9 +6070,14 @@ class PubServer(BaseHTTPRequestHandler):
"sizes": "144x144" "sizes": "144x144"
}, },
{ {
"src": "/logo152.png", "src": "/logo150.png",
"type": "image/png", "type": "image/png",
"sizes": "152x152" "sizes": "150x150"
},
{
"src": "/apple-touch-icon.png",
"type": "image/png",
"sizes": "180x180"
}, },
{ {
"src": "/logo192.png", "src": "/logo192.png",
@ -6092,6 +6118,33 @@ class PubServer(BaseHTTPRequestHandler):
'_GET', '_progressiveWebAppManifest', '_GET', '_progressiveWebAppManifest',
self.server.debug) self.server.debug)
def _browserConfig(self, callingDomain: str, GETstartTime) -> None:
"""Used by MS Windows to put an icon on the desktop if you
link to a website
"""
xmlStr = \
'<?xml version="1.0" encoding="utf-8"?>\n' + \
'<browserconfig>\n' + \
' <msapplication>\n' + \
' <tile>\n' + \
' <square150x150logo src="/logo150.png"/>\n' + \
' <TileColor>#eeeeee</TileColor>\n' + \
' </tile>\n' + \
' </msapplication>\n' + \
'</browserconfig>'
msg = json.dumps(xmlStr,
ensure_ascii=False).encode('utf-8')
msglen = len(msg)
self._set_headers('application/xrd+xml', msglen,
None, callingDomain, False)
self._write(msg)
if self.server.debug:
print('Sent browserconfig: ' + callingDomain)
fitnessPerformance(GETstartTime, self.server.fitness,
'_GET', '_browserConfig',
self.server.debug)
def _getFavicon(self, callingDomain: str, def _getFavicon(self, callingDomain: str,
baseDir: str, debug: bool, baseDir: str, debug: bool,
favFilename: str) -> None: favFilename: str) -> None:
@ -8726,7 +8779,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.sharedItemsFederatedDomains, self.server.sharedItemsFederatedDomains,
rolesList, rolesList,
None, None, self.server.CWlists, None, None, self.server.CWlists,
self.server.listsEnabled) self.server.listsEnabled,
self.server.contentLicenseUrl)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
msglen = len(msg) msglen = len(msg)
self._set_headers('text/html', msglen, self._set_headers('text/html', msglen,
@ -8841,7 +8895,8 @@ class PubServer(BaseHTTPRequestHandler):
skills, skills,
None, None, None, None,
self.server.CWlists, self.server.CWlists,
self.server.listsEnabled) self.server.listsEnabled,
self.server.contentLicenseUrl)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
msglen = len(msg) msglen = len(msg)
self._set_headers('text/html', msglen, self._set_headers('text/html', msglen,
@ -10834,7 +10889,8 @@ class PubServer(BaseHTTPRequestHandler):
shares, shares,
pageNumber, sharesPerPage, pageNumber, sharesPerPage,
self.server.CWlists, self.server.CWlists,
self.server.listsEnabled) self.server.listsEnabled,
self.server.contentLicenseUrl)
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
msglen = len(msg) msglen = len(msg)
self._set_headers('text/html', msglen, self._set_headers('text/html', msglen,
@ -10926,6 +10982,8 @@ class PubServer(BaseHTTPRequestHandler):
city = getSpoofedCity(self.server.city, city = getSpoofedCity(self.server.city,
baseDir, nickname, domain) baseDir, nickname, domain)
contentLicenseUrl = \
self.server.contentLicenseUrl
msg = \ msg = \
htmlProfile(self.server.signingPrivateKeyPem, htmlProfile(self.server.signingPrivateKeyPem,
self.server.rssIconAtTop, self.server.rssIconAtTop,
@ -10960,7 +11018,8 @@ class PubServer(BaseHTTPRequestHandler):
pageNumber, pageNumber,
followsPerPage, followsPerPage,
self.server.CWlists, self.server.CWlists,
self.server.listsEnabled).encode('utf-8') self.server.listsEnabled,
contentLicenseUrl).encode('utf-8')
msglen = len(msg) msglen = len(msg)
self._set_headers('text/html', self._set_headers('text/html',
msglen, cookie, callingDomain, False) msglen, cookie, callingDomain, False)
@ -11050,6 +11109,8 @@ class PubServer(BaseHTTPRequestHandler):
city = getSpoofedCity(self.server.city, city = getSpoofedCity(self.server.city,
baseDir, nickname, domain) baseDir, nickname, domain)
contentLicenseUrl = \
self.server.contentLicenseUrl
msg = \ msg = \
htmlProfile(self.server.signingPrivateKeyPem, htmlProfile(self.server.signingPrivateKeyPem,
self.server.rssIconAtTop, self.server.rssIconAtTop,
@ -11085,7 +11146,8 @@ class PubServer(BaseHTTPRequestHandler):
pageNumber, pageNumber,
followsPerPage, followsPerPage,
self.server.CWlists, self.server.CWlists,
self.server.listsEnabled).encode('utf-8') self.server.listsEnabled,
contentLicenseUrl).encode('utf-8')
msglen = len(msg) msglen = len(msg)
self._set_headers('text/html', msglen, self._set_headers('text/html', msglen,
cookie, callingDomain, False) cookie, callingDomain, False)
@ -11226,7 +11288,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.sharedItemsFederatedDomains, self.server.sharedItemsFederatedDomains,
None, None, None, None, None, None,
self.server.CWlists, self.server.CWlists,
self.server.listsEnabled).encode('utf-8') self.server.listsEnabled,
self.server.contentLicenseUrl).encode('utf-8')
msglen = len(msg) msglen = len(msg)
self._set_headers('text/html', msglen, self._set_headers('text/html', msglen,
cookie, callingDomain, False) cookie, callingDomain, False)
@ -12239,6 +12302,17 @@ class PubServer(BaseHTTPRequestHandler):
uaStr = self.headers['User-agent'] uaStr = self.headers['User-agent']
return uaStr return uaStr
def _permittedCrawlerPath(self, path: str) -> bool:
"""Is the given path permitted to be crawled by a search engine?
this should only allow through basic information, such as nodeinfo
"""
if path == '/' or path == '/about' or path == '/login' or \
path.startswith('/api/') or \
path.startswith('/nodeinfo/') or \
path.startswith('/blog/'):
return True
return False
def do_GET(self): def do_GET(self):
callingDomain = self.server.domainFull callingDomain = self.server.domainFull
@ -12267,9 +12341,10 @@ class PubServer(BaseHTTPRequestHandler):
uaStr = self._getUserAgent() uaStr = self._getUserAgent()
if self._blockedUserAgent(callingDomain, uaStr): if not self._permittedCrawlerPath(self.path):
self._400() if self._blockedUserAgent(callingDomain, uaStr):
return self._400()
return
refererDomain = self._getRefererDomain(uaStr) refererDomain = self._getRefererDomain(uaStr)
@ -12401,6 +12476,11 @@ class PubServer(BaseHTTPRequestHandler):
else: else:
self.path = '/' self.path = '/'
if '/browserconfig.xml' in self.path:
if self._hasAccept(callingDomain):
self._browserConfig(callingDomain, GETstartTime)
return
# default newswire favicon, for links to sites which # default newswire favicon, for links to sites which
# have no favicon # have no favicon
if 'newswire_favicon.ico' in self.path: if 'newswire_favicon.ico' in self.path:
@ -13089,7 +13169,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.peertubeInstances, self.server.peertubeInstances,
self.server.systemLanguage, self.server.systemLanguage,
self.server.personCache, self.server.personCache,
self.server.debug) self.server.debug,
self.server.contentLicenseUrl)
if msg is not None: if msg is not None:
msg = msg.encode('utf-8') msg = msg.encode('utf-8')
msglen = len(msg) msglen = len(msg)
@ -13482,10 +13563,11 @@ class PubServer(BaseHTTPRequestHandler):
self.path == '/logo96.png' or \ self.path == '/logo96.png' or \
self.path == '/logo128.png' or \ self.path == '/logo128.png' or \
self.path == '/logo144.png' or \ self.path == '/logo144.png' or \
self.path == '/logo152.png' or \ self.path == '/logo150.png' or \
self.path == '/logo192.png' or \ self.path == '/logo192.png' or \
self.path == '/logo256.png' or \ self.path == '/logo256.png' or \
self.path == '/logo512.png': self.path == '/logo512.png' or \
self.path == '/apple-touch-icon.png':
mediaFilename = \ mediaFilename = \
self.server.baseDir + '/img' + self.path self.server.baseDir + '/img' + self.path
if os.path.isfile(mediaFilename): if os.path.isfile(mediaFilename):
@ -13660,6 +13742,7 @@ class PubServer(BaseHTTPRequestHandler):
GETstartTime) GETstartTime)
return return
# show a background image on the login or person options page
if '-background.' in self.path: if '-background.' in self.path:
if self._showBackgroundImage(callingDomain, self.path, if self._showBackgroundImage(callingDomain, self.path,
self.server.baseDir, self.server.baseDir,
@ -13849,6 +13932,7 @@ class PubServer(BaseHTTPRequestHandler):
'_GET', 'login shown done', '_GET', 'login shown done',
self.server.debug) self.server.debug)
# the newswire screen on mobile
if htmlGET and self.path.startswith('/users/') and \ if htmlGET and self.path.startswith('/users/') and \
self.path.endswith('/newswiremobile'): self.path.endswith('/newswiremobile'):
if (authorized or if (authorized or
@ -14618,6 +14702,7 @@ class PubServer(BaseHTTPRequestHandler):
'_GET', 'post replies done', '_GET', 'post replies done',
self.server.debug) self.server.debug)
# roles on profile screen
if self.path.endswith('/roles') and usersInPath: if self.path.endswith('/roles') and usersInPath:
if self._showRoles(authorized, if self._showRoles(authorized,
callingDomain, self.path, callingDomain, self.path,
@ -15195,7 +15280,8 @@ class PubServer(BaseHTTPRequestHandler):
def _receiveNewPostProcess(self, postType: str, path: str, headers: {}, def _receiveNewPostProcess(self, postType: str, path: str, headers: {},
length: int, postBytes, boundary: str, length: int, postBytes, boundary: str,
callingDomain: str, cookie: str, callingDomain: str, cookie: str,
authorized: bool) -> int: authorized: bool,
contentLicenseUrl: str) -> int:
# Note: this needs to happen synchronously # Note: this needs to happen synchronously
# 0=this is not a new post # 0=this is not a new post
# 1=new post success # 1=new post success
@ -15272,7 +15358,8 @@ class PubServer(BaseHTTPRequestHandler):
convertImageToLowBandwidth(filename) convertImageToLowBandwidth(filename)
processMetaData(self.server.baseDir, processMetaData(self.server.baseDir,
nickname, self.server.domain, nickname, self.server.domain,
filename, postImageFilename, city) filename, postImageFilename, city,
contentLicenseUrl)
if os.path.isfile(postImageFilename): if os.path.isfile(postImageFilename):
print('POST media saved to ' + postImageFilename) print('POST media saved to ' + postImageFilename)
else: else:
@ -15399,7 +15486,8 @@ class PubServer(BaseHTTPRequestHandler):
fields['location'], False, fields['location'], False,
self.server.systemLanguage, self.server.systemLanguage,
conversationId, conversationId,
self.server.lowBandwidth) self.server.lowBandwidth,
self.server.contentLicenseUrl)
if messageJson: if messageJson:
if fields['schedulePost']: if fields['schedulePost']:
return 1 return 1
@ -15481,7 +15569,8 @@ class PubServer(BaseHTTPRequestHandler):
fields['location'], fields['location'],
self.server.systemLanguage, self.server.systemLanguage,
conversationId, conversationId,
self.server.lowBandwidth) self.server.lowBandwidth,
self.server.contentLicenseUrl)
if messageJson: if messageJson:
if fields['schedulePost']: if fields['schedulePost']:
return 1 return 1
@ -15573,7 +15662,8 @@ class PubServer(BaseHTTPRequestHandler):
attachmentMediaType, attachmentMediaType,
imgDescription, imgDescription,
city, city,
self.server.lowBandwidth) self.server.lowBandwidth,
self.server.contentLicenseUrl)
replaceYouTube(postJsonObject, replaceYouTube(postJsonObject,
self.server.YTReplacementDomain, self.server.YTReplacementDomain,
@ -15631,7 +15721,8 @@ class PubServer(BaseHTTPRequestHandler):
fields['location'], fields['location'],
self.server.systemLanguage, self.server.systemLanguage,
conversationId, conversationId,
self.server.lowBandwidth) self.server.lowBandwidth,
self.server.contentLicenseUrl)
if messageJson: if messageJson:
if fields['schedulePost']: if fields['schedulePost']:
return 1 return 1
@ -15682,7 +15773,8 @@ class PubServer(BaseHTTPRequestHandler):
fields['location'], fields['location'],
self.server.systemLanguage, self.server.systemLanguage,
conversationId, conversationId,
self.server.lowBandwidth) self.server.lowBandwidth,
self.server.contentLicenseUrl)
if messageJson: if messageJson:
if fields['schedulePost']: if fields['schedulePost']:
return 1 return 1
@ -15737,7 +15829,8 @@ class PubServer(BaseHTTPRequestHandler):
fields['location'], fields['location'],
self.server.systemLanguage, self.server.systemLanguage,
conversationId, conversationId,
self.server.lowBandwidth) self.server.lowBandwidth,
self.server.contentLicenseUrl)
if messageJson: if messageJson:
if fields['schedulePost']: if fields['schedulePost']:
return 1 return 1
@ -15790,7 +15883,8 @@ class PubServer(BaseHTTPRequestHandler):
fields['location'], fields['location'],
self.server.systemLanguage, self.server.systemLanguage,
conversationId, conversationId,
self.server.lowBandwidth) self.server.lowBandwidth,
self.server.contentLicenseUrl)
if messageJson: if messageJson:
if fields['schedulePost']: if fields['schedulePost']:
return 1 return 1
@ -15826,7 +15920,8 @@ class PubServer(BaseHTTPRequestHandler):
city, city,
self.server.debug, fields['subject'], self.server.debug, fields['subject'],
self.server.systemLanguage, self.server.systemLanguage,
self.server.lowBandwidth) self.server.lowBandwidth,
self.server.contentLicenseUrl)
if messageJson: if messageJson:
if self._postToOutbox(messageJson, if self._postToOutbox(messageJson,
self.server.projectVersion, self.server.projectVersion,
@ -15867,7 +15962,8 @@ class PubServer(BaseHTTPRequestHandler):
fields['subject'], fields['subject'],
intDuration, intDuration,
self.server.systemLanguage, self.server.systemLanguage,
self.server.lowBandwidth) self.server.lowBandwidth,
self.server.contentLicenseUrl)
if messageJson: if messageJson:
if self.server.debug: if self.server.debug:
print('DEBUG: new Question') print('DEBUG: new Question')
@ -15939,7 +16035,8 @@ class PubServer(BaseHTTPRequestHandler):
city, itemPrice, itemCurrency, city, itemPrice, itemCurrency,
self.server.systemLanguage, self.server.systemLanguage,
self.server.translate, sharesFileType, self.server.translate, sharesFileType,
self.server.lowBandwidth) self.server.lowBandwidth,
self.server.contentLicenseUrl)
if filename: if filename:
if os.path.isfile(filename): if os.path.isfile(filename):
try: try:
@ -15954,7 +16051,8 @@ class PubServer(BaseHTTPRequestHandler):
def _receiveNewPost(self, postType: str, path: str, def _receiveNewPost(self, postType: str, path: str,
callingDomain: str, cookie: str, callingDomain: str, cookie: str,
authorized: bool) -> int: authorized: bool,
contentLicenseUrl: str) -> int:
"""A new post has been created """A new post has been created
This creates a thread to send the new post This creates a thread to send the new post
""" """
@ -16056,7 +16154,8 @@ class PubServer(BaseHTTPRequestHandler):
path, headers, length, path, headers, length,
postBytes, boundary, postBytes, boundary,
callingDomain, cookie, callingDomain, cookie,
authorized) authorized,
contentLicenseUrl)
return pageNumber return pageNumber
def _cryptoAPIreadHandle(self): def _cryptoAPIreadHandle(self):
@ -16353,7 +16452,8 @@ class PubServer(BaseHTTPRequestHandler):
self.server.onionDomain, self.server.onionDomain,
self.server.i2pDomain, self.server.debug, self.server.i2pDomain, self.server.debug,
self.server.allowLocalNetworkAccess, self.server.allowLocalNetworkAccess,
self.server.systemLanguage) self.server.systemLanguage,
self.server.contentLicenseUrl)
return return
if authorized and self.path.endswith('/linksdata'): if authorized and self.path.endswith('/linksdata'):
@ -16713,7 +16813,8 @@ class PubServer(BaseHTTPRequestHandler):
pageNumber = \ pageNumber = \
self._receiveNewPost(currPostType, self.path, self._receiveNewPost(currPostType, self.path,
callingDomain, cookie, callingDomain, cookie,
authorized) authorized,
self.server.contentLicenseUrl)
if pageNumber: if pageNumber:
print(currPostType + ' post received') print(currPostType + ' post received')
nickname = self.path.split('/users/')[1] nickname = self.path.split('/users/')[1]
@ -17126,7 +17227,8 @@ def loadTokens(baseDir: str, tokensDict: {}, tokensLookup: {}) -> None:
break break
def runDaemon(listsEnabled: str, def runDaemon(contentLicenseUrl: str,
listsEnabled: str,
defaultReplyIntervalHours: int, defaultReplyIntervalHours: int,
lowBandwidth: bool, lowBandwidth: bool,
maxLikeCount: int, maxLikeCount: int,
@ -17214,6 +17316,11 @@ def runDaemon(listsEnabled: str,
# scan the theme directory for any svg files containing scripts # scan the theme directory for any svg files containing scripts
assert not scanThemesForScripts(baseDir) assert not scanThemesForScripts(baseDir)
# license for content of the instance
if not contentLicenseUrl:
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
httpd.contentLicenseUrl = contentLicenseUrl
# fitness metrics # fitness metrics
fitnessFilename = baseDir + '/accounts/fitness.json' fitnessFilename = baseDir + '/accounts/fitness.json'
httpd.fitness = {} httpd.fitness = {}

View File

@ -419,6 +419,7 @@ def _desktopReplyToPost(session, postId: str,
screenreader: str, systemLanguage: str, screenreader: str, systemLanguage: str,
espeak, conversationId: str, espeak, conversationId: str,
lowBandwidth: bool, lowBandwidth: bool,
contentLicenseUrl: str,
signingPrivateKeyPem: str) -> None: signingPrivateKeyPem: str) -> None:
"""Use the desktop client to send a reply to the most recent post """Use the desktop client to send a reply to the most recent post
""" """
@ -473,6 +474,7 @@ def _desktopReplyToPost(session, postId: str,
attachedImageDescription, city, attachedImageDescription, city,
cachedWebfingers, personCache, isArticle, cachedWebfingers, personCache, isArticle,
systemLanguage, lowBandwidth, systemLanguage, lowBandwidth,
contentLicenseUrl,
debug, postId, postId, debug, postId, postId,
conversationId, subject) == 0: conversationId, subject) == 0:
sayStr = 'Reply sent' sayStr = 'Reply sent'
@ -488,6 +490,7 @@ def _desktopNewPost(session,
debug: bool, debug: bool,
screenreader: str, systemLanguage: str, screenreader: str, systemLanguage: str,
espeak, lowBandwidth: bool, espeak, lowBandwidth: bool,
contentLicenseUrl: str,
signingPrivateKeyPem: str) -> None: signingPrivateKeyPem: str) -> None:
"""Use the desktop client to create a new post """Use the desktop client to create a new post
""" """
@ -538,6 +541,7 @@ def _desktopNewPost(session,
attachedImageDescription, city, attachedImageDescription, city,
cachedWebfingers, personCache, isArticle, cachedWebfingers, personCache, isArticle,
systemLanguage, lowBandwidth, systemLanguage, lowBandwidth,
contentLicenseUrl,
debug, None, None, debug, None, None,
conversationId, subject) == 0: conversationId, subject) == 0:
sayStr = 'Post sent' sayStr = 'Post sent'
@ -1124,6 +1128,7 @@ def _desktopNewDM(session, toHandle: str,
debug: bool, debug: bool,
screenreader: str, systemLanguage: str, screenreader: str, systemLanguage: str,
espeak, lowBandwidth: bool, espeak, lowBandwidth: bool,
contentLicenseUrl: str,
signingPrivateKeyPem: str) -> None: signingPrivateKeyPem: str) -> None:
"""Use the desktop client to create a new direct message """Use the desktop client to create a new direct message
which can include multiple destination handles which can include multiple destination handles
@ -1146,6 +1151,7 @@ def _desktopNewDM(session, toHandle: str,
debug, debug,
screenreader, systemLanguage, screenreader, systemLanguage,
espeak, lowBandwidth, espeak, lowBandwidth,
contentLicenseUrl,
signingPrivateKeyPem) signingPrivateKeyPem)
@ -1156,6 +1162,7 @@ def _desktopNewDMbase(session, toHandle: str,
debug: bool, debug: bool,
screenreader: str, systemLanguage: str, screenreader: str, systemLanguage: str,
espeak, lowBandwidth: bool, espeak, lowBandwidth: bool,
contentLicenseUrl: str,
signingPrivateKeyPem: str) -> None: signingPrivateKeyPem: str) -> None:
"""Use the desktop client to create a new direct message """Use the desktop client to create a new direct message
""" """
@ -1246,6 +1253,7 @@ def _desktopNewDMbase(session, toHandle: str,
attachedImageDescription, city, attachedImageDescription, city,
cachedWebfingers, personCache, isArticle, cachedWebfingers, personCache, isArticle,
systemLanguage, lowBandwidth, systemLanguage, lowBandwidth,
contentLicenseUrl,
debug, None, None, debug, None, None,
conversationId, subject) == 0: conversationId, subject) == 0:
sayStr = 'Direct message sent' sayStr = 'Direct message sent'
@ -1319,6 +1327,8 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
# TODO: this should probably be retrieved somehow from the server # TODO: this should probably be retrieved somehow from the server
signingPrivateKeyPem = None signingPrivateKeyPem = None
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
blockedCache = {} blockedCache = {}
indent = ' ' indent = ' '
@ -1716,6 +1726,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
screenreader, systemLanguage, screenreader, systemLanguage,
espeak, conversationId, espeak, conversationId,
lowBandwidth, lowBandwidth,
contentLicenseUrl,
signingPrivateKeyPem) signingPrivateKeyPem)
refreshTimeline = True refreshTimeline = True
print('') print('')
@ -1751,6 +1762,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
debug, debug,
screenreader, systemLanguage, screenreader, systemLanguage,
espeak, lowBandwidth, espeak, lowBandwidth,
contentLicenseUrl,
signingPrivateKeyPem) signingPrivateKeyPem)
refreshTimeline = True refreshTimeline = True
else: else:
@ -1762,6 +1774,7 @@ def runDesktopClient(baseDir: str, proxyType: str, httpPrefix: str,
debug, debug,
screenreader, systemLanguage, screenreader, systemLanguage,
espeak, lowBandwidth, espeak, lowBandwidth,
contentLicenseUrl,
signingPrivateKeyPem) signingPrivateKeyPem)
refreshTimeline = True refreshTimeline = True
print('') print('')

View File

@ -112,6 +112,9 @@ def str2bool(v) -> bool:
parser = argparse.ArgumentParser(description='ActivityPub Server') parser = argparse.ArgumentParser(description='ActivityPub Server')
parser.add_argument('--contentLicenseUrl', type=str,
default='https://creativecommons.org/licenses/by/4.0',
help='Url of the license used for the instance content')
parser.add_argument('--listsEnabled', type=str, parser.add_argument('--listsEnabled', type=str,
default=None, default=None,
help='Names of content warning lists enabled. ' + help='Names of content warning lists enabled. ' +
@ -1281,7 +1284,8 @@ if args.message:
args.commentsEnabled, attach, mediaType, args.commentsEnabled, attach, mediaType,
attachedImageDescription, city, attachedImageDescription, city,
cachedWebfingers, personCache, isArticle, cachedWebfingers, personCache, isArticle,
args.language, args.lowBandwidth, args.debug, args.language, args.lowBandwidth,
args.contentLicenseUrl, args.debug,
replyTo, replyTo, args.conversationId, subject) replyTo, replyTo, args.conversationId, subject)
for i in range(10): for i in range(10):
# TODO detect send success/fail # TODO detect send success/fail
@ -2330,7 +2334,8 @@ if args.avatar:
sys.exit() sys.exit()
city = 'London, England' city = 'London, England'
if setProfileImage(baseDir, httpPrefix, args.nickname, domain, if setProfileImage(baseDir, httpPrefix, args.nickname, domain,
port, args.avatar, 'avatar', '128x128', city): port, args.avatar, 'avatar', '128x128', city,
args.contentLicenseUrl):
print('Avatar added for ' + args.nickname) print('Avatar added for ' + args.nickname)
else: else:
print('Avatar was not added for ' + args.nickname) print('Avatar was not added for ' + args.nickname)
@ -2346,7 +2351,7 @@ if args.backgroundImage:
city = 'London, England' city = 'London, England'
if setProfileImage(baseDir, httpPrefix, args.nickname, domain, if setProfileImage(baseDir, httpPrefix, args.nickname, domain,
port, args.backgroundImage, 'background', port, args.backgroundImage, 'background',
'256x256', city): '256x256', city, args.contentLicenseUrl):
print('Background image added for ' + args.nickname) print('Background image added for ' + args.nickname)
else: else:
print('Background image was not added for ' + args.nickname) print('Background image was not added for ' + args.nickname)
@ -2716,7 +2721,8 @@ if args.testdata:
"mechanical", "mechanical",
"City", "0", "GBP", "City", "0", "GBP",
"2 months", "2 months",
debug, city, args.language, {}, 'shares', args.lowBandwidth) debug, city, args.language, {}, 'shares', args.lowBandwidth,
args.contentLicenseUrl)
addShare(baseDir, addShare(baseDir,
httpPrefix, nickname, domain, port, httpPrefix, nickname, domain, port,
"witch hat", "witch hat",
@ -2726,7 +2732,8 @@ if args.testdata:
"clothing", "clothing",
"City", "0", "GBP", "City", "0", "GBP",
"3 months", "3 months",
debug, city, args.language, {}, 'shares', args.lowBandwidth) debug, city, args.language, {}, 'shares', args.lowBandwidth,
args.contentLicenseUrl)
deleteAllPosts(baseDir, nickname, domain, 'inbox') deleteAllPosts(baseDir, nickname, domain, 'inbox')
deleteAllPosts(baseDir, nickname, domain, 'outbox') deleteAllPosts(baseDir, nickname, domain, 'outbox')
@ -2762,7 +2769,7 @@ if args.testdata:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, args.language, conversationId, testIsArticle, args.language, conversationId,
lowBandwidth) lowBandwidth, args.contentLicenseUrl)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"Zoiks!!!", "Zoiks!!!",
testFollowersOnly, testFollowersOnly,
@ -2775,7 +2782,7 @@ if args.testdata:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, args.language, conversationId, testIsArticle, args.language, conversationId,
lowBandwidth) lowBandwidth, args.contentLicenseUrl)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"Hey scoob we need like a hundred more #milkshakes", "Hey scoob we need like a hundred more #milkshakes",
testFollowersOnly, testFollowersOnly,
@ -2788,7 +2795,7 @@ if args.testdata:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, args.language, conversationId, testIsArticle, args.language, conversationId,
lowBandwidth) lowBandwidth, args.contentLicenseUrl)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"Getting kinda spooky around here", "Getting kinda spooky around here",
testFollowersOnly, testFollowersOnly,
@ -2801,7 +2808,7 @@ if args.testdata:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, args.language, conversationId, testIsArticle, args.language, conversationId,
lowBandwidth) lowBandwidth, args.contentLicenseUrl)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"And they would have gotten away with it too" + "And they would have gotten away with it too" +
"if it wasn't for those pesky hackers", "if it wasn't for those pesky hackers",
@ -2815,7 +2822,7 @@ if args.testdata:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, args.language, conversationId, testIsArticle, args.language, conversationId,
lowBandwidth) lowBandwidth, args.contentLicenseUrl)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"man these centralized sites are like the worst!", "man these centralized sites are like the worst!",
testFollowersOnly, testFollowersOnly,
@ -2828,7 +2835,7 @@ if args.testdata:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, args.language, conversationId, testIsArticle, args.language, conversationId,
lowBandwidth) lowBandwidth, args.contentLicenseUrl)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"another mystery solved #test", "another mystery solved #test",
testFollowersOnly, testFollowersOnly,
@ -2841,7 +2848,7 @@ if args.testdata:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, args.language, conversationId, testIsArticle, args.language, conversationId,
lowBandwidth) lowBandwidth, args.contentLicenseUrl)
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"let's go bowling", "let's go bowling",
testFollowersOnly, testFollowersOnly,
@ -2854,7 +2861,7 @@ if args.testdata:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, args.language, conversationId, testIsArticle, args.language, conversationId,
lowBandwidth) lowBandwidth, args.contentLicenseUrl)
domainFull = domain + ':' + str(port) domainFull = domain + ':' + str(port)
clearFollows(baseDir, nickname, domain) clearFollows(baseDir, nickname, domain)
followPerson(baseDir, nickname, domain, 'maxboardroom', domainFull, followPerson(baseDir, nickname, domain, 'maxboardroom', domainFull,
@ -2884,6 +2891,13 @@ minimumvotes = getConfigParam(baseDir, 'minvotes')
if minimumvotes: if minimumvotes:
args.minimumvotes = int(minimumvotes) args.minimumvotes = int(minimumvotes)
contentLicenseUrl = ''
if args.contentLicenseUrl:
contentLicenseUrl = args.contentLicenseUrl
setConfigParam(baseDir, 'contentLicenseUrl', contentLicenseUrl)
else:
contentLicenseUrl = getConfigParam(baseDir, 'contentLicenseUrl')
votingtime = getConfigParam(baseDir, 'votingtime') votingtime = getConfigParam(baseDir, 'votingtime')
if votingtime: if votingtime:
args.votingtime = votingtime args.votingtime = votingtime
@ -3078,7 +3092,8 @@ if args.defaultCurrency:
print('Default currency set to ' + args.defaultCurrency) print('Default currency set to ' + args.defaultCurrency)
if __name__ == "__main__": if __name__ == "__main__":
runDaemon(listsEnabled, runDaemon(contentLicenseUrl,
listsEnabled,
args.defaultReplyIntervalHours, args.defaultReplyIntervalHours,
args.lowBandwidth, args.maxLikeCount, args.lowBandwidth, args.maxLikeCount,
sharedItemsFederatedDomains, sharedItemsFederatedDomains,

View File

@ -209,6 +209,29 @@ def followerOfPerson(baseDir: str, nickname: str, domain: str,
federationList, debug, groupAccount, 'followers.txt') federationList, debug, groupAccount, 'followers.txt')
def getFollowerDomains(baseDir: str, nickname: str, domain: str) -> []:
"""Returns a list of domains for followers
"""
domain = removeDomainPort(domain)
followersFile = acctDir(baseDir, nickname, domain) + '/followers.txt'
if not os.path.isfile(followersFile):
return []
lines = []
with open(followersFile, 'r') as fpFollowers:
lines = fpFollowers.readlines()
domainsList = []
for handle in lines:
handle = handle.replace('\n', '')
followerDomain, _ = getDomainFromActor(handle)
if not followerDomain:
continue
if followerDomain not in domainsList:
domainsList.append(followerDomain)
return domainsList
def isFollowerOfPerson(baseDir: str, nickname: str, domain: str, def isFollowerOfPerson(baseDir: str, nickname: str, domain: str,
followerNickname: str, followerDomain: str) -> bool: followerNickname: str, followerDomain: str) -> bool:
"""is the given nickname a follower of followerNickname? """is the given nickname a follower of followerNickname?

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
img/logo150.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -2374,7 +2374,8 @@ def _bounceDM(senderPostId: str, session, httpPrefix: str,
cachedWebfingers: {}, personCache: {}, cachedWebfingers: {}, personCache: {},
translate: {}, debug: bool, translate: {}, debug: bool,
lastBounceMessage: [], systemLanguage: str, lastBounceMessage: [], systemLanguage: str,
signingPrivateKeyPem: str) -> bool: signingPrivateKeyPem: str,
contentLicenseUrl: str) -> bool:
"""Sends a bounce message back to the sending handle """Sends a bounce message back to the sending handle
if a DM has been rejected if a DM has been rejected
""" """
@ -2433,7 +2434,8 @@ def _bounceDM(senderPostId: str, session, httpPrefix: str,
inReplyTo, inReplyToAtomUri, inReplyTo, inReplyToAtomUri,
subject, debug, schedulePost, subject, debug, schedulePost,
eventDate, eventTime, location, eventDate, eventTime, location,
systemLanguage, conversationId, lowBandwidth) systemLanguage, conversationId, lowBandwidth,
contentLicenseUrl)
if not postJsonObject: if not postJsonObject:
print('WARN: unable to create bounce message to ' + sendingHandle) print('WARN: unable to create bounce message to ' + sendingHandle)
return False return False
@ -2459,7 +2461,8 @@ def _isValidDM(baseDir: str, nickname: str, domain: str, port: int,
translate: {}, debug: bool, translate: {}, debug: bool,
lastBounceMessage: [], lastBounceMessage: [],
handle: str, systemLanguage: str, handle: str, systemLanguage: str,
signingPrivateKeyPem: str) -> bool: signingPrivateKeyPem: str,
contentLicenseUrl: str) -> bool:
"""Is the given message a valid DM? """Is the given message a valid DM?
""" """
if nickname == 'inbox': if nickname == 'inbox':
@ -2537,7 +2540,8 @@ def _isValidDM(baseDir: str, nickname: str, domain: str, port: int,
translate, debug, translate, debug,
lastBounceMessage, lastBounceMessage,
systemLanguage, systemLanguage,
signingPrivateKeyPem) signingPrivateKeyPem,
contentLicenseUrl)
return False return False
# dm index will be updated # dm index will be updated
@ -2772,7 +2776,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
maxLikeCount: int, maxLikeCount: int,
signingPrivateKeyPem: str, signingPrivateKeyPem: str,
defaultReplyIntervalHours: int, defaultReplyIntervalHours: int,
CWlists: {}, listsEnabled: str) -> bool: CWlists: {}, listsEnabled: str,
contentLicenseUrl: str) -> bool:
""" Anything which needs to be done after initial checks have passed """ Anything which needs to be done after initial checks have passed
""" """
actor = keyId actor = keyId
@ -3004,7 +3009,8 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
translate, debug, translate, debug,
lastBounceMessage, lastBounceMessage,
handle, systemLanguage, handle, systemLanguage,
signingPrivateKeyPem): signingPrivateKeyPem,
contentLicenseUrl):
return False return False
# get the actor being replied to # get the actor being replied to
@ -3786,6 +3792,7 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
saveJson(queueJson['post'], sharedInboxPostFilename) saveJson(queueJson['post'], sharedInboxPostFilename)
listsEnabled = getConfigParam(baseDir, "listsEnabled") listsEnabled = getConfigParam(baseDir, "listsEnabled")
contentLicenseUrl = getConfigParam(baseDir, "contentLicenseUrl")
# for posts addressed to specific accounts # for posts addressed to specific accounts
for handle, capsId in recipientsDict.items(): for handle, capsId in recipientsDict.items():
@ -3818,7 +3825,8 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
maxLikeCount, maxLikeCount,
signingPrivateKeyPem, signingPrivateKeyPem,
defaultReplyIntervalHours, defaultReplyIntervalHours,
CWlists, listsEnabled) CWlists, listsEnabled,
contentLicenseUrl)
if debug: if debug:
pprint(queueJson['post']) pprint(queueJson['post'])
print('Queue: Queue post accepted') print('Queue: Queue post accepted')

View File

@ -107,7 +107,8 @@ def _removeMetaData(imageFilename: str, outputFilename: str) -> None:
def _spoofMetaData(baseDir: str, nickname: str, domain: str, def _spoofMetaData(baseDir: str, nickname: str, domain: str,
outputFilename: str, spoofCity: str) -> None: outputFilename: str, spoofCity: str,
contentLicenseUrl: str) -> None:
"""Spoof image metadata using a decoy model for a given city """Spoof image metadata using a decoy model for a given city
""" """
if not os.path.isfile(outputFilename): if not os.path.isfile(outputFilename):
@ -151,6 +152,7 @@ def _spoofMetaData(baseDir: str, nickname: str, domain: str,
'-GPSLongitude=' + str(longitude) + ' ' + '-GPSLongitude=' + str(longitude) + ' ' +
'-GPSLatitudeRef=' + latitudeRef + ' ' + '-GPSLatitudeRef=' + latitudeRef + ' ' +
'-GPSLatitude=' + str(latitude) + ' ' + '-GPSLatitude=' + str(latitude) + ' ' +
'-copyright="' + contentLicenseUrl + '" ' +
'-Comment="" ' + '-Comment="" ' +
outputFilename) != 0: # nosec outputFilename) != 0: # nosec
print('ERROR: exiftool failed to run') print('ERROR: exiftool failed to run')
@ -203,7 +205,7 @@ def convertImageToLowBandwidth(imageFilename: str) -> None:
def processMetaData(baseDir: str, nickname: str, domain: str, def processMetaData(baseDir: str, nickname: str, domain: str,
imageFilename: str, outputFilename: str, imageFilename: str, outputFilename: str,
city: str) -> None: city: str, contentLicenseUrl: str) -> None:
"""Handles image metadata. This tries to spoof the metadata """Handles image metadata. This tries to spoof the metadata
if possible, but otherwise just removes it if possible, but otherwise just removes it
""" """
@ -211,7 +213,8 @@ def processMetaData(baseDir: str, nickname: str, domain: str,
_removeMetaData(imageFilename, outputFilename) _removeMetaData(imageFilename, outputFilename)
# now add some spoofed data to misdirect surveillance capitalists # now add some spoofed data to misdirect surveillance capitalists
_spoofMetaData(baseDir, nickname, domain, outputFilename, city) _spoofMetaData(baseDir, nickname, domain, outputFilename, city,
contentLicenseUrl)
def _isMedia(imageFilename: str) -> bool: def _isMedia(imageFilename: str) -> bool:
@ -299,7 +302,8 @@ def attachMedia(baseDir: str, httpPrefix: str,
nickname: str, domain: str, port: int, nickname: str, domain: str, port: int,
postJson: {}, imageFilename: str, postJson: {}, imageFilename: str,
mediaType: str, description: str, mediaType: str, description: str,
city: str, lowBandwidth: bool) -> {}: city: str, lowBandwidth: bool,
contentLicenseUrl: str) -> {}:
"""Attaches media to a json object post """Attaches media to a json object post
The description can be None The description can be None
""" """
@ -357,7 +361,8 @@ def attachMedia(baseDir: str, httpPrefix: str,
if lowBandwidth: if lowBandwidth:
convertImageToLowBandwidth(imageFilename) convertImageToLowBandwidth(imageFilename)
processMetaData(baseDir, nickname, domain, processMetaData(baseDir, nickname, domain,
imageFilename, mediaFilename, city) imageFilename, mediaFilename, city,
contentLicenseUrl)
else: else:
copyfile(imageFilename, mediaFilename) copyfile(imageFilename, mediaFilename)
_updateEtag(mediaFilename) _updateEtag(mediaFilename)

View File

@ -530,7 +530,8 @@ def _convertRSStoActivityPub(baseDir: str, httpPrefix: str,
maxMirroredArticles: int, maxMirroredArticles: int,
allowLocalNetworkAccess: bool, allowLocalNetworkAccess: bool,
systemLanguage: str, systemLanguage: str,
lowBandwidth: bool) -> None: lowBandwidth: bool,
contentLicenseUrl: str) -> None:
"""Converts rss items in a newswire into posts """Converts rss items in a newswire into posts
""" """
if not newswire: if not newswire:
@ -622,7 +623,8 @@ def _convertRSStoActivityPub(baseDir: str, httpPrefix: str,
attachImageFilename, mediaType, attachImageFilename, mediaType,
imageDescription, city, imageDescription, city,
rssTitle, systemLanguage, rssTitle, systemLanguage,
conversationId, lowBandwidth) conversationId, lowBandwidth,
contentLicenseUrl)
if not blog: if not blog:
continue continue
@ -818,7 +820,8 @@ def runNewswireDaemon(baseDir: str, httpd,
httpd.maxMirroredArticles, httpd.maxMirroredArticles,
httpd.allowLocalNetworkAccess, httpd.allowLocalNetworkAccess,
httpd.systemLanguage, httpd.systemLanguage,
httpd.lowBandwidth) httpd.lowBandwidth,
httpd.contentLicenseUrl)
print('Newswire feed converted to ActivityPub') print('Newswire feed converted to ActivityPub')
if httpd.maxNewsPosts > 0: if httpd.maxNewsPosts > 0:

View File

@ -197,7 +197,8 @@ def postMessageToOutbox(session, translate: {},
peertubeInstances: str, theme: str, peertubeInstances: str, theme: str,
maxLikeCount: int, maxLikeCount: int,
maxRecentPosts: int, CWlists: {}, maxRecentPosts: int, CWlists: {},
listsEnabled: str) -> bool: listsEnabled: str,
contentLicenseUrl: str) -> bool:
"""post is received by the outbox """post is received by the outbox
Client to server message post Client to server message post
https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery https://www.w3.org/TR/activitypub/#client-to-server-outbox-delivery
@ -607,7 +608,8 @@ def postMessageToOutbox(session, translate: {},
print('DEBUG: handle share uploads') print('DEBUG: handle share uploads')
outboxShareUpload(baseDir, httpPrefix, postToNickname, domain, outboxShareUpload(baseDir, httpPrefix, postToNickname, domain,
port, messageJson, debug, city, port, messageJson, debug, city,
systemLanguage, translate, lowBandwidth) systemLanguage, translate, lowBandwidth,
contentLicenseUrl)
if debug: if debug:
print('DEBUG: handle undo share uploads') print('DEBUG: handle undo share uploads')

View File

@ -88,7 +88,8 @@ def generateRSAKey() -> (str, str):
def setProfileImage(baseDir: str, httpPrefix: str, nickname: str, domain: str, def setProfileImage(baseDir: str, httpPrefix: str, nickname: str, domain: str,
port: int, imageFilename: str, imageType: str, port: int, imageFilename: str, imageType: str,
resolution: str, city: str) -> bool: resolution: str, city: str,
contentLicenseUrl: str) -> bool:
"""Saves the given image file as an avatar or background """Saves the given image file as an avatar or background
image for the given person image for the given person
""" """
@ -151,7 +152,8 @@ def setProfileImage(baseDir: str, httpPrefix: str, nickname: str, domain: str,
resolution + ' -quality 50 ' + profileFilename resolution + ' -quality 50 ' + profileFilename
subprocess.call(cmd, shell=True) subprocess.call(cmd, shell=True)
processMetaData(baseDir, nickname, domain, processMetaData(baseDir, nickname, domain,
profileFilename, profileFilename, city) profileFilename, profileFilename, city,
contentLicenseUrl)
return True return True
return False return False

View File

@ -1064,7 +1064,8 @@ def _createPostS2S(baseDir: str, nickname: str, domain: str, port: int,
mediaType: str, imageDescription: str, city: str, mediaType: str, imageDescription: str, city: str,
postObjectType: str, summary: str, postObjectType: str, summary: str,
inReplyToAtomUri: str, systemLanguage: str, inReplyToAtomUri: str, systemLanguage: str,
conversationId: str, lowBandwidth: bool) -> {}: conversationId: str, lowBandwidth: bool,
contentLicenseUrl: str) -> {}:
"""Creates a new server-to-server post """Creates a new server-to-server post
""" """
actorUrl = localActorUrl(httpPrefix, nickname, domain) actorUrl = localActorUrl(httpPrefix, nickname, domain)
@ -1124,7 +1125,8 @@ def _createPostS2S(baseDir: str, nickname: str, domain: str, port: int,
newPost['object'] = \ newPost['object'] = \
attachMedia(baseDir, httpPrefix, nickname, domain, port, attachMedia(baseDir, httpPrefix, nickname, domain, port,
newPost['object'], attachImageFilename, newPost['object'], attachImageFilename,
mediaType, imageDescription, city, lowBandwidth) mediaType, imageDescription, city, lowBandwidth,
contentLicenseUrl)
return newPost return newPost
@ -1137,7 +1139,8 @@ def _createPostC2S(baseDir: str, nickname: str, domain: str, port: int,
mediaType: str, imageDescription: str, city: str, mediaType: str, imageDescription: str, city: str,
postObjectType: str, summary: str, postObjectType: str, summary: str,
inReplyToAtomUri: str, systemLanguage: str, inReplyToAtomUri: str, systemLanguage: str,
conversationId: str, lowBandwidth: str) -> {}: conversationId: str, lowBandwidth: str,
contentLicenseUrl: str) -> {}:
"""Creates a new client-to-server post """Creates a new client-to-server post
""" """
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)
@ -1187,7 +1190,8 @@ def _createPostC2S(baseDir: str, nickname: str, domain: str, port: int,
newPost = \ newPost = \
attachMedia(baseDir, httpPrefix, nickname, domain, port, attachMedia(baseDir, httpPrefix, nickname, domain, port,
newPost, attachImageFilename, newPost, attachImageFilename,
mediaType, imageDescription, city, lowBandwidth) mediaType, imageDescription, city, lowBandwidth,
contentLicenseUrl)
return newPost return newPost
@ -1314,7 +1318,8 @@ def _createPostBase(baseDir: str,
anonymousParticipationEnabled: bool, anonymousParticipationEnabled: bool,
eventStatus: str, ticketUrl: str, eventStatus: str, ticketUrl: str,
systemLanguage: str, systemLanguage: str,
conversationId: str, lowBandwidth: bool) -> {}: conversationId: str, lowBandwidth: bool,
contentLicenseUrl: str) -> {}:
"""Creates a message """Creates a message
""" """
content = removeInvalidChars(content) content = removeInvalidChars(content)
@ -1439,7 +1444,8 @@ def _createPostBase(baseDir: str,
mediaType, imageDescription, city, mediaType, imageDescription, city,
postObjectType, summary, postObjectType, summary,
inReplyToAtomUri, systemLanguage, inReplyToAtomUri, systemLanguage,
conversationId, lowBandwidth) conversationId, lowBandwidth,
contentLicenseUrl)
else: else:
newPost = \ newPost = \
_createPostC2S(baseDir, nickname, domain, port, _createPostC2S(baseDir, nickname, domain, port,
@ -1451,7 +1457,8 @@ def _createPostBase(baseDir: str,
mediaType, imageDescription, city, mediaType, imageDescription, city,
postObjectType, summary, postObjectType, summary,
inReplyToAtomUri, systemLanguage, inReplyToAtomUri, systemLanguage,
conversationId, lowBandwidth) conversationId, lowBandwidth,
contentLicenseUrl)
_createPostMentions(ccUrl, newPost, toRecipients, tags) _createPostMentions(ccUrl, newPost, toRecipients, tags)
@ -1685,7 +1692,8 @@ def createPublicPost(baseDir: str,
location: str, location: str,
isArticle: bool, isArticle: bool,
systemLanguage: str, systemLanguage: str,
conversationId: str, lowBandwidth: bool) -> {}: conversationId: str, lowBandwidth: bool,
contentLicenseUrl: str) -> {}:
"""Public post """Public post
""" """
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)
@ -1716,7 +1724,8 @@ def createPublicPost(baseDir: str,
repliesModerationOption, repliesModerationOption,
anonymousParticipationEnabled, anonymousParticipationEnabled,
eventStatus, ticketUrl, systemLanguage, eventStatus, ticketUrl, systemLanguage,
conversationId, lowBandwidth) conversationId, lowBandwidth,
contentLicenseUrl)
def _appendCitationsToBlogPost(baseDir: str, def _appendCitationsToBlogPost(baseDir: str,
@ -1759,7 +1768,8 @@ def createBlogPost(baseDir: str,
subject: str, schedulePost: bool, subject: str, schedulePost: bool,
eventDate: str, eventTime: str, eventDate: str, eventTime: str,
location: str, systemLanguage: str, location: str, systemLanguage: str,
conversationId: str, lowBandwidth: bool) -> {}: conversationId: str, lowBandwidth: bool,
contentLicenseUrl: str) -> {}:
blogJson = \ blogJson = \
createPublicPost(baseDir, createPublicPost(baseDir,
nickname, domain, port, httpPrefix, nickname, domain, port, httpPrefix,
@ -1771,7 +1781,7 @@ def createBlogPost(baseDir: str,
schedulePost, schedulePost,
eventDate, eventTime, location, eventDate, eventTime, location,
True, systemLanguage, conversationId, True, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
blogJson['object']['url'] = \ blogJson['object']['url'] = \
blogJson['object']['url'].replace('/@', '/users/') blogJson['object']['url'].replace('/@', '/users/')
_appendCitationsToBlogPost(baseDir, nickname, domain, blogJson) _appendCitationsToBlogPost(baseDir, nickname, domain, blogJson)
@ -1785,7 +1795,8 @@ def createNewsPost(baseDir: str,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, city: str, imageDescription: str, city: str,
subject: str, systemLanguage: str, subject: str, systemLanguage: str,
conversationId: str, lowBandwidth: bool) -> {}: conversationId: str, lowBandwidth: bool,
contentLicenseUrl: str) -> {}:
clientToServer = False clientToServer = False
inReplyTo = None inReplyTo = None
inReplyToAtomUri = None inReplyToAtomUri = None
@ -1804,7 +1815,7 @@ def createNewsPost(baseDir: str,
schedulePost, schedulePost,
eventDate, eventTime, location, eventDate, eventTime, location,
True, systemLanguage, conversationId, True, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
blog['object']['type'] = 'Article' blog['object']['type'] = 'Article'
return blog return blog
@ -1817,7 +1828,8 @@ def createQuestionPost(baseDir: str,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, city: str, imageDescription: str, city: str,
subject: str, durationDays: int, subject: str, durationDays: int,
systemLanguage: str, lowBandwidth: bool) -> {}: systemLanguage: str, lowBandwidth: bool,
contentLicenseUrl: str) -> {}:
"""Question post with multiple choice options """Question post with multiple choice options
""" """
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)
@ -1834,7 +1846,7 @@ def createQuestionPost(baseDir: str,
False, None, None, None, None, None, False, None, None, None, None, None,
None, None, None, None, None, None,
None, None, None, None, None, systemLanguage, None, None, None, None, None, systemLanguage,
None, lowBandwidth) None, lowBandwidth, contentLicenseUrl)
messageJson['object']['type'] = 'Question' messageJson['object']['type'] = 'Question'
messageJson['object']['oneOf'] = [] messageJson['object']['oneOf'] = []
messageJson['object']['votersCount'] = 0 messageJson['object']['votersCount'] = 0
@ -1866,7 +1878,8 @@ def createUnlistedPost(baseDir: str,
subject: str, schedulePost: bool, subject: str, schedulePost: bool,
eventDate: str, eventTime: str, eventDate: str, eventTime: str,
location: str, systemLanguage: str, location: str, systemLanguage: str,
conversationId: str, lowBandwidth: bool) -> {}: conversationId: str, lowBandwidth: bool,
contentLicenseUrl: str) -> {}:
"""Unlisted post. This has the #Public and followers links inverted. """Unlisted post. This has the #Public and followers links inverted.
""" """
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)
@ -1883,7 +1896,8 @@ def createUnlistedPost(baseDir: str,
schedulePost, eventDate, eventTime, location, schedulePost, eventDate, eventTime, location,
None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, systemLanguage, None, None, None, None, None, systemLanguage,
conversationId, lowBandwidth) conversationId, lowBandwidth,
contentLicenseUrl)
def createFollowersOnlyPost(baseDir: str, def createFollowersOnlyPost(baseDir: str,
@ -1899,7 +1913,8 @@ def createFollowersOnlyPost(baseDir: str,
subject: str, schedulePost: bool, subject: str, schedulePost: bool,
eventDate: str, eventTime: str, eventDate: str, eventTime: str,
location: str, systemLanguage: str, location: str, systemLanguage: str,
conversationId: str, lowBandwidth: bool) -> {}: conversationId: str, lowBandwidth: bool,
contentLicenseUrl: str) -> {}:
"""Followers only post """Followers only post
""" """
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)
@ -1916,7 +1931,8 @@ def createFollowersOnlyPost(baseDir: str,
schedulePost, eventDate, eventTime, location, schedulePost, eventDate, eventTime, location,
None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, systemLanguage, None, None, None, None, None, systemLanguage,
conversationId, lowBandwidth) conversationId, lowBandwidth,
contentLicenseUrl)
def getMentionedPeople(baseDir: str, httpPrefix: str, def getMentionedPeople(baseDir: str, httpPrefix: str,
@ -1968,7 +1984,8 @@ def createDirectMessagePost(baseDir: str,
schedulePost: bool, schedulePost: bool,
eventDate: str, eventTime: str, eventDate: str, eventTime: str,
location: str, systemLanguage: str, location: str, systemLanguage: str,
conversationId: str, lowBandwidth: bool) -> {}: conversationId: str, lowBandwidth: bool,
contentLicenseUrl: str) -> {}:
"""Direct Message post """Direct Message post
""" """
content = resolvePetnames(baseDir, nickname, domain, content) content = resolvePetnames(baseDir, nickname, domain, content)
@ -1992,7 +2009,8 @@ def createDirectMessagePost(baseDir: str,
schedulePost, eventDate, eventTime, location, schedulePost, eventDate, eventTime, location,
None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, systemLanguage, None, None, None, None, None, systemLanguage,
conversationId, lowBandwidth) conversationId, lowBandwidth,
contentLicenseUrl)
# mentioned recipients go into To rather than Cc # mentioned recipients go into To rather than Cc
messageJson['to'] = messageJson['object']['cc'] messageJson['to'] = messageJson['object']['cc']
messageJson['object']['to'] = messageJson['to'] messageJson['object']['to'] = messageJson['to']
@ -2012,7 +2030,8 @@ def createReportPost(baseDir: str,
attachImageFilename: str, mediaType: str, attachImageFilename: str, mediaType: str,
imageDescription: str, city: str, imageDescription: str, city: str,
debug: bool, subject: str, systemLanguage: str, debug: bool, subject: str, systemLanguage: str,
lowBandwidth: bool) -> {}: lowBandwidth: bool,
contentLicenseUrl: str) -> {}:
"""Send a report to moderators """Send a report to moderators
""" """
domainFull = getFullDomain(domain, port) domainFull = getFullDomain(domain, port)
@ -2086,7 +2105,7 @@ def createReportPost(baseDir: str,
False, None, None, None, None, None, False, None, None, None, None, None,
None, None, None, None, None, None,
None, None, None, None, None, systemLanguage, None, None, None, None, None, systemLanguage,
None, lowBandwidth) None, lowBandwidth, contentLicenseUrl)
if not postJsonObject: if not postJsonObject:
continue continue
@ -2183,7 +2202,7 @@ def sendPost(signingPrivateKeyPem: str, projectVersion: str,
isArticle: bool, systemLanguage: str, isArticle: bool, systemLanguage: str,
sharedItemsFederatedDomains: [], sharedItemsFederatedDomains: [],
sharedItemFederationTokens: {}, sharedItemFederationTokens: {},
lowBandwidth: bool, lowBandwidth: bool, contentLicenseUrl: str,
debug: bool = False, inReplyTo: str = None, debug: bool = False, inReplyTo: str = None,
inReplyToAtomUri: str = None, subject: str = None) -> int: inReplyToAtomUri: str = None, subject: str = None) -> int:
"""Post to another inbox. Used by unit tests. """Post to another inbox. Used by unit tests.
@ -2249,7 +2268,8 @@ def sendPost(signingPrivateKeyPem: str, projectVersion: str,
False, None, None, None, None, None, False, None, None, None, None, None,
None, None, None, None, None, None,
None, None, None, None, None, systemLanguage, None, None, None, None, None, systemLanguage,
conversationId, lowBandwidth) conversationId, lowBandwidth,
contentLicenseUrl)
# get the senders private key # get the senders private key
privateKeyPem = _getPersonKey(nickname, domain, baseDir, 'private') privateKeyPem = _getPersonKey(nickname, domain, baseDir, 'private')
@ -2331,6 +2351,7 @@ def sendPostViaServer(signingPrivateKeyPem: str, projectVersion: str,
cachedWebfingers: {}, personCache: {}, cachedWebfingers: {}, personCache: {},
isArticle: bool, systemLanguage: str, isArticle: bool, systemLanguage: str,
lowBandwidth: bool, lowBandwidth: bool,
contentLicenseUrl: str,
debug: bool = False, debug: bool = False,
inReplyTo: str = None, inReplyTo: str = None,
inReplyToAtomUri: str = None, inReplyToAtomUri: str = None,
@ -2416,7 +2437,8 @@ def sendPostViaServer(signingPrivateKeyPem: str, projectVersion: str,
False, None, None, None, None, None, False, None, None, None, None, None,
None, None, None, None, None, None,
None, None, None, None, None, systemLanguage, None, None, None, None, None, systemLanguage,
conversationId, lowBandwidth) conversationId, lowBandwidth,
contentLicenseUrl)
authHeader = createBasicAuthHeader(fromNickname, password) authHeader = createBasicAuthHeader(fromNickname, password)

View File

@ -128,7 +128,8 @@ def _updatePostSchedule(baseDir: str, handle: str, httpd,
httpd.maxLikeCount, httpd.maxLikeCount,
httpd.maxRecentPosts, httpd.maxRecentPosts,
httpd.CWlists, httpd.CWlists,
httpd.listsEnabled): httpd.listsEnabled,
httpd.contentLicenseUrl):
indexLines.remove(line) indexLines.remove(line)
try: try:
os.remove(postFilename) os.remove(postFilename)

View File

@ -308,7 +308,8 @@ def addShare(baseDir: str,
duration: str, debug: bool, city: str, duration: str, debug: bool, city: str,
price: str, currency: str, price: str, currency: str,
systemLanguage: str, translate: {}, systemLanguage: str, translate: {},
sharesFileType: str, lowBandwidth: bool) -> None: sharesFileType: str, lowBandwidth: bool,
contentLicenseUrl: str) -> None:
"""Adds a new share """Adds a new share
""" """
if isFilteredGlobally(baseDir, if isFilteredGlobally(baseDir,
@ -363,7 +364,7 @@ def addShare(baseDir: str,
convertImageToLowBandwidth(imageFilename) convertImageToLowBandwidth(imageFilename)
processMetaData(baseDir, nickname, domain, processMetaData(baseDir, nickname, domain,
imageFilename, itemIDfile + '.' + ext, imageFilename, itemIDfile + '.' + ext,
city) city, contentLicenseUrl)
if moveImage: if moveImage:
try: try:
os.remove(imageFilename) os.remove(imageFilename)
@ -1033,7 +1034,8 @@ def outboxShareUpload(baseDir: str, httpPrefix: str,
nickname: str, domain: str, port: int, nickname: str, domain: str, port: int,
messageJson: {}, debug: bool, city: str, messageJson: {}, debug: bool, city: str,
systemLanguage: str, translate: {}, systemLanguage: str, translate: {},
lowBandwidth: bool) -> None: lowBandwidth: bool,
contentLicenseUrl: str) -> None:
""" When a shared item is received by the outbox from c2s """ When a shared item is received by the outbox from c2s
""" """
if not messageJson.get('type'): if not messageJson.get('type'):
@ -1095,7 +1097,7 @@ def outboxShareUpload(baseDir: str, httpPrefix: str,
messageJson['object']['itemPrice'], messageJson['object']['itemPrice'],
messageJson['object']['itemCurrency'], messageJson['object']['itemCurrency'],
systemLanguage, translate, 'shares', systemLanguage, translate, 'shares',
lowBandwidth) lowBandwidth, contentLicenseUrl)
if debug: if debug:
print('DEBUG: shared item received via c2s') print('DEBUG: shared item received via c2s')

View File

@ -753,6 +753,7 @@ def createServerAlice(path: str, domain: str, port: int,
testLocation = None testLocation = None
testIsArticle = False testIsArticle = False
conversationId = None conversationId = None
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"No wise fish would go anywhere without a porpoise", "No wise fish would go anywhere without a porpoise",
testFollowersOnly, testFollowersOnly,
@ -766,7 +767,7 @@ def createServerAlice(path: str, domain: str, port: int,
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId, testIsArticle, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"Curiouser and curiouser!", "Curiouser and curiouser!",
testFollowersOnly, testFollowersOnly,
@ -780,7 +781,7 @@ def createServerAlice(path: str, domain: str, port: int,
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId, testIsArticle, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"In the gardens of memory, in the palace " + "In the gardens of memory, in the palace " +
"of dreams, that is where you and I shall meet", "of dreams, that is where you and I shall meet",
@ -795,7 +796,7 @@ def createServerAlice(path: str, domain: str, port: int,
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId, testIsArticle, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
regenerateIndexForBox(path, nickname, domain, 'outbox') regenerateIndexForBox(path, nickname, domain, 'outbox')
global testServerAliceRunning global testServerAliceRunning
testServerAliceRunning = True testServerAliceRunning = True
@ -818,8 +819,10 @@ def createServerAlice(path: str, domain: str, port: int,
maxLikeCount = 10 maxLikeCount = 10
defaultReplyIntervalHours = 9999999999 defaultReplyIntervalHours = 9999999999
listsEnabled = '' listsEnabled = ''
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
print('Server running: Alice') print('Server running: Alice')
runDaemon(listsEnabled, defaultReplyIntervalHours, runDaemon(contentLicenseUrl,
listsEnabled, defaultReplyIntervalHours,
lowBandwidth, maxLikeCount, lowBandwidth, maxLikeCount,
sharedItemsFederatedDomains, sharedItemsFederatedDomains,
userAgentsBlocked, userAgentsBlocked,
@ -892,6 +895,7 @@ def createServerBob(path: str, domain: str, port: int,
testLocation = None testLocation = None
testIsArticle = False testIsArticle = False
conversationId = None conversationId = None
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"It's your life, live it your way.", "It's your life, live it your way.",
testFollowersOnly, testFollowersOnly,
@ -905,7 +909,7 @@ def createServerBob(path: str, domain: str, port: int,
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId, testIsArticle, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"One of the things I've realised is that " + "One of the things I've realised is that " +
"I am very simple", "I am very simple",
@ -920,7 +924,7 @@ def createServerBob(path: str, domain: str, port: int,
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId, testIsArticle, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
createPublicPost(path, nickname, domain, port, httpPrefix, createPublicPost(path, nickname, domain, port, httpPrefix,
"Quantum physics is a bit of a passion of mine", "Quantum physics is a bit of a passion of mine",
testFollowersOnly, testFollowersOnly,
@ -934,7 +938,7 @@ def createServerBob(path: str, domain: str, port: int,
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId, testIsArticle, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
regenerateIndexForBox(path, nickname, domain, 'outbox') regenerateIndexForBox(path, nickname, domain, 'outbox')
global testServerBobRunning global testServerBobRunning
testServerBobRunning = True testServerBobRunning = True
@ -957,8 +961,10 @@ def createServerBob(path: str, domain: str, port: int,
maxLikeCount = 10 maxLikeCount = 10
defaultReplyIntervalHours = 9999999999 defaultReplyIntervalHours = 9999999999
listsEnabled = '' listsEnabled = ''
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
print('Server running: Bob') print('Server running: Bob')
runDaemon(listsEnabled, defaultReplyIntervalHours, runDaemon(contentLicenseUrl,
listsEnabled, defaultReplyIntervalHours,
lowBandwidth, maxLikeCount, lowBandwidth, maxLikeCount,
sharedItemsFederatedDomains, sharedItemsFederatedDomains,
userAgentsBlocked, userAgentsBlocked,
@ -1025,8 +1031,10 @@ def createServerEve(path: str, domain: str, port: int, federationList: [],
lowBandwidth = True lowBandwidth = True
defaultReplyIntervalHours = 9999999999 defaultReplyIntervalHours = 9999999999
listsEnabled = '' listsEnabled = ''
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
print('Server running: Eve') print('Server running: Eve')
runDaemon(listsEnabled, defaultReplyIntervalHours, runDaemon(contentLicenseUrl,
listsEnabled, defaultReplyIntervalHours,
lowBandwidth, maxLikeCount, lowBandwidth, maxLikeCount,
sharedItemsFederatedDomains, sharedItemsFederatedDomains,
userAgentsBlocked, userAgentsBlocked,
@ -1095,8 +1103,10 @@ def createServerGroup(path: str, domain: str, port: int,
lowBandwidth = True lowBandwidth = True
defaultReplyIntervalHours = 9999999999 defaultReplyIntervalHours = 9999999999
listsEnabled = '' listsEnabled = ''
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
print('Server running: Group') print('Server running: Group')
runDaemon(listsEnabled, defaultReplyIntervalHours, runDaemon(contentLicenseUrl,
listsEnabled, defaultReplyIntervalHours,
lowBandwidth, maxLikeCount, lowBandwidth, maxLikeCount,
sharedItemsFederatedDomains, sharedItemsFederatedDomains,
userAgentsBlocked, userAgentsBlocked,
@ -1132,6 +1142,7 @@ def testPostMessageBetweenServers(baseDir: str) -> None:
systemLanguage = 'en' systemLanguage = 'en'
httpPrefix = 'http' httpPrefix = 'http'
proxyType = None proxyType = None
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
if os.path.isdir(baseDir + '/.tests'): if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests', ignore_errors=False, onerror=None) shutil.rmtree(baseDir + '/.tests', ignore_errors=False, onerror=None)
@ -1235,6 +1246,7 @@ def testPostMessageBetweenServers(baseDir: str) -> None:
alicePersonCache, isArticle, systemLanguage, alicePersonCache, isArticle, systemLanguage,
aliceSharedItemsFederatedDomains, aliceSharedItemsFederatedDomains,
aliceSharedItemFederationTokens, lowBandwidth, aliceSharedItemFederationTokens, lowBandwidth,
contentLicenseUrl,
inReplyTo, inReplyToAtomUri, subject) inReplyTo, inReplyToAtomUri, subject)
print('sendResult: ' + str(sendResult)) print('sendResult: ' + str(sendResult))
@ -1433,6 +1445,7 @@ def testFollowBetweenServers(baseDir: str) -> None:
httpPrefix = 'http' httpPrefix = 'http'
proxyType = None proxyType = None
federationList = [] federationList = []
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
if os.path.isdir(baseDir + '/.tests'): if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests', ignore_errors=False, onerror=None) shutil.rmtree(baseDir + '/.tests', ignore_errors=False, onerror=None)
@ -1572,6 +1585,7 @@ def testFollowBetweenServers(baseDir: str) -> None:
alicePersonCache, isArticle, systemLanguage, alicePersonCache, isArticle, systemLanguage,
aliceSharedItemsFederatedDomains, aliceSharedItemsFederatedDomains,
aliceSharedItemFederationTokens, lowBandwidth, aliceSharedItemFederationTokens, lowBandwidth,
contentLicenseUrl,
inReplyTo, inReplyToAtomUri, subject) inReplyTo, inReplyToAtomUri, subject)
print('sendResult: ' + str(sendResult)) print('sendResult: ' + str(sendResult))
@ -1620,6 +1634,7 @@ def testSharedItemsFederation(baseDir: str) -> None:
httpPrefix = 'http' httpPrefix = 'http'
proxyType = None proxyType = None
federationList = [] federationList = []
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
if os.path.isdir(baseDir + '/.tests'): if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests', ignore_errors=False, onerror=None) shutil.rmtree(baseDir + '/.tests', ignore_errors=False, onerror=None)
@ -1920,7 +1935,8 @@ def testSharedItemsFederation(baseDir: str) -> None:
aliceSendThreads, alicePostLog, aliceCachedWebfingers, aliceSendThreads, alicePostLog, aliceCachedWebfingers,
alicePersonCache, isArticle, systemLanguage, alicePersonCache, isArticle, systemLanguage,
aliceSharedItemsFederatedDomains, aliceSharedItemsFederatedDomains,
aliceSharedItemFederationTokens, lowBandwidth, True, aliceSharedItemFederationTokens, lowBandwidth,
contentLicenseUrl, True,
inReplyTo, inReplyToAtomUri, subject) inReplyTo, inReplyToAtomUri, subject)
print('sendResult: ' + str(sendResult)) print('sendResult: ' + str(sendResult))
@ -2024,6 +2040,7 @@ def testGroupFollow(baseDir: str) -> None:
httpPrefix = 'http' httpPrefix = 'http'
proxyType = None proxyType = None
federationList = [] federationList = []
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
if os.path.isdir(baseDir + '/.tests'): if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests', ignore_errors=False, onerror=None) shutil.rmtree(baseDir + '/.tests', ignore_errors=False, onerror=None)
@ -2340,6 +2357,7 @@ def testGroupFollow(baseDir: str) -> None:
alicePersonCache, isArticle, systemLanguage, alicePersonCache, isArticle, systemLanguage,
aliceSharedItemsFederatedDomains, aliceSharedItemsFederatedDomains,
aliceSharedItemFederationTokens, lowBandwidth, aliceSharedItemFederationTokens, lowBandwidth,
contentLicenseUrl,
inReplyTo, inReplyToAtomUri, subject) inReplyTo, inReplyToAtomUri, subject)
print('sendResult: ' + str(sendResult)) print('sendResult: ' + str(sendResult))
@ -2692,6 +2710,7 @@ def _testCreatePerson(baseDir: str):
mediaType = None mediaType = None
conversationId = None conversationId = None
lowBandwidth = True lowBandwidth = True
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
content, followersOnly, saveToFile, clientToServer, content, followersOnly, saveToFile, clientToServer,
commentsEnabled, attachImageFilename, mediaType, commentsEnabled, attachImageFilename, mediaType,
@ -2700,7 +2719,7 @@ def _testCreatePerson(baseDir: str):
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId, testIsArticle, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
os.chdir(currDir) os.chdir(currDir)
shutil.rmtree(baseDir, ignore_errors=False, onerror=None) shutil.rmtree(baseDir, ignore_errors=False, onerror=None)
@ -2763,6 +2782,7 @@ def testClientToServer(baseDir: str):
global testServerAliceRunning global testServerAliceRunning
global testServerBobRunning global testServerBobRunning
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
testServerAliceRunning = False testServerAliceRunning = False
testServerBobRunning = False testServerBobRunning = False
@ -2879,6 +2899,7 @@ def testClientToServer(baseDir: str):
attachedImageDescription, city, attachedImageDescription, city,
cachedWebfingers, personCache, isArticle, cachedWebfingers, personCache, isArticle,
systemLanguage, lowBandwidth, systemLanguage, lowBandwidth,
contentLicenseUrl,
True, None, None, True, None, None,
conversationId, None) conversationId, None)
print('sendResult: ' + str(sendResult)) print('sendResult: ' + str(sendResult))
@ -4185,6 +4206,7 @@ def _testReplyToPublicPost(baseDir: str) -> None:
testIsArticle = False testIsArticle = False
conversationId = None conversationId = None
lowBandwidth = True lowBandwidth = True
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
reply = \ reply = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
content, followersOnly, saveToFile, content, followersOnly, saveToFile,
@ -4195,7 +4217,7 @@ def _testReplyToPublicPost(baseDir: str) -> None:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId, testIsArticle, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
# print(str(reply)) # print(str(reply))
assert reply['object']['content'] == \ assert reply['object']['content'] == \
'<p><span class=\"h-card\">' + \ '<p><span class=\"h-card\">' + \
@ -4717,6 +4739,7 @@ def _testLinksWithinPost(baseDir: str) -> None:
testIsArticle = False testIsArticle = False
conversationId = None conversationId = None
lowBandwidth = True lowBandwidth = True
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
postJsonObject = \ postJsonObject = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
@ -4728,7 +4751,7 @@ def _testLinksWithinPost(baseDir: str) -> None:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId, testIsArticle, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
assert postJsonObject['object']['content'] == \ assert postJsonObject['object']['content'] == \
'<p>This is a test post with links.<br><br>' + \ '<p>This is a test post with links.<br><br>' + \
@ -4765,7 +4788,7 @@ def _testLinksWithinPost(baseDir: str) -> None:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId, testIsArticle, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
assert postJsonObject['object']['content'] == content assert postJsonObject['object']['content'] == content
assert postJsonObject['object']['contentMap'][systemLanguage] == content assert postJsonObject['object']['contentMap'][systemLanguage] == content
@ -5703,6 +5726,7 @@ def _testCanReplyTo(baseDir: str) -> None:
testIsArticle = False testIsArticle = False
conversationId = None conversationId = None
lowBandwidth = True lowBandwidth = True
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
postJsonObject = \ postJsonObject = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix, createPublicPost(baseDir, nickname, domain, port, httpPrefix,
@ -5714,7 +5738,7 @@ def _testCanReplyTo(baseDir: str) -> None:
testSubject, testSchedulePost, testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation, testEventDate, testEventTime, testLocation,
testIsArticle, systemLanguage, conversationId, testIsArticle, systemLanguage, conversationId,
lowBandwidth) lowBandwidth, contentLicenseUrl)
# set the date on the post # set the date on the post
currDateStr = "2021-09-08T20:45:00Z" currDateStr = "2021-09-08T20:45:00Z"
postJsonObject['published'] = currDateStr postJsonObject['published'] = currDateStr

View File

@ -491,5 +491,6 @@
"System Monitor": "مراقب النظام", "System Monitor": "مراقب النظام",
"Add content warnings for the following sites": "أضف تحذيرات المحتوى للمواقع التالية", "Add content warnings for the following sites": "أضف تحذيرات المحتوى للمواقع التالية",
"Known Web Crawlers": "برامج زحف الويب المعروفة", "Known Web Crawlers": "برامج زحف الويب المعروفة",
"Add to the calendar": "أضف إلى التقويم" "Add to the calendar": "أضف إلى التقويم",
"Content License": "ترخيص المحتوى"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "Monitor del sistema", "System Monitor": "Monitor del sistema",
"Add content warnings for the following sites": "Afegiu advertiments de contingut per als llocs següents", "Add content warnings for the following sites": "Afegiu advertiments de contingut per als llocs següents",
"Known Web Crawlers": "Exploradors web coneguts", "Known Web Crawlers": "Exploradors web coneguts",
"Add to the calendar": "Afegeix al calendari" "Add to the calendar": "Afegeix al calendari",
"Content License": "Llicència de contingut"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "Monitor System", "System Monitor": "Monitor System",
"Add content warnings for the following sites": "Ychwanegwch rybuddion cynnwys ar gyfer y gwefannau canlynol", "Add content warnings for the following sites": "Ychwanegwch rybuddion cynnwys ar gyfer y gwefannau canlynol",
"Known Web Crawlers": "Crawlers Gwe Hysbys", "Known Web Crawlers": "Crawlers Gwe Hysbys",
"Add to the calendar": "Ychwanegwch at y calendr" "Add to the calendar": "Ychwanegwch at y calendr",
"Content License": "Trwydded Cynnwys"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "Systemmonitor", "System Monitor": "Systemmonitor",
"Add content warnings for the following sites": "Inhaltswarnungen für die folgenden Websites hinzufügen", "Add content warnings for the following sites": "Inhaltswarnungen für die folgenden Websites hinzufügen",
"Known Web Crawlers": "Bekannte Web-Crawler", "Known Web Crawlers": "Bekannte Web-Crawler",
"Add to the calendar": "Zum Kalender hinzufügen" "Add to the calendar": "Zum Kalender hinzufügen",
"Content License": "Inhaltslizenz"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "System Monitor", "System Monitor": "System Monitor",
"Add content warnings for the following sites": "Add content warnings for the following sites", "Add content warnings for the following sites": "Add content warnings for the following sites",
"Known Web Crawlers": "Known Web Crawlers", "Known Web Crawlers": "Known Web Crawlers",
"Add to the calendar": "Add to the calendar" "Add to the calendar": "Add to the calendar",
"Content License": "Content License"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "Monitor del sistema", "System Monitor": "Monitor del sistema",
"Add content warnings for the following sites": "Agregue advertencias de contenido para los siguientes sitios", "Add content warnings for the following sites": "Agregue advertencias de contenido para los siguientes sitios",
"Known Web Crawlers": "Rastreadores web conocidos", "Known Web Crawlers": "Rastreadores web conocidos",
"Add to the calendar": "Agregar al calendario" "Add to the calendar": "Agregar al calendario",
"Content License": "Licencia de contenido"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "Moniteur système", "System Monitor": "Moniteur système",
"Add content warnings for the following sites": "Ajouter des avertissements de contenu pour les sites suivants", "Add content warnings for the following sites": "Ajouter des avertissements de contenu pour les sites suivants",
"Known Web Crawlers": "Crawlers Web connus", "Known Web Crawlers": "Crawlers Web connus",
"Add to the calendar": "Ajouter au calendrier" "Add to the calendar": "Ajouter au calendrier",
"Content License": "Licence de contenu"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "Monatóir Córais", "System Monitor": "Monatóir Córais",
"Add content warnings for the following sites": "Cuir rabhaidh ábhair leis na suíomhanna seo a leanas", "Add content warnings for the following sites": "Cuir rabhaidh ábhair leis na suíomhanna seo a leanas",
"Known Web Crawlers": "Crawlers Gréasáin Aitheanta", "Known Web Crawlers": "Crawlers Gréasáin Aitheanta",
"Add to the calendar": "Cuir leis an bhféilire" "Add to the calendar": "Cuir leis an bhféilire",
"Content License": "Ceadúnas Ábhar"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "सिस्टम मॉनिटर", "System Monitor": "सिस्टम मॉनिटर",
"Add content warnings for the following sites": "निम्नलिखित साइटों के लिए सामग्री चेतावनियाँ जोड़ें", "Add content warnings for the following sites": "निम्नलिखित साइटों के लिए सामग्री चेतावनियाँ जोड़ें",
"Known Web Crawlers": "ज्ञात वेब क्रॉलर", "Known Web Crawlers": "ज्ञात वेब क्रॉलर",
"Add to the calendar": "कैलेंडर में जोड़ें" "Add to the calendar": "कैलेंडर में जोड़ें",
"Content License": "सामग्री लाइसेंस"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "Monitor di sistema", "System Monitor": "Monitor di sistema",
"Add content warnings for the following sites": "Aggiungi avvisi sui contenuti per i seguenti siti", "Add content warnings for the following sites": "Aggiungi avvisi sui contenuti per i seguenti siti",
"Known Web Crawlers": "Crawler Web conosciuti", "Known Web Crawlers": "Crawler Web conosciuti",
"Add to the calendar": "Aggiungi al calendario" "Add to the calendar": "Aggiungi al calendario",
"Content License": "Licenza sui contenuti"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "システムモニター", "System Monitor": "システムモニター",
"Add content warnings for the following sites": "次のサイトのコンテンツ警告を追加します", "Add content warnings for the following sites": "次のサイトのコンテンツ警告を追加します",
"Known Web Crawlers": "既知のWebクローラー", "Known Web Crawlers": "既知のWebクローラー",
"Add to the calendar": "カレンダーに追加" "Add to the calendar": "カレンダーに追加",
"Content License": "コンテンツライセンス"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "System Monitor", "System Monitor": "System Monitor",
"Add content warnings for the following sites": "Ji bo malperên jêrîn hişyariyên naverokê zêde bikin", "Add content warnings for the following sites": "Ji bo malperên jêrîn hişyariyên naverokê zêde bikin",
"Known Web Crawlers": "Crawlerên Webê yên naskirî", "Known Web Crawlers": "Crawlerên Webê yên naskirî",
"Add to the calendar": "Di salnameyê de zêde bike" "Add to the calendar": "Di salnameyê de zêde bike",
"Content License": "Naverok License de"
} }

View File

@ -487,5 +487,6 @@
"System Monitor": "System Monitor", "System Monitor": "System Monitor",
"Add content warnings for the following sites": "Add content warnings for the following sites", "Add content warnings for the following sites": "Add content warnings for the following sites",
"Known Web Crawlers": "Known Web Crawlers", "Known Web Crawlers": "Known Web Crawlers",
"Add to the calendar": "Add to the calendar" "Add to the calendar": "Add to the calendar",
"Content License": "Content License"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "Monitor de Sistema", "System Monitor": "Monitor de Sistema",
"Add content warnings for the following sites": "Adicione avisos de conteúdo para os seguintes sites", "Add content warnings for the following sites": "Adicione avisos de conteúdo para os seguintes sites",
"Known Web Crawlers": "Rastreadores da Web conhecidos", "Known Web Crawlers": "Rastreadores da Web conhecidos",
"Add to the calendar": "Adicionar ao calendário" "Add to the calendar": "Adicionar ao calendário",
"Content License": "Licença de Conteúdo"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "Системный монитор", "System Monitor": "Системный монитор",
"Add content warnings for the following sites": "Добавить предупреждения о содержании для следующих сайтов", "Add content warnings for the following sites": "Добавить предупреждения о содержании для следующих сайтов",
"Known Web Crawlers": "Известные веб-сканеры", "Known Web Crawlers": "Известные веб-сканеры",
"Add to the calendar": "Добавить в календарь" "Add to the calendar": "Добавить в календарь",
"Content License": "Лицензия на содержание"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "Ufuatiliaji wa Mfumo", "System Monitor": "Ufuatiliaji wa Mfumo",
"Add content warnings for the following sites": "Ongeza maonyo ya yaliyomo kwa wavuti zifuatazo", "Add content warnings for the following sites": "Ongeza maonyo ya yaliyomo kwa wavuti zifuatazo",
"Known Web Crawlers": "Watambaji Wavuti Wanaojulikana", "Known Web Crawlers": "Watambaji Wavuti Wanaojulikana",
"Add to the calendar": "Ongeza kwenye kalenda" "Add to the calendar": "Ongeza kwenye kalenda",
"Content License": "Leseni ya Maudhui"
} }

View File

@ -491,5 +491,6 @@
"System Monitor": "系统监视器", "System Monitor": "系统监视器",
"Add content warnings for the following sites": "为以下网站添加内容警告", "Add content warnings for the following sites": "为以下网站添加内容警告",
"Known Web Crawlers": "已知的网络爬虫", "Known Web Crawlers": "已知的网络爬虫",
"Add to the calendar": "添加到日历" "Add to the calendar": "添加到日历",
"Content License": "内容许可"
} }

View File

@ -53,6 +53,7 @@ from jami import getJamiAddress
from cwtch import getCwtchAddress from cwtch import getCwtchAddress
from filters import isFiltered from filters import isFiltered
from follow import isFollowerOfPerson from follow import isFollowerOfPerson
from follow import getFollowerDomains
from webapp_frontscreen import htmlFrontScreen from webapp_frontscreen import htmlFrontScreen
from webapp_utils import htmlKeyboardNavigation from webapp_utils import htmlKeyboardNavigation
from webapp_utils import htmlHideFromScreenReader from webapp_utils import htmlHideFromScreenReader
@ -541,7 +542,8 @@ def htmlProfile(signingPrivateKeyPem: str,
sharedItemsFederatedDomains: [], sharedItemsFederatedDomains: [],
extraJson: {}, pageNumber: int, extraJson: {}, pageNumber: int,
maxItemsPerPage: int, maxItemsPerPage: int,
CWlists: {}, listsEnabled: str) -> str: CWlists: {}, listsEnabled: str,
contentLicenseUrl: str) -> str:
"""Show the profile page as html """Show the profile page as html
""" """
nickname = profileJson['preferredUsername'] nickname = profileJson['preferredUsername']
@ -716,9 +718,12 @@ def htmlProfile(signingPrivateKeyPem: str,
break break
if selected == 'followers': if selected == 'followers':
if followApprovals: if followApprovals:
currFollowerDomains = \
getFollowerDomains(baseDir, nickname, domain)
with open(followRequestsFilename, 'r') as f: with open(followRequestsFilename, 'r') as f:
for followerHandle in f: for followerHandle in f:
if len(line) > 0: if len(line) > 0:
followerHandle = followerHandle.replace('\n', '')
if '://' in followerHandle: if '://' in followerHandle:
followerActor = followerHandle followerActor = followerHandle
else: else:
@ -726,13 +731,25 @@ def htmlProfile(signingPrivateKeyPem: str,
dom = followerHandle.split('@')[1] dom = followerHandle.split('@')[1]
followerActor = \ followerActor = \
localActorUrl(httpPrefix, nick, dom) localActorUrl(httpPrefix, nick, dom)
# is this a new domain?
# if so then append a new instance indicator
followerDomain, _ = \
getDomainFromActor(followerActor)
newFollowerDomain = ''
if followerDomain not in currFollowerDomains:
newFollowerDomain = ''
basePath = '/users/' + nickname basePath = '/users/' + nickname
followApprovalsSection += '<div class="container">' followApprovalsSection += '<div class="container">'
followApprovalsSection += \ followApprovalsSection += \
'<a href="' + followerActor + '">' '<a href="' + followerActor + '">'
followApprovalsSection += \ followApprovalsSection += \
'<span class="followRequestHandle">' + \ '<span class="followRequestHandle">' + \
followerHandle + '</span></a>' followerHandle + \
newFollowerDomain + '</span></a>'
# show Approve and Deny buttons
followApprovalsSection += \ followApprovalsSection += \
'<a href="' + basePath + \ '<a href="' + basePath + \
'/followapprove=' + followerHandle + '">' '/followapprove=' + followerHandle + '">'
@ -970,7 +987,8 @@ def htmlProfile(signingPrivateKeyPem: str,
getConfigParam(baseDir, 'instanceTitle') getConfigParam(baseDir, 'instanceTitle')
profileStr = \ profileStr = \
htmlHeaderWithPersonMarkup(cssFilename, instanceTitle, htmlHeaderWithPersonMarkup(cssFilename, instanceTitle,
profileJson, city) + \ profileJson, city,
contentLicenseUrl) + \
profileStr + htmlFooter() profileStr + htmlFooter()
return profileStr return profileStr
@ -1268,6 +1286,10 @@ def _htmlEditProfileInstance(baseDir: str, translate: {},
getConfigParam(baseDir, 'instanceDescriptionShort') getConfigParam(baseDir, 'instanceDescriptionShort')
instanceTitle = \ instanceTitle = \
getConfigParam(baseDir, 'instanceTitle') getConfigParam(baseDir, 'instanceTitle')
contentLicenseUrl = \
getConfigParam(baseDir, 'contentLicenseUrl')
if not contentLicenseUrl:
contentLicenseUrl = 'https://creativecommons.org/licenses/by/4.0'
instanceStr = beginEditSection(translate['Instance Settings']) instanceStr = beginEditSection(translate['Instance Settings'])
@ -1283,6 +1305,10 @@ def _htmlEditProfileInstance(baseDir: str, translate: {},
editTextArea(translate['Instance Description'], editTextArea(translate['Instance Description'],
'instanceDescription', instanceDescription, 200, 'instanceDescription', instanceDescription, 200,
'', True) '', True)
instanceStr += \
editTextField(translate['Content License'],
'contentLicenseUrl', contentLicenseUrl)
instanceStr += '<br>\n'
instanceStr += \ instanceStr += \
editTextField(translate['Custom post submit button text'], editTextField(translate['Custom post submit button text'],
'customSubmitText', customSubmitText) 'customSubmitText', customSubmitText)

View File

@ -533,8 +533,15 @@ def htmlHeaderWithExternalStyle(cssFilename: str, instanceTitle: str,
'<html lang="' + lang + '">\n' + \ '<html lang="' + lang + '">\n' + \
' <head>\n' + \ ' <head>\n' + \
' <meta charset="utf-8">\n' + \ ' <meta charset="utf-8">\n' + \
' <link rel="stylesheet" href="' + cssFile + '">\n' + \ ' <link rel="stylesheet" media="all" ' + \
'href="' + cssFile + '">\n' + \
' <link rel="manifest" href="/manifest.json">\n' + \ ' <link rel="manifest" href="/manifest.json">\n' + \
' <link href="/favicon.ico" rel="icon" type="image/x-icon">\n' + \
' <meta content="/browserconfig.xml" ' + \
'name="msapplication-config">\n' + \
' <meta content="yes" name="apple-mobile-web-app-capable">\n' + \
' <link href="/apple-touch-icon.png" rel="apple-touch-icon" ' + \
'sizes="180x180">\n' + \
' <meta name="theme-color" content="grey">\n' + \ ' <meta name="theme-color" content="grey">\n' + \
metadata + \ metadata + \
' <title>' + instanceTitle + '</title>\n' + \ ' <title>' + instanceTitle + '</title>\n' + \
@ -545,6 +552,7 @@ def htmlHeaderWithExternalStyle(cssFilename: str, instanceTitle: str,
def htmlHeaderWithPersonMarkup(cssFilename: str, instanceTitle: str, def htmlHeaderWithPersonMarkup(cssFilename: str, instanceTitle: str,
actorJson: {}, city: str, actorJson: {}, city: str,
contentLicenseUrl: str,
lang='en') -> str: lang='en') -> str:
"""html header which includes person markup """html header which includes person markup
https://schema.org/Person https://schema.org/Person
@ -658,7 +666,6 @@ def htmlHeaderWithPersonMarkup(cssFilename: str, instanceTitle: str,
' "url": "' + actorJson['id'] + '"\n' + \ ' "url": "' + actorJson['id'] + '"\n' + \
' },\n' ' },\n'
licenseUrl = 'https://creativecommons.org/licenses/by/4.0'
profileMarkup = \ profileMarkup = \
' <script id="initial-state" type="application/ld+json">\n' + \ ' <script id="initial-state" type="application/ld+json">\n' + \
' {\n' + \ ' {\n' + \
@ -679,7 +686,7 @@ def htmlHeaderWithPersonMarkup(cssFilename: str, instanceTitle: str,
' "name": "' + nameStr + '",\n' + \ ' "name": "' + nameStr + '",\n' + \
' "image": "' + actorJson['icon']['url'] + '",\n' + \ ' "image": "' + actorJson['icon']['url'] + '",\n' + \
' "description": "' + description + '",\n' + \ ' "description": "' + description + '",\n' + \
' "license": "' + licenseUrl + '"\n' + \ ' "license": "' + contentLicenseUrl + '"\n' + \
' }\n' + \ ' }\n' + \
' </script>\n' ' </script>\n'
@ -788,8 +795,11 @@ def htmlHeaderWithWebsiteMarkup(cssFilename: str, instanceTitle: str,
def htmlHeaderWithBlogMarkup(cssFilename: str, instanceTitle: str, def htmlHeaderWithBlogMarkup(cssFilename: str, instanceTitle: str,
httpPrefix: str, domain: str, nickname: str, httpPrefix: str, domain: str, nickname: str,
systemLanguage: str, published: str, systemLanguage: str,
title: str, snippet: str) -> str: published: str, modified: str,
title: str, snippet: str,
translate: {}, url: str,
contentLicenseUrl: str) -> str:
"""html header which includes blog post markup """html header which includes blog post markup
https://schema.org/BlogPosting https://schema.org/BlogPosting
""" """
@ -798,7 +808,6 @@ def htmlHeaderWithBlogMarkup(cssFilename: str, instanceTitle: str,
# license for content on the site may be different from # license for content on the site may be different from
# the software license # the software license
contentLicenseUrl = 'https://creativecommons.org/licenses/by/3.0'
blogMarkup = \ blogMarkup = \
' <script id="initial-state" type="application/ld+json">\n' + \ ' <script id="initial-state" type="application/ld+json">\n' + \
@ -807,7 +816,7 @@ def htmlHeaderWithBlogMarkup(cssFilename: str, instanceTitle: str,
' "@type" : "BlogPosting",\n' + \ ' "@type" : "BlogPosting",\n' + \
' "headline": "' + title + '",\n' + \ ' "headline": "' + title + '",\n' + \
' "datePublished": "' + published + '",\n' + \ ' "datePublished": "' + published + '",\n' + \
' "dateModified": "' + published + '",\n' + \ ' "dateModified": "' + modified + '",\n' + \
' "author": {\n' + \ ' "author": {\n' + \
' "@type": "Person",\n' + \ ' "@type": "Person",\n' + \
' "name": "' + nickname + '",\n' + \ ' "name": "' + nickname + '",\n' + \
@ -822,9 +831,23 @@ def htmlHeaderWithBlogMarkup(cssFilename: str, instanceTitle: str,
' "description": "' + snippet + '"\n' + \ ' "description": "' + snippet + '"\n' + \
' }\n' + \ ' }\n' + \
' </script>\n' ' </script>\n'
ogMetadata = \
' <meta property="og:locale" content="' + \
systemLanguage + '" />\n' + \
' <meta property="og:type" content="article" />\n' + \
' <meta property="og:title" content="' + title + '" />\n' + \
' <meta property="og:url" content="' + url + '" />\n' + \
' <meta content="Epicyon hosted on ' + domain + \
'" property="og:site_name" />\n' + \
' <meta property="article:published_time" content="' + \
published + '" />\n' + \
' <meta property="article:modified_time" content="' + \
modified + '" />\n'
htmlStr = \ htmlStr = \
htmlHeaderWithExternalStyle(cssFilename, instanceTitle, blogMarkup, htmlHeaderWithExternalStyle(cssFilename, instanceTitle,
systemLanguage) ogMetadata + blogMarkup, systemLanguage)
return htmlStr return htmlStr