mirror of https://gitlab.com/bashrc2/epicyon
Merge branch 'main' of gitlab.com:bashrc2/epicyon
commit
2921f8f6c2
76
posts.py
76
posts.py
|
|
@ -32,6 +32,7 @@ from webfinger import webfingerHandle
|
||||||
from httpsig import createSignedHeader
|
from httpsig import createSignedHeader
|
||||||
from siteactive import siteIsActive
|
from siteactive import siteIsActive
|
||||||
from languages import understoodPostLanguage
|
from languages import understoodPostLanguage
|
||||||
|
from utils import getUserPaths
|
||||||
from utils import invalidCiphertext
|
from utils import invalidCiphertext
|
||||||
from utils import hasObjectStringType
|
from utils import hasObjectStringType
|
||||||
from utils import removeIdEnding
|
from utils import removeIdEnding
|
||||||
|
|
@ -1259,6 +1260,29 @@ def _createPostPlaceAndTime(eventDate: str, endDate: str,
|
||||||
return eventDateStr
|
return eventDateStr
|
||||||
|
|
||||||
|
|
||||||
|
def _consolidateActorsList(actorsList: []) -> None:
|
||||||
|
""" consolidate duplicated actors
|
||||||
|
https://domain/@nick gets merged with https://domain/users/nick
|
||||||
|
"""
|
||||||
|
possibleDuplicateActors = []
|
||||||
|
for ccActor in actorsList:
|
||||||
|
if '/@' in ccActor:
|
||||||
|
if ccActor not in possibleDuplicateActors:
|
||||||
|
possibleDuplicateActors.append(ccActor)
|
||||||
|
if possibleDuplicateActors:
|
||||||
|
uPaths = getUserPaths()
|
||||||
|
removeActors = []
|
||||||
|
for ccActor in possibleDuplicateActors:
|
||||||
|
for usrPath in uPaths:
|
||||||
|
ccActorFull = ccActor.replace('/@', usrPath)
|
||||||
|
if ccActorFull in actorsList:
|
||||||
|
if ccActor not in removeActors:
|
||||||
|
removeActors.append(ccActor)
|
||||||
|
break
|
||||||
|
for ccActor in removeActors:
|
||||||
|
actorsList.remove(ccActor)
|
||||||
|
|
||||||
|
|
||||||
def _createPostMentions(ccUrl: str, newPost: {},
|
def _createPostMentions(ccUrl: str, newPost: {},
|
||||||
toRecipients: [], tags: []) -> None:
|
toRecipients: [], tags: []) -> None:
|
||||||
"""Updates mentions for a new post
|
"""Updates mentions for a new post
|
||||||
|
|
@ -1267,9 +1291,10 @@ def _createPostMentions(ccUrl: str, newPost: {},
|
||||||
return
|
return
|
||||||
if len(ccUrl) == 0:
|
if len(ccUrl) == 0:
|
||||||
return
|
return
|
||||||
newPost['cc'] = [ccUrl]
|
|
||||||
if newPost.get('object'):
|
if newPost.get('object'):
|
||||||
newPost['object']['cc'] = [ccUrl]
|
if ccUrl not in newPost['object']['cc']:
|
||||||
|
newPost['object']['cc'] = [ccUrl] + newPost['object']['cc']
|
||||||
|
|
||||||
# if this is a public post then include any mentions in cc
|
# if this is a public post then include any mentions in cc
|
||||||
toCC = newPost['object']['cc']
|
toCC = newPost['object']['cc']
|
||||||
|
|
@ -1283,6 +1308,13 @@ def _createPostMentions(ccUrl: str, newPost: {},
|
||||||
if tag['href'] not in toCC:
|
if tag['href'] not in toCC:
|
||||||
newPost['object']['cc'].append(tag['href'])
|
newPost['object']['cc'].append(tag['href'])
|
||||||
|
|
||||||
|
_consolidateActorsList(newPost['object']['cc'])
|
||||||
|
newPost['cc'] = newPost['object']['cc']
|
||||||
|
else:
|
||||||
|
if ccUrl not in newPost['cc']:
|
||||||
|
newPost['cc'] = [ccUrl] + newPost['cc']
|
||||||
|
_consolidateActorsList(['cc'])
|
||||||
|
|
||||||
|
|
||||||
def _createPostModReport(baseDir: str,
|
def _createPostModReport(baseDir: str,
|
||||||
isModerationReport: bool, newPost: {},
|
isModerationReport: bool, newPost: {},
|
||||||
|
|
@ -1302,6 +1334,30 @@ def _createPostModReport(baseDir: str,
|
||||||
modFile.write(newPostId + '\n')
|
modFile.write(newPostId + '\n')
|
||||||
|
|
||||||
|
|
||||||
|
def getActorFromInReplyTo(inReplyTo: str) -> str:
|
||||||
|
"""Tries to get the replied to actor from the inReplyTo post id
|
||||||
|
Note: this will not always be successful for some instance types
|
||||||
|
"""
|
||||||
|
replyNickname = getNicknameFromActor(inReplyTo)
|
||||||
|
if not replyNickname:
|
||||||
|
return None
|
||||||
|
replyActor = None
|
||||||
|
if '/' + replyNickname + '/' in inReplyTo:
|
||||||
|
replyActor = \
|
||||||
|
inReplyTo.split('/' + replyNickname + '/')[0] + \
|
||||||
|
'/' + replyNickname
|
||||||
|
elif '#' + replyNickname + '#' in inReplyTo:
|
||||||
|
replyActor = \
|
||||||
|
inReplyTo.split('#' + replyNickname + '#')[0] + \
|
||||||
|
'#' + replyNickname
|
||||||
|
replyActor = replyActor.replace('#', '/')
|
||||||
|
if not replyActor:
|
||||||
|
return None
|
||||||
|
if '://' not in replyActor:
|
||||||
|
return None
|
||||||
|
return replyActor
|
||||||
|
|
||||||
|
|
||||||
def _createPostBase(baseDir: str,
|
def _createPostBase(baseDir: str,
|
||||||
nickname: str, domain: str, port: int,
|
nickname: str, domain: str, port: int,
|
||||||
toUrl: str, ccUrl: str, httpPrefix: str, content: str,
|
toUrl: str, ccUrl: str, httpPrefix: str, content: str,
|
||||||
|
|
@ -1394,14 +1450,15 @@ def _createPostBase(baseDir: str,
|
||||||
if mention not in toCC:
|
if mention not in toCC:
|
||||||
toCC.append(mention)
|
toCC.append(mention)
|
||||||
|
|
||||||
# create a list of hashtags
|
|
||||||
# Only posts which are #Public are searchable by hashtag
|
|
||||||
if hashtagsDict:
|
|
||||||
isPublic = False
|
isPublic = False
|
||||||
for recipient in toRecipients:
|
for recipient in toRecipients:
|
||||||
if recipient.endswith('#Public'):
|
if recipient.endswith('#Public'):
|
||||||
isPublic = True
|
isPublic = True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# create a list of hashtags
|
||||||
|
# Only posts which are #Public are searchable by hashtag
|
||||||
|
if hashtagsDict:
|
||||||
for tagName, tag in hashtagsDict.items():
|
for tagName, tag in hashtagsDict.items():
|
||||||
if not tagExists(tag['type'], tag['name'], tags):
|
if not tagExists(tag['type'], tag['name'], tags):
|
||||||
tags.append(tag)
|
tags.append(tag)
|
||||||
|
|
@ -1421,6 +1478,7 @@ def _createPostBase(baseDir: str,
|
||||||
|
|
||||||
postContext = getIndividualPostContext()
|
postContext = getIndividualPostContext()
|
||||||
|
|
||||||
|
if not isPublic:
|
||||||
# make sure that CC doesn't also contain a To address
|
# make sure that CC doesn't also contain a To address
|
||||||
# eg. To: [ "https://mydomain/users/foo/followers" ]
|
# eg. To: [ "https://mydomain/users/foo/followers" ]
|
||||||
# CC: [ "X", "Y", "https://mydomain/users/foo", "Z" ]
|
# CC: [ "X", "Y", "https://mydomain/users/foo", "Z" ]
|
||||||
|
|
@ -1433,6 +1491,14 @@ def _createPostBase(baseDir: str,
|
||||||
break
|
break
|
||||||
for ccRemoval in removeFromCC:
|
for ccRemoval in removeFromCC:
|
||||||
toCC.remove(ccRemoval)
|
toCC.remove(ccRemoval)
|
||||||
|
else:
|
||||||
|
if inReplyTo:
|
||||||
|
# If this is a public post then get the actor being
|
||||||
|
# replied to end ensure that it is within the CC list
|
||||||
|
replyActor = getActorFromInReplyTo(inReplyTo)
|
||||||
|
if replyActor:
|
||||||
|
if replyActor not in toCC:
|
||||||
|
toCC.append(replyActor)
|
||||||
|
|
||||||
# the type of post to be made
|
# the type of post to be made
|
||||||
postObjectType = 'Note'
|
postObjectType = 'Note'
|
||||||
|
|
|
||||||
31
tests.py
31
tests.py
|
|
@ -36,6 +36,7 @@ from threads import threadWithTrace
|
||||||
from daemon import runDaemon
|
from daemon import runDaemon
|
||||||
from session import createSession
|
from session import createSession
|
||||||
from session import getJson
|
from session import getJson
|
||||||
|
from posts import getActorFromInReplyTo
|
||||||
from posts import regenerateIndexForBox
|
from posts import regenerateIndexForBox
|
||||||
from posts import removePostInteractions
|
from posts import removePostInteractions
|
||||||
from posts import getMentionedPeople
|
from posts import getMentionedPeople
|
||||||
|
|
@ -4239,6 +4240,7 @@ def _testReplyToPublicPost(baseDir: str) -> None:
|
||||||
mediaType = None
|
mediaType = None
|
||||||
imageDescription = 'Some description'
|
imageDescription = 'Some description'
|
||||||
city = 'London, England'
|
city = 'London, England'
|
||||||
|
testInReplyTo = postId
|
||||||
testInReplyToAtomUri = None
|
testInReplyToAtomUri = None
|
||||||
testSubject = None
|
testSubject = None
|
||||||
testSchedulePost = False
|
testSchedulePost = False
|
||||||
|
|
@ -4254,7 +4256,7 @@ def _testReplyToPublicPost(baseDir: str) -> None:
|
||||||
content, followersOnly, saveToFile,
|
content, followersOnly, saveToFile,
|
||||||
clientToServer, commentsEnabled,
|
clientToServer, commentsEnabled,
|
||||||
attachImageFilename, mediaType,
|
attachImageFilename, mediaType,
|
||||||
imageDescription, city, postId,
|
imageDescription, city, testInReplyTo,
|
||||||
testInReplyToAtomUri,
|
testInReplyToAtomUri,
|
||||||
testSubject, testSchedulePost,
|
testSubject, testSchedulePost,
|
||||||
testEventDate, testEventTime, testLocation,
|
testEventDate, testEventTime, testLocation,
|
||||||
|
|
@ -4275,8 +4277,20 @@ def _testReplyToPublicPost(baseDir: str) -> None:
|
||||||
assert len(reply['object']['cc']) >= 1
|
assert len(reply['object']['cc']) >= 1
|
||||||
assert reply['object']['cc'][0].endswith(nickname + '/followers')
|
assert reply['object']['cc'][0].endswith(nickname + '/followers')
|
||||||
assert len(reply['object']['tag']) == 1
|
assert len(reply['object']['tag']) == 1
|
||||||
|
if len(reply['object']['cc']) != 2:
|
||||||
|
print('reply["object"]["cc"]: ' + str(reply['object']['cc']))
|
||||||
assert len(reply['object']['cc']) == 2
|
assert len(reply['object']['cc']) == 2
|
||||||
assert reply['object']['cc'][1] == httpPrefix + '://rat.site/@ninjarodent'
|
assert reply['object']['cc'][1] == \
|
||||||
|
httpPrefix + '://rat.site/users/ninjarodent'
|
||||||
|
|
||||||
|
assert len(reply['to']) == 1
|
||||||
|
assert reply['to'][0].endswith('#Public')
|
||||||
|
assert len(reply['cc']) >= 1
|
||||||
|
assert reply['cc'][0].endswith(nickname + '/followers')
|
||||||
|
if len(reply['cc']) != 2:
|
||||||
|
print('reply["cc"]: ' + str(reply['cc']))
|
||||||
|
assert len(reply['cc']) == 2
|
||||||
|
assert reply['cc'][1] == httpPrefix + '://rat.site/users/ninjarodent'
|
||||||
|
|
||||||
|
|
||||||
def _getFunctionCallArgs(name: str, lines: [], startLineCtr: int) -> []:
|
def _getFunctionCallArgs(name: str, lines: [], startLineCtr: int) -> []:
|
||||||
|
|
@ -6013,6 +6027,18 @@ def _testHttpsigBaseNew(withDigest: bool, baseDir: str,
|
||||||
shutil.rmtree(path, ignore_errors=False, onerror=None)
|
shutil.rmtree(path, ignore_errors=False, onerror=None)
|
||||||
|
|
||||||
|
|
||||||
|
def _testGetActorFromInReplyTo() -> None:
|
||||||
|
print('testGetActorFromInReplyTo')
|
||||||
|
inReplyTo = \
|
||||||
|
'https://fosstodon.org/users/bashrc/statuses/107400700612621140'
|
||||||
|
replyActor = getActorFromInReplyTo(inReplyTo)
|
||||||
|
assert replyActor == 'https://fosstodon.org/users/bashrc'
|
||||||
|
|
||||||
|
inReplyTo = 'https://fosstodon.org/activity/107400700612621140'
|
||||||
|
replyActor = getActorFromInReplyTo(inReplyTo)
|
||||||
|
assert replyActor is None
|
||||||
|
|
||||||
|
|
||||||
def runAllTests():
|
def runAllTests():
|
||||||
baseDir = os.getcwd()
|
baseDir = os.getcwd()
|
||||||
print('Running tests...')
|
print('Running tests...')
|
||||||
|
|
@ -6020,6 +6046,7 @@ def runAllTests():
|
||||||
_translateOntology(baseDir)
|
_translateOntology(baseDir)
|
||||||
_testGetPriceFromString()
|
_testGetPriceFromString()
|
||||||
_testFunctions()
|
_testFunctions()
|
||||||
|
_testGetActorFromInReplyTo()
|
||||||
_testValidEmojiContent()
|
_testValidEmojiContent()
|
||||||
_testAddCWfromLists(baseDir)
|
_testAddCWfromLists(baseDir)
|
||||||
_testWordsSimilarity()
|
_testWordsSimilarity()
|
||||||
|
|
|
||||||
10
utils.py
10
utils.py
|
|
@ -600,6 +600,14 @@ def removeIdEnding(idStr: str) -> str:
|
||||||
return idStr
|
return idStr
|
||||||
|
|
||||||
|
|
||||||
|
def removeHashFromPostId(postId: str) -> str:
|
||||||
|
"""Removes any has from a post id
|
||||||
|
"""
|
||||||
|
if '#' not in postId:
|
||||||
|
return postId
|
||||||
|
return postId.split('#')[0]
|
||||||
|
|
||||||
|
|
||||||
def getProtocolPrefixes() -> []:
|
def getProtocolPrefixes() -> []:
|
||||||
"""Returns a list of valid prefixes
|
"""Returns a list of valid prefixes
|
||||||
"""
|
"""
|
||||||
|
|
@ -3138,6 +3146,8 @@ def hasActor(postJsonObject: {}, debug: bool) -> bool:
|
||||||
"""Does the given post have an actor?
|
"""Does the given post have an actor?
|
||||||
"""
|
"""
|
||||||
if postJsonObject.get('actor'):
|
if postJsonObject.get('actor'):
|
||||||
|
if '#' in postJsonObject['actor']:
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
if debug:
|
if debug:
|
||||||
if postJsonObject.get('type'):
|
if postJsonObject.get('type'):
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ from posts import postIsMuted
|
||||||
from posts import getPersonBox
|
from posts import getPersonBox
|
||||||
from posts import downloadAnnounce
|
from posts import downloadAnnounce
|
||||||
from posts import populateRepliesJson
|
from posts import populateRepliesJson
|
||||||
|
from utils import removeHashFromPostId
|
||||||
from utils import removeHtml
|
from utils import removeHtml
|
||||||
from utils import getActorLanguagesList
|
from utils import getActorLanguagesList
|
||||||
from utils import getBaseContentFromPost
|
from utils import getBaseContentFromPost
|
||||||
|
|
@ -390,11 +391,8 @@ def _getReplyIconHtml(baseDir: str, nickname: str, domain: str,
|
||||||
return replyStr
|
return replyStr
|
||||||
|
|
||||||
# reply is permitted - create reply icon
|
# reply is permitted - create reply icon
|
||||||
if '#' not in postJsonObject['object']['id']:
|
replyToLink = removeHashFromPostId(postJsonObject['object']['id'])
|
||||||
replyToLink = removeIdEnding(postJsonObject['object']['id'])
|
replyToLink = removeIdEnding(replyToLink)
|
||||||
else:
|
|
||||||
replyToLink = \
|
|
||||||
removeIdEnding(postJsonObject['object']['id'].split('#')[0])
|
|
||||||
|
|
||||||
# see Mike MacGirvin's replyTo suggestion
|
# see Mike MacGirvin's replyTo suggestion
|
||||||
if postJsonObject['object'].get('replyTo'):
|
if postJsonObject['object'].get('replyTo'):
|
||||||
|
|
@ -575,11 +573,8 @@ def _getAnnounceIconHtml(isAnnounced: bool,
|
||||||
unannounceLinkStr = '?unannounce=' + \
|
unannounceLinkStr = '?unannounce=' + \
|
||||||
removeIdEnding(announceJsonObject['id'])
|
removeIdEnding(announceJsonObject['id'])
|
||||||
|
|
||||||
if '#' not in postJsonObject['object']['id']:
|
announcePostId = removeHashFromPostId(postJsonObject['object']['id'])
|
||||||
announcePostId = removeIdEnding(postJsonObject['object']['id'])
|
announcePostId = removeIdEnding(announcePostId)
|
||||||
else:
|
|
||||||
announcePostId = \
|
|
||||||
removeIdEnding(postJsonObject['object']['id'].split('#')[0])
|
|
||||||
announceLinkStr = '?' + \
|
announceLinkStr = '?' + \
|
||||||
announceLink + '=' + announcePostId + pageNumberParam
|
announceLink + '=' + announcePostId + pageNumberParam
|
||||||
announceStr = \
|
announceStr = \
|
||||||
|
|
@ -647,10 +642,8 @@ def _getLikeIconHtml(nickname: str, domainFull: str,
|
||||||
likeStr += '<label class="likesCount">'
|
likeStr += '<label class="likesCount">'
|
||||||
likeStr += likeCountStr.replace('(', '').replace(')', '').strip()
|
likeStr += likeCountStr.replace('(', '').replace(')', '').strip()
|
||||||
likeStr += '</label>\n'
|
likeStr += '</label>\n'
|
||||||
if '#' not in postJsonObject['id']:
|
likePostId = removeHashFromPostId(postJsonObject['id'])
|
||||||
likePostId = removeIdEnding(postJsonObject['id'])
|
likePostId = removeIdEnding(likePostId)
|
||||||
else:
|
|
||||||
likePostId = removeIdEnding(postJsonObject['id'].split('#')[0])
|
|
||||||
likeStr += \
|
likeStr += \
|
||||||
' <a class="imageAnchor" href="/users/' + nickname + '?' + \
|
' <a class="imageAnchor" href="/users/' + nickname + '?' + \
|
||||||
likeLink + '=' + likePostId + \
|
likeLink + '=' + likePostId + \
|
||||||
|
|
@ -696,11 +689,8 @@ def _getBookmarkIconHtml(nickname: str, domainFull: str,
|
||||||
if translate.get(bookmarkTitle):
|
if translate.get(bookmarkTitle):
|
||||||
bookmarkTitle = translate[bookmarkTitle]
|
bookmarkTitle = translate[bookmarkTitle]
|
||||||
_logPostTiming(enableTimingLog, postStartTime, '12.6')
|
_logPostTiming(enableTimingLog, postStartTime, '12.6')
|
||||||
if '#' not in postJsonObject['object']['id']:
|
bookmarkPostId = removeHashFromPostId(postJsonObject['object']['id'])
|
||||||
bookmarkPostId = removeIdEnding(postJsonObject['object']['id'])
|
bookmarkPostId = removeIdEnding(bookmarkPostId)
|
||||||
else:
|
|
||||||
bookmarkPostId = \
|
|
||||||
removeIdEnding(postJsonObject['object']['id'].split('#')[0])
|
|
||||||
bookmarkStr = \
|
bookmarkStr = \
|
||||||
' <a class="imageAnchor" href="/users/' + nickname + '?' + \
|
' <a class="imageAnchor" href="/users/' + nickname + '?' + \
|
||||||
bookmarkLink + '=' + bookmarkPostId + \
|
bookmarkLink + '=' + bookmarkPostId + \
|
||||||
|
|
@ -737,11 +727,8 @@ def _getReactionIconHtml(nickname: str, domainFull: str,
|
||||||
if translate.get(reactionTitle):
|
if translate.get(reactionTitle):
|
||||||
reactionTitle = translate[reactionTitle]
|
reactionTitle = translate[reactionTitle]
|
||||||
_logPostTiming(enableTimingLog, postStartTime, '12.65')
|
_logPostTiming(enableTimingLog, postStartTime, '12.65')
|
||||||
if '#' not in postJsonObject['object']['id']:
|
reactionPostId = removeHashFromPostId(postJsonObject['object']['id'])
|
||||||
reactionPostId = removeIdEnding(postJsonObject['object']['id'])
|
reactionPostId = removeIdEnding(reactionPostId)
|
||||||
else:
|
|
||||||
reactionPostId = \
|
|
||||||
removeIdEnding(postJsonObject['object']['id'].split('#')[0])
|
|
||||||
reactionStr = \
|
reactionStr = \
|
||||||
' <a class="imageAnchor" href="/users/' + nickname + \
|
' <a class="imageAnchor" href="/users/' + nickname + \
|
||||||
'?selreact=' + reactionPostId + pageNumberParam + \
|
'?selreact=' + reactionPostId + pageNumberParam + \
|
||||||
|
|
@ -1383,10 +1370,8 @@ def individualPostAsHtml(signingPrivateKeyPem: str,
|
||||||
avatarPosition = ''
|
avatarPosition = ''
|
||||||
messageId = ''
|
messageId = ''
|
||||||
if postJsonObject.get('id'):
|
if postJsonObject.get('id'):
|
||||||
if '#' not in postJsonObject['id']:
|
messageId = removeHashFromPostId(postJsonObject['id'])
|
||||||
messageId = removeIdEnding(postJsonObject['id'])
|
messageId = removeIdEnding(messageId)
|
||||||
else:
|
|
||||||
messageId = removeIdEnding(postJsonObject['id'].split('#')[0])
|
|
||||||
|
|
||||||
_logPostTiming(enableTimingLog, postStartTime, '2')
|
_logPostTiming(enableTimingLog, postStartTime, '2')
|
||||||
|
|
||||||
|
|
@ -1645,8 +1630,11 @@ def individualPostAsHtml(signingPrivateKeyPem: str,
|
||||||
if postJsonObject['object']['conversation']:
|
if postJsonObject['object']['conversation']:
|
||||||
conversationId = postJsonObject['object']['conversation']
|
conversationId = postJsonObject['object']['conversation']
|
||||||
|
|
||||||
|
publicReply = False
|
||||||
|
if isPublicPost(postJsonObject):
|
||||||
|
publicReply = True
|
||||||
replyStr = _getReplyIconHtml(baseDir, nickname, domain,
|
replyStr = _getReplyIconHtml(baseDir, nickname, domain,
|
||||||
isPublicRepeat,
|
publicReply,
|
||||||
showIcons, commentsEnabled,
|
showIcons, commentsEnabled,
|
||||||
postJsonObject, pageNumberParam,
|
postJsonObject, pageNumberParam,
|
||||||
translate, systemLanguage,
|
translate, systemLanguage,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue