Add dm and reply notifications to speaker endpoint

merge-requests/21/head
Bob Mottram 2021-03-09 13:52:02 +00:00
parent 6a388a7103
commit 66056face5
5 changed files with 94 additions and 74 deletions

View File

@ -58,12 +58,12 @@ from filters import isFiltered
from utils import updateAnnounceCollection
from utils import undoAnnounceCollectionEntry
from utils import dangerousMarkup
from utils import isDM
from utils import isReply
from httpsig import messageContentDigest
from posts import createDirectMessagePost
from posts import validContentWarning
from posts import downloadAnnounce
from posts import isDM
from posts import isReply
from posts import isMuted
from posts import isImageMedia
from posts import sendSignedJson
@ -1408,7 +1408,9 @@ def _receiveAnnounce(recentPostsCache: {},
if isRecentPost(postJsonObject):
if not os.path.isfile(postFilename + '.tts'):
updateSpeaker(baseDir, nickname, domain,
domainFull = getFullDomain(domain, port)
updateSpeaker(baseDir, httpPrefix,
nickname, domain, domainFull,
postJsonObject, personCache,
translate, lookupActor)
ttsFile = open(postFilename + '.tts', "w+")
@ -2491,7 +2493,9 @@ def _inboxAfterInitial(recentPostsCache: {}, maxRecentPosts: int,
else:
if boxname == 'inbox':
if isRecentPost(postJsonObject):
updateSpeaker(baseDir, nickname, domain,
domainFull = getFullDomain(domain, port)
updateSpeaker(baseDir, httpPrefix,
nickname, domain, domainFull,
postJsonObject, personCache,
translate, None)
if not unitTest:

View File

@ -2921,34 +2921,6 @@ def createModeration(baseDir: str, nickname: str, domain: str, port: int,
return boxItems
def isDM(postJsonObject: {}) -> bool:
"""Returns true if the given post is a DM
"""
if postJsonObject['type'] != 'Create':
return False
if not postJsonObject.get('object'):
return False
if not isinstance(postJsonObject['object'], dict):
return False
if postJsonObject['object']['type'] != 'Note' and \
postJsonObject['object']['type'] != 'Patch' and \
postJsonObject['object']['type'] != 'EncryptedMessage' and \
postJsonObject['object']['type'] != 'Article':
return False
if postJsonObject['object'].get('moderationStatus'):
return False
fields = ('to', 'cc')
for f in fields:
if not postJsonObject['object'].get(f):
continue
for toAddress in postJsonObject['object'][f]:
if toAddress.endswith('#Public'):
return False
if toAddress.endswith('followers'):
return False
return True
def isImageMedia(session, baseDir: str, httpPrefix: str,
nickname: str, domain: str,
postJsonObject: {}, translate: {},
@ -2992,40 +2964,6 @@ def isImageMedia(session, baseDir: str, httpPrefix: str,
return False
def isReply(postJsonObject: {}, actor: str) -> bool:
"""Returns true if the given post is a reply to the given actor
"""
if postJsonObject['type'] != 'Create':
return False
if not postJsonObject.get('object'):
return False
if not isinstance(postJsonObject['object'], dict):
return False
if postJsonObject['object'].get('moderationStatus'):
return False
if postJsonObject['object']['type'] != 'Note' and \
postJsonObject['object']['type'] != 'EncryptedMessage' and \
postJsonObject['object']['type'] != 'Article':
return False
if postJsonObject['object'].get('inReplyTo'):
if isinstance(postJsonObject['object']['inReplyTo'], str):
if postJsonObject['object']['inReplyTo'].startswith(actor):
return True
if not postJsonObject['object'].get('tag'):
return False
if not isinstance(postJsonObject['object']['tag'], list):
return False
for tag in postJsonObject['object']['tag']:
if not tag.get('type'):
continue
if tag['type'] == 'Mention':
if not tag.get('href'):
continue
if actor in tag['href']:
return True
return False
def _addPostStringToTimeline(postStr: str, boxname: str,
postsInBox: [], boxActor: str) -> bool:
""" is this a valid timeline post?

View File

@ -12,6 +12,8 @@ import random
import urllib.parse
from auth import createBasicAuthHeader
from session import getJson
from utils import isDM
from utils import isReply
from utils import camelCaseSplit
from utils import getDomainFromActor
from utils import getNicknameFromActor
@ -263,7 +265,8 @@ def getSpeakerFromServer(baseDir: str, session,
def _speakerEndpointJson(displayName: str, summary: str,
content: str, imageDescription: str,
links: [], gender: str, postId: str) -> {}:
links: [], gender: str, postId: str,
postDM: bool, postReply: bool) -> {}:
"""Returns a json endpoint for the TTS speaker
"""
speakerJson = {
@ -272,7 +275,11 @@ def _speakerEndpointJson(displayName: str, summary: str,
"say": content,
"imageDescription": imageDescription,
"detectedLinks": links,
"id": postId
"id": postId,
"notify": {
"dm": postDM,
"reply": postReply
}
}
if gender:
speakerJson['gender'] = gender
@ -360,7 +367,8 @@ def getSSMLbox(baseDir: str, path: str,
instanceTitle, gender)
def _postToSpeakerJson(baseDir: str, nickname: str, domain: str,
def _postToSpeakerJson(baseDir: str, httpPrefix: str,
nickname: str, domain: str, domainFull: str,
postJsonObject: {}, personCache: {},
translate: {}, announcingActor: str) -> {}:
"""Converts an ActivityPub post into some Json containing
@ -429,19 +437,26 @@ def _postToSpeakerJson(baseDir: str, nickname: str, domain: str,
postId = None
if postJsonObject['object'].get('id'):
postId = postJsonObject['object']['id']
actor = httpPrefix + '://' + domainFull + '/users/' + nickname
postDM = isDM(postJsonObject)
postReply = isReply(postJsonObject, actor)
return _speakerEndpointJson(speakerName, summary,
content, imageDescription,
detectedLinks, gender, postId)
detectedLinks, gender, postId,
postDM, postReply)
def updateSpeaker(baseDir: str, nickname: str, domain: str,
def updateSpeaker(baseDir: str, httpPrefix: str,
nickname: str, domain: str, domainFull: str,
postJsonObject: {}, personCache: {},
translate: {}, announcingActor: str) -> None:
""" Generates a json file which can be used for TTS announcement
of incoming inbox posts
"""
speakerJson = \
_postToSpeakerJson(baseDir, nickname, domain,
_postToSpeakerJson(baseDir, httpPrefix,
nickname, domain, domainFull,
postJsonObject, personCache,
translate, announcingActor)
speakerFilename = \

View File

@ -2068,3 +2068,65 @@ def rejectPostId(baseDir: str, nickname: str, domain: str,
if rejectFile:
rejectFile.write('\n')
rejectFile.close()
def isDM(postJsonObject: {}) -> bool:
"""Returns true if the given post is a DM
"""
if postJsonObject['type'] != 'Create':
return False
if not postJsonObject.get('object'):
return False
if not isinstance(postJsonObject['object'], dict):
return False
if postJsonObject['object']['type'] != 'Note' and \
postJsonObject['object']['type'] != 'Patch' and \
postJsonObject['object']['type'] != 'EncryptedMessage' and \
postJsonObject['object']['type'] != 'Article':
return False
if postJsonObject['object'].get('moderationStatus'):
return False
fields = ('to', 'cc')
for f in fields:
if not postJsonObject['object'].get(f):
continue
for toAddress in postJsonObject['object'][f]:
if toAddress.endswith('#Public'):
return False
if toAddress.endswith('followers'):
return False
return True
def isReply(postJsonObject: {}, actor: str) -> bool:
"""Returns true if the given post is a reply to the given actor
"""
if postJsonObject['type'] != 'Create':
return False
if not postJsonObject.get('object'):
return False
if not isinstance(postJsonObject['object'], dict):
return False
if postJsonObject['object'].get('moderationStatus'):
return False
if postJsonObject['object']['type'] != 'Note' and \
postJsonObject['object']['type'] != 'EncryptedMessage' and \
postJsonObject['object']['type'] != 'Article':
return False
if postJsonObject['object'].get('inReplyTo'):
if isinstance(postJsonObject['object']['inReplyTo'], str):
if postJsonObject['object']['inReplyTo'].startswith(actor):
return True
if not postJsonObject['object'].get('tag'):
return False
if not isinstance(postJsonObject['object']['tag'], list):
return False
for tag in postJsonObject['object']['tag']:
if not tag.get('type'):
continue
if tag['type'] == 'Mention':
if not tag.get('href'):
continue
if actor in tag['href']:
return True
return False

View File

@ -19,9 +19,9 @@ from like import noOfLikes
from follow import isFollowingActor
from posts import postIsMuted
from posts import getPersonBox
from posts import isDM
from posts import downloadAnnounce
from posts import populateRepliesJson
from utils import isDM
from utils import rejectPostId
from utils import isRecentPost
from utils import getConfigParam
@ -1304,7 +1304,8 @@ def individualPostAsHtml(allowDownloads: bool,
postJsonObject['id'])
if announceFilename and postJsonObject.get('actor'):
if not os.path.isfile(announceFilename + '.tts'):
updateSpeaker(baseDir, nickname, domain,
updateSpeaker(baseDir, httpPrefix,
nickname, domain, domainFull,
postJsonObject, personCache,
translate, postJsonObject['actor'])
ttsFile = open(announceFilename + '.tts', "w+")