kopia lustrzana https://github.com/snarfed/bridgy-fed
rodzic
356903c3e9
commit
37c781a2df
40
atproto.py
40
atproto.py
|
@ -461,6 +461,10 @@ class ATProto(User, Protocol):
|
||||||
Doesn't deliver anywhere externally! Relays will receive this record
|
Doesn't deliver anywhere externally! Relays will receive this record
|
||||||
through ``subscribeRepos`` and then deliver it to AppView(s), which will
|
through ``subscribeRepos`` and then deliver it to AppView(s), which will
|
||||||
notify recipients as necessary.
|
notify recipients as necessary.
|
||||||
|
|
||||||
|
Exceptions:
|
||||||
|
* ``flag``s are translated to ``createReport`` to the mod service
|
||||||
|
* DMs are translated to ``sendMessage`` to the chat service
|
||||||
"""
|
"""
|
||||||
if util.domain_from_link(url) not in DOMAINS:
|
if util.domain_from_link(url) not in DOMAINS:
|
||||||
logger.info(f'Target PDS {url} is not us')
|
logger.info(f'Target PDS {url} is not us')
|
||||||
|
@ -527,6 +531,7 @@ class ATProto(User, Protocol):
|
||||||
# * delete actor => tombstone repo
|
# * delete actor => tombstone repo
|
||||||
# * flag => send report to mod service
|
# * flag => send report to mod service
|
||||||
# * stop-following => delete follow record (prepared above)
|
# * stop-following => delete follow record (prepared above)
|
||||||
|
# * dm => chat message
|
||||||
verb = obj.as1.get('verb')
|
verb = obj.as1.get('verb')
|
||||||
if verb == 'delete':
|
if verb == 'delete':
|
||||||
atp_base_id = (base_id if ATProto.owns_id(base_id)
|
atp_base_id = (base_id if ATProto.owns_id(base_id)
|
||||||
|
@ -537,7 +542,11 @@ class ATProto(User, Protocol):
|
||||||
arroba.server.storage.tombstone_repo(repo)
|
arroba.server.storage.tombstone_repo(repo)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
elif verb == 'flag':
|
if not record:
|
||||||
|
# _convert already logged
|
||||||
|
return False
|
||||||
|
|
||||||
|
if verb == 'flag':
|
||||||
logger.info(f'flag => createReport with {record}')
|
logger.info(f'flag => createReport with {record}')
|
||||||
return to_cls.create_report(record, from_user=user)
|
return to_cls.create_report(record, from_user=user)
|
||||||
|
|
||||||
|
@ -546,11 +555,13 @@ class ATProto(User, Protocol):
|
||||||
assert base_obj and base_obj.type == 'follow', base_obj
|
assert base_obj and base_obj.type == 'follow', base_obj
|
||||||
verb = 'delete'
|
verb = 'delete'
|
||||||
|
|
||||||
# write commit
|
elif as1.is_dm(obj.as1):
|
||||||
if not record:
|
# is_dm checked that `to` has one elem
|
||||||
# _convert already logged
|
to_id = as1.get_ids(base_obj_as1, 'to')[0]
|
||||||
return False
|
assert to_id.startswith('did:'), to_id
|
||||||
|
return ATProto.send_chat(record, from_repo=repo, to_did=to_id)
|
||||||
|
|
||||||
|
# write commit
|
||||||
type = record['$type']
|
type = record['$type']
|
||||||
lex_type = LEXICONS[type]['type']
|
lex_type = LEXICONS[type]['type']
|
||||||
assert lex_type == 'record', f"Can't store {type} object of type {lex_type}"
|
assert lex_type == 'record', f"Can't store {type} object of type {lex_type}"
|
||||||
|
@ -835,12 +846,14 @@ class ATProto(User, Protocol):
|
||||||
logger.info(f'Created report on {mod_host}: {json_dumps(output)}')
|
logger.info(f'Created report on {mod_host}: {json_dumps(output)}')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def send_chat(self, msg, from_user):
|
@classmethod
|
||||||
|
def send_chat(cls, msg, from_repo, to_did):
|
||||||
"""Sends a chat message to this user.
|
"""Sends a chat message to this user.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
msg (dict): ``chat.bsky.convo.defs#messageInput``
|
msg (dict): ``chat.bsky.convo.defs#messageInput``
|
||||||
from_user (models.User)
|
from_repo (arroba.repo.Repo)
|
||||||
|
to_did (str)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
bool: True if the report was sent successfully, False if the flag's
|
bool: True if the report was sent successfully, False if the flag's
|
||||||
|
@ -848,18 +861,11 @@ class ATProto(User, Protocol):
|
||||||
"""
|
"""
|
||||||
assert msg['$type'] == 'chat.bsky.convo.defs#messageInput'
|
assert msg['$type'] == 'chat.bsky.convo.defs#messageInput'
|
||||||
|
|
||||||
to_did = self.key.id()
|
|
||||||
from_did = from_user.get_copy(ATProto)
|
|
||||||
if not from_did or not from_user.is_enabled(ATProto):
|
|
||||||
return False
|
|
||||||
|
|
||||||
repo = arroba.server.storage.load_repo(from_did)
|
|
||||||
|
|
||||||
chat_host = os.environ['CHAT_HOST']
|
chat_host = os.environ['CHAT_HOST']
|
||||||
token = service_jwt(host=chat_host,
|
token = service_jwt(host=chat_host,
|
||||||
aud=os.environ['CHAT_DID'],
|
aud=os.environ['CHAT_DID'],
|
||||||
repo_did=from_did,
|
repo_did=from_repo.did,
|
||||||
privkey=repo.signing_key)
|
privkey=from_repo.signing_key)
|
||||||
client = Client(f'https://{chat_host}', truncate=True, headers={
|
client = Client(f'https://{chat_host}', truncate=True, headers={
|
||||||
'User-Agent': USER_AGENT,
|
'User-Agent': USER_AGENT,
|
||||||
'Authorization': f'Bearer {token}',
|
'Authorization': f'Bearer {token}',
|
||||||
|
@ -876,5 +882,5 @@ class ATProto(User, Protocol):
|
||||||
util.interpret_http_exception(e)
|
util.interpret_http_exception(e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logger.info(f'Sent chat message from {from_user.handle} to {self.handle} {to_did}: {json_dumps(sent)}')
|
logger.info(f'Sent chat message from {from_repo.handle} to {to_did}: {json_dumps(sent)}')
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -1741,8 +1741,7 @@ Sed tortor neque, aliquet quis posuere aliquam […]
|
||||||
'Authorization': ANY,
|
'Authorization': ANY,
|
||||||
})
|
})
|
||||||
|
|
||||||
# sendMessage
|
@patch('requests.post', return_value=requests_response({ # sendMessage
|
||||||
@patch('requests.post', return_value=requests_response({
|
|
||||||
'id': 'chat456',
|
'id': 'chat456',
|
||||||
'rev': '22222222tef2d',
|
'rev': '22222222tef2d',
|
||||||
'sender': {'did': 'did:plc:user'},
|
'sender': {'did': 'did:plc:user'},
|
||||||
|
@ -1764,18 +1763,25 @@ Sed tortor neque, aliquet quis posuere aliquam […]
|
||||||
}),
|
}),
|
||||||
requests_response(DID_DOC),
|
requests_response(DID_DOC),
|
||||||
])
|
])
|
||||||
def test_send_chat(self, mock_get, mock_post):
|
def test_send_dm_chat(self, mock_get, mock_post):
|
||||||
user = self.make_user_and_repo()
|
user = self.make_user_and_repo()
|
||||||
alice = ATProto(id='did:plc:alice')
|
|
||||||
|
|
||||||
self.assertTrue(alice.send_chat({
|
dm = Object(id='fake:dm', source_protocol='fake', our_as1={
|
||||||
'$type': 'chat.bsky.convo.defs#messageInput',
|
'objectType': 'note',
|
||||||
'text': 'hello world',
|
'actor': user.key.id(),
|
||||||
}, from_user=user))
|
'content': 'hello world',
|
||||||
|
'to': ['did:plc:alice'],
|
||||||
|
})
|
||||||
|
self.assertTrue(ATProto.send(dm, 'https://bsky.brid.gy/'))
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'User-Agent': common.USER_AGENT,
|
||||||
|
'Authorization': ANY,
|
||||||
|
}
|
||||||
mock_get.assert_any_call(
|
mock_get.assert_any_call(
|
||||||
'https://chat.service.local/xrpc/chat.bsky.convo.getConvoForMembers?members=did%3Aplc%3Aalice',
|
'https://chat.service.local/xrpc/chat.bsky.convo.getConvoForMembers?members=did%3Aplc%3Aalice',
|
||||||
json=None, data=None, headers=ANY)
|
json=None, data=None, headers=headers)
|
||||||
mock_post.assert_called_with(
|
mock_post.assert_called_with(
|
||||||
'https://chat.service.local/xrpc/chat.bsky.convo.sendMessage',
|
'https://chat.service.local/xrpc/chat.bsky.convo.sendMessage',
|
||||||
json={
|
json={
|
||||||
|
@ -1783,12 +1789,12 @@ Sed tortor neque, aliquet quis posuere aliquam […]
|
||||||
'message': {
|
'message': {
|
||||||
'$type': 'chat.bsky.convo.defs#messageInput',
|
'$type': 'chat.bsky.convo.defs#messageInput',
|
||||||
'text': 'hello world',
|
'text': 'hello world',
|
||||||
|
# unused
|
||||||
|
'createdAt': '2022-01-02T03:04:05.000Z',
|
||||||
|
'bridgyOriginalText': 'hello world',
|
||||||
|
'bridgyOriginalUrl': 'fake:dm',
|
||||||
},
|
},
|
||||||
}, data=None, headers={
|
}, data=None, headers=headers)
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'User-Agent': common.USER_AGENT,
|
|
||||||
'Authorization': ANY,
|
|
||||||
})
|
|
||||||
|
|
||||||
# getConvoForMembers
|
# getConvoForMembers
|
||||||
@patch('requests.get', return_value=requests_response({
|
@patch('requests.get', return_value=requests_response({
|
||||||
|
@ -1797,12 +1803,14 @@ Sed tortor neque, aliquet quis posuere aliquam […]
|
||||||
}, status=400))
|
}, status=400))
|
||||||
def test_send_chat_recipient_disabled(self, mock_get):
|
def test_send_chat_recipient_disabled(self, mock_get):
|
||||||
user = self.make_user_and_repo()
|
user = self.make_user_and_repo()
|
||||||
alice = ATProto(id='did:plc:alice')
|
|
||||||
|
|
||||||
self.assertFalse(alice.send_chat({
|
dm = Object(id='fake:dm', source_protocol='fake', our_as1={
|
||||||
'$type': 'chat.bsky.convo.defs#messageInput',
|
'objectType': 'note',
|
||||||
'text': 'hello world',
|
'actor': user.key.id(),
|
||||||
}, from_user=user))
|
'content': 'hello world',
|
||||||
|
'to': ['did:plc:alice'],
|
||||||
|
})
|
||||||
|
self.assertFalse(ATProto.send(dm, 'https://bsky.brid.gy/'))
|
||||||
|
|
||||||
mock_get.assert_any_call(
|
mock_get.assert_any_call(
|
||||||
'https://chat.service.local/xrpc/chat.bsky.convo.getConvoForMembers?members=did%3Aplc%3Aalice',
|
'https://chat.service.local/xrpc/chat.bsky.convo.getConvoForMembers?members=did%3Aplc%3Aalice',
|
||||||
|
|
Ładowanie…
Reference in New Issue