comparison tests/unit/test_ap-gateway.py @ 3907:755920bd30da

tests (unit/AP gateway): fix tests: rel 372
author Goffi <goffi@goffi.org>
date Thu, 22 Sep 2022 00:01:48 +0200
parents 989df1047c3c
children d43b197735d1
comparison
equal deleted inserted replaced
3906:d8baf92cb921 3907:755920bd30da
60 AP_REQUESTS = { 60 AP_REQUESTS = {
61 f"{TEST_BASE_URL}/.well-known/webfinger?" 61 f"{TEST_BASE_URL}/.well-known/webfinger?"
62 f"resource=acct:{parse.quote(TEST_AP_ACCOUNT)}": { 62 f"resource=acct:{parse.quote(TEST_AP_ACCOUNT)}": {
63 "aliases": [ 63 "aliases": [
64 f"{TEST_BASE_URL}/@{TEST_USER}", 64 f"{TEST_BASE_URL}/@{TEST_USER}",
65 f"{TEST_BASE_URL}/users/{TEST_USER}" 65 f"{TEST_BASE_URL}/users/{TEST_USER}",
66 ], 66 ],
67 "links": [ 67 "links": [
68 { 68 {
69 "href": f"{TEST_BASE_URL}/users/{TEST_USER}", 69 "href": f"{TEST_BASE_URL}/users/{TEST_USER}",
70 "rel": "self", 70 "rel": "self",
71 "type": "application/activity+json" 71 "type": "application/activity+json",
72 }, 72 },
73 ], 73 ],
74 "subject": f"acct:{TEST_AP_ACCOUNT}" 74 "subject": f"acct:{TEST_AP_ACCOUNT}",
75 }, 75 },
76
77 f"{TEST_BASE_URL}/users/{TEST_USER}": { 76 f"{TEST_BASE_URL}/users/{TEST_USER}": {
78 "@context": [ 77 "@context": [
79 "https://www.w3.org/ns/activitystreams", 78 "https://www.w3.org/ns/activitystreams",
80 ], 79 ],
81 "endpoints": { 80 "endpoints": {"sharedInbox": f"{TEST_BASE_URL}/inbox"},
82 "sharedInbox": f"{TEST_BASE_URL}/inbox"
83 },
84 "followers": f"{TEST_BASE_URL}/users/{TEST_USER}/followers", 81 "followers": f"{TEST_BASE_URL}/users/{TEST_USER}/followers",
85 "following": f"{TEST_BASE_URL}/users/{TEST_USER}/following", 82 "following": f"{TEST_BASE_URL}/users/{TEST_USER}/following",
86 "id": f"{TEST_BASE_URL}/users/{TEST_USER}", 83 "id": f"{TEST_BASE_URL}/users/{TEST_USER}",
87 "inbox": f"{TEST_BASE_URL}/users/{TEST_USER}/inbox", 84 "inbox": f"{TEST_BASE_URL}/users/{TEST_USER}/inbox",
88 "name": "test_user nickname", 85 "name": "test_user nickname",
89 "summary": "<p>test account</p>", 86 "summary": "<p>test account</p>",
90 "outbox": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", 87 "outbox": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox",
91 "preferredUsername": f"{TEST_USER}", 88 "preferredUsername": f"{TEST_USER}",
92 "type": "Person", 89 "type": "Person",
93 "url": f"{TEST_BASE_URL}/@{TEST_USER}" 90 "url": f"{TEST_BASE_URL}/@{TEST_USER}",
94 }, 91 },
95 f"{TEST_BASE_URL}/.well-known/webfinger?" 92 f"{TEST_BASE_URL}/.well-known/webfinger?"
96 f"resource=acct:{parse.quote('ext_user@example.org')}": { 93 f"resource=acct:{parse.quote('ext_user@example.org')}": {
97 "aliases": [ 94 "aliases": [f"{TEST_BASE_URL}/@ext_user", f"{TEST_BASE_URL}/users/ext_user"],
98 f"{TEST_BASE_URL}/@ext_user",
99 f"{TEST_BASE_URL}/users/ext_user"
100 ],
101 "links": [ 95 "links": [
102 { 96 {
103 "href": f"{TEST_BASE_URL}/users/ext_user", 97 "href": f"{TEST_BASE_URL}/users/ext_user",
104 "rel": "self", 98 "rel": "self",
105 "type": "application/activity+json" 99 "type": "application/activity+json",
106 }, 100 },
107 ], 101 ],
108 "subject": f"acct:ext_user@example.org" 102 "subject": f"acct:ext_user@example.org",
109 }, 103 },
110 f"{TEST_BASE_URL}/users/ext_user": { 104 f"{TEST_BASE_URL}/users/ext_user": {
111 "@context": [ 105 "@context": [
112 "https://www.w3.org/ns/activitystreams", 106 "https://www.w3.org/ns/activitystreams",
113 ], 107 ],
114 "endpoints": { 108 "endpoints": {"sharedInbox": f"{TEST_BASE_URL}/inbox"},
115 "sharedInbox": f"{TEST_BASE_URL}/inbox"
116 },
117 "followers": f"{TEST_BASE_URL}/users/ext_user/followers", 109 "followers": f"{TEST_BASE_URL}/users/ext_user/followers",
118 "following": f"{TEST_BASE_URL}/users/ext_user/following", 110 "following": f"{TEST_BASE_URL}/users/ext_user/following",
119 "id": f"{TEST_BASE_URL}/users/ext_user", 111 "id": f"{TEST_BASE_URL}/users/ext_user",
120 "inbox": f"{TEST_BASE_URL}/users/ext_user/inbox", 112 "inbox": f"{TEST_BASE_URL}/users/ext_user/inbox",
121 "name": "", 113 "name": "",
122 "outbox": f"{TEST_BASE_URL}/users/ext_user/outbox", 114 "outbox": f"{TEST_BASE_URL}/users/ext_user/outbox",
123 "preferredUsername": f"ext_user", 115 "preferredUsername": f"ext_user",
124 "type": "Person", 116 "type": "Person",
125 "url": f"{TEST_BASE_URL}/@ext_user" 117 "url": f"{TEST_BASE_URL}/@ext_user",
126 }, 118 },
127 f"{TEST_BASE_URL}/users/{TEST_USER}/outbox": { 119 f"{TEST_BASE_URL}/users/{TEST_USER}/outbox": {
128 "@context": "https://www.w3.org/ns/activitystreams", 120 "@context": "https://www.w3.org/ns/activitystreams",
129 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true", 121 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true",
130 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", 122 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox",
131 "last": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true", 123 "last": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true",
132 "totalItems": 4, 124 "totalItems": 4,
133 "type": "OrderedCollection" 125 "type": "OrderedCollection",
134 }, 126 },
135 f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true": { 127 f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true": {
136 "@context": [ 128 "@context": [
137 "https://www.w3.org/ns/activitystreams", 129 "https://www.w3.org/ns/activitystreams",
138 ], 130 ],
148 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", 140 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}",
149 "cc": [ 141 "cc": [
150 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", 142 f"{TEST_BASE_URL}/users/{TEST_USER}/followers",
151 ], 143 ],
152 "content": "<p>test message 1</p>", 144 "content": "<p>test message 1</p>",
153 "contentMap": { 145 "contentMap": {"en": "<p>test message 1</p>"},
154 "en": "<p>test message 1</p>"
155 },
156 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/1", 146 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/1",
157 "inReplyTo": None, 147 "inReplyTo": None,
158 "published": "2021-12-16T17:28:03Z", 148 "published": "2021-12-16T17:28:03Z",
159 "sensitive": False, 149 "sensitive": False,
160 "summary": None, 150 "summary": None,
161 "tag": [], 151 "tag": [],
162 "to": [ 152 "to": ["https://www.w3.org/ns/activitystreams#Public"],
163 "https://www.w3.org/ns/activitystreams#Public"
164 ],
165 "type": "Note", 153 "type": "Note",
166 "url": f"{TEST_BASE_URL}/@{TEST_USER}/1" 154 "url": f"{TEST_BASE_URL}/@{TEST_USER}/1",
167 }, 155 },
168 "published": "2021-12-16T17:28:03Z", 156 "published": "2021-12-16T17:28:03Z",
169 "to": [ 157 "to": ["https://www.w3.org/ns/activitystreams#Public"],
170 "https://www.w3.org/ns/activitystreams#Public" 158 "type": "Create",
171 ],
172 "type": "Create"
173 }, 159 },
174 { 160 {
175 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", 161 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}",
176 "cc": [ 162 "cc": [
177 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", 163 f"{TEST_BASE_URL}/users/{TEST_USER}/followers",
181 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", 167 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}",
182 "cc": [ 168 "cc": [
183 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", 169 f"{TEST_BASE_URL}/users/{TEST_USER}/followers",
184 ], 170 ],
185 "content": "<p>test message 2</p>", 171 "content": "<p>test message 2</p>",
186 "contentMap": { 172 "contentMap": {"en": "<p>test message 2</p>"},
187 "en": "<p>test message 2</p>"
188 },
189 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/2", 173 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/2",
190 "inReplyTo": None, 174 "inReplyTo": None,
191 "published": "2021-12-16T17:27:03Z", 175 "published": "2021-12-16T17:27:03Z",
192 "sensitive": False, 176 "sensitive": False,
193 "summary": None, 177 "summary": None,
194 "tag": [], 178 "tag": [],
195 "to": [ 179 "to": ["https://www.w3.org/ns/activitystreams#Public"],
196 "https://www.w3.org/ns/activitystreams#Public"
197 ],
198 "type": "Note", 180 "type": "Note",
199 "url": f"{TEST_BASE_URL}/@{TEST_USER}/2" 181 "url": f"{TEST_BASE_URL}/@{TEST_USER}/2",
200 }, 182 },
201 "published": "2021-12-16T17:27:03Z", 183 "published": "2021-12-16T17:27:03Z",
202 "to": [ 184 "to": ["https://www.w3.org/ns/activitystreams#Public"],
203 "https://www.w3.org/ns/activitystreams#Public" 185 "type": "Create",
204 ],
205 "type": "Create"
206 }, 186 },
207 { 187 {
208 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", 188 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}",
209 "cc": [ 189 "cc": [
210 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", 190 f"{TEST_BASE_URL}/users/{TEST_USER}/followers",
214 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", 194 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}",
215 "cc": [ 195 "cc": [
216 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", 196 f"{TEST_BASE_URL}/users/{TEST_USER}/followers",
217 ], 197 ],
218 "content": "<p>test message 3</p>", 198 "content": "<p>test message 3</p>",
219 "contentMap": { 199 "contentMap": {"en": "<p>test message 3</p>"},
220 "en": "<p>test message 3</p>"
221 },
222 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/3", 200 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/3",
223 "inReplyTo": None, 201 "inReplyTo": None,
224 "published": "2021-12-16T17:26:03Z", 202 "published": "2021-12-16T17:26:03Z",
225 "sensitive": False, 203 "sensitive": False,
226 "summary": None, 204 "summary": None,
227 "tag": [], 205 "tag": [],
228 "to": [ 206 "to": ["https://www.w3.org/ns/activitystreams#Public"],
229 "https://www.w3.org/ns/activitystreams#Public"
230 ],
231 "type": "Note", 207 "type": "Note",
232 "url": f"{TEST_BASE_URL}/@{TEST_USER}/3" 208 "url": f"{TEST_BASE_URL}/@{TEST_USER}/3",
233 }, 209 },
234 "published": "2021-12-16T17:26:03Z", 210 "published": "2021-12-16T17:26:03Z",
235 "to": [ 211 "to": ["https://www.w3.org/ns/activitystreams#Public"],
236 "https://www.w3.org/ns/activitystreams#Public" 212 "type": "Create",
237 ],
238 "type": "Create"
239 }, 213 },
240 { 214 {
241 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", 215 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}",
242 "cc": [ 216 "cc": [
243 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", 217 f"{TEST_BASE_URL}/users/{TEST_USER}/followers",
247 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", 221 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}",
248 "cc": [ 222 "cc": [
249 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", 223 f"{TEST_BASE_URL}/users/{TEST_USER}/followers",
250 ], 224 ],
251 "content": "<p>test message 4</p>", 225 "content": "<p>test message 4</p>",
252 "contentMap": { 226 "contentMap": {"en": "<p>test message 4</p>"},
253 "en": "<p>test message 4</p>"
254 },
255 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/4", 227 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/4",
256 "inReplyTo": None, 228 "inReplyTo": None,
257 "published": "2021-12-16T17:25:03Z", 229 "published": "2021-12-16T17:25:03Z",
258 "sensitive": False, 230 "sensitive": False,
259 "summary": None, 231 "summary": None,
260 "tag": [], 232 "tag": [],
261 "to": [ 233 "to": ["https://www.w3.org/ns/activitystreams#Public"],
262 "https://www.w3.org/ns/activitystreams#Public"
263 ],
264 "type": "Note", 234 "type": "Note",
265 "url": f"{TEST_BASE_URL}/@{TEST_USER}/4" 235 "url": f"{TEST_BASE_URL}/@{TEST_USER}/4",
266 }, 236 },
267 "published": "2021-12-16T17:25:03Z", 237 "published": "2021-12-16T17:25:03Z",
268 "to": [ 238 "to": ["https://www.w3.org/ns/activitystreams#Public"],
269 "https://www.w3.org/ns/activitystreams#Public" 239 "type": "Create",
270 ],
271 "type": "Create"
272 }, 240 },
273 ], 241 ],
274 "partOf": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", 242 "partOf": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox",
275 "prev": None, 243 "prev": None,
276 "type": "OrderedCollectionPage" 244 "type": "OrderedCollectionPage",
277 }, 245 },
278 f"{TEST_BASE_URL}/users/{TEST_USER}/following": { 246 f"{TEST_BASE_URL}/users/{TEST_USER}/following": {
279 "@context": "https://www.w3.org/ns/activitystreams", 247 "@context": "https://www.w3.org/ns/activitystreams",
280 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1", 248 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1",
281 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/following", 249 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/following",
282 "totalItems": 2, 250 "totalItems": 2,
283 "type": "OrderedCollection" 251 "type": "OrderedCollection",
284 }, 252 },
285 f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1": { 253 f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1": {
286 "@context": "https://www.w3.org/ns/activitystreams", 254 "@context": "https://www.w3.org/ns/activitystreams",
287 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1", 255 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1",
288 "orderedItems": [ 256 "orderedItems": [
289 f"{TEST_BASE_URL}/users/ext_user", 257 f"{TEST_BASE_URL}/users/ext_user",
290 f"https://{PUBLIC_URL}/_ap/{TYPE_ACTOR}/local_user%40{PUBLIC_URL}", 258 f"https://{PUBLIC_URL}/_ap/{TYPE_ACTOR}/local_user%40{PUBLIC_URL}",
291 ], 259 ],
292 "partOf": "{TEST_BASE_URL}/users/{TEST_USER}/following", 260 "partOf": "{TEST_BASE_URL}/users/{TEST_USER}/following",
293 "totalItems": 2, 261 "totalItems": 2,
294 "type": "OrderedCollectionPage" 262 "type": "OrderedCollectionPage",
295 }, 263 },
296 f"{TEST_BASE_URL}/users/{TEST_USER}/followers": { 264 f"{TEST_BASE_URL}/users/{TEST_USER}/followers": {
297 "@context": "https://www.w3.org/ns/activitystreams", 265 "@context": "https://www.w3.org/ns/activitystreams",
298 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1", 266 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1",
299 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/followers", 267 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/followers",
300 "totalItems": 2, 268 "totalItems": 2,
301 "type": "OrderedCollection" 269 "type": "OrderedCollection",
302 }, 270 },
303 f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1": { 271 f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1": {
304 "@context": "https://www.w3.org/ns/activitystreams", 272 "@context": "https://www.w3.org/ns/activitystreams",
305 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1", 273 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1",
306 "orderedItems": [ 274 "orderedItems": [
307 f"{TEST_BASE_URL}/users/ext_user", 275 f"{TEST_BASE_URL}/users/ext_user",
308 f"https://{PUBLIC_URL}/_ap/{TYPE_ACTOR}/local_user%40{PUBLIC_URL}", 276 f"https://{PUBLIC_URL}/_ap/{TYPE_ACTOR}/local_user%40{PUBLIC_URL}",
309 ], 277 ],
310 "partOf": "{TEST_BASE_URL}/users/{TEST_USER}/followers", 278 "partOf": "{TEST_BASE_URL}/users/{TEST_USER}/followers",
311 "totalItems": 2, 279 "totalItems": 2,
312 "type": "OrderedCollectionPage" 280 "type": "OrderedCollectionPage",
313 }, 281 },
314
315 } 282 }
316 283
317 XMPP_ITEM_TPL = """ 284 XMPP_ITEM_TPL = """
318 <item id='{id}' publisher='{publisher_jid}'> 285 <item id='{id}' publisher='{publisher_jid}'>
319 <entry xmlns='http://www.w3.org/2005/Atom' xml:lang='en'> 286 <entry xmlns='http://www.w3.org/2005/Atom' xml:lang='en'>
350 317
351 ITEM_BASE_TS = 1643385499 318 ITEM_BASE_TS = 1643385499
352 XMPP_ITEMS = [ 319 XMPP_ITEMS = [
353 xml_tools.parse( 320 xml_tools.parse(
354 "".join( 321 "".join(
355 l.strip() for l in XMPP_ITEM_TPL.format( 322 l.strip()
323 for l in XMPP_ITEM_TPL.format(
356 id=i, 324 id=i,
357 publisher_jid="some_user@test.example", 325 publisher_jid="some_user@test.example",
358 updated=xmpp_date(ITEM_BASE_TS + i * 60), 326 updated=xmpp_date(ITEM_BASE_TS + i * 60),
359 published=xmpp_date(ITEM_BASE_TS + i * 60), 327 published=xmpp_date(ITEM_BASE_TS + i * 60),
360 ).split("\n") 328 ).split("\n")
361 ), 329 ),
362 namespace=pubsub.NS_PUBSUB 330 namespace=pubsub.NS_PUBSUB,
363 ) 331 )
364 for i in range(1, 5) 332 for i in range(1, 5)
365 ] 333 ]
366 334
367 TEST_USER_DATA = AP_REQUESTS[f"{TEST_BASE_URL}/users/{TEST_USER}"] 335 TEST_USER_DATA = AP_REQUESTS[f"{TEST_BASE_URL}/users/{TEST_USER}"]
392 tested_node = kwargs.pop("tested_node", None) 360 tested_node = kwargs.pop("tested_node", None)
393 if tested_node is not None and node != tested_node: 361 if tested_node is not None and node != tested_node:
394 raise StanzaError("item-not-found") 362 raise StanzaError("item-not-found")
395 ret_items = kwargs.pop("ret_items", XMPP_ITEMS) 363 ret_items = kwargs.pop("ret_items", XMPP_ITEMS)
396 rsm_resp = rsm.RSMResponse( 364 rsm_resp = rsm.RSMResponse(
397 first=ret_items[0]["id"], 365 first=ret_items[0]["id"], last=ret_items[-1]["id"], index=0, count=len(ret_items)
398 last=ret_items[-1]["id"],
399 index=0,
400 count=len(ret_items)
401 ) 366 )
402 return ret_items, {"rsm": rsm_resp.toDict(), "complete": True} 367 return ret_items, {"rsm": rsm_resp.toDict(), "complete": True}
403 368
404 369
405 async def mock_getPubsubNode(client, service, node, with_subscriptions=False, **kwargs): 370 async def mock_getPubsubNode(client, service, node, with_subscriptions=False, **kwargs):
438 client = mockClient(jid.JID("ap.test.example")) 403 client = mockClient(jid.JID("ap.test.example"))
439 client.getVirtualClient = getVirtualClient 404 client.getVirtualClient = getVirtualClient
440 gateway.client = client 405 gateway.client = client
441 gateway.local_only = True 406 gateway.local_only = True
442 gateway.public_url = PUBLIC_URL 407 gateway.public_url = PUBLIC_URL
443 gateway.ap_path = '_ap' 408 gateway.ap_path = "_ap"
444 gateway.auto_mentions = True 409 gateway.auto_mentions = True
445 gateway.base_ap_url = parse.urljoin( 410 gateway.base_ap_url = parse.urljoin(
446 f"https://{gateway.public_url}", 411 f"https://{gateway.public_url}", f"{gateway.ap_path}/"
447 f"{gateway.ap_path}/"
448 ) 412 )
449 gateway.server = HTTPServer(gateway) 413 gateway.server = HTTPServer(gateway)
450 gateway.public_key_pem = None 414 gateway.public_key_pem = None
451 return gateway 415 return gateway
452 416
453 417
454 class TestActivityPubGateway: 418 class TestActivityPubGateway:
455
456 def getTitleXHTML(self, item_elt: domish.Element) -> domish.Element: 419 def getTitleXHTML(self, item_elt: domish.Element) -> domish.Element:
457 return next( 420 return next(
458 t for t in item_elt.entry.elements(NS_ATOM, "title") 421 t
422 for t in item_elt.entry.elements(NS_ATOM, "title")
459 if t.getAttribute("type") == "xhtml" 423 if t.getAttribute("type") == "xhtml"
460 ) 424 )
461
462 425
463 @ed 426 @ed
464 async def test_jid_and_node_convert_to_ap_handle(self, ap_gateway): 427 async def test_jid_and_node_convert_to_ap_handle(self, ap_gateway):
465 """JID and pubsub node are converted correctly to an AP actor handle""" 428 """JID and pubsub node are converted correctly to an AP actor handle"""
466 get_account = ap_gateway.getAPAccountFromJidAndNode 429 get_account = ap_gateway.getAPAccountFromJidAndNode
467 430
468 # local jid 431 # local jid
469 assert await get_account( 432 assert (
470 jid_ = jid.JID("simple@test.example"), 433 await get_account(jid_=jid.JID("simple@test.example"), node=None)
471 node = None 434 == "simple@test.example"
472 ) == "simple@test.example" 435 )
473 436
474 # non local jid 437 # non local jid
475 assert await get_account( 438 assert (
476 jid_ = jid.JID("simple@example.org"), 439 await get_account(jid_=jid.JID("simple@example.org"), node=None)
477 node = None 440 == "___simple.40example.2eorg@ap.test.example"
478 ) == "___simple.40example.2eorg@ap.test.example" 441 )
479 442
480 # local jid with non microblog node 443 # local jid with non microblog node
481 assert await get_account( 444 assert (
482 jid_ = jid.JID("simple@test.example"), 445 await get_account(jid_=jid.JID("simple@test.example"), node="some_other_node")
483 node = "some_other_node" 446 == "some_other_node---simple@test.example"
484 ) == "some_other_node---simple@test.example" 447 )
485 448
486 # local pubsub node 449 # local pubsub node
487 with patch.object(ap_gateway, "isPubsub") as isPubsub: 450 with patch.object(ap_gateway, "isPubsub") as isPubsub:
488 isPubsub.return_value = True 451 isPubsub.return_value = True
489 assert await get_account( 452 assert (
490 jid_ = jid.JID("pubsub.test.example"), 453 await get_account(jid_=jid.JID("pubsub.test.example"), node="some_node")
491 node = "some_node" 454 == "some_node@pubsub.test.example"
492 ) == "some_node@pubsub.test.example" 455 )
493 456
494 # non local pubsub node 457 # non local pubsub node
495 with patch.object(ap_gateway, "isPubsub") as isPubsub: 458 with patch.object(ap_gateway, "isPubsub") as isPubsub:
496 isPubsub.return_value = True 459 isPubsub.return_value = True
497 assert await get_account( 460 assert (
498 jid_ = jid.JID("pubsub.example.org"), 461 await get_account(jid_=jid.JID("pubsub.example.org"), node="some_node")
499 node = "some_node" 462 == "___some_node.40pubsub.2eexample.2eorg@ap.test.example"
500 ) == "___some_node.40pubsub.2eexample.2eorg@ap.test.example" 463 )
501 464
502 @ed 465 @ed
503 async def test_ap_handle_convert_to_jid_and_node(self, ap_gateway, monkeypatch): 466 async def test_ap_handle_convert_to_jid_and_node(self, ap_gateway, monkeypatch):
504 """AP actor handle convert correctly to JID and pubsub node""" 467 """AP actor handle convert correctly to JID and pubsub node"""
505 get_jid_node = ap_gateway.getJIDAndNode 468 get_jid_node = ap_gateway.getJIDAndNode
507 # for following assertion, host is not a pubsub service 470 # for following assertion, host is not a pubsub service
508 with patch.object(ap_gateway, "isPubsub") as isPubsub: 471 with patch.object(ap_gateway, "isPubsub") as isPubsub:
509 isPubsub.return_value = False 472 isPubsub.return_value = False
510 473
511 # simple local jid 474 # simple local jid
512 assert await get_jid_node( 475 assert await get_jid_node("toto@test.example") == (
513 "toto@test.example" 476 jid.JID("toto@test.example"),
514 ) == (jid.JID("toto@test.example"), None) 477 None,
478 )
515 479
516 # simple external jid 480 # simple external jid
517 481
518 ## with "local_only" set, it should raise an exception 482 ## with "local_only" set, it should raise an exception
519 with pytest.raises(exceptions.PermissionError): 483 with pytest.raises(exceptions.PermissionError):
520 await get_jid_node("toto@example.org") 484 await get_jid_node("toto@example.org")
521 485
522 ## with "local_only" unset, it should work 486 ## with "local_only" unset, it should work
523 with monkeypatch.context() as m: 487 with monkeypatch.context() as m:
524 m.setattr(ap_gateway, "local_only", False, raising=True) 488 m.setattr(ap_gateway, "local_only", False, raising=True)
525 assert await get_jid_node( 489 assert await get_jid_node("toto@example.org") == (
526 "toto@example.org" 490 jid.JID("toto@example.org"),
527 ) == (jid.JID("toto@example.org"), None) 491 None,
492 )
528 493
529 # explicit node 494 # explicit node
530 assert await get_jid_node( 495 assert await get_jid_node("tata---toto@test.example") == (
531 "tata---toto@test.example" 496 jid.JID("toto@test.example"),
532 ) == (jid.JID("toto@test.example"), "tata") 497 "tata",
498 )
533 499
534 # for following assertion, host is a pubsub service 500 # for following assertion, host is a pubsub service
535 with patch.object(ap_gateway, "isPubsub") as isPubsub: 501 with patch.object(ap_gateway, "isPubsub") as isPubsub:
536 isPubsub.return_value = True 502 isPubsub.return_value = True
537 503
538 # simple local node 504 # simple local node
539 assert await get_jid_node( 505 assert await get_jid_node("toto@pubsub.test.example") == (
540 "toto@pubsub.test.example" 506 jid.JID("pubsub.test.example"),
541 ) == (jid.JID("pubsub.test.example"), "toto") 507 "toto",
508 )
542 509
543 # encoded local node 510 # encoded local node
544 assert await get_jid_node( 511 assert await get_jid_node(
545 "___urn.3axmpp.3amicroblog.3a0@pubsub.test.example" 512 "___urn.3axmpp.3amicroblog.3a0@pubsub.test.example"
546 ) == (jid.JID("pubsub.test.example"), "urn:xmpp:microblog:0") 513 ) == (jid.JID("pubsub.test.example"), "urn:xmpp:microblog:0")
618 [e for e in items[1].entry.author.elements() if e.name == "uri"][0] 585 [e for e in items[1].entry.author.elements() if e.name == "uri"][0]
619 ) 586 )
620 assert author_uri == "xmpp:test_user\\40example.org@ap.test.example" 587 assert author_uri == "xmpp:test_user\\40example.org@ap.test.example"
621 assert str(items[1].entry.published) == "2021-12-16T17:28:03Z" 588 assert str(items[1].entry.published) == "2021-12-16T17:28:03Z"
622 589
623 items, rsm_resp = await ap_gateway.getAPItems( 590 items, rsm_resp = await ap_gateway.getAPItems(outbox, max_items=1, start_index=2)
624 outbox,
625 max_items=1,
626 start_index=2
627 )
628 591
629 assert rsm_resp.count == 4 592 assert rsm_resp.count == 4
630 assert rsm_resp.index == 2 593 assert rsm_resp.index == 2
631 assert rsm_resp.first == "https://example.org/users/test_user/statuses/2" 594 assert rsm_resp.first == "https://example.org/users/test_user/statuses/2"
632 assert rsm_resp.last == "https://example.org/users/test_user/statuses/2" 595 assert rsm_resp.last == "https://example.org/users/test_user/statuses/2"
639 "</title>" 602 "</title>"
640 ) 603 )
641 assert str(items[0].entry.published) == "2021-12-16T17:27:03Z" 604 assert str(items[0].entry.published) == "2021-12-16T17:27:03Z"
642 605
643 items, rsm_resp = await ap_gateway.getAPItems( 606 items, rsm_resp = await ap_gateway.getAPItems(
644 outbox, 607 outbox, max_items=3, chronological_pagination=False
645 max_items=3,
646 chronological_pagination=False
647 ) 608 )
648 assert rsm_resp.count == 4 609 assert rsm_resp.count == 4
649 assert rsm_resp.index == 1 610 assert rsm_resp.index == 1
650 assert rsm_resp.first == "https://example.org/users/test_user/statuses/3" 611 assert rsm_resp.first == "https://example.org/users/test_user/statuses/3"
651 assert rsm_resp.last == "https://example.org/users/test_user/statuses/1" 612 assert rsm_resp.last == "https://example.org/users/test_user/statuses/1"
668 ap_gateway, 629 ap_gateway,
669 type_: Optional[str] = None, 630 type_: Optional[str] = None,
670 url: Optional[str] = None, 631 url: Optional[str] = None,
671 doc: Optional[Any] = None, 632 doc: Optional[Any] = None,
672 query_data: Optional[dict] = None, 633 query_data: Optional[dict] = None,
673 signing_actor: Optional[str] = None 634 signing_actor: Optional[str] = None,
674 ) -> Dict[str, Any]: 635 ) -> Dict[str, Any]:
675 """Generate parameters for HTTPAPGServer's AP*Request 636 """Generate parameters for HTTPAPGServer's AP*Request
676 637
677 @param type_: one of the AP query type (e.g. "outbox") 638 @param type_: one of the AP query type (e.g. "outbox")
678 @param url: URL to query (mutually exclusif with type_) 639 @param url: URL to query (mutually exclusif with type_)
701 request.path = path.encode() 662 request.path = path.encode()
702 request.uri = uri.encode() 663 request.uri = uri.encode()
703 if doc is not None: 664 if doc is not None:
704 request.content = io.BytesIO(json.dumps(doc).encode()) 665 request.content = io.BytesIO(json.dumps(doc).encode())
705 666
706 ap_url = parse.urljoin( 667 ap_url = parse.urljoin(f"https://{ap_gateway.public_url}", path)
707 f"https://{ap_gateway.public_url}",
708 path
709 )
710 kwargs = { 668 kwargs = {
711 "request": request, 669 "request": request,
712 "account_jid": test_jid, 670 "account_jid": test_jid,
713 "node": None, 671 "node": None,
714 "ap_account": test_jid.full(), 672 "ap_account": test_jid.full(),
715 "ap_url": ap_url, 673 "ap_url": ap_url,
716 "signing_actor": signing_actor 674 "signing_actor": signing_actor,
717 } 675 }
718 if type_ == "outbox" and query_data: 676 if type_ == "outbox" and query_data:
719 kwargs["query_data"] = query_data 677 kwargs["query_data"] = query_data
720 # signing_actor is not used for page requests 678 # signing_actor is not used for page requests
721 del kwargs["signing_actor"] 679 del kwargs["signing_actor"]
726 """Pubsub nodes are converted to AP collections""" 684 """Pubsub nodes are converted to AP collections"""
727 monkeypatch.setattr(ap_gateway._p, "getItems", mock_getItems) 685 monkeypatch.setattr(ap_gateway._p, "getItems", mock_getItems)
728 outbox = await ap_gateway.server.resource.APOutboxRequest( 686 outbox = await ap_gateway.server.resource.APOutboxRequest(
729 **self.ap_request_params(ap_gateway, "outbox") 687 **self.ap_request_params(ap_gateway, "outbox")
730 ) 688 )
731 assert outbox["@context"] == "https://www.w3.org/ns/activitystreams" 689 assert outbox["@context"] == ["https://www.w3.org/ns/activitystreams"]
732 assert outbox["id"] == "https://test.example/_ap/outbox/some_user%40test.example" 690 assert outbox["id"] == "https://test.example/_ap/outbox/some_user%40test.example"
733 assert outbox["totalItems"] == len(XMPP_ITEMS) 691 assert outbox["totalItems"] == len(XMPP_ITEMS)
734 assert outbox["type"] == "OrderedCollection" 692 assert outbox["type"] == "OrderedCollection"
735 assert outbox["first"] 693 assert outbox["first"]
736 assert outbox["last"] 694 assert outbox["last"]
737 695
738 first_page = await ap_gateway.server.resource.APOutboxPageRequest( 696 first_page = await ap_gateway.server.resource.APOutboxPageRequest(
739 **self.ap_request_params(ap_gateway, url=outbox["first"]) 697 **self.ap_request_params(ap_gateway, url=outbox["first"])
740 ) 698 )
741 assert first_page["@context"] == "https://www.w3.org/ns/activitystreams" 699 assert first_page["@context"] == ["https://www.w3.org/ns/activitystreams"]
742 assert first_page["id"] == "https://test.example/_ap/outbox/some_user%40test.example?page=first" 700 assert (
701 first_page["id"]
702 == "https://test.example/_ap/outbox/some_user%40test.example?page=first"
703 )
743 assert first_page["type"] == "OrderedCollectionPage" 704 assert first_page["type"] == "OrderedCollectionPage"
744 assert first_page["partOf"] == outbox["id"] 705 assert first_page["partOf"] == outbox["id"]
745 assert len(first_page["orderedItems"]) == len(XMPP_ITEMS) 706 assert len(first_page["orderedItems"]) == len(XMPP_ITEMS)
746 first_item = first_page["orderedItems"][0] 707 first_item = first_page["orderedItems"][0]
747 assert first_item["@context"] == "https://www.w3.org/ns/activitystreams" 708 assert first_item["@context"] == ["https://www.w3.org/ns/activitystreams"]
748 assert first_item["id"] == "https://test.example/_ap/item/some_user%40test.example/4" 709 assert (
749 assert first_item["actor"] == "https://test.example/_ap/actor/some_user%40test.example" 710 first_item["id"] == "https://test.example/_ap/item/some_user%40test.example/4"
711 )
712 assert (
713 first_item["actor"]
714 == "https://test.example/_ap/actor/some_user%40test.example"
715 )
750 assert first_item["type"] == "Create" 716 assert first_item["type"] == "Create"
751 first_item_obj = first_item["object"] 717 first_item_obj = first_item["object"]
752 assert first_item_obj["id"] == first_item["id"] 718 assert first_item_obj["id"] == first_item["id"]
753 assert first_item_obj["type"] == "Note" 719 assert first_item_obj["type"] == "Note"
754 assert first_item_obj["published"] == "2022-01-28T16:02:19Z" 720 assert first_item_obj["published"] == "2022-01-28T16:02:19Z"
767 jid.JID("toto@example.org"), 733 jid.JID("toto@example.org"),
768 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), 734 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT),
769 ap_gateway._pps.subscriptions_node, 735 ap_gateway._pps.subscriptions_node,
770 None, 736 None,
771 None, 737 None,
772 None 738 None,
773 ) 739 )
774 assert len(items) == 2 740 assert len(items) == 2
775 for idx, entity in enumerate(( 741 for idx, entity in enumerate(
776 "local_user@test.example", 742 ("local_user@test.example", "ext_user\\40example.org@ap.test.example")
777 "ext_user\\40example.org@ap.test.example" 743 ):
778 )):
779 subscription_elt = next(items[idx].elements(NS_PPS, "subscription"), None) 744 subscription_elt = next(items[idx].elements(NS_PPS, "subscription"), None)
780 assert subscription_elt is not None 745 assert subscription_elt is not None
781 assert subscription_elt["node"] == ap_gateway._m.namespace 746 assert subscription_elt["node"] == ap_gateway._m.namespace
782 assert subscription_elt["service"] == entity 747 assert subscription_elt["service"] == entity
783 748
792 jid.JID("toto@example.org"), 757 jid.JID("toto@example.org"),
793 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), 758 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT),
794 ap_gateway._pps.getPublicSubscribersNode(ap_gateway._m.namespace), 759 ap_gateway._pps.getPublicSubscribersNode(ap_gateway._m.namespace),
795 None, 760 None,
796 None, 761 None,
797 None 762 None,
798 ) 763 )
799 assert len(items) == 2 764 assert len(items) == 2
800 for idx, entity in enumerate(( 765 for idx, entity in enumerate(
801 "local_user@test.example", 766 ("local_user@test.example", "ext_user\\40example.org@ap.test.example")
802 "ext_user\\40example.org@ap.test.example" 767 ):
803 )):
804 subscriber_elt = next(items[idx].elements(NS_PPS, "subscriber"), None) 768 subscriber_elt = next(items[idx].elements(NS_PPS, "subscriber"), None)
805 assert subscriber_elt is not None 769 assert subscriber_elt is not None
806 assert subscriber_elt["jid"] == entity 770 assert subscriber_elt["jid"] == entity
807 771
808 @ed 772 @ed
809 async def test_pps_to_following(self, ap_gateway, monkeypatch): 773 async def test_pps_to_following(self, ap_gateway, monkeypatch):
810 """Public Pubsub Subscription subscriptions are converted to AP following items""" 774 """Public Pubsub Subscription subscriptions are converted to AP following items"""
811 subscriptions = [ 775 subscriptions = [
812 pubsub.Item( 776 pubsub.Item(
813 id="subscription_1", 777 id="subscription_1",
814 payload = ap_gateway._pps.buildSubscriptionElt( 778 payload=ap_gateway._pps.buildSubscriptionElt(
815 ap_gateway._m.namespace, 779 ap_gateway._m.namespace, jid.JID("local_user@test.example")
816 jid.JID("local_user@test.example") 780 ),
817 )
818 ), 781 ),
819 pubsub.Item( 782 pubsub.Item(
820 id="subscription_2", 783 id="subscription_2",
821 payload = ap_gateway._pps.buildSubscriptionElt( 784 payload=ap_gateway._pps.buildSubscriptionElt(
822 ap_gateway._m.namespace, 785 ap_gateway._m.namespace,
823 jid.JID("ext_user\\40example.org@ap.test.example") 786 jid.JID("ext_user\\40example.org@ap.test.example"),
824 ) 787 ),
825 ) 788 ),
826 ] 789 ]
827 monkeypatch.setattr(ap_gateway._p, "getItems", partial( 790 monkeypatch.setattr(
828 mock_getItems, 791 ap_gateway._p, "getItems", partial(mock_getItems, ret_items=subscriptions)
829 ret_items=subscriptions 792 )
830 ))
831 following = await ap_gateway.server.resource.APFollowingRequest( 793 following = await ap_gateway.server.resource.APFollowingRequest(
832 **self.ap_request_params(ap_gateway, "following") 794 **self.ap_request_params(ap_gateway, "following")
833 ) 795 )
834 assert following["@context"] == "https://www.w3.org/ns/activitystreams" 796 assert following["@context"] == ["https://www.w3.org/ns/activitystreams"]
835 assert following["id"] == "https://test.example/_ap/following/some_user%40test.example" 797 assert (
798 following["id"]
799 == "https://test.example/_ap/following/some_user%40test.example"
800 )
836 assert following["totalItems"] == len(subscriptions) 801 assert following["totalItems"] == len(subscriptions)
837 assert following["type"] == "OrderedCollection" 802 assert following["type"] == "OrderedCollection"
838 assert following.get("first") 803 assert following.get("first")
839 804
840 first_page = following["first"] 805 first_page = following["first"]
841 assert first_page["type"] == "OrderedCollectionPage" 806 assert first_page["type"] == "OrderedCollectionPage"
842 assert len(first_page["orderedItems"]) == len(subscriptions) 807 assert len(first_page["orderedItems"]) == len(subscriptions)
843 items = first_page["orderedItems"] 808 items = first_page["orderedItems"]
844 assert items == ['local_user@test.example', 'ext_user@example.org'] 809 assert items == ["local_user@test.example", "ext_user@example.org"]
845 810
846 @ed 811 @ed
847 async def test_pps_to_followers(self, ap_gateway, monkeypatch): 812 async def test_pps_to_followers(self, ap_gateway, monkeypatch):
848 """Public Pubsub Subscription subscribers are converted to AP followers""" 813 """Public Pubsub Subscription subscribers are converted to AP followers"""
849 subscribers = [ 814 subscribers = [
850 pubsub.Item( 815 pubsub.Item(
851 id="subscriber_1", 816 id="subscriber_1",
852 payload = ap_gateway._pps.buildSubscriberElt( 817 payload=ap_gateway._pps.buildSubscriberElt(
853 jid.JID("local_user@test.example") 818 jid.JID("local_user@test.example")
854 ) 819 ),
855 ), 820 ),
856 pubsub.Item( 821 pubsub.Item(
857 id="subscriber_2", 822 id="subscriber_2",
858 payload = ap_gateway._pps.buildSubscriberElt( 823 payload=ap_gateway._pps.buildSubscriberElt(
859 jid.JID("ext_user\\40example.org@ap.test.example") 824 jid.JID("ext_user\\40example.org@ap.test.example")
860 ) 825 ),
861 ) 826 ),
862 ] 827 ]
863 monkeypatch.setattr(ap_gateway._p, "getItems", partial( 828 monkeypatch.setattr(
864 mock_getItems, 829 ap_gateway._p, "getItems", partial(mock_getItems, ret_items=subscribers)
865 ret_items=subscribers 830 )
866 ))
867 followers = await ap_gateway.server.resource.APFollowersRequest( 831 followers = await ap_gateway.server.resource.APFollowersRequest(
868 **self.ap_request_params(ap_gateway, "followers") 832 **self.ap_request_params(ap_gateway, "followers")
869 ) 833 )
870 assert followers["@context"] == "https://www.w3.org/ns/activitystreams" 834 assert followers["@context"] == ["https://www.w3.org/ns/activitystreams"]
871 assert followers["id"] == "https://test.example/_ap/followers/some_user%40test.example" 835 assert (
836 followers["id"]
837 == "https://test.example/_ap/followers/some_user%40test.example"
838 )
872 assert followers["totalItems"] == len(subscribers) 839 assert followers["totalItems"] == len(subscribers)
873 assert followers["type"] == "OrderedCollection" 840 assert followers["type"] == "OrderedCollection"
874 assert followers.get("first") 841 assert followers.get("first")
875 842
876 first_page = followers["first"] 843 first_page = followers["first"]
877 assert first_page["type"] == "OrderedCollectionPage" 844 assert first_page["type"] == "OrderedCollectionPage"
878 assert len(first_page["orderedItems"]) == len(subscribers) 845 assert len(first_page["orderedItems"]) == len(subscribers)
879 items = first_page["orderedItems"] 846 items = first_page["orderedItems"]
880 assert items == ['local_user@test.example', 'ext_user@example.org'] 847 assert items == ["local_user@test.example", "ext_user@example.org"]
881 848
882 @ed 849 @ed
883 async def test_xmpp_message_to_ap_direct_message(self, ap_gateway, monkeypatch): 850 async def test_xmpp_message_to_ap_direct_message(self, ap_gateway, monkeypatch):
884 """XMPP message are sent as AP direct message""" 851 """XMPP message are sent as AP direct message"""
885 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get) 852 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
888 mess_data = { 855 mess_data = {
889 "from": TEST_JID, 856 "from": TEST_JID,
890 "to": ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), 857 "to": ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT),
891 "type": "chat", 858 "type": "chat",
892 "message": {"": "This is a test message."}, 859 "message": {"": "This is a test message."},
893 "extra": { 860 "extra": {"origin-id": "123"},
894 "origin-id": "123"
895 }
896 } 861 }
897 with patch.object(ap_gateway, "signAndPost") as signAndPost: 862 with patch.object(ap_gateway, "signAndPost") as signAndPost:
898 await ap_gateway.onMessage(ap_gateway.client, mess_data) 863 await ap_gateway.onMessage(ap_gateway.client, mess_data)
899 url, actor_id, doc = signAndPost.call_args[0] 864 url, actor_id, doc = signAndPost.call_args[0]
900 assert url == "https://example.org/users/test_user/inbox" 865 assert url == "https://example.org/users/test_user/inbox"
901 assert actor_id == "https://test.example/_ap/actor/some_user%40test.example" 866 assert actor_id == "https://test.example/_ap/actor/some_user%40test.example"
902 obj = doc["object"] 867 obj = doc["object"]
903 assert doc["@context"] == "https://www.w3.org/ns/activitystreams" 868 assert doc["@context"] == ["https://www.w3.org/ns/activitystreams"]
904 assert doc["actor"] == "https://test.example/_ap/actor/some_user%40test.example" 869 assert doc["actor"] == "https://test.example/_ap/actor/some_user%40test.example"
905 assert obj["type"] == "Note" 870 assert obj["type"] == "Note"
906 assert obj["content"] == "This is a test message." 871 assert obj["content"] == "This is a test message."
907 assert obj["attributedTo"] == ( 872 assert obj["attributedTo"] == (
908 "https://test.example/_ap/actor/some_user%40test.example" 873 "https://test.example/_ap/actor/some_user%40test.example"
924 # we have to patch DeferredList to not wait forever 889 # we have to patch DeferredList to not wait forever
925 monkeypatch.setattr(defer, "DeferredList", AsyncMock()) 890 monkeypatch.setattr(defer, "DeferredList", AsyncMock())
926 891
927 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) 892 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
928 direct_ap_message = { 893 direct_ap_message = {
929 'attributedTo': TEST_AP_ACTOR_ID, 894 "attributedTo": TEST_AP_ACTOR_ID,
930 'cc': [], 895 "cc": [],
931 'content': '<p>test direct message</p>', 896 "content": "<p>test direct message</p>",
932 'contentMap': {'en': '<p>test direct message</p>'}, 897 "contentMap": {"en": "<p>test direct message</p>"},
933 'id': f'{TEST_AP_ACTOR_ID}/statuses/123', 898 "id": f"{TEST_AP_ACTOR_ID}/statuses/123",
934 'published': '2022-05-20T08:14:39Z', 899 "published": "2022-05-20T08:14:39Z",
935 'to': [xmpp_actor_id], 900 "to": [xmpp_actor_id],
936 'type': 'Note', 901 "type": "Note",
937 } 902 }
938 client = ap_gateway.client.getVirtualClient( 903 client = ap_gateway.client.getVirtualClient(
939 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) 904 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
940 ) 905 )
941 with patch.object(client, "sendMessage") as sendMessage: 906 with patch.object(client, "sendMessage") as sendMessage:
961 items_event = pubsub.ItemsEvent( 926 items_event = pubsub.ItemsEvent(
962 sender=TEST_JID, 927 sender=TEST_JID,
963 recipient=ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), 928 recipient=ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT),
964 nodeIdentifier=ap_gateway._m.namespace, 929 nodeIdentifier=ap_gateway._m.namespace,
965 items=[retract_elt], 930 items=[retract_elt],
966 headers={} 931 headers={},
967 ) 932 )
968 with patch.object(ap_gateway, "signAndPost") as signAndPost: 933 with patch.object(ap_gateway, "signAndPost") as signAndPost:
969 signAndPost.return_value = FakeTReqPostResponse() 934 signAndPost.return_value = FakeTReqPostResponse()
970 # we simulate the reception of a retract event 935 # we simulate the reception of a retract event
971 await ap_gateway._itemsReceived(ap_gateway.client, items_event) 936 await ap_gateway._itemsReceived(ap_gateway.client, items_event)
991 ap_item = { 956 ap_item = {
992 "@context": "https://www.w3.org/ns/activitystreams", 957 "@context": "https://www.w3.org/ns/activitystreams",
993 "actor": TEST_AP_ACTOR_ID, 958 "actor": TEST_AP_ACTOR_ID,
994 "id": "https://test.example/retract_123", 959 "id": "https://test.example/retract_123",
995 "type": "Delete", 960 "type": "Delete",
996 "object": {"id": f"{TEST_AP_ACTOR_ID}/item/123", 961 "object": {"id": f"{TEST_AP_ACTOR_ID}/item/123", "type": "Tombstone"},
997 "type": "Tombstone"}, 962 "to": ["https://www.w3.org/ns/activitystreams#Public"],
998 "to": ["https://www.w3.org/ns/activitystreams#Public"]
999 } 963 }
1000 with patch.multiple( 964 with patch.multiple(
1001 ap_gateway.host.memory.storage, 965 ap_gateway.host.memory.storage,
1002 get=DEFAULT, 966 get=DEFAULT,
1003 getPubsubNode=DEFAULT, 967 getPubsubNode=DEFAULT,
1004 deletePubsubItems=DEFAULT, 968 deletePubsubItems=DEFAULT,
1005 ) as mock_objs: 969 ) as mock_objs:
1006 mock_objs["get"].return_value=None 970 mock_objs["get"].return_value = None
1007 cached_node = MagicMock() 971 cached_node = MagicMock()
1008 mock_objs["getPubsubNode"].return_value=cached_node 972 mock_objs["getPubsubNode"].return_value = cached_node
1009 subscription = MagicMock() 973 subscription = MagicMock()
1010 subscription.state = SubscriptionState.SUBSCRIBED 974 subscription.state = SubscriptionState.SUBSCRIBED
1011 subscription.subscriber = TEST_JID 975 subscription.subscriber = TEST_JID
1012 cached_node.subscriptions = [subscription] 976 cached_node.subscriptions = [subscription]
1013 with patch.object( 977 with patch.object(
1016 # we simulate a received Delete activity 980 # we simulate a received Delete activity
1017 await ap_gateway.newAPDeleteItem( 981 await ap_gateway.newAPDeleteItem(
1018 client=client, 982 client=client,
1019 destinee=None, 983 destinee=None,
1020 node=ap_gateway._m.namespace, 984 node=ap_gateway._m.namespace,
1021 item=ap_item 985 item=ap_item,
1022 ) 986 )
1023 987
1024 # item is deleted from database 988 # item is deleted from database
1025 deletePubsubItems = mock_objs["deletePubsubItems"] 989 deletePubsubItems = mock_objs["deletePubsubItems"]
1026 assert deletePubsubItems.call_count == 1 990 assert deletePubsubItems.call_count == 1
1064 fake_fastened_elts = MagicMock() 1028 fake_fastened_elts = MagicMock()
1065 fake_fastened_elts.id = origin_id 1029 fake_fastened_elts.id = origin_id
1066 # we simulate the reception of a retract event using the message element that 1030 # we simulate the reception of a retract event using the message element that
1067 # we generated above 1031 # we generated above
1068 await ap_gateway._onMessageRetract( 1032 await ap_gateway._onMessageRetract(
1069 ap_gateway.client, 1033 ap_gateway.client, message_retract_elt, retract_elt, fake_fastened_elts
1070 message_retract_elt,
1071 retract_elt,
1072 fake_fastened_elts
1073 ) 1034 )
1074 url, actor_id, doc = signAndPost.call_args[0] 1035 url, actor_id, doc = signAndPost.call_args[0]
1075 1036
1076 # the AP delete activity must have been sent through signAndPost 1037 # the AP delete activity must have been sent through signAndPost
1077 # we check its values 1038 # we check its values
1106 ap_item = { 1067 ap_item = {
1107 "@context": "https://www.w3.org/ns/activitystreams", 1068 "@context": "https://www.w3.org/ns/activitystreams",
1108 "actor": TEST_AP_ACTOR_ID, 1069 "actor": TEST_AP_ACTOR_ID,
1109 "id": "https://test.example/retract_123", 1070 "id": "https://test.example/retract_123",
1110 "type": "Delete", 1071 "type": "Delete",
1111 "object": {"id": f"{TEST_AP_ACTOR_ID}/item/123", 1072 "object": {"id": f"{TEST_AP_ACTOR_ID}/item/123", "type": "Tombstone"},
1112 "type": "Tombstone"}, 1073 "to": ["https://www.w3.org/ns/activitystreams#Public"],
1113 "to": ["https://www.w3.org/ns/activitystreams#Public"]
1114 } 1074 }
1115 with patch.object(ap_gateway.host.memory.storage, "get") as storage_get: 1075 with patch.object(ap_gateway.host.memory.storage, "get") as storage_get:
1116 fake_history = MagicMock() 1076 fake_history = MagicMock()
1117 fake_history.source_jid = client.jid 1077 fake_history.source_jid = client.jid
1118 fake_history.dest_jid = TEST_JID 1078 fake_history.dest_jid = TEST_JID
1119 fake_history.origin_id = ap_item["id"] 1079 fake_history.origin_id = ap_item["id"]
1120 storage_get.return_value = fake_history 1080 storage_get.return_value = fake_history
1121 # we simulate a received Delete activity 1081 # we simulate a received Delete activity
1122 await ap_gateway.newAPDeleteItem( 1082 await ap_gateway.newAPDeleteItem(
1123 client=client, 1083 client=client, destinee=None, node=ap_gateway._m.namespace, item=ap_item
1124 destinee=None,
1125 node=ap_gateway._m.namespace,
1126 item=ap_item
1127 ) 1084 )
1128 1085
1129 # item is deleted from database 1086 # item is deleted from database
1130 assert retractDBHistory.call_count == 1 1087 assert retractDBHistory.call_count == 1
1131 assert retractDBHistory.call_args.args[0] == client 1088 assert retractDBHistory.call_args.args[0] == client
1155 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), 1112 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT),
1156 # VCard4 node 1113 # VCard4 node
1157 ap_gateway._v.node, 1114 ap_gateway._v.node,
1158 None, 1115 None,
1159 None, 1116 None,
1160 None 1117 None,
1161 ) 1118 )
1162 assert len(items) == 1 1119 assert len(items) == 1
1163 vcard_elt = next(items[0].elements(ap_gateway._v.namespace, "vcard")) 1120 vcard_elt = next(items[0].elements(ap_gateway._v.namespace, "vcard"))
1164 vcard = ap_gateway._v.vcard2Dict(vcard_elt) 1121 vcard = ap_gateway._v.vcard2Dict(vcard_elt)
1165 assert "test_user nickname" in vcard["nicknames"] 1122 assert "test_user nickname" in vcard["nicknames"]
1170 """XMPP identity is converted to AP actor metadata""" 1127 """XMPP identity is converted to AP actor metadata"""
1171 # XXX: XMPP identity is normally an amalgam of metadata from several 1128 # XXX: XMPP identity is normally an amalgam of metadata from several
1172 # XEPs/locations (vCard4, vcard-tmp, etc) 1129 # XEPs/locations (vCard4, vcard-tmp, etc)
1173 with patch.object(ap_gateway._i, "getIdentity") as getIdentity: 1130 with patch.object(ap_gateway._i, "getIdentity") as getIdentity:
1174 getIdentity.return_value = { 1131 getIdentity.return_value = {
1175 "nicknames": ["nick1", "nick2"], 1132 "nicknames": ["nick1", "nick2"],
1176 "description": "test description" 1133 "description": "test description",
1177 } 1134 }
1178 actor_data = await ap_gateway.server.resource.APActorRequest( 1135 actor_data = await ap_gateway.server.resource.APActorRequest(
1179 **self.ap_request_params(ap_gateway, ap_const.TYPE_ACTOR) 1136 **self.ap_request_params(ap_gateway, ap_const.TYPE_ACTOR)
1180 ) 1137 )
1181 1138
1191 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get) 1148 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
1192 1149
1193 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) 1150 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
1194 1151
1195 direct_addr_mention = { 1152 direct_addr_mention = {
1196 'attributedTo': TEST_AP_ACTOR_ID, 1153 "attributedTo": TEST_AP_ACTOR_ID,
1197 'cc': [], 1154 "cc": [],
1198 'content': '<p>test mention by direct addressing</p>', 1155 "content": "<p>test mention by direct addressing</p>",
1199 'id': f'{TEST_AP_ACTOR_ID}/statuses/direct_addr_123', 1156 "id": f"{TEST_AP_ACTOR_ID}/statuses/direct_addr_123",
1200 'published': '2022-05-20T08:14:39Z', 1157 "published": "2022-05-20T08:14:39Z",
1201 'to': [ap_const.NS_AP_PUBLIC, xmpp_actor_id], 1158 "to": [ap_const.NS_AP_PUBLIC, xmpp_actor_id],
1202 'type': 'Note' 1159 "type": "Note",
1203 } 1160 }
1204 client = ap_gateway.client.getVirtualClient( 1161 client = ap_gateway.client.getVirtualClient(
1205 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) 1162 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
1206 ) 1163 )
1207 monkeypatch.setattr(client, "sendMessage", MagicMock()) 1164 monkeypatch.setattr(client, "sendMessage", MagicMock())
1217 local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) 1174 local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
1218 expected_anchor = xmpp_uri.buildXMPPUri( 1175 expected_anchor = xmpp_uri.buildXMPPUri(
1219 "pubsub", 1176 "pubsub",
1220 path=local_actor_jid.full(), 1177 path=local_actor_jid.full(),
1221 node=ap_gateway._m.namespace, 1178 node=ap_gateway._m.namespace,
1222 item=direct_addr_mention["id"] 1179 item=direct_addr_mention["id"],
1223 ) 1180 )
1224 1181
1225 assert sendReference.call_args.kwargs["anchor"] == expected_anchor 1182 assert sendReference.call_args.kwargs["anchor"] == expected_anchor
1226 1183
1227 @ed 1184 @ed
1232 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get) 1189 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
1233 1190
1234 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) 1191 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
1235 1192
1236 direct_addr_mention = { 1193 direct_addr_mention = {
1237 'attributedTo': TEST_AP_ACTOR_ID, 1194 "attributedTo": TEST_AP_ACTOR_ID,
1238 'cc': [], 1195 "cc": [],
1239 'content': '<p>test mention by tag</p>', 1196 "content": "<p>test mention by tag</p>",
1240 'id': f'{TEST_AP_ACTOR_ID}/statuses/tag_123', 1197 "id": f"{TEST_AP_ACTOR_ID}/statuses/tag_123",
1241 'published': '2022-05-20T08:14:39Z', 1198 "published": "2022-05-20T08:14:39Z",
1242 'to': [ap_const.NS_AP_PUBLIC], 1199 "to": [ap_const.NS_AP_PUBLIC],
1243 "tag": [ 1200 "tag": [{"type": "Mention", "href": xmpp_actor_id, "name": f"@{TEST_JID}'"}],
1244 { 1201 "type": "Note",
1245 "type": "Mention",
1246 "href": xmpp_actor_id,
1247 "name": f"@{TEST_JID}'"
1248 }
1249 ],
1250 'type': 'Note'
1251 } 1202 }
1252 client = ap_gateway.client.getVirtualClient( 1203 client = ap_gateway.client.getVirtualClient(
1253 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) 1204 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
1254 ) 1205 )
1255 monkeypatch.setattr(client, "sendMessage", MagicMock()) 1206 monkeypatch.setattr(client, "sendMessage", MagicMock())
1265 local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) 1216 local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
1266 expected_anchor = xmpp_uri.buildXMPPUri( 1217 expected_anchor = xmpp_uri.buildXMPPUri(
1267 "pubsub", 1218 "pubsub",
1268 path=local_actor_jid.full(), 1219 path=local_actor_jid.full(),
1269 node=ap_gateway._m.namespace, 1220 node=ap_gateway._m.namespace,
1270 item=direct_addr_mention["id"] 1221 item=direct_addr_mention["id"],
1271 ) 1222 )
1272 1223
1273 assert sendReference.call_args.kwargs["anchor"] == expected_anchor 1224 assert sendReference.call_args.kwargs["anchor"] == expected_anchor
1274 1225
1275 @ed 1226 @ed
1281 1232
1282 mb_data = { 1233 mb_data = {
1283 "author_jid": TEST_JID.full(), 1234 "author_jid": TEST_JID.full(),
1284 "content": f"mention of @{TEST_AP_ACCOUNT}", 1235 "content": f"mention of @{TEST_AP_ACCOUNT}",
1285 "service": TEST_JID.full(), 1236 "service": TEST_JID.full(),
1286 "node": ap_gateway._m.namespace 1237 "node": ap_gateway._m.namespace,
1287 } 1238 }
1288 ap_item = await ap_gateway.mbdata2APitem(ap_gateway.client, mb_data, public=True) 1239 ap_item = await ap_gateway.mb_data_2_ap_item(
1240 ap_gateway.client, mb_data, public=True
1241 )
1289 1242
1290 ap_object = ap_item["object"] 1243 ap_object = ap_item["object"]
1291 assert TEST_AP_ACTOR_ID in ap_object["to"] 1244 assert TEST_AP_ACTOR_ID in ap_object["to"]
1292 expected_mention = { 1245 expected_mention = {
1293 "type": ap_const.TYPE_MENTION, 1246 "type": ap_const.TYPE_MENTION,
1294 "href": TEST_AP_ACTOR_ID, 1247 "href": TEST_AP_ACTOR_ID,
1295 "name": f"@{TEST_AP_ACCOUNT}" 1248 "name": f"@{TEST_AP_ACCOUNT}",
1296 } 1249 }
1297 assert expected_mention in ap_object["tag"] 1250 assert expected_mention in ap_object["tag"]
1298 1251
1299 @ed 1252 @ed
1300 async def test_no_auto_mentions_when_not_public(self, ap_gateway, monkeypatch): 1253 async def test_no_auto_mentions_when_not_public(self, ap_gateway, monkeypatch):
1301 """Check that no mention is send when the message is not public""" 1254 """Check that no mention is send when the message is not public"""
1302 # this is the same test as test_auto_mentions above, except that public is not set 1255 # this is the same test as test_auto_mentions above, except that public is not set
1303 # in mbdata2APitem 1256 # in mb_data_2_ap_item
1304 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get) 1257 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
1305 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json) 1258 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
1306 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get) 1259 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
1307 1260
1308 mb_data = { 1261 mb_data = {
1309 "author_jid": TEST_JID.full(), 1262 "author_jid": TEST_JID.full(),
1310 "content": f"mention of @{TEST_AP_ACCOUNT}", 1263 "content": f"mention of @{TEST_AP_ACCOUNT}",
1311 "service": TEST_JID.full(), 1264 "service": TEST_JID.full(),
1312 "node": ap_gateway._m.namespace 1265 "node": ap_gateway._m.namespace,
1313 } 1266 }
1314 ap_item = await ap_gateway.mbdata2APitem(ap_gateway.client, mb_data, public=False) 1267 ap_item = await ap_gateway.mb_data_2_ap_item(
1268 ap_gateway.client, mb_data, public=False
1269 )
1315 1270
1316 ap_object = ap_item["object"] 1271 ap_object = ap_item["object"]
1317 assert "to" not in ap_object 1272 assert "to" not in ap_object
1318 assert "tag" not in ap_object 1273 assert "tag" not in ap_object
1319 1274
1328 item_elt = XMPP_ITEMS[0] 1283 item_elt = XMPP_ITEMS[0]
1329 anchor = xmpp_uri.buildXMPPUri( 1284 anchor = xmpp_uri.buildXMPPUri(
1330 "pubsub", 1285 "pubsub",
1331 path=TEST_JID.full(), 1286 path=TEST_JID.full(),
1332 node=ap_gateway._m.namespace, 1287 node=ap_gateway._m.namespace,
1333 item=item_elt["id"] 1288 item=item_elt["id"],
1334 ) 1289 )
1335 1290
1336 ref_data: Dict[str, Union[str, int, dict]] = { 1291 ref_data: Dict[str, Union[str, int, dict]] = {
1337 "uri": xmpp_uri.buildXMPPUri(None, path=local_actor_jid.full()), 1292 "uri": xmpp_uri.buildXMPPUri(None, path=local_actor_jid.full()),
1338 "type_": "mention", 1293 "type_": "mention",
1339 "anchor": anchor 1294 "anchor": anchor,
1340 } 1295 }
1341 reference_elt = ap_gateway._refs.buildRefElement(**ref_data) 1296 reference_elt = ap_gateway._refs.buildRefElement(**ref_data)
1342 1297
1343 # we now update ref_data to look like what is received in the trigger 1298 # we now update ref_data to look like what is received in the trigger
1344 1299
1359 mock_pubsub_item = MagicMock 1314 mock_pubsub_item = MagicMock
1360 mock_pubsub_item.data = item_elt 1315 mock_pubsub_item.data = item_elt
1361 getItems.return_value = ([mock_pubsub_item], {}) 1316 getItems.return_value = ([mock_pubsub_item], {})
1362 with patch.object(ap_gateway, "signAndPost") as signAndPost: 1317 with patch.object(ap_gateway, "signAndPost") as signAndPost:
1363 signAndPost.return_value.code = 202 1318 signAndPost.return_value.code = 202
1364 await ap_gateway._onReferenceReceived(ap_gateway.client, message_elt, ref_data) 1319 await ap_gateway._onReferenceReceived(
1320 ap_gateway.client, message_elt, ref_data
1321 )
1365 1322
1366 # when reference is received, the referencing item must be sent to referenced 1323 # when reference is received, the referencing item must be sent to referenced
1367 # actor, and they must be in "to" field and in "tag" 1324 # actor, and they must be in "to" field and in "tag"
1368 assert signAndPost.call_count == 1 1325 assert signAndPost.call_count == 1
1369 send_ap_item = signAndPost.call_args.args[-1] 1326 send_ap_item = signAndPost.call_args.args[-1]
1372 expected_mention = { 1329 expected_mention = {
1373 "type": ap_const.TYPE_MENTION, 1330 "type": ap_const.TYPE_MENTION,
1374 "href": TEST_AP_ACTOR_ID, 1331 "href": TEST_AP_ACTOR_ID,
1375 # we don't have a prefixing "@" here, because it's not needed in referencing 1332 # we don't have a prefixing "@" here, because it's not needed in referencing
1376 # item with XMPP 1333 # item with XMPP
1377 "name": f"{TEST_AP_ACCOUNT}" 1334 "name": f"{TEST_AP_ACCOUNT}",
1378 } 1335 }
1379 assert expected_mention in ap_object["tag"] 1336 assert expected_mention in ap_object["tag"]
1380 1337
1381 @ed 1338 @ed
1382 async def test_xmpp_repeat_to_ap_announce(self, ap_gateway, monkeypatch): 1339 async def test_xmpp_repeat_to_ap_announce(self, ap_gateway, monkeypatch):
1391 ap_item = TEST_AP_ITEMS[0] 1348 ap_item = TEST_AP_ITEMS[0]
1392 ap_item_url = xmpp_uri.buildXMPPUri( 1349 ap_item_url = xmpp_uri.buildXMPPUri(
1393 "pubsub", 1350 "pubsub",
1394 path=recipient_jid.full(), 1351 path=recipient_jid.full(),
1395 node=ap_gateway._m.namespace, 1352 node=ap_gateway._m.namespace,
1396 item=ap_item["id"] 1353 item=ap_item["id"],
1397 ) 1354 )
1398 item_elt = xml_tools.parse(f""" 1355 item_elt = xml_tools.parse(
1356 f"""
1399 <item id="123" publisher="{TEST_JID}/res.123"> 1357 <item id="123" publisher="{TEST_JID}/res.123">
1400 <entry xmlns="http://www.w3.org/2005/Atom"> 1358 <entry xmlns="http://www.w3.org/2005/Atom">
1401 <title type="text">test message 1</title> 1359 <title type="text">test message 1</title>
1402 <title type="xhtml"> 1360 <title type="xhtml">
1403 <div xmlns="http://www.w3.org/1999/xhtml"> 1361 <div xmlns="http://www.w3.org/1999/xhtml">
1412 <published>2022-07-21T14:38:53Z</published> 1370 <published>2022-07-21T14:38:53Z</published>
1413 <id>{ap_item["id"]}</id> 1371 <id>{ap_item["id"]}</id>
1414 <link href="{ap_item_url}" rel="via"/> 1372 <link href="{ap_item_url}" rel="via"/>
1415 </entry> 1373 </entry>
1416 </item> 1374 </item>
1417 """) 1375 """
1376 )
1418 item_elt.uri = pubsub.NS_PUBSUB_EVENT 1377 item_elt.uri = pubsub.NS_PUBSUB_EVENT
1419 1378
1420 with patch.object(ap_gateway, "signAndPost") as signAndPost: 1379 with patch.object(ap_gateway, "signAndPost") as signAndPost:
1421 signAndPost.return_value.code = 202 1380 signAndPost.return_value.code = 202
1422 await ap_gateway.convertAndPostItems( 1381 await ap_gateway.convertAndPostItems(
1423 ap_gateway.client, 1382 ap_gateway.client,
1424 TEST_AP_ACCOUNT, 1383 TEST_AP_ACCOUNT,
1425 TEST_JID, 1384 TEST_JID,
1426 ap_gateway._m.namespace, 1385 ap_gateway._m.namespace,
1427 [item_elt] 1386 [item_elt],
1428 ) 1387 )
1429 1388
1430 assert signAndPost.called 1389 assert signAndPost.called
1431 url, actor_id, doc = signAndPost.call_args.args 1390 url, actor_id, doc = signAndPost.call_args.args
1432 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"] 1391 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"]
1450 ) 1409 )
1451 announce = { 1410 announce = {
1452 "@context": "https://www.w3.org/ns/activitystreams", 1411 "@context": "https://www.w3.org/ns/activitystreams",
1453 "type": "Announce", 1412 "type": "Announce",
1454 "actor": TEST_AP_ACTOR_ID, 1413 "actor": TEST_AP_ACTOR_ID,
1455 "cc": [ 1414 "cc": [xmpp_actor_id, TEST_USER_DATA["followers"]],
1456 xmpp_actor_id,
1457 TEST_USER_DATA["followers"]
1458 ],
1459 "id": "https://example.org/announce/123", 1415 "id": "https://example.org/announce/123",
1460 "object": xmpp_item_url, 1416 "object": xmpp_item_url,
1461 "published": "2022-07-22T09:24:12Z", 1417 "published": "2022-07-22T09:24:12Z",
1462 "to": [ap_const.NS_AP_PUBLIC] 1418 "to": [ap_const.NS_AP_PUBLIC],
1463 } 1419 }
1464 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems: 1420 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems:
1465 mock_pubsub_item = MagicMock 1421 mock_pubsub_item = MagicMock
1466 mock_pubsub_item.data = xmpp_item 1422 mock_pubsub_item.data = xmpp_item
1467 getItems.return_value = ([mock_pubsub_item], {}) 1423 getItems.return_value = ([mock_pubsub_item], {})
1468 with patch.object( 1424 with patch.object(
1469 ap_gateway.host.memory.storage, 1425 ap_gateway.host.memory.storage, "cachePubsubItems"
1470 "cachePubsubItems") as cachePubsubItems: 1426 ) as cachePubsubItems:
1471 await ap_gateway.server.resource.handleAnnounceActivity( 1427 await ap_gateway.server.resource.handleAnnounceActivity(
1472 Request(MagicMock()), 1428 Request(MagicMock()), announce, None, None, None, "", TEST_AP_ACTOR_ID
1473 announce,
1474 None,
1475 None,
1476 None,
1477 "",
1478 TEST_AP_ACTOR_ID
1479 ) 1429 )
1480 1430
1481 assert cachePubsubItems.called 1431 assert cachePubsubItems.called
1482 # the microblog data put in cache correspond to the item sent to subscribers 1432 # the microblog data put in cache correspond to the item sent to subscribers
1483 __, __, __, [mb_data] = cachePubsubItems.call_args.args 1433 __, __, __, [mb_data] = cachePubsubItems.call_args.args
1487 assert repeated["by"] == ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT).full() 1437 assert repeated["by"] == ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT).full()
1488 xmpp_item_xmpp_url = xmpp_uri.buildXMPPUri( 1438 xmpp_item_xmpp_url = xmpp_uri.buildXMPPUri(
1489 "pubsub", 1439 "pubsub",
1490 path=TEST_JID.full(), 1440 path=TEST_JID.full(),
1491 node=ap_gateway._m.namespace, 1441 node=ap_gateway._m.namespace,
1492 item=xmpp_item["id"] 1442 item=xmpp_item["id"],
1493 ) 1443 )
1494 assert repeated["uri"] == xmpp_item_xmpp_url 1444 assert repeated["uri"] == xmpp_item_xmpp_url
1495 1445
1496 @ed 1446 @ed
1497 async def test_xmpp_attachment_noticed_to_ap_like(self, ap_gateway, monkeypatch): 1447 async def test_xmpp_attachment_noticed_to_ap_like(self, ap_gateway, monkeypatch):
1502 1452
1503 recipient_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) 1453 recipient_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
1504 # noticed item 1454 # noticed item
1505 ap_item = TEST_AP_ITEMS[0] 1455 ap_item = TEST_AP_ITEMS[0]
1506 attachment_node = ap_gateway._pa.getAttachmentNodeName( 1456 attachment_node = ap_gateway._pa.getAttachmentNodeName(
1507 recipient_jid, 1457 recipient_jid, ap_gateway._m.namespace, ap_item["id"]
1508 ap_gateway._m.namespace, 1458 )
1509 ap_item["id"] 1459 item_elt = xml_tools.parse(
1510 ) 1460 f"""
1511 item_elt = xml_tools.parse(f"""
1512 <item id="{TEST_JID.userhost()}" published="{TEST_JID.userhostJID()}"> 1461 <item id="{TEST_JID.userhost()}" published="{TEST_JID.userhostJID()}">
1513 <attachments xmlns="urn:xmpp:pubsub-attachments:1"> 1462 <attachments xmlns="urn:xmpp:pubsub-attachments:1">
1514 <noticed timestamp="2022-07-22T12:29:45Z"/> 1463 <noticed timestamp="2022-07-22T12:29:45Z"/>
1515 </attachments> 1464 </attachments>
1516 </item> 1465 </item>
1517 """) 1466 """
1467 )
1518 item_elt.uri = pubsub.NS_PUBSUB_EVENT 1468 item_elt.uri = pubsub.NS_PUBSUB_EVENT
1519 items_event = pubsub.ItemsEvent( 1469 items_event = pubsub.ItemsEvent(
1520 TEST_JID, 1470 TEST_JID, recipient_jid, attachment_node, [item_elt], {}
1521 recipient_jid,
1522 attachment_node,
1523 [item_elt],
1524 {}
1525 ) 1471 )
1526 1472
1527 with patch.object(ap_gateway, "signAndPost") as signAndPost: 1473 with patch.object(ap_gateway, "signAndPost") as signAndPost:
1528 signAndPost.return_value.code = 202 1474 signAndPost.return_value.code = 202
1529 await ap_gateway._itemsReceived( 1475 await ap_gateway._itemsReceived(ap_gateway.client, items_event)
1530 ap_gateway.client,
1531 items_event
1532 )
1533 1476
1534 assert signAndPost.called 1477 assert signAndPost.called
1535 url, actor_id, doc = signAndPost.call_args.args 1478 url, actor_id, doc = signAndPost.call_args.args
1536 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"] 1479 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"]
1537 assert actor_id == ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) 1480 assert actor_id == ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
1554 ) 1497 )
1555 like = { 1498 like = {
1556 "@context": "https://www.w3.org/ns/activitystreams", 1499 "@context": "https://www.w3.org/ns/activitystreams",
1557 "type": "Like", 1500 "type": "Like",
1558 "actor": TEST_AP_ACTOR_ID, 1501 "actor": TEST_AP_ACTOR_ID,
1559 "cc": [ 1502 "cc": [xmpp_actor_id, TEST_USER_DATA["followers"]],
1560 xmpp_actor_id,
1561 TEST_USER_DATA["followers"]
1562 ],
1563 "id": "https://example.org/like/123", 1503 "id": "https://example.org/like/123",
1564 "object": xmpp_item_url, 1504 "object": xmpp_item_url,
1565 "published": "2022-07-22T09:24:12Z", 1505 "published": "2022-07-22T09:24:12Z",
1566 "to": [ap_const.NS_AP_PUBLIC] 1506 "to": [ap_const.NS_AP_PUBLIC],
1567 } 1507 }
1568 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems: 1508 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems:
1569 getItems.return_value = ([], {}) 1509 getItems.return_value = ([], {})
1570 with patch.object(ap_gateway._p, "sendItems") as sendItems: 1510 with patch.object(ap_gateway._p, "sendItems") as sendItems:
1571 await ap_gateway.server.resource.APInboxRequest( 1511 await ap_gateway.server.resource.APInboxRequest(
1572 **self.ap_request_params( 1512 **self.ap_request_params(
1573 ap_gateway, 1513 ap_gateway, "inbox", doc=like, signing_actor=TEST_AP_ACTOR_ID
1574 "inbox",
1575 doc=like,
1576 signing_actor=TEST_AP_ACTOR_ID
1577 ) 1514 )
1578 ) 1515 )
1579 1516
1580 assert sendItems.called 1517 assert sendItems.called
1581 si_client, si_service, si_node, [si_item] = sendItems.call_args.args 1518 si_client, si_service, si_node, [si_item] = sendItems.call_args.args
1601 ap_item = TEST_AP_ITEMS[0] 1538 ap_item = TEST_AP_ITEMS[0]
1602 ap_item_url = xmpp_uri.buildXMPPUri( 1539 ap_item_url = xmpp_uri.buildXMPPUri(
1603 "pubsub", 1540 "pubsub",
1604 path=recipient_jid.full(), 1541 path=recipient_jid.full(),
1605 node=ap_gateway._m.namespace, 1542 node=ap_gateway._m.namespace,
1606 item=ap_item["id"] 1543 item=ap_item["id"],
1607 ) 1544 )
1608 attachment_node = ap_gateway._pa.getAttachmentNodeName( 1545 attachment_node = ap_gateway._pa.getAttachmentNodeName(
1609 recipient_jid, 1546 recipient_jid, ap_gateway._m.namespace, ap_item["id"]
1610 ap_gateway._m.namespace,
1611 ap_item["id"]
1612 ) 1547 )
1613 reactions = ["🦁", "🥜", "🎻"] 1548 reactions = ["🦁", "🥜", "🎻"]
1614 item_elt = xml_tools.parse(f""" 1549 item_elt = xml_tools.parse(
1550 f"""
1615 <item id="{TEST_JID.userhost()}" published="{TEST_JID.userhostJID()}"> 1551 <item id="{TEST_JID.userhost()}" published="{TEST_JID.userhostJID()}">
1616 <attachments xmlns="urn:xmpp:pubsub-attachments:1"> 1552 <attachments xmlns="urn:xmpp:pubsub-attachments:1">
1617 <reactions timestamp="2022-08-31T12:17:23Z"> 1553 <reactions timestamp="2022-08-31T12:17:23Z">
1618 <reaction>{reactions[0]}</reaction> 1554 <reaction>{reactions[0]}</reaction>
1619 <reaction>{reactions[1]}</reaction> 1555 <reaction>{reactions[1]}</reaction>
1620 <reaction>{reactions[2]}</reaction> 1556 <reaction>{reactions[2]}</reaction>
1621 </reactions> 1557 </reactions>
1622 </attachments> 1558 </attachments>
1623 </item> 1559 </item>
1624 """) 1560 """
1561 )
1625 item_elt.uri = pubsub.NS_PUBSUB_EVENT 1562 item_elt.uri = pubsub.NS_PUBSUB_EVENT
1626 items_event = pubsub.ItemsEvent( 1563 items_event = pubsub.ItemsEvent(
1627 TEST_JID, 1564 TEST_JID, recipient_jid, attachment_node, [item_elt], {}
1628 recipient_jid,
1629 attachment_node,
1630 [item_elt],
1631 {}
1632 ) 1565 )
1633 1566
1634 with patch.object(ap_gateway, "signAndPost") as signAndPost: 1567 with patch.object(ap_gateway, "signAndPost") as signAndPost:
1635 signAndPost.return_value.code = 202 1568 signAndPost.return_value.code = 202
1636 await ap_gateway._itemsReceived( 1569 await ap_gateway._itemsReceived(ap_gateway.client, items_event)
1637 ap_gateway.client,
1638 items_event
1639 )
1640 1570
1641 assert signAndPost.call_count == 3 1571 assert signAndPost.call_count == 3
1642 for idx, call_args in enumerate(signAndPost.call_args_list): 1572 for idx, call_args in enumerate(signAndPost.call_args_list):
1643 url, actor_id, doc = call_args.args 1573 url, actor_id, doc = call_args.args
1644 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"] 1574 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"]
1670 ) 1600 )
1671 like = { 1601 like = {
1672 "@context": "https://www.w3.org/ns/activitystreams", 1602 "@context": "https://www.w3.org/ns/activitystreams",
1673 "type": "EmojiReact", 1603 "type": "EmojiReact",
1674 "actor": TEST_AP_ACTOR_ID, 1604 "actor": TEST_AP_ACTOR_ID,
1675 "cc": [ 1605 "cc": [xmpp_actor_id, TEST_USER_DATA["followers"]],
1676 xmpp_actor_id,
1677 TEST_USER_DATA["followers"]
1678 ],
1679 "id": "https://example.org/like/123", 1606 "id": "https://example.org/like/123",
1680 "object": xmpp_item_url, 1607 "object": xmpp_item_url,
1681 "content": "🐅", 1608 "content": "🐅",
1682 "published": "2022-07-22T09:24:12Z", 1609 "published": "2022-07-22T09:24:12Z",
1683 "to": [ap_const.NS_AP_PUBLIC] 1610 "to": [ap_const.NS_AP_PUBLIC],
1684 } 1611 }
1685 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems: 1612 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems:
1686 getItems.return_value = ([], {}) 1613 getItems.return_value = ([], {})
1687 with patch.object(ap_gateway._p, "sendItems") as sendItems: 1614 with patch.object(ap_gateway._p, "sendItems") as sendItems:
1688 await ap_gateway.server.resource.APInboxRequest( 1615 await ap_gateway.server.resource.APInboxRequest(
1689 **self.ap_request_params( 1616 **self.ap_request_params(
1690 ap_gateway, 1617 ap_gateway, "inbox", doc=like, signing_actor=TEST_AP_ACTOR_ID
1691 "inbox",
1692 doc=like,
1693 signing_actor=TEST_AP_ACTOR_ID
1694 ) 1618 )
1695 ) 1619 )
1696 1620
1697 assert sendItems.called 1621 assert sendItems.called
1698 si_client, si_service, si_node, [si_item] = sendItems.call_args.args 1622 si_client, si_service, si_node, [si_item] = sendItems.call_args.args