Skip to content

Commit 864a3af

Browse files
authored
Fetch existing invitation route (#3572)
* fetch existing invitation route Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> * lint Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> * fetch by oob_id Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> * linting Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> * change to path parameter Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> * return entire record Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> * test new route and manager function Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> * lint Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> * fix tests Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> * return class from function Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> * add fn return type Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> * add query parameter for oob_id and fix unit test Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca> --------- Signed-off-by: PatStLouis <patrick.st-louis@opsecid.ca>
1 parent 2bd6f27 commit 864a3af

File tree

4 files changed

+121
-2
lines changed

4 files changed

+121
-2
lines changed

acapy_agent/protocols/out_of_band/v1_0/manager.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,19 @@ async def delete_stale_connection_by_invitation(self, invi_msg_id: str):
11721172
for conn_rec in conn_records:
11731173
await conn_rec.delete_record(session)
11741174

1175+
async def fetch_oob_invitation_record_by_id(self, oob_id: str) -> OobRecord:
1176+
"""Fetch oob_record associated with an oob_id."""
1177+
async with self.profile.session() as session:
1178+
oob_record = await OobRecord.retrieve_by_id(
1179+
session,
1180+
record_id=oob_id,
1181+
)
1182+
1183+
if not oob_record:
1184+
raise StorageNotFoundError(f"No record found with oob_id {oob_id}")
1185+
1186+
return oob_record
1187+
11751188
async def delete_conn_and_oob_record_invitation(self, invi_msg_id: str):
11761189
"""Delete conn_record and oob_record associated with an invi_msg_id."""
11771190
async with self.profile.session() as session:
@@ -1180,7 +1193,6 @@ async def delete_conn_and_oob_record_invitation(self, invi_msg_id: str):
11801193
tag_filter={
11811194
"invitation_msg_id": invi_msg_id,
11821195
},
1183-
post_filter_positive={},
11841196
)
11851197
for conn_rec in conn_records:
11861198
await conn_rec.delete_record(session)
@@ -1189,7 +1201,6 @@ async def delete_conn_and_oob_record_invitation(self, invi_msg_id: str):
11891201
tag_filter={
11901202
"invi_msg_id": invi_msg_id,
11911203
},
1192-
post_filter_positive={},
11931204
)
11941205
for oob_rec in oob_records:
11951206
await oob_rec.delete_record(session)

acapy_agent/protocols/out_of_band/v1_0/routes.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ class OutOfBandModuleResponseSchema(OpenAPISchema):
3535
"""Response schema for Out of Band Module."""
3636

3737

38+
class OobIdQueryStringSchema(OpenAPISchema):
39+
"""Parameters and validators for fetch invitation request query string."""
40+
41+
oob_id = fields.Str(
42+
required=True,
43+
validate=UUID4_VALIDATE,
44+
metadata={"description": "The Out of Band id to fetch"},
45+
)
46+
47+
3848
class InvitationCreateQueryStringSchema(OpenAPISchema):
3949
"""Parameters and validators for create invitation request query string."""
4050

@@ -217,6 +227,45 @@ class InvitationRecordMatchInfoSchema(OpenAPISchema):
217227
)
218228

219229

230+
class OobInvitationRecordMatchInfoSchema(OpenAPISchema):
231+
"""Path parameters and validators for request taking invitation record."""
232+
233+
oob_id = fields.Str(
234+
required=True,
235+
validate=UUID4_VALIDATE,
236+
metadata={
237+
"description": "OOB Invitation identifier",
238+
"example": UUID4_EXAMPLE,
239+
},
240+
)
241+
242+
243+
@docs(tags=["out-of-band"], summary="Fetch an existing Out-of-Band invitation.")
244+
@querystring_schema(OobIdQueryStringSchema())
245+
@response_schema(InvitationRecordResponseSchema(), description="")
246+
@tenant_authentication
247+
async def invitation_fetch(request: web.BaseRequest):
248+
"""Request handler for fetching an invitation.
249+
250+
Args:
251+
request: aiohttp request object
252+
253+
"""
254+
context: AdminRequestContext = request["context"]
255+
profile = context.profile
256+
oob_mgr = OutOfBandManager(profile)
257+
try:
258+
record = await oob_mgr.fetch_oob_invitation_record_by_id(
259+
request.query.get("oob_id")
260+
)
261+
except StorageNotFoundError as err:
262+
raise web.HTTPNotFound(reason=err.roll_up) from err
263+
except StorageError as err:
264+
raise web.HTTPBadRequest(reason=err.roll_up) from err
265+
266+
return web.json_response(record.serialize())
267+
268+
220269
@docs(
221270
tags=["out-of-band"],
222271
summary="Create a new connection invitation",
@@ -365,6 +414,11 @@ async def register(app: web.Application):
365414
[
366415
web.post("/out-of-band/create-invitation", invitation_create),
367416
web.post("/out-of-band/receive-invitation", invitation_receive),
417+
web.get(
418+
"/out-of-band/invitations",
419+
invitation_fetch,
420+
allow_head=False,
421+
),
368422
web.delete("/out-of-band/invitations/{invi_msg_id}", invitation_remove),
369423
]
370424
)

acapy_agent/protocols/out_of_band/v1_0/tests/test_manager.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1886,3 +1886,36 @@ async def test_delete_conn_and_oob_record_invitation(self):
18861886
await self.manager.delete_conn_and_oob_record_invitation("test123")
18871887
mock_connrecord_delete.assert_called_once()
18881888
mock_oobrecord_delete.assert_called_once()
1889+
1890+
async def test_fetch_invitation_succeeds(self):
1891+
self.profile.context.update_settings({"public_invites": True})
1892+
1893+
with mock.patch.object(
1894+
AskarWallet, "get_public_did", autospec=True
1895+
) as mock_wallet_get_public_did:
1896+
mock_wallet_get_public_did.return_value = DIDInfo(
1897+
TestConfig.test_did,
1898+
TestConfig.test_verkey,
1899+
None,
1900+
method=SOV,
1901+
key_type=ED25519,
1902+
)
1903+
invi_rec = await self.manager.create_invitation(
1904+
my_endpoint=TestConfig.test_endpoint,
1905+
public=True,
1906+
hs_protos=[HSProto.RFC23],
1907+
)
1908+
1909+
invi_rec = await self.manager.fetch_oob_invitation_record_by_id(
1910+
oob_id=invi_rec.oob_id
1911+
)
1912+
1913+
assert invi_rec.invitation._type == DIDCommPrefix.qualify_current(
1914+
self.TEST_INVI_MESSAGE_TYPE
1915+
)
1916+
assert not invi_rec.invitation.requests_attach
1917+
assert (
1918+
DIDCommPrefix.qualify_current(HSProto.RFC23.name)
1919+
in invi_rec.invitation.handshake_protocols
1920+
)
1921+
assert invi_rec.invitation.services == [f"did:sov:{TestConfig.test_did}"]

acapy_agent/protocols/out_of_band/v1_0/tests/test_routes.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,27 @@ async def test_invitation_create(self):
7575
)
7676
mock_json_response.assert_called_once_with({"abc": "123"})
7777

78+
async def test_invitation_fetch(self):
79+
self.request.query = {"oob_id": "dummy"}
80+
81+
with (
82+
mock.patch.object(
83+
test_module, "OutOfBandManager", autospec=True
84+
) as mock_oob_mgr,
85+
mock.patch.object(
86+
test_module.web, "json_response", mock.Mock()
87+
) as mock_json_response,
88+
):
89+
mock_oob_mgr.return_value.fetch_oob_invitation_record_by_id = (
90+
mock.CoroutineMock(
91+
return_value=mock.MagicMock(
92+
serialize=mock.MagicMock(return_value={"abc": "123"})
93+
)
94+
)
95+
)
96+
await test_module.invitation_fetch(self.request)
97+
mock_json_response.assert_called_once_with({"abc": "123"})
98+
7899
async def test_invitation_remove(self):
79100
self.request.match_info = {"invi_msg_id": "dummy"}
80101

0 commit comments

Comments
 (0)