Enforce convention of underscore before local function names

alt-html-css
Bob Mottram 2020-12-22 18:06:23 +00:00
parent 0cf0841402
commit 5cd9aa8d66
42 changed files with 1805 additions and 1786 deletions

View File

@ -15,7 +15,7 @@ from utils import domainPermitted
from utils import followPerson
def createAcceptReject(baseDir: str, federationList: [],
def _createAcceptReject(baseDir: str, federationList: [],
nickname: str, domain: str, port: int,
toUrl: str, ccUrl: str, httpPrefix: str,
objectJson: {}, acceptType: str) -> {}:
@ -51,7 +51,7 @@ def createAccept(baseDir: str, federationList: [],
nickname: str, domain: str, port: int,
toUrl: str, ccUrl: str, httpPrefix: str,
objectJson: {}) -> {}:
return createAcceptReject(baseDir, federationList,
return _createAcceptReject(baseDir, federationList,
nickname, domain, port,
toUrl, ccUrl, httpPrefix,
objectJson, 'Accept')
@ -61,13 +61,13 @@ def createReject(baseDir: str, federationList: [],
nickname: str, domain: str, port: int,
toUrl: str, ccUrl: str, httpPrefix: str,
objectJson: {}) -> {}:
return createAcceptReject(baseDir, federationList,
return _createAcceptReject(baseDir, federationList,
nickname, domain, port,
toUrl, ccUrl,
httpPrefix, objectJson, 'Reject')
def acceptFollow(baseDir: str, domain: str, messageJson: {},
def _acceptFollow(baseDir: str, domain: str, messageJson: {},
federationList: [], debug: bool) -> None:
"""Receiving a follow Accept activity
"""
@ -204,7 +204,7 @@ def receiveAcceptReject(session, baseDir: str,
' does not contain a nickname. ' +
'Assuming single user instance.')
# receive follow accept
acceptFollow(baseDir, domain, messageJson, federationList, debug)
_acceptFollow(baseDir, domain, messageJson, federationList, debug)
if debug:
print('DEBUG: Uh, ' + messageJson['type'] + ', I guess')
return True

12
auth.py
View File

@ -14,7 +14,7 @@ import secrets
from utils import isSystemAccount
def hashPassword(password: str) -> str:
def _hashPassword(password: str) -> str:
"""Hash a password for storing
"""
salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii')
@ -25,7 +25,7 @@ def hashPassword(password: str) -> str:
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
"""
pwdhash = hashlib.pbkdf2_hmac('sha512',
@ -57,7 +57,7 @@ def constantTimeStringCheck(string1: str, string2: str) -> bool:
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
"""
if not storedPassword:
@ -66,7 +66,7 @@ def verifyPassword(storedPassword: str, providedPassword: str) -> bool:
return False
salt = storedPassword[:64]
storedPassword = storedPassword[64:]
pwHash = getPasswordHash(salt, providedPassword)
pwHash = _getPasswordHash(salt, providedPassword)
return constantTimeStringCheck(pwHash, storedPassword)
@ -137,7 +137,7 @@ def authorizeBasic(baseDir: str, path: str, authHeader: str,
if line.startswith(nickname+':'):
storedPassword = \
line.split(':')[1].replace('\n', '').replace('\r', '')
success = verifyPassword(storedPassword, providedPassword)
success = _verifyPassword(storedPassword, providedPassword)
if not success:
if debug:
print('DEBUG: Password check failed for ' + nickname)
@ -159,7 +159,7 @@ def storeBasicCredentials(baseDir: str, nickname: str, password: str) -> bool:
os.mkdir(baseDir + '/accounts')
passwordFile = baseDir + '/accounts/passwords'
storeStr = nickname + ':' + hashPassword(password)
storeStr = nickname + ':' + _hashPassword(password)
if os.path.isfile(passwordFile):
if nickname + ':' in open(passwordFile).read():
with open(passwordFile, "r") as fin:

43
blog.py
View File

@ -26,7 +26,7 @@ from newswire import rss2Header
from newswire import rss2Footer
def noOfBlogReplies(baseDir: str, httpPrefix: str, translate: {},
def _noOfBlogReplies(baseDir: str, httpPrefix: str, translate: {},
nickname: str, domain: str, domainFull: str,
postId: str, depth=0) -> int:
"""Returns the number of replies on the post
@ -66,7 +66,8 @@ def noOfBlogReplies(baseDir: str, httpPrefix: str, translate: {},
replyPostId = replyPostId.replace('.json', '')
if locatePost(baseDir, nickname, domain, replyPostId):
replyPostId = replyPostId.replace('.replies', '')
replies += 1 + noOfBlogReplies(baseDir, httpPrefix, translate,
replies += \
1 + _noOfBlogReplies(baseDir, httpPrefix, translate,
nickname, domain, domainFull,
replyPostId, depth+1)
else:
@ -86,7 +87,7 @@ def noOfBlogReplies(baseDir: str, httpPrefix: str, translate: {},
return replies
def getBlogReplies(baseDir: str, httpPrefix: str, translate: {},
def _getBlogReplies(baseDir: str, httpPrefix: str, translate: {},
nickname: str, domain: str, domainFull: str,
postId: str, depth=0) -> str:
"""Returns a string containing html blog posts
@ -136,7 +137,7 @@ def getBlogReplies(baseDir: str, httpPrefix: str, translate: {},
continue
with open(postFilename, "r") as postFile:
repliesStr += postFile.read() + '\n'
rply = getBlogReplies(baseDir, httpPrefix, translate,
rply = _getBlogReplies(baseDir, httpPrefix, translate,
nickname, domain, domainFull,
replyPostId, depth+1)
if rply not in repliesStr:
@ -152,7 +153,7 @@ def getBlogReplies(baseDir: str, httpPrefix: str, translate: {},
return ''
def htmlBlogPostContent(authorized: bool,
def _htmlBlogPostContent(authorized: bool,
baseDir: str, httpPrefix: str, translate: {},
nickname: str, domain: str, domainFull: str,
postJsonObject: {},
@ -269,7 +270,7 @@ def htmlBlogPostContent(authorized: bool,
'/users/' + nickname + '">' + translate['About the author'] + \
'</a></p>\n'
replies = noOfBlogReplies(baseDir, httpPrefix, translate,
replies = _noOfBlogReplies(baseDir, httpPrefix, translate,
nickname, domain, domainFull,
postJsonObject['object']['id'])
@ -288,11 +289,11 @@ def htmlBlogPostContent(authorized: bool,
else:
blogStr += blogSeparator + '<h1>' + translate['Replies'] + '</h1>\n'
if not titleStr:
blogStr += getBlogReplies(baseDir, httpPrefix, translate,
blogStr += _getBlogReplies(baseDir, httpPrefix, translate,
nickname, domain, domainFull,
postJsonObject['object']['id'])
else:
blogRepliesStr = getBlogReplies(baseDir, httpPrefix, translate,
blogRepliesStr = _getBlogReplies(baseDir, httpPrefix, translate,
nickname, domain, domainFull,
postJsonObject['object']['id'])
blogStr += blogRepliesStr.replace('>' + titleStr + '<', '')
@ -300,7 +301,7 @@ def htmlBlogPostContent(authorized: bool,
return blogStr
def htmlBlogPostRSS2(authorized: bool,
def _htmlBlogPostRSS2(authorized: bool,
baseDir: str, httpPrefix: str, translate: {},
nickname: str, domain: str, domainFull: str,
postJsonObject: {},
@ -331,7 +332,7 @@ def htmlBlogPostRSS2(authorized: bool,
return rssStr
def htmlBlogPostRSS3(authorized: bool,
def _htmlBlogPostRSS3(authorized: bool,
baseDir: str, httpPrefix: str, translate: {},
nickname: str, domain: str, domainFull: str,
postJsonObject: {},
@ -359,7 +360,7 @@ def htmlBlogPostRSS3(authorized: bool,
return rssStr
def htmlBlogRemoveCwButton(blogStr: str, translate: {}) -> str:
def _htmlBlogRemoveCwButton(blogStr: str, translate: {}) -> str:
"""Removes the CW button from blog posts, where the
summary field is instead used as the blog title
"""
@ -383,9 +384,9 @@ def htmlBlogPost(authorized: bool,
if os.path.isfile(baseDir + '/blog.css'):
cssFilename = baseDir + '/blog.css'
blogStr = htmlHeaderWithExternalStyle(cssFilename)
htmlBlogRemoveCwButton(blogStr, translate)
_htmlBlogRemoveCwButton(blogStr, translate)
blogStr += htmlBlogPostContent(authorized, baseDir,
blogStr += _htmlBlogPostContent(authorized, baseDir,
httpPrefix, translate,
nickname, domain,
domainFull, postJsonObject,
@ -428,7 +429,7 @@ def htmlBlogPage(authorized: bool, session,
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
blogStr = htmlHeaderWithExternalStyle(cssFilename)
htmlBlogRemoveCwButton(blogStr, translate)
_htmlBlogRemoveCwButton(blogStr, translate)
blogsIndex = baseDir + '/accounts/' + \
nickname + '@' + domain + '/tlblogs.index'
@ -472,7 +473,7 @@ def htmlBlogPage(authorized: bool, session,
if item['type'] != 'Create':
continue
blogStr += htmlBlogPostContent(authorized, baseDir,
blogStr += _htmlBlogPostContent(authorized, baseDir,
httpPrefix, translate,
nickname, domain,
domainFull, item,
@ -544,7 +545,7 @@ def htmlBlogPageRSS2(authorized: bool, session,
continue
blogRSS2 += \
htmlBlogPostRSS2(authorized, baseDir,
_htmlBlogPostRSS2(authorized, baseDir,
httpPrefix, translate,
nickname, domain,
domainFull, item,
@ -590,7 +591,7 @@ def htmlBlogPageRSS3(authorized: bool, session,
continue
blogRSS3 += \
htmlBlogPostRSS3(authorized, baseDir,
_htmlBlogPostRSS3(authorized, baseDir,
httpPrefix, translate,
nickname, domain,
domainFull, item,
@ -599,7 +600,7 @@ def htmlBlogPageRSS3(authorized: bool, session,
return blogRSS3
def noOfBlogAccounts(baseDir: str) -> int:
def _noOfBlogAccounts(baseDir: str) -> int:
"""Returns the number of blog accounts
"""
ctr = 0
@ -617,7 +618,7 @@ def noOfBlogAccounts(baseDir: str) -> int:
return ctr
def singleBlogAccountNickname(baseDir: str) -> str:
def _singleBlogAccountNickname(baseDir: str) -> str:
"""Returns the nickname of a single blog account
"""
for subdir, dirs, files in os.walk(baseDir + '/accounts'):
@ -647,8 +648,8 @@ def htmlBlogView(authorized: bool,
cssFilename = baseDir + '/epicyon.css'
blogStr = htmlHeaderWithExternalStyle(cssFilename)
if noOfBlogAccounts(baseDir) <= 1:
nickname = singleBlogAccountNickname(baseDir)
if _noOfBlogAccounts(baseDir) <= 1:
nickname = _singleBlogAccountNickname(baseDir)
if nickname:
return htmlBlogPage(authorized, session,
baseDir, httpPrefix, translate,

View File

@ -39,7 +39,7 @@ 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.
@ -57,7 +57,7 @@ def base83_encode(value, length):
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.
"""
@ -67,14 +67,14 @@ def srgb_to_linear(value):
return math.pow((value + 0.055) / 1.055, 2.4)
def sign_pow(value, exp):
def _sign_pow(value, exp):
"""
Sign-preserving exponentiation.
"""
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.
"""
@ -113,9 +113,9 @@ def blurhash_encode(image, components_x=4, components_y=4, linear=False):
image_linear_line = []
for x in range(int(width)):
image_linear_line.append([
srgb_to_linear(image[y][x][0]),
srgb_to_linear(image[y][x][1]),
srgb_to_linear(image[y][x][2])
_srgb_to_linear(image[y][x][0]),
_srgb_to_linear(image[y][x][1]),
_srgb_to_linear(image[y][x][2])
])
image_linear.append(image_linear_line)
else:
@ -149,9 +149,9 @@ def blurhash_encode(image, components_x=4, components_y=4, linear=False):
abs(component[1]), abs(component[2]))
# Encode components
dc_value = (linear_to_srgb(components[0][0]) << 16) + \
(linear_to_srgb(components[0][1]) << 8) + \
linear_to_srgb(components[0][2])
dc_value = (_linear_to_srgb(components[0][0]) << 16) + \
(_linear_to_srgb(components[0][1]) << 8) + \
_linear_to_srgb(components[0][2])
quant_max_ac_component = int(max(0, min(82,
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
g2 = g / ac_component_norm_factor
b2 = b / ac_component_norm_factor
r3 = math.floor(sign_pow(r2, 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)
r3 = math.floor(_sign_pow(r2, 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)
ac_values.append(
int(max(0.0, min(18.0, r3))) * 19 * 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
blurhash = ""
blurhash += base83_encode((components_x - 1) + (components_y - 1) * 9, 1)
blurhash += base83_encode(quant_max_ac_component, 1)
blurhash += base83_encode(dc_value, 4)
blurhash += _base83_encode((components_x - 1) + (components_y - 1) * 9, 1)
blurhash += _base83_encode(quant_max_ac_component, 1)
blurhash += _base83_encode(dc_value, 4)
for ac_value in ac_values:
blurhash += base83_encode(ac_value, 2)
blurhash += _base83_encode(ac_value, 2)
return blurhash

View File

@ -107,7 +107,7 @@ def undoBookmarksCollectionEntry(recentPostsCache: {},
def bookmarkedByPerson(postJsonObject: {}, nickname: str, domain: str) -> bool:
"""Returns True if the given post is bookmarked by the given person
"""
if noOfBookmarks(postJsonObject) == 0:
if _noOfBookmarks(postJsonObject) == 0:
return False
actorMatch = domain + '/users/' + nickname
for item in postJsonObject['object']['bookmarks']['items']:
@ -116,7 +116,7 @@ def bookmarkedByPerson(postJsonObject: {}, nickname: str, domain: str) -> bool:
return False
def noOfBookmarks(postJsonObject: {}) -> int:
def _noOfBookmarks(postJsonObject: {}) -> int:
"""Returns the number of bookmarks ona given post
"""
if not postJsonObject.get('object'):

View File

@ -33,7 +33,7 @@ def removeHtmlTag(htmlStr: str, tag: str) -> str:
return htmlStr
def removeQuotesWithinQuotes(content: str) -> str:
def _removeQuotesWithinQuotes(content: str) -> str:
"""Removes any blockquote inside blockquote
"""
if '<blockquote>' not in content:
@ -96,7 +96,7 @@ def htmlReplaceEmailQuote(content: str) -> str:
else:
lineStr = lineStr.replace('&gt;', '<br>')
newContent += '<p>' + lineStr + '</blockquote></p>'
return removeQuotesWithinQuotes(newContent)
return _removeQuotesWithinQuotes(newContent)
def htmlReplaceQuoteMarks(content: str) -> str:
@ -314,7 +314,7 @@ def replaceEmojiFromTags(content: str, tag: [], messageType: str) -> str:
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
tagged appropriately
"""
@ -416,7 +416,7 @@ def validHashTag(hashtag: str) -> bool:
return False
def addHashTags(wordStr: str, httpPrefix: str, domain: str,
def _addHashTags(wordStr: str, httpPrefix: str, domain: str,
replaceHashTags: {}, postHashtags: {}) -> bool:
"""Detects hashtags and adds them to the replacements dict
Also updates the hashtags list to be added to the post
@ -438,7 +438,7 @@ def addHashTags(wordStr: str, httpPrefix: str, domain: str,
return True
def addEmoji(baseDir: str, wordStr: str,
def _addEmoji(baseDir: str, wordStr: str,
httpPrefix: str, domain: str,
replaceEmoji: {}, postTags: {},
emojiDict: {}) -> bool:
@ -489,7 +489,7 @@ def tagExists(tagType: str, tagName: str, tags: {}) -> bool:
return False
def addMention(wordStr: str, httpPrefix: str, following: str,
def _addMention(wordStr: str, httpPrefix: str, following: str,
replaceMentions: {}, recipients: [], tags: {}) -> bool:
"""Detects mentions and adds them to the replacements dict and
recipients list
@ -672,7 +672,7 @@ def removeLongWords(content: str, maxWordLength: int,
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
the lines of the file
"""
@ -685,7 +685,7 @@ def loadAutoTags(baseDir: str, nickname: str, domain: str) -> []:
return []
def autoTag(baseDir: str, nickname: str, domain: str,
def _autoTag(baseDir: str, nickname: str, domain: str,
wordStr: str, autoTagList: [],
appendTags: []):
"""Generates a list of tags to be automatically appended to the content
@ -719,7 +719,7 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
maxWordLength = 40
content = content.replace('\r', '')
content = content.replace('\n', ' --linebreak-- ')
content = addMusicTag(content, 'nowplaying')
content = _addMusicTag(content, 'nowplaying')
contentSimplified = \
content.replace(',', ' ').replace(';', ' ').replace('- ', ' ')
contentSimplified = contentSimplified.replace('. ', ' ').strip()
@ -760,7 +760,7 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
# extract mentions and tags from words
longWordsList = []
prevWordStr = ''
autoTagsList = loadAutoTags(baseDir, nickname, domain)
autoTagsList = _loadAutoTags(baseDir, nickname, domain)
appendTags = []
for wordStr in words:
wordLen = len(wordStr)
@ -769,12 +769,12 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
longWordsList.append(wordStr)
firstChar = wordStr[0]
if firstChar == '@':
if addMention(wordStr, httpPrefix, following,
if _addMention(wordStr, httpPrefix, following,
replaceMentions, recipients, hashtags):
prevWordStr = ''
continue
elif firstChar == '#':
if addHashTags(wordStr, httpPrefix, originalDomain,
if _addHashTags(wordStr, httpPrefix, originalDomain,
replaceHashTags, hashtags):
prevWordStr = ''
continue
@ -791,16 +791,16 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
emojiDict = loadJson(baseDir + '/emoji/emoji.json')
# print('TAG: looking up emoji for :'+wordStr2+':')
addEmoji(baseDir, ':' + wordStr2 + ':', httpPrefix,
_addEmoji(baseDir, ':' + wordStr2 + ':', httpPrefix,
originalDomain, replaceEmoji, hashtags,
emojiDict)
else:
if autoTag(baseDir, nickname, domain, wordStr,
if _autoTag(baseDir, nickname, domain, wordStr,
autoTagsList, appendTags):
prevWordStr = ''
continue
if prevWordStr:
if autoTag(baseDir, nickname, domain,
if _autoTag(baseDir, nickname, domain,
prevWordStr + ' ' + wordStr,
autoTagsList, appendTags):
prevWordStr = ''
@ -810,7 +810,7 @@ def addHtmlTags(baseDir: str, httpPrefix: str,
# add any auto generated tags
for appended in appendTags:
content = content + ' ' + appended
addHashTags(appended, httpPrefix, originalDomain,
_addHashTags(appended, httpPrefix, originalDomain,
replaceHashTags, hashtags)
# replace words with their html versions

View File

@ -7,7 +7,7 @@ __email__ = "bob@freedombone.net"
__status__ = "Production"
def getDonationTypes() -> str:
def _getDonationTypes() -> str:
return ('patreon', 'paypal', 'gofundme', 'liberapay',
'kickstarter', 'indiegogo', 'crowdsupply',
'subscribestar')
@ -18,7 +18,7 @@ def getDonationUrl(actorJson: {}) -> str:
"""
if not actorJson.get('attachment'):
return ''
donationType = getDonationTypes()
donationType = _getDonationTypes()
for propertyValue in actorJson['attachment']:
if not propertyValue.get('name'):
continue
@ -54,7 +54,7 @@ def setDonationUrl(actorJson: {}, donateUrl: str) -> None:
if not actorJson.get('attachment'):
actorJson['attachment'] = []
donationType = getDonationTypes()
donationType = _getDonationTypes()
donateName = None
for paymentService in donationType:
if paymentService in donateUrl:

View File

@ -79,7 +79,7 @@ def removeGlobalFilter(baseDir: str, words: str) -> bool:
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
"""
if '/twitter.' in content or '@twitter.' in content:
@ -89,7 +89,7 @@ def isTwitterPost(content: str) -> bool:
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
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
"""
globalFiltersFilename = baseDir + '/accounts/filters.txt'
if isFilteredBase(globalFiltersFilename, content):
if _isFilteredBase(globalFiltersFilename, content):
return True
if not nickname or not domain:
@ -132,9 +132,9 @@ def isFiltered(baseDir: str, nickname: str, domain: str, content: str) -> bool:
removeTwitter = baseDir + '/accounts/' + \
nickname + '@' + domain + '/.removeTwitter'
if os.path.isfile(removeTwitter):
if isTwitterPost(content):
if _isTwitterPost(content):
return True
accountFiltersFilename = baseDir + '/accounts/' + \
nickname + '@' + domain + '/filters.txt'
return isFilteredBase(accountFiltersFilename, content)
return _isFilteredBase(accountFiltersFilename, content)

View File

@ -65,7 +65,7 @@ def createInitialLastSeen(baseDir: str, httpPrefix: str) -> None:
break
def preApprovedFollower(baseDir: str,
def _preApprovedFollower(baseDir: str,
nickname: str, domain: str,
approveHandle: str,
allowNewsFollowers: bool) -> bool:
@ -84,7 +84,7 @@ def preApprovedFollower(baseDir: str,
return False
def removeFromFollowBase(baseDir: str,
def _removeFromFollowBase(baseDir: str,
nickname: str, domain: str,
acceptOrDenyHandle: str, followFile: str,
debug: bool) -> None:
@ -114,16 +114,16 @@ def removeFromFollowRequests(baseDir: str,
denyHandle: str, debug: bool) -> None:
"""Removes a handle from follow requests
"""
removeFromFollowBase(baseDir, nickname, domain,
_removeFromFollowBase(baseDir, nickname, domain,
denyHandle, 'followrequests', debug)
def removeFromFollowRejects(baseDir: str,
def _removeFromFollowRejects(baseDir: str,
nickname: str, domain: str,
acceptHandle: str, debug: bool) -> None:
"""Removes a handle from follow rejects
"""
removeFromFollowBase(baseDir, nickname, domain,
_removeFromFollowBase(baseDir, nickname, domain,
acceptHandle, 'followrejects', debug)
@ -179,7 +179,7 @@ def followerOfPerson(baseDir: str, nickname: str, domain: str,
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:
"""is the given nickname a follower of followerNickname?
"""
@ -291,7 +291,7 @@ def clearFollowers(baseDir: str, nickname: str, domain: str) -> None:
clearFollows(baseDir, nickname, domain, 'followers.txt')
def getNoOfFollows(baseDir: str, nickname: str, domain: str,
def _getNoOfFollows(baseDir: str, nickname: str, domain: str,
authenticated: bool,
followFile='following.txt') -> int:
"""Returns the number of follows or followers
@ -324,11 +324,11 @@ def getNoOfFollows(baseDir: str, nickname: str, domain: str,
return ctr
def getNoOfFollowers(baseDir: str,
def _getNoOfFollowers(baseDir: str,
nickname: str, domain: str, authenticated: bool) -> int:
"""Returns the number of followers of the given person
"""
return getNoOfFollows(baseDir, nickname, domain,
return _getNoOfFollows(baseDir, nickname, domain,
authenticated, 'followers.txt')
@ -382,7 +382,7 @@ def getFollowingFeed(baseDir: str, domain: str, port: int, path: str,
httpPrefix + '://' + domain + '/users/' + \
nickname + '/' + followFile
totalStr = \
getNoOfFollows(baseDir, nickname, domain, authenticated)
_getNoOfFollows(baseDir, nickname, domain, authenticated)
following = {
'@context': 'https://www.w3.org/ns/activitystreams',
'first': firstStr,
@ -463,14 +463,14 @@ def getFollowingFeed(baseDir: str, domain: str, port: int, path: str,
return following
def followApprovalRequired(baseDir: str, nicknameToFollow: str,
def _followApprovalRequired(baseDir: str, nicknameToFollow: str,
domainToFollow: str, debug: bool,
followRequestHandle: str,
allowNewsFollowers: bool) -> bool:
""" Returns the policy for follower approvals
"""
# has this handle already been manually approved?
if preApprovedFollower(baseDir, nicknameToFollow, domainToFollow,
if _preApprovedFollower(baseDir, nicknameToFollow, domainToFollow,
followRequestHandle, allowNewsFollowers):
return False
@ -494,7 +494,7 @@ def followApprovalRequired(baseDir: str, nicknameToFollow: str,
return manuallyApproveFollows
def noOfFollowRequests(baseDir: str,
def _noOfFollowRequests(baseDir: str,
nicknameToFollow: str, domainToFollow: str,
nickname: str, domain: str, fromPort: int,
followType: str) -> int:
@ -521,7 +521,7 @@ def noOfFollowRequests(baseDir: str,
return ctr
def storeFollowRequest(baseDir: str,
def _storeFollowRequest(baseDir: str,
nicknameToFollow: str, domainToFollow: str, port: int,
nickname: str, domain: str, fromPort: int,
followJson: {},
@ -668,7 +668,7 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
nicknameToFollow)
return True
if maxFollowers > 0:
if getNoOfFollowers(baseDir,
if _getNoOfFollowers(baseDir,
nicknameToFollow, domainToFollow,
True) > maxFollowers:
print('WARN: ' + nicknameToFollow +
@ -682,7 +682,7 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
baseDir + '/accounts/' + handleToFollow)
return True
if isFollowerOfPerson(baseDir,
if _isFollowerOfPerson(baseDir,
nicknameToFollow, domainToFollowFull,
nickname, domainFull):
if debug:
@ -693,26 +693,26 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
# what is the followers policy?
approveHandle = nickname + '@' + domainFull
if followApprovalRequired(baseDir, nicknameToFollow,
if _followApprovalRequired(baseDir, nicknameToFollow,
domainToFollow, debug, approveHandle,
allowNewsFollowers):
print('Follow approval is required')
if domain.endswith('.onion'):
if noOfFollowRequests(baseDir,
if _noOfFollowRequests(baseDir,
nicknameToFollow, domainToFollow,
nickname, domain, fromPort,
'onion') > 5:
print('Too many follow requests from onion addresses')
return False
elif domain.endswith('.i2p'):
if noOfFollowRequests(baseDir,
if _noOfFollowRequests(baseDir,
nicknameToFollow, domainToFollow,
nickname, domain, fromPort,
'i2p') > 5:
print('Too many follow requests from i2p addresses')
return False
else:
if noOfFollowRequests(baseDir,
if _noOfFollowRequests(baseDir,
nicknameToFollow, domainToFollow,
nickname, domain, fromPort,
'') > 10:
@ -720,7 +720,7 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str,
return False
print('Storing follow request for approval')
return storeFollowRequest(baseDir,
return _storeFollowRequest(baseDir,
nicknameToFollow, domainToFollow, port,
nickname, domain, fromPort,
messageJson, debug, messageJson['actor'])
@ -920,13 +920,13 @@ def sendFollowRequest(session, baseDir: str,
'object': followedId
}
if followApprovalRequired(baseDir, nickname, domain, debug,
if _followApprovalRequired(baseDir, nickname, domain, debug,
followHandle, allowNewsFollowers):
# Remove any follow requests rejected for the account being followed.
# 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
# follow request will block them again.
removeFromFollowRejects(baseDir,
_removeFromFollowRejects(baseDir,
nickname, domain,
followHandle, debug)

View File

@ -34,7 +34,7 @@ def receivingCalendarEvents(baseDir: str, nickname: str, domain: str,
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,
followingDomain: str,
add: bool) -> None:
@ -100,12 +100,12 @@ def receiveCalendarEvents(baseDir: str, nickname: str, domain: str,
def addPersonToCalendar(baseDir: str, nickname: str, domain: str,
followingNickname: str,
followingDomain: str) -> None:
receiveCalendarEvents(baseDir, nickname, domain,
_receiveCalendarEvents(baseDir, nickname, domain,
followingNickname, followingDomain, True)
def removePersonFromCalendar(baseDir: str, nickname: str, domain: str,
followingNickname: str,
followingDomain: str) -> None:
receiveCalendarEvents(baseDir, nickname, domain,
_receiveCalendarEvents(baseDir, nickname, domain,
followingNickname, followingDomain, False)

24
git.py
View File

@ -10,7 +10,7 @@ import os
import html
def gitFormatContent(content: str) -> str:
def _gitFormatContent(content: str) -> str:
""" replace html formatting, so that it's more
like the original patch file
"""
@ -22,7 +22,7 @@ def gitFormatContent(content: str) -> str:
return patchStr
def getGitProjectName(baseDir: str, nickname: str, domain: str,
def _getGitProjectName(baseDir: str, nickname: str, domain: str,
subject: str) -> str:
"""Returns the project name for a git patch
The project name should be contained within the subject line
@ -71,13 +71,13 @@ def isGitPatch(baseDir: str, nickname: str, domain: str,
return False
if checkProjectName:
projectName = \
getGitProjectName(baseDir, nickname, domain, subject)
_getGitProjectName(baseDir, nickname, domain, subject)
if not projectName:
return False
return True
def getGitHash(patchStr: str) -> str:
def _getGitHash(patchStr: str) -> str:
"""Returns the commit hash from a given patch
"""
patchLines = patchStr.split('\n')
@ -91,7 +91,7 @@ def getGitHash(patchStr: str) -> str:
return None
def getPatchDescription(patchStr: str) -> str:
def _getPatchDescription(patchStr: str) -> str:
"""Returns the description from a given patch
"""
patchLines = patchStr.split('\n')
@ -134,8 +134,8 @@ def convertPostToPatch(baseDir: str, nickname: str, domain: str,
postJsonObject['object']['content'],
False):
return False
patchStr = gitFormatContent(postJsonObject['object']['content'])
commitHash = getGitHash(patchStr)
patchStr = _gitFormatContent(postJsonObject['object']['content'])
commitHash = _getGitHash(patchStr)
if not commitHash:
return False
postJsonObject['object']['type'] = 'Patch'
@ -146,7 +146,7 @@ def convertPostToPatch(baseDir: str, nickname: str, domain: str,
postJsonObject['object']['hash'] = commitHash
postJsonObject['object']['description'] = {
"mediaType": "text/plain",
"content": getPatchDescription(patchStr)
"content": _getPatchDescription(patchStr)
}
# remove content map
if postJsonObject['object'].get('contentMap'):
@ -155,7 +155,7 @@ def convertPostToPatch(baseDir: str, nickname: str, domain: str,
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
"""
fromStr = 'AP-signed-off-by: '
@ -181,7 +181,7 @@ def receiveGitPatch(baseDir: str, nickname: str, domain: str,
messageType, subject, content):
return False
patchStr = gitFormatContent(content)
patchStr = _gitFormatContent(content)
patchLines = patchStr.split('\n')
patchFilename = None
@ -197,7 +197,7 @@ def receiveGitPatch(baseDir: str, nickname: str, domain: str,
patchSubject = patchSubject.replace('[PATCH]', '').strip()
patchSubject = patchSubject.replace(' ', '_')
projectName = \
getGitProjectName(baseDir, nickname, domain, subject)
_getGitProjectName(baseDir, nickname, domain, subject)
if not os.path.isdir(patchesDir):
os.mkdir(patchesDir)
projectDir = patchesDir + '/' + projectName
@ -209,7 +209,7 @@ def receiveGitPatch(baseDir: str, nickname: str, domain: str,
if not patchFilename:
return False
patchStr = \
gitAddFromHandle(patchStr, '@' + fromNickname + '@' + fromDomain)
_gitAddFromHandle(patchStr, '@' + fromNickname + '@' + fromDomain)
with open(patchFilename, 'w+') as patchFile:
patchFile.write(patchStr)
patchNotifyFilename = \

View File

@ -17,7 +17,7 @@ from utils import daysInMonth
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
"""
try:
@ -28,7 +28,7 @@ def validUuid(testUuid: str, version=4):
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
"""
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 \
eventJson.get('uuid') and eventJson.get('content'):
if not validUuid(eventJson['uuid']):
if not _validUuid(eventJson['uuid']):
return False
print('Mobilizon type event')
# 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'
if os.path.isfile(tlEventsFilename):
removeEventFromTimeline(eventId, tlEventsFilename)
_removeEventFromTimeline(eventId, tlEventsFilename)
try:
with open(tlEventsFilename, 'r+') as tlEventsFile:
content = tlEventsFile.read()
@ -146,7 +146,7 @@ def saveEventPost(baseDir: str, handle: str, postId: str,
return True
def isHappeningEvent(tag: {}) -> bool:
def _isHappeningEvent(tag: {}) -> bool:
"""Is this tag an Event or Place ActivityStreams type?
"""
if not tag.get('type'):
@ -156,7 +156,7 @@ def isHappeningEvent(tag: {}) -> bool:
return True
def isHappeningPost(postJsonObject: {}) -> bool:
def _isHappeningPost(postJsonObject: {}) -> bool:
"""Is this a post with tags?
"""
if not postJsonObject:
@ -208,13 +208,13 @@ def getTodaysEvents(baseDir: str, nickname: str, domain: str,
continue
postJsonObject = loadJson(postFilename)
if not isHappeningPost(postJsonObject):
if not _isHappeningPost(postJsonObject):
continue
postEvent = []
dayOfMonth = None
for tag in postJsonObject['object']['tag']:
if not isHappeningEvent(tag):
if not _isHappeningEvent(tag):
continue
# this tag is an event or a place
if tag['type'] == 'Event':
@ -275,11 +275,11 @@ def todaysEventsCheck(baseDir: str, nickname: str, domain: str) -> bool:
continue
postJsonObject = loadJson(postFilename)
if not isHappeningPost(postJsonObject):
if not _isHappeningPost(postJsonObject):
continue
for tag in postJsonObject['object']['tag']:
if not isHappeningEvent(tag):
if not _isHappeningEvent(tag):
continue
# this tag is an event or a place
if tag['type'] != 'Event':
@ -322,11 +322,11 @@ def thisWeeksEventsCheck(baseDir: str, nickname: str, domain: str) -> bool:
continue
postJsonObject = loadJson(postFilename)
if not isHappeningPost(postJsonObject):
if not _isHappeningPost(postJsonObject):
continue
for tag in postJsonObject['object']['tag']:
if not isHappeningEvent(tag):
if not _isHappeningEvent(tag):
continue
# this tag is an event or a place
if tag['type'] != 'Event':
@ -377,14 +377,14 @@ def getThisWeeksEvents(baseDir: str, nickname: str, domain: str) -> {}:
continue
postJsonObject = loadJson(postFilename)
if not isHappeningPost(postJsonObject):
if not _isHappeningPost(postJsonObject):
continue
postEvent = []
dayOfMonth = None
weekDayIndex = None
for tag in postJsonObject['object']['tag']:
if not isHappeningEvent(tag):
if not _isHappeningEvent(tag):
continue
# this tag is an event or a place
if tag['type'] == 'Event':
@ -462,13 +462,13 @@ def getCalendarEvents(baseDir: str, nickname: str, domain: str,
continue
postJsonObject = loadJson(postFilename)
if not isHappeningPost(postJsonObject):
if not _isHappeningPost(postJsonObject):
continue
postEvent = []
dayOfMonth = None
for tag in postJsonObject['object']['tag']:
if not isHappeningEvent(tag):
if not _isHappeningEvent(tag):
continue
# this tag is an event or a place
if tag['type'] == 'Event':

View File

@ -135,7 +135,7 @@ def createSignedHeader(privateKeyPem: str, nickname: str,
return headers
def verifyRecentSignature(signedDateStr: str) -> bool:
def _verifyRecentSignature(signedDateStr: str) -> bool:
"""Checks whether the given time taken from the header is within
12 hours of the current time
"""
@ -219,7 +219,7 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
else:
if headers.get(signedHeader):
if signedHeader == 'date':
if not verifyRecentSignature(headers[signedHeader]):
if not _verifyRecentSignature(headers[signedHeader]):
if debug:
print('DEBUG: ' +
'verifyPostHeaders date is not recent ' +
@ -230,7 +230,7 @@ def verifyPostHeaders(httpPrefix: str, publicKeyPem: str, headers: dict,
else:
signedHeaderCap = signedHeader.capitalize()
if signedHeaderCap == 'Date':
if not verifyRecentSignature(headers[signedHeaderCap]):
if not _verifyRecentSignature(headers[signedHeaderCap]):
if debug:
print('DEBUG: ' +
'verifyPostHeaders date is not recent ' +

158
inbox.py
View File

@ -138,7 +138,7 @@ def storeHashTags(baseDir: str, nickname: str, postJsonObject: {}) -> None:
setHashtagCategory(baseDir, tagName, categoryStr)
def inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int,
def _inboxStorePostToHtmlCache(recentPostsCache: {}, maxRecentPosts: int,
translate: {},
baseDir: str, httpPrefix: str,
session, cachedWebfingers: {}, personCache: {},
@ -451,7 +451,7 @@ def savePostToInboxQueue(baseDir: str, httpPrefix: str,
return filename
def inboxPostRecipientsAdd(baseDir: str, httpPrefix: str, toList: [],
def _inboxPostRecipientsAdd(baseDir: str, httpPrefix: str, toList: [],
recipientsDict: {},
domainMatch: str, domain: str,
actor: str, debug: bool) -> bool:
@ -485,7 +485,7 @@ def inboxPostRecipientsAdd(baseDir: str, httpPrefix: str, toList: [],
return followerRecipients, recipientsDict
def inboxPostRecipients(baseDir: str, postJsonObject: {},
def _inboxPostRecipients(baseDir: str, postJsonObject: {},
httpPrefix: str, domain: str, port: int,
debug: bool) -> ([], []):
"""Returns dictionaries containing the recipients of the given post
@ -520,7 +520,7 @@ def inboxPostRecipients(baseDir: str, postJsonObject: {},
if debug:
print('DEBUG: resolving "to"')
includesFollowers, recipientsDict = \
inboxPostRecipientsAdd(baseDir, httpPrefix,
_inboxPostRecipientsAdd(baseDir, httpPrefix,
recipientsList,
recipientsDict,
domainMatch, domainBase,
@ -537,7 +537,7 @@ def inboxPostRecipients(baseDir: str, postJsonObject: {},
else:
recipientsList = [postJsonObject['object']['cc']]
includesFollowers, recipientsDict = \
inboxPostRecipientsAdd(baseDir, httpPrefix,
_inboxPostRecipientsAdd(baseDir, httpPrefix,
recipientsList,
recipientsDict,
domainMatch, domainBase,
@ -562,7 +562,7 @@ def inboxPostRecipients(baseDir: str, postJsonObject: {},
else:
recipientsList = [postJsonObject['to']]
includesFollowers, recipientsDict = \
inboxPostRecipientsAdd(baseDir, httpPrefix,
_inboxPostRecipientsAdd(baseDir, httpPrefix,
recipientsList,
recipientsDict,
domainMatch, domainBase,
@ -576,7 +576,7 @@ def inboxPostRecipients(baseDir: str, postJsonObject: {},
else:
recipientsList = [postJsonObject['cc']]
includesFollowers, recipientsDict = \
inboxPostRecipientsAdd(baseDir, httpPrefix,
_inboxPostRecipientsAdd(baseDir, httpPrefix,
recipientsList,
recipientsDict,
domainMatch, domainBase,
@ -596,7 +596,7 @@ def inboxPostRecipients(baseDir: str, postJsonObject: {},
return recipientsDict, recipientsDictFollowers
def receiveUndoFollow(session, baseDir: str, httpPrefix: str,
def _receiveUndoFollow(session, baseDir: str, httpPrefix: str,
port: int, messageJson: {},
federationList: [],
debug: bool) -> bool:
@ -653,7 +653,7 @@ def receiveUndoFollow(session, baseDir: str, httpPrefix: str,
return False
def receiveUndo(session, baseDir: str, httpPrefix: str,
def _receiveUndo(session, baseDir: str, httpPrefix: str,
port: int, sendThreads: [], postLog: [],
cachedWebfingers: {}, personCache: {},
messageJson: {}, federationList: [],
@ -698,13 +698,13 @@ def receiveUndo(session, baseDir: str, httpPrefix: str,
' object within object is not a string')
return False
if messageJson['object']['type'] == 'Follow':
return receiveUndoFollow(session, baseDir, httpPrefix,
return _receiveUndoFollow(session, baseDir, httpPrefix,
port, messageJson,
federationList, debug)
return False
def receiveEventPost(recentPostsCache: {}, session, baseDir: str,
def _receiveEventPost(recentPostsCache: {}, session, baseDir: str,
httpPrefix: str, domain: str, port: int,
sendThreads: [], postLog: [], cachedWebfingers: {},
personCache: {}, messageJson: {}, federationList: [],
@ -723,11 +723,12 @@ def receiveEventPost(recentPostsCache: {}, session, baseDir: str,
saveEventPost(baseDir, handle, postId, messageJson['object'])
def personReceiveUpdate(baseDir: str,
def _personReceiveUpdate(baseDir: str,
domain: str, port: int,
updateNickname: str, updateDomain: str,
updatePort: int,
personJson: {}, personCache: {}, debug: bool) -> bool:
personJson: {}, personCache: {},
debug: bool) -> bool:
"""Changes an actor. eg: avatar or display name change
"""
print('Receiving actor update for ' + personJson['url'] +
@ -795,8 +796,9 @@ def personReceiveUpdate(baseDir: str,
return True
def receiveUpdateToQuestion(recentPostsCache: {}, messageJson: {},
baseDir: str, nickname: str, domain: str) -> None:
def _receiveUpdateToQuestion(recentPostsCache: {}, messageJson: {},
baseDir: str,
nickname: str, domain: str) -> None:
"""Updating a question as new votes arrive
"""
# message url of the question
@ -832,7 +834,7 @@ def receiveUpdateToQuestion(recentPostsCache: {}, messageJson: {},
removePostFromCache(messageJson, recentPostsCache)
def receiveUpdate(recentPostsCache: {}, session, baseDir: str,
def _receiveUpdate(recentPostsCache: {}, session, baseDir: str,
httpPrefix: str, domain: str, port: int,
sendThreads: [], postLog: [], cachedWebfingers: {},
personCache: {}, messageJson: {}, federationList: [],
@ -867,7 +869,7 @@ def receiveUpdate(recentPostsCache: {}, session, baseDir: str,
return False
if messageJson['object']['type'] == 'Question':
receiveUpdateToQuestion(recentPostsCache, messageJson,
_receiveUpdateToQuestion(recentPostsCache, messageJson,
baseDir, nickname, domain)
if debug:
print('DEBUG: Question update was received')
@ -880,7 +882,7 @@ def receiveUpdate(recentPostsCache: {}, session, baseDir: str,
if updateNickname:
updateDomain, updatePort = \
getDomainFromActor(messageJson['id'])
if personReceiveUpdate(baseDir, domain, port,
if _personReceiveUpdate(baseDir, domain, port,
updateNickname, updateDomain,
updatePort, messageJson,
personCache, debug):
@ -901,7 +903,7 @@ def receiveUpdate(recentPostsCache: {}, session, baseDir: str,
if updateNickname:
updateDomain, updatePort = \
getDomainFromActor(messageJson['actor'])
if personReceiveUpdate(baseDir,
if _personReceiveUpdate(baseDir,
domain, port,
updateNickname, updateDomain,
updatePort,
@ -914,7 +916,7 @@ def receiveUpdate(recentPostsCache: {}, session, baseDir: str,
return False
def receiveLike(recentPostsCache: {},
def _receiveLike(recentPostsCache: {},
session, handle: str, isGroup: bool, baseDir: str,
httpPrefix: str, domain: str, port: int,
onionDomain: str,
@ -968,7 +970,7 @@ def receiveLike(recentPostsCache: {},
if debug:
print('DEBUG: liked post found in inbox')
if not alreadyLiked(baseDir,
if not _alreadyLiked(baseDir,
handle.split('@')[0],
handle.split('@')[1],
messageJson['object'],
@ -976,12 +978,12 @@ def receiveLike(recentPostsCache: {},
updateLikesCollection(recentPostsCache, baseDir, postFilename,
messageJson['object'],
messageJson['actor'], domain, debug)
likeNotify(baseDir, domain, onionDomain, handle,
_likeNotify(baseDir, domain, onionDomain, handle,
messageJson['actor'], messageJson['object'])
return True
def receiveUndoLike(recentPostsCache: {},
def _receiveUndoLike(recentPostsCache: {},
session, handle: str, isGroup: bool, baseDir: str,
httpPrefix: str, domain: str, port: int,
sendThreads: [], postLog: [], cachedWebfingers: {},
@ -1042,7 +1044,7 @@ def receiveUndoLike(recentPostsCache: {},
return True
def receiveBookmark(recentPostsCache: {},
def _receiveBookmark(recentPostsCache: {},
session, handle: str, isGroup: bool, baseDir: str,
httpPrefix: str, domain: str, port: int,
sendThreads: [], postLog: [], cachedWebfingers: {},
@ -1108,7 +1110,7 @@ def receiveBookmark(recentPostsCache: {},
return True
def receiveUndoBookmark(recentPostsCache: {},
def _receiveUndoBookmark(recentPostsCache: {},
session, handle: str, isGroup: bool, baseDir: str,
httpPrefix: str, domain: str, port: int,
sendThreads: [], postLog: [], cachedWebfingers: {},
@ -1177,7 +1179,7 @@ def receiveUndoBookmark(recentPostsCache: {},
return True
def receiveDelete(session, handle: str, isGroup: bool, baseDir: str,
def _receiveDelete(session, handle: str, isGroup: bool, baseDir: str,
httpPrefix: str, domain: str, port: int,
sendThreads: [], postLog: [], cachedWebfingers: {},
personCache: {}, messageJson: {}, federationList: [],
@ -1263,9 +1265,10 @@ def receiveDelete(session, handle: str, isGroup: bool, baseDir: str,
return True
def receiveAnnounce(recentPostsCache: {},
def _receiveAnnounce(recentPostsCache: {},
session, handle: str, isGroup: bool, baseDir: str,
httpPrefix: str, domain: str, onionDomain: str, port: int,
httpPrefix: str,
domain: str, onionDomain: str, port: int,
sendThreads: [], postLog: [], cachedWebfingers: {},
personCache: {}, messageJson: {}, federationList: [],
debug: bool, translate: {},
@ -1410,7 +1413,7 @@ def receiveAnnounce(recentPostsCache: {},
return True
def receiveUndoAnnounce(recentPostsCache: {},
def _receiveUndoAnnounce(recentPostsCache: {},
session, handle: str, isGroup: bool, baseDir: str,
httpPrefix: str, domain: str, port: int,
sendThreads: [], postLog: [], cachedWebfingers: {},
@ -1482,7 +1485,7 @@ def jsonPostAllowsComments(postJsonObject: {}) -> bool:
return True
def postAllowsComments(postFilename: str) -> bool:
def _postAllowsComments(postFilename: str) -> bool:
"""Returns true if the given post allows comments/replies
"""
postJsonObject = loadJson(postFilename)
@ -1533,7 +1536,7 @@ def populateReplies(baseDir: str, httpPrefix: str, domain: str,
if debug:
print('DEBUG: post may have expired - ' + replyTo)
return False
if not postAllowsComments(postFilename):
if not _postAllowsComments(postFilename):
if debug:
print('DEBUG: post does not allow comments - ' + replyTo)
return False
@ -1555,19 +1558,19 @@ def populateReplies(baseDir: str, httpPrefix: str, domain: str,
return True
def estimateNumberOfMentions(content: str) -> int:
def _estimateNumberOfMentions(content: str) -> int:
"""Returns a rough estimate of the number of mentions
"""
return int(content.count('@') / 2)
def estimateNumberOfEmoji(content: str) -> int:
def _estimateNumberOfEmoji(content: str) -> int:
"""Returns a rough estimate of the number of emoji
"""
return int(content.count(':') / 2)
def validPostContent(baseDir: str, nickname: str, domain: str,
def _validPostContent(baseDir: str, nickname: str, domain: str,
messageJson: {}, maxMentions: int, maxEmoji: int,
allowLocalNetworkAccess: bool) -> bool:
"""Is the content of a received post valid?
@ -1615,14 +1618,14 @@ def validPostContent(baseDir: str, nickname: str, domain: str,
return False
# check (rough) number of mentions
mentionsEst = estimateNumberOfMentions(messageJson['object']['content'])
mentionsEst = _estimateNumberOfMentions(messageJson['object']['content'])
if mentionsEst > maxMentions:
if messageJson['object'].get('id'):
print('REJECT HELLTHREAD: ' + messageJson['object']['id'])
print('REJECT HELLTHREAD: Too many mentions in post - ' +
messageJson['object']['content'])
return False
if estimateNumberOfEmoji(messageJson['object']['content']) > maxEmoji:
if _estimateNumberOfEmoji(messageJson['object']['content']) > maxEmoji:
if messageJson['object'].get('id'):
print('REJECT EMOJI OVERLOAD: ' + messageJson['object']['id'])
print('REJECT EMOJI OVERLOAD: Too many emoji in post - ' +
@ -1650,7 +1653,7 @@ def validPostContent(baseDir: str, nickname: str, domain: str,
postPostFilename = locatePost(baseDir, nickname, domain,
originalPostId)
if postPostFilename:
if not postAllowsComments(postPostFilename):
if not _postAllowsComments(postPostFilename):
print('REJECT: reply to post which does not ' +
'allow comments: ' + originalPostId)
return False
@ -1658,7 +1661,7 @@ def validPostContent(baseDir: str, nickname: str, domain: str,
return True
def obtainAvatarForReplyPost(session, baseDir: str, httpPrefix: str,
def _obtainAvatarForReplyPost(session, baseDir: str, httpPrefix: str,
domain: str, onionDomain: str, personCache: {},
postJsonObject: {}, debug: bool) -> None:
"""Tries to obtain the actor for the person being replied to
@ -1708,7 +1711,7 @@ def obtainAvatarForReplyPost(session, baseDir: str, httpPrefix: str,
time.sleep(5)
def dmNotify(baseDir: str, handle: str, url: str) -> None:
def _dmNotify(baseDir: str, handle: str, url: str) -> None:
"""Creates a notification that a new DM has arrived
"""
accountDir = baseDir + '/accounts/' + handle
@ -1720,7 +1723,7 @@ def dmNotify(baseDir: str, handle: str, url: str) -> None:
fp.write(url)
def alreadyLiked(baseDir: str, nickname: str, domain: str,
def _alreadyLiked(baseDir: str, nickname: str, domain: str,
postUrl: str, likerActor: str) -> bool:
"""Is the given post already liked by the given handle?
"""
@ -1751,7 +1754,7 @@ def alreadyLiked(baseDir: str, nickname: str, domain: str,
return False
def likeNotify(baseDir: str, domain: str, onionDomain: str,
def _likeNotify(baseDir: str, domain: str, onionDomain: str,
handle: str, actor: str, url: str) -> None:
"""Creates a notification that a like has arrived
"""
@ -1784,7 +1787,7 @@ def likeNotify(baseDir: str, domain: str, onionDomain: str,
if likerNickname and likerDomain:
likerHandle = likerNickname + '@' + likerDomain
else:
print('likeNotify likerHandle: ' +
print('_likeNotify likerHandle: ' +
str(likerNickname) + '@' + str(likerDomain))
likerHandle = actor
if likerHandle != handle:
@ -1813,7 +1816,7 @@ def likeNotify(baseDir: str, domain: str, onionDomain: str,
pass
def replyNotify(baseDir: str, handle: str, url: str) -> None:
def _replyNotify(baseDir: str, handle: str, url: str) -> None:
"""Creates a notification that a new reply has arrived
"""
accountDir = baseDir + '/accounts/' + handle
@ -1825,7 +1828,7 @@ def replyNotify(baseDir: str, handle: str, url: str) -> None:
fp.write(url)
def gitPatchNotify(baseDir: str, handle: str,
def _gitPatchNotify(baseDir: str, handle: str,
subject: str, content: str,
fromNickname: str, fromDomain: str) -> None:
"""Creates a notification that a new git patch has arrived
@ -1840,7 +1843,7 @@ def gitPatchNotify(baseDir: str, handle: str,
fp.write('git ' + handle + ' ' + subject)
def groupHandle(baseDir: str, handle: str) -> bool:
def _groupHandle(baseDir: str, handle: str) -> bool:
"""Is the given account handle a group?
"""
actorFile = baseDir + '/accounts/' + handle + '.json'
@ -1852,7 +1855,7 @@ def groupHandle(baseDir: str, handle: str) -> bool:
return actorJson['type'] == 'Group'
def getGroupName(baseDir: str, handle: str) -> str:
def _getGroupName(baseDir: str, handle: str) -> str:
"""Returns the preferred name of a group
"""
actorFile = baseDir + '/accounts/' + handle + '.json'
@ -1864,7 +1867,7 @@ def getGroupName(baseDir: str, handle: str) -> str:
return actorJson['name']
def sendToGroupMembers(session, baseDir: str, handle: str, port: int,
def _sendToGroupMembers(session, baseDir: str, handle: str, port: int,
postJsonObject: {},
httpPrefix: str, federationList: [],
sendThreads: [], postLog: [], cachedWebfingers: {},
@ -1877,7 +1880,7 @@ def sendToGroupMembers(session, baseDir: str, handle: str, port: int,
if not postJsonObject.get('object'):
return
nickname = handle.split('@')[0]
# groupname = getGroupName(baseDir, handle)
# groupname = _getGroupName(baseDir, handle)
domain = handle.split('@')[1]
domainFull = getFullDomain(domain, port)
# set sender
@ -1941,7 +1944,8 @@ def sendToGroupMembers(session, baseDir: str, handle: str, port: int,
personCache, debug, __version__)
def inboxUpdateCalendar(baseDir: str, handle: str, postJsonObject: {}) -> None:
def _inboxUpdateCalendar(baseDir: str, handle: str,
postJsonObject: {}) -> None:
"""Detects whether the tag list on a post contains calendar events
and if so saves the post id to a file in the calendar directory
for the account
@ -2017,7 +2021,7 @@ def inboxUpdateIndex(boxname: str, baseDir: str, handle: str,
return False
def updateLastSeen(baseDir: str, handle: str, actor: str) -> None:
def _updateLastSeen(baseDir: str, handle: str, actor: str) -> None:
"""Updates the time when the given handle last saw the given actor
This can later be used to indicate if accounts are dormant/abandoned/moved
"""
@ -2049,7 +2053,7 @@ def updateLastSeen(baseDir: str, handle: str, actor: str) -> None:
lastSeenFile.write(str(daysSinceEpoch))
def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
session, keyId: str, handle: str, messageJson: {},
baseDir: str, httpPrefix: str, sendThreads: [],
postLog: [], cachedWebfingers: {}, personCache: {},
@ -2069,11 +2073,11 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
if '#' in actor:
actor = keyId.split('#')[0]
updateLastSeen(baseDir, handle, actor)
_updateLastSeen(baseDir, handle, actor)
isGroup = groupHandle(baseDir, handle)
isGroup = _groupHandle(baseDir, handle)
if receiveLike(recentPostsCache,
if _receiveLike(recentPostsCache,
session, handle, isGroup,
baseDir, httpPrefix,
domain, port,
@ -2088,7 +2092,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
print('DEBUG: Like accepted from ' + actor)
return False
if receiveUndoLike(recentPostsCache,
if _receiveUndoLike(recentPostsCache,
session, handle, isGroup,
baseDir, httpPrefix,
domain, port,
@ -2102,7 +2106,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
print('DEBUG: Undo like accepted from ' + actor)
return False
if receiveBookmark(recentPostsCache,
if _receiveBookmark(recentPostsCache,
session, handle, isGroup,
baseDir, httpPrefix,
domain, port,
@ -2116,7 +2120,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
print('DEBUG: Bookmark accepted from ' + actor)
return False
if receiveUndoBookmark(recentPostsCache,
if _receiveUndoBookmark(recentPostsCache,
session, handle, isGroup,
baseDir, httpPrefix,
domain, port,
@ -2130,9 +2134,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
print('DEBUG: Undo bookmark accepted from ' + actor)
return False
# labelAccusatoryPost(messageJson, translate)
if receiveAnnounce(recentPostsCache,
if _receiveAnnounce(recentPostsCache,
session, handle, isGroup,
baseDir, httpPrefix,
domain, onionDomain, port,
@ -2146,7 +2148,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
if debug:
print('DEBUG: Announce accepted from ' + actor)
if receiveUndoAnnounce(recentPostsCache,
if _receiveUndoAnnounce(recentPostsCache,
session, handle, isGroup,
baseDir, httpPrefix,
domain, port,
@ -2160,7 +2162,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
print('DEBUG: Undo announce accepted from ' + actor)
return False
if receiveDelete(session, handle, isGroup,
if _receiveDelete(session, handle, isGroup,
baseDir, httpPrefix,
domain, port,
sendThreads, postLog,
@ -2188,7 +2190,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
postJsonObject = messageJson
nickname = handle.split('@')[0]
if validPostContent(baseDir, nickname, domain,
if _validPostContent(baseDir, nickname, domain,
postJsonObject, maxMentions, maxEmoji,
allowLocalNetworkAccess):
@ -2213,7 +2215,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
jsonObj['summary'],
jsonObj['content'],
fromNickname, fromDomain):
gitPatchNotify(baseDir, handle,
_gitPatchNotify(baseDir, handle,
jsonObj['summary'],
jsonObj['content'],
fromNickname, fromDomain)
@ -2293,7 +2295,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
return False
# dm index will be updated
updateIndexList.append('dm')
dmNotify(baseDir, handle,
_dmNotify(baseDir, handle,
httpPrefix + '://' + domain + '/users/' +
nickname + '/dm')
@ -2313,7 +2315,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
if isinstance(inReplyTo, str):
if not isMuted(baseDir, nickname, domain,
inReplyTo):
replyNotify(baseDir, handle,
_replyNotify(baseDir, handle,
httpPrefix + '://' + domain +
'/users/' + nickname +
'/tlreplies')
@ -2333,7 +2335,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
updateIndexList.append('tlevents')
# get the avatar for a reply/announce
obtainAvatarForReplyPost(session, baseDir,
_obtainAvatarForReplyPost(session, baseDir,
httpPrefix, domain, onionDomain,
personCache, postJsonObject, debug)
@ -2359,7 +2361,7 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
print('Saving inbox post as html to cache')
htmlCacheStartTime = time.time()
inboxStorePostToHtmlCache(recentPostsCache,
_inboxStorePostToHtmlCache(recentPostsCache,
maxRecentPosts,
translate, baseDir,
httpPrefix,
@ -2379,13 +2381,13 @@ def inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
' post as html to cache in ' +
timeDiff + ' mS')
inboxUpdateCalendar(baseDir, handle, postJsonObject)
_inboxUpdateCalendar(baseDir, handle, postJsonObject)
storeHashTags(baseDir, handle.split('@')[0], postJsonObject)
# send the post out to group members
if isGroup:
sendToGroupMembers(session, baseDir, handle, port,
_sendToGroupMembers(session, baseDir, handle, port,
postJsonObject,
httpPrefix, federationList, sendThreads,
postLog, cachedWebfingers, personCache,
@ -2420,7 +2422,7 @@ def clearQueueItems(baseDir: str, queue: []) -> None:
print('Removed ' + str(ctr) + ' inbox queue items')
def restoreQueueItems(baseDir: str, queue: []) -> None:
def _restoreQueueItems(baseDir: str, queue: []) -> None:
"""Checks the queue for each account and appends filenames
"""
queue.clear()
@ -2483,7 +2485,7 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
# if queue processing was interrupted (eg server crash)
# then this loads any outstanding items back into the queue
restoreQueueItems(baseDir, queue)
_restoreQueueItems(baseDir, queue)
# keep track of numbers of incoming posts per day
quotasLastUpdateDaily = int(time.time())
@ -2515,7 +2517,7 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
queueRestoreCtr += 1
if queueRestoreCtr >= 30:
queueRestoreCtr = 0
restoreQueueItems(baseDir, queue)
_restoreQueueItems(baseDir, queue)
continue
currTime = int(time.time())
@ -2731,7 +2733,7 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
# if queueJson['post'].get('id'):
# queueJson['post']['id']=queueJson['id']
if receiveUndo(session,
if _receiveUndo(session,
baseDir, httpPrefix, port,
sendThreads, postLog,
cachedWebfingers,
@ -2782,7 +2784,7 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
queue.pop(0)
continue
if receiveEventPost(recentPostsCache, session,
if _receiveEventPost(recentPostsCache, session,
baseDir, httpPrefix,
domain, port,
sendThreads, postLog,
@ -2799,7 +2801,7 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
queue.pop(0)
continue
if receiveUpdate(recentPostsCache, session,
if _receiveUpdate(recentPostsCache, session,
baseDir, httpPrefix,
domain, port,
sendThreads, postLog,
@ -2818,7 +2820,7 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
# get recipients list
recipientsDict, recipientsDictFollowers = \
inboxPostRecipients(baseDir, queueJson['post'],
_inboxPostRecipients(baseDir, queueJson['post'],
httpPrefix, domain, port, debug)
if len(recipientsDict.items()) == 0 and \
len(recipientsDictFollowers.items()) == 0:
@ -2866,7 +2868,7 @@ def runInboxQueue(recentPostsCache: {}, maxRecentPosts: int,
for handle, capsId in recipientsDict.items():
destination = \
queueJson['destination'].replace(inboxHandle, handle)
inboxAfterInitial(recentPostsCache,
_inboxAfterInitial(recentPostsCache,
maxRecentPosts,
session, keyId, handle,
queueJson['post'],

View File

@ -28,21 +28,21 @@ import base64
import json
def b64safeEncode(payload: {}) -> str:
def _b64safeEncode(payload: {}) -> str:
"""
b64 url safe encoding with the padding removed.
"""
return base64.urlsafe_b64encode(payload).rstrip(b'=')
def b64safeDecode(payload: {}) -> str:
def _b64safeDecode(payload: {}) -> str:
"""
b64 url safe decoding with the padding added.
"""
return base64.urlsafe_b64decode(payload + b'=' * (4 - len(payload) % 4))
def normalizeJson(payload: {}) -> str:
def _normalizeJson(payload: {}) -> str:
"""
Normalize with URDNA2015
"""
@ -50,7 +50,7 @@ def normalizeJson(payload: {}) -> str:
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
"""
@ -60,7 +60,7 @@ def signRs256(payload: {}, privateKeyPem: str) -> str:
return signature
def verifyRs256(payload: {}, signature: str, publicKeyPem: str) -> bool:
def _verifyRs256(payload: {}, signature: str, publicKeyPem: str) -> bool:
"""
Verifies a RS256 signature
"""
@ -69,7 +69,7 @@ def verifyRs256(payload: {}, signature: str, publicKeyPem: str) -> bool:
return verifier.verify(SHA256.new(payload), signature)
def signJws(payload: {}, privateKeyPem: str) -> str:
def _signJws(payload: {}, privateKeyPem: str) -> str:
"""
Prepare payload to sign
"""
@ -78,28 +78,28 @@ def signJws(payload: {}, privateKeyPem: str) -> str:
'b64': False,
'crit': ['b64']
}
normalizedJson = normalizeJson(header)
encodedHeader = b64safeEncode(normalizedJson)
normalizedJson = _normalizeJson(header)
encodedHeader = _b64safeEncode(normalizedJson)
preparedPayload = b'.'.join([encodedHeader, payload])
signature = signRs256(preparedPayload, privateKeyPem)
encodedSignature = b64safeEncode(signature)
signature = _signRs256(preparedPayload, privateKeyPem)
encodedSignature = _b64safeEncode(signature)
jwsSignature = b'..'.join([encodedHeader, encodedSignature])
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
"""
encodedHeader, encodedSignature = jwsSignature.split(b'..')
signature = b64safeDecode(encodedSignature)
signature = _b64safeDecode(encodedSignature)
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
"""
@ -117,8 +117,8 @@ def jsonldSign(jldDocument: {}, privateKeyPem: str) -> {}:
Produces a signed JSON-LD document with a Json Web Signature
"""
jldDocument = deepcopy(jldDocument)
normalizedJldHash = jsonldNormalize(jldDocument)
jwsSignature = signJws(normalizedJldHash, privateKeyPem)
normalizedJldHash = _jsonldNormalize(jldDocument)
jwsSignature = _signJws(normalizedJldHash, privateKeyPem)
# construct the signature document and add it to jsonld
signature = {
@ -138,9 +138,9 @@ def jsonldVerify(signedJldDocument: {}, publicKeyPem: str) -> bool:
signedJldDocument = deepcopy(signedJldDocument)
signature = signedJldDocument.pop('signature')
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) -> {}:

View File

@ -50,7 +50,7 @@ def noOfLikes(postJsonObject: {}) -> int:
return len(postJsonObject['object']['likes']['items'])
def like(recentPostsCache: {},
def _like(recentPostsCache: {},
session, baseDir: str, federationList: [],
nickname: str, domain: str, port: int,
ccList: [], httpPrefix: str,
@ -134,7 +134,7 @@ def likePost(recentPostsCache: {},
actorLiked = httpPrefix + '://' + likeDomain + '/users/' + likeNickname
objectUrl = actorLiked + '/statuses/' + str(likeStatusNumber)
return like(recentPostsCache,
return _like(recentPostsCache,
session, baseDir, federationList, nickname, domain, port,
ccList, httpPrefix, objectUrl, actorLiked, clientToServer,
sendThreads, postLog, personCache, cachedWebfingers,

View File

@ -62,7 +62,7 @@ def manualDenyFollowRequest(session, baseDir: str,
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
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
if approveHandleFull in open(followersFilename).read():
# mark this handle as approved for following
approveFollowerHandle(accountDir, approveHandle)
_approveFollowerHandle(accountDir, approveHandle)
# update the follow requests with the handles not yet approved
os.rename(approveFollowsFilename + '.new', approveFollowsFilename)
# remove the .follow file

View File

@ -56,12 +56,12 @@ def removeMetaData(imageFilename: str, outputFilename: str) -> None:
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"))
return blurhash_encode(value)
def isMedia(imageFilename: str) -> bool:
def _isMedia(imageFilename: str) -> bool:
permittedMedia = getMediaExtensions()
for m in permittedMedia:
if imageFilename.endswith('.' + m):
@ -103,7 +103,7 @@ def getAttachmentMediaType(filename: str) -> str:
return mediaType
def updateEtag(mediaFilename: str) -> None:
def _updateEtag(mediaFilename: str) -> None:
""" calculate the etag, which is a sha1 of the data
"""
# 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
time to calculate it
"""
if not isMedia(imageFilename):
if not _isMedia(imageFilename):
return postJson
fileExtension = None
@ -182,7 +182,7 @@ def attachMedia(baseDir: str, httpPrefix: str, domain: str, port: int,
if mediaType.startswith('image/'):
attachmentJson['focialPoint'] = [0.0, 0.0]
if useBlurhash:
attachmentJson['blurhash'] = getImageHash(imageFilename)
attachmentJson['blurhash'] = _getImageHash(imageFilename)
postJson['attachment'] = [attachmentJson]
if baseDir:
@ -190,7 +190,7 @@ def attachMedia(baseDir: str, httpPrefix: str, domain: str, port: int,
removeMetaData(imageFilename, mediaFilename)
else:
copyfile(imageFilename, mediaFilename)
updateEtag(mediaFilename)
_updateEtag(mediaFilename)
return postJson

View File

@ -9,7 +9,7 @@ __status__ = "Production"
import os
def migrateFollows(followFilename: str, oldHandle: str,
def _migrateFollows(followFilename: str, oldHandle: str,
newHandle: str) -> None:
"""Changes a handle within following or followers list
"""
@ -48,7 +48,7 @@ def migrateAccount(baseDir: str, oldHandle: str, newHandle: str) -> None:
if '@' in handle:
accountDir = baseDir + '/accounts/' + handle
followFilename = accountDir + '/following.txt'
migrateFollows(followFilename, oldHandle, newHandle)
_migrateFollows(followFilename, oldHandle, newHandle)
followFilename = accountDir + '/followers.txt'
migrateFollows(followFilename, oldHandle, newHandle)
_migrateFollows(followFilename, oldHandle, newHandle)
break

View File

@ -35,7 +35,7 @@ from inbox import storeHashTags
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
"""
basePath = baseDir + '/accounts/news@' + domain
@ -59,7 +59,7 @@ def updateFeedsOutboxIndex(baseDir: str, domain: str, postId: str) -> None:
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
"""
arrivedFile = open(postFilename + '.arrived', 'w+')
@ -68,7 +68,7 @@ def saveArrivedTime(baseDir: str, postFilename: str, arrived: str) -> None:
arrivedFile.close()
def removeControlCharacters(content: str) -> str:
def _removeControlCharacters(content: str) -> str:
"""Remove escaped html
"""
if '&' in content:
@ -227,7 +227,7 @@ def hashtagRuleTree(operators: [],
return tree
def newswireHashtagProcessing(session, baseDir: str, postJsonObject: {},
def _newswireHashtagProcessing(session, baseDir: str, postJsonObject: {},
hashtags: [], httpPrefix: str,
domain: str, port: int,
personCache: {},
@ -356,7 +356,7 @@ def newswireHashtagProcessing(session, baseDir: str, postJsonObject: {},
return True
def createNewsMirror(baseDir: str, domain: str,
def _createNewsMirror(baseDir: str, domain: str,
postIdNumber: str, url: str,
maxMirroredArticles: int) -> bool:
"""Creates a local mirror of a news article
@ -446,7 +446,7 @@ def createNewsMirror(baseDir: str, domain: str,
return True
def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
def _convertRSStoActivityPub(baseDir: str, httpPrefix: str,
domain: str, port: int,
newswire: {},
translate: {},
@ -497,7 +497,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
newswire[originalDateStr][3] = filename
continue
rssTitle = removeControlCharacters(item[0])
rssTitle = _removeControlCharacters(item[0])
url = item[1]
if dangerousMarkup(url, allowLocalNetworkAccess) or \
dangerousMarkup(rssTitle, allowLocalNetworkAccess):
@ -505,7 +505,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
rssDescription = ''
# get the rss description if it exists
rssDescription = removeControlCharacters(item[4])
rssDescription = _removeControlCharacters(item[4])
if rssDescription.startswith('<![CDATA['):
rssDescription = rssDescription.replace('<![CDATA[', '')
rssDescription = rssDescription.replace(']]>', '')
@ -555,7 +555,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
continue
if mirrored:
if not createNewsMirror(baseDir, domain, statusNumber,
if not _createNewsMirror(baseDir, domain, statusNumber,
url, maxMirroredArticles):
continue
@ -590,7 +590,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
moderated = item[5]
savePost = newswireHashtagProcessing(session, baseDir, blog, hashtags,
savePost = _newswireHashtagProcessing(session, baseDir, blog, hashtags,
httpPrefix, domain, port,
personCache, cachedWebfingers,
federationList,
@ -628,7 +628,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
blog['object']['content'] = content
# update the newswire tags if new ones have been found by
# newswireHashtagProcessing
# _newswireHashtagProcessing
for tag in hashtags:
if tag not in newswire[originalDateStr][6]:
newswire[originalDateStr][6].append(tag)
@ -637,13 +637,13 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
clearFromPostCaches(baseDir, recentPostsCache, postId)
if saveJson(blog, filename):
updateFeedsOutboxIndex(baseDir, domain, postId + '.json')
_updateFeedsOutboxIndex(baseDir, domain, postId + '.json')
# Save a file containing the time when the post arrived
# this can then later be used to construct the news timeline
# excluding items during the voting period
if moderated:
saveArrivedTime(baseDir, filename,
_saveArrivedTime(baseDir, filename,
blog['object']['arrived'])
else:
if os.path.isfile(filename + '.arrived'):
@ -658,7 +658,7 @@ def convertRSStoActivityPub(baseDir: str, httpPrefix: str,
newswire[originalDateStr][3] = filename
def mergeWithPreviousNewswire(oldNewswire: {}, newNewswire: {}) -> None:
def _mergeWithPreviousNewswire(oldNewswire: {}, newNewswire: {}) -> None:
"""Preserve any votes or generated activitypub post filename
as rss feeds are updated
"""
@ -707,14 +707,14 @@ def runNewswireDaemon(baseDir: str, httpd,
if os.path.isfile(newswireStateFilename):
httpd.newswire = loadJson(newswireStateFilename)
mergeWithPreviousNewswire(httpd.newswire, newNewswire)
_mergeWithPreviousNewswire(httpd.newswire, newNewswire)
httpd.newswire = newNewswire
if newNewswire:
saveJson(httpd.newswire, newswireStateFilename)
print('Newswire updated')
convertRSStoActivityPub(baseDir,
_convertRSStoActivityPub(baseDir,
httpPrefix, domain, port,
newNewswire, translate,
httpd.recentPostsCache,

View File

@ -29,7 +29,7 @@ from blocking import isBlockedHashtag
from filters import isFiltered
def removeCDATA(text: str) -> str:
def _removeCDATA(text: str) -> str:
"""Removes any CDATA from the given text
"""
if 'CDATA[' in text:
@ -95,7 +95,7 @@ def getNewswireTags(text: str, maxTags: int) -> []:
return tags
def addNewswireDictEntry(baseDir: str, domain: str,
def _addNewswireDictEntry(baseDir: str, domain: str,
newswire: {}, dateStr: str,
title: str, link: str,
votesStatus: str, postFilename: str,
@ -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
# YY-MM-DDTHH:MM:SSZ
postDate = pubDate.replace(' ', 'T').replace('+00:00', 'Z')
@ -219,10 +219,10 @@ def loadHashtagCategories(baseDir: str, language: str) -> None:
with open(hashtagCategoriesFilename, 'r') as fp:
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,
force=False) -> None:
"""Updates hashtag categories based upon an rss feed
@ -261,7 +261,7 @@ def xml2StrToHashtagCategories(baseDir: str, xmlStr: str,
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,
maxPostsPerSource: int,
maxFeedItemSizeKb: int,
@ -274,7 +274,7 @@ def xml2StrToDict(baseDir: str, domain: str, xmlStr: str,
# is this an rss feed containing hashtag categories?
if '<title>#categories</title>' in xmlStr:
xml2StrToHashtagCategories(baseDir, xmlStr,
_xml2StrToHashtagCategories(baseDir, xmlStr,
maxCategoriesFeedItemSizeKb)
return {}
@ -300,17 +300,17 @@ def xml2StrToDict(baseDir: str, domain: str, xmlStr: str,
if '</pubDate>' not in rssItem:
continue
title = rssItem.split('<title>')[1]
title = removeCDATA(title.split('</title>')[0])
title = _removeCDATA(title.split('</title>')[0])
description = ''
if '<description>' in rssItem and '</description>' in rssItem:
description = rssItem.split('<description>')[1]
description = removeCDATA(description.split('</description>')[0])
description = _removeCDATA(description.split('</description>')[0])
else:
if '<media:description>' in rssItem and \
'</media:description>' in rssItem:
description = rssItem.split('<media:description>')[1]
description = description.split('</media:description>')[0]
description = removeCDATA(description)
description = _removeCDATA(description)
link = rssItem.split('<link>')[1]
link = link.split('</link>')[0]
if '://' not in link:
@ -325,10 +325,10 @@ def xml2StrToDict(baseDir: str, domain: str, xmlStr: str,
pubDateStr = parseFeedDate(pubDate)
if pubDateStr:
if validFeedDate(pubDateStr):
if _validFeedDate(pubDateStr):
postFilename = ''
votesStatus = []
addNewswireDictEntry(baseDir, domain,
_addNewswireDictEntry(baseDir, domain,
result, pubDateStr,
title, link,
votesStatus, postFilename,
@ -341,7 +341,7 @@ def xml2StrToDict(baseDir: str, domain: str, xmlStr: str,
return result
def xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
def _xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
moderated: bool, mirrored: bool,
maxPostsPerSource: int,
maxFeedItemSizeKb: int,
@ -356,7 +356,7 @@ def xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
# is this an rss feed containing hashtag categories?
if '<title>#categories</title>' in xmlStr:
xml2StrToHashtagCategories(baseDir, xmlStr,
_xml2StrToHashtagCategories(baseDir, xmlStr,
maxCategoriesFeedItemSizeKb)
return {}
@ -384,17 +384,17 @@ def xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
if '</dc:date>' not in rssItem:
continue
title = rssItem.split('<title>')[1]
title = removeCDATA(title.split('</title>')[0])
title = _removeCDATA(title.split('</title>')[0])
description = ''
if '<description>' in rssItem and '</description>' in rssItem:
description = rssItem.split('<description>')[1]
description = removeCDATA(description.split('</description>')[0])
description = _removeCDATA(description.split('</description>')[0])
else:
if '<media:description>' in rssItem and \
'</media:description>' in rssItem:
description = rssItem.split('<media:description>')[1]
description = description.split('</media:description>')[0]
description = removeCDATA(description)
description = _removeCDATA(description)
link = rssItem.split('<link>')[1]
link = link.split('</link>')[0]
if '://' not in link:
@ -409,10 +409,10 @@ def xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
pubDateStr = parseFeedDate(pubDate)
if pubDateStr:
if validFeedDate(pubDateStr):
if _validFeedDate(pubDateStr):
postFilename = ''
votesStatus = []
addNewswireDictEntry(baseDir, domain,
_addNewswireDictEntry(baseDir, domain,
result, pubDateStr,
title, link,
votesStatus, postFilename,
@ -425,7 +425,7 @@ def xml1StrToDict(baseDir: str, domain: str, xmlStr: str,
return result
def atomFeedToDict(baseDir: str, domain: str, xmlStr: str,
def _atomFeedToDict(baseDir: str, domain: str, xmlStr: str,
moderated: bool, mirrored: bool,
maxPostsPerSource: int,
maxFeedItemSizeKb: int) -> {}:
@ -456,17 +456,17 @@ def atomFeedToDict(baseDir: str, domain: str, xmlStr: str,
if '</updated>' not in atomItem:
continue
title = atomItem.split('<title>')[1]
title = removeCDATA(title.split('</title>')[0])
title = _removeCDATA(title.split('</title>')[0])
description = ''
if '<summary>' in atomItem and '</summary>' in atomItem:
description = atomItem.split('<summary>')[1]
description = removeCDATA(description.split('</summary>')[0])
description = _removeCDATA(description.split('</summary>')[0])
else:
if '<media:description>' in atomItem and \
'</media:description>' in atomItem:
description = atomItem.split('<media:description>')[1]
description = description.split('</media:description>')[0]
description = removeCDATA(description)
description = _removeCDATA(description)
link = atomItem.split('<link>')[1]
link = link.split('</link>')[0]
if '://' not in link:
@ -481,10 +481,10 @@ def atomFeedToDict(baseDir: str, domain: str, xmlStr: str,
pubDateStr = parseFeedDate(pubDate)
if pubDateStr:
if validFeedDate(pubDateStr):
if _validFeedDate(pubDateStr):
postFilename = ''
votesStatus = []
addNewswireDictEntry(baseDir, domain,
_addNewswireDictEntry(baseDir, domain,
result, pubDateStr,
title, link,
votesStatus, postFilename,
@ -497,7 +497,7 @@ def atomFeedToDict(baseDir: str, domain: str, xmlStr: str,
return result
def atomFeedYTToDict(baseDir: str, domain: str, xmlStr: str,
def _atomFeedYTToDict(baseDir: str, domain: str, xmlStr: str,
moderated: bool, mirrored: bool,
maxPostsPerSource: int,
maxFeedItemSizeKb: int) -> {}:
@ -532,17 +532,17 @@ def atomFeedYTToDict(baseDir: str, domain: str, xmlStr: str,
if '</yt:videoId>' not in atomItem:
continue
title = atomItem.split('<title>')[1]
title = removeCDATA(title.split('</title>')[0])
title = _removeCDATA(title.split('</title>')[0])
description = ''
if '<media:description>' in atomItem and \
'</media:description>' in atomItem:
description = atomItem.split('<media:description>')[1]
description = description.split('</media:description>')[0]
description = removeCDATA(description)
description = _removeCDATA(description)
elif '<summary>' in atomItem and '</summary>' in atomItem:
description = atomItem.split('<summary>')[1]
description = description.split('</summary>')[0]
description = removeCDATA(description)
description = _removeCDATA(description)
link = atomItem.split('<yt:videoId>')[1]
link = link.split('</yt:videoId>')[0]
link = 'https://www.youtube.com/watch?v=' + link.strip()
@ -551,10 +551,10 @@ def atomFeedYTToDict(baseDir: str, domain: str, xmlStr: str,
pubDateStr = parseFeedDate(pubDate)
if pubDateStr:
if validFeedDate(pubDateStr):
if _validFeedDate(pubDateStr):
postFilename = ''
votesStatus = []
addNewswireDictEntry(baseDir, domain,
_addNewswireDictEntry(baseDir, domain,
result, pubDateStr,
title, link,
votesStatus, postFilename,
@ -567,7 +567,7 @@ def atomFeedYTToDict(baseDir: str, domain: str, xmlStr: str,
return result
def xmlStrToDict(baseDir: str, domain: str, xmlStr: str,
def _xmlStrToDict(baseDir: str, domain: str, xmlStr: str,
moderated: bool, mirrored: bool,
maxPostsPerSource: int,
maxFeedItemSizeKb: int,
@ -576,27 +576,27 @@ def xmlStrToDict(baseDir: str, domain: str, xmlStr: str,
"""
if '<yt:videoId>' in xmlStr and '<yt:channelId>' in xmlStr:
print('YouTube feed: reading')
return atomFeedYTToDict(baseDir, domain,
return _atomFeedYTToDict(baseDir, domain,
xmlStr, moderated, mirrored,
maxPostsPerSource, maxFeedItemSizeKb)
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,
return _xml1StrToDict(baseDir, domain,
xmlStr, moderated, mirrored,
maxPostsPerSource, maxFeedItemSizeKb,
maxCategoriesFeedItemSizeKb)
elif 'xmlns="http://www.w3.org/2005/Atom"' in xmlStr:
return atomFeedToDict(baseDir, domain,
return _atomFeedToDict(baseDir, domain,
xmlStr, moderated, mirrored,
maxPostsPerSource, maxFeedItemSizeKb)
return {}
def YTchannelToAtomFeed(url: str) -> str:
def _YTchannelToAtomFeed(url: str) -> str:
"""Converts a YouTube channel url into an atom feed url
"""
if 'youtube.com/channel/' not in url:
@ -633,13 +633,13 @@ def getRSS(baseDir: str, domain: str, session, url: str,
'Mozilla/5.0 (X11; Linux x86_64; rv:81.0) Gecko/20100101 Firefox/81.0'
if not session:
print('WARN: no session specified for getRSS')
url = YTchannelToAtomFeed(url)
url = _YTchannelToAtomFeed(url)
try:
result = session.get(url, headers=sessionHeaders, params=sessionParams)
if result:
if int(len(result.text) / 1024) < maxFeedSizeKb and \
not containsInvalidChars(result.text):
return xmlStrToDict(baseDir, domain, result.text,
return _xmlStrToDict(baseDir, domain, result.text,
moderated, mirrored,
maxPostsPerSource,
maxFeedItemSizeKb,
@ -692,7 +692,7 @@ def getRSSfromDict(baseDir: str, newswire: {},
continue
rssStr += '<item>\n'
rssStr += ' <title>' + fields[0] + '</title>\n'
description = removeCDATA(firstParagraphFromString(fields[4]))
description = _removeCDATA(firstParagraphFromString(fields[4]))
rssStr += ' <description>' + description + '</description>\n'
url = fields[1]
if '://' not in url:
@ -707,7 +707,7 @@ def getRSSfromDict(baseDir: str, newswire: {},
return rssStr
def isNewswireBlogPost(postJsonObject: {}) -> bool:
def _isNewswireBlogPost(postJsonObject: {}) -> bool:
"""Is the given object a 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
@ -727,7 +727,7 @@ def isNewswireBlogPost(postJsonObject: {}) -> bool:
return False
def getHashtagsFromPost(postJsonObject: {}) -> []:
def _getHashtagsFromPost(postJsonObject: {}) -> []:
"""Returns a list of any hashtags within a post
"""
if not postJsonObject.get('object'):
@ -753,7 +753,7 @@ def getHashtagsFromPost(postJsonObject: {}) -> []:
return tags
def addAccountBlogsToNewswire(baseDir: str, nickname: str, domain: str,
def _addAccountBlogsToNewswire(baseDir: str, nickname: str, domain: str,
newswire: {},
maxBlogsPerAccount: int,
indexFilename: str,
@ -803,7 +803,7 @@ def addAccountBlogsToNewswire(baseDir: str, nickname: str, domain: str,
postJsonObject = None
if fullPostFilename:
postJsonObject = loadJson(fullPostFilename)
if isNewswireBlogPost(postJsonObject):
if _isNewswireBlogPost(postJsonObject):
published = postJsonObject['object']['published']
published = published.replace('T', ' ')
published = published.replace('Z', '+00:00')
@ -812,14 +812,14 @@ def addAccountBlogsToNewswire(baseDir: str, nickname: str, domain: str,
votes = loadJson(fullPostFilename + '.votes')
content = postJsonObject['object']['content']
description = firstParagraphFromString(content)
description = removeCDATA(description)
addNewswireDictEntry(baseDir, domain,
description = _removeCDATA(description)
_addNewswireDictEntry(baseDir, domain,
newswire, published,
postJsonObject['object']['summary'],
postJsonObject['object']['url'],
votes, fullPostFilename,
description, moderated, False,
getHashtagsFromPost(postJsonObject),
_getHashtagsFromPost(postJsonObject),
maxTags)
ctr += 1
@ -827,7 +827,7 @@ def addAccountBlogsToNewswire(baseDir: str, nickname: str, domain: str,
break
def addBlogsToNewswire(baseDir: str, domain: str, newswire: {},
def _addBlogsToNewswire(baseDir: str, domain: str, newswire: {},
maxBlogsPerAccount: int,
maxTags: int) -> None:
"""Adds blogs from each user account into the newswire
@ -857,7 +857,7 @@ def addBlogsToNewswire(baseDir: str, domain: str, newswire: {},
blogsIndex = accountDir + '/tlblogs.index'
if os.path.isfile(blogsIndex):
domain = handle.split('@')[1]
addAccountBlogsToNewswire(baseDir, nickname, domain,
_addAccountBlogsToNewswire(baseDir, nickname, domain,
newswire, maxBlogsPerAccount,
blogsIndex, maxTags)
break
@ -926,7 +926,7 @@ def getDictFromNewswire(session, baseDir: str, domain: str,
result[dateStr] = item
# add blogs from each user account
addBlogsToNewswire(baseDir, domain, result,
_addBlogsToNewswire(baseDir, domain, result,
maxPostsPerSource, maxTags)
# sort into chronological order, latest first

View File

@ -134,7 +134,7 @@ def setOrganizationScheme(baseDir: str, nickname: str, domain: str,
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
"""
if ':' in domain:
@ -201,7 +201,7 @@ 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,
manualFollowerApproval: bool,
password=None) -> (str, str, {}, {}):
@ -377,7 +377,7 @@ def registerAccount(baseDir: str, httpPrefix: str, domain: str, port: int,
manualFollowerApproval: bool) -> bool:
"""Registers a new account from the web interface
"""
if accountExists(baseDir, nickname, domain):
if _accountExists(baseDir, nickname, domain):
return False
if not validNickname(domain, nickname):
print('REGISTER: Nickname ' + nickname + ' is invalid')
@ -449,7 +449,7 @@ def createPerson(baseDir: str, nickname: str, domain: str, port: int,
return None, None, None, None
(privateKeyPem, publicKeyPem,
newPerson, webfingerEndpoint) = createPersonBase(baseDir, nickname,
newPerson, webfingerEndpoint) = _createPersonBase(baseDir, nickname,
domain, port,
httpPrefix,
saveToFile,
@ -525,7 +525,7 @@ def createSharedInbox(baseDir: str, nickname: str, domain: str, port: int,
httpPrefix: str) -> (str, str, {}, {}):
"""Generates the shared inbox
"""
return createPersonBase(baseDir, nickname, domain, port, httpPrefix,
return _createPersonBase(baseDir, nickname, domain, port, httpPrefix,
True, True, None)
@ -845,7 +845,7 @@ def canRemovePost(baseDir: str, nickname: str,
return True
def removeTagsForNickname(baseDir: str, nickname: str,
def _removeTagsForNickname(baseDir: str, nickname: str,
domain: str, port: int) -> None:
"""Removes tags for a nickname
"""
@ -900,7 +900,7 @@ def removeAccount(baseDir: str, nickname: str,
unsuspendAccount(baseDir, nickname)
handle = nickname + '@' + domain
removePassword(baseDir, nickname)
removeTagsForNickname(baseDir, nickname, domain, port)
_removeTagsForNickname(baseDir, nickname, domain, port)
if os.path.isdir(baseDir + '/deactivated/' + handle):
shutil.rmtree(baseDir + '/deactivated/' + handle)
if os.path.isdir(baseDir + '/accounts/' + handle):

View File

@ -77,7 +77,7 @@ def getPetName(baseDir: str, nickname: str, domain: str,
return ''
def getPetNameHandle(baseDir: str, nickname: str, domain: str,
def _getPetNameHandle(baseDir: str, nickname: str, domain: str,
petname: str) -> str:
"""Given a petname returns the handle
"""
@ -113,7 +113,7 @@ def resolvePetnames(baseDir: str, nickname: str, domain: str,
if not wrd.startswith('@'):
break
# does a petname handle exist for this?
handle = getPetNameHandle(baseDir, nickname, domain, wrd)
handle = _getPetNameHandle(baseDir, nickname, domain, wrd)
if not handle:
continue
# replace the petname with the handle

147
posts.py
View File

@ -116,7 +116,7 @@ def noOfFollowersOnDomain(baseDir: str, handle: str,
return ctr
def getPersonKey(nickname: str, domain: str, baseDir: str, keyType='public',
def _getPersonKey(nickname: str, domain: str, baseDir: str, keyType='public',
debug=False):
"""Returns the public or private key of a person
"""
@ -136,7 +136,7 @@ def getPersonKey(nickname: str, domain: str, baseDir: str, keyType='public',
return keyPem
def cleanHtml(rawHtml: str) -> str:
def _cleanHtml(rawHtml: str) -> str:
# text=BeautifulSoup(rawHtml, 'html.parser').get_text()
text = rawHtml
return html.unescape(text)
@ -288,7 +288,7 @@ def getPersonBox(baseDir: str, session, wfRequest: {},
avatarUrl, displayName
def getPosts(session, outboxUrl: str, maxPosts: int,
def _getPosts(session, outboxUrl: str, maxPosts: int,
maxMentions: int,
maxEmoji: int, maxAttachments: int,
federationList: [],
@ -445,7 +445,7 @@ def getPosts(session, outboxUrl: str, maxPosts: int,
sensitive = item['object']['sensitive']
if simple:
print(cleanHtml(content) + '\n')
print(_cleanHtml(content) + '\n')
else:
pprint(item)
personPosts[item['id']] = {
@ -453,7 +453,7 @@ def getPosts(session, outboxUrl: str, maxPosts: int,
"inreplyto": inReplyTo,
"summary": summary,
"html": content,
"plaintext": cleanHtml(content),
"plaintext": _cleanHtml(content),
"attachment": attachment,
"mentions": mentions,
"emoji": emoji,
@ -519,7 +519,7 @@ def getPostDomains(session, outboxUrl: str, maxPosts: int,
return postDomains
def getPostsForBlockedDomains(baseDir: str,
def _getPostsForBlockedDomains(baseDir: str,
session, outboxUrl: str, maxPosts: int,
maxMentions: int,
maxEmoji: int, maxAttachments: int,
@ -643,7 +643,7 @@ def savePostToBox(baseDir: str, httpPrefix: str, postId: str,
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
This allows posts for a hashtag to be quickly looked up
"""
@ -677,7 +677,7 @@ def updateHashtagsIndex(baseDir: str, tag: {}, newPostId: str) -> None:
tagsFilename + ' ' + str(e))
def addSchedulePost(baseDir: str, nickname: str, domain: str,
def _addSchedulePost(baseDir: str, nickname: str, domain: str,
eventDateStr: str, postId: str) -> None:
"""Adds a scheduled post to the index
"""
@ -703,7 +703,7 @@ def addSchedulePost(baseDir: str, nickname: str, domain: str,
scheduleFile.close()
def appendEventFields(newPost: {},
def _appendEventFields(newPost: {},
eventUUID: str, eventStatus: str,
anonymousParticipationEnabled: bool,
repliesModerationOption: str,
@ -758,7 +758,7 @@ def validContentWarning(cw: str) -> str:
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
the lines of the file
"""
@ -771,13 +771,13 @@ def loadAutoCW(baseDir: str, nickname: str, domain: str) -> []:
return []
def addAutoCW(baseDir: str, nickname: str, domain: str,
def _addAutoCW(baseDir: str, nickname: str, domain: str,
subject: str, content: str) -> str:
"""Appends any automatic CW to the subject line
and returns the new subject line
"""
newSubject = subject
autoCWList = loadAutoCW(baseDir, nickname, domain)
autoCWList = _loadAutoCW(baseDir, nickname, domain)
for cwRule in autoCWList:
if '->' not in cwRule:
continue
@ -793,10 +793,10 @@ def addAutoCW(baseDir: str, nickname: str, domain: str,
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,
followersOnly: bool, saveToFile: bool, clientToServer: bool,
commentsEnabled: bool,
followersOnly: bool, saveToFile: bool,
clientToServer: bool, commentsEnabled: bool,
attachImageFilename: str,
mediaType: str, imageDescription: str,
useBlurhash: bool, isModerationReport: bool,
@ -812,7 +812,7 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
eventStatus=None, ticketUrl=None) -> {}:
"""Creates a message
"""
subject = addAutoCW(baseDir, nickname, domain, subject, content)
subject = _addAutoCW(baseDir, nickname, domain, subject, content)
if nickname != 'news':
mentionedRecipients = \
@ -885,7 +885,7 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
if not tagExists(tag['type'], tag['name'], tags):
tags.append(tag)
if isPublic:
updateHashtagsIndex(baseDir, tag, newPostId)
_updateHashtagsIndex(baseDir, tag, newPostId)
print('Content tags: ' + str(tags))
if inReplyTo and not sensitive:
@ -1031,7 +1031,7 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
attachMedia(baseDir, httpPrefix, domain, port,
newPost['object'], attachImageFilename,
mediaType, imageDescription, useBlurhash)
appendEventFields(newPost['object'], eventUUID, eventStatus,
_appendEventFields(newPost['object'], eventUUID, eventStatus,
anonymousParticipationEnabled,
repliesModerationOption,
category, joinMode,
@ -1079,7 +1079,7 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
attachMedia(baseDir, httpPrefix, domain, port,
newPost, attachImageFilename,
mediaType, imageDescription, useBlurhash)
appendEventFields(newPost, eventUUID, eventStatus,
_appendEventFields(newPost, eventUUID, eventStatus,
anonymousParticipationEnabled,
repliesModerationOption,
category, joinMode,
@ -1123,7 +1123,8 @@ def createPostBase(baseDir: str, nickname: str, domain: str, port: int,
if schedulePost:
if eventDate and eventTime:
# 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,
nickname, domain, newPost, 'scheduled')
else:
@ -1179,7 +1180,7 @@ def outboxMessageCreateWrap(httpPrefix: str,
return newPost
def postIsAddressedToFollowers(baseDir: str,
def _postIsAddressedToFollowers(baseDir: str,
nickname: str, domain: str, port: int,
httpPrefix: str,
postJsonObject: {}) -> bool:
@ -1227,7 +1228,7 @@ def createPublicPost(baseDir: str,
"""Public post
"""
domainFull = getFullDomain(domain, port)
return createPostBase(baseDir, nickname, domain, port,
return _createPostBase(baseDir, nickname, domain, port,
'https://www.w3.org/ns/activitystreams#Public',
httpPrefix + '://' + domainFull + '/users/' +
nickname + '/followers',
@ -1328,7 +1329,7 @@ def createQuestionPost(baseDir: str,
"""
domainFull = getFullDomain(domain, port)
messageJson = \
createPostBase(baseDir, nickname, domain, port,
_createPostBase(baseDir, nickname, domain, port,
'https://www.w3.org/ns/activitystreams#Public',
httpPrefix + '://' + domainFull + '/users/' +
nickname + '/followers',
@ -1373,7 +1374,7 @@ def createUnlistedPost(baseDir: str,
"""Unlisted post. This has the #Public and followers links inverted.
"""
domainFull = getFullDomain(domain, port)
return createPostBase(baseDir, nickname, domain, port,
return _createPostBase(baseDir, nickname, domain, port,
httpPrefix + '://' + domainFull + '/users/' +
nickname + '/followers',
'https://www.w3.org/ns/activitystreams#Public',
@ -1402,7 +1403,7 @@ def createFollowersOnlyPost(baseDir: str,
"""Followers only post
"""
domainFull = getFullDomain(domain, port)
return createPostBase(baseDir, nickname, domain, port,
return _createPostBase(baseDir, nickname, domain, port,
httpPrefix + '://' + domainFull + '/users/' +
nickname + '/followers',
None,
@ -1451,7 +1452,7 @@ def createEventPost(baseDir: str,
if followersOnly:
toStr1 = toStr2
toStr2 = None
return createPostBase(baseDir, nickname, domain, port,
return _createPostBase(baseDir, nickname, domain, port,
toStr1, toStr2,
httpPrefix, content, followersOnly, saveToFile,
clientToServer, commentsEnabled,
@ -1526,7 +1527,7 @@ def createDirectMessagePost(baseDir: str,
postTo = None
postCc = None
messageJson = \
createPostBase(baseDir, nickname, domain, port,
_createPostBase(baseDir, nickname, domain, port,
postTo, postCc,
httpPrefix, content, followersOnly, saveToFile,
clientToServer, commentsEnabled,
@ -1616,7 +1617,7 @@ def createReportPost(baseDir: str,
handle = toNickname + '@' + domain
postJsonObject = \
createPostBase(baseDir, nickname, domain, port,
_createPostBase(baseDir, nickname, domain, port,
toUrl, postCc,
httpPrefix, content, followersOnly, saveToFile,
clientToServer, commentsEnabled,
@ -1766,7 +1767,7 @@ def sendPost(projectVersion: str,
# sharedInbox is optional
postJsonObject = \
createPostBase(baseDir, nickname, domain, port,
_createPostBase(baseDir, nickname, domain, port,
toPersonId, cc, httpPrefix, content,
followersOnly, saveToFile, clientToServer,
commentsEnabled,
@ -1779,7 +1780,7 @@ def sendPost(projectVersion: str,
None, None, None, None, None)
# get the senders private key
privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private')
privateKeyPem = _getPersonKey(nickname, domain, baseDir, 'private')
if len(privateKeyPem) == 0:
return 6
@ -1902,7 +1903,7 @@ def sendPostViaServer(projectVersion: str,
'/users/' + toNickname
postJsonObject = \
createPostBase(baseDir,
_createPostBase(baseDir,
fromNickname, fromDomain, fromPort,
toPersonId, cc, httpPrefix, content,
followersOnly, saveToFile, clientToServer,
@ -1969,7 +1970,7 @@ def groupFollowersByDomain(baseDir: str, nickname: str, domain: str) -> {}:
return grouped
def addFollowersToPublicPost(postJsonObject: {}) -> None:
def _addFollowersToPublicPost(postJsonObject: {}) -> None:
"""Adds followers entry to cc if it doesn't exist
"""
if not postJsonObject.get('actor'):
@ -2099,7 +2100,7 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str,
# sharedInbox is optional
# get the senders private key
privateKeyPem = getPersonKey(nickname, domain, baseDir, 'private', debug)
privateKeyPem = _getPersonKey(nickname, domain, baseDir, 'private', debug)
if len(privateKeyPem) == 0:
if debug:
print('DEBUG: Private key not found for ' +
@ -2112,7 +2113,7 @@ def sendSignedJson(postJsonObject: {}, session, baseDir: str,
return 7
postPath = inboxUrl.split(toDomain, 1)[1]
addFollowersToPublicPost(postJsonObject)
_addFollowersToPublicPost(postJsonObject)
if not postJsonObject.get('signature'):
try:
@ -2332,7 +2333,7 @@ def sendToNamedAddresses(session, baseDir: str,
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
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
def sendingProfileUpdate(postJsonObject: {}) -> bool:
def _sendingProfileUpdate(postJsonObject: {}) -> bool:
"""Returns true if the given json is a profile update
"""
if postJsonObject['type'] != 'Update':
@ -2386,7 +2387,7 @@ def sendToFollowers(session, baseDir: str,
if not session:
print('WARN: No session for sendToFollowers')
return
if not postIsAddressedToFollowers(baseDir, nickname, domain,
if not _postIsAddressedToFollowers(baseDir, nickname, domain,
port, httpPrefix,
postJsonObject):
if debug:
@ -2428,7 +2429,7 @@ def sendToFollowers(session, baseDir: str,
print('Sending post to followers domain is active: ' +
followerDomainUrl)
withSharedInbox = hasSharedInbox(session, httpPrefix, followerDomain)
withSharedInbox = _hasSharedInbox(session, httpPrefix, followerDomain)
if debug:
if withSharedInbox:
print(followerDomain + ' has shared inbox')
@ -2467,7 +2468,7 @@ def sendToFollowers(session, baseDir: str,
toNickname = 'inbox'
if toNickname != 'inbox' and postJsonObject.get('type'):
if sendingProfileUpdate(postJsonObject):
if _sendingProfileUpdate(postJsonObject):
print('Sending post to followers ' +
'shared inbox of ' + toDomain)
toNickname = 'inbox'
@ -2554,7 +2555,7 @@ def createInbox(recentPostsCache: {},
session, baseDir: str, nickname: str, domain: str, port: int,
httpPrefix: str, itemsPerPage: int, headerOnly: bool,
pageNumber=None) -> {}:
return createBoxIndexed(recentPostsCache,
return _createBoxIndexed(recentPostsCache,
session, baseDir, 'inbox',
nickname, domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
@ -2564,7 +2565,7 @@ def createInbox(recentPostsCache: {},
def createBookmarksTimeline(session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str, itemsPerPage: int,
headerOnly: bool, pageNumber=None) -> {}:
return createBoxIndexed({}, session, baseDir, 'tlbookmarks',
return _createBoxIndexed({}, session, baseDir, 'tlbookmarks',
nickname, domain,
port, httpPrefix, itemsPerPage, headerOnly,
True, 0, False, 0, pageNumber)
@ -2574,7 +2575,7 @@ def createEventsTimeline(recentPostsCache: {},
session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str, itemsPerPage: int,
headerOnly: bool, pageNumber=None) -> {}:
return createBoxIndexed(recentPostsCache, session, baseDir, 'tlevents',
return _createBoxIndexed(recentPostsCache, session, baseDir, 'tlevents',
nickname, domain,
port, httpPrefix, itemsPerPage, headerOnly,
True, 0, False, 0, pageNumber)
@ -2584,7 +2585,7 @@ def createDMTimeline(recentPostsCache: {},
session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str, itemsPerPage: int,
headerOnly: bool, pageNumber=None) -> {}:
return createBoxIndexed(recentPostsCache,
return _createBoxIndexed(recentPostsCache,
session, baseDir, 'dm', nickname,
domain, port, httpPrefix, itemsPerPage,
headerOnly, True, 0, False, 0, pageNumber)
@ -2594,7 +2595,7 @@ def createRepliesTimeline(recentPostsCache: {},
session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str, itemsPerPage: int,
headerOnly: bool, pageNumber=None) -> {}:
return createBoxIndexed(recentPostsCache, session, baseDir, 'tlreplies',
return _createBoxIndexed(recentPostsCache, session, baseDir, 'tlreplies',
nickname, domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
0, False, 0, pageNumber)
@ -2603,7 +2604,7 @@ def createRepliesTimeline(recentPostsCache: {},
def createBlogsTimeline(session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str, itemsPerPage: int,
headerOnly: bool, pageNumber=None) -> {}:
return createBoxIndexed({}, session, baseDir, 'tlblogs', nickname,
return _createBoxIndexed({}, session, baseDir, 'tlblogs', nickname,
domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
0, False, 0, pageNumber)
@ -2612,7 +2613,7 @@ def createBlogsTimeline(session, baseDir: str, nickname: str, domain: str,
def createFeaturesTimeline(session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str, itemsPerPage: int,
headerOnly: bool, pageNumber=None) -> {}:
return createBoxIndexed({}, session, baseDir, 'tlfeatures', nickname,
return _createBoxIndexed({}, session, baseDir, 'tlfeatures', nickname,
domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
0, False, 0, pageNumber)
@ -2621,7 +2622,7 @@ def createFeaturesTimeline(session, baseDir: str, nickname: str, domain: str,
def createMediaTimeline(session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str, itemsPerPage: int,
headerOnly: bool, pageNumber=None) -> {}:
return createBoxIndexed({}, session, baseDir, 'tlmedia', nickname,
return _createBoxIndexed({}, session, baseDir, 'tlmedia', nickname,
domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
0, False, 0, pageNumber)
@ -2632,7 +2633,7 @@ def createNewsTimeline(session, baseDir: str, nickname: str, domain: str,
headerOnly: bool, newswireVotesThreshold: int,
positiveVoting: bool, votingTimeMins: int,
pageNumber=None) -> {}:
return createBoxIndexed({}, session, baseDir, 'outbox', 'news',
return _createBoxIndexed({}, session, baseDir, 'outbox', 'news',
domain, port, httpPrefix,
itemsPerPage, headerOnly, True,
newswireVotesThreshold, positiveVoting,
@ -2643,7 +2644,7 @@ def createOutbox(session, baseDir: str, nickname: str, domain: str,
port: int, httpPrefix: str,
itemsPerPage: int, headerOnly: bool, authorized: bool,
pageNumber=None) -> {}:
return createBoxIndexed({}, session, baseDir, 'outbox',
return _createBoxIndexed({}, session, baseDir, 'outbox',
nickname, domain, port, httpPrefix,
itemsPerPage, headerOnly, authorized,
0, False, 0, pageNumber)
@ -2816,7 +2817,7 @@ def isReply(postJsonObject: {}, actor: str) -> bool:
return False
def addPostStringToTimeline(postStr: str, boxname: str,
def _addPostStringToTimeline(postStr: str, boxname: str,
postsInBox: [], boxActor: str) -> bool:
""" is this a valid timeline post?
"""
@ -2853,7 +2854,7 @@ def addPostStringToTimeline(postStr: str, boxname: str,
return False
def addPostToTimeline(filePath: str, boxname: str,
def _addPostToTimeline(filePath: str, boxname: str,
postsInBox: [], boxActor: str) -> bool:
""" Reads a post from file and decides whether it is valid
"""
@ -2866,11 +2867,11 @@ def addPostToTimeline(filePath: str, boxname: str,
# append a replies identifier, which will later be removed
postStr += '<hasReplies>'
return addPostStringToTimeline(postStr, boxname, postsInBox, boxActor)
return _addPostStringToTimeline(postStr, boxname, postsInBox, boxActor)
return False
def createBoxIndexed(recentPostsCache: {},
def _createBoxIndexed(recentPostsCache: {},
session, baseDir: str, boxname: str,
nickname: str, domain: str, port: int, httpPrefix: str,
itemsPerPage: int, headerOnly: bool, authorized: bool,
@ -3006,7 +3007,7 @@ def createBoxIndexed(recentPostsCache: {},
if postUrl in recentPostsCache['index']:
if recentPostsCache['json'].get(postUrl):
url = recentPostsCache['json'][postUrl]
addPostStringToTimeline(url,
_addPostStringToTimeline(url,
boxname, postsInBox,
boxActor)
postsCtr += 1
@ -3017,7 +3018,7 @@ def createBoxIndexed(recentPostsCache: {},
locatePost(baseDir, nickname,
domain, postUrl, False)
if fullPostFilename:
addPostToTimeline(fullPostFilename, boxname,
_addPostToTimeline(fullPostFilename, boxname,
postsInBox, boxActor)
else:
# if this is the features timeline
@ -3026,7 +3027,7 @@ def createBoxIndexed(recentPostsCache: {},
locatePost(baseDir, timelineNickname,
domain, postUrl, False)
if fullPostFilename:
addPostToTimeline(fullPostFilename, boxname,
_addPostToTimeline(fullPostFilename, boxname,
postsInBox, boxActor)
else:
print('WARN: unable to locate post ' + postUrl)
@ -3314,7 +3315,7 @@ def getPublicPostsOfPerson(baseDir: str, nickname: str, domain: str,
maxMentions = 10
maxEmoji = 10
maxAttachments = 5
getPosts(session, personUrl, 30, maxMentions, maxEmoji,
_getPosts(session, personUrl, 30, maxMentions, maxEmoji,
maxAttachments, federationList,
personCache, raw, simple, debug,
projectVersion, httpPrefix, domain)
@ -3413,7 +3414,7 @@ def getPublicPostInfo(session, baseDir: str, nickname: str, domain: str,
domainsInfo[d] = []
blockedPosts = \
getPostsForBlockedDomains(baseDir, session, personUrl, maxPosts,
_getPostsForBlockedDomains(baseDir, session, personUrl, maxPosts,
maxMentions,
maxEmoji, maxAttachments,
federationList,
@ -3467,7 +3468,7 @@ def getPublicPostDomainsBlocked(session, baseDir: str,
return blockedDomains
def getNonMutualsOfPerson(baseDir: str,
def _getNonMutualsOfPerson(baseDir: str,
nickname: str, domain: str) -> []:
"""Returns the followers who are not mutuals of a person
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):
"""Checks follower accounts for references to globally blocked domains
"""
nonMutuals = getNonMutualsOfPerson(baseDir, nickname, domain)
nonMutuals = _getNonMutualsOfPerson(baseDir, nickname, domain)
if not nonMutuals:
print('No non-mutual followers were found')
return
@ -3614,7 +3615,7 @@ def populateRepliesJson(baseDir: str, nickname: str, domain: str,
repliesJson['orderedItems'].append(pjo)
def rejectAnnounce(announceFilename: str):
def _rejectAnnounce(announceFilename: str):
"""Marks an announce as rejected
"""
if not os.path.isfile(announceFilename + '.reject'):
@ -3699,40 +3700,40 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str,
if not isinstance(announcedJson, dict):
print('WARN: announce json is not a dict - ' +
postJsonObject['object'])
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
return None
if not announcedJson.get('id'):
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
return None
if '/statuses/' not in announcedJson['id']:
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
return None
if '/users/' not in announcedJson['id'] and \
'/accounts/' not in announcedJson['id'] and \
'/channel/' not in announcedJson['id'] and \
'/profile/' not in announcedJson['id']:
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
return None
if not announcedJson.get('type'):
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
# pprint(announcedJson)
return None
if announcedJson['type'] != 'Note' and \
announcedJson['type'] != 'Article':
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
# pprint(announcedJson)
return None
if not announcedJson.get('content'):
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
return None
if not announcedJson.get('published'):
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
return None
if not validPostDate(announcedJson['published']):
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
return None
if isFiltered(baseDir, nickname, domain, announcedJson['content']):
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
return None
# remove any long words
announcedJson['content'] = \
@ -3748,7 +3749,7 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str,
actorNickname, actorDomain, actorPort,
announcedJson)
if announcedJson['type'] != 'Create':
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
# pprint(announcedJson)
return None
@ -3765,7 +3766,7 @@ def downloadAnnounce(session, baseDir: str, httpPrefix: str,
attributedDomain = getFullDomain(attributedDomain, attributedPort)
if isBlocked(baseDir, nickname, domain,
attributedNickname, attributedDomain):
rejectAnnounce(announceFilename)
_rejectAnnounce(announceFilename)
return None
postJsonObject = announcedJson
replaceYouTube(postJsonObject, YTReplacementDomain)

View File

@ -63,7 +63,7 @@ def clearEditorStatus(baseDir: str) -> None:
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
"""
if ':' in domain:
@ -92,7 +92,7 @@ def addModerator(baseDir: str, nickname: str, domain: str) -> None:
f.write(nickname + '\n')
def removeModerator(baseDir: str, nickname: str):
def _removeModerator(baseDir: str, nickname: str):
"""Removes a moderator nickname from the file
"""
moderatorsFile = baseDir + '/accounts/moderators.txt'
@ -125,7 +125,7 @@ def setRole(baseDir: str, nickname: str, domain: str,
if role:
# add the role
if project == 'instance' and 'role' == 'moderator':
addModerator(baseDir, nickname, domain)
_addModerator(baseDir, nickname, domain)
if actorJson['roles'].get(project):
if role not in actorJson['roles'][project]:
actorJson['roles'][project].append(role)
@ -134,7 +134,7 @@ def setRole(baseDir: str, nickname: str, domain: str,
else:
# remove the role
if project == 'instance':
removeModerator(baseDir, nickname)
_removeModerator(baseDir, nickname)
if actorJson['roles'].get(project):
actorJson['roles'][project].remove(role)
# if the project contains no roles then remove it
@ -144,7 +144,7 @@ def setRole(baseDir: str, nickname: str, domain: str,
return True
def getRoles(baseDir: str, nickname: str, domain: str,
def _getRoles(baseDir: str, nickname: str, domain: str,
project: str) -> []:
"""Returns the roles for a given person on a given project
"""
@ -198,7 +198,7 @@ def outboxDelegate(baseDir: str, authenticatedNickname: str,
# instance delegators can delagate to other projects
# than their own
canDelegate = False
delegatorRoles = getRoles(baseDir, delegatorNickname,
delegatorRoles = _getRoles(baseDir, delegatorNickname,
domain, 'instance')
if delegatorRoles:
if 'delegator' in delegatorRoles:
@ -207,7 +207,7 @@ def outboxDelegate(baseDir: str, authenticatedNickname: str,
if not canDelegate:
canDelegate = True
# non-instance delegators can only delegate within their project
delegatorRoles = getRoles(baseDir, delegatorNickname,
delegatorRoles = _getRoles(baseDir, delegatorNickname,
domain, project)
if delegatorRoles:
if 'delegator' not in delegatorRoles:
@ -230,7 +230,7 @@ def outboxDelegate(baseDir: str, authenticatedNickname: str,
return True
# what roles is this person already assigned to?
existingRoles = getRoles(baseDir, nickname, domain, project)
existingRoles = _getRoles(baseDir, nickname, domain, project)
if existingRoles:
if role in existingRoles:
if debug:

View File

@ -14,7 +14,7 @@ from utils import loadJson
from outbox import postMessageToOutbox
def updatePostSchedule(baseDir: str, handle: str, httpd,
def _updatePostSchedule(baseDir: str, handle: str, httpd,
maxScheduledPosts: int) -> None:
"""Checks if posts are due to be delivered and if so moves them to the outbox
"""
@ -145,7 +145,7 @@ def runPostSchedule(baseDir: str, httpd, maxScheduledPosts: int):
baseDir + '/accounts/' + account + '/schedule.index'
if not os.path.isfile(scheduleIndexFilename):
continue
updatePostSchedule(baseDir, account, httpd, maxScheduledPosts)
_updatePostSchedule(baseDir, account, httpd, maxScheduledPosts)
break

View File

@ -176,11 +176,11 @@ def expireShares(baseDir: str) -> None:
continue
nickname = account.split('@')[0]
domain = account.split('@')[1]
expireSharesForAccount(baseDir, nickname, domain)
_expireSharesForAccount(baseDir, nickname, domain)
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
"""
handleDomain = domain

View File

@ -101,7 +101,7 @@ thrBob = None
thrEve = None
def testHttpsigBase(withDigest):
def _testHttpsigBase(withDigest):
print('testHttpsig(' + str(withDigest) + ')')
baseDir = os.getcwd()
@ -206,8 +206,8 @@ def testHttpsigBase(withDigest):
def testHttpsig():
testHttpsigBase(True)
testHttpsigBase(False)
_testHttpsigBase(True)
_testHttpsigBase(False)
def testCache():
@ -2617,6 +2617,11 @@ def testFunctions():
excludeImports = [
'link'
]
excludeLocal = [
'pyjsonld',
'daemon',
'tests'
]
# check that functions are called somewhere
for name, properties in functionProperties.items():
if name in exclusions:
@ -2626,6 +2631,16 @@ def testFunctions():
' in module ' + properties['module'] +
' is not called anywhere')
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:
for modName in properties['calledInModule']:
if modName == properties['module']:
@ -2635,8 +2650,6 @@ def testFunctions():
print(importStr + ' not found in ' + modName + '.py')
assert False
print('Function: ' + name + '')
# print(str(function))
# print(str(functionProperties))
def runAllTests():

View File

@ -14,7 +14,7 @@ from shutil import copyfile
from content import dangerousCSS
def getThemeFiles() -> []:
def _getThemeFiles() -> []:
return ('epicyon.css', 'login.css', 'follow.css',
'suspended.css', 'calendar.css', 'blog.css',
'options.css', 'search.css', 'links.css')
@ -38,7 +38,7 @@ def getThemesList(baseDir: str) -> []:
return themes
def setThemeInConfig(baseDir: str, name: str) -> bool:
def _setThemeInConfig(baseDir: str, name: str) -> bool:
configFilename = baseDir + '/config.json'
if not os.path.isfile(configFilename):
return False
@ -49,7 +49,7 @@ def setThemeInConfig(baseDir: str, name: str) -> bool:
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
"""
configFilename = baseDir + '/config.json'
@ -62,7 +62,7 @@ def setNewswirePublishAsIcon(baseDir: str, useIcon: bool) -> bool:
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)
as buttons
"""
@ -76,7 +76,7 @@ def setIconsAsButtons(baseDir: str, useButtons: bool) -> bool:
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
"""
configFilename = baseDir + '/config.json'
@ -89,7 +89,7 @@ def setRssIconAtTop(baseDir: str, atTop: bool) -> bool:
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
in the newswire column
"""
@ -103,7 +103,7 @@ def setPublishButtonAtTop(baseDir: str, atTop: bool) -> bool:
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,
calendar, etc as full width
"""
@ -127,8 +127,8 @@ def getTheme(baseDir: str) -> str:
return 'default'
def removeTheme(baseDir: str):
themeFiles = getThemeFiles()
def _removeTheme(baseDir: str):
themeFiles = _getThemeFiles()
for filename in themeFiles:
if os.path.isfile(baseDir + '/' + filename):
os.remove(baseDir + '/' + filename)
@ -183,14 +183,14 @@ def setCSSparam(css: str, param: str, value: str) -> str:
return newcss.strip()
def setThemeFromDict(baseDir: str, name: str,
def _setThemeFromDict(baseDir: str, name: str,
themeParams: {}, bgParams: {},
allowLocalNetworkAccess: bool) -> None:
"""Uses a dictionary to set a theme
"""
if name:
setThemeInConfig(baseDir, name)
themeFiles = getThemeFiles()
_setThemeInConfig(baseDir, name)
themeFiles = _getThemeFiles()
for filename in themeFiles:
# check for custom css within the theme directory
templateFilename = baseDir + '/theme/' + name + '/epicyon-' + filename
@ -215,33 +215,33 @@ def setThemeFromDict(baseDir: str, name: str,
for paramName, paramValue in themeParams.items():
if paramName == 'newswire-publish-icon':
if paramValue.lower() == 'true':
setNewswirePublishAsIcon(baseDir, True)
_setNewswirePublishAsIcon(baseDir, True)
else:
setNewswirePublishAsIcon(baseDir, False)
_setNewswirePublishAsIcon(baseDir, False)
continue
elif paramName == 'full-width-timeline-buttons':
if paramValue.lower() == 'true':
setFullWidthTimelineButtonHeader(baseDir, True)
_setFullWidthTimelineButtonHeader(baseDir, True)
else:
setFullWidthTimelineButtonHeader(baseDir, False)
_setFullWidthTimelineButtonHeader(baseDir, False)
continue
elif paramName == 'icons-as-buttons':
if paramValue.lower() == 'true':
setIconsAsButtons(baseDir, True)
_setIconsAsButtons(baseDir, True)
else:
setIconsAsButtons(baseDir, False)
_setIconsAsButtons(baseDir, False)
continue
elif paramName == 'rss-icon-at-top':
if paramValue.lower() == 'true':
setRssIconAtTop(baseDir, True)
_setRssIconAtTop(baseDir, True)
else:
setRssIconAtTop(baseDir, False)
_setRssIconAtTop(baseDir, False)
continue
elif paramName == 'publish-button-at-top':
if paramValue.lower() == 'true':
setPublishButtonAtTop(baseDir, True)
_setPublishButtonAtTop(baseDir, True)
else:
setPublishButtonAtTop(baseDir, False)
_setPublishButtonAtTop(baseDir, False)
continue
css = setCSSparam(css, paramName, paramValue)
filename = baseDir + '/' + filename
@ -249,16 +249,16 @@ def setThemeFromDict(baseDir: str, name: str,
cssfile.write(css)
if bgParams.get('login'):
setBackgroundFormat(baseDir, name, 'login', bgParams['login'])
_setBackgroundFormat(baseDir, name, 'login', bgParams['login'])
if bgParams.get('follow'):
setBackgroundFormat(baseDir, name, 'follow', bgParams['follow'])
_setBackgroundFormat(baseDir, name, 'follow', bgParams['follow'])
if bgParams.get('options'):
setBackgroundFormat(baseDir, name, 'options', bgParams['options'])
_setBackgroundFormat(baseDir, name, 'options', bgParams['options'])
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:
"""Sets the background file extension
"""
@ -277,7 +277,7 @@ def setBackgroundFormat(baseDir: str, name: str,
def enableGrayscale(baseDir: str) -> None:
"""Enables grayscale for the current theme
"""
themeFiles = getThemeFiles()
themeFiles = _getThemeFiles()
for filename in themeFiles:
templateFilename = baseDir + '/' + filename
if not os.path.isfile(templateFilename):
@ -300,7 +300,7 @@ def enableGrayscale(baseDir: str) -> None:
def disableGrayscale(baseDir: str) -> None:
"""Disables grayscale for the current theme
"""
themeFiles = getThemeFiles()
themeFiles = _getThemeFiles()
for filename in themeFiles:
templateFilename = baseDir + '/' + filename
if not os.path.isfile(templateFilename):
@ -318,7 +318,7 @@ def disableGrayscale(baseDir: str) -> None:
os.remove(grayscaleFilename)
def setCustomFont(baseDir: str):
def _setCustomFont(baseDir: str):
"""Uses a dictionary to set a theme
"""
customFontExt = None
@ -337,7 +337,7 @@ def setCustomFont(baseDir: str):
if not customFontExt:
return
themeFiles = getThemeFiles()
themeFiles = _getThemeFiles()
for filename in themeFiles:
templateFilename = baseDir + '/' + filename
if not os.path.isfile(templateFilename):
@ -356,7 +356,7 @@ def setCustomFont(baseDir: str):
cssfile.write(css)
def readVariablesFile(baseDir: str, themeName: str,
def _readVariablesFile(baseDir: str, themeName: str,
variablesFile: str,
allowLocalNetworkAccess: bool) -> None:
"""Reads variables from a file in the theme directory
@ -370,14 +370,14 @@ def readVariablesFile(baseDir: str, themeName: str,
"options": "jpg",
"search": "jpg"
}
setThemeFromDict(baseDir, themeName, themeParams, bgParams,
_setThemeFromDict(baseDir, themeName, themeParams, bgParams,
allowLocalNetworkAccess)
def setThemeDefault(baseDir: str, allowLocalNetworkAccess: bool):
def _setThemeDefault(baseDir: str, allowLocalNetworkAccess: bool):
name = 'default'
removeTheme(baseDir)
setThemeInConfig(baseDir, name)
_removeTheme(baseDir)
_setThemeInConfig(baseDir, name)
bgParams = {
"login": "jpg",
"follow": "jpg",
@ -394,11 +394,11 @@ def setThemeDefault(baseDir: str, allowLocalNetworkAccess: bool):
"banner-height-mobile": "10vh",
"search-banner-height-mobile": "15vh"
}
setThemeFromDict(baseDir, name, themeParams, bgParams,
_setThemeFromDict(baseDir, name, themeParams, bgParams,
allowLocalNetworkAccess)
def setThemeFonts(baseDir: str, themeName: str) -> None:
def _setThemeFonts(baseDir: str, themeName: str) -> None:
"""Adds custom theme fonts
"""
themeNameLower = themeName.lower()
@ -422,7 +422,7 @@ def setThemeFonts(baseDir: str, themeName: str) -> None:
break
def setThemeImages(baseDir: str, name: str) -> None:
def _setThemeImages(baseDir: str, name: str) -> None:
"""Changes the profile background image
and banner to the defaults
"""
@ -557,7 +557,7 @@ def setTheme(baseDir: str, name: str, domain: str,
result = False
prevThemeName = getTheme(baseDir)
removeTheme(baseDir)
_removeTheme(baseDir)
themes = getThemesList(baseDir)
for themeName in themes:
@ -573,21 +573,21 @@ def setTheme(baseDir: str, name: str, domain: str,
if prevThemeName.lower() != themeNameLower:
# change the banner and profile image
# to the default for the theme
setThemeImages(baseDir, name)
setThemeFonts(baseDir, name)
_setThemeImages(baseDir, name)
_setThemeFonts(baseDir, name)
result = True
if not result:
# default
setThemeDefault(baseDir)
_setThemeDefault(baseDir)
result = True
variablesFile = baseDir + '/theme/' + name + '/theme.json'
if os.path.isfile(variablesFile):
readVariablesFile(baseDir, name, variablesFile,
_readVariablesFile(baseDir, name, variablesFile,
allowLocalNetworkAccess)
setCustomFont(baseDir)
_setCustomFont(baseDir)
# set the news avatar
newsAvatarThemeFilename = \
@ -604,5 +604,5 @@ def setTheme(baseDir: str, name: str, domain: str,
else:
disableGrayscale(baseDir)
setThemeInConfig(baseDir, name)
_setThemeInConfig(baseDir, name)
return result

View File

@ -197,7 +197,7 @@ def isSystemAccount(nickname: str) -> bool:
return False
def createConfig(baseDir: str) -> None:
def _createConfig(baseDir: str) -> None:
"""Creates a configuration file
"""
configFilename = baseDir + '/config.json'
@ -211,7 +211,7 @@ def createConfig(baseDir: str) -> None:
def setConfigParam(baseDir: str, variableName: str, variableValue) -> None:
"""Sets a configuration value
"""
createConfig(baseDir)
_createConfig(baseDir)
configFilename = baseDir + '/config.json'
configJson = {}
if os.path.isfile(configFilename):
@ -223,7 +223,7 @@ def setConfigParam(baseDir: str, variableName: str, variableValue) -> None:
def getConfigParam(baseDir: str, variableName: str):
"""Gets a configuration value
"""
createConfig(baseDir)
_createConfig(baseDir)
configFilename = baseDir + '/config.json'
configJson = loadJson(configFilename)
if configJson:
@ -610,7 +610,7 @@ def getDomainFromActor(actor: str) -> (str, int):
return domain, port
def setDefaultPetName(baseDir: str, nickname: str, domain: str,
def _setDefaultPetName(baseDir: str, nickname: str, domain: str,
followNickname: str, followDomain: str) -> None:
"""Sets a default petname
This helps especially when using onion or i2p address
@ -723,7 +723,7 @@ def followPerson(baseDir: str, nickname: str, domain: str,
addPersonToCalendar(baseDir, nickname, domain,
followNickname, followDomain)
# add a default petname
setDefaultPetName(baseDir, nickname, domain,
_setDefaultPetName(baseDir, nickname, domain,
followNickname, followDomain)
return True
@ -864,7 +864,8 @@ def locatePost(baseDir: str, nickname: str, domain: str,
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'):
return
if not postJson['attachment'][0].get('url'):
@ -907,7 +908,7 @@ def removeModerationPostFromIndex(baseDir: str, postUrl: str,
' from moderation index')
def isReplyToBlogPost(baseDir: str, nickname: str, domain: str,
def _isReplyToBlogPost(baseDir: str, nickname: str, domain: str,
postJsonObject: str):
"""Is the given post a reply to a blog post?
"""
@ -947,7 +948,7 @@ def deletePost(baseDir: str, httpPrefix: str,
return
# don't remove replies to blog posts
if isReplyToBlogPost(baseDir, nickname, domain,
if _isReplyToBlogPost(baseDir, nickname, domain,
postJsonObject):
return
@ -966,7 +967,7 @@ def deletePost(baseDir: str, httpPrefix: str,
del recentPostsCache['html'][postId]
# remove any attachment
removeAttachment(baseDir, httpPrefix, domain, postJsonObject)
_removeAttachment(baseDir, httpPrefix, domain, postJsonObject)
extensions = ('votes', 'arrived', 'muted')
for ext in extensions:

View File

@ -89,7 +89,7 @@ def htmlCalendarDeleteConfirm(cssCache: {}, translate: {}, baseDir: str,
return deletePostStr
def htmlCalendarDay(cssCache: {}, translate: {},
def _htmlCalendarDay(cssCache: {}, translate: {},
baseDir: str, path: str,
year: int, monthNumber: int, dayNumber: int,
nickname: str, domain: str, dayEvents: [],
@ -251,7 +251,7 @@ def htmlCalendar(cssCache: {}, translate: {},
if events:
if events.get(str(dayNumber)):
dayEvents = events[str(dayNumber)]
return htmlCalendarDay(cssCache, translate, baseDir, path,
return _htmlCalendarDay(cssCache, translate, baseDir, path,
year, monthNumber, dayNumber,
nickname, domain, dayEvents,
monthName, actor)

View File

@ -19,14 +19,14 @@ from webapp_utils import htmlFooter
from webapp_utils import getBannerFile
def linksExist(baseDir: str) -> bool:
def _linksExist(baseDir: str) -> bool:
"""Returns true if links have been created
"""
linksFilename = baseDir + '/accounts/links.txt'
return os.path.isfile(linksFilename)
def getLeftColumnShares(baseDir: str,
def _getLeftColumnShares(baseDir: str,
httpPrefix: str, domainFull: str,
nickname: str,
maxSharesInLeftColumn: int,
@ -164,7 +164,7 @@ def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
# show a number of shares
maxSharesInLeftColumn = 3
sharesList = \
getLeftColumnShares(baseDir,
_getLeftColumnShares(baseDir,
httpPrefix, domainFull, nickname,
maxSharesInLeftColumn, translate)
if linksList and sharesList:
@ -271,7 +271,7 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
headerButtonsFrontScreen(translate, nickname,
'links', authorized,
iconsAsButtons) + '</center>'
if linksExist(baseDir):
if _linksExist(baseDir):
htmlStr += \
getLeftColumnContent(baseDir, nickname, domainFull,
httpPrefix, translate,

View File

@ -24,7 +24,7 @@ from webapp_utils import htmlPostSeparator
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
"""
if totalVotes <= 0:
@ -177,7 +177,7 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
# show the newswire lines
newswireContentStr = \
htmlNewswire(baseDir, newswire, nickname, moderator, translate,
_htmlNewswire(baseDir, newswire, nickname, moderator, translate,
positiveVoting)
htmlStr += newswireContentStr
@ -187,7 +187,7 @@ def getRightColumnContent(baseDir: str, nickname: str, domainFull: str,
return htmlStr
def htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
def _htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
translate: {}, positiveVoting: bool) -> str:
"""Converts a newswire dict into html
"""
@ -220,7 +220,7 @@ def htmlNewswire(baseDir: str, newswire: {}, nickname: str, moderator: bool,
if moderator:
totalVotes = votesOnNewswireItem(item[2])
totalVotesStr = \
votesIndicator(totalVotes, positiveVoting)
_votesIndicator(totalVotes, positiveVoting)
title = removeLongWords(item[0], 16, []).replace('\n', '<br>')
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
# votes for or against
totalVotesStr = \
votesIndicator(totalVotes, positiveVoting)
_votesIndicator(totalVotes, positiveVoting)
title = removeLongWords(item[0], 16, []).replace('\n', '<br>')
if moderator and moderatedItem:

View File

@ -17,7 +17,7 @@ from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter
def htmlFollowingDataList(baseDir: str, nickname: str,
def _htmlFollowingDataList(baseDir: str, nickname: str,
domain: str, domainFull: str) -> str:
"""Returns a datalist of handles being followed
"""
@ -57,7 +57,7 @@ def htmlFollowingDataList(baseDir: str, nickname: str,
return listStr
def htmlNewPostDropDown(scopeIcon: str, scopeDescription: str,
def _htmlNewPostDropDown(scopeIcon: str, scopeDescription: str,
replyStr: str,
translate: {},
showPublicOnDropdown: bool,
@ -617,7 +617,7 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
dropDownContent = ''
if not reportUrl and not shareDescription:
dropDownContent = \
htmlNewPostDropDown(scopeIcon, scopeDescription,
_htmlNewPostDropDown(scopeIcon, scopeDescription,
replyStr,
translate,
showPublicOnDropdown,
@ -717,7 +717,7 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
' <input type="text" name="mentions" ' + \
'list="followingHandles" value="' + mentionsStr + '" selected>\n'
newPostForm += \
htmlFollowingDataList(baseDir, nickname, domain, domainFull)
_htmlFollowingDataList(baseDir, nickname, domain, domainFull)
newPostForm += ''
selectedStr = ''

View File

@ -20,7 +20,7 @@ from webapp_column_right import getRightColumnContent
from webapp_post import individualPostAsHtml
def htmlFrontScreenPosts(recentPostsCache: {}, maxRecentPosts: int,
def _htmlFrontScreenPosts(recentPostsCache: {}, maxRecentPosts: int,
translate: {},
baseDir: str, httpPrefix: str,
nickname: str, domain: str, port: int,
@ -139,7 +139,7 @@ def htmlFrontScreen(rssIconAtTop: bool,
bannerFile, bannerFilename = \
getBannerFile(baseDir, nickname, domain, theme)
profileStr += \
htmlFrontScreenPosts(recentPostsCache, maxRecentPosts,
_htmlFrontScreenPosts(recentPostsCache, maxRecentPosts,
translate,
baseDir, httpPrefix,
nickname, domain, port,

View File

@ -51,7 +51,7 @@ def getHashtagCategoriesFeed(baseDir: str,
return rssStr
def getHashtagDomainMax(domainHistogram: {}) -> str:
def _getHashtagDomainMax(domainHistogram: {}) -> str:
"""Returns the domain with the maximum number of hashtags
"""
maxCount = 1
@ -63,7 +63,7 @@ def getHashtagDomainMax(domainHistogram: {}) -> str:
return maxDomain
def getHashtagDomainHistogram(domainHistogram: {}, translate: {}) -> str:
def _getHashtagDomainHistogram(domainHistogram: {}, translate: {}) -> str:
"""Returns the html for a histogram of domains
from which hashtags are coming
"""
@ -88,7 +88,7 @@ def getHashtagDomainHistogram(domainHistogram: {}, translate: {}) -> str:
rightColStr = ''
for i in range(len(domainHistogram)):
domain = getHashtagDomainMax(domainHistogram)
domain = _getHashtagDomainMax(domainHistogram)
if not domain:
break
percent = int(domainHistogram[domain] * 100 / totalCount)
@ -224,7 +224,7 @@ def htmlHashTagSwarm(baseDir: str, actor: str, translate: {}) -> str:
getContentWarningButton('alltags', translate, tagSwarmStr)
tagSwarmHtml = categorySwarmStr + tagSwarmStr.strip() + '\n'
# tagSwarmHtml += getHashtagDomainHistogram(domainHistogram, translate)
# tagSwarmHtml += _getHashtagDomainHistogram(domainHistogram, translate)
return tagSwarmHtml

View File

@ -7,7 +7,7 @@ __email__ = "bob@freedombone.net"
__status__ = "Production"
def addEmbeddedVideoFromSites(translate: {}, content: str,
def _addEmbeddedVideoFromSites(translate: {}, content: str,
width=400, height=300) -> str:
"""Adds embedded videos
"""
@ -122,7 +122,7 @@ def addEmbeddedVideoFromSites(translate: {}, content: str,
return content
def addEmbeddedAudio(translate: {}, content: str) -> str:
def _addEmbeddedAudio(translate: {}, content: str) -> str:
"""Adds embedded audio for mp3/ogg
"""
if not ('.mp3' in content or '.ogg' in content):
@ -167,7 +167,7 @@ def addEmbeddedAudio(translate: {}, content: str) -> str:
return content
def addEmbeddedVideo(translate: {}, content: str,
def _addEmbeddedVideo(translate: {}, content: str,
width=400, height=300) -> str:
"""Adds embedded video for mp4/webm/ogv
"""
@ -219,6 +219,6 @@ def addEmbeddedVideo(translate: {}, content: str,
def addEmbeddedElements(translate: {}, content: str) -> str:
"""Adds embedded elements for various media types
"""
content = addEmbeddedVideoFromSites(translate, content)
content = addEmbeddedAudio(translate, content)
return addEmbeddedVideo(translate, content)
content = _addEmbeddedVideoFromSites(translate, content)
content = _addEmbeddedAudio(translate, content)
return _addEmbeddedVideo(translate, content)

View File

@ -63,7 +63,7 @@ from webapp_question import insertQuestion
from devices import E2EEdecryptMessageFromDevice
def logPostTiming(enableTimingLog: bool, postStartTime, debugId: str) -> None:
def _logPostTiming(enableTimingLog: bool, postStartTime, debugId: str) -> None:
"""Create a log of timings for performance tuning
"""
if not enableTimingLog:
@ -92,7 +92,7 @@ def preparePostFromHtmlCache(postHtml: str, boxName: str,
return withPageNumber
def saveIndividualPostAsHtmlToCache(baseDir: str,
def _saveIndividualPostAsHtmlToCache(baseDir: str,
nickname: str, domain: str,
postJsonObject: {},
postHtml: str) -> bool:
@ -118,7 +118,7 @@ def saveIndividualPostAsHtmlToCache(baseDir: str,
return False
def getPostFromRecentCache(session,
def _getPostFromRecentCache(session,
baseDir: str,
httpPrefix: str,
nickname: str, domain: str,
@ -157,13 +157,13 @@ def getPostFromRecentCache(session,
getPersonAvatarUrl(baseDir, postActor, personCache,
allowDownloads)
logPostTiming(enableTimingLog, postStartTime, '2.1')
_logPostTiming(enableTimingLog, postStartTime, '2.1')
updateAvatarImageCache(session, baseDir, httpPrefix,
postActor, avatarUrl, personCache,
allowDownloads)
logPostTiming(enableTimingLog, postStartTime, '2.2')
_logPostTiming(enableTimingLog, postStartTime, '2.2')
postHtml = \
loadIndividualPostAsHtmlFromCache(baseDir, nickname, domain,
@ -174,11 +174,11 @@ def getPostFromRecentCache(session,
postHtml = preparePostFromHtmlCache(postHtml, boxName, pageNumber)
updateRecentPostsCache(recentPostsCache, maxRecentPosts,
postJsonObject, postHtml)
logPostTiming(enableTimingLog, postStartTime, '3')
_logPostTiming(enableTimingLog, postStartTime, '3')
return postHtml
def getAvatarImageHtml(showAvatarOptions: bool,
def _getAvatarImageHtml(showAvatarOptions: bool,
nickname: str, domainFull: str,
avatarUrl: str, postActor: str,
translate: {}, avatarPosition: str,
@ -215,7 +215,7 @@ def getAvatarImageHtml(showAvatarOptions: bool,
return avatarLink.strip()
def getReplyIconHtml(nickname: str, isPublicRepeat: bool,
def _getReplyIconHtml(nickname: str, isPublicRepeat: bool,
showIcons: bool, commentsEnabled: bool,
postJsonObject: {}, pageNumberParam: str,
translate: {}) -> str:
@ -274,7 +274,7 @@ def getReplyIconHtml(nickname: str, isPublicRepeat: bool,
return replyStr
def getEditIconHtml(baseDir: str, nickname: str, domainFull: str,
def _getEditIconHtml(baseDir: str, nickname: str, domainFull: str,
postJsonObject: {}, actorNickname: str,
translate: {}, isEvent: bool) -> str:
"""Returns html for the edit icon/button
@ -330,7 +330,7 @@ def getEditIconHtml(baseDir: str, nickname: str, domainFull: str,
return editStr
def getAnnounceIconHtml(nickname: str, domainFull: str,
def _getAnnounceIconHtml(nickname: str, domainFull: str,
postJsonObject: {},
isPublicRepeat: bool,
isModerationPost: bool,
@ -372,7 +372,7 @@ def getAnnounceIconHtml(nickname: str, domainFull: str,
return announceStr
def getLikeIconHtml(nickname: str, domainFull: str,
def _getLikeIconHtml(nickname: str, domainFull: str,
isModerationPost: bool,
showLikeButton: bool,
postJsonObject: {},
@ -390,7 +390,7 @@ def getLikeIconHtml(nickname: str, domainFull: str,
likeTitle = translate['Like this post']
likeCount = noOfLikes(postJsonObject)
logPostTiming(enableTimingLog, postStartTime, '12.1')
_logPostTiming(enableTimingLog, postStartTime, '12.1')
likeCountStr = ''
if likeCount > 0:
@ -406,7 +406,7 @@ def getLikeIconHtml(nickname: str, domainFull: str,
likeLink = 'unlike'
likeTitle = translate['Undo the like']
logPostTiming(enableTimingLog, postStartTime, '12.2')
_logPostTiming(enableTimingLog, postStartTime, '12.2')
likeStr = ''
if likeCountStr:
@ -430,7 +430,7 @@ def getLikeIconHtml(nickname: str, domainFull: str,
return likeStr
def getBookmarkIconHtml(nickname: str, domainFull: str,
def _getBookmarkIconHtml(nickname: str, domainFull: str,
postJsonObject: {},
isModerationPost: bool,
translate: {},
@ -452,7 +452,7 @@ def getBookmarkIconHtml(nickname: str, domainFull: str,
bookmarkIcon = 'bookmark.png'
bookmarkLink = 'unbookmark'
bookmarkTitle = translate['Undo the bookmark']
logPostTiming(enableTimingLog, postStartTime, '12.6')
_logPostTiming(enableTimingLog, postStartTime, '12.6')
bookmarkStr = \
' <a class="imageAnchor" href="/users/' + nickname + '?' + \
bookmarkLink + '=' + postJsonObject['object']['id'] + \
@ -468,7 +468,7 @@ def getBookmarkIconHtml(nickname: str, domainFull: str,
return bookmarkStr
def getMuteIconHtml(isMuted: bool,
def _getMuteIconHtml(isMuted: bool,
postActor: str,
messageId: str,
nickname: str, domainFull: str,
@ -512,7 +512,7 @@ def getMuteIconHtml(isMuted: bool,
return muteStr
def getDeleteIconHtml(nickname: str, domainFull: str,
def _getDeleteIconHtml(nickname: str, domainFull: str,
allowDeletion: bool,
postActor: str,
messageId: str,
@ -541,7 +541,7 @@ def getDeleteIconHtml(nickname: str, domainFull: str,
return deleteStr
def getPublishedDateStr(postJsonObject: {},
def _getPublishedDateStr(postJsonObject: {},
showPublishedDateOnly: bool) -> str:
"""Return the html for the published date on a post
"""
@ -575,7 +575,7 @@ def getPublishedDateStr(postJsonObject: {},
return publishedStr
def getBlogCitationsHtml(boxName: str,
def _getBlogCitationsHtml(boxName: str,
postJsonObject: {},
translate: {}) -> str:
"""Returns blog citations as html
@ -609,7 +609,7 @@ def getBlogCitationsHtml(boxName: str,
return citationsStr
def boostOwnTootHtml(translate: {}) -> str:
def _boostOwnTootHtml(translate: {}) -> str:
"""The html title for announcing your own post
"""
return ' <img loading="lazy" title="' + \
@ -619,7 +619,7 @@ def boostOwnTootHtml(translate: {}) -> str:
'/repeat_inactive.png" class="announceOrReply"/>\n'
def announceUnattributedHtml(translate: {},
def _announceUnattributedHtml(translate: {},
postJsonObject: {}) -> str:
"""Returns the html for an announce title where there
is no attribution on the announced post
@ -634,7 +634,7 @@ def announceUnattributedHtml(translate: {},
'" class="announceOrReply">@unattributed</a>\n'
def announceWithoutDisplayNameHtml(translate: {},
def _announceWithoutDisplayNameHtml(translate: {},
announceNickname: str,
announceDomain: str,
postJsonObject: {}) -> str:
@ -650,7 +650,7 @@ def announceWithoutDisplayNameHtml(translate: {},
announceNickname + '@' + announceDomain + '</a>\n'
def announceWithDisplayNameHtml(translate: {},
def _announceWithDisplayNameHtml(translate: {},
postJsonObject: {},
announceDisplayName: str) -> str:
"""Returns html for an announce having a display name
@ -665,7 +665,7 @@ def announceWithDisplayNameHtml(translate: {},
'class="announceOrReply">' + announceDisplayName + '</a>\n'
def getPostTitleAnnounceHtml(baseDir: str,
def _getPostTitleAnnounceHtml(baseDir: str,
httpPrefix: str,
nickname: str, domain: str,
showRepeatIcon: bool,
@ -695,10 +695,10 @@ def getPostTitleAnnounceHtml(baseDir: str,
attributedTo = postJsonObject['object']['attributedTo']
if attributedTo.startswith(postActor):
titleStr += boostOwnTootHtml(translate)
titleStr += _boostOwnTootHtml(translate)
else:
# boosting another person's post
logPostTiming(enableTimingLog, postStartTime, '13.2')
_logPostTiming(enableTimingLog, postStartTime, '13.2')
announceNickname = None
if attributedTo:
announceNickname = getNicknameFromActor(attributedTo)
@ -710,7 +710,7 @@ def getPostTitleAnnounceHtml(baseDir: str,
announceDisplayName = \
getDisplayName(baseDir, attributedTo, personCache)
if announceDisplayName:
logPostTiming(enableTimingLog, postStartTime, '13.3')
_logPostTiming(enableTimingLog, postStartTime, '13.3')
# add any emoji to the display name
if ':' in announceDisplayName:
@ -719,9 +719,9 @@ def getPostTitleAnnounceHtml(baseDir: str,
nickname, domain,
announceDisplayName,
False)
logPostTiming(enableTimingLog, postStartTime, '13.3.1')
_logPostTiming(enableTimingLog, postStartTime, '13.3.1')
titleStr += \
announceWithDisplayNameHtml(translate,
_announceWithDisplayNameHtml(translate,
postJsonObject,
announceDisplayName)
# show avatar of person replied to
@ -731,7 +731,7 @@ def getPostTitleAnnounceHtml(baseDir: str,
getPersonAvatarUrl(baseDir, announceActor,
personCache, allowDownloads)
logPostTiming(enableTimingLog, postStartTime, '13.4')
_logPostTiming(enableTimingLog, postStartTime, '13.4')
if announceAvatarUrl:
idx = 'Show options for this person'
@ -756,23 +756,23 @@ def getPostTitleAnnounceHtml(baseDir: str,
'/></a>\n </div>\n'
else:
titleStr += \
announceWithoutDisplayNameHtml(translate,
_announceWithoutDisplayNameHtml(translate,
announceNickname,
announceDomain,
postJsonObject)
else:
titleStr += \
announceUnattributedHtml(translate,
_announceUnattributedHtml(translate,
postJsonObject)
else:
titleStr += \
announceUnattributedHtml(translate, postJsonObject)
_announceUnattributedHtml(translate, postJsonObject)
return (titleStr, replyAvatarImageInPost,
containerClassIcons, containerClass)
def replyToYourselfHtml(translate: {}, ) -> str:
def _replyToYourselfHtml(translate: {}, ) -> str:
"""Returns html for a title which is a reply to yourself
"""
return ' <img loading="lazy" title="' + \
@ -782,7 +782,7 @@ def replyToYourselfHtml(translate: {}, ) -> str:
'/reply.png" class="announceOrReply"/>\n'
def replyToUnknownHtml(translate: {},
def _replyToUnknownHtml(translate: {},
postJsonObject: {}) -> str:
"""Returns the html title for a reply to an unknown handle
"""
@ -795,7 +795,7 @@ def replyToUnknownHtml(translate: {},
'" class="announceOrReply">@unknown</a>\n'
def replyWithUnknownPathHtml(translate: {},
def _replyWithUnknownPathHtml(translate: {},
postJsonObject: {},
postDomain: str) -> str:
"""Returns html title for a reply with an unknown path
@ -812,7 +812,7 @@ def replyWithUnknownPathHtml(translate: {},
postDomain + '</a>\n'
def getReplyHtml(translate: {},
def _getReplyHtml(translate: {},
inReplyTo: str, replyDisplayName: str) -> str:
"""Returns html title for a reply
"""
@ -827,7 +827,7 @@ def getReplyHtml(translate: {},
replyDisplayName + '</a>\n'
def getReplyWithoutDisplayName(translate: {},
def _getReplyWithoutDisplayName(translate: {},
inReplyTo: str,
replyNickname: str, replyDomain: str) -> str:
"""Returns html for a reply without a display name,
@ -842,7 +842,7 @@ def getReplyWithoutDisplayName(translate: {},
replyNickname + '@' + replyDomain + '</a>\n'
def getPostTitleReplyHtml(baseDir: str,
def _getPostTitleReplyHtml(baseDir: str,
httpPrefix: str,
nickname: str, domain: str,
showRepeatIcon: bool,
@ -873,7 +873,7 @@ def getPostTitleReplyHtml(baseDir: str,
containerClassIcons = 'containericons darker'
containerClass = 'container darker'
if postJsonObject['object']['inReplyTo'].startswith(postActor):
titleStr += replyToYourselfHtml(translate)
titleStr += _replyToYourselfHtml(translate)
return (titleStr, replyAvatarImageInPost,
containerClassIcons, containerClass)
@ -894,7 +894,7 @@ def getPostTitleReplyHtml(baseDir: str,
if replyDisplayName:
# add emoji to the display name
if ':' in replyDisplayName:
logPostTiming(enableTimingLog, postStartTime, '13.5')
_logPostTiming(enableTimingLog, postStartTime, '13.5')
replyDisplayName = \
addEmojiToDisplayName(baseDir,
@ -903,12 +903,12 @@ def getPostTitleReplyHtml(baseDir: str,
domain,
replyDisplayName,
False)
logPostTiming(enableTimingLog, postStartTime, '13.6')
_logPostTiming(enableTimingLog, postStartTime, '13.6')
titleStr += \
getReplyHtml(translate, inReplyTo, replyDisplayName)
_getReplyHtml(translate, inReplyTo, replyDisplayName)
logPostTiming(enableTimingLog, postStartTime, '13.7')
_logPostTiming(enableTimingLog, postStartTime, '13.7')
# show avatar of person replied to
replyAvatarUrl = \
@ -917,7 +917,7 @@ def getPostTitleReplyHtml(baseDir: str,
personCache,
allowDownloads)
logPostTiming(enableTimingLog, postStartTime, '13.8')
_logPostTiming(enableTimingLog, postStartTime, '13.8')
if replyAvatarUrl:
replyAvatarImageInPost = \
@ -947,12 +947,13 @@ def getPostTitleReplyHtml(baseDir: str,
inReplyTo = \
postJsonObject['object']['inReplyTo']
titleStr += \
getReplyWithoutDisplayName(translate,
_getReplyWithoutDisplayName(translate,
inReplyTo,
replyNickname, replyDomain)
replyNickname,
replyDomain)
else:
titleStr += \
replyToUnknownHtml(translate, postJsonObject)
_replyToUnknownHtml(translate, postJsonObject)
else:
postDomain = \
postJsonObject['object']['inReplyTo']
@ -963,14 +964,14 @@ def getPostTitleReplyHtml(baseDir: str,
postDomain = postDomain.split('/', 1)[0]
if postDomain:
titleStr += \
replyWithUnknownPathHtml(translate,
_replyWithUnknownPathHtml(translate,
postJsonObject, postDomain)
return (titleStr, replyAvatarImageInPost,
containerClassIcons, containerClass)
def getPostTitleHtml(baseDir: str,
def _getPostTitleHtml(baseDir: str,
httpPrefix: str,
nickname: str, domain: str,
showRepeatIcon: bool,
@ -998,7 +999,7 @@ def getPostTitleHtml(baseDir: str,
containerClassIcons, containerClass)
if isAnnounced:
return getPostTitleAnnounceHtml(baseDir,
return _getPostTitleAnnounceHtml(baseDir,
httpPrefix,
nickname, domain,
showRepeatIcon,
@ -1017,7 +1018,7 @@ def getPostTitleHtml(baseDir: str,
containerClassIcons,
containerClass)
return getPostTitleReplyHtml(baseDir,
return _getPostTitleReplyHtml(baseDir,
httpPrefix,
nickname, domain,
showRepeatIcon,
@ -1037,7 +1038,7 @@ def getPostTitleHtml(baseDir: str,
containerClass)
def getFooterWithIcons(showIcons: bool,
def _getFooterWithIcons(showIcons: bool,
containerClassIcons: str,
replyStr: str, announceStr: str,
likeStr: str, bookmarkStr: str,
@ -1098,14 +1099,14 @@ def individualPostAsHtml(allowDownloads: bool,
# accurate timing of different parts of the code
enableTimingLog = not allowDownloads
logPostTiming(enableTimingLog, postStartTime, '1')
_logPostTiming(enableTimingLog, postStartTime, '1')
avatarPosition = ''
messageId = ''
if postJsonObject.get('id'):
messageId = removeIdEnding(postJsonObject['id'])
logPostTiming(enableTimingLog, postStartTime, '2')
_logPostTiming(enableTimingLog, postStartTime, '2')
messageIdStr = ''
if messageId:
@ -1119,7 +1120,7 @@ def individualPostAsHtml(allowDownloads: bool,
# get the html post from the recent posts cache if it exists there
postHtml = \
getPostFromRecentCache(session, baseDir,
_getPostFromRecentCache(session, baseDir,
httpPrefix, nickname, domain,
postJsonObject,
postActor,
@ -1137,7 +1138,7 @@ def individualPostAsHtml(allowDownloads: bool,
if postHtml:
return postHtml
logPostTiming(enableTimingLog, postStartTime, '4')
_logPostTiming(enableTimingLog, postStartTime, '4')
avatarUrl = \
getAvatarImageUrl(session,
@ -1145,7 +1146,7 @@ def individualPostAsHtml(allowDownloads: bool,
postActor, personCache,
avatarUrl, allowDownloads)
logPostTiming(enableTimingLog, postStartTime, '5')
_logPostTiming(enableTimingLog, postStartTime, '5')
# get the display name
if domainFull not in postActor:
@ -1156,7 +1157,7 @@ def individualPostAsHtml(allowDownloads: bool,
projectVersion, httpPrefix,
nickname, domain, 'outbox',
72367)
logPostTiming(enableTimingLog, postStartTime, '6')
_logPostTiming(enableTimingLog, postStartTime, '6')
if avatarUrl2:
avatarUrl = avatarUrl2
@ -1168,10 +1169,10 @@ def individualPostAsHtml(allowDownloads: bool,
nickname, domain,
displayName, False)
logPostTiming(enableTimingLog, postStartTime, '7')
_logPostTiming(enableTimingLog, postStartTime, '7')
avatarLink = \
getAvatarImageHtml(showAvatarOptions,
_getAvatarImageHtml(showAvatarOptions,
nickname, domainFull,
avatarUrl, postActor,
translate, avatarPosition,
@ -1215,7 +1216,7 @@ def individualPostAsHtml(allowDownloads: bool,
postJsonObject = postJsonAnnounce
isAnnounced = True
logPostTiming(enableTimingLog, postStartTime, '8')
_logPostTiming(enableTimingLog, postStartTime, '8')
if not isinstance(postJsonObject['object'], dict):
return ''
@ -1266,7 +1267,7 @@ def individualPostAsHtml(allowDownloads: bool,
'">@' + actorNickname + '@' + actorDomain + '</a>\n'
# benchmark 9
logPostTiming(enableTimingLog, postStartTime, '9')
_logPostTiming(enableTimingLog, postStartTime, '9')
# Show a DM icon for DMs in the inbox timeline
if showDMicon:
@ -1280,23 +1281,23 @@ def individualPostAsHtml(allowDownloads: bool,
if postJsonObject['object']['commentsEnabled'] is False:
commentsEnabled = False
replyStr = getReplyIconHtml(nickname, isPublicRepeat,
replyStr = _getReplyIconHtml(nickname, isPublicRepeat,
showIcons, commentsEnabled,
postJsonObject, pageNumberParam,
translate)
logPostTiming(enableTimingLog, postStartTime, '10')
_logPostTiming(enableTimingLog, postStartTime, '10')
isEvent = isEventPost(postJsonObject)
logPostTiming(enableTimingLog, postStartTime, '11')
_logPostTiming(enableTimingLog, postStartTime, '11')
editStr = getEditIconHtml(baseDir, nickname, domainFull,
editStr = _getEditIconHtml(baseDir, nickname, domainFull,
postJsonObject, actorNickname,
translate, isEvent)
announceStr = \
getAnnounceIconHtml(nickname, domainFull,
_getAnnounceIconHtml(nickname, domainFull,
postJsonObject,
isPublicRepeat,
isModerationPost,
@ -1306,7 +1307,7 @@ def individualPostAsHtml(allowDownloads: bool,
timelinePostBookmark,
boxName)
logPostTiming(enableTimingLog, postStartTime, '12')
_logPostTiming(enableTimingLog, postStartTime, '12')
# whether to show a like button
hideLikeButtonFile = \
@ -1315,7 +1316,7 @@ def individualPostAsHtml(allowDownloads: bool,
if os.path.isfile(hideLikeButtonFile):
showLikeButton = False
likeStr = getLikeIconHtml(nickname, domainFull,
likeStr = _getLikeIconHtml(nickname, domainFull,
isModerationPost,
showLikeButton,
postJsonObject,
@ -1325,10 +1326,10 @@ def individualPostAsHtml(allowDownloads: bool,
timelinePostBookmark,
boxName)
logPostTiming(enableTimingLog, postStartTime, '12.5')
_logPostTiming(enableTimingLog, postStartTime, '12.5')
bookmarkStr = \
getBookmarkIconHtml(nickname, domainFull,
_getBookmarkIconHtml(nickname, domainFull,
postJsonObject,
isModerationPost,
translate,
@ -1337,14 +1338,14 @@ def individualPostAsHtml(allowDownloads: bool,
pageNumberParam,
timelinePostBookmark)
logPostTiming(enableTimingLog, postStartTime, '12.9')
_logPostTiming(enableTimingLog, postStartTime, '12.9')
isMuted = postIsMuted(baseDir, nickname, domain, postJsonObject, messageId)
logPostTiming(enableTimingLog, postStartTime, '13')
_logPostTiming(enableTimingLog, postStartTime, '13')
muteStr = \
getMuteIconHtml(isMuted,
_getMuteIconHtml(isMuted,
postActor,
messageId,
nickname, domainFull,
@ -1355,7 +1356,7 @@ def individualPostAsHtml(allowDownloads: bool,
translate)
deleteStr = \
getDeleteIconHtml(nickname, domainFull,
_getDeleteIconHtml(nickname, domainFull,
allowDeletion,
postActor,
messageId,
@ -1363,13 +1364,13 @@ def individualPostAsHtml(allowDownloads: bool,
pageNumberParam,
translate)
logPostTiming(enableTimingLog, postStartTime, '13.1')
_logPostTiming(enableTimingLog, postStartTime, '13.1')
# get the title: x replies to y, x announces y, etc
(titleStr2,
replyAvatarImageInPost,
containerClassIcons,
containerClass) = getPostTitleHtml(baseDir,
containerClass) = _getPostTitleHtml(baseDir,
httpPrefix,
nickname, domain,
showRepeatIcon,
@ -1389,7 +1390,7 @@ def individualPostAsHtml(allowDownloads: bool,
containerClass)
titleStr += titleStr2
logPostTiming(enableTimingLog, postStartTime, '14')
_logPostTiming(enableTimingLog, postStartTime, '14')
attachmentStr, galleryStr = \
getPostAttachmentsAsHtml(postJsonObject, boxName, translate,
@ -1398,9 +1399,9 @@ def individualPostAsHtml(allowDownloads: bool,
bookmarkStr, deleteStr, muteStr)
publishedStr = \
getPublishedDateStr(postJsonObject, showPublishedDateOnly)
_getPublishedDateStr(postJsonObject, showPublishedDateOnly)
logPostTiming(enableTimingLog, postStartTime, '15')
_logPostTiming(enableTimingLog, postStartTime, '15')
publishedLink = messageId
# blog posts should have no /statuses/ in their link
@ -1427,7 +1428,7 @@ def individualPostAsHtml(allowDownloads: bool,
containerClassIcons = 'containericons dm'
containerClass = 'container dm'
newFooterStr = getFooterWithIcons(showIcons,
newFooterStr = _getFooterWithIcons(showIcons,
containerClassIcons,
replyStr, announceStr,
likeStr, bookmarkStr,
@ -1466,7 +1467,7 @@ def individualPostAsHtml(allowDownloads: bool,
postJsonObject['object']['summary'],
postJsonObject['object']['content'])
logPostTiming(enableTimingLog, postStartTime, '16')
_logPostTiming(enableTimingLog, postStartTime, '16')
if not isPatch:
objectContent = \
@ -1509,7 +1510,7 @@ def individualPostAsHtml(allowDownloads: bool,
else:
contentStr += cwContentStr
logPostTiming(enableTimingLog, postStartTime, '17')
_logPostTiming(enableTimingLog, postStartTime, '17')
if postJsonObject['object'].get('tag') and not isPatch:
contentStr = \
@ -1531,7 +1532,7 @@ def individualPostAsHtml(allowDownloads: bool,
# show blog citations
citationsStr = \
getBlogCitationsHtml(boxName, postJsonObject, translate)
_getBlogCitationsHtml(boxName, postJsonObject, translate)
postHtml = ''
if boxName != 'tlmedia':
@ -1546,18 +1547,18 @@ def individualPostAsHtml(allowDownloads: bool,
else:
postHtml = galleryStr
logPostTiming(enableTimingLog, postStartTime, '18')
_logPostTiming(enableTimingLog, postStartTime, '18')
# save the created html to the recent posts cache
if not showPublicOnly and storeToCache and \
boxName != 'tlmedia' and boxName != 'tlbookmarks' and \
boxName != 'bookmarks':
saveIndividualPostAsHtmlToCache(baseDir, nickname, domain,
_saveIndividualPostAsHtmlToCache(baseDir, nickname, domain,
postJsonObject, postHtml)
updateRecentPostsCache(recentPostsCache, maxRecentPosts,
postJsonObject, postHtml)
logPostTiming(enableTimingLog, postStartTime, '19')
_logPostTiming(enableTimingLog, postStartTime, '19')
return postHtml

View File

@ -214,7 +214,7 @@ def htmlProfileAfterSearch(cssCache: {},
imageUrl = profileJson['image']['url']
profileStr = \
getProfileHeaderAfterSearch(baseDir,
_getProfileHeaderAfterSearch(baseDir,
nickname, defaultTimeline,
searchNickname,
searchDomainFull,
@ -287,7 +287,7 @@ def htmlProfileAfterSearch(cssCache: {},
return htmlHeaderWithExternalStyle(cssFilename) + profileStr + htmlFooter()
def getProfileHeader(baseDir: str, nickname: str, domain: str,
def _getProfileHeader(baseDir: str, nickname: str, domain: str,
domainFull: str, translate: {},
defaultTimeline: str,
displayName: str,
@ -327,7 +327,7 @@ def getProfileHeader(baseDir: str, nickname: str, domain: str,
return htmlStr
def getProfileHeaderAfterSearch(baseDir: str,
def _getProfileHeaderAfterSearch(baseDir: str,
nickname: str, defaultTimeline: str,
searchNickname: str,
searchDomainFull: str,
@ -568,7 +568,7 @@ def htmlProfile(rssIconAtTop: bool,
avatarUrl = profileJson['icon']['url']
profileHeaderStr = \
getProfileHeader(baseDir, nickname, domain,
_getProfileHeader(baseDir, nickname, domain,
domainFull, translate,
defaultTimeline, displayName,
avatarDescription,
@ -621,7 +621,7 @@ def htmlProfile(rssIconAtTop: bool,
if selected == 'posts':
profileStr += \
htmlProfilePosts(recentPostsCache, maxRecentPosts,
_htmlProfilePosts(recentPostsCache, maxRecentPosts,
translate,
baseDir, httpPrefix, authorized,
nickname, domain, port,
@ -631,7 +631,7 @@ def htmlProfile(rssIconAtTop: bool,
showPublishedDateOnly) + licenseStr
elif selected == 'following':
profileStr += \
htmlProfileFollowing(translate, baseDir, httpPrefix,
_htmlProfileFollowing(translate, baseDir, httpPrefix,
authorized, nickname,
domain, port, session,
wfRequest, personCache, extraJson,
@ -640,7 +640,7 @@ def htmlProfile(rssIconAtTop: bool,
dormantMonths)
elif selected == 'followers':
profileStr += \
htmlProfileFollowing(translate, baseDir, httpPrefix,
_htmlProfileFollowing(translate, baseDir, httpPrefix,
authorized, nickname,
domain, port, session,
wfRequest, personCache, extraJson,
@ -649,14 +649,14 @@ def htmlProfile(rssIconAtTop: bool,
maxItemsPerPage, dormantMonths)
elif selected == 'roles':
profileStr += \
htmlProfileRoles(translate, nickname, domainFull,
_htmlProfileRoles(translate, nickname, domainFull,
extraJson)
elif selected == 'skills':
profileStr += \
htmlProfileSkills(translate, nickname, domainFull, extraJson)
_htmlProfileSkills(translate, nickname, domainFull, extraJson)
elif selected == 'shares':
profileStr += \
htmlProfileShares(actor, translate,
_htmlProfileShares(actor, translate,
nickname, domainFull,
extraJson) + licenseStr
@ -666,7 +666,7 @@ def htmlProfile(rssIconAtTop: bool,
return profileStr
def htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
def _htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
translate: {},
baseDir: str, httpPrefix: str,
authorized: bool,
@ -720,7 +720,7 @@ def htmlProfilePosts(recentPostsCache: {}, maxRecentPosts: int,
return profileStr
def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
def _htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
authorized: bool,
nickname: str, domain: str, port: int,
session, wfRequest: {}, personCache: {},
@ -756,7 +756,7 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
dormantMonths)
profileStr += \
individualFollowAsHtml(translate, baseDir, session,
_individualFollowAsHtml(translate, baseDir, session,
wfRequest, personCache,
domain, followingActor,
authorized, nickname,
@ -778,7 +778,7 @@ def htmlProfileFollowing(translate: {}, baseDir: str, httpPrefix: str,
return profileStr
def htmlProfileRoles(translate: {}, nickname: str, domain: str,
def _htmlProfileRoles(translate: {}, nickname: str, domain: str,
rolesJson: {}) -> str:
"""Shows roles on the profile screen
"""
@ -801,7 +801,7 @@ def htmlProfileRoles(translate: {}, nickname: str, domain: str,
return profileStr
def htmlProfileSkills(translate: {}, nickname: str, domain: str,
def _htmlProfileSkills(translate: {}, nickname: str, domain: str,
skillsJson: {}) -> str:
"""Shows skills on the profile screen
"""
@ -817,7 +817,7 @@ def htmlProfileSkills(translate: {}, nickname: str, domain: str,
return profileStr
def htmlProfileShares(actor: str, translate: {},
def _htmlProfileShares(actor: str, translate: {},
nickname: str, domain: str, sharesJson: {}) -> str:
"""Shows shares on the profile screen
"""
@ -1450,7 +1450,7 @@ def htmlEditProfile(cssCache: {}, translate: {}, baseDir: str, path: str,
return editProfileForm
def individualFollowAsHtml(translate: {},
def _individualFollowAsHtml(translate: {},
baseDir: str, session, wfRequest: {},
personCache: {}, domain: str,
followUrl: str,

View File

@ -27,7 +27,7 @@ from webapp_headerbuttons import headerButtonsTimeline
from posts import isModerator
def logTimelineTiming(enableTimingLog: bool, timelineStartTime,
def _logTimelineTiming(enableTimingLog: bool, timelineStartTime,
boxName: str, debugId: str) -> None:
"""Create a log of timings for performance tuning
"""
@ -127,7 +127,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
bannerFile, bannerFilename = \
getBannerFile(baseDir, nickname, domain, theme)
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '1')
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '1')
# is the user a moderator?
if not moderator:
@ -137,7 +137,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
if not editor:
editor = isEditor(baseDir, nickname)
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '2')
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '2')
# the appearance of buttons - highlighted or not
inboxButton = 'button'
@ -221,7 +221,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
'" src="/icons/person.png"/></a>\n'
break
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '3')
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '3')
# moderation / reports button
moderationButtonStr = ''
@ -256,7 +256,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
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
newsHeader = False
@ -487,17 +487,17 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
tlStr += '</div>\n</form>\n'
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '6')
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '6')
if boxName == 'tlshares':
maxSharesPerAccount = itemsPerPage
return (tlStr +
htmlSharesTimeline(translate, pageNumber, itemsPerPage,
_htmlSharesTimeline(translate, pageNumber, itemsPerPage,
baseDir, actor, nickname, domain, port,
maxSharesPerAccount, httpPrefix) +
htmlFooter())
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '7')
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '7')
# page up arrow
if pageNumber > 1:
@ -543,12 +543,12 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
preparePostFromHtmlCache(currTlStr,
boxName,
pageNumber)
logTimelineTiming(enableTimingLog,
_logTimelineTiming(enableTimingLog,
timelineStartTime,
boxName, '10')
if not currTlStr:
logTimelineTiming(enableTimingLog,
_logTimelineTiming(enableTimingLog,
timelineStartTime,
boxName, '11')
@ -570,7 +570,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
showIndividualPostIcons,
manuallyApproveFollowers,
False, True)
logTimelineTiming(enableTimingLog,
_logTimelineTiming(enableTimingLog,
timelineStartTime, boxName, '12')
if currTlStr:
@ -612,7 +612,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
rightColumnStr + ' </td>\n'
tlStr += ' </tr>\n'
logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '9')
_logTimelineTiming(enableTimingLog, timelineStartTime, boxName, '9')
tlStr += ' </tbody>\n'
tlStr += '</table>\n'
@ -656,7 +656,7 @@ def htmlIndividualShare(actor: str, item: {}, translate: {},
return profileStr
def htmlSharesTimeline(translate: {}, pageNumber: int, itemsPerPage: int,
def _htmlSharesTimeline(translate: {}, pageNumber: int, itemsPerPage: int,
baseDir: str, actor: str,
nickname: str, domain: str, port: int,
maxSharesPerAccount: int, httpPrefix: str) -> str:

View File

@ -167,7 +167,7 @@ def getContentWarningButton(postID: str, translate: {},
'</div></details>\n'
def getActorPropertyUrl(actorJson: {}, propertyName: str) -> str:
def _getActorPropertyUrl(actorJson: {}, propertyName: str) -> str:
"""Returns a url property from an actor
"""
if not actorJson.get('attachment'):
@ -206,10 +206,10 @@ def getActorPropertyUrl(actorJson: {}, propertyName: str) -> str:
def getBlogAddress(actorJson: {}) -> str:
"""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
"""
if not actorJson.get('attachment'):
@ -269,7 +269,7 @@ def setActorPropertyUrl(actorJson: {}, propertyName: str, url: str) -> None:
def setBlogAddress(actorJson: {}, blogAddress: str) -> None:
"""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,
@ -475,7 +475,7 @@ def postContainsPublic(postJsonObject: {}) -> bool:
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):
"""
returns the filenames for an image with the given name
@ -495,28 +495,28 @@ def getImageFile(baseDir: str, name: str, directory: str,
def getBannerFile(baseDir: str,
nickname: str, domain: str, theme: str) -> (str, str):
return getImageFile(baseDir, 'banner',
return _getImageFile(baseDir, 'banner',
baseDir + '/accounts/' + nickname + '@' + domain,
nickname, domain, theme)
def getSearchBannerFile(baseDir: str,
nickname: str, domain: str, theme: str) -> (str, str):
return getImageFile(baseDir, 'search_banner',
return _getImageFile(baseDir, 'search_banner',
baseDir + '/accounts/' + nickname + '@' + domain,
nickname, domain, theme)
def getLeftImageFile(baseDir: 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,
nickname, domain, theme)
def getRightImageFile(baseDir: 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,
nickname, domain, theme)

View File

@ -25,7 +25,7 @@ from utils import saveJson
from utils import getProtocolPrefixes
def parseHandle(handle: str) -> (str, str):
def _parseHandle(handle: str) -> (str, str):
if '.' not in handle:
return None, None
prefixes = getProtocolPrefixes()
@ -54,7 +54,7 @@ def webfingerHandle(session, handle: str, httpPrefix: str,
print('WARN: No session specified for webfingerHandle')
return None
nickname, domain = parseHandle(handle)
nickname, domain = _parseHandle(handle)
if not nickname:
return None
wfDomain = domain
@ -97,7 +97,7 @@ def webfingerHandle(session, handle: str, httpPrefix: str,
return result
def generateMagicKey(publicKeyPem) -> str:
def _generateMagicKey(publicKeyPem) -> str:
"""See magic_key method in
https://github.com/tootsuite/mastodon/blob/
707ddf7808f90e3ab042d7642d368c2ce8e95e6f/app/models/account.rb
@ -170,7 +170,7 @@ def createWebfingerEndpoint(nickname: str, domain: str, port: int,
"type": "application/activity+json"
},
{
"href": generateMagicKey(publicKeyPem),
"href": _generateMagicKey(publicKeyPem),
"rel": "magic-public-key"
}
],
@ -271,7 +271,7 @@ def webfingerLookup(path: str, baseDir: str,
return wfJson
def webfingerUpdateFromProfile(wfJson: {}, actorJson: {}) -> bool:
def _webfingerUpdateFromProfile(wfJson: {}, actorJson: {}) -> bool:
"""Updates webfinger Email/blog/xmpp links from profile
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:
return
if webfingerUpdateFromProfile(wfJson, actorJson):
if _webfingerUpdateFromProfile(wfJson, actorJson):
if saveJson(wfJson, filename):
cachedWebfingers[handle] = wfJson