|
18 | 18 | from ....admin.request_context import AdminRequestContext |
19 | 19 | from ....messaging.models.base import BaseModelError |
20 | 20 | from ....messaging.models.openapi import OpenAPISchema |
| 21 | +from ....messaging.models.paginated_query import ( |
| 22 | + PaginatedQuerySchema, |
| 23 | + get_paginated_query_params, |
| 24 | +) |
21 | 25 | from ....messaging.valid import UUID4_EXAMPLE, UUID4_VALIDATE |
22 | 26 | from ....storage.error import StorageError, StorageNotFoundError |
23 | 27 | from ...didcomm_prefix import DIDCommPrefix |
|
26 | 30 | from .message_types import SPEC_URI |
27 | 31 | from .messages.invitation import HSProto, InvitationMessage, InvitationMessageSchema |
28 | 32 | from .models.invitation import InvitationRecordSchema |
29 | | -from .models.oob_record import OobRecordSchema |
| 33 | +from .models.oob_record import OobRecord, OobRecordSchema |
30 | 34 |
|
31 | 35 | LOGGER = logging.getLogger(__name__) |
32 | 36 |
|
@@ -240,6 +244,106 @@ class OobInvitationRecordMatchInfoSchema(OpenAPISchema): |
240 | 244 | ) |
241 | 245 |
|
242 | 246 |
|
| 247 | +class OobRecordListQueryStringSchema(PaginatedQuerySchema): |
| 248 | + """Parameters and validators for OOB record list request query string.""" |
| 249 | + |
| 250 | + state = fields.Str( |
| 251 | + required=False, |
| 252 | + validate=validate.OneOf( |
| 253 | + OobRecord.get_attributes_by_prefix("STATE_", walk_mro=True) |
| 254 | + ), |
| 255 | + metadata={ |
| 256 | + "description": "OOB record state", |
| 257 | + "example": OobRecord.STATE_INITIAL, |
| 258 | + }, |
| 259 | + ) |
| 260 | + role = fields.Str( |
| 261 | + required=False, |
| 262 | + validate=validate.OneOf( |
| 263 | + OobRecord.get_attributes_by_prefix("ROLE_", walk_mro=False) |
| 264 | + ), |
| 265 | + metadata={ |
| 266 | + "description": "OOB record role", |
| 267 | + "example": OobRecord.ROLE_SENDER, |
| 268 | + }, |
| 269 | + ) |
| 270 | + connection_id = fields.Str( |
| 271 | + required=False, |
| 272 | + validate=UUID4_VALIDATE, |
| 273 | + metadata={ |
| 274 | + "description": "Connection identifier", |
| 275 | + "example": UUID4_EXAMPLE, |
| 276 | + }, |
| 277 | + ) |
| 278 | + invi_msg_id = fields.Str( |
| 279 | + required=False, |
| 280 | + validate=UUID4_VALIDATE, |
| 281 | + metadata={ |
| 282 | + "description": "Invitation message identifier", |
| 283 | + "example": UUID4_EXAMPLE, |
| 284 | + }, |
| 285 | + ) |
| 286 | + |
| 287 | + |
| 288 | +class OobRecordListSchema(OpenAPISchema): |
| 289 | + """Result schema for OOB record list.""" |
| 290 | + |
| 291 | + results = fields.List( |
| 292 | + fields.Nested(OobRecordSchema()), |
| 293 | + required=True, |
| 294 | + metadata={"description": "List of OOB records"}, |
| 295 | + ) |
| 296 | + |
| 297 | + |
| 298 | +@docs( |
| 299 | + tags=["out-of-band"], |
| 300 | + summary="Query OOB records", |
| 301 | +) |
| 302 | +@querystring_schema(OobRecordListQueryStringSchema()) |
| 303 | +@response_schema(OobRecordListSchema(), 200, description="") |
| 304 | +@tenant_authentication |
| 305 | +async def oob_records_list(request: web.BaseRequest): |
| 306 | + """Request handler for searching OOB records. |
| 307 | +
|
| 308 | + Args: |
| 309 | + request: aiohttp request object |
| 310 | +
|
| 311 | + Returns: |
| 312 | + The OOB record list response |
| 313 | +
|
| 314 | + """ |
| 315 | + context: AdminRequestContext = request["context"] |
| 316 | + |
| 317 | + tag_filter = { |
| 318 | + k: request.query[k] |
| 319 | + for k in ("state", "connection_id", "invi_msg_id") |
| 320 | + if request.query.get(k, "") != "" |
| 321 | + } |
| 322 | + post_filter = { |
| 323 | + k: request.query[k] for k in ("role",) if request.query.get(k, "") != "" |
| 324 | + } |
| 325 | + |
| 326 | + limit, offset, order_by, descending = get_paginated_query_params(request) |
| 327 | + |
| 328 | + profile = context.profile |
| 329 | + try: |
| 330 | + async with profile.session() as session: |
| 331 | + records = await OobRecord.query( |
| 332 | + session, |
| 333 | + tag_filter, |
| 334 | + limit=limit, |
| 335 | + offset=offset, |
| 336 | + order_by=order_by, |
| 337 | + descending=descending, |
| 338 | + post_filter_positive=post_filter, |
| 339 | + ) |
| 340 | + results = [record.serialize() for record in records] |
| 341 | + except (StorageError, BaseModelError) as err: |
| 342 | + raise web.HTTPBadRequest(reason=err.roll_up) from err |
| 343 | + |
| 344 | + return web.json_response({"results": results}) |
| 345 | + |
| 346 | + |
243 | 347 | @docs(tags=["out-of-band"], summary="Fetch an existing Out-of-Band invitation.") |
244 | 348 | @querystring_schema(OobIdQueryStringSchema()) |
245 | 349 | @response_schema(InvitationRecordResponseSchema(), description="") |
@@ -413,6 +517,11 @@ async def register(app: web.Application): |
413 | 517 | [ |
414 | 518 | web.post("/out-of-band/create-invitation", invitation_create), |
415 | 519 | web.post("/out-of-band/receive-invitation", invitation_receive), |
| 520 | + web.get( |
| 521 | + "/out-of-band/records", |
| 522 | + oob_records_list, |
| 523 | + allow_head=False, |
| 524 | + ), |
416 | 525 | web.get( |
417 | 526 | "/out-of-band/invitations", |
418 | 527 | invitation_fetch, |
|
0 commit comments