forked from indymedia/epicyon
Enforce convention of underscore before local function names
parent
0cf0841402
commit
5cd9aa8d66
|
|
@ -15,10 +15,10 @@ from utils import domainPermitted
|
||||||
from utils import followPerson
|
from utils import followPerson
|
||||||
|
|
||||||
|
|
||||||
def createAcceptReject(baseDir: str, federationList: [],
|
def _createAcceptReject(baseDir: str, federationList: [],
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
toUrl: str, ccUrl: str, httpPrefix: str,
|
toUrl: str, ccUrl: str, httpPrefix: str,
|
||||||
objectJson: {}, acceptType: str) -> {}:
|
objectJson: {}, acceptType: str) -> {}:
|
||||||
"""Accepts or rejects something (eg. a follow request or offer)
|
"""Accepts or rejects something (eg. a follow request or offer)
|
||||||
Typically toUrl will be https://www.w3.org/ns/activitystreams#Public
|
Typically toUrl will be https://www.w3.org/ns/activitystreams#Public
|
||||||
and ccUrl might be a specific person favorited or repeated and
|
and ccUrl might be a specific person favorited or repeated and
|
||||||
|
|
@ -51,24 +51,24 @@ def createAccept(baseDir: str, federationList: [],
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
toUrl: str, ccUrl: str, httpPrefix: str,
|
toUrl: str, ccUrl: str, httpPrefix: str,
|
||||||
objectJson: {}) -> {}:
|
objectJson: {}) -> {}:
|
||||||
return createAcceptReject(baseDir, federationList,
|
return _createAcceptReject(baseDir, federationList,
|
||||||
nickname, domain, port,
|
nickname, domain, port,
|
||||||
toUrl, ccUrl, httpPrefix,
|
toUrl, ccUrl, httpPrefix,
|
||||||
objectJson, 'Accept')
|
objectJson, 'Accept')
|
||||||
|
|
||||||
|
|
||||||
def createReject(baseDir: str, federationList: [],
|
def createReject(baseDir: str, federationList: [],
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
toUrl: str, ccUrl: str, httpPrefix: str,
|
toUrl: str, ccUrl: str, httpPrefix: str,
|
||||||
objectJson: {}) -> {}:
|
objectJson: {}) -> {}:
|
||||||
return createAcceptReject(baseDir, federationList,
|
return _createAcceptReject(baseDir, federationList,
|
||||||
nickname, domain, port,
|
nickname, domain, port,
|
||||||
toUrl, ccUrl,
|
toUrl, ccUrl,
|
||||||
httpPrefix, objectJson, 'Reject')
|
httpPrefix, objectJson, 'Reject')
|
||||||
|
|
||||||
|
|
||||||
def acceptFollow(baseDir: str, domain: str, messageJson: {},
|
def _acceptFollow(baseDir: str, domain: str, messageJson: {},
|
||||||
federationList: [], debug: bool) -> None:
|
federationList: [], debug: bool) -> None:
|
||||||
"""Receiving a follow Accept activity
|
"""Receiving a follow Accept activity
|
||||||
"""
|
"""
|
||||||
if not messageJson.get('object'):
|
if not messageJson.get('object'):
|
||||||
|
|
@ -204,7 +204,7 @@ def receiveAcceptReject(session, baseDir: str,
|
||||||
' does not contain a nickname. ' +
|
' does not contain a nickname. ' +
|
||||||
'Assuming single user instance.')
|
'Assuming single user instance.')
|
||||||
# receive follow accept
|
# receive follow accept
|
||||||
acceptFollow(baseDir, domain, messageJson, federationList, debug)
|
_acceptFollow(baseDir, domain, messageJson, federationList, debug)
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: Uh, ' + messageJson['type'] + ', I guess')
|
print('DEBUG: Uh, ' + messageJson['type'] + ', I guess')
|
||||||
return True
|
return True
|
||||||
|
|
|
||||||
12
auth.py
12
auth.py
|
|
@ -14,7 +14,7 @@ import secrets
|
||||||
from utils import isSystemAccount
|
from utils import isSystemAccount
|
||||||
|
|
||||||
|
|
||||||
def hashPassword(password: str) -> str:
|
def _hashPassword(password: str) -> str:
|
||||||
"""Hash a password for storing
|
"""Hash a password for storing
|
||||||
"""
|
"""
|
||||||
salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii')
|
salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii')
|
||||||
|
|
@ -25,7 +25,7 @@ def hashPassword(password: str) -> str:
|
||||||
return (salt + pwdhash).decode('ascii')
|
return (salt + pwdhash).decode('ascii')
|
||||||
|
|
||||||
|
|
||||||
def getPasswordHash(salt: str, providedPassword: str) -> str:
|
def _getPasswordHash(salt: str, providedPassword: str) -> str:
|
||||||
"""Returns the hash of a password
|
"""Returns the hash of a password
|
||||||
"""
|
"""
|
||||||
pwdhash = hashlib.pbkdf2_hmac('sha512',
|
pwdhash = hashlib.pbkdf2_hmac('sha512',
|
||||||
|
|
@ -57,7 +57,7 @@ def constantTimeStringCheck(string1: str, string2: str) -> bool:
|
||||||
return matched
|
return matched
|
||||||
|
|
||||||
|
|
||||||
def verifyPassword(storedPassword: str, providedPassword: str) -> bool:
|
def _verifyPassword(storedPassword: str, providedPassword: str) -> bool:
|
||||||
"""Verify a stored password against one provided by user
|
"""Verify a stored password against one provided by user
|
||||||
"""
|
"""
|
||||||
if not storedPassword:
|
if not storedPassword:
|
||||||
|
|
@ -66,7 +66,7 @@ def verifyPassword(storedPassword: str, providedPassword: str) -> bool:
|
||||||
return False
|
return False
|
||||||
salt = storedPassword[:64]
|
salt = storedPassword[:64]
|
||||||
storedPassword = storedPassword[64:]
|
storedPassword = storedPassword[64:]
|
||||||
pwHash = getPasswordHash(salt, providedPassword)
|
pwHash = _getPasswordHash(salt, providedPassword)
|
||||||
return constantTimeStringCheck(pwHash, storedPassword)
|
return constantTimeStringCheck(pwHash, storedPassword)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -137,7 +137,7 @@ def authorizeBasic(baseDir: str, path: str, authHeader: str,
|
||||||
if line.startswith(nickname+':'):
|
if line.startswith(nickname+':'):
|
||||||
storedPassword = \
|
storedPassword = \
|
||||||
line.split(':')[1].replace('\n', '').replace('\r', '')
|
line.split(':')[1].replace('\n', '').replace('\r', '')
|
||||||
success = verifyPassword(storedPassword, providedPassword)
|
success = _verifyPassword(storedPassword, providedPassword)
|
||||||
if not success:
|
if not success:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: Password check failed for ' + nickname)
|
print('DEBUG: Password check failed for ' + nickname)
|
||||||
|
|
@ -159,7 +159,7 @@ def storeBasicCredentials(baseDir: str, nickname: str, password: str) -> bool:
|
||||||
os.mkdir(baseDir + '/accounts')
|
os.mkdir(baseDir + '/accounts')
|
||||||
|
|
||||||
passwordFile = baseDir + '/accounts/passwords'
|
passwordFile = baseDir + '/accounts/passwords'
|
||||||
storeStr = nickname + ':' + hashPassword(password)
|
storeStr = nickname + ':' + _hashPassword(password)
|
||||||
if os.path.isfile(passwordFile):
|
if os.path.isfile(passwordFile):
|
||||||
if nickname + ':' in open(passwordFile).read():
|
if nickname + ':' in open(passwordFile).read():
|
||||||
with open(passwordFile, "r") as fin:
|
with open(passwordFile, "r") as fin:
|
||||||
|
|
|
||||||
129
blog.py
129
blog.py
|
|
@ -26,9 +26,9 @@ from newswire import rss2Header
|
||||||
from newswire import rss2Footer
|
from newswire import rss2Footer
|
||||||
|
|
||||||
|
|
||||||
def noOfBlogReplies(baseDir: str, httpPrefix: str, translate: {},
|
def _noOfBlogReplies(baseDir: str, httpPrefix: str, translate: {},
|
||||||
nickname: str, domain: str, domainFull: str,
|
nickname: str, domain: str, domainFull: str,
|
||||||
postId: str, depth=0) -> int:
|
postId: str, depth=0) -> int:
|
||||||
"""Returns the number of replies on the post
|
"""Returns the number of replies on the post
|
||||||
This is recursive, so can handle replies to replies
|
This is recursive, so can handle replies to replies
|
||||||
"""
|
"""
|
||||||
|
|
@ -66,9 +66,10 @@ def noOfBlogReplies(baseDir: str, httpPrefix: str, translate: {},
|
||||||
replyPostId = replyPostId.replace('.json', '')
|
replyPostId = replyPostId.replace('.json', '')
|
||||||
if locatePost(baseDir, nickname, domain, replyPostId):
|
if locatePost(baseDir, nickname, domain, replyPostId):
|
||||||
replyPostId = replyPostId.replace('.replies', '')
|
replyPostId = replyPostId.replace('.replies', '')
|
||||||
replies += 1 + noOfBlogReplies(baseDir, httpPrefix, translate,
|
replies += \
|
||||||
nickname, domain, domainFull,
|
1 + _noOfBlogReplies(baseDir, httpPrefix, translate,
|
||||||
replyPostId, depth+1)
|
nickname, domain, domainFull,
|
||||||
|
replyPostId, depth+1)
|
||||||
else:
|
else:
|
||||||
# remove post which no longer exists
|
# remove post which no longer exists
|
||||||
removals.append(replyPostId)
|
removals.append(replyPostId)
|
||||||
|
|
@ -86,9 +87,9 @@ def noOfBlogReplies(baseDir: str, httpPrefix: str, translate: {},
|
||||||
return replies
|
return replies
|
||||||
|
|
||||||
|
|
||||||
def getBlogReplies(baseDir: str, httpPrefix: str, translate: {},
|
def _getBlogReplies(baseDir: str, httpPrefix: str, translate: {},
|
||||||
nickname: str, domain: str, domainFull: str,
|
nickname: str, domain: str, domainFull: str,
|
||||||
postId: str, depth=0) -> str:
|
postId: str, depth=0) -> str:
|
||||||
"""Returns a string containing html blog posts
|
"""Returns a string containing html blog posts
|
||||||
"""
|
"""
|
||||||
if depth > 4:
|
if depth > 4:
|
||||||
|
|
@ -136,9 +137,9 @@ def getBlogReplies(baseDir: str, httpPrefix: str, translate: {},
|
||||||
continue
|
continue
|
||||||
with open(postFilename, "r") as postFile:
|
with open(postFilename, "r") as postFile:
|
||||||
repliesStr += postFile.read() + '\n'
|
repliesStr += postFile.read() + '\n'
|
||||||
rply = getBlogReplies(baseDir, httpPrefix, translate,
|
rply = _getBlogReplies(baseDir, httpPrefix, translate,
|
||||||
nickname, domain, domainFull,
|
nickname, domain, domainFull,
|
||||||
replyPostId, depth+1)
|
replyPostId, depth+1)
|
||||||
if rply not in repliesStr:
|
if rply not in repliesStr:
|
||||||
repliesStr += rply
|
repliesStr += rply
|
||||||
|
|
||||||
|
|
@ -152,12 +153,12 @@ def getBlogReplies(baseDir: str, httpPrefix: str, translate: {},
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
def htmlBlogPostContent(authorized: bool,
|
def _htmlBlogPostContent(authorized: bool,
|
||||||
baseDir: str, httpPrefix: str, translate: {},
|
baseDir: str, httpPrefix: str, translate: {},
|
||||||
nickname: str, domain: str, domainFull: str,
|
nickname: str, domain: str, domainFull: str,
|
||||||
postJsonObject: {},
|
postJsonObject: {},
|
||||||
handle: str, restrictToDomain: bool,
|
handle: str, restrictToDomain: bool,
|
||||||
blogSeparator='<hr>') -> str:
|
blogSeparator='<hr>') -> str:
|
||||||
"""Returns the content for a single blog post
|
"""Returns the content for a single blog post
|
||||||
"""
|
"""
|
||||||
linkedAuthor = False
|
linkedAuthor = False
|
||||||
|
|
@ -269,9 +270,9 @@ def htmlBlogPostContent(authorized: bool,
|
||||||
'/users/' + nickname + '">' + translate['About the author'] + \
|
'/users/' + nickname + '">' + translate['About the author'] + \
|
||||||
'</a></p>\n'
|
'</a></p>\n'
|
||||||
|
|
||||||
replies = noOfBlogReplies(baseDir, httpPrefix, translate,
|
replies = _noOfBlogReplies(baseDir, httpPrefix, translate,
|
||||||
nickname, domain, domainFull,
|
nickname, domain, domainFull,
|
||||||
postJsonObject['object']['id'])
|
postJsonObject['object']['id'])
|
||||||
|
|
||||||
# separator between blogs should be centered
|
# separator between blogs should be centered
|
||||||
if '<center>' not in blogSeparator:
|
if '<center>' not in blogSeparator:
|
||||||
|
|
@ -288,23 +289,23 @@ def htmlBlogPostContent(authorized: bool,
|
||||||
else:
|
else:
|
||||||
blogStr += blogSeparator + '<h1>' + translate['Replies'] + '</h1>\n'
|
blogStr += blogSeparator + '<h1>' + translate['Replies'] + '</h1>\n'
|
||||||
if not titleStr:
|
if not titleStr:
|
||||||
blogStr += getBlogReplies(baseDir, httpPrefix, translate,
|
blogStr += _getBlogReplies(baseDir, httpPrefix, translate,
|
||||||
nickname, domain, domainFull,
|
nickname, domain, domainFull,
|
||||||
postJsonObject['object']['id'])
|
postJsonObject['object']['id'])
|
||||||
else:
|
else:
|
||||||
blogRepliesStr = getBlogReplies(baseDir, httpPrefix, translate,
|
blogRepliesStr = _getBlogReplies(baseDir, httpPrefix, translate,
|
||||||
nickname, domain, domainFull,
|
nickname, domain, domainFull,
|
||||||
postJsonObject['object']['id'])
|
postJsonObject['object']['id'])
|
||||||
blogStr += blogRepliesStr.replace('>' + titleStr + '<', '')
|
blogStr += blogRepliesStr.replace('>' + titleStr + '<', '')
|
||||||
|
|
||||||
return blogStr
|
return blogStr
|
||||||
|
|
||||||
|
|
||||||
def htmlBlogPostRSS2(authorized: bool,
|
def _htmlBlogPostRSS2(authorized: bool,
|
||||||
baseDir: str, httpPrefix: str, translate: {},
|
baseDir: str, httpPrefix: str, translate: {},
|
||||||
nickname: str, domain: str, domainFull: str,
|
nickname: str, domain: str, domainFull: str,
|
||||||
postJsonObject: {},
|
postJsonObject: {},
|
||||||
handle: str, restrictToDomain: bool) -> str:
|
handle: str, restrictToDomain: bool) -> str:
|
||||||
"""Returns the RSS version 2 feed for a single blog post
|
"""Returns the RSS version 2 feed for a single blog post
|
||||||
"""
|
"""
|
||||||
rssStr = ''
|
rssStr = ''
|
||||||
|
|
@ -331,11 +332,11 @@ def htmlBlogPostRSS2(authorized: bool,
|
||||||
return rssStr
|
return rssStr
|
||||||
|
|
||||||
|
|
||||||
def htmlBlogPostRSS3(authorized: bool,
|
def _htmlBlogPostRSS3(authorized: bool,
|
||||||
baseDir: str, httpPrefix: str, translate: {},
|
baseDir: str, httpPrefix: str, translate: {},
|
||||||
nickname: str, domain: str, domainFull: str,
|
nickname: str, domain: str, domainFull: str,
|
||||||
postJsonObject: {},
|
postJsonObject: {},
|
||||||
handle: str, restrictToDomain: bool) -> str:
|
handle: str, restrictToDomain: bool) -> str:
|
||||||
"""Returns the RSS version 3 feed for a single blog post
|
"""Returns the RSS version 3 feed for a single blog post
|
||||||
"""
|
"""
|
||||||
rssStr = ''
|
rssStr = ''
|
||||||
|
|
@ -359,7 +360,7 @@ def htmlBlogPostRSS3(authorized: bool,
|
||||||
return rssStr
|
return rssStr
|
||||||
|
|
||||||
|
|
||||||
def htmlBlogRemoveCwButton(blogStr: str, translate: {}) -> str:
|
def _htmlBlogRemoveCwButton(blogStr: str, translate: {}) -> str:
|
||||||
"""Removes the CW button from blog posts, where the
|
"""Removes the CW button from blog posts, where the
|
||||||
summary field is instead used as the blog title
|
summary field is instead used as the blog title
|
||||||
"""
|
"""
|
||||||
|
|
@ -383,13 +384,13 @@ def htmlBlogPost(authorized: bool,
|
||||||
if os.path.isfile(baseDir + '/blog.css'):
|
if os.path.isfile(baseDir + '/blog.css'):
|
||||||
cssFilename = baseDir + '/blog.css'
|
cssFilename = baseDir + '/blog.css'
|
||||||
blogStr = htmlHeaderWithExternalStyle(cssFilename)
|
blogStr = htmlHeaderWithExternalStyle(cssFilename)
|
||||||
htmlBlogRemoveCwButton(blogStr, translate)
|
_htmlBlogRemoveCwButton(blogStr, translate)
|
||||||
|
|
||||||
blogStr += htmlBlogPostContent(authorized, baseDir,
|
blogStr += _htmlBlogPostContent(authorized, baseDir,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
nickname, domain,
|
nickname, domain,
|
||||||
domainFull, postJsonObject,
|
domainFull, postJsonObject,
|
||||||
None, False)
|
None, False)
|
||||||
|
|
||||||
# show rss links
|
# show rss links
|
||||||
blogStr += '<p class="rssfeed">'
|
blogStr += '<p class="rssfeed">'
|
||||||
|
|
@ -428,7 +429,7 @@ def htmlBlogPage(authorized: bool, session,
|
||||||
if os.path.isfile(baseDir + '/epicyon.css'):
|
if os.path.isfile(baseDir + '/epicyon.css'):
|
||||||
cssFilename = baseDir + '/epicyon.css'
|
cssFilename = baseDir + '/epicyon.css'
|
||||||
blogStr = htmlHeaderWithExternalStyle(cssFilename)
|
blogStr = htmlHeaderWithExternalStyle(cssFilename)
|
||||||
htmlBlogRemoveCwButton(blogStr, translate)
|
_htmlBlogRemoveCwButton(blogStr, translate)
|
||||||
|
|
||||||
blogsIndex = baseDir + '/accounts/' + \
|
blogsIndex = baseDir + '/accounts/' + \
|
||||||
nickname + '@' + domain + '/tlblogs.index'
|
nickname + '@' + domain + '/tlblogs.index'
|
||||||
|
|
@ -472,11 +473,11 @@ def htmlBlogPage(authorized: bool, session,
|
||||||
if item['type'] != 'Create':
|
if item['type'] != 'Create':
|
||||||
continue
|
continue
|
||||||
|
|
||||||
blogStr += htmlBlogPostContent(authorized, baseDir,
|
blogStr += _htmlBlogPostContent(authorized, baseDir,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
nickname, domain,
|
nickname, domain,
|
||||||
domainFull, item,
|
domainFull, item,
|
||||||
None, True)
|
None, True)
|
||||||
|
|
||||||
if len(timelineJson['orderedItems']) >= noOfItems:
|
if len(timelineJson['orderedItems']) >= noOfItems:
|
||||||
blogStr += navigateStr
|
blogStr += navigateStr
|
||||||
|
|
@ -544,11 +545,11 @@ def htmlBlogPageRSS2(authorized: bool, session,
|
||||||
continue
|
continue
|
||||||
|
|
||||||
blogRSS2 += \
|
blogRSS2 += \
|
||||||
htmlBlogPostRSS2(authorized, baseDir,
|
_htmlBlogPostRSS2(authorized, baseDir,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
nickname, domain,
|
nickname, domain,
|
||||||
domainFull, item,
|
domainFull, item,
|
||||||
None, True)
|
None, True)
|
||||||
|
|
||||||
if includeHeader:
|
if includeHeader:
|
||||||
return blogRSS2 + rss2Footer()
|
return blogRSS2 + rss2Footer()
|
||||||
|
|
@ -590,16 +591,16 @@ def htmlBlogPageRSS3(authorized: bool, session,
|
||||||
continue
|
continue
|
||||||
|
|
||||||
blogRSS3 += \
|
blogRSS3 += \
|
||||||
htmlBlogPostRSS3(authorized, baseDir,
|
_htmlBlogPostRSS3(authorized, baseDir,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
nickname, domain,
|
nickname, domain,
|
||||||
domainFull, item,
|
domainFull, item,
|
||||||
None, True)
|
None, True)
|
||||||
|
|
||||||
return blogRSS3
|
return blogRSS3
|
||||||
|
|
||||||
|
|
||||||
def noOfBlogAccounts(baseDir: str) -> int:
|
def _noOfBlogAccounts(baseDir: str) -> int:
|
||||||
"""Returns the number of blog accounts
|
"""Returns the number of blog accounts
|
||||||
"""
|
"""
|
||||||
ctr = 0
|
ctr = 0
|
||||||
|
|
@ -617,7 +618,7 @@ def noOfBlogAccounts(baseDir: str) -> int:
|
||||||
return ctr
|
return ctr
|
||||||
|
|
||||||
|
|
||||||
def singleBlogAccountNickname(baseDir: str) -> str:
|
def _singleBlogAccountNickname(baseDir: str) -> str:
|
||||||
"""Returns the nickname of a single blog account
|
"""Returns the nickname of a single blog account
|
||||||
"""
|
"""
|
||||||
for subdir, dirs, files in os.walk(baseDir + '/accounts'):
|
for subdir, dirs, files in os.walk(baseDir + '/accounts'):
|
||||||
|
|
@ -647,8 +648,8 @@ def htmlBlogView(authorized: bool,
|
||||||
cssFilename = baseDir + '/epicyon.css'
|
cssFilename = baseDir + '/epicyon.css'
|
||||||
blogStr = htmlHeaderWithExternalStyle(cssFilename)
|
blogStr = htmlHeaderWithExternalStyle(cssFilename)
|
||||||
|
|
||||||
if noOfBlogAccounts(baseDir) <= 1:
|
if _noOfBlogAccounts(baseDir) <= 1:
|
||||||
nickname = singleBlogAccountNickname(baseDir)
|
nickname = _singleBlogAccountNickname(baseDir)
|
||||||
if nickname:
|
if nickname:
|
||||||
return htmlBlogPage(authorized, session,
|
return htmlBlogPage(authorized, session,
|
||||||
baseDir, httpPrefix, translate,
|
baseDir, httpPrefix, translate,
|
||||||
|
|
|
||||||
34
blurhash.py
34
blurhash.py
|
|
@ -39,7 +39,7 @@ alphabet = \
|
||||||
alphabet_values = dict(zip(alphabet, range(len(alphabet))))
|
alphabet_values = dict(zip(alphabet, range(len(alphabet))))
|
||||||
|
|
||||||
|
|
||||||
def base83_encode(value, length):
|
def _base83_encode(value, length):
|
||||||
"""
|
"""
|
||||||
Decodes an integer to a base83 string, as used in blurhash.
|
Decodes an integer to a base83 string, as used in blurhash.
|
||||||
|
|
||||||
|
|
@ -57,7 +57,7 @@ def base83_encode(value, length):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def srgb_to_linear(value):
|
def _srgb_to_linear(value):
|
||||||
"""
|
"""
|
||||||
srgb 0-255 integer to linear 0.0-1.0 floating point conversion.
|
srgb 0-255 integer to linear 0.0-1.0 floating point conversion.
|
||||||
"""
|
"""
|
||||||
|
|
@ -67,14 +67,14 @@ def srgb_to_linear(value):
|
||||||
return math.pow((value + 0.055) / 1.055, 2.4)
|
return math.pow((value + 0.055) / 1.055, 2.4)
|
||||||
|
|
||||||
|
|
||||||
def sign_pow(value, exp):
|
def _sign_pow(value, exp):
|
||||||
"""
|
"""
|
||||||
Sign-preserving exponentiation.
|
Sign-preserving exponentiation.
|
||||||
"""
|
"""
|
||||||
return math.copysign(math.pow(abs(value), exp), value)
|
return math.copysign(math.pow(abs(value), exp), value)
|
||||||
|
|
||||||
|
|
||||||
def linear_to_srgb(value):
|
def _linear_to_srgb(value):
|
||||||
"""
|
"""
|
||||||
linear 0.0-1.0 floating point to srgb 0-255 integer conversion.
|
linear 0.0-1.0 floating point to srgb 0-255 integer conversion.
|
||||||
"""
|
"""
|
||||||
|
|
@ -113,9 +113,9 @@ def blurhash_encode(image, components_x=4, components_y=4, linear=False):
|
||||||
image_linear_line = []
|
image_linear_line = []
|
||||||
for x in range(int(width)):
|
for x in range(int(width)):
|
||||||
image_linear_line.append([
|
image_linear_line.append([
|
||||||
srgb_to_linear(image[y][x][0]),
|
_srgb_to_linear(image[y][x][0]),
|
||||||
srgb_to_linear(image[y][x][1]),
|
_srgb_to_linear(image[y][x][1]),
|
||||||
srgb_to_linear(image[y][x][2])
|
_srgb_to_linear(image[y][x][2])
|
||||||
])
|
])
|
||||||
image_linear.append(image_linear_line)
|
image_linear.append(image_linear_line)
|
||||||
else:
|
else:
|
||||||
|
|
@ -149,9 +149,9 @@ def blurhash_encode(image, components_x=4, components_y=4, linear=False):
|
||||||
abs(component[1]), abs(component[2]))
|
abs(component[1]), abs(component[2]))
|
||||||
|
|
||||||
# Encode components
|
# Encode components
|
||||||
dc_value = (linear_to_srgb(components[0][0]) << 16) + \
|
dc_value = (_linear_to_srgb(components[0][0]) << 16) + \
|
||||||
(linear_to_srgb(components[0][1]) << 8) + \
|
(_linear_to_srgb(components[0][1]) << 8) + \
|
||||||
linear_to_srgb(components[0][2])
|
_linear_to_srgb(components[0][2])
|
||||||
|
|
||||||
quant_max_ac_component = int(max(0, min(82,
|
quant_max_ac_component = int(max(0, min(82,
|
||||||
math.floor(max_ac_component *
|
math.floor(max_ac_component *
|
||||||
|
|
@ -163,9 +163,9 @@ def blurhash_encode(image, components_x=4, components_y=4, linear=False):
|
||||||
r2 = r / ac_component_norm_factor
|
r2 = r / ac_component_norm_factor
|
||||||
g2 = g / ac_component_norm_factor
|
g2 = g / ac_component_norm_factor
|
||||||
b2 = b / ac_component_norm_factor
|
b2 = b / ac_component_norm_factor
|
||||||
r3 = math.floor(sign_pow(r2, 0.5) * 9.0 + 9.5)
|
r3 = math.floor(_sign_pow(r2, 0.5) * 9.0 + 9.5)
|
||||||
g3 = math.floor(sign_pow(g2, 0.5) * 9.0 + 9.5)
|
g3 = math.floor(_sign_pow(g2, 0.5) * 9.0 + 9.5)
|
||||||
b3 = math.floor(sign_pow(b2, 0.5) * 9.0 + 9.5)
|
b3 = math.floor(_sign_pow(b2, 0.5) * 9.0 + 9.5)
|
||||||
ac_values.append(
|
ac_values.append(
|
||||||
int(max(0.0, min(18.0, r3))) * 19 * 19 +
|
int(max(0.0, min(18.0, r3))) * 19 * 19 +
|
||||||
int(max(0.0, min(18.0, g3))) * 19 +
|
int(max(0.0, min(18.0, g3))) * 19 +
|
||||||
|
|
@ -174,10 +174,10 @@ def blurhash_encode(image, components_x=4, components_y=4, linear=False):
|
||||||
|
|
||||||
# Build final blurhash
|
# Build final blurhash
|
||||||
blurhash = ""
|
blurhash = ""
|
||||||
blurhash += base83_encode((components_x - 1) + (components_y - 1) * 9, 1)
|
blurhash += _base83_encode((components_x - 1) + (components_y - 1) * 9, 1)
|
||||||
blurhash += base83_encode(quant_max_ac_component, 1)
|
blurhash += _base83_encode(quant_max_ac_component, 1)
|
||||||
blurhash += base83_encode(dc_value, 4)
|
blurhash += _base83_encode(dc_value, 4)
|
||||||
for ac_value in ac_values:
|
for ac_value in ac_values:
|
||||||
blurhash += base83_encode(ac_value, 2)
|
blurhash += _base83_encode(ac_value, 2)
|
||||||
|
|
||||||
return blurhash
|
return blurhash
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ def undoBookmarksCollectionEntry(recentPostsCache: {},
|
||||||
def bookmarkedByPerson(postJsonObject: {}, nickname: str, domain: str) -> bool:
|
def bookmarkedByPerson(postJsonObject: {}, nickname: str, domain: str) -> bool:
|
||||||
"""Returns True if the given post is bookmarked by the given person
|
"""Returns True if the given post is bookmarked by the given person
|
||||||
"""
|
"""
|
||||||
if noOfBookmarks(postJsonObject) == 0:
|
if _noOfBookmarks(postJsonObject) == 0:
|
||||||
return False
|
return False
|
||||||
actorMatch = domain + '/users/' + nickname
|
actorMatch = domain + '/users/' + nickname
|
||||||
for item in postJsonObject['object']['bookmarks']['items']:
|
for item in postJsonObject['object']['bookmarks']['items']:
|
||||||
|
|
@ -116,7 +116,7 @@ def bookmarkedByPerson(postJsonObject: {}, nickname: str, domain: str) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def noOfBookmarks(postJsonObject: {}) -> int:
|
def _noOfBookmarks(postJsonObject: {}) -> int:
|
||||||
"""Returns the number of bookmarks ona given post
|
"""Returns the number of bookmarks ona given post
|
||||||
"""
|
"""
|
||||||
if not postJsonObject.get('object'):
|
if not postJsonObject.get('object'):
|
||||||
|
|
|
||||||
62
content.py
62
content.py
|
|
@ -33,7 +33,7 @@ def removeHtmlTag(htmlStr: str, tag: str) -> str:
|
||||||
return htmlStr
|
return htmlStr
|
||||||
|
|
||||||
|
|
||||||
def removeQuotesWithinQuotes(content: str) -> str:
|
def _removeQuotesWithinQuotes(content: str) -> str:
|
||||||
"""Removes any blockquote inside blockquote
|
"""Removes any blockquote inside blockquote
|
||||||
"""
|
"""
|
||||||
if '<blockquote>' not in content:
|
if '<blockquote>' not in content:
|
||||||
|
|
@ -96,7 +96,7 @@ def htmlReplaceEmailQuote(content: str) -> str:
|
||||||
else:
|
else:
|
||||||
lineStr = lineStr.replace('>', '<br>')
|
lineStr = lineStr.replace('>', '<br>')
|
||||||
newContent += '<p>' + lineStr + '</blockquote></p>'
|
newContent += '<p>' + lineStr + '</blockquote></p>'
|
||||||
return removeQuotesWithinQuotes(newContent)
|
return _removeQuotesWithinQuotes(newContent)
|
||||||
|
|
||||||
|
|
||||||
def htmlReplaceQuoteMarks(content: str) -> str:
|
def htmlReplaceQuoteMarks(content: str) -> str:
|
||||||
|
|
@ -314,7 +314,7 @@ def replaceEmojiFromTags(content: str, tag: [], messageType: str) -> str:
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
def addMusicTag(content: str, tag: str) -> str:
|
def _addMusicTag(content: str, tag: str) -> str:
|
||||||
"""If a music link is found then ensure that the post is
|
"""If a music link is found then ensure that the post is
|
||||||
tagged appropriately
|
tagged appropriately
|
||||||
"""
|
"""
|
||||||
|
|
@ -416,8 +416,8 @@ def validHashTag(hashtag: str) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def addHashTags(wordStr: str, httpPrefix: str, domain: str,
|
def _addHashTags(wordStr: str, httpPrefix: str, domain: str,
|
||||||
replaceHashTags: {}, postHashtags: {}) -> bool:
|
replaceHashTags: {}, postHashtags: {}) -> bool:
|
||||||
"""Detects hashtags and adds them to the replacements dict
|
"""Detects hashtags and adds them to the replacements dict
|
||||||
Also updates the hashtags list to be added to the post
|
Also updates the hashtags list to be added to the post
|
||||||
"""
|
"""
|
||||||
|
|
@ -438,10 +438,10 @@ def addHashTags(wordStr: str, httpPrefix: str, domain: str,
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def addEmoji(baseDir: str, wordStr: str,
|
def _addEmoji(baseDir: str, wordStr: str,
|
||||||
httpPrefix: str, domain: str,
|
httpPrefix: str, domain: str,
|
||||||
replaceEmoji: {}, postTags: {},
|
replaceEmoji: {}, postTags: {},
|
||||||
emojiDict: {}) -> bool:
|
emojiDict: {}) -> bool:
|
||||||
"""Detects Emoji and adds them to the replacements dict
|
"""Detects Emoji and adds them to the replacements dict
|
||||||
Also updates the tags list to be added to the post
|
Also updates the tags list to be added to the post
|
||||||
"""
|
"""
|
||||||
|
|
@ -489,8 +489,8 @@ def tagExists(tagType: str, tagName: str, tags: {}) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def addMention(wordStr: str, httpPrefix: str, following: str,
|
def _addMention(wordStr: str, httpPrefix: str, following: str,
|
||||||
replaceMentions: {}, recipients: [], tags: {}) -> bool:
|
replaceMentions: {}, recipients: [], tags: {}) -> bool:
|
||||||
"""Detects mentions and adds them to the replacements dict and
|
"""Detects mentions and adds them to the replacements dict and
|
||||||
recipients list
|
recipients list
|
||||||
"""
|
"""
|
||||||
|
|
@ -672,7 +672,7 @@ def removeLongWords(content: str, maxWordLength: int,
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
def loadAutoTags(baseDir: str, nickname: str, domain: str) -> []:
|
def _loadAutoTags(baseDir: str, nickname: str, domain: str) -> []:
|
||||||
"""Loads automatic tags file and returns a list containing
|
"""Loads automatic tags file and returns a list containing
|
||||||
the lines of the file
|
the lines of the file
|
||||||
"""
|
"""
|
||||||
|
|
@ -685,9 +685,9 @@ def loadAutoTags(baseDir: str, nickname: str, domain: str) -> []:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def autoTag(baseDir: str, nickname: str, domain: str,
|
def _autoTag(baseDir: str, nickname: str, domain: str,
|
||||||
wordStr: str, autoTagList: [],
|
wordStr: str, autoTagList: [],
|
||||||
appendTags: []):
|
appendTags: []):
|
||||||
"""Generates a list of tags to be automatically appended to the content
|
"""Generates a list of tags to be automatically appended to the content
|
||||||
"""
|
"""
|
||||||
for tagRule in autoTagList:
|
for tagRule in autoTagList:
|
||||||
|
|
@ -719,7 +719,7 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
|
||||||
maxWordLength = 40
|
maxWordLength = 40
|
||||||
content = content.replace('\r', '')
|
content = content.replace('\r', '')
|
||||||
content = content.replace('\n', ' --linebreak-- ')
|
content = content.replace('\n', ' --linebreak-- ')
|
||||||
content = addMusicTag(content, 'nowplaying')
|
content = _addMusicTag(content, 'nowplaying')
|
||||||
contentSimplified = \
|
contentSimplified = \
|
||||||
content.replace(',', ' ').replace(';', ' ').replace('- ', ' ')
|
content.replace(',', ' ').replace(';', ' ').replace('- ', ' ')
|
||||||
contentSimplified = contentSimplified.replace('. ', ' ').strip()
|
contentSimplified = contentSimplified.replace('. ', ' ').strip()
|
||||||
|
|
@ -760,7 +760,7 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
|
||||||
# extract mentions and tags from words
|
# extract mentions and tags from words
|
||||||
longWordsList = []
|
longWordsList = []
|
||||||
prevWordStr = ''
|
prevWordStr = ''
|
||||||
autoTagsList = loadAutoTags(baseDir, nickname, domain)
|
autoTagsList = _loadAutoTags(baseDir, nickname, domain)
|
||||||
appendTags = []
|
appendTags = []
|
||||||
for wordStr in words:
|
for wordStr in words:
|
||||||
wordLen = len(wordStr)
|
wordLen = len(wordStr)
|
||||||
|
|
@ -769,13 +769,13 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
|
||||||
longWordsList.append(wordStr)
|
longWordsList.append(wordStr)
|
||||||
firstChar = wordStr[0]
|
firstChar = wordStr[0]
|
||||||
if firstChar == '@':
|
if firstChar == '@':
|
||||||
if addMention(wordStr, httpPrefix, following,
|
if _addMention(wordStr, httpPrefix, following,
|
||||||
replaceMentions, recipients, hashtags):
|
replaceMentions, recipients, hashtags):
|
||||||
prevWordStr = ''
|
prevWordStr = ''
|
||||||
continue
|
continue
|
||||||
elif firstChar == '#':
|
elif firstChar == '#':
|
||||||
if addHashTags(wordStr, httpPrefix, originalDomain,
|
if _addHashTags(wordStr, httpPrefix, originalDomain,
|
||||||
replaceHashTags, hashtags):
|
replaceHashTags, hashtags):
|
||||||
prevWordStr = ''
|
prevWordStr = ''
|
||||||
continue
|
continue
|
||||||
elif ':' in wordStr:
|
elif ':' in wordStr:
|
||||||
|
|
@ -791,18 +791,18 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
|
||||||
emojiDict = loadJson(baseDir + '/emoji/emoji.json')
|
emojiDict = loadJson(baseDir + '/emoji/emoji.json')
|
||||||
|
|
||||||
# print('TAG: looking up emoji for :'+wordStr2+':')
|
# print('TAG: looking up emoji for :'+wordStr2+':')
|
||||||
addEmoji(baseDir, ':' + wordStr2 + ':', httpPrefix,
|
_addEmoji(baseDir, ':' + wordStr2 + ':', httpPrefix,
|
||||||
originalDomain, replaceEmoji, hashtags,
|
originalDomain, replaceEmoji, hashtags,
|
||||||
emojiDict)
|
emojiDict)
|
||||||
else:
|
else:
|
||||||
if autoTag(baseDir, nickname, domain, wordStr,
|
if _autoTag(baseDir, nickname, domain, wordStr,
|
||||||
autoTagsList, appendTags):
|
autoTagsList, appendTags):
|
||||||
prevWordStr = ''
|
prevWordStr = ''
|
||||||
continue
|
continue
|
||||||
if prevWordStr:
|
if prevWordStr:
|
||||||
if autoTag(baseDir, nickname, domain,
|
if _autoTag(baseDir, nickname, domain,
|
||||||
prevWordStr + ' ' + wordStr,
|
prevWordStr + ' ' + wordStr,
|
||||||
autoTagsList, appendTags):
|
autoTagsList, appendTags):
|
||||||
prevWordStr = ''
|
prevWordStr = ''
|
||||||
continue
|
continue
|
||||||
prevWordStr = wordStr
|
prevWordStr = wordStr
|
||||||
|
|
@ -810,8 +810,8 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
|
||||||
# add any auto generated tags
|
# add any auto generated tags
|
||||||
for appended in appendTags:
|
for appended in appendTags:
|
||||||
content = content + ' ' + appended
|
content = content + ' ' + appended
|
||||||
addHashTags(appended, httpPrefix, originalDomain,
|
_addHashTags(appended, httpPrefix, originalDomain,
|
||||||
replaceHashTags, hashtags)
|
replaceHashTags, hashtags)
|
||||||
|
|
||||||
# replace words with their html versions
|
# replace words with their html versions
|
||||||
for wordStr, replaceStr in replaceMentions.items():
|
for wordStr, replaceStr in replaceMentions.items():
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ __email__ = "bob@freedombone.net"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
|
|
||||||
|
|
||||||
def getDonationTypes() -> str:
|
def _getDonationTypes() -> str:
|
||||||
return ('patreon', 'paypal', 'gofundme', 'liberapay',
|
return ('patreon', 'paypal', 'gofundme', 'liberapay',
|
||||||
'kickstarter', 'indiegogo', 'crowdsupply',
|
'kickstarter', 'indiegogo', 'crowdsupply',
|
||||||
'subscribestar')
|
'subscribestar')
|
||||||
|
|
@ -18,7 +18,7 @@ def getDonationUrl(actorJson: {}) -> str:
|
||||||
"""
|
"""
|
||||||
if not actorJson.get('attachment'):
|
if not actorJson.get('attachment'):
|
||||||
return ''
|
return ''
|
||||||
donationType = getDonationTypes()
|
donationType = _getDonationTypes()
|
||||||
for propertyValue in actorJson['attachment']:
|
for propertyValue in actorJson['attachment']:
|
||||||
if not propertyValue.get('name'):
|
if not propertyValue.get('name'):
|
||||||
continue
|
continue
|
||||||
|
|
@ -54,7 +54,7 @@ def setDonationUrl(actorJson: {}, donateUrl: str) -> None:
|
||||||
if not actorJson.get('attachment'):
|
if not actorJson.get('attachment'):
|
||||||
actorJson['attachment'] = []
|
actorJson['attachment'] = []
|
||||||
|
|
||||||
donationType = getDonationTypes()
|
donationType = _getDonationTypes()
|
||||||
donateName = None
|
donateName = None
|
||||||
for paymentService in donationType:
|
for paymentService in donationType:
|
||||||
if paymentService in donateUrl:
|
if paymentService in donateUrl:
|
||||||
|
|
|
||||||
10
filters.py
10
filters.py
|
|
@ -79,7 +79,7 @@ def removeGlobalFilter(baseDir: str, words: str) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def isTwitterPost(content: str) -> bool:
|
def _isTwitterPost(content: str) -> bool:
|
||||||
"""Returns true if the given post content is a retweet or twitter crosspost
|
"""Returns true if the given post content is a retweet or twitter crosspost
|
||||||
"""
|
"""
|
||||||
if '/twitter.' in content or '@twitter.' in content:
|
if '/twitter.' in content or '@twitter.' in content:
|
||||||
|
|
@ -89,7 +89,7 @@ def isTwitterPost(content: str) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def isFilteredBase(filename: str, content: str) -> bool:
|
def _isFilteredBase(filename: str, content: str) -> bool:
|
||||||
"""Uses the given file containing filtered words to check
|
"""Uses the given file containing filtered words to check
|
||||||
the given content
|
the given content
|
||||||
"""
|
"""
|
||||||
|
|
@ -122,7 +122,7 @@ def isFiltered(baseDir: str, nickname: str, domain: str, content: str) -> bool:
|
||||||
words must be present although not necessarily adjacent
|
words must be present although not necessarily adjacent
|
||||||
"""
|
"""
|
||||||
globalFiltersFilename = baseDir + '/accounts/filters.txt'
|
globalFiltersFilename = baseDir + '/accounts/filters.txt'
|
||||||
if isFilteredBase(globalFiltersFilename, content):
|
if _isFilteredBase(globalFiltersFilename, content):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if not nickname or not domain:
|
if not nickname or not domain:
|
||||||
|
|
@ -132,9 +132,9 @@ def isFiltered(baseDir: str, nickname: str, domain: str, content: str) -> bool:
|
||||||
removeTwitter = baseDir + '/accounts/' + \
|
removeTwitter = baseDir + '/accounts/' + \
|
||||||
nickname + '@' + domain + '/.removeTwitter'
|
nickname + '@' + domain + '/.removeTwitter'
|
||||||
if os.path.isfile(removeTwitter):
|
if os.path.isfile(removeTwitter):
|
||||||
if isTwitterPost(content):
|
if _isTwitterPost(content):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
accountFiltersFilename = baseDir + '/accounts/' + \
|
accountFiltersFilename = baseDir + '/accounts/' + \
|
||||||
nickname + '@' + domain + '/filters.txt'
|
nickname + '@' + domain + '/filters.txt'
|
||||||
return isFilteredBase(accountFiltersFilename, content)
|
return _isFilteredBase(accountFiltersFilename, content)
|
||||||
|
|
|
||||||
140
follow.py
140
follow.py
|
|
@ -65,10 +65,10 @@ def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def preApprovedFollower(baseDir: str,
|
def _preApprovedFollower(baseDir: str,
|
||||||
nickname: str, domain: str,
|
nickname: str, domain: str,
|
||||||
approveHandle: str,
|
approveHandle: str,
|
||||||
allowNewsFollowers: bool) -> bool:
|
allowNewsFollowers: bool) -> bool:
|
||||||
"""Is the given handle an already manually approved follower?
|
"""Is the given handle an already manually approved follower?
|
||||||
"""
|
"""
|
||||||
# optionally allow the news account to be followed
|
# optionally allow the news account to be followed
|
||||||
|
|
@ -84,10 +84,10 @@ def preApprovedFollower(baseDir: str,
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def removeFromFollowBase(baseDir: str,
|
def _removeFromFollowBase(baseDir: str,
|
||||||
nickname: str, domain: str,
|
nickname: str, domain: str,
|
||||||
acceptOrDenyHandle: str, followFile: str,
|
acceptOrDenyHandle: str, followFile: str,
|
||||||
debug: bool) -> None:
|
debug: bool) -> None:
|
||||||
"""Removes a handle from follow requests or rejects file
|
"""Removes a handle from follow requests or rejects file
|
||||||
"""
|
"""
|
||||||
handle = nickname + '@' + domain
|
handle = nickname + '@' + domain
|
||||||
|
|
@ -114,17 +114,17 @@ def removeFromFollowRequests(baseDir: str,
|
||||||
denyHandle: str, debug: bool) -> None:
|
denyHandle: str, debug: bool) -> None:
|
||||||
"""Removes a handle from follow requests
|
"""Removes a handle from follow requests
|
||||||
"""
|
"""
|
||||||
removeFromFollowBase(baseDir, nickname, domain,
|
_removeFromFollowBase(baseDir, nickname, domain,
|
||||||
denyHandle, 'followrequests', debug)
|
denyHandle, 'followrequests', debug)
|
||||||
|
|
||||||
|
|
||||||
def removeFromFollowRejects(baseDir: str,
|
def _removeFromFollowRejects(baseDir: str,
|
||||||
nickname: str, domain: str,
|
nickname: str, domain: str,
|
||||||
acceptHandle: str, debug: bool) -> None:
|
acceptHandle: str, debug: bool) -> None:
|
||||||
"""Removes a handle from follow rejects
|
"""Removes a handle from follow rejects
|
||||||
"""
|
"""
|
||||||
removeFromFollowBase(baseDir, nickname, domain,
|
_removeFromFollowBase(baseDir, nickname, domain,
|
||||||
acceptHandle, 'followrejects', debug)
|
acceptHandle, 'followrejects', debug)
|
||||||
|
|
||||||
|
|
||||||
def isFollowingActor(baseDir: str,
|
def isFollowingActor(baseDir: str,
|
||||||
|
|
@ -179,8 +179,8 @@ def followerOfPerson(baseDir: str, nickname: str, domain: str,
|
||||||
federationList, debug, 'followers.txt')
|
federationList, debug, 'followers.txt')
|
||||||
|
|
||||||
|
|
||||||
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?
|
||||||
"""
|
"""
|
||||||
if ':' in domain:
|
if ':' in domain:
|
||||||
|
|
@ -291,9 +291,9 @@ def clearFollowers(baseDir: str, nickname: str, domain: str) -> None:
|
||||||
clearFollows(baseDir, nickname, domain, 'followers.txt')
|
clearFollows(baseDir, nickname, domain, 'followers.txt')
|
||||||
|
|
||||||
|
|
||||||
def getNoOfFollows(baseDir: str, nickname: str, domain: str,
|
def _getNoOfFollows(baseDir: str, nickname: str, domain: str,
|
||||||
authenticated: bool,
|
authenticated: bool,
|
||||||
followFile='following.txt') -> int:
|
followFile='following.txt') -> int:
|
||||||
"""Returns the number of follows or followers
|
"""Returns the number of follows or followers
|
||||||
"""
|
"""
|
||||||
# only show number of followers to authenticated
|
# only show number of followers to authenticated
|
||||||
|
|
@ -324,12 +324,12 @@ def getNoOfFollows(baseDir: str, nickname: str, domain: str,
|
||||||
return ctr
|
return ctr
|
||||||
|
|
||||||
|
|
||||||
def getNoOfFollowers(baseDir: str,
|
def _getNoOfFollowers(baseDir: str,
|
||||||
nickname: str, domain: str, authenticated: bool) -> int:
|
nickname: str, domain: str, authenticated: bool) -> int:
|
||||||
"""Returns the number of followers of the given person
|
"""Returns the number of followers of the given person
|
||||||
"""
|
"""
|
||||||
return getNoOfFollows(baseDir, nickname, domain,
|
return _getNoOfFollows(baseDir, nickname, domain,
|
||||||
authenticated, 'followers.txt')
|
authenticated, 'followers.txt')
|
||||||
|
|
||||||
|
|
||||||
def getFollowingFeed(baseDir: str, domain: str, port: int, path: str,
|
def getFollowingFeed(baseDir: str, domain: str, port: int, path: str,
|
||||||
|
|
@ -382,7 +382,7 @@ def getFollowingFeed(baseDir: str, domain: str, port: int, path: str,
|
||||||
httpPrefix + '://' + domain + '/users/' + \
|
httpPrefix + '://' + domain + '/users/' + \
|
||||||
nickname + '/' + followFile
|
nickname + '/' + followFile
|
||||||
totalStr = \
|
totalStr = \
|
||||||
getNoOfFollows(baseDir, nickname, domain, authenticated)
|
_getNoOfFollows(baseDir, nickname, domain, authenticated)
|
||||||
following = {
|
following = {
|
||||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
'first': firstStr,
|
'first': firstStr,
|
||||||
|
|
@ -463,15 +463,15 @@ def getFollowingFeed(baseDir: str, domain: str, port: int, path: str,
|
||||||
return following
|
return following
|
||||||
|
|
||||||
|
|
||||||
def followApprovalRequired(baseDir: str, nicknameToFollow: str,
|
def _followApprovalRequired(baseDir: str, nicknameToFollow: str,
|
||||||
domainToFollow: str, debug: bool,
|
domainToFollow: str, debug: bool,
|
||||||
followRequestHandle: str,
|
followRequestHandle: str,
|
||||||
allowNewsFollowers: bool) -> bool:
|
allowNewsFollowers: bool) -> bool:
|
||||||
""" Returns the policy for follower approvals
|
""" Returns the policy for follower approvals
|
||||||
"""
|
"""
|
||||||
# has this handle already been manually approved?
|
# has this handle already been manually approved?
|
||||||
if preApprovedFollower(baseDir, nicknameToFollow, domainToFollow,
|
if _preApprovedFollower(baseDir, nicknameToFollow, domainToFollow,
|
||||||
followRequestHandle, allowNewsFollowers):
|
followRequestHandle, allowNewsFollowers):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
manuallyApproveFollows = False
|
manuallyApproveFollows = False
|
||||||
|
|
@ -494,10 +494,10 @@ def followApprovalRequired(baseDir: str, nicknameToFollow: str,
|
||||||
return manuallyApproveFollows
|
return manuallyApproveFollows
|
||||||
|
|
||||||
|
|
||||||
def noOfFollowRequests(baseDir: str,
|
def _noOfFollowRequests(baseDir: str,
|
||||||
nicknameToFollow: str, domainToFollow: str,
|
nicknameToFollow: str, domainToFollow: str,
|
||||||
nickname: str, domain: str, fromPort: int,
|
nickname: str, domain: str, fromPort: int,
|
||||||
followType: str) -> int:
|
followType: str) -> int:
|
||||||
"""Returns the current number of follow requests
|
"""Returns the current number of follow requests
|
||||||
"""
|
"""
|
||||||
accountsDir = baseDir + '/accounts/' + \
|
accountsDir = baseDir + '/accounts/' + \
|
||||||
|
|
@ -521,11 +521,11 @@ def noOfFollowRequests(baseDir: str,
|
||||||
return ctr
|
return ctr
|
||||||
|
|
||||||
|
|
||||||
def storeFollowRequest(baseDir: str,
|
def _storeFollowRequest(baseDir: str,
|
||||||
nicknameToFollow: str, domainToFollow: str, port: int,
|
nicknameToFollow: str, domainToFollow: str, port: int,
|
||||||
nickname: str, domain: str, fromPort: int,
|
nickname: str, domain: str, fromPort: int,
|
||||||
followJson: {},
|
followJson: {},
|
||||||
debug: bool, personUrl: str) -> bool:
|
debug: bool, personUrl: str) -> bool:
|
||||||
"""Stores the follow request for later use
|
"""Stores the follow request for later use
|
||||||
"""
|
"""
|
||||||
accountsDir = baseDir + '/accounts/' + \
|
accountsDir = baseDir + '/accounts/' + \
|
||||||
|
|
@ -668,9 +668,9 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
|
||||||
nicknameToFollow)
|
nicknameToFollow)
|
||||||
return True
|
return True
|
||||||
if maxFollowers > 0:
|
if maxFollowers > 0:
|
||||||
if getNoOfFollowers(baseDir,
|
if _getNoOfFollowers(baseDir,
|
||||||
nicknameToFollow, domainToFollow,
|
nicknameToFollow, domainToFollow,
|
||||||
True) > maxFollowers:
|
True) > maxFollowers:
|
||||||
print('WARN: ' + nicknameToFollow +
|
print('WARN: ' + nicknameToFollow +
|
||||||
' has reached their maximum number of followers')
|
' has reached their maximum number of followers')
|
||||||
return True
|
return True
|
||||||
|
|
@ -682,9 +682,9 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
|
||||||
baseDir + '/accounts/' + handleToFollow)
|
baseDir + '/accounts/' + handleToFollow)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if isFollowerOfPerson(baseDir,
|
if _isFollowerOfPerson(baseDir,
|
||||||
nicknameToFollow, domainToFollowFull,
|
nicknameToFollow, domainToFollowFull,
|
||||||
nickname, domainFull):
|
nickname, domainFull):
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: ' + nickname + '@' + domain +
|
print('DEBUG: ' + nickname + '@' + domain +
|
||||||
' is already a follower of ' +
|
' is already a follower of ' +
|
||||||
|
|
@ -693,37 +693,37 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
|
||||||
|
|
||||||
# what is the followers policy?
|
# what is the followers policy?
|
||||||
approveHandle = nickname + '@' + domainFull
|
approveHandle = nickname + '@' + domainFull
|
||||||
if followApprovalRequired(baseDir, nicknameToFollow,
|
if _followApprovalRequired(baseDir, nicknameToFollow,
|
||||||
domainToFollow, debug, approveHandle,
|
domainToFollow, debug, approveHandle,
|
||||||
allowNewsFollowers):
|
allowNewsFollowers):
|
||||||
print('Follow approval is required')
|
print('Follow approval is required')
|
||||||
if domain.endswith('.onion'):
|
if domain.endswith('.onion'):
|
||||||
if noOfFollowRequests(baseDir,
|
if _noOfFollowRequests(baseDir,
|
||||||
nicknameToFollow, domainToFollow,
|
nicknameToFollow, domainToFollow,
|
||||||
nickname, domain, fromPort,
|
nickname, domain, fromPort,
|
||||||
'onion') > 5:
|
'onion') > 5:
|
||||||
print('Too many follow requests from onion addresses')
|
print('Too many follow requests from onion addresses')
|
||||||
return False
|
return False
|
||||||
elif domain.endswith('.i2p'):
|
elif domain.endswith('.i2p'):
|
||||||
if noOfFollowRequests(baseDir,
|
if _noOfFollowRequests(baseDir,
|
||||||
nicknameToFollow, domainToFollow,
|
nicknameToFollow, domainToFollow,
|
||||||
nickname, domain, fromPort,
|
nickname, domain, fromPort,
|
||||||
'i2p') > 5:
|
'i2p') > 5:
|
||||||
print('Too many follow requests from i2p addresses')
|
print('Too many follow requests from i2p addresses')
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
if noOfFollowRequests(baseDir,
|
if _noOfFollowRequests(baseDir,
|
||||||
nicknameToFollow, domainToFollow,
|
nicknameToFollow, domainToFollow,
|
||||||
nickname, domain, fromPort,
|
nickname, domain, fromPort,
|
||||||
'') > 10:
|
'') > 10:
|
||||||
print('Too many follow requests')
|
print('Too many follow requests')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
print('Storing follow request for approval')
|
print('Storing follow request for approval')
|
||||||
return storeFollowRequest(baseDir,
|
return _storeFollowRequest(baseDir,
|
||||||
nicknameToFollow, domainToFollow, port,
|
nicknameToFollow, domainToFollow, port,
|
||||||
nickname, domain, fromPort,
|
nickname, domain, fromPort,
|
||||||
messageJson, debug, messageJson['actor'])
|
messageJson, debug, messageJson['actor'])
|
||||||
else:
|
else:
|
||||||
print('Follow request does not require approval')
|
print('Follow request does not require approval')
|
||||||
# update the followers
|
# update the followers
|
||||||
|
|
@ -920,15 +920,15 @@ def sendFollowRequest(session, baseDir: str,
|
||||||
'object': followedId
|
'object': followedId
|
||||||
}
|
}
|
||||||
|
|
||||||
if followApprovalRequired(baseDir, nickname, domain, debug,
|
if _followApprovalRequired(baseDir, nickname, domain, debug,
|
||||||
followHandle, allowNewsFollowers):
|
followHandle, allowNewsFollowers):
|
||||||
# Remove any follow requests rejected for the account being followed.
|
# Remove any follow requests rejected for the account being followed.
|
||||||
# It's assumed that if you are following someone then you are
|
# It's assumed that if you are following someone then you are
|
||||||
# ok with them following back. If this isn't the case then a rejected
|
# ok with them following back. If this isn't the case then a rejected
|
||||||
# follow request will block them again.
|
# follow request will block them again.
|
||||||
removeFromFollowRejects(baseDir,
|
_removeFromFollowRejects(baseDir,
|
||||||
nickname, domain,
|
nickname, domain,
|
||||||
followHandle, debug)
|
followHandle, debug)
|
||||||
|
|
||||||
sendSignedJson(newFollowJson, session, baseDir, nickname, domain, port,
|
sendSignedJson(newFollowJson, session, baseDir, nickname, domain, port,
|
||||||
followNickname, followDomain, followPort,
|
followNickname, followDomain, followPort,
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,10 @@ def receivingCalendarEvents(baseDir: str, nickname: str, domain: str,
|
||||||
return handle + '\n' in open(calendarFilename).read()
|
return handle + '\n' in open(calendarFilename).read()
|
||||||
|
|
||||||
|
|
||||||
def receiveCalendarEvents(baseDir: str, nickname: str, domain: str,
|
def _receiveCalendarEvents(baseDir: str, nickname: str, domain: str,
|
||||||
followingNickname: str,
|
followingNickname: str,
|
||||||
followingDomain: str,
|
followingDomain: str,
|
||||||
add: bool) -> None:
|
add: bool) -> None:
|
||||||
"""Adds or removes a handle from the following.txt list into a list
|
"""Adds or removes a handle from the following.txt list into a list
|
||||||
indicating whether to receive calendar events from that account
|
indicating whether to receive calendar events from that account
|
||||||
"""
|
"""
|
||||||
|
|
@ -100,12 +100,12 @@ def receiveCalendarEvents(baseDir: str, nickname: str, domain: str,
|
||||||
def addPersonToCalendar(baseDir: str, nickname: str, domain: str,
|
def addPersonToCalendar(baseDir: str, nickname: str, domain: str,
|
||||||
followingNickname: str,
|
followingNickname: str,
|
||||||
followingDomain: str) -> None:
|
followingDomain: str) -> None:
|
||||||
receiveCalendarEvents(baseDir, nickname, domain,
|
_receiveCalendarEvents(baseDir, nickname, domain,
|
||||||
followingNickname, followingDomain, True)
|
followingNickname, followingDomain, True)
|
||||||
|
|
||||||
|
|
||||||
def removePersonFromCalendar(baseDir: str, nickname: str, domain: str,
|
def removePersonFromCalendar(baseDir: str, nickname: str, domain: str,
|
||||||
followingNickname: str,
|
followingNickname: str,
|
||||||
followingDomain: str) -> None:
|
followingDomain: str) -> None:
|
||||||
receiveCalendarEvents(baseDir, nickname, domain,
|
_receiveCalendarEvents(baseDir, nickname, domain,
|
||||||
followingNickname, followingDomain, False)
|
followingNickname, followingDomain, False)
|
||||||
|
|
|
||||||
26
git.py
26
git.py
|
|
@ -10,7 +10,7 @@ import os
|
||||||
import html
|
import html
|
||||||
|
|
||||||
|
|
||||||
def gitFormatContent(content: str) -> str:
|
def _gitFormatContent(content: str) -> str:
|
||||||
""" replace html formatting, so that it's more
|
""" replace html formatting, so that it's more
|
||||||
like the original patch file
|
like the original patch file
|
||||||
"""
|
"""
|
||||||
|
|
@ -22,8 +22,8 @@ def gitFormatContent(content: str) -> str:
|
||||||
return patchStr
|
return patchStr
|
||||||
|
|
||||||
|
|
||||||
def getGitProjectName(baseDir: str, nickname: str, domain: str,
|
def _getGitProjectName(baseDir: str, nickname: str, domain: str,
|
||||||
subject: str) -> str:
|
subject: str) -> str:
|
||||||
"""Returns the project name for a git patch
|
"""Returns the project name for a git patch
|
||||||
The project name should be contained within the subject line
|
The project name should be contained within the subject line
|
||||||
and should match against a list of projects which the account
|
and should match against a list of projects which the account
|
||||||
|
|
@ -71,13 +71,13 @@ def isGitPatch(baseDir: str, nickname: str, domain: str,
|
||||||
return False
|
return False
|
||||||
if checkProjectName:
|
if checkProjectName:
|
||||||
projectName = \
|
projectName = \
|
||||||
getGitProjectName(baseDir, nickname, domain, subject)
|
_getGitProjectName(baseDir, nickname, domain, subject)
|
||||||
if not projectName:
|
if not projectName:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def getGitHash(patchStr: str) -> str:
|
def _getGitHash(patchStr: str) -> str:
|
||||||
"""Returns the commit hash from a given patch
|
"""Returns the commit hash from a given patch
|
||||||
"""
|
"""
|
||||||
patchLines = patchStr.split('\n')
|
patchLines = patchStr.split('\n')
|
||||||
|
|
@ -91,7 +91,7 @@ def getGitHash(patchStr: str) -> str:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def getPatchDescription(patchStr: str) -> str:
|
def _getPatchDescription(patchStr: str) -> str:
|
||||||
"""Returns the description from a given patch
|
"""Returns the description from a given patch
|
||||||
"""
|
"""
|
||||||
patchLines = patchStr.split('\n')
|
patchLines = patchStr.split('\n')
|
||||||
|
|
@ -134,8 +134,8 @@ def convertPostToPatch(baseDir: str, nickname: str, domain: str,
|
||||||
postJsonObject['object']['content'],
|
postJsonObject['object']['content'],
|
||||||
False):
|
False):
|
||||||
return False
|
return False
|
||||||
patchStr = gitFormatContent(postJsonObject['object']['content'])
|
patchStr = _gitFormatContent(postJsonObject['object']['content'])
|
||||||
commitHash = getGitHash(patchStr)
|
commitHash = _getGitHash(patchStr)
|
||||||
if not commitHash:
|
if not commitHash:
|
||||||
return False
|
return False
|
||||||
postJsonObject['object']['type'] = 'Patch'
|
postJsonObject['object']['type'] = 'Patch'
|
||||||
|
|
@ -146,7 +146,7 @@ def convertPostToPatch(baseDir: str, nickname: str, domain: str,
|
||||||
postJsonObject['object']['hash'] = commitHash
|
postJsonObject['object']['hash'] = commitHash
|
||||||
postJsonObject['object']['description'] = {
|
postJsonObject['object']['description'] = {
|
||||||
"mediaType": "text/plain",
|
"mediaType": "text/plain",
|
||||||
"content": getPatchDescription(patchStr)
|
"content": _getPatchDescription(patchStr)
|
||||||
}
|
}
|
||||||
# remove content map
|
# remove content map
|
||||||
if postJsonObject['object'].get('contentMap'):
|
if postJsonObject['object'].get('contentMap'):
|
||||||
|
|
@ -155,7 +155,7 @@ def convertPostToPatch(baseDir: str, nickname: str, domain: str,
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def gitAddFromHandle(patchStr: str, handle: str) -> str:
|
def _gitAddFromHandle(patchStr: str, handle: str) -> str:
|
||||||
"""Adds the activitypub handle of the sender to the patch
|
"""Adds the activitypub handle of the sender to the patch
|
||||||
"""
|
"""
|
||||||
fromStr = 'AP-signed-off-by: '
|
fromStr = 'AP-signed-off-by: '
|
||||||
|
|
@ -181,7 +181,7 @@ def receiveGitPatch(baseDir: str, nickname: str, domain: str,
|
||||||
messageType, subject, content):
|
messageType, subject, content):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
patchStr = gitFormatContent(content)
|
patchStr = _gitFormatContent(content)
|
||||||
|
|
||||||
patchLines = patchStr.split('\n')
|
patchLines = patchStr.split('\n')
|
||||||
patchFilename = None
|
patchFilename = None
|
||||||
|
|
@ -197,7 +197,7 @@ def receiveGitPatch(baseDir: str, nickname: str, domain: str,
|
||||||
patchSubject = patchSubject.replace('[PATCH]', '').strip()
|
patchSubject = patchSubject.replace('[PATCH]', '').strip()
|
||||||
patchSubject = patchSubject.replace(' ', '_')
|
patchSubject = patchSubject.replace(' ', '_')
|
||||||
projectName = \
|
projectName = \
|
||||||
getGitProjectName(baseDir, nickname, domain, subject)
|
_getGitProjectName(baseDir, nickname, domain, subject)
|
||||||
if not os.path.isdir(patchesDir):
|
if not os.path.isdir(patchesDir):
|
||||||
os.mkdir(patchesDir)
|
os.mkdir(patchesDir)
|
||||||
projectDir = patchesDir + '/' + projectName
|
projectDir = patchesDir + '/' + projectName
|
||||||
|
|
@ -209,7 +209,7 @@ def receiveGitPatch(baseDir: str, nickname: str, domain: str,
|
||||||
if not patchFilename:
|
if not patchFilename:
|
||||||
return False
|
return False
|
||||||
patchStr = \
|
patchStr = \
|
||||||
gitAddFromHandle(patchStr, '@' + fromNickname + '@' + fromDomain)
|
_gitAddFromHandle(patchStr, '@' + fromNickname + '@' + fromDomain)
|
||||||
with open(patchFilename, 'w+') as patchFile:
|
with open(patchFilename, 'w+') as patchFile:
|
||||||
patchFile.write(patchStr)
|
patchFile.write(patchStr)
|
||||||
patchNotifyFilename = \
|
patchNotifyFilename = \
|
||||||
|
|
|
||||||
32
happening.py
32
happening.py
|
|
@ -17,7 +17,7 @@ from utils import daysInMonth
|
||||||
from utils import mergeDicts
|
from utils import mergeDicts
|
||||||
|
|
||||||
|
|
||||||
def validUuid(testUuid: str, version=4):
|
def _validUuid(testUuid: str, version=4):
|
||||||
"""Check if uuid_to_test is a valid UUID
|
"""Check if uuid_to_test is a valid UUID
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
|
@ -28,7 +28,7 @@ def validUuid(testUuid: str, version=4):
|
||||||
return str(uuid_obj) == testUuid
|
return str(uuid_obj) == testUuid
|
||||||
|
|
||||||
|
|
||||||
def removeEventFromTimeline(eventId: str, tlEventsFilename: str) -> None:
|
def _removeEventFromTimeline(eventId: str, tlEventsFilename: str) -> None:
|
||||||
"""Removes the given event Id from the timeline
|
"""Removes the given event Id from the timeline
|
||||||
"""
|
"""
|
||||||
if eventId + '\n' not in open(tlEventsFilename).read():
|
if eventId + '\n' not in open(tlEventsFilename).read():
|
||||||
|
|
@ -71,7 +71,7 @@ def saveEventPost(baseDir: str, handle: str, postId: str,
|
||||||
|
|
||||||
if eventJson.get('name') and eventJson.get('actor') and \
|
if eventJson.get('name') and eventJson.get('actor') and \
|
||||||
eventJson.get('uuid') and eventJson.get('content'):
|
eventJson.get('uuid') and eventJson.get('content'):
|
||||||
if not validUuid(eventJson['uuid']):
|
if not _validUuid(eventJson['uuid']):
|
||||||
return False
|
return False
|
||||||
print('Mobilizon type event')
|
print('Mobilizon type event')
|
||||||
# if this is a full description of an event then save it
|
# if this is a full description of an event then save it
|
||||||
|
|
@ -92,7 +92,7 @@ def saveEventPost(baseDir: str, handle: str, postId: str,
|
||||||
tlEventsFilename = baseDir + '/accounts/' + handle + '/events.txt'
|
tlEventsFilename = baseDir + '/accounts/' + handle + '/events.txt'
|
||||||
|
|
||||||
if os.path.isfile(tlEventsFilename):
|
if os.path.isfile(tlEventsFilename):
|
||||||
removeEventFromTimeline(eventId, tlEventsFilename)
|
_removeEventFromTimeline(eventId, tlEventsFilename)
|
||||||
try:
|
try:
|
||||||
with open(tlEventsFilename, 'r+') as tlEventsFile:
|
with open(tlEventsFilename, 'r+') as tlEventsFile:
|
||||||
content = tlEventsFile.read()
|
content = tlEventsFile.read()
|
||||||
|
|
@ -146,7 +146,7 @@ def saveEventPost(baseDir: str, handle: str, postId: str,
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def isHappeningEvent(tag: {}) -> bool:
|
def _isHappeningEvent(tag: {}) -> bool:
|
||||||
"""Is this tag an Event or Place ActivityStreams type?
|
"""Is this tag an Event or Place ActivityStreams type?
|
||||||
"""
|
"""
|
||||||
if not tag.get('type'):
|
if not tag.get('type'):
|
||||||
|
|
@ -156,7 +156,7 @@ def isHappeningEvent(tag: {}) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def isHappeningPost(postJsonObject: {}) -> bool:
|
def _isHappeningPost(postJsonObject: {}) -> bool:
|
||||||
"""Is this a post with tags?
|
"""Is this a post with tags?
|
||||||
"""
|
"""
|
||||||
if not postJsonObject:
|
if not postJsonObject:
|
||||||
|
|
@ -208,13 +208,13 @@ def getTodaysEvents(baseDir: str, nickname: str, domain: str,
|
||||||
continue
|
continue
|
||||||
|
|
||||||
postJsonObject = loadJson(postFilename)
|
postJsonObject = loadJson(postFilename)
|
||||||
if not isHappeningPost(postJsonObject):
|
if not _isHappeningPost(postJsonObject):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
postEvent = []
|
postEvent = []
|
||||||
dayOfMonth = None
|
dayOfMonth = None
|
||||||
for tag in postJsonObject['object']['tag']:
|
for tag in postJsonObject['object']['tag']:
|
||||||
if not isHappeningEvent(tag):
|
if not _isHappeningEvent(tag):
|
||||||
continue
|
continue
|
||||||
# this tag is an event or a place
|
# this tag is an event or a place
|
||||||
if tag['type'] == 'Event':
|
if tag['type'] == 'Event':
|
||||||
|
|
@ -275,11 +275,11 @@ def todaysEventsCheck(baseDir: str, nickname: str, domain: str) -> bool:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
postJsonObject = loadJson(postFilename)
|
postJsonObject = loadJson(postFilename)
|
||||||
if not isHappeningPost(postJsonObject):
|
if not _isHappeningPost(postJsonObject):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for tag in postJsonObject['object']['tag']:
|
for tag in postJsonObject['object']['tag']:
|
||||||
if not isHappeningEvent(tag):
|
if not _isHappeningEvent(tag):
|
||||||
continue
|
continue
|
||||||
# this tag is an event or a place
|
# this tag is an event or a place
|
||||||
if tag['type'] != 'Event':
|
if tag['type'] != 'Event':
|
||||||
|
|
@ -322,11 +322,11 @@ def thisWeeksEventsCheck(baseDir: str, nickname: str, domain: str) -> bool:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
postJsonObject = loadJson(postFilename)
|
postJsonObject = loadJson(postFilename)
|
||||||
if not isHappeningPost(postJsonObject):
|
if not _isHappeningPost(postJsonObject):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for tag in postJsonObject['object']['tag']:
|
for tag in postJsonObject['object']['tag']:
|
||||||
if not isHappeningEvent(tag):
|
if not _isHappeningEvent(tag):
|
||||||
continue
|
continue
|
||||||
# this tag is an event or a place
|
# this tag is an event or a place
|
||||||
if tag['type'] != 'Event':
|
if tag['type'] != 'Event':
|
||||||
|
|
@ -377,14 +377,14 @@ def getThisWeeksEvents(baseDir: str, nickname: str, domain: str) -> {}:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
postJsonObject = loadJson(postFilename)
|
postJsonObject = loadJson(postFilename)
|
||||||
if not isHappeningPost(postJsonObject):
|
if not _isHappeningPost(postJsonObject):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
postEvent = []
|
postEvent = []
|
||||||
dayOfMonth = None
|
dayOfMonth = None
|
||||||
weekDayIndex = None
|
weekDayIndex = None
|
||||||
for tag in postJsonObject['object']['tag']:
|
for tag in postJsonObject['object']['tag']:
|
||||||
if not isHappeningEvent(tag):
|
if not _isHappeningEvent(tag):
|
||||||
continue
|
continue
|
||||||
# this tag is an event or a place
|
# this tag is an event or a place
|
||||||
if tag['type'] == 'Event':
|
if tag['type'] == 'Event':
|
||||||
|
|
@ -462,13 +462,13 @@ def getCalendarEvents(baseDir: str, nickname: str, domain: str,
|
||||||
continue
|
continue
|
||||||
|
|
||||||
postJsonObject = loadJson(postFilename)
|
postJsonObject = loadJson(postFilename)
|
||||||
if not isHappeningPost(postJsonObject):
|
if not _isHappeningPost(postJsonObject):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
postEvent = []
|
postEvent = []
|
||||||
dayOfMonth = None
|
dayOfMonth = None
|
||||||
for tag in postJsonObject['object']['tag']:
|
for tag in postJsonObject['object']['tag']:
|
||||||
if not isHappeningEvent(tag):
|
if not _isHappeningEvent(tag):
|
||||||
continue
|
continue
|
||||||
# this tag is an event or a place
|
# this tag is an event or a place
|
||||||
if tag['type'] == 'Event':
|
if tag['type'] == 'Event':
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ def createSignedHeader(privateKeyPem: str, nickname: str,
|
||||||
return headers
|
return headers
|
||||||
|
|
||||||
|
|
||||||
def verifyRecentSignature(signedDateStr: str) -> bool:
|
def _verifyRecentSignature(signedDateStr: str) -> bool:
|
||||||
"""Checks whether the given time taken from the header is within
|
"""Checks whether the given time taken from the header is within
|
||||||
12 hours of the current time
|
12 hours of the current time
|
||||||
"""
|
"""
|
||||||
|
|
@ -219,7 +219,7 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
|
||||||
else:
|
else:
|
||||||
if headers.get(signedHeader):
|
if headers.get(signedHeader):
|
||||||
if signedHeader == 'date':
|
if signedHeader == 'date':
|
||||||
if not verifyRecentSignature(headers[signedHeader]):
|
if not _verifyRecentSignature(headers[signedHeader]):
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: ' +
|
print('DEBUG: ' +
|
||||||
'verifyPostHeaders date is not recent ' +
|
'verifyPostHeaders date is not recent ' +
|
||||||
|
|
@ -230,7 +230,7 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
|
||||||
else:
|
else:
|
||||||
signedHeaderCap = signedHeader.capitalize()
|
signedHeaderCap = signedHeader.capitalize()
|
||||||
if signedHeaderCap == 'Date':
|
if signedHeaderCap == 'Date':
|
||||||
if not verifyRecentSignature(headers[signedHeaderCap]):
|
if not _verifyRecentSignature(headers[signedHeaderCap]):
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: ' +
|
print('DEBUG: ' +
|
||||||
'verifyPostHeaders date is not recent ' +
|
'verifyPostHeaders date is not recent ' +
|
||||||
|
|
|
||||||
36
jsonldsig.py
36
jsonldsig.py
|
|
@ -28,21 +28,21 @@ import base64
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
|
||||||
def b64safeEncode(payload: {}) -> str:
|
def _b64safeEncode(payload: {}) -> str:
|
||||||
"""
|
"""
|
||||||
b64 url safe encoding with the padding removed.
|
b64 url safe encoding with the padding removed.
|
||||||
"""
|
"""
|
||||||
return base64.urlsafe_b64encode(payload).rstrip(b'=')
|
return base64.urlsafe_b64encode(payload).rstrip(b'=')
|
||||||
|
|
||||||
|
|
||||||
def b64safeDecode(payload: {}) -> str:
|
def _b64safeDecode(payload: {}) -> str:
|
||||||
"""
|
"""
|
||||||
b64 url safe decoding with the padding added.
|
b64 url safe decoding with the padding added.
|
||||||
"""
|
"""
|
||||||
return base64.urlsafe_b64decode(payload + b'=' * (4 - len(payload) % 4))
|
return base64.urlsafe_b64decode(payload + b'=' * (4 - len(payload) % 4))
|
||||||
|
|
||||||
|
|
||||||
def normalizeJson(payload: {}) -> str:
|
def _normalizeJson(payload: {}) -> str:
|
||||||
"""
|
"""
|
||||||
Normalize with URDNA2015
|
Normalize with URDNA2015
|
||||||
"""
|
"""
|
||||||
|
|
@ -50,7 +50,7 @@ def normalizeJson(payload: {}) -> str:
|
||||||
sort_keys=True).encode('utf-8')
|
sort_keys=True).encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
def signRs256(payload: {}, privateKeyPem: str) -> str:
|
def _signRs256(payload: {}, privateKeyPem: str) -> str:
|
||||||
"""
|
"""
|
||||||
Produce a RS256 signature of the payload
|
Produce a RS256 signature of the payload
|
||||||
"""
|
"""
|
||||||
|
|
@ -60,7 +60,7 @@ def signRs256(payload: {}, privateKeyPem: str) -> str:
|
||||||
return signature
|
return signature
|
||||||
|
|
||||||
|
|
||||||
def verifyRs256(payload: {}, signature: str, publicKeyPem: str) -> bool:
|
def _verifyRs256(payload: {}, signature: str, publicKeyPem: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Verifies a RS256 signature
|
Verifies a RS256 signature
|
||||||
"""
|
"""
|
||||||
|
|
@ -69,7 +69,7 @@ def verifyRs256(payload: {}, signature: str, publicKeyPem: str) -> bool:
|
||||||
return verifier.verify(SHA256.new(payload), signature)
|
return verifier.verify(SHA256.new(payload), signature)
|
||||||
|
|
||||||
|
|
||||||
def signJws(payload: {}, privateKeyPem: str) -> str:
|
def _signJws(payload: {}, privateKeyPem: str) -> str:
|
||||||
"""
|
"""
|
||||||
Prepare payload to sign
|
Prepare payload to sign
|
||||||
"""
|
"""
|
||||||
|
|
@ -78,28 +78,28 @@ def signJws(payload: {}, privateKeyPem: str) -> str:
|
||||||
'b64': False,
|
'b64': False,
|
||||||
'crit': ['b64']
|
'crit': ['b64']
|
||||||
}
|
}
|
||||||
normalizedJson = normalizeJson(header)
|
normalizedJson = _normalizeJson(header)
|
||||||
encodedHeader = b64safeEncode(normalizedJson)
|
encodedHeader = _b64safeEncode(normalizedJson)
|
||||||
preparedPayload = b'.'.join([encodedHeader, payload])
|
preparedPayload = b'.'.join([encodedHeader, payload])
|
||||||
|
|
||||||
signature = signRs256(preparedPayload, privateKeyPem)
|
signature = _signRs256(preparedPayload, privateKeyPem)
|
||||||
encodedSignature = b64safeEncode(signature)
|
encodedSignature = _b64safeEncode(signature)
|
||||||
jwsSignature = b'..'.join([encodedHeader, encodedSignature])
|
jwsSignature = b'..'.join([encodedHeader, encodedSignature])
|
||||||
|
|
||||||
return jwsSignature
|
return jwsSignature
|
||||||
|
|
||||||
|
|
||||||
def verifyJws(payload: {}, jwsSignature: str, publicKeyPem: str) -> bool:
|
def _verifyJws(payload: {}, jwsSignature: str, publicKeyPem: str) -> bool:
|
||||||
"""
|
"""
|
||||||
Verifies a signature using the given public key
|
Verifies a signature using the given public key
|
||||||
"""
|
"""
|
||||||
encodedHeader, encodedSignature = jwsSignature.split(b'..')
|
encodedHeader, encodedSignature = jwsSignature.split(b'..')
|
||||||
signature = b64safeDecode(encodedSignature)
|
signature = _b64safeDecode(encodedSignature)
|
||||||
payload = b'.'.join([encodedHeader, payload])
|
payload = b'.'.join([encodedHeader, payload])
|
||||||
return verifyRs256(payload, signature, publicKeyPem)
|
return _verifyRs256(payload, signature, publicKeyPem)
|
||||||
|
|
||||||
|
|
||||||
def jsonldNormalize(jldDocument: str):
|
def _jsonldNormalize(jldDocument: str):
|
||||||
"""
|
"""
|
||||||
Normalize and hash the json-ld document
|
Normalize and hash the json-ld document
|
||||||
"""
|
"""
|
||||||
|
|
@ -117,8 +117,8 @@ def jsonldSign(jldDocument: {}, privateKeyPem: str) -> {}:
|
||||||
Produces a signed JSON-LD document with a Json Web Signature
|
Produces a signed JSON-LD document with a Json Web Signature
|
||||||
"""
|
"""
|
||||||
jldDocument = deepcopy(jldDocument)
|
jldDocument = deepcopy(jldDocument)
|
||||||
normalizedJldHash = jsonldNormalize(jldDocument)
|
normalizedJldHash = _jsonldNormalize(jldDocument)
|
||||||
jwsSignature = signJws(normalizedJldHash, privateKeyPem)
|
jwsSignature = _signJws(normalizedJldHash, privateKeyPem)
|
||||||
|
|
||||||
# construct the signature document and add it to jsonld
|
# construct the signature document and add it to jsonld
|
||||||
signature = {
|
signature = {
|
||||||
|
|
@ -138,9 +138,9 @@ def jsonldVerify(signedJldDocument: {}, publicKeyPem: str) -> bool:
|
||||||
signedJldDocument = deepcopy(signedJldDocument)
|
signedJldDocument = deepcopy(signedJldDocument)
|
||||||
signature = signedJldDocument.pop('signature')
|
signature = signedJldDocument.pop('signature')
|
||||||
jwsSignature = signature['signatureValue'].encode('utf-8')
|
jwsSignature = signature['signatureValue'].encode('utf-8')
|
||||||
normalizedJldHash = jsonldNormalize(signedJldDocument)
|
normalizedJldHash = _jsonldNormalize(signedJldDocument)
|
||||||
|
|
||||||
return verifyJws(normalizedJldHash, jwsSignature, publicKeyPem)
|
return _verifyJws(normalizedJldHash, jwsSignature, publicKeyPem)
|
||||||
|
|
||||||
|
|
||||||
def testSignJsonld(jldDocument: {}, privateKeyPem: str) -> {}:
|
def testSignJsonld(jldDocument: {}, privateKeyPem: str) -> {}:
|
||||||
|
|
|
||||||
28
like.py
28
like.py
|
|
@ -50,15 +50,15 @@ def noOfLikes(postJsonObject: {}) -> int:
|
||||||
return len(postJsonObject['object']['likes']['items'])
|
return len(postJsonObject['object']['likes']['items'])
|
||||||
|
|
||||||
|
|
||||||
def like(recentPostsCache: {},
|
def _like(recentPostsCache: {},
|
||||||
session, baseDir: str, federationList: [],
|
session, baseDir: str, federationList: [],
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
ccList: [], httpPrefix: str,
|
ccList: [], httpPrefix: str,
|
||||||
objectUrl: str, actorLiked: str,
|
objectUrl: str, actorLiked: str,
|
||||||
clientToServer: bool,
|
clientToServer: bool,
|
||||||
sendThreads: [], postLog: [],
|
sendThreads: [], postLog: [],
|
||||||
personCache: {}, cachedWebfingers: {},
|
personCache: {}, cachedWebfingers: {},
|
||||||
debug: bool, projectVersion: str) -> {}:
|
debug: bool, projectVersion: str) -> {}:
|
||||||
"""Creates a like
|
"""Creates a like
|
||||||
actor is the person doing the liking
|
actor is the person doing the liking
|
||||||
'to' might be a specific person (actor) whose post was liked
|
'to' might be a specific person (actor) whose post was liked
|
||||||
|
|
@ -134,11 +134,11 @@ def likePost(recentPostsCache: {},
|
||||||
actorLiked = httpPrefix + '://' + likeDomain + '/users/' + likeNickname
|
actorLiked = httpPrefix + '://' + likeDomain + '/users/' + likeNickname
|
||||||
objectUrl = actorLiked + '/statuses/' + str(likeStatusNumber)
|
objectUrl = actorLiked + '/statuses/' + str(likeStatusNumber)
|
||||||
|
|
||||||
return like(recentPostsCache,
|
return _like(recentPostsCache,
|
||||||
session, baseDir, federationList, nickname, domain, port,
|
session, baseDir, federationList, nickname, domain, port,
|
||||||
ccList, httpPrefix, objectUrl, actorLiked, clientToServer,
|
ccList, httpPrefix, objectUrl, actorLiked, clientToServer,
|
||||||
sendThreads, postLog, personCache, cachedWebfingers,
|
sendThreads, postLog, personCache, cachedWebfingers,
|
||||||
debug, projectVersion)
|
debug, projectVersion)
|
||||||
|
|
||||||
|
|
||||||
def sendLikeViaServer(baseDir: str, session,
|
def sendLikeViaServer(baseDir: str, session,
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ def manualDenyFollowRequest(session, baseDir: str,
|
||||||
print('Follow request from ' + denyHandle + ' was denied.')
|
print('Follow request from ' + denyHandle + ' was denied.')
|
||||||
|
|
||||||
|
|
||||||
def approveFollowerHandle(accountDir: str, approveHandle: str) -> None:
|
def _approveFollowerHandle(accountDir: str, approveHandle: str) -> None:
|
||||||
""" Record manually approved handles so that if they unfollow and then
|
""" Record manually approved handles so that if they unfollow and then
|
||||||
re-follow later then they don't need to be manually approved again
|
re-follow later then they don't need to be manually approved again
|
||||||
"""
|
"""
|
||||||
|
|
@ -203,7 +203,7 @@ def manualApproveFollowRequest(session, baseDir: str,
|
||||||
# in followers.txt
|
# in followers.txt
|
||||||
if approveHandleFull in open(followersFilename).read():
|
if approveHandleFull in open(followersFilename).read():
|
||||||
# mark this handle as approved for following
|
# mark this handle as approved for following
|
||||||
approveFollowerHandle(accountDir, approveHandle)
|
_approveFollowerHandle(accountDir, approveHandle)
|
||||||
# update the follow requests with the handles not yet approved
|
# update the follow requests with the handles not yet approved
|
||||||
os.rename(approveFollowsFilename + '.new', approveFollowsFilename)
|
os.rename(approveFollowsFilename + '.new', approveFollowsFilename)
|
||||||
# remove the .follow file
|
# remove the .follow file
|
||||||
|
|
|
||||||
12
media.py
12
media.py
|
|
@ -56,12 +56,12 @@ def removeMetaData(imageFilename: str, outputFilename: str) -> None:
|
||||||
os.system('/usr/bin/mogrify -strip ' + outputFilename) # nosec
|
os.system('/usr/bin/mogrify -strip ' + outputFilename) # nosec
|
||||||
|
|
||||||
|
|
||||||
def getImageHash(imageFilename: str) -> str:
|
def _getImageHash(imageFilename: str) -> str:
|
||||||
value = numpy.array(Image.open(imageFilename).convert("RGB"))
|
value = numpy.array(Image.open(imageFilename).convert("RGB"))
|
||||||
return blurhash_encode(value)
|
return blurhash_encode(value)
|
||||||
|
|
||||||
|
|
||||||
def isMedia(imageFilename: str) -> bool:
|
def _isMedia(imageFilename: str) -> bool:
|
||||||
permittedMedia = getMediaExtensions()
|
permittedMedia = getMediaExtensions()
|
||||||
for m in permittedMedia:
|
for m in permittedMedia:
|
||||||
if imageFilename.endswith('.' + m):
|
if imageFilename.endswith('.' + m):
|
||||||
|
|
@ -103,7 +103,7 @@ def getAttachmentMediaType(filename: str) -> str:
|
||||||
return mediaType
|
return mediaType
|
||||||
|
|
||||||
|
|
||||||
def updateEtag(mediaFilename: str) -> None:
|
def _updateEtag(mediaFilename: str) -> None:
|
||||||
""" calculate the etag, which is a sha1 of the data
|
""" calculate the etag, which is a sha1 of the data
|
||||||
"""
|
"""
|
||||||
# only create etags for media
|
# only create etags for media
|
||||||
|
|
@ -143,7 +143,7 @@ def attachMedia(baseDir: str, httpPrefix: str, domain: str, port: int,
|
||||||
Blurhash is optional, since low power systems may take a long
|
Blurhash is optional, since low power systems may take a long
|
||||||
time to calculate it
|
time to calculate it
|
||||||
"""
|
"""
|
||||||
if not isMedia(imageFilename):
|
if not _isMedia(imageFilename):
|
||||||
return postJson
|
return postJson
|
||||||
|
|
||||||
fileExtension = None
|
fileExtension = None
|
||||||
|
|
@ -182,7 +182,7 @@ def attachMedia(baseDir: str, httpPrefix: str, domain: str, port: int,
|
||||||
if mediaType.startswith('image/'):
|
if mediaType.startswith('image/'):
|
||||||
attachmentJson['focialPoint'] = [0.0, 0.0]
|
attachmentJson['focialPoint'] = [0.0, 0.0]
|
||||||
if useBlurhash:
|
if useBlurhash:
|
||||||
attachmentJson['blurhash'] = getImageHash(imageFilename)
|
attachmentJson['blurhash'] = _getImageHash(imageFilename)
|
||||||
postJson['attachment'] = [attachmentJson]
|
postJson['attachment'] = [attachmentJson]
|
||||||
|
|
||||||
if baseDir:
|
if baseDir:
|
||||||
|
|
@ -190,7 +190,7 @@ def attachMedia(baseDir: str, httpPrefix: str, domain: str, port: int,
|
||||||
removeMetaData(imageFilename, mediaFilename)
|
removeMetaData(imageFilename, mediaFilename)
|
||||||
else:
|
else:
|
||||||
copyfile(imageFilename, mediaFilename)
|
copyfile(imageFilename, mediaFilename)
|
||||||
updateEtag(mediaFilename)
|
_updateEtag(mediaFilename)
|
||||||
|
|
||||||
return postJson
|
return postJson
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ __status__ = "Production"
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
def migrateFollows(followFilename: str, oldHandle: str,
|
def _migrateFollows(followFilename: str, oldHandle: str,
|
||||||
newHandle: str) -> None:
|
newHandle: str) -> None:
|
||||||
"""Changes a handle within following or followers list
|
"""Changes a handle within following or followers list
|
||||||
"""
|
"""
|
||||||
if not os.path.isfile(followFilename):
|
if not os.path.isfile(followFilename):
|
||||||
|
|
@ -48,7 +48,7 @@ def migrateAccount(baseDir: str, oldHandle: str, newHandle: str) -> None:
|
||||||
if '@' in handle:
|
if '@' in handle:
|
||||||
accountDir = baseDir + '/accounts/' + handle
|
accountDir = baseDir + '/accounts/' + handle
|
||||||
followFilename = accountDir + '/following.txt'
|
followFilename = accountDir + '/following.txt'
|
||||||
migrateFollows(followFilename, oldHandle, newHandle)
|
_migrateFollows(followFilename, oldHandle, newHandle)
|
||||||
followFilename = accountDir + '/followers.txt'
|
followFilename = accountDir + '/followers.txt'
|
||||||
migrateFollows(followFilename, oldHandle, newHandle)
|
_migrateFollows(followFilename, oldHandle, newHandle)
|
||||||
break
|
break
|
||||||
|
|
|
||||||
108
newsdaemon.py
108
newsdaemon.py
|
|
@ -35,7 +35,7 @@ from inbox import storeHashTags
|
||||||
from session import createSession
|
from session import createSession
|
||||||
|
|
||||||
|
|
||||||
def updateFeedsOutboxIndex(baseDir: str, domain: str, postId: str) -> None:
|
def _updateFeedsOutboxIndex(baseDir: str, domain: str, postId: str) -> None:
|
||||||
"""Updates the index used for imported RSS feeds
|
"""Updates the index used for imported RSS feeds
|
||||||
"""
|
"""
|
||||||
basePath = baseDir + '/accounts/news@' + domain
|
basePath = baseDir + '/accounts/news@' + domain
|
||||||
|
|
@ -59,7 +59,7 @@ def updateFeedsOutboxIndex(baseDir: str, domain: str, postId: str) -> None:
|
||||||
feedsFile.close()
|
feedsFile.close()
|
||||||
|
|
||||||
|
|
||||||
def saveArrivedTime(baseDir: str, postFilename: str, arrived: str) -> None:
|
def _saveArrivedTime(baseDir: str, postFilename: str, arrived: str) -> None:
|
||||||
"""Saves the time when an rss post arrived to a file
|
"""Saves the time when an rss post arrived to a file
|
||||||
"""
|
"""
|
||||||
arrivedFile = open(postFilename + '.arrived', 'w+')
|
arrivedFile = open(postFilename + '.arrived', 'w+')
|
||||||
|
|
@ -68,7 +68,7 @@ def saveArrivedTime(baseDir: str, postFilename: str, arrived: str) -> None:
|
||||||
arrivedFile.close()
|
arrivedFile.close()
|
||||||
|
|
||||||
|
|
||||||
def removeControlCharacters(content: str) -> str:
|
def _removeControlCharacters(content: str) -> str:
|
||||||
"""Remove escaped html
|
"""Remove escaped html
|
||||||
"""
|
"""
|
||||||
if '&' in content:
|
if '&' in content:
|
||||||
|
|
@ -227,14 +227,14 @@ def hashtagRuleTree(operators: [],
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
|
|
||||||
def newswireHashtagProcessing(session, baseDir: str, postJsonObject: {},
|
def _newswireHashtagProcessing(session, baseDir: str, postJsonObject: {},
|
||||||
hashtags: [], httpPrefix: str,
|
hashtags: [], httpPrefix: str,
|
||||||
domain: str, port: int,
|
domain: str, port: int,
|
||||||
personCache: {},
|
personCache: {},
|
||||||
cachedWebfingers: {},
|
cachedWebfingers: {},
|
||||||
federationList: [],
|
federationList: [],
|
||||||
sendThreads: [], postLog: [],
|
sendThreads: [], postLog: [],
|
||||||
moderated: bool, url: str) -> bool:
|
moderated: bool, url: str) -> bool:
|
||||||
"""Applies hashtag rules to a news post.
|
"""Applies hashtag rules to a news post.
|
||||||
Returns true if the post should be saved to the news timeline
|
Returns true if the post should be saved to the news timeline
|
||||||
of this instance
|
of this instance
|
||||||
|
|
@ -356,9 +356,9 @@ def newswireHashtagProcessing(session, baseDir: str, postJsonObject: {},
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def createNewsMirror(baseDir: str, domain: str,
|
def _createNewsMirror(baseDir: str, domain: str,
|
||||||
postIdNumber: str, url: str,
|
postIdNumber: str, url: str,
|
||||||
maxMirroredArticles: int) -> bool:
|
maxMirroredArticles: int) -> bool:
|
||||||
"""Creates a local mirror of a news article
|
"""Creates a local mirror of a news article
|
||||||
"""
|
"""
|
||||||
if '|' in url or '>' in url:
|
if '|' in url or '>' in url:
|
||||||
|
|
@ -446,17 +446,17 @@ def createNewsMirror(baseDir: str, domain: str,
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
def _convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
||||||
domain: str, port: int,
|
domain: str, port: int,
|
||||||
newswire: {},
|
newswire: {},
|
||||||
translate: {},
|
translate: {},
|
||||||
recentPostsCache: {}, maxRecentPosts: int,
|
recentPostsCache: {}, maxRecentPosts: int,
|
||||||
session, cachedWebfingers: {},
|
session, cachedWebfingers: {},
|
||||||
personCache: {},
|
personCache: {},
|
||||||
federationList: [],
|
federationList: [],
|
||||||
sendThreads: [], postLog: [],
|
sendThreads: [], postLog: [],
|
||||||
maxMirroredArticles: int,
|
maxMirroredArticles: int,
|
||||||
allowLocalNetworkAccess: bool) -> None:
|
allowLocalNetworkAccess: bool) -> None:
|
||||||
"""Converts rss items in a newswire into posts
|
"""Converts rss items in a newswire into posts
|
||||||
"""
|
"""
|
||||||
if not newswire:
|
if not newswire:
|
||||||
|
|
@ -497,7 +497,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
||||||
newswire[originalDateStr][3] = filename
|
newswire[originalDateStr][3] = filename
|
||||||
continue
|
continue
|
||||||
|
|
||||||
rssTitle = removeControlCharacters(item[0])
|
rssTitle = _removeControlCharacters(item[0])
|
||||||
url = item[1]
|
url = item[1]
|
||||||
if dangerousMarkup(url, allowLocalNetworkAccess) or \
|
if dangerousMarkup(url, allowLocalNetworkAccess) or \
|
||||||
dangerousMarkup(rssTitle, allowLocalNetworkAccess):
|
dangerousMarkup(rssTitle, allowLocalNetworkAccess):
|
||||||
|
|
@ -505,7 +505,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
||||||
rssDescription = ''
|
rssDescription = ''
|
||||||
|
|
||||||
# get the rss description if it exists
|
# get the rss description if it exists
|
||||||
rssDescription = removeControlCharacters(item[4])
|
rssDescription = _removeControlCharacters(item[4])
|
||||||
if rssDescription.startswith('<![CDATA['):
|
if rssDescription.startswith('<![CDATA['):
|
||||||
rssDescription = rssDescription.replace('<![CDATA[', '')
|
rssDescription = rssDescription.replace('<![CDATA[', '')
|
||||||
rssDescription = rssDescription.replace(']]>', '')
|
rssDescription = rssDescription.replace(']]>', '')
|
||||||
|
|
@ -555,8 +555,8 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if mirrored:
|
if mirrored:
|
||||||
if not createNewsMirror(baseDir, domain, statusNumber,
|
if not _createNewsMirror(baseDir, domain, statusNumber,
|
||||||
url, maxMirroredArticles):
|
url, maxMirroredArticles):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
idStr = \
|
idStr = \
|
||||||
|
|
@ -590,12 +590,12 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
||||||
|
|
||||||
moderated = item[5]
|
moderated = item[5]
|
||||||
|
|
||||||
savePost = newswireHashtagProcessing(session, baseDir, blog, hashtags,
|
savePost = _newswireHashtagProcessing(session, baseDir, blog, hashtags,
|
||||||
httpPrefix, domain, port,
|
httpPrefix, domain, port,
|
||||||
personCache, cachedWebfingers,
|
personCache, cachedWebfingers,
|
||||||
federationList,
|
federationList,
|
||||||
sendThreads, postLog,
|
sendThreads, postLog,
|
||||||
moderated, url)
|
moderated, url)
|
||||||
|
|
||||||
# save the post and update the index
|
# save the post and update the index
|
||||||
if savePost:
|
if savePost:
|
||||||
|
|
@ -628,7 +628,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
||||||
blog['object']['content'] = content
|
blog['object']['content'] = content
|
||||||
|
|
||||||
# update the newswire tags if new ones have been found by
|
# update the newswire tags if new ones have been found by
|
||||||
# newswireHashtagProcessing
|
# _newswireHashtagProcessing
|
||||||
for tag in hashtags:
|
for tag in hashtags:
|
||||||
if tag not in newswire[originalDateStr][6]:
|
if tag not in newswire[originalDateStr][6]:
|
||||||
newswire[originalDateStr][6].append(tag)
|
newswire[originalDateStr][6].append(tag)
|
||||||
|
|
@ -637,14 +637,14 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
||||||
|
|
||||||
clearFromPostCaches(baseDir, recentPostsCache, postId)
|
clearFromPostCaches(baseDir, recentPostsCache, postId)
|
||||||
if saveJson(blog, filename):
|
if saveJson(blog, filename):
|
||||||
updateFeedsOutboxIndex(baseDir, domain, postId + '.json')
|
_updateFeedsOutboxIndex(baseDir, domain, postId + '.json')
|
||||||
|
|
||||||
# Save a file containing the time when the post arrived
|
# Save a file containing the time when the post arrived
|
||||||
# this can then later be used to construct the news timeline
|
# this can then later be used to construct the news timeline
|
||||||
# excluding items during the voting period
|
# excluding items during the voting period
|
||||||
if moderated:
|
if moderated:
|
||||||
saveArrivedTime(baseDir, filename,
|
_saveArrivedTime(baseDir, filename,
|
||||||
blog['object']['arrived'])
|
blog['object']['arrived'])
|
||||||
else:
|
else:
|
||||||
if os.path.isfile(filename + '.arrived'):
|
if os.path.isfile(filename + '.arrived'):
|
||||||
os.remove(filename + '.arrived')
|
os.remove(filename + '.arrived')
|
||||||
|
|
@ -658,7 +658,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
|
||||||
newswire[originalDateStr][3] = filename
|
newswire[originalDateStr][3] = filename
|
||||||
|
|
||||||
|
|
||||||
def mergeWithPreviousNewswire(oldNewswire: {}, newNewswire: {}) -> None:
|
def _mergeWithPreviousNewswire(oldNewswire: {}, newNewswire: {}) -> None:
|
||||||
"""Preserve any votes or generated activitypub post filename
|
"""Preserve any votes or generated activitypub post filename
|
||||||
as rss feeds are updated
|
as rss feeds are updated
|
||||||
"""
|
"""
|
||||||
|
|
@ -707,26 +707,26 @@ def runNewswireDaemon(baseDir: str, httpd,
|
||||||
if os.path.isfile(newswireStateFilename):
|
if os.path.isfile(newswireStateFilename):
|
||||||
httpd.newswire = loadJson(newswireStateFilename)
|
httpd.newswire = loadJson(newswireStateFilename)
|
||||||
|
|
||||||
mergeWithPreviousNewswire(httpd.newswire, newNewswire)
|
_mergeWithPreviousNewswire(httpd.newswire, newNewswire)
|
||||||
|
|
||||||
httpd.newswire = newNewswire
|
httpd.newswire = newNewswire
|
||||||
if newNewswire:
|
if newNewswire:
|
||||||
saveJson(httpd.newswire, newswireStateFilename)
|
saveJson(httpd.newswire, newswireStateFilename)
|
||||||
print('Newswire updated')
|
print('Newswire updated')
|
||||||
|
|
||||||
convertRSStoActivityPub(baseDir,
|
_convertRSStoActivityPub(baseDir,
|
||||||
httpPrefix, domain, port,
|
httpPrefix, domain, port,
|
||||||
newNewswire, translate,
|
newNewswire, translate,
|
||||||
httpd.recentPostsCache,
|
httpd.recentPostsCache,
|
||||||
httpd.maxRecentPosts,
|
httpd.maxRecentPosts,
|
||||||
httpd.session,
|
httpd.session,
|
||||||
httpd.cachedWebfingers,
|
httpd.cachedWebfingers,
|
||||||
httpd.personCache,
|
httpd.personCache,
|
||||||
httpd.federationList,
|
httpd.federationList,
|
||||||
httpd.sendThreads,
|
httpd.sendThreads,
|
||||||
httpd.postLog,
|
httpd.postLog,
|
||||||
httpd.maxMirroredArticles,
|
httpd.maxMirroredArticles,
|
||||||
httpd.allowLocalNetworkAccess)
|
httpd.allowLocalNetworkAccess)
|
||||||
print('Newswire feed converted to ActivityPub')
|
print('Newswire feed converted to ActivityPub')
|
||||||
|
|
||||||
if httpd.maxNewsPosts > 0:
|
if httpd.maxNewsPosts > 0:
|
||||||
|
|
|
||||||
248
newswire.py
248
newswire.py
|
|
@ -29,7 +29,7 @@ from blocking import isBlockedHashtag
|
||||||
from filters import isFiltered
|
from filters import isFiltered
|
||||||
|
|
||||||
|
|
||||||
def removeCDATA(text: str) -> str:
|
def _removeCDATA(text: str) -> str:
|
||||||
"""Removes any CDATA from the given text
|
"""Removes any CDATA from the given text
|
||||||
"""
|
"""
|
||||||
if 'CDATA[' in text:
|
if 'CDATA[' in text:
|
||||||
|
|
@ -95,13 +95,13 @@ def getNewswireTags(text: str, maxTags: int) -> []:
|
||||||
return tags
|
return tags
|
||||||
|
|
||||||
|
|
||||||
def addNewswireDictEntry(baseDir: str, domain: str,
|
def _addNewswireDictEntry(baseDir: str, domain: str,
|
||||||
newswire: {}, dateStr: str,
|
newswire: {}, dateStr: str,
|
||||||
title: str, link: str,
|
title: str, link: str,
|
||||||
votesStatus: str, postFilename: str,
|
votesStatus: str, postFilename: str,
|
||||||
description: str, moderated: bool,
|
description: str, moderated: bool,
|
||||||
mirrored: bool,
|
mirrored: bool,
|
||||||
tags=[], maxTags=32) -> None:
|
tags=[], maxTags=32) -> None:
|
||||||
"""Update the newswire dictionary
|
"""Update the newswire dictionary
|
||||||
"""
|
"""
|
||||||
# remove any markup
|
# remove any markup
|
||||||
|
|
@ -143,7 +143,7 @@ def addNewswireDictEntry(baseDir: str, domain: str,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def validFeedDate(pubDate: str) -> bool:
|
def _validFeedDate(pubDate: str) -> bool:
|
||||||
# convert from YY-MM-DD HH:MM:SS+00:00 to
|
# convert from YY-MM-DD HH:MM:SS+00:00 to
|
||||||
# YY-MM-DDTHH:MM:SSZ
|
# YY-MM-DDTHH:MM:SSZ
|
||||||
postDate = pubDate.replace(' ', 'T').replace('+00:00', 'Z')
|
postDate = pubDate.replace(' ', 'T').replace('+00:00', 'Z')
|
||||||
|
|
@ -219,12 +219,12 @@ def loadHashtagCategories(baseDir: str, language: str) -> None:
|
||||||
|
|
||||||
with open(hashtagCategoriesFilename, 'r') as fp:
|
with open(hashtagCategoriesFilename, 'r') as fp:
|
||||||
xmlStr = fp.read()
|
xmlStr = fp.read()
|
||||||
xml2StrToHashtagCategories(baseDir, xmlStr, 1024, True)
|
_xml2StrToHashtagCategories(baseDir, xmlStr, 1024, True)
|
||||||
|
|
||||||
|
|
||||||
def xml2StrToHashtagCategories(baseDir: str, xmlStr: str,
|
def _xml2StrToHashtagCategories(baseDir: str, xmlStr: str,
|
||||||
maxCategoriesFeedItemSizeKb: int,
|
maxCategoriesFeedItemSizeKb: int,
|
||||||
force=False) -> None:
|
force=False) -> None:
|
||||||
"""Updates hashtag categories based upon an rss feed
|
"""Updates hashtag categories based upon an rss feed
|
||||||
"""
|
"""
|
||||||
rssItems = xmlStr.split('<item>')
|
rssItems = xmlStr.split('<item>')
|
||||||
|
|
@ -261,11 +261,11 @@ def xml2StrToHashtagCategories(baseDir: str, xmlStr: str,
|
||||||
setHashtagCategory(baseDir, hashtag, categoryStr, force)
|
setHashtagCategory(baseDir, hashtag, categoryStr, force)
|
||||||
|
|
||||||
|
|
||||||
def xml2StrToDict(baseDir: str, domain: str, xmlStr: str,
|
def _xml2StrToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
moderated: bool, mirrored: bool,
|
moderated: bool, mirrored: bool,
|
||||||
maxPostsPerSource: int,
|
maxPostsPerSource: int,
|
||||||
maxFeedItemSizeKb: int,
|
maxFeedItemSizeKb: int,
|
||||||
maxCategoriesFeedItemSizeKb: int) -> {}:
|
maxCategoriesFeedItemSizeKb: int) -> {}:
|
||||||
"""Converts an xml RSS 2.0 string to a dictionary
|
"""Converts an xml RSS 2.0 string to a dictionary
|
||||||
"""
|
"""
|
||||||
if '<item>' not in xmlStr:
|
if '<item>' not in xmlStr:
|
||||||
|
|
@ -274,8 +274,8 @@ def xml2StrToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
|
|
||||||
# is this an rss feed containing hashtag categories?
|
# is this an rss feed containing hashtag categories?
|
||||||
if '<title>#categories</title>' in xmlStr:
|
if '<title>#categories</title>' in xmlStr:
|
||||||
xml2StrToHashtagCategories(baseDir, xmlStr,
|
_xml2StrToHashtagCategories(baseDir, xmlStr,
|
||||||
maxCategoriesFeedItemSizeKb)
|
maxCategoriesFeedItemSizeKb)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
rssItems = xmlStr.split('<item>')
|
rssItems = xmlStr.split('<item>')
|
||||||
|
|
@ -300,17 +300,17 @@ def xml2StrToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
if '</pubDate>' not in rssItem:
|
if '</pubDate>' not in rssItem:
|
||||||
continue
|
continue
|
||||||
title = rssItem.split('<title>')[1]
|
title = rssItem.split('<title>')[1]
|
||||||
title = removeCDATA(title.split('</title>')[0])
|
title = _removeCDATA(title.split('</title>')[0])
|
||||||
description = ''
|
description = ''
|
||||||
if '<description>' in rssItem and '</description>' in rssItem:
|
if '<description>' in rssItem and '</description>' in rssItem:
|
||||||
description = rssItem.split('<description>')[1]
|
description = rssItem.split('<description>')[1]
|
||||||
description = removeCDATA(description.split('</description>')[0])
|
description = _removeCDATA(description.split('</description>')[0])
|
||||||
else:
|
else:
|
||||||
if '<media:description>' in rssItem and \
|
if '<media:description>' in rssItem and \
|
||||||
'</media:description>' in rssItem:
|
'</media:description>' in rssItem:
|
||||||
description = rssItem.split('<media:description>')[1]
|
description = rssItem.split('<media:description>')[1]
|
||||||
description = description.split('</media:description>')[0]
|
description = description.split('</media:description>')[0]
|
||||||
description = removeCDATA(description)
|
description = _removeCDATA(description)
|
||||||
link = rssItem.split('<link>')[1]
|
link = rssItem.split('<link>')[1]
|
||||||
link = link.split('</link>')[0]
|
link = link.split('</link>')[0]
|
||||||
if '://' not in link:
|
if '://' not in link:
|
||||||
|
|
@ -325,14 +325,14 @@ def xml2StrToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
|
|
||||||
pubDateStr = parseFeedDate(pubDate)
|
pubDateStr = parseFeedDate(pubDate)
|
||||||
if pubDateStr:
|
if pubDateStr:
|
||||||
if validFeedDate(pubDateStr):
|
if _validFeedDate(pubDateStr):
|
||||||
postFilename = ''
|
postFilename = ''
|
||||||
votesStatus = []
|
votesStatus = []
|
||||||
addNewswireDictEntry(baseDir, domain,
|
_addNewswireDictEntry(baseDir, domain,
|
||||||
result, pubDateStr,
|
result, pubDateStr,
|
||||||
title, link,
|
title, link,
|
||||||
votesStatus, postFilename,
|
votesStatus, postFilename,
|
||||||
description, moderated, mirrored)
|
description, moderated, mirrored)
|
||||||
postCtr += 1
|
postCtr += 1
|
||||||
if postCtr >= maxPostsPerSource:
|
if postCtr >= maxPostsPerSource:
|
||||||
break
|
break
|
||||||
|
|
@ -341,11 +341,11 @@ def xml2StrToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
|
def _xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
moderated: bool, mirrored: bool,
|
moderated: bool, mirrored: bool,
|
||||||
maxPostsPerSource: int,
|
maxPostsPerSource: int,
|
||||||
maxFeedItemSizeKb: int,
|
maxFeedItemSizeKb: int,
|
||||||
maxCategoriesFeedItemSizeKb: int) -> {}:
|
maxCategoriesFeedItemSizeKb: int) -> {}:
|
||||||
"""Converts an xml RSS 1.0 string to a dictionary
|
"""Converts an xml RSS 1.0 string to a dictionary
|
||||||
https://validator.w3.org/feed/docs/rss1.html
|
https://validator.w3.org/feed/docs/rss1.html
|
||||||
"""
|
"""
|
||||||
|
|
@ -356,8 +356,8 @@ def xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
|
|
||||||
# is this an rss feed containing hashtag categories?
|
# is this an rss feed containing hashtag categories?
|
||||||
if '<title>#categories</title>' in xmlStr:
|
if '<title>#categories</title>' in xmlStr:
|
||||||
xml2StrToHashtagCategories(baseDir, xmlStr,
|
_xml2StrToHashtagCategories(baseDir, xmlStr,
|
||||||
maxCategoriesFeedItemSizeKb)
|
maxCategoriesFeedItemSizeKb)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
rssItems = xmlStr.split(itemStr)
|
rssItems = xmlStr.split(itemStr)
|
||||||
|
|
@ -384,17 +384,17 @@ def xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
if '</dc:date>' not in rssItem:
|
if '</dc:date>' not in rssItem:
|
||||||
continue
|
continue
|
||||||
title = rssItem.split('<title>')[1]
|
title = rssItem.split('<title>')[1]
|
||||||
title = removeCDATA(title.split('</title>')[0])
|
title = _removeCDATA(title.split('</title>')[0])
|
||||||
description = ''
|
description = ''
|
||||||
if '<description>' in rssItem and '</description>' in rssItem:
|
if '<description>' in rssItem and '</description>' in rssItem:
|
||||||
description = rssItem.split('<description>')[1]
|
description = rssItem.split('<description>')[1]
|
||||||
description = removeCDATA(description.split('</description>')[0])
|
description = _removeCDATA(description.split('</description>')[0])
|
||||||
else:
|
else:
|
||||||
if '<media:description>' in rssItem and \
|
if '<media:description>' in rssItem and \
|
||||||
'</media:description>' in rssItem:
|
'</media:description>' in rssItem:
|
||||||
description = rssItem.split('<media:description>')[1]
|
description = rssItem.split('<media:description>')[1]
|
||||||
description = description.split('</media:description>')[0]
|
description = description.split('</media:description>')[0]
|
||||||
description = removeCDATA(description)
|
description = _removeCDATA(description)
|
||||||
link = rssItem.split('<link>')[1]
|
link = rssItem.split('<link>')[1]
|
||||||
link = link.split('</link>')[0]
|
link = link.split('</link>')[0]
|
||||||
if '://' not in link:
|
if '://' not in link:
|
||||||
|
|
@ -409,14 +409,14 @@ def xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
|
|
||||||
pubDateStr = parseFeedDate(pubDate)
|
pubDateStr = parseFeedDate(pubDate)
|
||||||
if pubDateStr:
|
if pubDateStr:
|
||||||
if validFeedDate(pubDateStr):
|
if _validFeedDate(pubDateStr):
|
||||||
postFilename = ''
|
postFilename = ''
|
||||||
votesStatus = []
|
votesStatus = []
|
||||||
addNewswireDictEntry(baseDir, domain,
|
_addNewswireDictEntry(baseDir, domain,
|
||||||
result, pubDateStr,
|
result, pubDateStr,
|
||||||
title, link,
|
title, link,
|
||||||
votesStatus, postFilename,
|
votesStatus, postFilename,
|
||||||
description, moderated, mirrored)
|
description, moderated, mirrored)
|
||||||
postCtr += 1
|
postCtr += 1
|
||||||
if postCtr >= maxPostsPerSource:
|
if postCtr >= maxPostsPerSource:
|
||||||
break
|
break
|
||||||
|
|
@ -425,10 +425,10 @@ def xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def atomFeedToDict(baseDir: str, domain: str, xmlStr: str,
|
def _atomFeedToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
moderated: bool, mirrored: bool,
|
moderated: bool, mirrored: bool,
|
||||||
maxPostsPerSource: int,
|
maxPostsPerSource: int,
|
||||||
maxFeedItemSizeKb: int) -> {}:
|
maxFeedItemSizeKb: int) -> {}:
|
||||||
"""Converts an atom feed string to a dictionary
|
"""Converts an atom feed string to a dictionary
|
||||||
"""
|
"""
|
||||||
if '<entry>' not in xmlStr:
|
if '<entry>' not in xmlStr:
|
||||||
|
|
@ -456,17 +456,17 @@ def atomFeedToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
if '</updated>' not in atomItem:
|
if '</updated>' not in atomItem:
|
||||||
continue
|
continue
|
||||||
title = atomItem.split('<title>')[1]
|
title = atomItem.split('<title>')[1]
|
||||||
title = removeCDATA(title.split('</title>')[0])
|
title = _removeCDATA(title.split('</title>')[0])
|
||||||
description = ''
|
description = ''
|
||||||
if '<summary>' in atomItem and '</summary>' in atomItem:
|
if '<summary>' in atomItem and '</summary>' in atomItem:
|
||||||
description = atomItem.split('<summary>')[1]
|
description = atomItem.split('<summary>')[1]
|
||||||
description = removeCDATA(description.split('</summary>')[0])
|
description = _removeCDATA(description.split('</summary>')[0])
|
||||||
else:
|
else:
|
||||||
if '<media:description>' in atomItem and \
|
if '<media:description>' in atomItem and \
|
||||||
'</media:description>' in atomItem:
|
'</media:description>' in atomItem:
|
||||||
description = atomItem.split('<media:description>')[1]
|
description = atomItem.split('<media:description>')[1]
|
||||||
description = description.split('</media:description>')[0]
|
description = description.split('</media:description>')[0]
|
||||||
description = removeCDATA(description)
|
description = _removeCDATA(description)
|
||||||
link = atomItem.split('<link>')[1]
|
link = atomItem.split('<link>')[1]
|
||||||
link = link.split('</link>')[0]
|
link = link.split('</link>')[0]
|
||||||
if '://' not in link:
|
if '://' not in link:
|
||||||
|
|
@ -481,14 +481,14 @@ def atomFeedToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
|
|
||||||
pubDateStr = parseFeedDate(pubDate)
|
pubDateStr = parseFeedDate(pubDate)
|
||||||
if pubDateStr:
|
if pubDateStr:
|
||||||
if validFeedDate(pubDateStr):
|
if _validFeedDate(pubDateStr):
|
||||||
postFilename = ''
|
postFilename = ''
|
||||||
votesStatus = []
|
votesStatus = []
|
||||||
addNewswireDictEntry(baseDir, domain,
|
_addNewswireDictEntry(baseDir, domain,
|
||||||
result, pubDateStr,
|
result, pubDateStr,
|
||||||
title, link,
|
title, link,
|
||||||
votesStatus, postFilename,
|
votesStatus, postFilename,
|
||||||
description, moderated, mirrored)
|
description, moderated, mirrored)
|
||||||
postCtr += 1
|
postCtr += 1
|
||||||
if postCtr >= maxPostsPerSource:
|
if postCtr >= maxPostsPerSource:
|
||||||
break
|
break
|
||||||
|
|
@ -497,10 +497,10 @@ def atomFeedToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def atomFeedYTToDict(baseDir: str, domain: str, xmlStr: str,
|
def _atomFeedYTToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
moderated: bool, mirrored: bool,
|
moderated: bool, mirrored: bool,
|
||||||
maxPostsPerSource: int,
|
maxPostsPerSource: int,
|
||||||
maxFeedItemSizeKb: int) -> {}:
|
maxFeedItemSizeKb: int) -> {}:
|
||||||
"""Converts an atom-style YouTube feed string to a dictionary
|
"""Converts an atom-style YouTube feed string to a dictionary
|
||||||
"""
|
"""
|
||||||
if '<entry>' not in xmlStr:
|
if '<entry>' not in xmlStr:
|
||||||
|
|
@ -532,17 +532,17 @@ def atomFeedYTToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
if '</yt:videoId>' not in atomItem:
|
if '</yt:videoId>' not in atomItem:
|
||||||
continue
|
continue
|
||||||
title = atomItem.split('<title>')[1]
|
title = atomItem.split('<title>')[1]
|
||||||
title = removeCDATA(title.split('</title>')[0])
|
title = _removeCDATA(title.split('</title>')[0])
|
||||||
description = ''
|
description = ''
|
||||||
if '<media:description>' in atomItem and \
|
if '<media:description>' in atomItem and \
|
||||||
'</media:description>' in atomItem:
|
'</media:description>' in atomItem:
|
||||||
description = atomItem.split('<media:description>')[1]
|
description = atomItem.split('<media:description>')[1]
|
||||||
description = description.split('</media:description>')[0]
|
description = description.split('</media:description>')[0]
|
||||||
description = removeCDATA(description)
|
description = _removeCDATA(description)
|
||||||
elif '<summary>' in atomItem and '</summary>' in atomItem:
|
elif '<summary>' in atomItem and '</summary>' in atomItem:
|
||||||
description = atomItem.split('<summary>')[1]
|
description = atomItem.split('<summary>')[1]
|
||||||
description = description.split('</summary>')[0]
|
description = description.split('</summary>')[0]
|
||||||
description = removeCDATA(description)
|
description = _removeCDATA(description)
|
||||||
link = atomItem.split('<yt:videoId>')[1]
|
link = atomItem.split('<yt:videoId>')[1]
|
||||||
link = link.split('</yt:videoId>')[0]
|
link = link.split('</yt:videoId>')[0]
|
||||||
link = 'https://www.youtube.com/watch?v=' + link.strip()
|
link = 'https://www.youtube.com/watch?v=' + link.strip()
|
||||||
|
|
@ -551,14 +551,14 @@ def atomFeedYTToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
|
|
||||||
pubDateStr = parseFeedDate(pubDate)
|
pubDateStr = parseFeedDate(pubDate)
|
||||||
if pubDateStr:
|
if pubDateStr:
|
||||||
if validFeedDate(pubDateStr):
|
if _validFeedDate(pubDateStr):
|
||||||
postFilename = ''
|
postFilename = ''
|
||||||
votesStatus = []
|
votesStatus = []
|
||||||
addNewswireDictEntry(baseDir, domain,
|
_addNewswireDictEntry(baseDir, domain,
|
||||||
result, pubDateStr,
|
result, pubDateStr,
|
||||||
title, link,
|
title, link,
|
||||||
votesStatus, postFilename,
|
votesStatus, postFilename,
|
||||||
description, moderated, mirrored)
|
description, moderated, mirrored)
|
||||||
postCtr += 1
|
postCtr += 1
|
||||||
if postCtr >= maxPostsPerSource:
|
if postCtr >= maxPostsPerSource:
|
||||||
break
|
break
|
||||||
|
|
@ -567,36 +567,36 @@ def atomFeedYTToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def xmlStrToDict(baseDir: str, domain: str, xmlStr: str,
|
def _xmlStrToDict(baseDir: str, domain: str, xmlStr: str,
|
||||||
moderated: bool, mirrored: bool,
|
moderated: bool, mirrored: bool,
|
||||||
maxPostsPerSource: int,
|
maxPostsPerSource: int,
|
||||||
maxFeedItemSizeKb: int,
|
maxFeedItemSizeKb: int,
|
||||||
maxCategoriesFeedItemSizeKb: int) -> {}:
|
maxCategoriesFeedItemSizeKb: int) -> {}:
|
||||||
"""Converts an xml string to a dictionary
|
"""Converts an xml string to a dictionary
|
||||||
"""
|
"""
|
||||||
if '<yt:videoId>' in xmlStr and '<yt:channelId>' in xmlStr:
|
if '<yt:videoId>' in xmlStr and '<yt:channelId>' in xmlStr:
|
||||||
print('YouTube feed: reading')
|
print('YouTube feed: reading')
|
||||||
return atomFeedYTToDict(baseDir, domain,
|
return _atomFeedYTToDict(baseDir, domain,
|
||||||
xmlStr, moderated, mirrored,
|
xmlStr, moderated, mirrored,
|
||||||
maxPostsPerSource, maxFeedItemSizeKb)
|
maxPostsPerSource, maxFeedItemSizeKb)
|
||||||
elif 'rss version="2.0"' in xmlStr:
|
elif 'rss version="2.0"' in xmlStr:
|
||||||
return xml2StrToDict(baseDir, domain,
|
return _xml2StrToDict(baseDir, domain,
|
||||||
xmlStr, moderated, mirrored,
|
|
||||||
maxPostsPerSource, maxFeedItemSizeKb,
|
|
||||||
maxCategoriesFeedItemSizeKb)
|
|
||||||
elif '<?xml version="1.0"' in xmlStr:
|
|
||||||
return xml1StrToDict(baseDir, domain,
|
|
||||||
xmlStr, moderated, mirrored,
|
|
||||||
maxPostsPerSource, maxFeedItemSizeKb,
|
|
||||||
maxCategoriesFeedItemSizeKb)
|
|
||||||
elif 'xmlns="http://www.w3.org/2005/Atom"' in xmlStr:
|
|
||||||
return atomFeedToDict(baseDir, domain,
|
|
||||||
xmlStr, moderated, mirrored,
|
xmlStr, moderated, mirrored,
|
||||||
maxPostsPerSource, maxFeedItemSizeKb)
|
maxPostsPerSource, maxFeedItemSizeKb,
|
||||||
|
maxCategoriesFeedItemSizeKb)
|
||||||
|
elif '<?xml version="1.0"' in xmlStr:
|
||||||
|
return _xml1StrToDict(baseDir, domain,
|
||||||
|
xmlStr, moderated, mirrored,
|
||||||
|
maxPostsPerSource, maxFeedItemSizeKb,
|
||||||
|
maxCategoriesFeedItemSizeKb)
|
||||||
|
elif 'xmlns="http://www.w3.org/2005/Atom"' in xmlStr:
|
||||||
|
return _atomFeedToDict(baseDir, domain,
|
||||||
|
xmlStr, moderated, mirrored,
|
||||||
|
maxPostsPerSource, maxFeedItemSizeKb)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def YTchannelToAtomFeed(url: str) -> str:
|
def _YTchannelToAtomFeed(url: str) -> str:
|
||||||
"""Converts a YouTube channel url into an atom feed url
|
"""Converts a YouTube channel url into an atom feed url
|
||||||
"""
|
"""
|
||||||
if 'youtube.com/channel/' not in url:
|
if 'youtube.com/channel/' not in url:
|
||||||
|
|
@ -633,17 +633,17 @@ def getRSS(baseDir: str, domain: str, session, url: str,
|
||||||
'Mozilla/5.0 (X11; Linux x86_64; rv:81.0) Gecko/20100101 Firefox/81.0'
|
'Mozilla/5.0 (X11; Linux x86_64; rv:81.0) Gecko/20100101 Firefox/81.0'
|
||||||
if not session:
|
if not session:
|
||||||
print('WARN: no session specified for getRSS')
|
print('WARN: no session specified for getRSS')
|
||||||
url = YTchannelToAtomFeed(url)
|
url = _YTchannelToAtomFeed(url)
|
||||||
try:
|
try:
|
||||||
result = session.get(url, headers=sessionHeaders, params=sessionParams)
|
result = session.get(url, headers=sessionHeaders, params=sessionParams)
|
||||||
if result:
|
if result:
|
||||||
if int(len(result.text) / 1024) < maxFeedSizeKb and \
|
if int(len(result.text) / 1024) < maxFeedSizeKb and \
|
||||||
not containsInvalidChars(result.text):
|
not containsInvalidChars(result.text):
|
||||||
return xmlStrToDict(baseDir, domain, result.text,
|
return _xmlStrToDict(baseDir, domain, result.text,
|
||||||
moderated, mirrored,
|
moderated, mirrored,
|
||||||
maxPostsPerSource,
|
maxPostsPerSource,
|
||||||
maxFeedItemSizeKb,
|
maxFeedItemSizeKb,
|
||||||
maxCategoriesFeedItemSizeKb)
|
maxCategoriesFeedItemSizeKb)
|
||||||
else:
|
else:
|
||||||
print('WARN: feed is too large, ' +
|
print('WARN: feed is too large, ' +
|
||||||
'or contains invalid characters: ' + url)
|
'or contains invalid characters: ' + url)
|
||||||
|
|
@ -692,7 +692,7 @@ def getRSSfromDict(baseDir: str, newswire: {},
|
||||||
continue
|
continue
|
||||||
rssStr += '<item>\n'
|
rssStr += '<item>\n'
|
||||||
rssStr += ' <title>' + fields[0] + '</title>\n'
|
rssStr += ' <title>' + fields[0] + '</title>\n'
|
||||||
description = removeCDATA(firstParagraphFromString(fields[4]))
|
description = _removeCDATA(firstParagraphFromString(fields[4]))
|
||||||
rssStr += ' <description>' + description + '</description>\n'
|
rssStr += ' <description>' + description + '</description>\n'
|
||||||
url = fields[1]
|
url = fields[1]
|
||||||
if '://' not in url:
|
if '://' not in url:
|
||||||
|
|
@ -707,7 +707,7 @@ def getRSSfromDict(baseDir: str, newswire: {},
|
||||||
return rssStr
|
return rssStr
|
||||||
|
|
||||||
|
|
||||||
def isNewswireBlogPost(postJsonObject: {}) -> bool:
|
def _isNewswireBlogPost(postJsonObject: {}) -> bool:
|
||||||
"""Is the given object a blog post?
|
"""Is the given object a blog post?
|
||||||
There isn't any difference between a blog post and a newswire blog post
|
There isn't any difference between a blog post and a newswire blog post
|
||||||
but we may here need to check for different properties than
|
but we may here need to check for different properties than
|
||||||
|
|
@ -727,7 +727,7 @@ def isNewswireBlogPost(postJsonObject: {}) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def getHashtagsFromPost(postJsonObject: {}) -> []:
|
def _getHashtagsFromPost(postJsonObject: {}) -> []:
|
||||||
"""Returns a list of any hashtags within a post
|
"""Returns a list of any hashtags within a post
|
||||||
"""
|
"""
|
||||||
if not postJsonObject.get('object'):
|
if not postJsonObject.get('object'):
|
||||||
|
|
@ -753,11 +753,11 @@ def getHashtagsFromPost(postJsonObject: {}) -> []:
|
||||||
return tags
|
return tags
|
||||||
|
|
||||||
|
|
||||||
def addAccountBlogsToNewswire(baseDir: str, nickname: str, domain: str,
|
def _addAccountBlogsToNewswire(baseDir: str, nickname: str, domain: str,
|
||||||
newswire: {},
|
newswire: {},
|
||||||
maxBlogsPerAccount: int,
|
maxBlogsPerAccount: int,
|
||||||
indexFilename: str,
|
indexFilename: str,
|
||||||
maxTags: int) -> None:
|
maxTags: int) -> None:
|
||||||
"""Adds blogs for the given account to the newswire
|
"""Adds blogs for the given account to the newswire
|
||||||
"""
|
"""
|
||||||
if not os.path.isfile(indexFilename):
|
if not os.path.isfile(indexFilename):
|
||||||
|
|
@ -803,7 +803,7 @@ def addAccountBlogsToNewswire(baseDir: str, nickname: str, domain: str,
|
||||||
postJsonObject = None
|
postJsonObject = None
|
||||||
if fullPostFilename:
|
if fullPostFilename:
|
||||||
postJsonObject = loadJson(fullPostFilename)
|
postJsonObject = loadJson(fullPostFilename)
|
||||||
if isNewswireBlogPost(postJsonObject):
|
if _isNewswireBlogPost(postJsonObject):
|
||||||
published = postJsonObject['object']['published']
|
published = postJsonObject['object']['published']
|
||||||
published = published.replace('T', ' ')
|
published = published.replace('T', ' ')
|
||||||
published = published.replace('Z', '+00:00')
|
published = published.replace('Z', '+00:00')
|
||||||
|
|
@ -812,24 +812,24 @@ def addAccountBlogsToNewswire(baseDir: str, nickname: str, domain: str,
|
||||||
votes = loadJson(fullPostFilename + '.votes')
|
votes = loadJson(fullPostFilename + '.votes')
|
||||||
content = postJsonObject['object']['content']
|
content = postJsonObject['object']['content']
|
||||||
description = firstParagraphFromString(content)
|
description = firstParagraphFromString(content)
|
||||||
description = removeCDATA(description)
|
description = _removeCDATA(description)
|
||||||
addNewswireDictEntry(baseDir, domain,
|
_addNewswireDictEntry(baseDir, domain,
|
||||||
newswire, published,
|
newswire, published,
|
||||||
postJsonObject['object']['summary'],
|
postJsonObject['object']['summary'],
|
||||||
postJsonObject['object']['url'],
|
postJsonObject['object']['url'],
|
||||||
votes, fullPostFilename,
|
votes, fullPostFilename,
|
||||||
description, moderated, False,
|
description, moderated, False,
|
||||||
getHashtagsFromPost(postJsonObject),
|
_getHashtagsFromPost(postJsonObject),
|
||||||
maxTags)
|
maxTags)
|
||||||
|
|
||||||
ctr += 1
|
ctr += 1
|
||||||
if ctr >= maxBlogsPerAccount:
|
if ctr >= maxBlogsPerAccount:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def addBlogsToNewswire(baseDir: str, domain: str, newswire: {},
|
def _addBlogsToNewswire(baseDir: str, domain: str, newswire: {},
|
||||||
maxBlogsPerAccount: int,
|
maxBlogsPerAccount: int,
|
||||||
maxTags: int) -> None:
|
maxTags: int) -> None:
|
||||||
"""Adds blogs from each user account into the newswire
|
"""Adds blogs from each user account into the newswire
|
||||||
"""
|
"""
|
||||||
moderationDict = {}
|
moderationDict = {}
|
||||||
|
|
@ -857,9 +857,9 @@ def addBlogsToNewswire(baseDir: str, domain: str, newswire: {},
|
||||||
blogsIndex = accountDir + '/tlblogs.index'
|
blogsIndex = accountDir + '/tlblogs.index'
|
||||||
if os.path.isfile(blogsIndex):
|
if os.path.isfile(blogsIndex):
|
||||||
domain = handle.split('@')[1]
|
domain = handle.split('@')[1]
|
||||||
addAccountBlogsToNewswire(baseDir, nickname, domain,
|
_addAccountBlogsToNewswire(baseDir, nickname, domain,
|
||||||
newswire, maxBlogsPerAccount,
|
newswire, maxBlogsPerAccount,
|
||||||
blogsIndex, maxTags)
|
blogsIndex, maxTags)
|
||||||
break
|
break
|
||||||
|
|
||||||
# sort the moderation dict into chronological order, latest first
|
# sort the moderation dict into chronological order, latest first
|
||||||
|
|
@ -926,8 +926,8 @@ def getDictFromNewswire(session, baseDir: str, domain: str,
|
||||||
result[dateStr] = item
|
result[dateStr] = item
|
||||||
|
|
||||||
# add blogs from each user account
|
# add blogs from each user account
|
||||||
addBlogsToNewswire(baseDir, domain, result,
|
_addBlogsToNewswire(baseDir, domain, result,
|
||||||
maxPostsPerSource, maxTags)
|
maxPostsPerSource, maxTags)
|
||||||
|
|
||||||
# sort into chronological order, latest first
|
# sort into chronological order, latest first
|
||||||
sortedResult = OrderedDict(sorted(result.items(), reverse=True))
|
sortedResult = OrderedDict(sorted(result.items(), reverse=True))
|
||||||
|
|
|
||||||
34
person.py
34
person.py
|
|
@ -134,7 +134,7 @@ def setOrganizationScheme(baseDir: str, nickname: str, domain: str,
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def accountExists(baseDir: str, nickname: str, domain: str) -> bool:
|
def _accountExists(baseDir: str, nickname: str, domain: str) -> bool:
|
||||||
"""Returns true if the given account exists
|
"""Returns true if the given account exists
|
||||||
"""
|
"""
|
||||||
if ':' in domain:
|
if ':' in domain:
|
||||||
|
|
@ -201,10 +201,10 @@ def getDefaultPersonContext() -> str:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def createPersonBase(baseDir: str, nickname: str, domain: str, port: int,
|
def _createPersonBase(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
httpPrefix: str, saveToFile: bool,
|
httpPrefix: str, saveToFile: bool,
|
||||||
manualFollowerApproval: bool,
|
manualFollowerApproval: bool,
|
||||||
password=None) -> (str, str, {}, {}):
|
password=None) -> (str, str, {}, {}):
|
||||||
"""Returns the private key, public key, actor and webfinger endpoint
|
"""Returns the private key, public key, actor and webfinger endpoint
|
||||||
"""
|
"""
|
||||||
privateKeyPem, publicKeyPem = generateRSAKey()
|
privateKeyPem, publicKeyPem = generateRSAKey()
|
||||||
|
|
@ -377,7 +377,7 @@ def registerAccount(baseDir: str, httpPrefix: str, domain: str, port: int,
|
||||||
manualFollowerApproval: bool) -> bool:
|
manualFollowerApproval: bool) -> bool:
|
||||||
"""Registers a new account from the web interface
|
"""Registers a new account from the web interface
|
||||||
"""
|
"""
|
||||||
if accountExists(baseDir, nickname, domain):
|
if _accountExists(baseDir, nickname, domain):
|
||||||
return False
|
return False
|
||||||
if not validNickname(domain, nickname):
|
if not validNickname(domain, nickname):
|
||||||
print('REGISTER: Nickname ' + nickname + ' is invalid')
|
print('REGISTER: Nickname ' + nickname + ' is invalid')
|
||||||
|
|
@ -449,12 +449,12 @@ def createPerson(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
return None, None, None, None
|
return None, None, None, None
|
||||||
|
|
||||||
(privateKeyPem, publicKeyPem,
|
(privateKeyPem, publicKeyPem,
|
||||||
newPerson, webfingerEndpoint) = createPersonBase(baseDir, nickname,
|
newPerson, webfingerEndpoint) = _createPersonBase(baseDir, nickname,
|
||||||
domain, port,
|
domain, port,
|
||||||
httpPrefix,
|
httpPrefix,
|
||||||
saveToFile,
|
saveToFile,
|
||||||
manualFollowerApproval,
|
manualFollowerApproval,
|
||||||
password)
|
password)
|
||||||
if not getConfigParam(baseDir, 'admin'):
|
if not getConfigParam(baseDir, 'admin'):
|
||||||
if nickname != 'news':
|
if nickname != 'news':
|
||||||
# print(nickname+' becomes the instance admin and a moderator')
|
# print(nickname+' becomes the instance admin and a moderator')
|
||||||
|
|
@ -525,8 +525,8 @@ def createSharedInbox(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
httpPrefix: str) -> (str, str, {}, {}):
|
httpPrefix: str) -> (str, str, {}, {}):
|
||||||
"""Generates the shared inbox
|
"""Generates the shared inbox
|
||||||
"""
|
"""
|
||||||
return createPersonBase(baseDir, nickname, domain, port, httpPrefix,
|
return _createPersonBase(baseDir, nickname, domain, port, httpPrefix,
|
||||||
True, True, None)
|
True, True, None)
|
||||||
|
|
||||||
|
|
||||||
def createNewsInbox(baseDir: str, domain: str, port: int,
|
def createNewsInbox(baseDir: str, domain: str, port: int,
|
||||||
|
|
@ -845,8 +845,8 @@ def canRemovePost(baseDir: str, nickname: str,
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def removeTagsForNickname(baseDir: str, nickname: str,
|
def _removeTagsForNickname(baseDir: str, nickname: str,
|
||||||
domain: str, port: int) -> None:
|
domain: str, port: int) -> None:
|
||||||
"""Removes tags for a nickname
|
"""Removes tags for a nickname
|
||||||
"""
|
"""
|
||||||
if not os.path.isdir(baseDir + '/tags'):
|
if not os.path.isdir(baseDir + '/tags'):
|
||||||
|
|
@ -900,7 +900,7 @@ def removeAccount(baseDir: str, nickname: str,
|
||||||
unsuspendAccount(baseDir, nickname)
|
unsuspendAccount(baseDir, nickname)
|
||||||
handle = nickname + '@' + domain
|
handle = nickname + '@' + domain
|
||||||
removePassword(baseDir, nickname)
|
removePassword(baseDir, nickname)
|
||||||
removeTagsForNickname(baseDir, nickname, domain, port)
|
_removeTagsForNickname(baseDir, nickname, domain, port)
|
||||||
if os.path.isdir(baseDir + '/deactivated/' + handle):
|
if os.path.isdir(baseDir + '/deactivated/' + handle):
|
||||||
shutil.rmtree(baseDir + '/deactivated/' + handle)
|
shutil.rmtree(baseDir + '/deactivated/' + handle)
|
||||||
if os.path.isdir(baseDir + '/accounts/' + handle):
|
if os.path.isdir(baseDir + '/accounts/' + handle):
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,8 @@ def getPetName(baseDir: str, nickname: str, domain: str,
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
|
||||||
def getPetNameHandle(baseDir: str, nickname: str, domain: str,
|
def _getPetNameHandle(baseDir: str, nickname: str, domain: str,
|
||||||
petname: str) -> str:
|
petname: str) -> str:
|
||||||
"""Given a petname returns the handle
|
"""Given a petname returns the handle
|
||||||
"""
|
"""
|
||||||
if petname.startswith('@'):
|
if petname.startswith('@'):
|
||||||
|
|
@ -113,7 +113,7 @@ def resolvePetnames(baseDir: str, nickname: str, domain: str,
|
||||||
if not wrd.startswith('@'):
|
if not wrd.startswith('@'):
|
||||||
break
|
break
|
||||||
# does a petname handle exist for this?
|
# does a petname handle exist for this?
|
||||||
handle = getPetNameHandle(baseDir, nickname, domain, wrd)
|
handle = _getPetNameHandle(baseDir, nickname, domain, wrd)
|
||||||
if not handle:
|
if not handle:
|
||||||
continue
|
continue
|
||||||
# replace the petname with the handle
|
# replace the petname with the handle
|
||||||
|
|
|
||||||
565
posts.py
565
posts.py
|
|
@ -116,8 +116,8 @@ def noOfFollowersOnDomain(baseDir: str, handle: str,
|
||||||
return ctr
|
return ctr
|
||||||
|
|
||||||
|
|
||||||
def getPersonKey(nickname: str, domain: str, baseDir: str, keyType='public',
|
def _getPersonKey(nickname: str, domain: str, baseDir: str, keyType='public',
|
||||||
debug=False):
|
debug=False):
|
||||||
"""Returns the public or private key of a person
|
"""Returns the public or private key of a person
|
||||||
"""
|
"""
|
||||||
handle = nickname + '@' + domain
|
handle = nickname + '@' + domain
|
||||||
|
|
@ -136,7 +136,7 @@ def getPersonKey(nickname: str, domain: str, baseDir: str, keyType='public',
|
||||||
return keyPem
|
return keyPem
|
||||||
|
|
||||||
|
|
||||||
def cleanHtml(rawHtml: str) -> str:
|
def _cleanHtml(rawHtml: str) -> str:
|
||||||
# text=BeautifulSoup(rawHtml, 'html.parser').get_text()
|
# text=BeautifulSoup(rawHtml, 'html.parser').get_text()
|
||||||
text = rawHtml
|
text = rawHtml
|
||||||
return html.unescape(text)
|
return html.unescape(text)
|
||||||
|
|
@ -288,14 +288,14 @@ def getPersonBox(baseDir: str, session, wfRequest: {},
|
||||||
avatarUrl, displayName
|
avatarUrl, displayName
|
||||||
|
|
||||||
|
|
||||||
def getPosts(session, outboxUrl: str, maxPosts: int,
|
def _getPosts(session, outboxUrl: str, maxPosts: int,
|
||||||
maxMentions: int,
|
maxMentions: int,
|
||||||
maxEmoji: int, maxAttachments: int,
|
maxEmoji: int, maxAttachments: int,
|
||||||
federationList: [],
|
federationList: [],
|
||||||
personCache: {}, raw: bool,
|
personCache: {}, raw: bool,
|
||||||
simple: bool, debug: bool,
|
simple: bool, debug: bool,
|
||||||
projectVersion: str, httpPrefix: str,
|
projectVersion: str, httpPrefix: str,
|
||||||
domain: str) -> {}:
|
domain: str) -> {}:
|
||||||
"""Gets public posts from an outbox
|
"""Gets public posts from an outbox
|
||||||
"""
|
"""
|
||||||
personPosts = {}
|
personPosts = {}
|
||||||
|
|
@ -445,7 +445,7 @@ def getPosts(session, outboxUrl: str, maxPosts: int,
|
||||||
sensitive = item['object']['sensitive']
|
sensitive = item['object']['sensitive']
|
||||||
|
|
||||||
if simple:
|
if simple:
|
||||||
print(cleanHtml(content) + '\n')
|
print(_cleanHtml(content) + '\n')
|
||||||
else:
|
else:
|
||||||
pprint(item)
|
pprint(item)
|
||||||
personPosts[item['id']] = {
|
personPosts[item['id']] = {
|
||||||
|
|
@ -453,7 +453,7 @@ def getPosts(session, outboxUrl: str, maxPosts: int,
|
||||||
"inreplyto": inReplyTo,
|
"inreplyto": inReplyTo,
|
||||||
"summary": summary,
|
"summary": summary,
|
||||||
"html": content,
|
"html": content,
|
||||||
"plaintext": cleanHtml(content),
|
"plaintext": _cleanHtml(content),
|
||||||
"attachment": attachment,
|
"attachment": attachment,
|
||||||
"mentions": mentions,
|
"mentions": mentions,
|
||||||
"emoji": emoji,
|
"emoji": emoji,
|
||||||
|
|
@ -519,15 +519,15 @@ def getPostDomains(session, outboxUrl: str, maxPosts: int,
|
||||||
return postDomains
|
return postDomains
|
||||||
|
|
||||||
|
|
||||||
def getPostsForBlockedDomains(baseDir: str,
|
def _getPostsForBlockedDomains(baseDir: str,
|
||||||
session, outboxUrl: str, maxPosts: int,
|
session, outboxUrl: str, maxPosts: int,
|
||||||
maxMentions: int,
|
maxMentions: int,
|
||||||
maxEmoji: int, maxAttachments: int,
|
maxEmoji: int, maxAttachments: int,
|
||||||
federationList: [],
|
federationList: [],
|
||||||
personCache: {},
|
personCache: {},
|
||||||
debug: bool,
|
debug: bool,
|
||||||
projectVersion: str, httpPrefix: str,
|
projectVersion: str, httpPrefix: str,
|
||||||
domain: str) -> {}:
|
domain: str) -> {}:
|
||||||
"""Returns a dictionary of posts for blocked domains
|
"""Returns a dictionary of posts for blocked domains
|
||||||
"""
|
"""
|
||||||
if not outboxUrl:
|
if not outboxUrl:
|
||||||
|
|
@ -643,7 +643,7 @@ def savePostToBox(baseDir: str, httpPrefix: str, postId: str,
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
|
||||||
def updateHashtagsIndex(baseDir: str, tag: {}, newPostId: str) -> None:
|
def _updateHashtagsIndex(baseDir: str, tag: {}, newPostId: str) -> None:
|
||||||
"""Writes the post url for hashtags to a file
|
"""Writes the post url for hashtags to a file
|
||||||
This allows posts for a hashtag to be quickly looked up
|
This allows posts for a hashtag to be quickly looked up
|
||||||
"""
|
"""
|
||||||
|
|
@ -677,8 +677,8 @@ def updateHashtagsIndex(baseDir: str, tag: {}, newPostId: str) -> None:
|
||||||
tagsFilename + ' ' + str(e))
|
tagsFilename + ' ' + str(e))
|
||||||
|
|
||||||
|
|
||||||
def addSchedulePost(baseDir: str, nickname: str, domain: str,
|
def _addSchedulePost(baseDir: str, nickname: str, domain: str,
|
||||||
eventDateStr: str, postId: str) -> None:
|
eventDateStr: str, postId: str) -> None:
|
||||||
"""Adds a scheduled post to the index
|
"""Adds a scheduled post to the index
|
||||||
"""
|
"""
|
||||||
handle = nickname + '@' + domain
|
handle = nickname + '@' + domain
|
||||||
|
|
@ -703,18 +703,18 @@ def addSchedulePost(baseDir: str, nickname: str, domain: str,
|
||||||
scheduleFile.close()
|
scheduleFile.close()
|
||||||
|
|
||||||
|
|
||||||
def appendEventFields(newPost: {},
|
def _appendEventFields(newPost: {},
|
||||||
eventUUID: str, eventStatus: str,
|
eventUUID: str, eventStatus: str,
|
||||||
anonymousParticipationEnabled: bool,
|
anonymousParticipationEnabled: bool,
|
||||||
repliesModerationOption: str,
|
repliesModerationOption: str,
|
||||||
category: str,
|
category: str,
|
||||||
joinMode: str,
|
joinMode: str,
|
||||||
eventDateStr: str,
|
eventDateStr: str,
|
||||||
endDateStr: str,
|
endDateStr: str,
|
||||||
location: str,
|
location: str,
|
||||||
maximumAttendeeCapacity: int,
|
maximumAttendeeCapacity: int,
|
||||||
ticketUrl: str,
|
ticketUrl: str,
|
||||||
subject: str) -> None:
|
subject: str) -> None:
|
||||||
"""Appends Mobilizon-type event fields to a post
|
"""Appends Mobilizon-type event fields to a post
|
||||||
"""
|
"""
|
||||||
if not eventUUID:
|
if not eventUUID:
|
||||||
|
|
@ -758,7 +758,7 @@ def validContentWarning(cw: str) -> str:
|
||||||
return cw
|
return cw
|
||||||
|
|
||||||
|
|
||||||
def loadAutoCW(baseDir: str, nickname: str, domain: str) -> []:
|
def _loadAutoCW(baseDir: str, nickname: str, domain: str) -> []:
|
||||||
"""Loads automatic CWs file and returns a list containing
|
"""Loads automatic CWs file and returns a list containing
|
||||||
the lines of the file
|
the lines of the file
|
||||||
"""
|
"""
|
||||||
|
|
@ -771,13 +771,13 @@ def loadAutoCW(baseDir: str, nickname: str, domain: str) -> []:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def addAutoCW(baseDir: str, nickname: str, domain: str,
|
def _addAutoCW(baseDir: str, nickname: str, domain: str,
|
||||||
subject: str, content: str) -> str:
|
subject: str, content: str) -> str:
|
||||||
"""Appends any automatic CW to the subject line
|
"""Appends any automatic CW to the subject line
|
||||||
and returns the new subject line
|
and returns the new subject line
|
||||||
"""
|
"""
|
||||||
newSubject = subject
|
newSubject = subject
|
||||||
autoCWList = loadAutoCW(baseDir, nickname, domain)
|
autoCWList = _loadAutoCW(baseDir, nickname, domain)
|
||||||
for cwRule in autoCWList:
|
for cwRule in autoCWList:
|
||||||
if '->' not in cwRule:
|
if '->' not in cwRule:
|
||||||
continue
|
continue
|
||||||
|
|
@ -793,26 +793,26 @@ def addAutoCW(baseDir: str, nickname: str, domain: str,
|
||||||
return newSubject
|
return newSubject
|
||||||
|
|
||||||
|
|
||||||
def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
|
def _createPostBase(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
toUrl: str, ccUrl: str, httpPrefix: str, content: str,
|
toUrl: str, ccUrl: str, httpPrefix: str, content: str,
|
||||||
followersOnly: bool, saveToFile: bool, clientToServer: bool,
|
followersOnly: bool, saveToFile: bool,
|
||||||
commentsEnabled: bool,
|
clientToServer: bool, commentsEnabled: bool,
|
||||||
attachImageFilename: str,
|
attachImageFilename: str,
|
||||||
mediaType: str, imageDescription: str,
|
mediaType: str, imageDescription: str,
|
||||||
useBlurhash: bool, isModerationReport: bool,
|
useBlurhash: bool, isModerationReport: bool,
|
||||||
isArticle: bool,
|
isArticle: bool,
|
||||||
inReplyTo=None,
|
inReplyTo=None,
|
||||||
inReplyToAtomUri=None, subject=None, schedulePost=False,
|
inReplyToAtomUri=None, subject=None, schedulePost=False,
|
||||||
eventDate=None, eventTime=None, location=None,
|
eventDate=None, eventTime=None, location=None,
|
||||||
eventUUID=None, category=None, joinMode=None,
|
eventUUID=None, category=None, joinMode=None,
|
||||||
endDate=None, endTime=None,
|
endDate=None, endTime=None,
|
||||||
maximumAttendeeCapacity=None,
|
maximumAttendeeCapacity=None,
|
||||||
repliesModerationOption=None,
|
repliesModerationOption=None,
|
||||||
anonymousParticipationEnabled=None,
|
anonymousParticipationEnabled=None,
|
||||||
eventStatus=None, ticketUrl=None) -> {}:
|
eventStatus=None, ticketUrl=None) -> {}:
|
||||||
"""Creates a message
|
"""Creates a message
|
||||||
"""
|
"""
|
||||||
subject = addAutoCW(baseDir, nickname, domain, subject, content)
|
subject = _addAutoCW(baseDir, nickname, domain, subject, content)
|
||||||
|
|
||||||
if nickname != 'news':
|
if nickname != 'news':
|
||||||
mentionedRecipients = \
|
mentionedRecipients = \
|
||||||
|
|
@ -885,7 +885,7 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
if not tagExists(tag['type'], tag['name'], tags):
|
if not tagExists(tag['type'], tag['name'], tags):
|
||||||
tags.append(tag)
|
tags.append(tag)
|
||||||
if isPublic:
|
if isPublic:
|
||||||
updateHashtagsIndex(baseDir, tag, newPostId)
|
_updateHashtagsIndex(baseDir, tag, newPostId)
|
||||||
print('Content tags: ' + str(tags))
|
print('Content tags: ' + str(tags))
|
||||||
|
|
||||||
if inReplyTo and not sensitive:
|
if inReplyTo and not sensitive:
|
||||||
|
|
@ -1031,13 +1031,13 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
attachMedia(baseDir, httpPrefix, domain, port,
|
attachMedia(baseDir, httpPrefix, domain, port,
|
||||||
newPost['object'], attachImageFilename,
|
newPost['object'], attachImageFilename,
|
||||||
mediaType, imageDescription, useBlurhash)
|
mediaType, imageDescription, useBlurhash)
|
||||||
appendEventFields(newPost['object'], eventUUID, eventStatus,
|
_appendEventFields(newPost['object'], eventUUID, eventStatus,
|
||||||
anonymousParticipationEnabled,
|
anonymousParticipationEnabled,
|
||||||
repliesModerationOption,
|
repliesModerationOption,
|
||||||
category, joinMode,
|
category, joinMode,
|
||||||
eventDateStr, endDateStr,
|
eventDateStr, endDateStr,
|
||||||
location, maximumAttendeeCapacity,
|
location, maximumAttendeeCapacity,
|
||||||
ticketUrl, subject)
|
ticketUrl, subject)
|
||||||
else:
|
else:
|
||||||
idStr = \
|
idStr = \
|
||||||
httpPrefix + '://' + domain + '/users/' + nickname + \
|
httpPrefix + '://' + domain + '/users/' + nickname + \
|
||||||
|
|
@ -1079,13 +1079,13 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
attachMedia(baseDir, httpPrefix, domain, port,
|
attachMedia(baseDir, httpPrefix, domain, port,
|
||||||
newPost, attachImageFilename,
|
newPost, attachImageFilename,
|
||||||
mediaType, imageDescription, useBlurhash)
|
mediaType, imageDescription, useBlurhash)
|
||||||
appendEventFields(newPost, eventUUID, eventStatus,
|
_appendEventFields(newPost, eventUUID, eventStatus,
|
||||||
anonymousParticipationEnabled,
|
anonymousParticipationEnabled,
|
||||||
repliesModerationOption,
|
repliesModerationOption,
|
||||||
category, joinMode,
|
category, joinMode,
|
||||||
eventDateStr, endDateStr,
|
eventDateStr, endDateStr,
|
||||||
location, maximumAttendeeCapacity,
|
location, maximumAttendeeCapacity,
|
||||||
ticketUrl, subject)
|
ticketUrl, subject)
|
||||||
if ccUrl:
|
if ccUrl:
|
||||||
if len(ccUrl) > 0:
|
if len(ccUrl) > 0:
|
||||||
newPost['cc'] = [ccUrl]
|
newPost['cc'] = [ccUrl]
|
||||||
|
|
@ -1123,7 +1123,8 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
if schedulePost:
|
if schedulePost:
|
||||||
if eventDate and eventTime:
|
if eventDate and eventTime:
|
||||||
# add an item to the scheduled post index file
|
# add an item to the scheduled post index file
|
||||||
addSchedulePost(baseDir, nickname, domain, eventDateStr, newPostId)
|
_addSchedulePost(baseDir, nickname, domain,
|
||||||
|
eventDateStr, newPostId)
|
||||||
savePostToBox(baseDir, httpPrefix, newPostId,
|
savePostToBox(baseDir, httpPrefix, newPostId,
|
||||||
nickname, domain, newPost, 'scheduled')
|
nickname, domain, newPost, 'scheduled')
|
||||||
else:
|
else:
|
||||||
|
|
@ -1179,10 +1180,10 @@ def outboxMessageCreateWrap(httpPrefix: str,
|
||||||
return newPost
|
return newPost
|
||||||
|
|
||||||
|
|
||||||
def postIsAddressedToFollowers(baseDir: str,
|
def _postIsAddressedToFollowers(baseDir: str,
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
httpPrefix: str,
|
httpPrefix: str,
|
||||||
postJsonObject: {}) -> bool:
|
postJsonObject: {}) -> bool:
|
||||||
"""Returns true if the given post is addressed to followers of the nickname
|
"""Returns true if the given post is addressed to followers of the nickname
|
||||||
"""
|
"""
|
||||||
domainFull = getFullDomain(domain, port)
|
domainFull = getFullDomain(domain, port)
|
||||||
|
|
@ -1227,18 +1228,18 @@ def createPublicPost(baseDir: str,
|
||||||
"""Public post
|
"""Public post
|
||||||
"""
|
"""
|
||||||
domainFull = getFullDomain(domain, port)
|
domainFull = getFullDomain(domain, port)
|
||||||
return createPostBase(baseDir, nickname, domain, port,
|
return _createPostBase(baseDir, nickname, domain, port,
|
||||||
'https://www.w3.org/ns/activitystreams#Public',
|
'https://www.w3.org/ns/activitystreams#Public',
|
||||||
httpPrefix + '://' + domainFull + '/users/' +
|
httpPrefix + '://' + domainFull + '/users/' +
|
||||||
nickname + '/followers',
|
nickname + '/followers',
|
||||||
httpPrefix, content, followersOnly, saveToFile,
|
httpPrefix, content, followersOnly, saveToFile,
|
||||||
clientToServer, commentsEnabled,
|
clientToServer, commentsEnabled,
|
||||||
attachImageFilename, mediaType,
|
attachImageFilename, mediaType,
|
||||||
imageDescription, useBlurhash,
|
imageDescription, useBlurhash,
|
||||||
False, False, inReplyTo, inReplyToAtomUri, subject,
|
False, False, inReplyTo, inReplyToAtomUri, subject,
|
||||||
schedulePost, eventDate, eventTime, location,
|
schedulePost, eventDate, eventTime, location,
|
||||||
None, None, None, None, None,
|
None, None, None, None, None,
|
||||||
None, None, None, None, None)
|
None, None, None, None, None)
|
||||||
|
|
||||||
|
|
||||||
def createBlogPost(baseDir: str,
|
def createBlogPost(baseDir: str,
|
||||||
|
|
@ -1328,18 +1329,18 @@ def createQuestionPost(baseDir: str,
|
||||||
"""
|
"""
|
||||||
domainFull = getFullDomain(domain, port)
|
domainFull = getFullDomain(domain, port)
|
||||||
messageJson = \
|
messageJson = \
|
||||||
createPostBase(baseDir, nickname, domain, port,
|
_createPostBase(baseDir, nickname, domain, port,
|
||||||
'https://www.w3.org/ns/activitystreams#Public',
|
'https://www.w3.org/ns/activitystreams#Public',
|
||||||
httpPrefix + '://' + domainFull + '/users/' +
|
httpPrefix + '://' + domainFull + '/users/' +
|
||||||
nickname + '/followers',
|
nickname + '/followers',
|
||||||
httpPrefix, content, followersOnly, saveToFile,
|
httpPrefix, content, followersOnly, saveToFile,
|
||||||
clientToServer, commentsEnabled,
|
clientToServer, commentsEnabled,
|
||||||
attachImageFilename, mediaType,
|
attachImageFilename, mediaType,
|
||||||
imageDescription, useBlurhash,
|
imageDescription, useBlurhash,
|
||||||
False, False, None, None, subject,
|
False, False, None, None, subject,
|
||||||
False, None, None, None, None, None,
|
False, None, None, None, None, None,
|
||||||
None, None, None,
|
None, None, None,
|
||||||
None, None, None, None, None)
|
None, None, None, None, None)
|
||||||
messageJson['object']['type'] = 'Question'
|
messageJson['object']['type'] = 'Question'
|
||||||
messageJson['object']['oneOf'] = []
|
messageJson['object']['oneOf'] = []
|
||||||
messageJson['object']['votersCount'] = 0
|
messageJson['object']['votersCount'] = 0
|
||||||
|
|
@ -1373,18 +1374,18 @@ def createUnlistedPost(baseDir: 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)
|
||||||
return createPostBase(baseDir, nickname, domain, port,
|
return _createPostBase(baseDir, nickname, domain, port,
|
||||||
httpPrefix + '://' + domainFull + '/users/' +
|
httpPrefix + '://' + domainFull + '/users/' +
|
||||||
nickname + '/followers',
|
nickname + '/followers',
|
||||||
'https://www.w3.org/ns/activitystreams#Public',
|
'https://www.w3.org/ns/activitystreams#Public',
|
||||||
httpPrefix, content, followersOnly, saveToFile,
|
httpPrefix, content, followersOnly, saveToFile,
|
||||||
clientToServer, commentsEnabled,
|
clientToServer, commentsEnabled,
|
||||||
attachImageFilename, mediaType,
|
attachImageFilename, mediaType,
|
||||||
imageDescription, useBlurhash,
|
imageDescription, useBlurhash,
|
||||||
False, False, inReplyTo, inReplyToAtomUri, subject,
|
False, False, inReplyTo, inReplyToAtomUri, subject,
|
||||||
schedulePost, eventDate, eventTime, location,
|
schedulePost, eventDate, eventTime, location,
|
||||||
None, None, None, None, None,
|
None, None, None, None, None,
|
||||||
None, None, None, None, None)
|
None, None, None, None, None)
|
||||||
|
|
||||||
|
|
||||||
def createFollowersOnlyPost(baseDir: str,
|
def createFollowersOnlyPost(baseDir: str,
|
||||||
|
|
@ -1402,18 +1403,18 @@ def createFollowersOnlyPost(baseDir: str,
|
||||||
"""Followers only post
|
"""Followers only post
|
||||||
"""
|
"""
|
||||||
domainFull = getFullDomain(domain, port)
|
domainFull = getFullDomain(domain, port)
|
||||||
return createPostBase(baseDir, nickname, domain, port,
|
return _createPostBase(baseDir, nickname, domain, port,
|
||||||
httpPrefix + '://' + domainFull + '/users/' +
|
httpPrefix + '://' + domainFull + '/users/' +
|
||||||
nickname + '/followers',
|
nickname + '/followers',
|
||||||
None,
|
None,
|
||||||
httpPrefix, content, followersOnly, saveToFile,
|
httpPrefix, content, followersOnly, saveToFile,
|
||||||
clientToServer, commentsEnabled,
|
clientToServer, commentsEnabled,
|
||||||
attachImageFilename, mediaType,
|
attachImageFilename, mediaType,
|
||||||
imageDescription, useBlurhash,
|
imageDescription, useBlurhash,
|
||||||
False, False, inReplyTo, inReplyToAtomUri, subject,
|
False, False, inReplyTo, inReplyToAtomUri, subject,
|
||||||
schedulePost, eventDate, eventTime, location,
|
schedulePost, eventDate, eventTime, location,
|
||||||
None, None, None, None, None,
|
None, None, None, None, None,
|
||||||
None, None, None, None, None)
|
None, None, None, None, None)
|
||||||
|
|
||||||
|
|
||||||
def createEventPost(baseDir: str,
|
def createEventPost(baseDir: str,
|
||||||
|
|
@ -1451,19 +1452,19 @@ def createEventPost(baseDir: str,
|
||||||
if followersOnly:
|
if followersOnly:
|
||||||
toStr1 = toStr2
|
toStr1 = toStr2
|
||||||
toStr2 = None
|
toStr2 = None
|
||||||
return createPostBase(baseDir, nickname, domain, port,
|
return _createPostBase(baseDir, nickname, domain, port,
|
||||||
toStr1, toStr2,
|
toStr1, toStr2,
|
||||||
httpPrefix, content, followersOnly, saveToFile,
|
httpPrefix, content, followersOnly, saveToFile,
|
||||||
clientToServer, commentsEnabled,
|
clientToServer, commentsEnabled,
|
||||||
attachImageFilename, mediaType,
|
attachImageFilename, mediaType,
|
||||||
imageDescription, useBlurhash,
|
imageDescription, useBlurhash,
|
||||||
False, False, None, None, subject,
|
False, False, None, None, subject,
|
||||||
schedulePost, eventDate, eventTime, location,
|
schedulePost, eventDate, eventTime, location,
|
||||||
eventUUID, category, joinMode,
|
eventUUID, category, joinMode,
|
||||||
endDate, endTime, maximumAttendeeCapacity,
|
endDate, endTime, maximumAttendeeCapacity,
|
||||||
repliesModerationOption,
|
repliesModerationOption,
|
||||||
anonymousParticipationEnabled,
|
anonymousParticipationEnabled,
|
||||||
eventStatus, ticketUrl)
|
eventStatus, ticketUrl)
|
||||||
|
|
||||||
|
|
||||||
def getMentionedPeople(baseDir: str, httpPrefix: str,
|
def getMentionedPeople(baseDir: str, httpPrefix: str,
|
||||||
|
|
@ -1526,16 +1527,16 @@ def createDirectMessagePost(baseDir: str,
|
||||||
postTo = None
|
postTo = None
|
||||||
postCc = None
|
postCc = None
|
||||||
messageJson = \
|
messageJson = \
|
||||||
createPostBase(baseDir, nickname, domain, port,
|
_createPostBase(baseDir, nickname, domain, port,
|
||||||
postTo, postCc,
|
postTo, postCc,
|
||||||
httpPrefix, content, followersOnly, saveToFile,
|
httpPrefix, content, followersOnly, saveToFile,
|
||||||
clientToServer, commentsEnabled,
|
clientToServer, commentsEnabled,
|
||||||
attachImageFilename, mediaType,
|
attachImageFilename, mediaType,
|
||||||
imageDescription, useBlurhash,
|
imageDescription, useBlurhash,
|
||||||
False, False, inReplyTo, inReplyToAtomUri, subject,
|
False, False, inReplyTo, inReplyToAtomUri, subject,
|
||||||
schedulePost, eventDate, eventTime, location,
|
schedulePost, eventDate, eventTime, location,
|
||||||
None, None, None, None, None,
|
None, None, None, None, None,
|
||||||
None, None, None, None, None)
|
None, None, None, None, None)
|
||||||
# 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']
|
||||||
|
|
@ -1616,16 +1617,16 @@ def createReportPost(baseDir: str,
|
||||||
handle = toNickname + '@' + domain
|
handle = toNickname + '@' + domain
|
||||||
|
|
||||||
postJsonObject = \
|
postJsonObject = \
|
||||||
createPostBase(baseDir, nickname, domain, port,
|
_createPostBase(baseDir, nickname, domain, port,
|
||||||
toUrl, postCc,
|
toUrl, postCc,
|
||||||
httpPrefix, content, followersOnly, saveToFile,
|
httpPrefix, content, followersOnly, saveToFile,
|
||||||
clientToServer, commentsEnabled,
|
clientToServer, commentsEnabled,
|
||||||
attachImageFilename, mediaType,
|
attachImageFilename, mediaType,
|
||||||
imageDescription, useBlurhash,
|
imageDescription, useBlurhash,
|
||||||
True, False, None, None, subject,
|
True, False, None, None, subject,
|
||||||
False, None, None, None, None, None,
|
False, None, None, None, None, None,
|
||||||
None, None, None,
|
None, None, None,
|
||||||
None, None, None, None, None)
|
None, None, None, None, None)
|
||||||
if not postJsonObject:
|
if not postJsonObject:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -1766,20 +1767,20 @@ def sendPost(projectVersion: str,
|
||||||
# sharedInbox is optional
|
# sharedInbox is optional
|
||||||
|
|
||||||
postJsonObject = \
|
postJsonObject = \
|
||||||
createPostBase(baseDir, nickname, domain, port,
|
_createPostBase(baseDir, nickname, domain, port,
|
||||||
toPersonId, cc, httpPrefix, content,
|
toPersonId, cc, httpPrefix, content,
|
||||||
followersOnly, saveToFile, clientToServer,
|
followersOnly, saveToFile, clientToServer,
|
||||||
commentsEnabled,
|
commentsEnabled,
|
||||||
attachImageFilename, mediaType,
|
attachImageFilename, mediaType,
|
||||||
imageDescription, useBlurhash,
|
imageDescription, useBlurhash,
|
||||||
False, isArticle, inReplyTo,
|
False, isArticle, inReplyTo,
|
||||||
inReplyToAtomUri, subject,
|
inReplyToAtomUri, subject,
|
||||||
False, None, None, None, None, None,
|
False, None, None, None, None, None,
|
||||||
None, None, None,
|
None, None, None,
|
||||||
None, None, None, None, None)
|
None, None, None, None, None)
|
||||||
|
|
||||||
# get the senders private key
|
# get the senders private key
|
||||||
privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private')
|
privateKeyPem = _getPersonKey(nickname, domain, baseDir, 'private')
|
||||||
if len(privateKeyPem) == 0:
|
if len(privateKeyPem) == 0:
|
||||||
return 6
|
return 6
|
||||||
|
|
||||||
|
|
@ -1902,18 +1903,18 @@ def sendPostViaServer(projectVersion: str,
|
||||||
'/users/' + toNickname
|
'/users/' + toNickname
|
||||||
|
|
||||||
postJsonObject = \
|
postJsonObject = \
|
||||||
createPostBase(baseDir,
|
_createPostBase(baseDir,
|
||||||
fromNickname, fromDomain, fromPort,
|
fromNickname, fromDomain, fromPort,
|
||||||
toPersonId, cc, httpPrefix, content,
|
toPersonId, cc, httpPrefix, content,
|
||||||
followersOnly, saveToFile, clientToServer,
|
followersOnly, saveToFile, clientToServer,
|
||||||
commentsEnabled,
|
commentsEnabled,
|
||||||
attachImageFilename, mediaType,
|
attachImageFilename, mediaType,
|
||||||
imageDescription, useBlurhash,
|
imageDescription, useBlurhash,
|
||||||
False, isArticle, inReplyTo,
|
False, isArticle, inReplyTo,
|
||||||
inReplyToAtomUri, subject,
|
inReplyToAtomUri, subject,
|
||||||
False, None, None, None, None, None,
|
False, None, None, None, None, None,
|
||||||
None, None, None,
|
None, None, None,
|
||||||
None, None, None, None, None)
|
None, None, None, None, None)
|
||||||
|
|
||||||
authHeader = createBasicAuthHeader(fromNickname, password)
|
authHeader = createBasicAuthHeader(fromNickname, password)
|
||||||
|
|
||||||
|
|
@ -1969,7 +1970,7 @@ def groupFollowersByDomain(baseDir: str, nickname: str, domain: str) -> {}:
|
||||||
return grouped
|
return grouped
|
||||||
|
|
||||||
|
|
||||||
def addFollowersToPublicPost(postJsonObject: {}) -> None:
|
def _addFollowersToPublicPost(postJsonObject: {}) -> None:
|
||||||
"""Adds followers entry to cc if it doesn't exist
|
"""Adds followers entry to cc if it doesn't exist
|
||||||
"""
|
"""
|
||||||
if not postJsonObject.get('actor'):
|
if not postJsonObject.get('actor'):
|
||||||
|
|
@ -2099,7 +2100,7 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str,
|
||||||
# sharedInbox is optional
|
# sharedInbox is optional
|
||||||
|
|
||||||
# get the senders private key
|
# get the senders private key
|
||||||
privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private', debug)
|
privateKeyPem = _getPersonKey(nickname, domain, baseDir, 'private', debug)
|
||||||
if len(privateKeyPem) == 0:
|
if len(privateKeyPem) == 0:
|
||||||
if debug:
|
if debug:
|
||||||
print('DEBUG: Private key not found for ' +
|
print('DEBUG: Private key not found for ' +
|
||||||
|
|
@ -2112,7 +2113,7 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str,
|
||||||
return 7
|
return 7
|
||||||
postPath = inboxUrl.split(toDomain, 1)[1]
|
postPath = inboxUrl.split(toDomain, 1)[1]
|
||||||
|
|
||||||
addFollowersToPublicPost(postJsonObject)
|
_addFollowersToPublicPost(postJsonObject)
|
||||||
|
|
||||||
if not postJsonObject.get('signature'):
|
if not postJsonObject.get('signature'):
|
||||||
try:
|
try:
|
||||||
|
|
@ -2332,7 +2333,7 @@ def sendToNamedAddresses(session, baseDir: str,
|
||||||
personCache, debug, projectVersion)
|
personCache, debug, projectVersion)
|
||||||
|
|
||||||
|
|
||||||
def hasSharedInbox(session, httpPrefix: str, domain: str) -> bool:
|
def _hasSharedInbox(session, httpPrefix: str, domain: str) -> bool:
|
||||||
"""Returns true if the given domain has a shared inbox
|
"""Returns true if the given domain has a shared inbox
|
||||||
This tries the new and the old way of webfingering the shared inbox
|
This tries the new and the old way of webfingering the shared inbox
|
||||||
"""
|
"""
|
||||||
|
|
@ -2351,7 +2352,7 @@ def hasSharedInbox(session, httpPrefix: str, domain: str) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def sendingProfileUpdate(postJsonObject: {}) -> bool:
|
def _sendingProfileUpdate(postJsonObject: {}) -> bool:
|
||||||
"""Returns true if the given json is a profile update
|
"""Returns true if the given json is a profile update
|
||||||
"""
|
"""
|
||||||
if postJsonObject['type'] != 'Update':
|
if postJsonObject['type'] != 'Update':
|
||||||
|
|
@ -2386,9 +2387,9 @@ def sendToFollowers(session, baseDir: str,
|
||||||
if not session:
|
if not session:
|
||||||
print('WARN: No session for sendToFollowers')
|
print('WARN: No session for sendToFollowers')
|
||||||
return
|
return
|
||||||
if not postIsAddressedToFollowers(baseDir, nickname, domain,
|
if not _postIsAddressedToFollowers(baseDir, nickname, domain,
|
||||||
port, httpPrefix,
|
port, httpPrefix,
|
||||||
postJsonObject):
|
postJsonObject):
|
||||||
if debug:
|
if debug:
|
||||||
print('Post is not addressed to followers')
|
print('Post is not addressed to followers')
|
||||||
return
|
return
|
||||||
|
|
@ -2428,7 +2429,7 @@ def sendToFollowers(session, baseDir: str,
|
||||||
print('Sending post to followers domain is active: ' +
|
print('Sending post to followers domain is active: ' +
|
||||||
followerDomainUrl)
|
followerDomainUrl)
|
||||||
|
|
||||||
withSharedInbox = hasSharedInbox(session, httpPrefix, followerDomain)
|
withSharedInbox = _hasSharedInbox(session, httpPrefix, followerDomain)
|
||||||
if debug:
|
if debug:
|
||||||
if withSharedInbox:
|
if withSharedInbox:
|
||||||
print(followerDomain + ' has shared inbox')
|
print(followerDomain + ' has shared inbox')
|
||||||
|
|
@ -2467,7 +2468,7 @@ def sendToFollowers(session, baseDir: str,
|
||||||
toNickname = 'inbox'
|
toNickname = 'inbox'
|
||||||
|
|
||||||
if toNickname != 'inbox' and postJsonObject.get('type'):
|
if toNickname != 'inbox' and postJsonObject.get('type'):
|
||||||
if sendingProfileUpdate(postJsonObject):
|
if _sendingProfileUpdate(postJsonObject):
|
||||||
print('Sending post to followers ' +
|
print('Sending post to followers ' +
|
||||||
'shared inbox of ' + toDomain)
|
'shared inbox of ' + toDomain)
|
||||||
toNickname = 'inbox'
|
toNickname = 'inbox'
|
||||||
|
|
@ -2554,77 +2555,77 @@ def createInbox(recentPostsCache: {},
|
||||||
session, baseDir: str, nickname: str, domain: str, port: int,
|
session, baseDir: str, nickname: str, domain: str, port: int,
|
||||||
httpPrefix: str, itemsPerPage: int, headerOnly: bool,
|
httpPrefix: str, itemsPerPage: int, headerOnly: bool,
|
||||||
pageNumber=None) -> {}:
|
pageNumber=None) -> {}:
|
||||||
return createBoxIndexed(recentPostsCache,
|
return _createBoxIndexed(recentPostsCache,
|
||||||
session, baseDir, 'inbox',
|
session, baseDir, 'inbox',
|
||||||
nickname, domain, port, httpPrefix,
|
nickname, domain, port, httpPrefix,
|
||||||
itemsPerPage, headerOnly, True,
|
itemsPerPage, headerOnly, True,
|
||||||
0, False, 0, pageNumber)
|
0, False, 0, pageNumber)
|
||||||
|
|
||||||
|
|
||||||
def createBookmarksTimeline(session, baseDir: str, nickname: str, domain: str,
|
def createBookmarksTimeline(session, baseDir: str, nickname: str, domain: str,
|
||||||
port: int, httpPrefix: str, itemsPerPage: int,
|
port: int, httpPrefix: str, itemsPerPage: int,
|
||||||
headerOnly: bool, pageNumber=None) -> {}:
|
headerOnly: bool, pageNumber=None) -> {}:
|
||||||
return createBoxIndexed({}, session, baseDir, 'tlbookmarks',
|
return _createBoxIndexed({}, session, baseDir, 'tlbookmarks',
|
||||||
nickname, domain,
|
nickname, domain,
|
||||||
port, httpPrefix, itemsPerPage, headerOnly,
|
port, httpPrefix, itemsPerPage, headerOnly,
|
||||||
True, 0, False, 0, pageNumber)
|
True, 0, False, 0, pageNumber)
|
||||||
|
|
||||||
|
|
||||||
def createEventsTimeline(recentPostsCache: {},
|
def createEventsTimeline(recentPostsCache: {},
|
||||||
session, baseDir: str, nickname: str, domain: str,
|
session, baseDir: str, nickname: str, domain: str,
|
||||||
port: int, httpPrefix: str, itemsPerPage: int,
|
port: int, httpPrefix: str, itemsPerPage: int,
|
||||||
headerOnly: bool, pageNumber=None) -> {}:
|
headerOnly: bool, pageNumber=None) -> {}:
|
||||||
return createBoxIndexed(recentPostsCache, session, baseDir, 'tlevents',
|
return _createBoxIndexed(recentPostsCache, session, baseDir, 'tlevents',
|
||||||
nickname, domain,
|
nickname, domain,
|
||||||
port, httpPrefix, itemsPerPage, headerOnly,
|
port, httpPrefix, itemsPerPage, headerOnly,
|
||||||
True, 0, False, 0, pageNumber)
|
True, 0, False, 0, pageNumber)
|
||||||
|
|
||||||
|
|
||||||
def createDMTimeline(recentPostsCache: {},
|
def createDMTimeline(recentPostsCache: {},
|
||||||
session, baseDir: str, nickname: str, domain: str,
|
session, baseDir: str, nickname: str, domain: str,
|
||||||
port: int, httpPrefix: str, itemsPerPage: int,
|
port: int, httpPrefix: str, itemsPerPage: int,
|
||||||
headerOnly: bool, pageNumber=None) -> {}:
|
headerOnly: bool, pageNumber=None) -> {}:
|
||||||
return createBoxIndexed(recentPostsCache,
|
return _createBoxIndexed(recentPostsCache,
|
||||||
session, baseDir, 'dm', nickname,
|
session, baseDir, 'dm', nickname,
|
||||||
domain, port, httpPrefix, itemsPerPage,
|
domain, port, httpPrefix, itemsPerPage,
|
||||||
headerOnly, True, 0, False, 0, pageNumber)
|
headerOnly, True, 0, False, 0, pageNumber)
|
||||||
|
|
||||||
|
|
||||||
def createRepliesTimeline(recentPostsCache: {},
|
def createRepliesTimeline(recentPostsCache: {},
|
||||||
session, baseDir: str, nickname: str, domain: str,
|
session, baseDir: str, nickname: str, domain: str,
|
||||||
port: int, httpPrefix: str, itemsPerPage: int,
|
port: int, httpPrefix: str, itemsPerPage: int,
|
||||||
headerOnly: bool, pageNumber=None) -> {}:
|
headerOnly: bool, pageNumber=None) -> {}:
|
||||||
return createBoxIndexed(recentPostsCache, session, baseDir, 'tlreplies',
|
return _createBoxIndexed(recentPostsCache, session, baseDir, 'tlreplies',
|
||||||
nickname, domain, port, httpPrefix,
|
nickname, domain, port, httpPrefix,
|
||||||
itemsPerPage, headerOnly, True,
|
itemsPerPage, headerOnly, True,
|
||||||
0, False, 0, pageNumber)
|
0, False, 0, pageNumber)
|
||||||
|
|
||||||
|
|
||||||
def createBlogsTimeline(session, baseDir: str, nickname: str, domain: str,
|
def createBlogsTimeline(session, baseDir: str, nickname: str, domain: str,
|
||||||
port: int, httpPrefix: str, itemsPerPage: int,
|
port: int, httpPrefix: str, itemsPerPage: int,
|
||||||
headerOnly: bool, pageNumber=None) -> {}:
|
headerOnly: bool, pageNumber=None) -> {}:
|
||||||
return createBoxIndexed({}, session, baseDir, 'tlblogs', nickname,
|
return _createBoxIndexed({}, session, baseDir, 'tlblogs', nickname,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
itemsPerPage, headerOnly, True,
|
itemsPerPage, headerOnly, True,
|
||||||
0, False, 0, pageNumber)
|
0, False, 0, pageNumber)
|
||||||
|
|
||||||
|
|
||||||
def createFeaturesTimeline(session, baseDir: str, nickname: str, domain: str,
|
def createFeaturesTimeline(session, baseDir: str, nickname: str, domain: str,
|
||||||
port: int, httpPrefix: str, itemsPerPage: int,
|
port: int, httpPrefix: str, itemsPerPage: int,
|
||||||
headerOnly: bool, pageNumber=None) -> {}:
|
headerOnly: bool, pageNumber=None) -> {}:
|
||||||
return createBoxIndexed({}, session, baseDir, 'tlfeatures', nickname,
|
return _createBoxIndexed({}, session, baseDir, 'tlfeatures', nickname,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
itemsPerPage, headerOnly, True,
|
itemsPerPage, headerOnly, True,
|
||||||
0, False, 0, pageNumber)
|
0, False, 0, pageNumber)
|
||||||
|
|
||||||
|
|
||||||
def createMediaTimeline(session, baseDir: str, nickname: str, domain: str,
|
def createMediaTimeline(session, baseDir: str, nickname: str, domain: str,
|
||||||
port: int, httpPrefix: str, itemsPerPage: int,
|
port: int, httpPrefix: str, itemsPerPage: int,
|
||||||
headerOnly: bool, pageNumber=None) -> {}:
|
headerOnly: bool, pageNumber=None) -> {}:
|
||||||
return createBoxIndexed({}, session, baseDir, 'tlmedia', nickname,
|
return _createBoxIndexed({}, session, baseDir, 'tlmedia', nickname,
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
itemsPerPage, headerOnly, True,
|
itemsPerPage, headerOnly, True,
|
||||||
0, False, 0, pageNumber)
|
0, False, 0, pageNumber)
|
||||||
|
|
||||||
|
|
||||||
def createNewsTimeline(session, baseDir: str, nickname: str, domain: str,
|
def createNewsTimeline(session, baseDir: str, nickname: str, domain: str,
|
||||||
|
|
@ -2632,21 +2633,21 @@ def createNewsTimeline(session, baseDir: str, nickname: str, domain: str,
|
||||||
headerOnly: bool, newswireVotesThreshold: int,
|
headerOnly: bool, newswireVotesThreshold: int,
|
||||||
positiveVoting: bool, votingTimeMins: int,
|
positiveVoting: bool, votingTimeMins: int,
|
||||||
pageNumber=None) -> {}:
|
pageNumber=None) -> {}:
|
||||||
return createBoxIndexed({}, session, baseDir, 'outbox', 'news',
|
return _createBoxIndexed({}, session, baseDir, 'outbox', 'news',
|
||||||
domain, port, httpPrefix,
|
domain, port, httpPrefix,
|
||||||
itemsPerPage, headerOnly, True,
|
itemsPerPage, headerOnly, True,
|
||||||
newswireVotesThreshold, positiveVoting,
|
newswireVotesThreshold, positiveVoting,
|
||||||
votingTimeMins, pageNumber)
|
votingTimeMins, pageNumber)
|
||||||
|
|
||||||
|
|
||||||
def createOutbox(session, baseDir: str, nickname: str, domain: str,
|
def createOutbox(session, baseDir: str, nickname: str, domain: str,
|
||||||
port: int, httpPrefix: str,
|
port: int, httpPrefix: str,
|
||||||
itemsPerPage: int, headerOnly: bool, authorized: bool,
|
itemsPerPage: int, headerOnly: bool, authorized: bool,
|
||||||
pageNumber=None) -> {}:
|
pageNumber=None) -> {}:
|
||||||
return createBoxIndexed({}, session, baseDir, 'outbox',
|
return _createBoxIndexed({}, session, baseDir, 'outbox',
|
||||||
nickname, domain, port, httpPrefix,
|
nickname, domain, port, httpPrefix,
|
||||||
itemsPerPage, headerOnly, authorized,
|
itemsPerPage, headerOnly, authorized,
|
||||||
0, False, 0, pageNumber)
|
0, False, 0, pageNumber)
|
||||||
|
|
||||||
|
|
||||||
def createModeration(baseDir: str, nickname: str, domain: str, port: int,
|
def createModeration(baseDir: str, nickname: str, domain: str, port: int,
|
||||||
|
|
@ -2816,8 +2817,8 @@ def isReply(postJsonObject: {}, actor: str) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def addPostStringToTimeline(postStr: str, boxname: str,
|
def _addPostStringToTimeline(postStr: str, boxname: str,
|
||||||
postsInBox: [], boxActor: str) -> bool:
|
postsInBox: [], boxActor: str) -> bool:
|
||||||
""" is this a valid timeline post?
|
""" is this a valid timeline post?
|
||||||
"""
|
"""
|
||||||
# must be a recognized ActivityPub type
|
# must be a recognized ActivityPub type
|
||||||
|
|
@ -2853,8 +2854,8 @@ def addPostStringToTimeline(postStr: str, boxname: str,
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def addPostToTimeline(filePath: str, boxname: str,
|
def _addPostToTimeline(filePath: str, boxname: str,
|
||||||
postsInBox: [], boxActor: str) -> bool:
|
postsInBox: [], boxActor: str) -> bool:
|
||||||
""" Reads a post from file and decides whether it is valid
|
""" Reads a post from file and decides whether it is valid
|
||||||
"""
|
"""
|
||||||
with open(filePath, 'r') as postFile:
|
with open(filePath, 'r') as postFile:
|
||||||
|
|
@ -2866,16 +2867,16 @@ def addPostToTimeline(filePath: str, boxname: str,
|
||||||
# append a replies identifier, which will later be removed
|
# append a replies identifier, which will later be removed
|
||||||
postStr += '<hasReplies>'
|
postStr += '<hasReplies>'
|
||||||
|
|
||||||
return addPostStringToTimeline(postStr, boxname, postsInBox, boxActor)
|
return _addPostStringToTimeline(postStr, boxname, postsInBox, boxActor)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def createBoxIndexed(recentPostsCache: {},
|
def _createBoxIndexed(recentPostsCache: {},
|
||||||
session, baseDir: str, boxname: str,
|
session, baseDir: str, boxname: str,
|
||||||
nickname: str, domain: str, port: int, httpPrefix: str,
|
nickname: str, domain: str, port: int, httpPrefix: str,
|
||||||
itemsPerPage: int, headerOnly: bool, authorized: bool,
|
itemsPerPage: int, headerOnly: bool, authorized: bool,
|
||||||
newswireVotesThreshold: int, positiveVoting: bool,
|
newswireVotesThreshold: int, positiveVoting: bool,
|
||||||
votingTimeMins: int, pageNumber=None) -> {}:
|
votingTimeMins: int, pageNumber=None) -> {}:
|
||||||
"""Constructs the box feed for a person with the given nickname
|
"""Constructs the box feed for a person with the given nickname
|
||||||
"""
|
"""
|
||||||
if not authorized or not pageNumber:
|
if not authorized or not pageNumber:
|
||||||
|
|
@ -3006,9 +3007,9 @@ def createBoxIndexed(recentPostsCache: {},
|
||||||
if postUrl in recentPostsCache['index']:
|
if postUrl in recentPostsCache['index']:
|
||||||
if recentPostsCache['json'].get(postUrl):
|
if recentPostsCache['json'].get(postUrl):
|
||||||
url = recentPostsCache['json'][postUrl]
|
url = recentPostsCache['json'][postUrl]
|
||||||
addPostStringToTimeline(url,
|
_addPostStringToTimeline(url,
|
||||||
boxname, postsInBox,
|
boxname, postsInBox,
|
||||||
boxActor)
|
boxActor)
|
||||||
postsCtr += 1
|
postsCtr += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -3017,8 +3018,8 @@ def createBoxIndexed(recentPostsCache: {},
|
||||||
locatePost(baseDir, nickname,
|
locatePost(baseDir, nickname,
|
||||||
domain, postUrl, False)
|
domain, postUrl, False)
|
||||||
if fullPostFilename:
|
if fullPostFilename:
|
||||||
addPostToTimeline(fullPostFilename, boxname,
|
_addPostToTimeline(fullPostFilename, boxname,
|
||||||
postsInBox, boxActor)
|
postsInBox, boxActor)
|
||||||
else:
|
else:
|
||||||
# if this is the features timeline
|
# if this is the features timeline
|
||||||
if timelineNickname != nickname:
|
if timelineNickname != nickname:
|
||||||
|
|
@ -3026,8 +3027,8 @@ def createBoxIndexed(recentPostsCache: {},
|
||||||
locatePost(baseDir, timelineNickname,
|
locatePost(baseDir, timelineNickname,
|
||||||
domain, postUrl, False)
|
domain, postUrl, False)
|
||||||
if fullPostFilename:
|
if fullPostFilename:
|
||||||
addPostToTimeline(fullPostFilename, boxname,
|
_addPostToTimeline(fullPostFilename, boxname,
|
||||||
postsInBox, boxActor)
|
postsInBox, boxActor)
|
||||||
else:
|
else:
|
||||||
print('WARN: unable to locate post ' + postUrl)
|
print('WARN: unable to locate post ' + postUrl)
|
||||||
else:
|
else:
|
||||||
|
|
@ -3314,10 +3315,10 @@ def getPublicPostsOfPerson(baseDir: str, nickname: str, domain: str,
|
||||||
maxMentions = 10
|
maxMentions = 10
|
||||||
maxEmoji = 10
|
maxEmoji = 10
|
||||||
maxAttachments = 5
|
maxAttachments = 5
|
||||||
getPosts(session, personUrl, 30, maxMentions, maxEmoji,
|
_getPosts(session, personUrl, 30, maxMentions, maxEmoji,
|
||||||
maxAttachments, federationList,
|
maxAttachments, federationList,
|
||||||
personCache, raw, simple, debug,
|
personCache, raw, simple, debug,
|
||||||
projectVersion, httpPrefix, domain)
|
projectVersion, httpPrefix, domain)
|
||||||
|
|
||||||
|
|
||||||
def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str,
|
def getPublicPostDomains(session, baseDir: str, nickname: str, domain: str,
|
||||||
|
|
@ -3413,14 +3414,14 @@ def getPublicPostInfo(session, baseDir: str, nickname: str, domain: str,
|
||||||
domainsInfo[d] = []
|
domainsInfo[d] = []
|
||||||
|
|
||||||
blockedPosts = \
|
blockedPosts = \
|
||||||
getPostsForBlockedDomains(baseDir, session, personUrl, maxPosts,
|
_getPostsForBlockedDomains(baseDir, session, personUrl, maxPosts,
|
||||||
maxMentions,
|
maxMentions,
|
||||||
maxEmoji, maxAttachments,
|
maxEmoji, maxAttachments,
|
||||||
federationList,
|
federationList,
|
||||||
personCache,
|
personCache,
|
||||||
debug,
|
debug,
|
||||||
projectVersion, httpPrefix,
|
projectVersion, httpPrefix,
|
||||||
domain)
|
domain)
|
||||||
for blockedDomain, postUrlList in blockedPosts.items():
|
for blockedDomain, postUrlList in blockedPosts.items():
|
||||||
domainsInfo[blockedDomain] += postUrlList
|
domainsInfo[blockedDomain] += postUrlList
|
||||||
|
|
||||||
|
|
@ -3467,8 +3468,8 @@ def getPublicPostDomainsBlocked(session, baseDir: str,
|
||||||
return blockedDomains
|
return blockedDomains
|
||||||
|
|
||||||
|
|
||||||
def getNonMutualsOfPerson(baseDir: str,
|
def _getNonMutualsOfPerson(baseDir: str,
|
||||||
nickname: str, domain: str) -> []:
|
nickname: str, domain: str) -> []:
|
||||||
"""Returns the followers who are not mutuals of a person
|
"""Returns the followers who are not mutuals of a person
|
||||||
i.e. accounts which follow you but you don't follow them
|
i.e. accounts which follow you but you don't follow them
|
||||||
"""
|
"""
|
||||||
|
|
@ -3490,7 +3491,7 @@ def checkDomains(session, baseDir: str,
|
||||||
maxBlockedDomains: int, singleCheck: bool):
|
maxBlockedDomains: int, singleCheck: bool):
|
||||||
"""Checks follower accounts for references to globally blocked domains
|
"""Checks follower accounts for references to globally blocked domains
|
||||||
"""
|
"""
|
||||||
nonMutuals = getNonMutualsOfPerson(baseDir, nickname, domain)
|
nonMutuals = _getNonMutualsOfPerson(baseDir, nickname, domain)
|
||||||
if not nonMutuals:
|
if not nonMutuals:
|
||||||
print('No non-mutual followers were found')
|
print('No non-mutual followers were found')
|
||||||
return
|
return
|
||||||
|
|
@ -3614,7 +3615,7 @@ def populateRepliesJson(baseDir: str, nickname: str, domain: str,
|
||||||
repliesJson['orderedItems'].append(pjo)
|
repliesJson['orderedItems'].append(pjo)
|
||||||
|
|
||||||
|
|
||||||
def rejectAnnounce(announceFilename: str):
|
def _rejectAnnounce(announceFilename: str):
|
||||||
"""Marks an announce as rejected
|
"""Marks an announce as rejected
|
||||||
"""
|
"""
|
||||||
if not os.path.isfile(announceFilename + '.reject'):
|
if not os.path.isfile(announceFilename + '.reject'):
|
||||||
|
|
@ -3699,40 +3700,40 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str,
|
||||||
if not isinstance(announcedJson, dict):
|
if not isinstance(announcedJson, dict):
|
||||||
print('WARN: announce json is not a dict - ' +
|
print('WARN: announce json is not a dict - ' +
|
||||||
postJsonObject['object'])
|
postJsonObject['object'])
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
if not announcedJson.get('id'):
|
if not announcedJson.get('id'):
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
if '/statuses/' not in announcedJson['id']:
|
if '/statuses/' not in announcedJson['id']:
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
if '/users/' not in announcedJson['id'] and \
|
if '/users/' not in announcedJson['id'] and \
|
||||||
'/accounts/' not in announcedJson['id'] and \
|
'/accounts/' not in announcedJson['id'] and \
|
||||||
'/channel/' not in announcedJson['id'] and \
|
'/channel/' not in announcedJson['id'] and \
|
||||||
'/profile/' not in announcedJson['id']:
|
'/profile/' not in announcedJson['id']:
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
if not announcedJson.get('type'):
|
if not announcedJson.get('type'):
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
# pprint(announcedJson)
|
# pprint(announcedJson)
|
||||||
return None
|
return None
|
||||||
if announcedJson['type'] != 'Note' and \
|
if announcedJson['type'] != 'Note' and \
|
||||||
announcedJson['type'] != 'Article':
|
announcedJson['type'] != 'Article':
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
# pprint(announcedJson)
|
# pprint(announcedJson)
|
||||||
return None
|
return None
|
||||||
if not announcedJson.get('content'):
|
if not announcedJson.get('content'):
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
if not announcedJson.get('published'):
|
if not announcedJson.get('published'):
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
if not validPostDate(announcedJson['published']):
|
if not validPostDate(announcedJson['published']):
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
if isFiltered(baseDir, nickname, domain, announcedJson['content']):
|
if isFiltered(baseDir, nickname, domain, announcedJson['content']):
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
# remove any long words
|
# remove any long words
|
||||||
announcedJson['content'] = \
|
announcedJson['content'] = \
|
||||||
|
|
@ -3748,7 +3749,7 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str,
|
||||||
actorNickname, actorDomain, actorPort,
|
actorNickname, actorDomain, actorPort,
|
||||||
announcedJson)
|
announcedJson)
|
||||||
if announcedJson['type'] != 'Create':
|
if announcedJson['type'] != 'Create':
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
# pprint(announcedJson)
|
# pprint(announcedJson)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -3765,7 +3766,7 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str,
|
||||||
attributedDomain = getFullDomain(attributedDomain, attributedPort)
|
attributedDomain = getFullDomain(attributedDomain, attributedPort)
|
||||||
if isBlocked(baseDir, nickname, domain,
|
if isBlocked(baseDir, nickname, domain,
|
||||||
attributedNickname, attributedDomain):
|
attributedNickname, attributedDomain):
|
||||||
rejectAnnounce(announceFilename)
|
_rejectAnnounce(announceFilename)
|
||||||
return None
|
return None
|
||||||
postJsonObject = announcedJson
|
postJsonObject = announcedJson
|
||||||
replaceYouTube(postJsonObject, YTReplacementDomain)
|
replaceYouTube(postJsonObject, YTReplacementDomain)
|
||||||
|
|
|
||||||
22
roles.py
22
roles.py
|
|
@ -63,7 +63,7 @@ def clearEditorStatus(baseDir: str) -> None:
|
||||||
saveJson(actorJson, filename)
|
saveJson(actorJson, filename)
|
||||||
|
|
||||||
|
|
||||||
def addModerator(baseDir: str, nickname: str, domain: str) -> None:
|
def _addModerator(baseDir: str, nickname: str, domain: str) -> None:
|
||||||
"""Adds a moderator nickname to the file
|
"""Adds a moderator nickname to the file
|
||||||
"""
|
"""
|
||||||
if ':' in domain:
|
if ':' in domain:
|
||||||
|
|
@ -92,7 +92,7 @@ def addModerator(baseDir: str, nickname: str, domain: str) -> None:
|
||||||
f.write(nickname + '\n')
|
f.write(nickname + '\n')
|
||||||
|
|
||||||
|
|
||||||
def removeModerator(baseDir: str, nickname: str):
|
def _removeModerator(baseDir: str, nickname: str):
|
||||||
"""Removes a moderator nickname from the file
|
"""Removes a moderator nickname from the file
|
||||||
"""
|
"""
|
||||||
moderatorsFile = baseDir + '/accounts/moderators.txt'
|
moderatorsFile = baseDir + '/accounts/moderators.txt'
|
||||||
|
|
@ -125,7 +125,7 @@ def setRole(baseDir: str, nickname: str, domain: str,
|
||||||
if role:
|
if role:
|
||||||
# add the role
|
# add the role
|
||||||
if project == 'instance' and 'role' == 'moderator':
|
if project == 'instance' and 'role' == 'moderator':
|
||||||
addModerator(baseDir, nickname, domain)
|
_addModerator(baseDir, nickname, domain)
|
||||||
if actorJson['roles'].get(project):
|
if actorJson['roles'].get(project):
|
||||||
if role not in actorJson['roles'][project]:
|
if role not in actorJson['roles'][project]:
|
||||||
actorJson['roles'][project].append(role)
|
actorJson['roles'][project].append(role)
|
||||||
|
|
@ -134,7 +134,7 @@ def setRole(baseDir: str, nickname: str, domain: str,
|
||||||
else:
|
else:
|
||||||
# remove the role
|
# remove the role
|
||||||
if project == 'instance':
|
if project == 'instance':
|
||||||
removeModerator(baseDir, nickname)
|
_removeModerator(baseDir, nickname)
|
||||||
if actorJson['roles'].get(project):
|
if actorJson['roles'].get(project):
|
||||||
actorJson['roles'][project].remove(role)
|
actorJson['roles'][project].remove(role)
|
||||||
# if the project contains no roles then remove it
|
# if the project contains no roles then remove it
|
||||||
|
|
@ -144,8 +144,8 @@ def setRole(baseDir: str, nickname: str, domain: str,
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def getRoles(baseDir: str, nickname: str, domain: str,
|
def _getRoles(baseDir: str, nickname: str, domain: str,
|
||||||
project: str) -> []:
|
project: str) -> []:
|
||||||
"""Returns the roles for a given person on a given project
|
"""Returns the roles for a given person on a given project
|
||||||
"""
|
"""
|
||||||
actorFilename = baseDir + '/accounts/' + \
|
actorFilename = baseDir + '/accounts/' + \
|
||||||
|
|
@ -198,8 +198,8 @@ def outboxDelegate(baseDir: str, authenticatedNickname: str,
|
||||||
# instance delegators can delagate to other projects
|
# instance delegators can delagate to other projects
|
||||||
# than their own
|
# than their own
|
||||||
canDelegate = False
|
canDelegate = False
|
||||||
delegatorRoles = getRoles(baseDir, delegatorNickname,
|
delegatorRoles = _getRoles(baseDir, delegatorNickname,
|
||||||
domain, 'instance')
|
domain, 'instance')
|
||||||
if delegatorRoles:
|
if delegatorRoles:
|
||||||
if 'delegator' in delegatorRoles:
|
if 'delegator' in delegatorRoles:
|
||||||
canDelegate = True
|
canDelegate = True
|
||||||
|
|
@ -207,8 +207,8 @@ def outboxDelegate(baseDir: str, authenticatedNickname: str,
|
||||||
if not canDelegate:
|
if not canDelegate:
|
||||||
canDelegate = True
|
canDelegate = True
|
||||||
# non-instance delegators can only delegate within their project
|
# non-instance delegators can only delegate within their project
|
||||||
delegatorRoles = getRoles(baseDir, delegatorNickname,
|
delegatorRoles = _getRoles(baseDir, delegatorNickname,
|
||||||
domain, project)
|
domain, project)
|
||||||
if delegatorRoles:
|
if delegatorRoles:
|
||||||
if 'delegator' not in delegatorRoles:
|
if 'delegator' not in delegatorRoles:
|
||||||
return False
|
return False
|
||||||
|
|
@ -230,7 +230,7 @@ def outboxDelegate(baseDir: str, authenticatedNickname: str,
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# what roles is this person already assigned to?
|
# what roles is this person already assigned to?
|
||||||
existingRoles = getRoles(baseDir, nickname, domain, project)
|
existingRoles = _getRoles(baseDir, nickname, domain, project)
|
||||||
if existingRoles:
|
if existingRoles:
|
||||||
if role in existingRoles:
|
if role in existingRoles:
|
||||||
if debug:
|
if debug:
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ from utils import loadJson
|
||||||
from outbox import postMessageToOutbox
|
from outbox import postMessageToOutbox
|
||||||
|
|
||||||
|
|
||||||
def updatePostSchedule(baseDir: str, handle: str, httpd,
|
def _updatePostSchedule(baseDir: str, handle: str, httpd,
|
||||||
maxScheduledPosts: int) -> None:
|
maxScheduledPosts: int) -> None:
|
||||||
"""Checks if posts are due to be delivered and if so moves them to the outbox
|
"""Checks if posts are due to be delivered and if so moves them to the outbox
|
||||||
"""
|
"""
|
||||||
scheduleIndexFilename = baseDir + '/accounts/' + handle + '/schedule.index'
|
scheduleIndexFilename = baseDir + '/accounts/' + handle + '/schedule.index'
|
||||||
|
|
@ -145,7 +145,7 @@ def runPostSchedule(baseDir: str, httpd, maxScheduledPosts: int):
|
||||||
baseDir + '/accounts/' + account + '/schedule.index'
|
baseDir + '/accounts/' + account + '/schedule.index'
|
||||||
if not os.path.isfile(scheduleIndexFilename):
|
if not os.path.isfile(scheduleIndexFilename):
|
||||||
continue
|
continue
|
||||||
updatePostSchedule(baseDir, account, httpd, maxScheduledPosts)
|
_updatePostSchedule(baseDir, account, httpd, maxScheduledPosts)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -176,11 +176,11 @@ def expireShares(baseDir: str) -> None:
|
||||||
continue
|
continue
|
||||||
nickname = account.split('@')[0]
|
nickname = account.split('@')[0]
|
||||||
domain = account.split('@')[1]
|
domain = account.split('@')[1]
|
||||||
expireSharesForAccount(baseDir, nickname, domain)
|
_expireSharesForAccount(baseDir, nickname, domain)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def expireSharesForAccount(baseDir: str, nickname: str, domain: str) -> None:
|
def _expireSharesForAccount(baseDir: str, nickname: str, domain: str) -> None:
|
||||||
"""Removes expired items from shares for a particular account
|
"""Removes expired items from shares for a particular account
|
||||||
"""
|
"""
|
||||||
handleDomain = domain
|
handleDomain = domain
|
||||||
|
|
|
||||||
23
tests.py
23
tests.py
|
|
@ -101,7 +101,7 @@ thrBob = None
|
||||||
thrEve = None
|
thrEve = None
|
||||||
|
|
||||||
|
|
||||||
def testHttpsigBase(withDigest):
|
def _testHttpsigBase(withDigest):
|
||||||
print('testHttpsig(' + str(withDigest) + ')')
|
print('testHttpsig(' + str(withDigest) + ')')
|
||||||
|
|
||||||
baseDir = os.getcwd()
|
baseDir = os.getcwd()
|
||||||
|
|
@ -206,8 +206,8 @@ def testHttpsigBase(withDigest):
|
||||||
|
|
||||||
|
|
||||||
def testHttpsig():
|
def testHttpsig():
|
||||||
testHttpsigBase(True)
|
_testHttpsigBase(True)
|
||||||
testHttpsigBase(False)
|
_testHttpsigBase(False)
|
||||||
|
|
||||||
|
|
||||||
def testCache():
|
def testCache():
|
||||||
|
|
@ -2617,6 +2617,11 @@ def testFunctions():
|
||||||
excludeImports = [
|
excludeImports = [
|
||||||
'link'
|
'link'
|
||||||
]
|
]
|
||||||
|
excludeLocal = [
|
||||||
|
'pyjsonld',
|
||||||
|
'daemon',
|
||||||
|
'tests'
|
||||||
|
]
|
||||||
# check that functions are called somewhere
|
# check that functions are called somewhere
|
||||||
for name, properties in functionProperties.items():
|
for name, properties in functionProperties.items():
|
||||||
if name in exclusions:
|
if name in exclusions:
|
||||||
|
|
@ -2626,6 +2631,16 @@ def testFunctions():
|
||||||
' in module ' + properties['module'] +
|
' in module ' + properties['module'] +
|
||||||
' is not called anywhere')
|
' is not called anywhere')
|
||||||
assert properties['calledInModule']
|
assert properties['calledInModule']
|
||||||
|
|
||||||
|
if len(properties['calledInModule']) == 1:
|
||||||
|
modName = properties['calledInModule'][0]
|
||||||
|
if modName not in excludeLocal and \
|
||||||
|
modName == properties['module']:
|
||||||
|
if not name.startswith('_'):
|
||||||
|
print('Local function ' + name +
|
||||||
|
' in ' + modName + ' does not begin with _')
|
||||||
|
assert False
|
||||||
|
|
||||||
if name not in excludeImports:
|
if name not in excludeImports:
|
||||||
for modName in properties['calledInModule']:
|
for modName in properties['calledInModule']:
|
||||||
if modName == properties['module']:
|
if modName == properties['module']:
|
||||||
|
|
@ -2635,8 +2650,6 @@ def testFunctions():
|
||||||
print(importStr + ' not found in ' + modName + '.py')
|
print(importStr + ' not found in ' + modName + '.py')
|
||||||
assert False
|
assert False
|
||||||
print('Function: ' + name + ' ✓')
|
print('Function: ' + name + ' ✓')
|
||||||
# print(str(function))
|
|
||||||
# print(str(functionProperties))
|
|
||||||
|
|
||||||
|
|
||||||
def runAllTests():
|
def runAllTests():
|
||||||
|
|
|
||||||
108
theme.py
108
theme.py
|
|
@ -14,7 +14,7 @@ from shutil import copyfile
|
||||||
from content import dangerousCSS
|
from content import dangerousCSS
|
||||||
|
|
||||||
|
|
||||||
def getThemeFiles() -> []:
|
def _getThemeFiles() -> []:
|
||||||
return ('epicyon.css', 'login.css', 'follow.css',
|
return ('epicyon.css', 'login.css', 'follow.css',
|
||||||
'suspended.css', 'calendar.css', 'blog.css',
|
'suspended.css', 'calendar.css', 'blog.css',
|
||||||
'options.css', 'search.css', 'links.css')
|
'options.css', 'search.css', 'links.css')
|
||||||
|
|
@ -38,7 +38,7 @@ def getThemesList(baseDir: str) -> []:
|
||||||
return themes
|
return themes
|
||||||
|
|
||||||
|
|
||||||
def setThemeInConfig(baseDir: str, name: str) -> bool:
|
def _setThemeInConfig(baseDir: str, name: str) -> bool:
|
||||||
configFilename = baseDir + '/config.json'
|
configFilename = baseDir + '/config.json'
|
||||||
if not os.path.isfile(configFilename):
|
if not os.path.isfile(configFilename):
|
||||||
return False
|
return False
|
||||||
|
|
@ -49,7 +49,7 @@ def setThemeInConfig(baseDir: str, name: str) -> bool:
|
||||||
return saveJson(configJson, configFilename)
|
return saveJson(configJson, configFilename)
|
||||||
|
|
||||||
|
|
||||||
def setNewswirePublishAsIcon(baseDir: str, useIcon: bool) -> bool:
|
def _setNewswirePublishAsIcon(baseDir: str, useIcon: bool) -> bool:
|
||||||
"""Shows the newswire publish action as an icon or a button
|
"""Shows the newswire publish action as an icon or a button
|
||||||
"""
|
"""
|
||||||
configFilename = baseDir + '/config.json'
|
configFilename = baseDir + '/config.json'
|
||||||
|
|
@ -62,7 +62,7 @@ def setNewswirePublishAsIcon(baseDir: str, useIcon: bool) -> bool:
|
||||||
return saveJson(configJson, configFilename)
|
return saveJson(configJson, configFilename)
|
||||||
|
|
||||||
|
|
||||||
def setIconsAsButtons(baseDir: str, useButtons: bool) -> bool:
|
def _setIconsAsButtons(baseDir: str, useButtons: bool) -> bool:
|
||||||
"""Whether to show icons in the header (inbox, outbox, etc)
|
"""Whether to show icons in the header (inbox, outbox, etc)
|
||||||
as buttons
|
as buttons
|
||||||
"""
|
"""
|
||||||
|
|
@ -76,7 +76,7 @@ def setIconsAsButtons(baseDir: str, useButtons: bool) -> bool:
|
||||||
return saveJson(configJson, configFilename)
|
return saveJson(configJson, configFilename)
|
||||||
|
|
||||||
|
|
||||||
def setRssIconAtTop(baseDir: str, atTop: bool) -> bool:
|
def _setRssIconAtTop(baseDir: str, atTop: bool) -> bool:
|
||||||
"""Whether to show RSS icon at the top of the timeline
|
"""Whether to show RSS icon at the top of the timeline
|
||||||
"""
|
"""
|
||||||
configFilename = baseDir + '/config.json'
|
configFilename = baseDir + '/config.json'
|
||||||
|
|
@ -89,7 +89,7 @@ def setRssIconAtTop(baseDir: str, atTop: bool) -> bool:
|
||||||
return saveJson(configJson, configFilename)
|
return saveJson(configJson, configFilename)
|
||||||
|
|
||||||
|
|
||||||
def setPublishButtonAtTop(baseDir: str, atTop: bool) -> bool:
|
def _setPublishButtonAtTop(baseDir: str, atTop: bool) -> bool:
|
||||||
"""Whether to show the publish button above the title image
|
"""Whether to show the publish button above the title image
|
||||||
in the newswire column
|
in the newswire column
|
||||||
"""
|
"""
|
||||||
|
|
@ -103,7 +103,7 @@ def setPublishButtonAtTop(baseDir: str, atTop: bool) -> bool:
|
||||||
return saveJson(configJson, configFilename)
|
return saveJson(configJson, configFilename)
|
||||||
|
|
||||||
|
|
||||||
def setFullWidthTimelineButtonHeader(baseDir: str, fullWidth: bool) -> bool:
|
def _setFullWidthTimelineButtonHeader(baseDir: str, fullWidth: bool) -> bool:
|
||||||
"""Shows the timeline button header containing inbox, outbox,
|
"""Shows the timeline button header containing inbox, outbox,
|
||||||
calendar, etc as full width
|
calendar, etc as full width
|
||||||
"""
|
"""
|
||||||
|
|
@ -127,8 +127,8 @@ def getTheme(baseDir: str) -> str:
|
||||||
return 'default'
|
return 'default'
|
||||||
|
|
||||||
|
|
||||||
def removeTheme(baseDir: str):
|
def _removeTheme(baseDir: str):
|
||||||
themeFiles = getThemeFiles()
|
themeFiles = _getThemeFiles()
|
||||||
for filename in themeFiles:
|
for filename in themeFiles:
|
||||||
if os.path.isfile(baseDir + '/' + filename):
|
if os.path.isfile(baseDir + '/' + filename):
|
||||||
os.remove(baseDir + '/' + filename)
|
os.remove(baseDir + '/' + filename)
|
||||||
|
|
@ -183,14 +183,14 @@ def setCSSparam(css: str, param: str, value: str) -> str:
|
||||||
return newcss.strip()
|
return newcss.strip()
|
||||||
|
|
||||||
|
|
||||||
def setThemeFromDict(baseDir: str, name: str,
|
def _setThemeFromDict(baseDir: str, name: str,
|
||||||
themeParams: {}, bgParams: {},
|
themeParams: {}, bgParams: {},
|
||||||
allowLocalNetworkAccess: bool) -> None:
|
allowLocalNetworkAccess: bool) -> None:
|
||||||
"""Uses a dictionary to set a theme
|
"""Uses a dictionary to set a theme
|
||||||
"""
|
"""
|
||||||
if name:
|
if name:
|
||||||
setThemeInConfig(baseDir, name)
|
_setThemeInConfig(baseDir, name)
|
||||||
themeFiles = getThemeFiles()
|
themeFiles = _getThemeFiles()
|
||||||
for filename in themeFiles:
|
for filename in themeFiles:
|
||||||
# check for custom css within the theme directory
|
# check for custom css within the theme directory
|
||||||
templateFilename = baseDir + '/theme/' + name + '/epicyon-' + filename
|
templateFilename = baseDir + '/theme/' + name + '/epicyon-' + filename
|
||||||
|
|
@ -215,33 +215,33 @@ def setThemeFromDict(baseDir: str, name: str,
|
||||||
for paramName, paramValue in themeParams.items():
|
for paramName, paramValue in themeParams.items():
|
||||||
if paramName == 'newswire-publish-icon':
|
if paramName == 'newswire-publish-icon':
|
||||||
if paramValue.lower() == 'true':
|
if paramValue.lower() == 'true':
|
||||||
setNewswirePublishAsIcon(baseDir, True)
|
_setNewswirePublishAsIcon(baseDir, True)
|
||||||
else:
|
else:
|
||||||
setNewswirePublishAsIcon(baseDir, False)
|
_setNewswirePublishAsIcon(baseDir, False)
|
||||||
continue
|
continue
|
||||||
elif paramName == 'full-width-timeline-buttons':
|
elif paramName == 'full-width-timeline-buttons':
|
||||||
if paramValue.lower() == 'true':
|
if paramValue.lower() == 'true':
|
||||||
setFullWidthTimelineButtonHeader(baseDir, True)
|
_setFullWidthTimelineButtonHeader(baseDir, True)
|
||||||
else:
|
else:
|
||||||
setFullWidthTimelineButtonHeader(baseDir, False)
|
_setFullWidthTimelineButtonHeader(baseDir, False)
|
||||||
continue
|
continue
|
||||||
elif paramName == 'icons-as-buttons':
|
elif paramName == 'icons-as-buttons':
|
||||||
if paramValue.lower() == 'true':
|
if paramValue.lower() == 'true':
|
||||||
setIconsAsButtons(baseDir, True)
|
_setIconsAsButtons(baseDir, True)
|
||||||
else:
|
else:
|
||||||
setIconsAsButtons(baseDir, False)
|
_setIconsAsButtons(baseDir, False)
|
||||||
continue
|
continue
|
||||||
elif paramName == 'rss-icon-at-top':
|
elif paramName == 'rss-icon-at-top':
|
||||||
if paramValue.lower() == 'true':
|
if paramValue.lower() == 'true':
|
||||||
setRssIconAtTop(baseDir, True)
|
_setRssIconAtTop(baseDir, True)
|
||||||
else:
|
else:
|
||||||
setRssIconAtTop(baseDir, False)
|
_setRssIconAtTop(baseDir, False)
|
||||||
continue
|
continue
|
||||||
elif paramName == 'publish-button-at-top':
|
elif paramName == 'publish-button-at-top':
|
||||||
if paramValue.lower() == 'true':
|
if paramValue.lower() == 'true':
|
||||||
setPublishButtonAtTop(baseDir, True)
|
_setPublishButtonAtTop(baseDir, True)
|
||||||
else:
|
else:
|
||||||
setPublishButtonAtTop(baseDir, False)
|
_setPublishButtonAtTop(baseDir, False)
|
||||||
continue
|
continue
|
||||||
css = setCSSparam(css, paramName, paramValue)
|
css = setCSSparam(css, paramName, paramValue)
|
||||||
filename = baseDir + '/' + filename
|
filename = baseDir + '/' + filename
|
||||||
|
|
@ -249,17 +249,17 @@ def setThemeFromDict(baseDir: str, name: str,
|
||||||
cssfile.write(css)
|
cssfile.write(css)
|
||||||
|
|
||||||
if bgParams.get('login'):
|
if bgParams.get('login'):
|
||||||
setBackgroundFormat(baseDir, name, 'login', bgParams['login'])
|
_setBackgroundFormat(baseDir, name, 'login', bgParams['login'])
|
||||||
if bgParams.get('follow'):
|
if bgParams.get('follow'):
|
||||||
setBackgroundFormat(baseDir, name, 'follow', bgParams['follow'])
|
_setBackgroundFormat(baseDir, name, 'follow', bgParams['follow'])
|
||||||
if bgParams.get('options'):
|
if bgParams.get('options'):
|
||||||
setBackgroundFormat(baseDir, name, 'options', bgParams['options'])
|
_setBackgroundFormat(baseDir, name, 'options', bgParams['options'])
|
||||||
if bgParams.get('search'):
|
if bgParams.get('search'):
|
||||||
setBackgroundFormat(baseDir, name, 'search', bgParams['search'])
|
_setBackgroundFormat(baseDir, name, 'search', bgParams['search'])
|
||||||
|
|
||||||
|
|
||||||
def setBackgroundFormat(baseDir: str, name: str,
|
def _setBackgroundFormat(baseDir: str, name: str,
|
||||||
backgroundType: str, extension: str) -> None:
|
backgroundType: str, extension: str) -> None:
|
||||||
"""Sets the background file extension
|
"""Sets the background file extension
|
||||||
"""
|
"""
|
||||||
if extension == 'jpg':
|
if extension == 'jpg':
|
||||||
|
|
@ -277,7 +277,7 @@ def setBackgroundFormat(baseDir: str, name: str,
|
||||||
def enableGrayscale(baseDir: str) -> None:
|
def enableGrayscale(baseDir: str) -> None:
|
||||||
"""Enables grayscale for the current theme
|
"""Enables grayscale for the current theme
|
||||||
"""
|
"""
|
||||||
themeFiles = getThemeFiles()
|
themeFiles = _getThemeFiles()
|
||||||
for filename in themeFiles:
|
for filename in themeFiles:
|
||||||
templateFilename = baseDir + '/' + filename
|
templateFilename = baseDir + '/' + filename
|
||||||
if not os.path.isfile(templateFilename):
|
if not os.path.isfile(templateFilename):
|
||||||
|
|
@ -300,7 +300,7 @@ def enableGrayscale(baseDir: str) -> None:
|
||||||
def disableGrayscale(baseDir: str) -> None:
|
def disableGrayscale(baseDir: str) -> None:
|
||||||
"""Disables grayscale for the current theme
|
"""Disables grayscale for the current theme
|
||||||
"""
|
"""
|
||||||
themeFiles = getThemeFiles()
|
themeFiles = _getThemeFiles()
|
||||||
for filename in themeFiles:
|
for filename in themeFiles:
|
||||||
templateFilename = baseDir + '/' + filename
|
templateFilename = baseDir + '/' + filename
|
||||||
if not os.path.isfile(templateFilename):
|
if not os.path.isfile(templateFilename):
|
||||||
|
|
@ -318,7 +318,7 @@ def disableGrayscale(baseDir: str) -> None:
|
||||||
os.remove(grayscaleFilename)
|
os.remove(grayscaleFilename)
|
||||||
|
|
||||||
|
|
||||||
def setCustomFont(baseDir: str):
|
def _setCustomFont(baseDir: str):
|
||||||
"""Uses a dictionary to set a theme
|
"""Uses a dictionary to set a theme
|
||||||
"""
|
"""
|
||||||
customFontExt = None
|
customFontExt = None
|
||||||
|
|
@ -337,7 +337,7 @@ def setCustomFont(baseDir: str):
|
||||||
if not customFontExt:
|
if not customFontExt:
|
||||||
return
|
return
|
||||||
|
|
||||||
themeFiles = getThemeFiles()
|
themeFiles = _getThemeFiles()
|
||||||
for filename in themeFiles:
|
for filename in themeFiles:
|
||||||
templateFilename = baseDir + '/' + filename
|
templateFilename = baseDir + '/' + filename
|
||||||
if not os.path.isfile(templateFilename):
|
if not os.path.isfile(templateFilename):
|
||||||
|
|
@ -356,9 +356,9 @@ def setCustomFont(baseDir: str):
|
||||||
cssfile.write(css)
|
cssfile.write(css)
|
||||||
|
|
||||||
|
|
||||||
def readVariablesFile(baseDir: str, themeName: str,
|
def _readVariablesFile(baseDir: str, themeName: str,
|
||||||
variablesFile: str,
|
variablesFile: str,
|
||||||
allowLocalNetworkAccess: bool) -> None:
|
allowLocalNetworkAccess: bool) -> None:
|
||||||
"""Reads variables from a file in the theme directory
|
"""Reads variables from a file in the theme directory
|
||||||
"""
|
"""
|
||||||
themeParams = loadJson(variablesFile, 0)
|
themeParams = loadJson(variablesFile, 0)
|
||||||
|
|
@ -370,14 +370,14 @@ def readVariablesFile(baseDir: str, themeName: str,
|
||||||
"options": "jpg",
|
"options": "jpg",
|
||||||
"search": "jpg"
|
"search": "jpg"
|
||||||
}
|
}
|
||||||
setThemeFromDict(baseDir, themeName, themeParams, bgParams,
|
_setThemeFromDict(baseDir, themeName, themeParams, bgParams,
|
||||||
allowLocalNetworkAccess)
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def setThemeDefault(baseDir: str, allowLocalNetworkAccess: bool):
|
def _setThemeDefault(baseDir: str, allowLocalNetworkAccess: bool):
|
||||||
name = 'default'
|
name = 'default'
|
||||||
removeTheme(baseDir)
|
_removeTheme(baseDir)
|
||||||
setThemeInConfig(baseDir, name)
|
_setThemeInConfig(baseDir, name)
|
||||||
bgParams = {
|
bgParams = {
|
||||||
"login": "jpg",
|
"login": "jpg",
|
||||||
"follow": "jpg",
|
"follow": "jpg",
|
||||||
|
|
@ -394,11 +394,11 @@ def setThemeDefault(baseDir: str, allowLocalNetworkAccess: bool):
|
||||||
"banner-height-mobile": "10vh",
|
"banner-height-mobile": "10vh",
|
||||||
"search-banner-height-mobile": "15vh"
|
"search-banner-height-mobile": "15vh"
|
||||||
}
|
}
|
||||||
setThemeFromDict(baseDir, name, themeParams, bgParams,
|
_setThemeFromDict(baseDir, name, themeParams, bgParams,
|
||||||
allowLocalNetworkAccess)
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
|
|
||||||
def setThemeFonts(baseDir: str, themeName: str) -> None:
|
def _setThemeFonts(baseDir: str, themeName: str) -> None:
|
||||||
"""Adds custom theme fonts
|
"""Adds custom theme fonts
|
||||||
"""
|
"""
|
||||||
themeNameLower = themeName.lower()
|
themeNameLower = themeName.lower()
|
||||||
|
|
@ -422,7 +422,7 @@ def setThemeFonts(baseDir: str, themeName: str) -> None:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def setThemeImages(baseDir: str, name: str) -> None:
|
def _setThemeImages(baseDir: str, name: str) -> None:
|
||||||
"""Changes the profile background image
|
"""Changes the profile background image
|
||||||
and banner to the defaults
|
and banner to the defaults
|
||||||
"""
|
"""
|
||||||
|
|
@ -557,7 +557,7 @@ def setTheme(baseDir: str, name: str, domain: str,
|
||||||
result = False
|
result = False
|
||||||
|
|
||||||
prevThemeName = getTheme(baseDir)
|
prevThemeName = getTheme(baseDir)
|
||||||
removeTheme(baseDir)
|
_removeTheme(baseDir)
|
||||||
|
|
||||||
themes = getThemesList(baseDir)
|
themes = getThemesList(baseDir)
|
||||||
for themeName in themes:
|
for themeName in themes:
|
||||||
|
|
@ -573,21 +573,21 @@ def setTheme(baseDir: str, name: str, domain: str,
|
||||||
if prevThemeName.lower() != themeNameLower:
|
if prevThemeName.lower() != themeNameLower:
|
||||||
# change the banner and profile image
|
# change the banner and profile image
|
||||||
# to the default for the theme
|
# to the default for the theme
|
||||||
setThemeImages(baseDir, name)
|
_setThemeImages(baseDir, name)
|
||||||
setThemeFonts(baseDir, name)
|
_setThemeFonts(baseDir, name)
|
||||||
result = True
|
result = True
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
# default
|
# default
|
||||||
setThemeDefault(baseDir)
|
_setThemeDefault(baseDir)
|
||||||
result = True
|
result = True
|
||||||
|
|
||||||
variablesFile = baseDir + '/theme/' + name + '/theme.json'
|
variablesFile = baseDir + '/theme/' + name + '/theme.json'
|
||||||
if os.path.isfile(variablesFile):
|
if os.path.isfile(variablesFile):
|
||||||
readVariablesFile(baseDir, name, variablesFile,
|
_readVariablesFile(baseDir, name, variablesFile,
|
||||||
allowLocalNetworkAccess)
|
allowLocalNetworkAccess)
|
||||||
|
|
||||||
setCustomFont(baseDir)
|
_setCustomFont(baseDir)
|
||||||
|
|
||||||
# set the news avatar
|
# set the news avatar
|
||||||
newsAvatarThemeFilename = \
|
newsAvatarThemeFilename = \
|
||||||
|
|
@ -604,5 +604,5 @@ def setTheme(baseDir: str, name: str, domain: str,
|
||||||
else:
|
else:
|
||||||
disableGrayscale(baseDir)
|
disableGrayscale(baseDir)
|
||||||
|
|
||||||
setThemeInConfig(baseDir, name)
|
_setThemeInConfig(baseDir, name)
|
||||||
return result
|
return result
|
||||||
|
|
|
||||||
27
utils.py
27
utils.py
|
|
@ -197,7 +197,7 @@ def isSystemAccount(nickname: str) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def createConfig(baseDir: str) -> None:
|
def _createConfig(baseDir: str) -> None:
|
||||||
"""Creates a configuration file
|
"""Creates a configuration file
|
||||||
"""
|
"""
|
||||||
configFilename = baseDir + '/config.json'
|
configFilename = baseDir + '/config.json'
|
||||||
|
|
@ -211,7 +211,7 @@ def createConfig(baseDir: str) -> None:
|
||||||
def setConfigParam(baseDir: str, variableName: str, variableValue) -> None:
|
def setConfigParam(baseDir: str, variableName: str, variableValue) -> None:
|
||||||
"""Sets a configuration value
|
"""Sets a configuration value
|
||||||
"""
|
"""
|
||||||
createConfig(baseDir)
|
_createConfig(baseDir)
|
||||||
configFilename = baseDir + '/config.json'
|
configFilename = baseDir + '/config.json'
|
||||||
configJson = {}
|
configJson = {}
|
||||||
if os.path.isfile(configFilename):
|
if os.path.isfile(configFilename):
|
||||||
|
|
@ -223,7 +223,7 @@ def setConfigParam(baseDir: str, variableName: str, variableValue) -> None:
|
||||||
def getConfigParam(baseDir: str, variableName: str):
|
def getConfigParam(baseDir: str, variableName: str):
|
||||||
"""Gets a configuration value
|
"""Gets a configuration value
|
||||||
"""
|
"""
|
||||||
createConfig(baseDir)
|
_createConfig(baseDir)
|
||||||
configFilename = baseDir + '/config.json'
|
configFilename = baseDir + '/config.json'
|
||||||
configJson = loadJson(configFilename)
|
configJson = loadJson(configFilename)
|
||||||
if configJson:
|
if configJson:
|
||||||
|
|
@ -610,8 +610,8 @@ def getDomainFromActor(actor: str) -> (str, int):
|
||||||
return domain, port
|
return domain, port
|
||||||
|
|
||||||
|
|
||||||
def setDefaultPetName(baseDir: str, nickname: str, domain: str,
|
def _setDefaultPetName(baseDir: str, nickname: str, domain: str,
|
||||||
followNickname: str, followDomain: str) -> None:
|
followNickname: str, followDomain: str) -> None:
|
||||||
"""Sets a default petname
|
"""Sets a default petname
|
||||||
This helps especially when using onion or i2p address
|
This helps especially when using onion or i2p address
|
||||||
"""
|
"""
|
||||||
|
|
@ -723,8 +723,8 @@ def followPerson(baseDir: str, nickname: str, domain: str,
|
||||||
addPersonToCalendar(baseDir, nickname, domain,
|
addPersonToCalendar(baseDir, nickname, domain,
|
||||||
followNickname, followDomain)
|
followNickname, followDomain)
|
||||||
# add a default petname
|
# add a default petname
|
||||||
setDefaultPetName(baseDir, nickname, domain,
|
_setDefaultPetName(baseDir, nickname, domain,
|
||||||
followNickname, followDomain)
|
followNickname, followDomain)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -864,7 +864,8 @@ def locatePost(baseDir: str, nickname: str, domain: str,
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def removeAttachment(baseDir: str, httpPrefix: str, domain: str, postJson: {}):
|
def _removeAttachment(baseDir: str, httpPrefix: str, domain: str,
|
||||||
|
postJson: {}):
|
||||||
if not postJson.get('attachment'):
|
if not postJson.get('attachment'):
|
||||||
return
|
return
|
||||||
if not postJson['attachment'][0].get('url'):
|
if not postJson['attachment'][0].get('url'):
|
||||||
|
|
@ -907,8 +908,8 @@ def removeModerationPostFromIndex(baseDir: str, postUrl: str,
|
||||||
' from moderation index')
|
' from moderation index')
|
||||||
|
|
||||||
|
|
||||||
def isReplyToBlogPost(baseDir: str, nickname: str, domain: str,
|
def _isReplyToBlogPost(baseDir: str, nickname: str, domain: str,
|
||||||
postJsonObject: str):
|
postJsonObject: str):
|
||||||
"""Is the given post a reply to a blog post?
|
"""Is the given post a reply to a blog post?
|
||||||
"""
|
"""
|
||||||
if not postJsonObject.get('object'):
|
if not postJsonObject.get('object'):
|
||||||
|
|
@ -947,8 +948,8 @@ def deletePost(baseDir: str, httpPrefix: str,
|
||||||
return
|
return
|
||||||
|
|
||||||
# don't remove replies to blog posts
|
# don't remove replies to blog posts
|
||||||
if isReplyToBlogPost(baseDir, nickname, domain,
|
if _isReplyToBlogPost(baseDir, nickname, domain,
|
||||||
postJsonObject):
|
postJsonObject):
|
||||||
return
|
return
|
||||||
|
|
||||||
# remove from recent posts cache in memory
|
# remove from recent posts cache in memory
|
||||||
|
|
@ -966,7 +967,7 @@ def deletePost(baseDir: str, httpPrefix: str,
|
||||||
del recentPostsCache['html'][postId]
|
del recentPostsCache['html'][postId]
|
||||||
|
|
||||||
# remove any attachment
|
# remove any attachment
|
||||||
removeAttachment(baseDir, httpPrefix, domain, postJsonObject)
|
_removeAttachment(baseDir, httpPrefix, domain, postJsonObject)
|
||||||
|
|
||||||
extensions = ('votes', 'arrived', 'muted')
|
extensions = ('votes', 'arrived', 'muted')
|
||||||
for ext in extensions:
|
for ext in extensions:
|
||||||
|
|
|
||||||
|
|
@ -89,11 +89,11 @@ def htmlCalendarDeleteConfirm(cssCache: {}, translate: {}, baseDir: str,
|
||||||
return deletePostStr
|
return deletePostStr
|
||||||
|
|
||||||
|
|
||||||
def htmlCalendarDay(cssCache: {}, translate: {},
|
def _htmlCalendarDay(cssCache: {}, translate: {},
|
||||||
baseDir: str, path: str,
|
baseDir: str, path: str,
|
||||||
year: int, monthNumber: int, dayNumber: int,
|
year: int, monthNumber: int, dayNumber: int,
|
||||||
nickname: str, domain: str, dayEvents: [],
|
nickname: str, domain: str, dayEvents: [],
|
||||||
monthName: str, actor: str) -> str:
|
monthName: str, actor: str) -> str:
|
||||||
"""Show a day within the calendar
|
"""Show a day within the calendar
|
||||||
"""
|
"""
|
||||||
accountDir = baseDir + '/accounts/' + nickname + '@' + domain
|
accountDir = baseDir + '/accounts/' + nickname + '@' + domain
|
||||||
|
|
@ -251,10 +251,10 @@ def htmlCalendar(cssCache: {}, translate: {},
|
||||||
if events:
|
if events:
|
||||||
if events.get(str(dayNumber)):
|
if events.get(str(dayNumber)):
|
||||||
dayEvents = events[str(dayNumber)]
|
dayEvents = events[str(dayNumber)]
|
||||||
return htmlCalendarDay(cssCache, translate, baseDir, path,
|
return _htmlCalendarDay(cssCache, translate, baseDir, path,
|
||||||
year, monthNumber, dayNumber,
|
year, monthNumber, dayNumber,
|
||||||
nickname, domain, dayEvents,
|
nickname, domain, dayEvents,
|
||||||
monthName, actor)
|
monthName, actor)
|
||||||
|
|
||||||
events = \
|
events = \
|
||||||
getCalendarEvents(baseDir, nickname, domain, year, monthNumber)
|
getCalendarEvents(baseDir, nickname, domain, year, monthNumber)
|
||||||
|
|
|
||||||
|
|
@ -19,18 +19,18 @@ from webapp_utils import htmlFooter
|
||||||
from webapp_utils import getBannerFile
|
from webapp_utils import getBannerFile
|
||||||
|
|
||||||
|
|
||||||
def linksExist(baseDir: str) -> bool:
|
def _linksExist(baseDir: str) -> bool:
|
||||||
"""Returns true if links have been created
|
"""Returns true if links have been created
|
||||||
"""
|
"""
|
||||||
linksFilename = baseDir + '/accounts/links.txt'
|
linksFilename = baseDir + '/accounts/links.txt'
|
||||||
return os.path.isfile(linksFilename)
|
return os.path.isfile(linksFilename)
|
||||||
|
|
||||||
|
|
||||||
def getLeftColumnShares(baseDir: str,
|
def _getLeftColumnShares(baseDir: str,
|
||||||
httpPrefix: str, domainFull: str,
|
httpPrefix: str, domainFull: str,
|
||||||
nickname: str,
|
nickname: str,
|
||||||
maxSharesInLeftColumn: int,
|
maxSharesInLeftColumn: int,
|
||||||
translate: {}) -> []:
|
translate: {}) -> []:
|
||||||
"""get any shares and turn them into the left column links format
|
"""get any shares and turn them into the left column links format
|
||||||
"""
|
"""
|
||||||
pageNumber = 1
|
pageNumber = 1
|
||||||
|
|
@ -164,9 +164,9 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
# show a number of shares
|
# show a number of shares
|
||||||
maxSharesInLeftColumn = 3
|
maxSharesInLeftColumn = 3
|
||||||
sharesList = \
|
sharesList = \
|
||||||
getLeftColumnShares(baseDir,
|
_getLeftColumnShares(baseDir,
|
||||||
httpPrefix, domainFull, nickname,
|
httpPrefix, domainFull, nickname,
|
||||||
maxSharesInLeftColumn, translate)
|
maxSharesInLeftColumn, translate)
|
||||||
if linksList and sharesList:
|
if linksList and sharesList:
|
||||||
linksList = sharesList + linksList
|
linksList = sharesList + linksList
|
||||||
|
|
||||||
|
|
@ -271,7 +271,7 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
|
||||||
headerButtonsFrontScreen(translate, nickname,
|
headerButtonsFrontScreen(translate, nickname,
|
||||||
'links', authorized,
|
'links', authorized,
|
||||||
iconsAsButtons) + '</center>'
|
iconsAsButtons) + '</center>'
|
||||||
if linksExist(baseDir):
|
if _linksExist(baseDir):
|
||||||
htmlStr += \
|
htmlStr += \
|
||||||
getLeftColumnContent(baseDir, nickname, domainFull,
|
getLeftColumnContent(baseDir, nickname, domainFull,
|
||||||
httpPrefix, translate,
|
httpPrefix, translate,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ from webapp_utils import htmlPostSeparator
|
||||||
from webapp_utils import headerButtonsFrontScreen
|
from webapp_utils import headerButtonsFrontScreen
|
||||||
|
|
||||||
|
|
||||||
def votesIndicator(totalVotes: int, positiveVoting: bool) -> str:
|
def _votesIndicator(totalVotes: int, positiveVoting: bool) -> str:
|
||||||
"""Returns an indicator of the number of votes on a newswire item
|
"""Returns an indicator of the number of votes on a newswire item
|
||||||
"""
|
"""
|
||||||
if totalVotes <= 0:
|
if totalVotes <= 0:
|
||||||
|
|
@ -177,8 +177,8 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
|
|
||||||
# show the newswire lines
|
# show the newswire lines
|
||||||
newswireContentStr = \
|
newswireContentStr = \
|
||||||
htmlNewswire(baseDir, newswire, nickname, moderator, translate,
|
_htmlNewswire(baseDir, newswire, nickname, moderator, translate,
|
||||||
positiveVoting)
|
positiveVoting)
|
||||||
htmlStr += newswireContentStr
|
htmlStr += newswireContentStr
|
||||||
|
|
||||||
# show the rss icon at the bottom, typically on the right hand side
|
# show the rss icon at the bottom, typically on the right hand side
|
||||||
|
|
@ -187,8 +187,8 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
|
||||||
return htmlStr
|
return htmlStr
|
||||||
|
|
||||||
|
|
||||||
def htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
|
def _htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
|
||||||
translate: {}, positiveVoting: bool) -> str:
|
translate: {}, positiveVoting: bool) -> str:
|
||||||
"""Converts a newswire dict into html
|
"""Converts a newswire dict into html
|
||||||
"""
|
"""
|
||||||
separatorStr = htmlPostSeparator(baseDir, 'right')
|
separatorStr = htmlPostSeparator(baseDir, 'right')
|
||||||
|
|
@ -220,7 +220,7 @@ def htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
|
||||||
if moderator:
|
if moderator:
|
||||||
totalVotes = votesOnNewswireItem(item[2])
|
totalVotes = votesOnNewswireItem(item[2])
|
||||||
totalVotesStr = \
|
totalVotesStr = \
|
||||||
votesIndicator(totalVotes, positiveVoting)
|
_votesIndicator(totalVotes, positiveVoting)
|
||||||
|
|
||||||
title = removeLongWords(item[0], 16, []).replace('\n', '<br>')
|
title = removeLongWords(item[0], 16, []).replace('\n', '<br>')
|
||||||
htmlStr += '<p class="newswireItemVotedOn">' + \
|
htmlStr += '<p class="newswireItemVotedOn">' + \
|
||||||
|
|
@ -247,7 +247,7 @@ def htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
|
||||||
# show a number of ticks or crosses for how many
|
# show a number of ticks or crosses for how many
|
||||||
# votes for or against
|
# votes for or against
|
||||||
totalVotesStr = \
|
totalVotesStr = \
|
||||||
votesIndicator(totalVotes, positiveVoting)
|
_votesIndicator(totalVotes, positiveVoting)
|
||||||
|
|
||||||
title = removeLongWords(item[0], 16, []).replace('\n', '<br>')
|
title = removeLongWords(item[0], 16, []).replace('\n', '<br>')
|
||||||
if moderator and moderatedItem:
|
if moderator and moderatedItem:
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ from webapp_utils import htmlHeaderWithExternalStyle
|
||||||
from webapp_utils import htmlFooter
|
from webapp_utils import htmlFooter
|
||||||
|
|
||||||
|
|
||||||
def htmlFollowingDataList(baseDir: str, nickname: str,
|
def _htmlFollowingDataList(baseDir: str, nickname: str,
|
||||||
domain: str, domainFull: str) -> str:
|
domain: str, domainFull: str) -> str:
|
||||||
"""Returns a datalist of handles being followed
|
"""Returns a datalist of handles being followed
|
||||||
"""
|
"""
|
||||||
listStr = '<datalist id="followingHandles">\n'
|
listStr = '<datalist id="followingHandles">\n'
|
||||||
|
|
@ -57,20 +57,20 @@ def htmlFollowingDataList(baseDir: str, nickname: str,
|
||||||
return listStr
|
return listStr
|
||||||
|
|
||||||
|
|
||||||
def htmlNewPostDropDown(scopeIcon: str, scopeDescription: str,
|
def _htmlNewPostDropDown(scopeIcon: str, scopeDescription: str,
|
||||||
replyStr: str,
|
replyStr: str,
|
||||||
translate: {},
|
translate: {},
|
||||||
showPublicOnDropdown: bool,
|
showPublicOnDropdown: bool,
|
||||||
defaultTimeline: str,
|
defaultTimeline: str,
|
||||||
pathBase: str,
|
pathBase: str,
|
||||||
dropdownNewPostSuffix: str,
|
dropdownNewPostSuffix: str,
|
||||||
dropdownNewBlogSuffix: str,
|
dropdownNewBlogSuffix: str,
|
||||||
dropdownUnlistedSuffix: str,
|
dropdownUnlistedSuffix: str,
|
||||||
dropdownFollowersSuffix: str,
|
dropdownFollowersSuffix: str,
|
||||||
dropdownDMSuffix: str,
|
dropdownDMSuffix: str,
|
||||||
dropdownReminderSuffix: str,
|
dropdownReminderSuffix: str,
|
||||||
dropdownEventSuffix: str,
|
dropdownEventSuffix: str,
|
||||||
dropdownReportSuffix: str) -> str:
|
dropdownReportSuffix: str) -> str:
|
||||||
"""Returns the html for a drop down list of new post types
|
"""Returns the html for a drop down list of new post types
|
||||||
"""
|
"""
|
||||||
dropDownContent = '<div class="newPostDropdown">\n'
|
dropDownContent = '<div class="newPostDropdown">\n'
|
||||||
|
|
@ -617,20 +617,20 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
|
||||||
dropDownContent = ''
|
dropDownContent = ''
|
||||||
if not reportUrl and not shareDescription:
|
if not reportUrl and not shareDescription:
|
||||||
dropDownContent = \
|
dropDownContent = \
|
||||||
htmlNewPostDropDown(scopeIcon, scopeDescription,
|
_htmlNewPostDropDown(scopeIcon, scopeDescription,
|
||||||
replyStr,
|
replyStr,
|
||||||
translate,
|
translate,
|
||||||
showPublicOnDropdown,
|
showPublicOnDropdown,
|
||||||
defaultTimeline,
|
defaultTimeline,
|
||||||
pathBase,
|
pathBase,
|
||||||
dropdownNewPostSuffix,
|
dropdownNewPostSuffix,
|
||||||
dropdownNewBlogSuffix,
|
dropdownNewBlogSuffix,
|
||||||
dropdownUnlistedSuffix,
|
dropdownUnlistedSuffix,
|
||||||
dropdownFollowersSuffix,
|
dropdownFollowersSuffix,
|
||||||
dropdownDMSuffix,
|
dropdownDMSuffix,
|
||||||
dropdownReminderSuffix,
|
dropdownReminderSuffix,
|
||||||
dropdownEventSuffix,
|
dropdownEventSuffix,
|
||||||
dropdownReportSuffix)
|
dropdownReportSuffix)
|
||||||
else:
|
else:
|
||||||
if not shareDescription:
|
if not shareDescription:
|
||||||
# reporting a post to moderator
|
# reporting a post to moderator
|
||||||
|
|
@ -717,7 +717,7 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
|
||||||
' <input type="text" name="mentions" ' + \
|
' <input type="text" name="mentions" ' + \
|
||||||
'list="followingHandles" value="' + mentionsStr + '" selected>\n'
|
'list="followingHandles" value="' + mentionsStr + '" selected>\n'
|
||||||
newPostForm += \
|
newPostForm += \
|
||||||
htmlFollowingDataList(baseDir, nickname, domain, domainFull)
|
_htmlFollowingDataList(baseDir, nickname, domain, domainFull)
|
||||||
newPostForm += ''
|
newPostForm += ''
|
||||||
selectedStr = ''
|
selectedStr = ''
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,14 @@ from webapp_column_right import getRightColumnContent
|
||||||
from webapp_post import individualPostAsHtml
|
from webapp_post import individualPostAsHtml
|
||||||
|
|
||||||
|
|
||||||
def htmlFrontScreenPosts(recentPostsCache: {}, maxRecentPosts: int,
|
def _htmlFrontScreenPosts(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
translate: {},
|
translate: {},
|
||||||
baseDir: str, httpPrefix: str,
|
baseDir: str, httpPrefix: str,
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
session, wfRequest: {}, personCache: {},
|
session, wfRequest: {}, personCache: {},
|
||||||
projectVersion: str,
|
projectVersion: str,
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool) -> str:
|
showPublishedDateOnly: bool) -> str:
|
||||||
"""Shows posts on the front screen of a news instance
|
"""Shows posts on the front screen of a news instance
|
||||||
These should only be public blog posts from the features timeline
|
These should only be public blog posts from the features timeline
|
||||||
which is the blog timeline of the news actor
|
which is the blog timeline of the news actor
|
||||||
|
|
@ -139,14 +139,14 @@ def htmlFrontScreen(rssIconAtTop: bool,
|
||||||
bannerFile, bannerFilename = \
|
bannerFile, bannerFilename = \
|
||||||
getBannerFile(baseDir, nickname, domain, theme)
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
profileStr += \
|
profileStr += \
|
||||||
htmlFrontScreenPosts(recentPostsCache, maxRecentPosts,
|
_htmlFrontScreenPosts(recentPostsCache, maxRecentPosts,
|
||||||
translate,
|
translate,
|
||||||
baseDir, httpPrefix,
|
baseDir, httpPrefix,
|
||||||
nickname, domain, port,
|
nickname, domain, port,
|
||||||
session, wfRequest, personCache,
|
session, wfRequest, personCache,
|
||||||
projectVersion,
|
projectVersion,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly) + licenseStr
|
showPublishedDateOnly) + licenseStr
|
||||||
|
|
||||||
# Footer which is only used for system accounts
|
# Footer which is only used for system accounts
|
||||||
profileFooterStr = ' </td>\n'
|
profileFooterStr = ' </td>\n'
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ def getHashtagCategoriesFeed(baseDir: str,
|
||||||
return rssStr
|
return rssStr
|
||||||
|
|
||||||
|
|
||||||
def getHashtagDomainMax(domainHistogram: {}) -> str:
|
def _getHashtagDomainMax(domainHistogram: {}) -> str:
|
||||||
"""Returns the domain with the maximum number of hashtags
|
"""Returns the domain with the maximum number of hashtags
|
||||||
"""
|
"""
|
||||||
maxCount = 1
|
maxCount = 1
|
||||||
|
|
@ -63,7 +63,7 @@ def getHashtagDomainMax(domainHistogram: {}) -> str:
|
||||||
return maxDomain
|
return maxDomain
|
||||||
|
|
||||||
|
|
||||||
def getHashtagDomainHistogram(domainHistogram: {}, translate: {}) -> str:
|
def _getHashtagDomainHistogram(domainHistogram: {}, translate: {}) -> str:
|
||||||
"""Returns the html for a histogram of domains
|
"""Returns the html for a histogram of domains
|
||||||
from which hashtags are coming
|
from which hashtags are coming
|
||||||
"""
|
"""
|
||||||
|
|
@ -88,7 +88,7 @@ def getHashtagDomainHistogram(domainHistogram: {}, translate: {}) -> str:
|
||||||
rightColStr = ''
|
rightColStr = ''
|
||||||
|
|
||||||
for i in range(len(domainHistogram)):
|
for i in range(len(domainHistogram)):
|
||||||
domain = getHashtagDomainMax(domainHistogram)
|
domain = _getHashtagDomainMax(domainHistogram)
|
||||||
if not domain:
|
if not domain:
|
||||||
break
|
break
|
||||||
percent = int(domainHistogram[domain] * 100 / totalCount)
|
percent = int(domainHistogram[domain] * 100 / totalCount)
|
||||||
|
|
@ -224,7 +224,7 @@ def htmlHashTagSwarm(baseDir: str, actor: str, translate: {}) -> str:
|
||||||
getContentWarningButton('alltags', translate, tagSwarmStr)
|
getContentWarningButton('alltags', translate, tagSwarmStr)
|
||||||
|
|
||||||
tagSwarmHtml = categorySwarmStr + tagSwarmStr.strip() + '\n'
|
tagSwarmHtml = categorySwarmStr + tagSwarmStr.strip() + '\n'
|
||||||
# tagSwarmHtml += getHashtagDomainHistogram(domainHistogram, translate)
|
# tagSwarmHtml += _getHashtagDomainHistogram(domainHistogram, translate)
|
||||||
return tagSwarmHtml
|
return tagSwarmHtml
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ __email__ = "bob@freedombone.net"
|
||||||
__status__ = "Production"
|
__status__ = "Production"
|
||||||
|
|
||||||
|
|
||||||
def addEmbeddedVideoFromSites(translate: {}, content: str,
|
def _addEmbeddedVideoFromSites(translate: {}, content: str,
|
||||||
width=400, height=300) -> str:
|
width=400, height=300) -> str:
|
||||||
"""Adds embedded videos
|
"""Adds embedded videos
|
||||||
"""
|
"""
|
||||||
if '>vimeo.com/' in content:
|
if '>vimeo.com/' in content:
|
||||||
|
|
@ -122,7 +122,7 @@ def addEmbeddedVideoFromSites(translate: {}, content: str,
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
def addEmbeddedAudio(translate: {}, content: str) -> str:
|
def _addEmbeddedAudio(translate: {}, content: str) -> str:
|
||||||
"""Adds embedded audio for mp3/ogg
|
"""Adds embedded audio for mp3/ogg
|
||||||
"""
|
"""
|
||||||
if not ('.mp3' in content or '.ogg' in content):
|
if not ('.mp3' in content or '.ogg' in content):
|
||||||
|
|
@ -167,8 +167,8 @@ def addEmbeddedAudio(translate: {}, content: str) -> str:
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
def addEmbeddedVideo(translate: {}, content: str,
|
def _addEmbeddedVideo(translate: {}, content: str,
|
||||||
width=400, height=300) -> str:
|
width=400, height=300) -> str:
|
||||||
"""Adds embedded video for mp4/webm/ogv
|
"""Adds embedded video for mp4/webm/ogv
|
||||||
"""
|
"""
|
||||||
if not ('.mp4' in content or '.webm' in content or '.ogv' in content):
|
if not ('.mp4' in content or '.webm' in content or '.ogv' in content):
|
||||||
|
|
@ -219,6 +219,6 @@ def addEmbeddedVideo(translate: {}, content: str,
|
||||||
def addEmbeddedElements(translate: {}, content: str) -> str:
|
def addEmbeddedElements(translate: {}, content: str) -> str:
|
||||||
"""Adds embedded elements for various media types
|
"""Adds embedded elements for various media types
|
||||||
"""
|
"""
|
||||||
content = addEmbeddedVideoFromSites(translate, content)
|
content = _addEmbeddedVideoFromSites(translate, content)
|
||||||
content = addEmbeddedAudio(translate, content)
|
content = _addEmbeddedAudio(translate, content)
|
||||||
return addEmbeddedVideo(translate, content)
|
return _addEmbeddedVideo(translate, content)
|
||||||
|
|
|
||||||
703
webapp_post.py
703
webapp_post.py
File diff suppressed because it is too large
Load Diff
|
|
@ -214,14 +214,14 @@ def htmlProfileAfterSearch(cssCache: {},
|
||||||
imageUrl = profileJson['image']['url']
|
imageUrl = profileJson['image']['url']
|
||||||
|
|
||||||
profileStr = \
|
profileStr = \
|
||||||
getProfileHeaderAfterSearch(baseDir,
|
_getProfileHeaderAfterSearch(baseDir,
|
||||||
nickname, defaultTimeline,
|
nickname, defaultTimeline,
|
||||||
searchNickname,
|
searchNickname,
|
||||||
searchDomainFull,
|
searchDomainFull,
|
||||||
translate,
|
translate,
|
||||||
displayName,
|
displayName,
|
||||||
profileDescriptionShort,
|
profileDescriptionShort,
|
||||||
avatarUrl, imageUrl)
|
avatarUrl, imageUrl)
|
||||||
|
|
||||||
domainFull = getFullDomain(domain, port)
|
domainFull = getFullDomain(domain, port)
|
||||||
|
|
||||||
|
|
@ -287,14 +287,14 @@ def htmlProfileAfterSearch(cssCache: {},
|
||||||
return htmlHeaderWithExternalStyle(cssFilename) + profileStr + htmlFooter()
|
return htmlHeaderWithExternalStyle(cssFilename) + profileStr + htmlFooter()
|
||||||
|
|
||||||
|
|
||||||
def getProfileHeader(baseDir: str, nickname: str, domain: str,
|
def _getProfileHeader(baseDir: str, nickname: str, domain: str,
|
||||||
domainFull: str, translate: {},
|
domainFull: str, translate: {},
|
||||||
defaultTimeline: str,
|
defaultTimeline: str,
|
||||||
displayName: str,
|
displayName: str,
|
||||||
avatarDescription: str,
|
avatarDescription: str,
|
||||||
profileDescriptionShort: str,
|
profileDescriptionShort: str,
|
||||||
loginButton: str, avatarUrl: str,
|
loginButton: str, avatarUrl: str,
|
||||||
theme: str) -> str:
|
theme: str) -> str:
|
||||||
"""The header of the profile screen, containing background
|
"""The header of the profile screen, containing background
|
||||||
image and avatar
|
image and avatar
|
||||||
"""
|
"""
|
||||||
|
|
@ -327,14 +327,14 @@ def getProfileHeader(baseDir: str, nickname: str, domain: str,
|
||||||
return htmlStr
|
return htmlStr
|
||||||
|
|
||||||
|
|
||||||
def getProfileHeaderAfterSearch(baseDir: str,
|
def _getProfileHeaderAfterSearch(baseDir: str,
|
||||||
nickname: str, defaultTimeline: str,
|
nickname: str, defaultTimeline: str,
|
||||||
searchNickname: str,
|
searchNickname: str,
|
||||||
searchDomainFull: str,
|
searchDomainFull: str,
|
||||||
translate: {},
|
translate: {},
|
||||||
displayName: str,
|
displayName: str,
|
||||||
profileDescriptionShort: str,
|
profileDescriptionShort: str,
|
||||||
avatarUrl: str, imageUrl: str) -> str:
|
avatarUrl: str, imageUrl: str) -> str:
|
||||||
"""The header of a searched for handle, containing background
|
"""The header of a searched for handle, containing background
|
||||||
image and avatar
|
image and avatar
|
||||||
"""
|
"""
|
||||||
|
|
@ -568,12 +568,12 @@ def htmlProfile(rssIconAtTop: bool,
|
||||||
|
|
||||||
avatarUrl = profileJson['icon']['url']
|
avatarUrl = profileJson['icon']['url']
|
||||||
profileHeaderStr = \
|
profileHeaderStr = \
|
||||||
getProfileHeader(baseDir, nickname, domain,
|
_getProfileHeader(baseDir, nickname, domain,
|
||||||
domainFull, translate,
|
domainFull, translate,
|
||||||
defaultTimeline, displayName,
|
defaultTimeline, displayName,
|
||||||
avatarDescription,
|
avatarDescription,
|
||||||
profileDescriptionShort,
|
profileDescriptionShort,
|
||||||
loginButton, avatarUrl, theme)
|
loginButton, avatarUrl, theme)
|
||||||
|
|
||||||
profileStr = profileHeaderStr + donateSection
|
profileStr = profileHeaderStr + donateSection
|
||||||
profileStr += '<div class="container" id="buttonheader">\n'
|
profileStr += '<div class="container" id="buttonheader">\n'
|
||||||
|
|
@ -621,44 +621,44 @@ def htmlProfile(rssIconAtTop: bool,
|
||||||
|
|
||||||
if selected == 'posts':
|
if selected == 'posts':
|
||||||
profileStr += \
|
profileStr += \
|
||||||
htmlProfilePosts(recentPostsCache, maxRecentPosts,
|
_htmlProfilePosts(recentPostsCache, maxRecentPosts,
|
||||||
translate,
|
translate,
|
||||||
baseDir, httpPrefix, authorized,
|
baseDir, httpPrefix, authorized,
|
||||||
nickname, domain, port,
|
nickname, domain, port,
|
||||||
session, wfRequest, personCache,
|
session, wfRequest, personCache,
|
||||||
projectVersion,
|
projectVersion,
|
||||||
YTReplacementDomain,
|
YTReplacementDomain,
|
||||||
showPublishedDateOnly) + licenseStr
|
showPublishedDateOnly) + licenseStr
|
||||||
elif selected == 'following':
|
elif selected == 'following':
|
||||||
profileStr += \
|
profileStr += \
|
||||||
htmlProfileFollowing(translate, baseDir, httpPrefix,
|
_htmlProfileFollowing(translate, baseDir, httpPrefix,
|
||||||
authorized, nickname,
|
authorized, nickname,
|
||||||
domain, port, session,
|
domain, port, session,
|
||||||
wfRequest, personCache, extraJson,
|
wfRequest, personCache, extraJson,
|
||||||
projectVersion, ["unfollow"], selected,
|
projectVersion, ["unfollow"], selected,
|
||||||
usersPath, pageNumber, maxItemsPerPage,
|
usersPath, pageNumber, maxItemsPerPage,
|
||||||
dormantMonths)
|
dormantMonths)
|
||||||
elif selected == 'followers':
|
elif selected == 'followers':
|
||||||
profileStr += \
|
profileStr += \
|
||||||
htmlProfileFollowing(translate, baseDir, httpPrefix,
|
_htmlProfileFollowing(translate, baseDir, httpPrefix,
|
||||||
authorized, nickname,
|
authorized, nickname,
|
||||||
domain, port, session,
|
domain, port, session,
|
||||||
wfRequest, personCache, extraJson,
|
wfRequest, personCache, extraJson,
|
||||||
projectVersion, ["block"],
|
projectVersion, ["block"],
|
||||||
selected, usersPath, pageNumber,
|
selected, usersPath, pageNumber,
|
||||||
maxItemsPerPage, dormantMonths)
|
maxItemsPerPage, dormantMonths)
|
||||||
elif selected == 'roles':
|
elif selected == 'roles':
|
||||||
profileStr += \
|
profileStr += \
|
||||||
htmlProfileRoles(translate, nickname, domainFull,
|
_htmlProfileRoles(translate, nickname, domainFull,
|
||||||
extraJson)
|
extraJson)
|
||||||
elif selected == 'skills':
|
elif selected == 'skills':
|
||||||
profileStr += \
|
profileStr += \
|
||||||
htmlProfileSkills(translate, nickname, domainFull, extraJson)
|
_htmlProfileSkills(translate, nickname, domainFull, extraJson)
|
||||||
elif selected == 'shares':
|
elif selected == 'shares':
|
||||||
profileStr += \
|
profileStr += \
|
||||||
htmlProfileShares(actor, translate,
|
_htmlProfileShares(actor, translate,
|
||||||
nickname, domainFull,
|
nickname, domainFull,
|
||||||
extraJson) + licenseStr
|
extraJson) + licenseStr
|
||||||
|
|
||||||
profileStr = \
|
profileStr = \
|
||||||
htmlHeaderWithExternalStyle(cssFilename) + \
|
htmlHeaderWithExternalStyle(cssFilename) + \
|
||||||
|
|
@ -666,15 +666,15 @@ def htmlProfile(rssIconAtTop: bool,
|
||||||
return profileStr
|
return profileStr
|
||||||
|
|
||||||
|
|
||||||
def htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
|
def _htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
translate: {},
|
translate: {},
|
||||||
baseDir: str, httpPrefix: str,
|
baseDir: str, httpPrefix: str,
|
||||||
authorized: bool,
|
authorized: bool,
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
session, wfRequest: {}, personCache: {},
|
session, wfRequest: {}, personCache: {},
|
||||||
projectVersion: str,
|
projectVersion: str,
|
||||||
YTReplacementDomain: str,
|
YTReplacementDomain: str,
|
||||||
showPublishedDateOnly: bool) -> str:
|
showPublishedDateOnly: bool) -> str:
|
||||||
"""Shows posts on the profile screen
|
"""Shows posts on the profile screen
|
||||||
These should only be public posts
|
These should only be public posts
|
||||||
"""
|
"""
|
||||||
|
|
@ -720,16 +720,16 @@ def htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
|
||||||
return profileStr
|
return profileStr
|
||||||
|
|
||||||
|
|
||||||
def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
|
def _htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
|
||||||
authorized: bool,
|
authorized: bool,
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
session, wfRequest: {}, personCache: {},
|
session, wfRequest: {}, personCache: {},
|
||||||
followingJson: {}, projectVersion: str,
|
followingJson: {}, projectVersion: str,
|
||||||
buttons: [],
|
buttons: [],
|
||||||
feedName: str, actor: str,
|
feedName: str, actor: str,
|
||||||
pageNumber: int,
|
pageNumber: int,
|
||||||
maxItemsPerPage: int,
|
maxItemsPerPage: int,
|
||||||
dormantMonths: int) -> str:
|
dormantMonths: int) -> str:
|
||||||
"""Shows following on the profile screen
|
"""Shows following on the profile screen
|
||||||
"""
|
"""
|
||||||
profileStr = ''
|
profileStr = ''
|
||||||
|
|
@ -756,12 +756,12 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
|
||||||
dormantMonths)
|
dormantMonths)
|
||||||
|
|
||||||
profileStr += \
|
profileStr += \
|
||||||
individualFollowAsHtml(translate, baseDir, session,
|
_individualFollowAsHtml(translate, baseDir, session,
|
||||||
wfRequest, personCache,
|
wfRequest, personCache,
|
||||||
domain, followingActor,
|
domain, followingActor,
|
||||||
authorized, nickname,
|
authorized, nickname,
|
||||||
httpPrefix, projectVersion, dormant,
|
httpPrefix, projectVersion, dormant,
|
||||||
buttons)
|
buttons)
|
||||||
|
|
||||||
if authorized and maxItemsPerPage and pageNumber:
|
if authorized and maxItemsPerPage and pageNumber:
|
||||||
if len(followingJson['orderedItems']) >= maxItemsPerPage:
|
if len(followingJson['orderedItems']) >= maxItemsPerPage:
|
||||||
|
|
@ -778,8 +778,8 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
|
||||||
return profileStr
|
return profileStr
|
||||||
|
|
||||||
|
|
||||||
def htmlProfileRoles(translate: {}, nickname: str, domain: str,
|
def _htmlProfileRoles(translate: {}, nickname: str, domain: str,
|
||||||
rolesJson: {}) -> str:
|
rolesJson: {}) -> str:
|
||||||
"""Shows roles on the profile screen
|
"""Shows roles on the profile screen
|
||||||
"""
|
"""
|
||||||
profileStr = ''
|
profileStr = ''
|
||||||
|
|
@ -801,8 +801,8 @@ def htmlProfileRoles(translate: {}, nickname: str, domain: str,
|
||||||
return profileStr
|
return profileStr
|
||||||
|
|
||||||
|
|
||||||
def htmlProfileSkills(translate: {}, nickname: str, domain: str,
|
def _htmlProfileSkills(translate: {}, nickname: str, domain: str,
|
||||||
skillsJson: {}) -> str:
|
skillsJson: {}) -> str:
|
||||||
"""Shows skills on the profile screen
|
"""Shows skills on the profile screen
|
||||||
"""
|
"""
|
||||||
profileStr = ''
|
profileStr = ''
|
||||||
|
|
@ -817,8 +817,8 @@ def htmlProfileSkills(translate: {}, nickname: str, domain: str,
|
||||||
return profileStr
|
return profileStr
|
||||||
|
|
||||||
|
|
||||||
def htmlProfileShares(actor: str, translate: {},
|
def _htmlProfileShares(actor: str, translate: {},
|
||||||
nickname: str, domain: str, sharesJson: {}) -> str:
|
nickname: str, domain: str, sharesJson: {}) -> str:
|
||||||
"""Shows shares on the profile screen
|
"""Shows shares on the profile screen
|
||||||
"""
|
"""
|
||||||
profileStr = ''
|
profileStr = ''
|
||||||
|
|
@ -1450,16 +1450,16 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
|
||||||
return editProfileForm
|
return editProfileForm
|
||||||
|
|
||||||
|
|
||||||
def individualFollowAsHtml(translate: {},
|
def _individualFollowAsHtml(translate: {},
|
||||||
baseDir: str, session, wfRequest: {},
|
baseDir: str, session, wfRequest: {},
|
||||||
personCache: {}, domain: str,
|
personCache: {}, domain: str,
|
||||||
followUrl: str,
|
followUrl: str,
|
||||||
authorized: bool,
|
authorized: bool,
|
||||||
actorNickname: str,
|
actorNickname: str,
|
||||||
httpPrefix: str,
|
httpPrefix: str,
|
||||||
projectVersion: str,
|
projectVersion: str,
|
||||||
dormant: bool,
|
dormant: bool,
|
||||||
buttons=[]) -> str:
|
buttons=[]) -> str:
|
||||||
"""An individual follow entry on the profile screen
|
"""An individual follow entry on the profile screen
|
||||||
"""
|
"""
|
||||||
nickname = getNicknameFromActor(followUrl)
|
nickname = getNicknameFromActor(followUrl)
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ from webapp_headerbuttons import headerButtonsTimeline
|
||||||
from posts import isModerator
|
from posts import isModerator
|
||||||
|
|
||||||
|
|
||||||
def logTimelineTiming(enableTimingLog: bool, timelineStartTime,
|
def _logTimelineTiming(enableTimingLog: bool, timelineStartTime,
|
||||||
boxName: str, debugId: str) -> None:
|
boxName: str, debugId: str) -> None:
|
||||||
"""Create a log of timings for performance tuning
|
"""Create a log of timings for performance tuning
|
||||||
"""
|
"""
|
||||||
if not enableTimingLog:
|
if not enableTimingLog:
|
||||||
|
|
@ -127,7 +127,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
bannerFile, bannerFilename = \
|
bannerFile, bannerFilename = \
|
||||||
getBannerFile(baseDir, nickname, domain, theme)
|
getBannerFile(baseDir, nickname, domain, theme)
|
||||||
|
|
||||||
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '1')
|
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '1')
|
||||||
|
|
||||||
# is the user a moderator?
|
# is the user a moderator?
|
||||||
if not moderator:
|
if not moderator:
|
||||||
|
|
@ -137,7 +137,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
if not editor:
|
if not editor:
|
||||||
editor = isEditor(baseDir, nickname)
|
editor = isEditor(baseDir, nickname)
|
||||||
|
|
||||||
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '2')
|
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '2')
|
||||||
|
|
||||||
# the appearance of buttons - highlighted or not
|
# the appearance of buttons - highlighted or not
|
||||||
inboxButton = 'button'
|
inboxButton = 'button'
|
||||||
|
|
@ -221,7 +221,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
'" src="/icons/person.png"/></a>\n'
|
'" src="/icons/person.png"/></a>\n'
|
||||||
break
|
break
|
||||||
|
|
||||||
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '3')
|
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '3')
|
||||||
|
|
||||||
# moderation / reports button
|
# moderation / reports button
|
||||||
moderationButtonStr = ''
|
moderationButtonStr = ''
|
||||||
|
|
@ -256,7 +256,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
||||||
tlStr = htmlHeaderWithExternalStyle(cssFilename)
|
tlStr = htmlHeaderWithExternalStyle(cssFilename)
|
||||||
|
|
||||||
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '4')
|
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '4')
|
||||||
|
|
||||||
# if this is a news instance and we are viewing the news timeline
|
# if this is a news instance and we are viewing the news timeline
|
||||||
newsHeader = False
|
newsHeader = False
|
||||||
|
|
@ -487,17 +487,17 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
|
|
||||||
tlStr += '</div>\n</form>\n'
|
tlStr += '</div>\n</form>\n'
|
||||||
|
|
||||||
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '6')
|
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '6')
|
||||||
|
|
||||||
if boxName == 'tlshares':
|
if boxName == 'tlshares':
|
||||||
maxSharesPerAccount = itemsPerPage
|
maxSharesPerAccount = itemsPerPage
|
||||||
return (tlStr +
|
return (tlStr +
|
||||||
htmlSharesTimeline(translate, pageNumber, itemsPerPage,
|
_htmlSharesTimeline(translate, pageNumber, itemsPerPage,
|
||||||
baseDir, actor, nickname, domain, port,
|
baseDir, actor, nickname, domain, port,
|
||||||
maxSharesPerAccount, httpPrefix) +
|
maxSharesPerAccount, httpPrefix) +
|
||||||
htmlFooter())
|
htmlFooter())
|
||||||
|
|
||||||
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '7')
|
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '7')
|
||||||
|
|
||||||
# page up arrow
|
# page up arrow
|
||||||
if pageNumber > 1:
|
if pageNumber > 1:
|
||||||
|
|
@ -543,14 +543,14 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
preparePostFromHtmlCache(currTlStr,
|
preparePostFromHtmlCache(currTlStr,
|
||||||
boxName,
|
boxName,
|
||||||
pageNumber)
|
pageNumber)
|
||||||
logTimelineTiming(enableTimingLog,
|
_logTimelineTiming(enableTimingLog,
|
||||||
timelineStartTime,
|
timelineStartTime,
|
||||||
boxName, '10')
|
boxName, '10')
|
||||||
|
|
||||||
if not currTlStr:
|
if not currTlStr:
|
||||||
logTimelineTiming(enableTimingLog,
|
_logTimelineTiming(enableTimingLog,
|
||||||
timelineStartTime,
|
timelineStartTime,
|
||||||
boxName, '11')
|
boxName, '11')
|
||||||
|
|
||||||
# read the post from disk
|
# read the post from disk
|
||||||
currTlStr = \
|
currTlStr = \
|
||||||
|
|
@ -570,8 +570,8 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
showIndividualPostIcons,
|
showIndividualPostIcons,
|
||||||
manuallyApproveFollowers,
|
manuallyApproveFollowers,
|
||||||
False, True)
|
False, True)
|
||||||
logTimelineTiming(enableTimingLog,
|
_logTimelineTiming(enableTimingLog,
|
||||||
timelineStartTime, boxName, '12')
|
timelineStartTime, boxName, '12')
|
||||||
|
|
||||||
if currTlStr:
|
if currTlStr:
|
||||||
itemCtr += 1
|
itemCtr += 1
|
||||||
|
|
@ -612,7 +612,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
|
||||||
rightColumnStr + ' </td>\n'
|
rightColumnStr + ' </td>\n'
|
||||||
tlStr += ' </tr>\n'
|
tlStr += ' </tr>\n'
|
||||||
|
|
||||||
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '9')
|
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '9')
|
||||||
|
|
||||||
tlStr += ' </tbody>\n'
|
tlStr += ' </tbody>\n'
|
||||||
tlStr += '</table>\n'
|
tlStr += '</table>\n'
|
||||||
|
|
@ -656,10 +656,10 @@ def htmlIndividualShare(actor: str, item: {}, translate: {},
|
||||||
return profileStr
|
return profileStr
|
||||||
|
|
||||||
|
|
||||||
def htmlSharesTimeline(translate: {}, pageNumber: int, itemsPerPage: int,
|
def _htmlSharesTimeline(translate: {}, pageNumber: int, itemsPerPage: int,
|
||||||
baseDir: str, actor: str,
|
baseDir: str, actor: str,
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
maxSharesPerAccount: int, httpPrefix: str) -> str:
|
maxSharesPerAccount: int, httpPrefix: str) -> str:
|
||||||
"""Show shared items timeline as html
|
"""Show shared items timeline as html
|
||||||
"""
|
"""
|
||||||
sharesJson, lastPage = \
|
sharesJson, lastPage = \
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ def getContentWarningButton(postID: str, translate: {},
|
||||||
'</div></details>\n'
|
'</div></details>\n'
|
||||||
|
|
||||||
|
|
||||||
def getActorPropertyUrl(actorJson: {}, propertyName: str) -> str:
|
def _getActorPropertyUrl(actorJson: {}, propertyName: str) -> str:
|
||||||
"""Returns a url property from an actor
|
"""Returns a url property from an actor
|
||||||
"""
|
"""
|
||||||
if not actorJson.get('attachment'):
|
if not actorJson.get('attachment'):
|
||||||
|
|
@ -206,10 +206,10 @@ def getActorPropertyUrl(actorJson: {}, propertyName: str) -> str:
|
||||||
def getBlogAddress(actorJson: {}) -> str:
|
def getBlogAddress(actorJson: {}) -> str:
|
||||||
"""Returns blog address for the given actor
|
"""Returns blog address for the given actor
|
||||||
"""
|
"""
|
||||||
return getActorPropertyUrl(actorJson, 'Blog')
|
return _getActorPropertyUrl(actorJson, 'Blog')
|
||||||
|
|
||||||
|
|
||||||
def setActorPropertyUrl(actorJson: {}, propertyName: str, url: str) -> None:
|
def _setActorPropertyUrl(actorJson: {}, propertyName: str, url: str) -> None:
|
||||||
"""Sets a url for the given actor property
|
"""Sets a url for the given actor property
|
||||||
"""
|
"""
|
||||||
if not actorJson.get('attachment'):
|
if not actorJson.get('attachment'):
|
||||||
|
|
@ -269,7 +269,7 @@ def setActorPropertyUrl(actorJson: {}, propertyName: str, url: str) -> None:
|
||||||
def setBlogAddress(actorJson: {}, blogAddress: str) -> None:
|
def setBlogAddress(actorJson: {}, blogAddress: str) -> None:
|
||||||
"""Sets an blog address for the given actor
|
"""Sets an blog address for the given actor
|
||||||
"""
|
"""
|
||||||
setActorPropertyUrl(actorJson, 'Blog', removeHtml(blogAddress))
|
_setActorPropertyUrl(actorJson, 'Blog', removeHtml(blogAddress))
|
||||||
|
|
||||||
|
|
||||||
def updateAvatarImageCache(session, baseDir: str, httpPrefix: str,
|
def updateAvatarImageCache(session, baseDir: str, httpPrefix: str,
|
||||||
|
|
@ -475,8 +475,8 @@ def postContainsPublic(postJsonObject: {}) -> bool:
|
||||||
return containsPublic
|
return containsPublic
|
||||||
|
|
||||||
|
|
||||||
def getImageFile(baseDir: str, name: str, directory: str,
|
def _getImageFile(baseDir: str, name: str, directory: str,
|
||||||
nickname: str, domain: str, theme: str) -> (str, str):
|
nickname: str, domain: str, theme: str) -> (str, str):
|
||||||
"""
|
"""
|
||||||
returns the filenames for an image with the given name
|
returns the filenames for an image with the given name
|
||||||
"""
|
"""
|
||||||
|
|
@ -495,30 +495,30 @@ def getImageFile(baseDir: str, name: str, directory: str,
|
||||||
|
|
||||||
def getBannerFile(baseDir: str,
|
def getBannerFile(baseDir: str,
|
||||||
nickname: str, domain: str, theme: str) -> (str, str):
|
nickname: str, domain: str, theme: str) -> (str, str):
|
||||||
return getImageFile(baseDir, 'banner',
|
return _getImageFile(baseDir, 'banner',
|
||||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||||
nickname, domain, theme)
|
nickname, domain, theme)
|
||||||
|
|
||||||
|
|
||||||
def getSearchBannerFile(baseDir: str,
|
def getSearchBannerFile(baseDir: str,
|
||||||
nickname: str, domain: str, theme: str) -> (str, str):
|
nickname: str, domain: str, theme: str) -> (str, str):
|
||||||
return getImageFile(baseDir, 'search_banner',
|
return _getImageFile(baseDir, 'search_banner',
|
||||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||||
nickname, domain, theme)
|
nickname, domain, theme)
|
||||||
|
|
||||||
|
|
||||||
def getLeftImageFile(baseDir: str,
|
def getLeftImageFile(baseDir: str,
|
||||||
nickname: str, domain: str, theme: str) -> (str, str):
|
nickname: str, domain: str, theme: str) -> (str, str):
|
||||||
return getImageFile(baseDir, 'left_col_image',
|
return _getImageFile(baseDir, 'left_col_image',
|
||||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||||
nickname, domain, theme)
|
nickname, domain, theme)
|
||||||
|
|
||||||
|
|
||||||
def getRightImageFile(baseDir: str,
|
def getRightImageFile(baseDir: str,
|
||||||
nickname: str, domain: str, theme: str) -> (str, str):
|
nickname: str, domain: str, theme: str) -> (str, str):
|
||||||
return getImageFile(baseDir, 'right_col_image',
|
return _getImageFile(baseDir, 'right_col_image',
|
||||||
baseDir + '/accounts/' + nickname + '@' + domain,
|
baseDir + '/accounts/' + nickname + '@' + domain,
|
||||||
nickname, domain, theme)
|
nickname, domain, theme)
|
||||||
|
|
||||||
|
|
||||||
def htmlHeaderWithExternalStyle(cssFilename: str, lang='en') -> str:
|
def htmlHeaderWithExternalStyle(cssFilename: str, lang='en') -> str:
|
||||||
|
|
|
||||||
12
webfinger.py
12
webfinger.py
|
|
@ -25,7 +25,7 @@ from utils import saveJson
|
||||||
from utils import getProtocolPrefixes
|
from utils import getProtocolPrefixes
|
||||||
|
|
||||||
|
|
||||||
def parseHandle(handle: str) -> (str, str):
|
def _parseHandle(handle: str) -> (str, str):
|
||||||
if '.' not in handle:
|
if '.' not in handle:
|
||||||
return None, None
|
return None, None
|
||||||
prefixes = getProtocolPrefixes()
|
prefixes = getProtocolPrefixes()
|
||||||
|
|
@ -54,7 +54,7 @@ def webfingerHandle(session, handle: str, httpPrefix: str,
|
||||||
print('WARN: No session specified for webfingerHandle')
|
print('WARN: No session specified for webfingerHandle')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
nickname, domain = parseHandle(handle)
|
nickname, domain = _parseHandle(handle)
|
||||||
if not nickname:
|
if not nickname:
|
||||||
return None
|
return None
|
||||||
wfDomain = domain
|
wfDomain = domain
|
||||||
|
|
@ -97,7 +97,7 @@ def webfingerHandle(session, handle: str, httpPrefix: str,
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def generateMagicKey(publicKeyPem) -> str:
|
def _generateMagicKey(publicKeyPem) -> str:
|
||||||
"""See magic_key method in
|
"""See magic_key method in
|
||||||
https://github.com/tootsuite/mastodon/blob/
|
https://github.com/tootsuite/mastodon/blob/
|
||||||
707ddf7808f90e3ab042d7642d368c2ce8e95e6f/app/models/account.rb
|
707ddf7808f90e3ab042d7642d368c2ce8e95e6f/app/models/account.rb
|
||||||
|
|
@ -170,7 +170,7 @@ def createWebfingerEndpoint(nickname: str, domain: str, port: int,
|
||||||
"type": "application/activity+json"
|
"type": "application/activity+json"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"href": generateMagicKey(publicKeyPem),
|
"href": _generateMagicKey(publicKeyPem),
|
||||||
"rel": "magic-public-key"
|
"rel": "magic-public-key"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
@ -271,7 +271,7 @@ def webfingerLookup(path: str, baseDir: str,
|
||||||
return wfJson
|
return wfJson
|
||||||
|
|
||||||
|
|
||||||
def webfingerUpdateFromProfile(wfJson: {}, actorJson: {}) -> bool:
|
def _webfingerUpdateFromProfile(wfJson: {}, actorJson: {}) -> bool:
|
||||||
"""Updates webfinger Email/blog/xmpp links from profile
|
"""Updates webfinger Email/blog/xmpp links from profile
|
||||||
Returns true if one or more tags has been changed
|
Returns true if one or more tags has been changed
|
||||||
"""
|
"""
|
||||||
|
|
@ -350,6 +350,6 @@ def webfingerUpdate(baseDir: str, nickname: str, domain: str,
|
||||||
if not actorJson:
|
if not actorJson:
|
||||||
return
|
return
|
||||||
|
|
||||||
if webfingerUpdateFromProfile(wfJson, actorJson):
|
if _webfingerUpdateFromProfile(wfJson, actorJson):
|
||||||
if saveJson(wfJson, filename):
|
if saveJson(wfJson, filename):
|
||||||
cachedWebfingers[handle] = wfJson
|
cachedWebfingers[handle] = wfJson
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue