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

merge-requests/30/head
Bob Mottram 2021-12-06 20:02:48 +00:00
commit 2921f8f6c2
4 changed files with 141 additions and 50 deletions

104
posts.py
View File

@ -32,6 +32,7 @@ from webfinger import webfingerHandle
from httpsig import createSignedHeader
from siteactive import siteIsActive
from languages import understoodPostLanguage
from utils import getUserPaths
from utils import invalidCiphertext
from utils import hasObjectStringType
from utils import removeIdEnding
@ -1259,6 +1260,29 @@ def _createPostPlaceAndTime(eventDate: str, endDate: str,
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: {},
toRecipients: [], tags: []) -> None:
"""Updates mentions for a new post
@ -1267,9 +1291,10 @@ def _createPostMentions(ccUrl: str, newPost: {},
return
if len(ccUrl) == 0:
return
newPost['cc'] = [ccUrl]
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
toCC = newPost['object']['cc']
@ -1283,6 +1308,13 @@ def _createPostMentions(ccUrl: str, newPost: {},
if tag['href'] not in toCC:
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,
isModerationReport: bool, newPost: {},
@ -1302,6 +1334,30 @@ def _createPostModReport(baseDir: str,
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,
nickname: str, domain: str, port: int,
toUrl: str, ccUrl: str, httpPrefix: str, content: str,
@ -1394,14 +1450,15 @@ def _createPostBase(baseDir: str,
if mention not in toCC:
toCC.append(mention)
isPublic = False
for recipient in toRecipients:
if recipient.endswith('#Public'):
isPublic = True
break
# create a list of hashtags
# Only posts which are #Public are searchable by hashtag
if hashtagsDict:
isPublic = False
for recipient in toRecipients:
if recipient.endswith('#Public'):
isPublic = True
break
for tagName, tag in hashtagsDict.items():
if not tagExists(tag['type'], tag['name'], tags):
tags.append(tag)
@ -1421,18 +1478,27 @@ def _createPostBase(baseDir: str,
postContext = getIndividualPostContext()
# make sure that CC doesn't also contain a To address
# eg. To: [ "https://mydomain/users/foo/followers" ]
# CC: [ "X", "Y", "https://mydomain/users/foo", "Z" ]
removeFromCC = []
for ccRecipient in toCC:
for sendToActor in toRecipients:
if ccRecipient in sendToActor and \
ccRecipient not in removeFromCC:
removeFromCC.append(ccRecipient)
break
for ccRemoval in removeFromCC:
toCC.remove(ccRemoval)
if not isPublic:
# make sure that CC doesn't also contain a To address
# eg. To: [ "https://mydomain/users/foo/followers" ]
# CC: [ "X", "Y", "https://mydomain/users/foo", "Z" ]
removeFromCC = []
for ccRecipient in toCC:
for sendToActor in toRecipients:
if ccRecipient in sendToActor and \
ccRecipient not in removeFromCC:
removeFromCC.append(ccRecipient)
break
for ccRemoval in removeFromCC:
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
postObjectType = 'Note'

View File

@ -36,6 +36,7 @@ from threads import threadWithTrace
from daemon import runDaemon
from session import createSession
from session import getJson
from posts import getActorFromInReplyTo
from posts import regenerateIndexForBox
from posts import removePostInteractions
from posts import getMentionedPeople
@ -4239,6 +4240,7 @@ def _testReplyToPublicPost(baseDir: str) -> None:
mediaType = None
imageDescription = 'Some description'
city = 'London, England'
testInReplyTo = postId
testInReplyToAtomUri = None
testSubject = None
testSchedulePost = False
@ -4254,7 +4256,7 @@ def _testReplyToPublicPost(baseDir: str) -> None:
content, followersOnly, saveToFile,
clientToServer, commentsEnabled,
attachImageFilename, mediaType,
imageDescription, city, postId,
imageDescription, city, testInReplyTo,
testInReplyToAtomUri,
testSubject, testSchedulePost,
testEventDate, testEventTime, testLocation,
@ -4275,8 +4277,20 @@ def _testReplyToPublicPost(baseDir: str) -> None:
assert len(reply['object']['cc']) >= 1
assert reply['object']['cc'][0].endswith(nickname + '/followers')
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 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) -> []:
@ -6013,6 +6027,18 @@ def _testHttpsigBaseNew(withDigest: bool, baseDir: str,
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():
baseDir = os.getcwd()
print('Running tests...')
@ -6020,6 +6046,7 @@ def runAllTests():
_translateOntology(baseDir)
_testGetPriceFromString()
_testFunctions()
_testGetActorFromInReplyTo()
_testValidEmojiContent()
_testAddCWfromLists(baseDir)
_testWordsSimilarity()

View File

@ -600,6 +600,14 @@ def removeIdEnding(idStr: str) -> str:
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() -> []:
"""Returns a list of valid prefixes
"""
@ -3138,6 +3146,8 @@ def hasActor(postJsonObject: {}, debug: bool) -> bool:
"""Does the given post have an actor?
"""
if postJsonObject.get('actor'):
if '#' in postJsonObject['actor']:
return False
return True
if debug:
if postJsonObject.get('type'):

View File

@ -23,6 +23,7 @@ from posts import postIsMuted
from posts import getPersonBox
from posts import downloadAnnounce
from posts import populateRepliesJson
from utils import removeHashFromPostId
from utils import removeHtml
from utils import getActorLanguagesList
from utils import getBaseContentFromPost
@ -390,11 +391,8 @@ def _getReplyIconHtml(baseDir: str, nickname: str, domain: str,
return replyStr
# reply is permitted - create reply icon
if '#' not in postJsonObject['object']['id']:
replyToLink = removeIdEnding(postJsonObject['object']['id'])
else:
replyToLink = \
removeIdEnding(postJsonObject['object']['id'].split('#')[0])
replyToLink = removeHashFromPostId(postJsonObject['object']['id'])
replyToLink = removeIdEnding(replyToLink)
# see Mike MacGirvin's replyTo suggestion
if postJsonObject['object'].get('replyTo'):
@ -575,11 +573,8 @@ def _getAnnounceIconHtml(isAnnounced: bool,
unannounceLinkStr = '?unannounce=' + \
removeIdEnding(announceJsonObject['id'])
if '#' not in postJsonObject['object']['id']:
announcePostId = removeIdEnding(postJsonObject['object']['id'])
else:
announcePostId = \
removeIdEnding(postJsonObject['object']['id'].split('#')[0])
announcePostId = removeHashFromPostId(postJsonObject['object']['id'])
announcePostId = removeIdEnding(announcePostId)
announceLinkStr = '?' + \
announceLink + '=' + announcePostId + pageNumberParam
announceStr = \
@ -647,10 +642,8 @@ def _getLikeIconHtml(nickname: str, domainFull: str,
likeStr += '<label class="likesCount">'
likeStr += likeCountStr.replace('(', '').replace(')', '').strip()
likeStr += '</label>\n'
if '#' not in postJsonObject['id']:
likePostId = removeIdEnding(postJsonObject['id'])
else:
likePostId = removeIdEnding(postJsonObject['id'].split('#')[0])
likePostId = removeHashFromPostId(postJsonObject['id'])
likePostId = removeIdEnding(likePostId)
likeStr += \
' <a class="imageAnchor" href="/users/' + nickname + '?' + \
likeLink + '=' + likePostId + \
@ -696,11 +689,8 @@ def _getBookmarkIconHtml(nickname: str, domainFull: str,
if translate.get(bookmarkTitle):
bookmarkTitle = translate[bookmarkTitle]
_logPostTiming(enableTimingLog, postStartTime, '12.6')
if '#' not in postJsonObject['object']['id']:
bookmarkPostId = removeIdEnding(postJsonObject['object']['id'])
else:
bookmarkPostId = \
removeIdEnding(postJsonObject['object']['id'].split('#')[0])
bookmarkPostId = removeHashFromPostId(postJsonObject['object']['id'])
bookmarkPostId = removeIdEnding(bookmarkPostId)
bookmarkStr = \
' <a class="imageAnchor" href="/users/' + nickname + '?' + \
bookmarkLink + '=' + bookmarkPostId + \
@ -737,11 +727,8 @@ def _getReactionIconHtml(nickname: str, domainFull: str,
if translate.get(reactionTitle):
reactionTitle = translate[reactionTitle]
_logPostTiming(enableTimingLog, postStartTime, '12.65')
if '#' not in postJsonObject['object']['id']:
reactionPostId = removeIdEnding(postJsonObject['object']['id'])
else:
reactionPostId = \
removeIdEnding(postJsonObject['object']['id'].split('#')[0])
reactionPostId = removeHashFromPostId(postJsonObject['object']['id'])
reactionPostId = removeIdEnding(reactionPostId)
reactionStr = \
' <a class="imageAnchor" href="/users/' + nickname + \
'?selreact=' + reactionPostId + pageNumberParam + \
@ -1383,10 +1370,8 @@ def individualPostAsHtml(signingPrivateKeyPem: str,
avatarPosition = ''
messageId = ''
if postJsonObject.get('id'):
if '#' not in postJsonObject['id']:
messageId = removeIdEnding(postJsonObject['id'])
else:
messageId = removeIdEnding(postJsonObject['id'].split('#')[0])
messageId = removeHashFromPostId(postJsonObject['id'])
messageId = removeIdEnding(messageId)
_logPostTiming(enableTimingLog, postStartTime, '2')
@ -1645,8 +1630,11 @@ def individualPostAsHtml(signingPrivateKeyPem: str,
if postJsonObject['object']['conversation']:
conversationId = postJsonObject['object']['conversation']
publicReply = False
if isPublicPost(postJsonObject):
publicReply = True
replyStr = _getReplyIconHtml(baseDir, nickname, domain,
isPublicRepeat,
publicReply,
showIcons, commentsEnabled,
postJsonObject, pageNumberParam,
translate, systemLanguage,