",
"id": f"{TEST_AP_ACTOR_ID}/statuses/tag_123",
"published": "2022-05-20T08:14:39Z",
"to": [ap_const.NS_AP_PUBLIC],
"tag": [{"type": "Mention", "href": xmpp_actor_id, "name": f"@{TEST_JID}'"}],
"type": "Note",
}
client = ap_gateway.client.getVirtualClient(
ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
)
monkeypatch.setattr(client, "sendMessage", MagicMock())
with patch.object(ap_gateway._refs, "sendReference") as sendReference:
await ap_gateway.newAPItem(
client, None, ap_gateway._m.namespace, direct_addr_mention
)
assert sendReference.call_count == 1
assert sendReference.call_args.kwargs["to_jid"] == TEST_JID
local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
expected_anchor = xmpp_uri.buildXMPPUri(
"pubsub",
path=local_actor_jid.full(),
node=ap_gateway._m.namespace,
item=direct_addr_mention["id"],
)
assert sendReference.call_args.kwargs["anchor"] == expected_anchor
@ed
async def test_auto_mentions(self, ap_gateway, monkeypatch):
"""Check that mentions in body are converted to AP mentions"""
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
mb_data = {
"author_jid": TEST_JID.full(),
"content": f"mention of @{TEST_AP_ACCOUNT}",
"service": TEST_JID.full(),
"node": ap_gateway._m.namespace,
}
ap_item = await ap_gateway.mb_data_2_ap_item(
ap_gateway.client, mb_data, public=True
)
ap_object = ap_item["object"]
assert TEST_AP_ACTOR_ID in ap_object["to"]
expected_mention = {
"type": ap_const.TYPE_MENTION,
"href": TEST_AP_ACTOR_ID,
"name": f"@{TEST_AP_ACCOUNT}",
}
assert expected_mention in ap_object["tag"]
@ed
async def test_no_auto_mentions_when_not_public(self, ap_gateway, monkeypatch):
"""Check that no mention is send when the message is not public"""
# this is the same test as test_auto_mentions above, except that public is not set
# in mb_data_2_ap_item
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
mb_data = {
"author_jid": TEST_JID.full(),
"content": f"mention of @{TEST_AP_ACCOUNT}",
"service": TEST_JID.full(),
"node": ap_gateway._m.namespace,
}
ap_item = await ap_gateway.mb_data_2_ap_item(
ap_gateway.client, mb_data, public=False
)
ap_object = ap_item["object"]
assert "to" not in ap_object
assert "tag" not in ap_object
@ed
async def test_xmpp_reference_to_ap_mention(self, ap_gateway, monkeypatch):
"""Check that XEP-0372 references are converted to AP mention"""
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
item_elt = XMPP_ITEMS[0]
anchor = xmpp_uri.buildXMPPUri(
"pubsub",
path=TEST_JID.full(),
node=ap_gateway._m.namespace,
item=item_elt["id"],
)
ref_data: Dict[str, Union[str, int, dict]] = {
"uri": xmpp_uri.buildXMPPUri(None, path=local_actor_jid.full()),
"type_": "mention",
"anchor": anchor,
}
reference_elt = ap_gateway._refs.buildRefElement(**ref_data)
# we now update ref_data to look like what is received in the trigger
ref_data["parsed_uri"] = xmpp_uri.parseXMPPUri(ref_data["uri"])
ref_data["parsed_anchor"] = xmpp_uri.parseXMPPUri(ref_data["anchor"])
# "type" is a builtin function, thus "type_" is used in buildRefElement, but in
# ref_data is "type" without underscore
ref_data["type"] = ref_data["type_"]
del ref_data["type_"]
message_elt = domish.Element((None, "message"))
message_elt.addChild(reference_elt)
with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems:
# getItems returns a sqla_mapping.PubsubItem, thus we need to fake it and set
# the item_elt we want to use in its "data" attribute
mock_pubsub_item = MagicMock
mock_pubsub_item.data = item_elt
getItems.return_value = ([mock_pubsub_item], {})
with patch.object(ap_gateway, "signAndPost") as signAndPost:
signAndPost.return_value.code = 202
await ap_gateway._onReferenceReceived(
ap_gateway.client, message_elt, ref_data
)
# when reference is received, the referencing item must be sent to referenced
# actor, and they must be in "to" field and in "tag"
assert signAndPost.call_count == 1
send_ap_item = signAndPost.call_args.args[-1]
ap_object = send_ap_item["object"]
assert TEST_AP_ACTOR_ID in ap_object["to"]
expected_mention = {
"type": ap_const.TYPE_MENTION,
"href": TEST_AP_ACTOR_ID,
# we don't have a prefixing "@" here, because it's not needed in referencing
# item with XMPP
"name": f"{TEST_AP_ACCOUNT}",
}
assert expected_mention in ap_object["tag"]
@ed
async def test_xmpp_repeat_to_ap_announce(self, ap_gateway, monkeypatch):
"""XEP-0272 post repeat is converted to AP Announce activity"""
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
# JID repeated AP actor (also the recipient of the message)
recipient_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
# repeated item
ap_item = TEST_AP_ITEMS[0]
ap_item_url = xmpp_uri.buildXMPPUri(
"pubsub",
path=recipient_jid.full(),
node=ap_gateway._m.namespace,
item=ap_item["id"],
)
item_elt = xml_tools.parse(
f"""
test message 1
test message 1
test_userxmpp:{recipient_jid}2022-07-21T14:38:53Z2022-07-21T14:38:53Z{ap_item["id"]}
"""
)
item_elt.uri = pubsub.NS_PUBSUB_EVENT
with patch.object(ap_gateway, "signAndPost") as signAndPost:
signAndPost.return_value.code = 202
await ap_gateway.convertAndPostItems(
ap_gateway.client,
TEST_AP_ACCOUNT,
TEST_JID,
ap_gateway._m.namespace,
[item_elt],
)
assert signAndPost.called
url, actor_id, doc = signAndPost.call_args.args
assert url == TEST_USER_DATA["endpoints"]["sharedInbox"]
assert actor_id == ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
assert doc["type"] == "Announce"
assert ap_const.NS_AP_PUBLIC in doc["to"]
assert doc["object"] == ap_item["id"]
@ed
async def test_ap_announce_to_xmpp_repeat(self, ap_gateway, monkeypatch):
"""AP Announce activity is converted to XEP-0272 post repeat"""
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
# announced item
xmpp_item = XMPP_ITEMS[0]
xmpp_item_url = ap_gateway.buildAPURL(
ap_const.TYPE_ITEM, TEST_JID.userhost(), xmpp_item["id"]
)
announce = {
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Announce",
"actor": TEST_AP_ACTOR_ID,
"cc": [xmpp_actor_id, TEST_USER_DATA["followers"]],
"id": "https://example.org/announce/123",
"object": xmpp_item_url,
"published": "2022-07-22T09:24:12Z",
"to": [ap_const.NS_AP_PUBLIC],
}
with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems:
mock_pubsub_item = MagicMock
mock_pubsub_item.data = xmpp_item
getItems.return_value = ([mock_pubsub_item], {})
with patch.object(
ap_gateway.host.memory.storage, "cachePubsubItems"
) as cachePubsubItems:
await ap_gateway.server.resource.handleAnnounceActivity(
Request(MagicMock()), announce, None, None, None, "", TEST_AP_ACTOR_ID
)
assert cachePubsubItems.called
# the microblog data put in cache correspond to the item sent to subscribers
__, __, __, [mb_data] = cachePubsubItems.call_args.args
extra = mb_data["extra"]
assert "repeated" in extra
repeated = extra["repeated"]
assert repeated["by"] == ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT).full()
xmpp_item_xmpp_url = xmpp_uri.buildXMPPUri(
"pubsub",
path=TEST_JID.full(),
node=ap_gateway._m.namespace,
item=xmpp_item["id"],
)
assert repeated["uri"] == xmpp_item_xmpp_url
@ed
async def test_xmpp_attachment_noticed_to_ap_like(self, ap_gateway, monkeypatch):
"""Pubsub-attachments ``noticed`` is converted to AP Like activity"""
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
recipient_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
# noticed item
ap_item = TEST_AP_ITEMS[0]
attachment_node = ap_gateway._pa.getAttachmentNodeName(
recipient_jid, ap_gateway._m.namespace, ap_item["id"]
)
item_elt = xml_tools.parse(
f"""
"""
)
item_elt.uri = pubsub.NS_PUBSUB_EVENT
items_event = pubsub.ItemsEvent(
TEST_JID, recipient_jid, attachment_node, [item_elt], {}
)
with patch.object(ap_gateway, "signAndPost") as signAndPost:
signAndPost.return_value.code = 202
await ap_gateway._itemsReceived(ap_gateway.client, items_event)
assert signAndPost.called
url, actor_id, doc = signAndPost.call_args.args
assert url == TEST_USER_DATA["endpoints"]["sharedInbox"]
assert actor_id == ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
assert doc["type"] == "Like"
assert ap_const.NS_AP_PUBLIC in doc["cc"]
assert doc["object"] == ap_item["id"]
@ed
async def test_ap_like_to_xmpp_noticed_attachment(self, ap_gateway, monkeypatch):
"""AP Like activity is converted to ``noticed`` attachment"""
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
# liked item
xmpp_item = XMPP_ITEMS[0]
xmpp_item_url = ap_gateway.buildAPURL(
ap_const.TYPE_ITEM, TEST_JID.userhost(), xmpp_item["id"]
)
like = {
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Like",
"actor": TEST_AP_ACTOR_ID,
"cc": [xmpp_actor_id, TEST_USER_DATA["followers"]],
"id": "https://example.org/like/123",
"object": xmpp_item_url,
"published": "2022-07-22T09:24:12Z",
"to": [ap_const.NS_AP_PUBLIC],
}
with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems:
getItems.return_value = ([], {})
with patch.object(ap_gateway._p, "sendItems") as sendItems:
await ap_gateway.server.resource.APInboxRequest(
**self.ap_request_params(
ap_gateway, "inbox", doc=like, signing_actor=TEST_AP_ACTOR_ID
)
)
assert sendItems.called
si_client, si_service, si_node, [si_item] = sendItems.call_args.args
assert si_client.jid == ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
assert si_service == TEST_JID
assert si_node == ap_gateway._pa.getAttachmentNodeName(
TEST_JID, ap_gateway._m.namespace, xmpp_item["id"]
)
[parsed_item] = ap_gateway._pa.items2attachmentData(si_client, [si_item])
assert parsed_item["from"] == si_client.jid.full()
assert "noticed" in parsed_item
assert parsed_item["noticed"]["noticed"] == True
@ed
async def test_xmpp_pubsub_reactions_to_ap(self, ap_gateway, monkeypatch):
"""Pubsub-attachments ``reactions`` is converted to AP EmojiReact activity"""
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
recipient_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
# noticed item
ap_item = TEST_AP_ITEMS[0]
ap_item_url = xmpp_uri.buildXMPPUri(
"pubsub",
path=recipient_jid.full(),
node=ap_gateway._m.namespace,
item=ap_item["id"],
)
attachment_node = ap_gateway._pa.getAttachmentNodeName(
recipient_jid, ap_gateway._m.namespace, ap_item["id"]
)
reactions = ["π¦", "π₯", "π»"]
item_elt = xml_tools.parse(
f"""
{reactions[0]}{reactions[1]}{reactions[2]}
"""
)
item_elt.uri = pubsub.NS_PUBSUB_EVENT
items_event = pubsub.ItemsEvent(
TEST_JID, recipient_jid, attachment_node, [item_elt], {}
)
with patch.object(ap_gateway, "signAndPost") as signAndPost:
signAndPost.return_value.code = 202
await ap_gateway._itemsReceived(ap_gateway.client, items_event)
assert signAndPost.call_count == 3
for idx, call_args in enumerate(signAndPost.call_args_list):
url, actor_id, doc = call_args.args
assert url == TEST_USER_DATA["endpoints"]["sharedInbox"]
assert actor_id == ap_gateway.buildAPURL(
ap_const.TYPE_ACTOR, TEST_JID.userhost()
)
assert doc["type"] == "EmojiReact"
assert ap_const.NS_AP_PUBLIC in doc["cc"]
assert doc["object"] == ap_item["id"]
# reactions can be sent in random order (due to the use of set), thus we check
# if each reaction appear once, and that nothing is left after all calls are
# checked.
assert doc["content"] in reactions
reactions.remove(doc["content"])
assert len(reactions) == 0
@ed
async def test_ap_reactions_to_xmpp(self, ap_gateway, monkeypatch):
"""AP EmojiReact activity is converted to ``reactions`` attachment"""
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
# item on which reaction is attached
xmpp_item = XMPP_ITEMS[0]
xmpp_item_url = ap_gateway.buildAPURL(
ap_const.TYPE_ITEM, TEST_JID.userhost(), xmpp_item["id"]
)
like = {
"@context": "https://www.w3.org/ns/activitystreams",
"type": "EmojiReact",
"actor": TEST_AP_ACTOR_ID,
"cc": [xmpp_actor_id, TEST_USER_DATA["followers"]],
"id": "https://example.org/like/123",
"object": xmpp_item_url,
"content": "π ",
"published": "2022-07-22T09:24:12Z",
"to": [ap_const.NS_AP_PUBLIC],
}
with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems:
getItems.return_value = ([], {})
with patch.object(ap_gateway._p, "sendItems") as sendItems:
await ap_gateway.server.resource.APInboxRequest(
**self.ap_request_params(
ap_gateway, "inbox", doc=like, signing_actor=TEST_AP_ACTOR_ID
)
)
assert sendItems.called
si_client, si_service, si_node, [si_item] = sendItems.call_args.args
assert si_client.jid == ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
assert si_service == TEST_JID
assert si_node == ap_gateway._pa.getAttachmentNodeName(
TEST_JID, ap_gateway._m.namespace, xmpp_item["id"]
)
[parsed_item] = ap_gateway._pa.items2attachmentData(si_client, [si_item])
assert parsed_item["from"] == si_client.jid.full()
assert "reactions" in parsed_item
assert parsed_item["reactions"]["reactions"] == ["π "]