From 6f0a5bf3d55c155c7beb094406dce1b615f60eba Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 4 Nov 2021 11:48:23 +0000 Subject: [PATCH 1/4] Tidying of receiving question votes --- inbox.py | 109 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/inbox.py b/inbox.py index 774da80eb..b7ce37110 100644 --- a/inbox.py +++ b/inbox.py @@ -2547,6 +2547,58 @@ def _isValidDM(baseDir: str, nickname: str, domain: str, port: int, return True +def _receiveQuestionVote(baseDir: str, nickname: str, domain: str, + httpPrefix: str, handle: str, debug: bool, + postJsonObject: {}, recentPostsCache: {}, + session, onionDomain: str, i2pDomain: str, port: int, + federationList: [], sendThreads: [], postLog: [], + cachedWebfingers: {}, personCache: {}, + signingPrivateKeyPem: str) -> None: + """Updates the votes on a Question/poll + """ + # if this is a reply to a question then update the votes + questionJson, questionPostFilename = \ + questionUpdateVotes(baseDir, nickname, domain, postJsonObject) + if not questionJson: + return + if not questionPostFilename: + return + + removePostFromCache(questionJson, recentPostsCache) + # add id to inbox index + inboxUpdateIndex('inbox', baseDir, handle, + questionPostFilename, debug) + # ensure that the cached post is removed if it exists, so + # that it then will be recreated + cachedPostFilename = \ + getCachedPostFilename(baseDir, nickname, domain, questionJson) + if cachedPostFilename: + if os.path.isfile(cachedPostFilename): + try: + os.remove(cachedPostFilename) + except BaseException: + print('EX: replytoQuestion unable to delete ' + + cachedPostFilename) + # Is this a question created by this instance? + idPrefix = httpPrefix + '://' + domain + if not questionJson['object']['id'].startswith(idPrefix): + return + # if the votes on a question have changed then + # send out an update + questionJson['type'] = 'Update' + sharedItemsFederatedDomains = [] + sharedItemFederationTokens = {} + sendToFollowersThread(session, baseDir, nickname, domain, + onionDomain, i2pDomain, port, + httpPrefix, federationList, + sendThreads, postLog, + cachedWebfingers, personCache, + postJsonObject, debug, __version__, + sharedItemsFederatedDomains, + sharedItemFederationTokens, + signingPrivateKeyPem) + + def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, session, keyId: str, handle: str, messageJson: {}, baseDir: str, httpPrefix: str, sendThreads: [], @@ -2787,56 +2839,13 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, populateReplies(baseDir, httpPrefix, domain, postJsonObject, maxReplies, debug) - # if this is a reply to a question then update the votes - questionJson, questionPostFilename = \ - questionUpdateVotes(baseDir, nickname, domain, postJsonObject) - if questionJson and questionPostFilename: - removePostFromCache(questionJson, recentPostsCache) - # add id to inbox index - inboxUpdateIndex('inbox', baseDir, handle, - questionPostFilename, debug) - # ensure that the cached post is removed if it exists, so - # that it then will be recreated - cachedPostFilename = \ - getCachedPostFilename(baseDir, nickname, domain, questionJson) - if cachedPostFilename: - if os.path.isfile(cachedPostFilename): - try: - os.remove(cachedPostFilename) - except BaseException: - print('EX: replytoQuestion unable to delete ' + - cachedPostFilename) - # Is this a question created by this instance? - idPrefix = httpPrefix + '://' + domain - if questionJson['object']['id'].startswith(idPrefix): - # if the votes on a question have changed then - # send out an update - questionJson['type'] = 'Update' - sharedItemsFederatedDomains = [] - sharedItemFederationTokens = {} - - sharedItemFederationTokens = {} - sharedItemsFederatedDomains = [] - sharedItemsFederatedDomainsStr = \ - getConfigParam(baseDir, 'sharedItemsFederatedDomains') - if sharedItemsFederatedDomainsStr: - siFederatedDomainsList = \ - sharedItemsFederatedDomainsStr.split(',') - for sharedFederatedDomain in siFederatedDomainsList: - domainStr = sharedFederatedDomain.strip() - sharedItemsFederatedDomains.append(domainStr) - - sendToFollowersThread(session, baseDir, - nickname, domain, - onionDomain, i2pDomain, port, - httpPrefix, federationList, - sendThreads, postLog, - cachedWebfingers, personCache, - postJsonObject, debug, - __version__, - sharedItemsFederatedDomains, - sharedItemFederationTokens, - signingPrivateKeyPem) + _receiveQuestionVote(baseDir, nickname, domain, + httpPrefix, handle, debug, + postJsonObject, recentPostsCache, + session, onionDomain, i2pDomain, port, + federationList, sendThreads, postLog, + cachedWebfingers, personCache, + signingPrivateKeyPem) isReplyToMutedPost = False From 6f43314d34ae73a53fec291e5461cf48c32c20d6 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 4 Nov 2021 12:29:53 +0000 Subject: [PATCH 2/4] Tidying of reply notifications --- inbox.py | 98 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/inbox.py b/inbox.py index b7ce37110..023f8e00a 100644 --- a/inbox.py +++ b/inbox.py @@ -2599,6 +2599,57 @@ def _receiveQuestionVote(baseDir: str, nickname: str, domain: str, signingPrivateKeyPem) +def _createReplyNotificationFile(baseDir: str, nickname: str, domain: str, + handle: str, debug: bool, postIsDM: bool, + postJsonObject: {}, actor: str, + updateIndexList: [], httpPrefix: str, + defaultReplyIntervalHours: int) -> bool: + """Generates a file indicating that a new reply has arrived + The file can then be used by other systems to create a notification + xmpp, matrix, email, etc + """ + isReplyToMutedPost = False + if postIsDM: + return isReplyToMutedPost + if not isReply(postJsonObject, actor): + return isReplyToMutedPost + if nickname == 'inbox': + return isReplyToMutedPost + # replies index will be updated + updateIndexList.append('tlreplies') + + conversationId = None + if postJsonObject['object'].get('conversation'): + conversationId = postJsonObject['object']['conversation'] + + if not postJsonObject['object'].get('inReplyTo'): + return isReplyToMutedPost + inReplyTo = postJsonObject['object']['inReplyTo'] + if not inReplyTo: + return isReplyToMutedPost + if not isinstance(inReplyTo, str): + return isReplyToMutedPost + if not isMuted(baseDir, nickname, domain, inReplyTo, conversationId): + # check if the reply is within the allowed time period + # after publication + replyIntervalHours = \ + getReplyIntervalHours(baseDir, nickname, domain, + defaultReplyIntervalHours) + if canReplyTo(baseDir, nickname, domain, inReplyTo, + replyIntervalHours): + actUrl = localActorUrl(httpPrefix, nickname, domain) + _replyNotify(baseDir, handle, actUrl + '/tlreplies') + else: + if debug: + print('Reply to ' + inReplyTo + ' is outside of the ' + + 'permitted interval of ' + str(replyIntervalHours) + + ' hours') + return False + else: + isReplyToMutedPost = True + return isReplyToMutedPost + + def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, session, keyId: str, handle: str, messageJson: {}, baseDir: str, httpPrefix: str, sendThreads: [], @@ -2870,47 +2921,12 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, actor = localActorUrl(httpPrefix, nickname, domainFull) # create a reply notification file if needed - if not postIsDM and isReply(postJsonObject, actor): - if nickname != 'inbox': - # replies index will be updated - updateIndexList.append('tlreplies') - - conversationId = None - if postJsonObject['object'].get('conversation'): - conversationId = \ - postJsonObject['object']['conversation'] - - if postJsonObject['object'].get('inReplyTo'): - inReplyTo = postJsonObject['object']['inReplyTo'] - if inReplyTo: - if isinstance(inReplyTo, str): - if not isMuted(baseDir, nickname, domain, - inReplyTo, conversationId): - # check if the reply is within the allowed - # time period after publication - hrs = defaultReplyIntervalHours - replyIntervalHours = \ - getReplyIntervalHours(baseDir, - nickname, - domain, hrs) - if canReplyTo(baseDir, nickname, domain, - inReplyTo, - replyIntervalHours): - actUrl = \ - localActorUrl(httpPrefix, - nickname, domain) - _replyNotify(baseDir, handle, - actUrl + '/tlreplies') - else: - if debug: - print('Reply to ' + inReplyTo + - ' is outside of the ' + - 'permitted interval of ' + - str(replyIntervalHours) + - ' hours') - return False - else: - isReplyToMutedPost = True + isReplyToMutedPost = \ + _createReplyNotificationFile(baseDir, nickname, domain, + handle, debug, postIsDM, + postJsonObject, actor, + updateIndexList, httpPrefix, + defaultReplyIntervalHours) if isImageMedia(session, baseDir, httpPrefix, nickname, domain, postJsonObject, From 27cf80dce25794470ef5f48cd1cd1333a5b7e86a Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 4 Nov 2021 12:43:46 +0000 Subject: [PATCH 3/4] Tidying of low frequency post notification --- inbox.py | 53 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/inbox.py b/inbox.py index 023f8e00a..b33c0f117 100644 --- a/inbox.py +++ b/inbox.py @@ -2650,6 +2650,37 @@ def _createReplyNotificationFile(baseDir: str, nickname: str, domain: str, return isReplyToMutedPost +def _lowFrequencyPostNotification(baseDir: str, httpPrefix: str, nickname: str, + domain: str, port: int, handle: str, + postIsDM: bool, jsonObj: {}) -> None: + """Should we notify that a post from this person has arrived? + This is for cases where the notify checkbox is enabled on the + person options screen + """ + if postIsDM: + return + if not jsonObj: + return + if not jsonObj.get('attributedTo'): + return + if not jsonObj.get('id'): + return + attributedTo = jsonObj['attributedTo'] + if not isinstance(attributedTo, str): + return + fromNickname = getNicknameFromActor(attributedTo) + fromDomain, fromPort = getDomainFromActor(attributedTo) + fromDomainFull = getFullDomain(fromDomain, fromPort) + if notifyWhenPersonPosts(baseDir, nickname, domain, + fromNickname, fromDomainFull): + postId = removeIdEnding(jsonObj['id']) + domFull = getFullDomain(domain, port) + postLink = \ + localActorUrl(httpPrefix, nickname, domFull) + \ + '?notifypost=' + postId.replace('/', '-') + _notifyPostArrival(baseDir, handle, postLink) + + def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, session, keyId: str, handle: str, messageJson: {}, baseDir: str, httpPrefix: str, sendThreads: [], @@ -2950,25 +2981,9 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, # save the post to file if saveJson(postJsonObject, destinationFilename): - # should we notify that a post from this person has arrived? - # This is for cases where the notify checkbox is enabled - # on the person options screen - if not postIsDM and jsonObj: - if jsonObj.get('attributedTo') and jsonObj.get('id'): - attributedTo = jsonObj['attributedTo'] - if isinstance(attributedTo, str): - fromNickname = getNicknameFromActor(attributedTo) - fromDomain, fromPort = getDomainFromActor(attributedTo) - fromDomainFull = getFullDomain(fromDomain, fromPort) - if notifyWhenPersonPosts(baseDir, nickname, domain, - fromNickname, fromDomainFull): - postId = removeIdEnding(jsonObj['id']) - domFull = getFullDomain(domain, port) - postLink = \ - localActorUrl(httpPrefix, - nickname, domFull) + \ - '?notifypost=' + postId.replace('/', '-') - _notifyPostArrival(baseDir, handle, postLink) + _lowFrequencyPostNotification(baseDir, httpPrefix, + nickname, domain, port, + handle, postIsDM, jsonObj) # If this is a reply to a muted post then also mute it. # This enables you to ignore a threat that's getting boring From a8d76b4d1885e5cd11ea3fbdfe71787dcd5471c2 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Thu, 4 Nov 2021 13:05:04 +0000 Subject: [PATCH 4/4] Tidying of checking for git patches --- inbox.py | 59 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/inbox.py b/inbox.py index b33c0f117..79d618497 100644 --- a/inbox.py +++ b/inbox.py @@ -2681,6 +2681,38 @@ def _lowFrequencyPostNotification(baseDir: str, httpPrefix: str, nickname: str, _notifyPostArrival(baseDir, handle, postLink) +def _checkForGitPatches(baseDir: str, nickname: str, domain: str, + handle: str, jsonObj: {}) -> int: + """check for incoming git patches + """ + if not jsonObj: + return 0 + if not jsonObj.get('content'): + return 0 + if not jsonObj.get('summary'): + return 0 + if not jsonObj.get('attributedTo'): + return 0 + attributedTo = jsonObj['attributedTo'] + if not isinstance(attributedTo, str): + return 0 + fromNickname = getNicknameFromActor(attributedTo) + fromDomain, fromPort = getDomainFromActor(attributedTo) + fromDomainFull = getFullDomain(fromDomain, fromPort) + if receiveGitPatch(baseDir, nickname, domain, + jsonObj['type'], jsonObj['summary'], + jsonObj['content'], + fromNickname, fromDomainFull): + _gitPatchNotify(baseDir, handle, + jsonObj['summary'], jsonObj['content'], + fromNickname, fromDomainFull) + return 1 + elif '[PATCH]' in jsonObj['content']: + print('WARN: git patch not accepted - ' + jsonObj['summary']) + return 2 + return 0 + + def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, session, keyId: str, handle: str, messageJson: {}, baseDir: str, httpPrefix: str, sendThreads: [], @@ -2885,29 +2917,10 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int, jsonObj = None else: jsonObj = postJsonObject - # check for incoming git patches - if jsonObj: - if jsonObj.get('content') and \ - jsonObj.get('summary') and \ - jsonObj.get('attributedTo'): - attributedTo = jsonObj['attributedTo'] - if isinstance(attributedTo, str): - fromNickname = getNicknameFromActor(attributedTo) - fromDomain, fromPort = getDomainFromActor(attributedTo) - fromDomain = getFullDomain(fromDomain, fromPort) - if receiveGitPatch(baseDir, nickname, domain, - jsonObj['type'], - jsonObj['summary'], - jsonObj['content'], - fromNickname, fromDomain): - _gitPatchNotify(baseDir, handle, - jsonObj['summary'], - jsonObj['content'], - fromNickname, fromDomain) - elif '[PATCH]' in jsonObj['content']: - print('WARN: git patch not accepted - ' + - jsonObj['summary']) - return False + + if _checkForGitPatches(baseDir, nickname, domain, + handle, jsonObj) == 2: + return False # replace YouTube links, so they get less tracking data replaceYouTube(postJsonObject, YTReplacementDomain, systemLanguage)