Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Pagination support for fetching wallets, connections, cred ex and proof records #850

Merged
merged 21 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0f6c19f
:sparkles: add limit and offset query params to get_tenants
ff137 May 28, 2024
2feade9
:sparkles: add limit and offset for fetching connections, cred ex, an…
ff137 Jun 18, 2024
0c462ec
:sparkles: define default definitions for pagination query parameters
ff137 Jun 27, 2024
d8abbe7
:sparkles: add pagination query parameters to fetch record endpoints
ff137 Jun 27, 2024
608c44d
:sparkles: add pagination parameters to issuer and verifier services
ff137 Jun 27, 2024
b4169bf
:white_check_mark: fix tests to expect limit and offset query params
ff137 Jun 27, 2024
d45bebe
:white_check_mark: update route tests
ff137 Jun 27, 2024
b832d97
:white_check_mark: end-to-end test coverage for fetching paginated re…
ff137 Jul 1, 2024
7fefd31
:white_check_mark: add clean-up to tests that leave credential exchan…
ff137 Jul 1, 2024
131d77c
:white_check_mark: assert failures instead of marking as expected fai…
ff137 Jul 4, 2024
63ab999
:white_check_mark: add clean up of pres ex records, to not conflict w…
ff137 Jul 4, 2024
3000b90
:white_check_mark: skip pagination test in regression mode
ff137 Jul 4, 2024
6da5f54
:white_check_mark: modify pagination assertions to handle case where …
ff137 Jul 4, 2024
a9d8426
:construction: test pagination fix for post-filter query params
ff137 Jul 4, 2024
5566832
:arrow_up: Upgrade aca-py to recent nightly build with python3.12
ff137 Jul 9, 2024
1ca5709
:white_check_mark: temporarily skip in regression test suit, since th…
ff137 Jul 9, 2024
fc96f29
:white_check_mark: temporarily skip in regression test suit, since th…
ff137 Jul 9, 2024
c152554
Merge branch 'development' into feat/pagination
ff137 Jul 11, 2024
6a6518d
:construction_worker: fix build context
ff137 Jul 11, 2024
7492f55
Merge branch 'development' into feat/pagination
ff137 Jul 15, 2024
d29b780
:white_check_mark: skip unique records across pages check, until ACA-…
ff137 Jul 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions app/routes/admin/tenants.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
remove_actor_by_id,
)
from app.services.trust_registry.util.actor import assert_actor_name
from app.util.pagination import limit_query_parameter, offset_query_parameter
from app.util.tenants import (
get_wallet_and_assert_valid_group,
tenant_from_wallet_record,
Expand Down Expand Up @@ -304,6 +305,8 @@ async def get_tenant(
async def get_tenants(
wallet_name: Optional[str] = None,
group_id: Optional[str] = group_id_query,
limit: Optional[int] = limit_query_parameter,
offset: Optional[int] = offset_query_parameter,
admin_auth: AcaPyAuthVerified = Depends(acapy_auth_tenant_admin),
) -> List[Tenant]:
"""Get all tenants, or fetch by wallet name."""
Expand All @@ -316,6 +319,8 @@ async def get_tenants(
wallets = await handle_acapy_call(
logger=bound_logger,
acapy_call=admin_controller.multitenancy.get_wallets,
limit=limit,
offset=offset,
wallet_name=wallet_name,
group_id=group_id,
)
Expand Down
7 changes: 7 additions & 0 deletions app/routes/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from app.dependencies.auth import AcaPyAuth, acapy_auth_from_header
from app.exceptions import handle_acapy_call
from app.models.connections import AcceptInvitation, CreateInvitation
from app.util.pagination import limit_query_parameter, offset_query_parameter
from shared.log_config import get_logger
from shared.models.connection_record import (
Connection,
Expand Down Expand Up @@ -134,6 +135,8 @@ async def accept_invitation(

@router.get("", summary="Fetch Connection Records", response_model=List[Connection])
async def get_connections(
limit: Optional[int] = limit_query_parameter,
offset: Optional[int] = offset_query_parameter,
alias: Optional[str] = None,
connection_protocol: Optional[Protocol] = None,
invitation_key: Optional[str] = None,
Expand All @@ -155,6 +158,8 @@ async def get_connections(

Parameters (Optional):
---
limit: int - The maximum number of records to retrieve
offset: int - The offset to start retrieving records from
alias: str
connection_protocol: Protocol: "connections/1.0", "didexchange/1.0"
invitation_key: str
Expand All @@ -176,6 +181,8 @@ async def get_connections(
connections = await handle_acapy_call(
logger=logger,
acapy_call=aries_controller.connection.get_connections,
limit=limit,
offset=offset,
alias=alias,
connection_protocol=connection_protocol,
invitation_key=invitation_key,
Expand Down
19 changes: 14 additions & 5 deletions app/routes/issuer.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
issuer_from_protocol_version,
)
from app.util.did import did_from_credential_definition_id, qualified_did_sov
from app.util.pagination import limit_query_parameter, offset_query_parameter
from app.util.retry_method import coroutine_with_retry_until_value
from shared.log_config import get_logger
from shared.models.credential_exchange import (
Expand Down Expand Up @@ -333,6 +334,8 @@ async def store_credential(
response_model=List[CredentialExchange],
)
async def get_credentials(
limit: Optional[int] = limit_query_parameter,
offset: Optional[int] = offset_query_parameter,
connection_id: Optional[str] = Query(None),
role: Optional[Role] = Query(None),
state: Optional[State] = Query(None),
Expand All @@ -356,14 +359,16 @@ async def get_credentials(

The following parameters can be set to filter the fetched exchange records: connection_id, role, state, thread_id.

Parameters:
Parameters (Optional):
---
connection_id: str (Optional)
role: Role (Optional): "issuer", "holder"
state: State (Optional): "proposal-sent", "proposal-received", "offer-sent", "offer-received",
limit: int - The maximum number of records to retrieve
offset: int - The offset to start retrieving records from
connection_id: str
role: Role: "issuer", "holder"
state: State: "proposal-sent", "proposal-received", "offer-sent", "offer-received",
"request-sent", "request-received", "credential-issued", "credential-received",
"credential-revoked", "abandoned", "done"
thread_id: UUID (Optional)
thread_id: UUID

Returns:
---
Expand All @@ -377,6 +382,8 @@ async def get_credentials(
bound_logger.debug("Fetching v1 records")
v1_records = await IssueCredentialFacades.V1.value.get_records(
controller=aries_controller,
limit=limit,
offset=offset,
connection_id=connection_id,
role=role,
state=back_to_v1_credential_state(state) if state else None,
Expand All @@ -386,6 +393,8 @@ async def get_credentials(
bound_logger.debug("Fetching v2 records")
v2_records = await IssueCredentialFacades.V2.value.get_records(
controller=aries_controller,
limit=limit,
offset=offset,
connection_id=connection_id,
role=role,
state=state,
Expand Down
11 changes: 10 additions & 1 deletion app/routes/verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
assert_valid_verifier,
get_verifier_by_version,
)
from app.util.pagination import limit_query_parameter, offset_query_parameter
from shared.log_config import get_logger
from shared.models.presentation_exchange import (
PresentationExchange,
Expand Down Expand Up @@ -324,11 +325,13 @@ async def reject_proof_request(
response_model=List[PresentationExchange],
)
async def get_proof_records(
auth: AcaPyAuth = Depends(acapy_auth_from_header),
limit: Optional[int] = limit_query_parameter,
offset: Optional[int] = offset_query_parameter,
connection_id: Optional[str] = None,
role: Optional[Role] = None,
state: Optional[State] = None,
thread_id: Optional[UUID] = None,
auth: AcaPyAuth = Depends(acapy_auth_from_header),
) -> List[PresentationExchange]:
"""
Get all presentation exchange records for this tenant
Expand All @@ -339,6 +342,8 @@ async def get_proof_records(

Parameters (Optional):
---
limit: int: The maximum number of records to retrieve
offset: int: The offset to start retrieving records from
connection_id: str
role: Role: "prover", "verifier"
state: State: "presentation-received", "presentation-sent", "proposal-received", "proposal-sent",
Expand All @@ -358,6 +363,8 @@ async def get_proof_records(
logger.debug("Fetching v1 proof records")
v1_records = await VerifierFacade.V1.value.get_proof_records(
controller=aries_controller,
limit=limit,
offset=offset,
connection_id=connection_id,
role=role,
state=back_to_v1_presentation_state(state) if state else None,
Expand All @@ -366,6 +373,8 @@ async def get_proof_records(
logger.debug("Fetching v2 proof records")
v2_records = await VerifierFacade.V2.value.get_proof_records(
controller=aries_controller,
limit=limit,
offset=offset,
connection_id=connection_id,
role=role,
state=state,
Expand Down
4 changes: 4 additions & 0 deletions app/services/issuer/acapy_issuer_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ async def delete_credential_exchange_record(
async def get_records(
cls,
controller: AcaPyClient,
limit: Optional[int] = None,
offset: Optional[int] = None,
connection_id: Optional[str] = None,
role: Optional[str] = None,
state: Optional[str] = None,
Expand All @@ -187,6 +189,8 @@ async def get_records(
result = await handle_acapy_call(
logger=bound_logger,
acapy_call=controller.issue_credential_v1_0.get_records,
limit=limit,
offset=offset,
connection_id=connection_id,
role=role,
state=state,
Expand Down
4 changes: 4 additions & 0 deletions app/services/issuer/acapy_issuer_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ async def delete_credential_exchange_record(
async def get_records(
cls,
controller: AcaPyClient,
limit: Optional[int] = None,
offset: Optional[int] = None,
connection_id: Optional[str] = None,
role: Optional[str] = None,
state: Optional[str] = None,
Expand All @@ -209,6 +211,8 @@ async def get_records(
result = await handle_acapy_call(
logger=bound_logger,
acapy_call=controller.issue_credential_v2_0.get_records,
limit=limit,
offset=offset,
connection_id=connection_id,
role=role,
state=state,
Expand Down
6 changes: 5 additions & 1 deletion app/services/verifier/acapy_verifier_v1.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List
from typing import List, Optional

Dismissed Show dismissed Hide dismissed
from aries_cloudcontroller import (
AcaPyClient,
Expand Down Expand Up @@ -185,6 +185,8 @@ async def reject_proof_request(
async def get_proof_records(
cls,
controller: AcaPyClient,
limit: Optional[int] = None,
offset: Optional[int] = None,
connection_id: str = None,
role: str = None,
state: str = None,
Expand All @@ -195,6 +197,8 @@ async def get_proof_records(
presentation_exchange = await handle_acapy_call(
logger=logger,
acapy_call=controller.present_proof_v1_0.get_records,
limit=limit,
offset=offset,
connection_id=connection_id,
role=role,
state=state,
Expand Down
6 changes: 5 additions & 1 deletion app/services/verifier/acapy_verifier_v2.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import List
from typing import List, Optional

from aries_cloudcontroller import (
AcaPyClient,
Expand Down Expand Up @@ -201,6 +201,8 @@ async def reject_proof_request(
async def get_proof_records(
cls,
controller: AcaPyClient,
limit: Optional[int] = None,
offset: Optional[int] = None,
connection_id: str = None,
role: str = None,
state: str = None,
Expand All @@ -211,6 +213,8 @@ async def get_proof_records(
presentation_exchange = await handle_acapy_call(
logger=logger,
acapy_call=controller.present_proof_v2_0.get_records,
limit=limit,
offset=offset,
connection_id=connection_id,
role=role,
state=state,
Expand Down
8 changes: 8 additions & 0 deletions app/tests/e2e/issuer/ld_proof/test_ld_proof_did_key_bbs.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ async def test_send_jsonld_key_bbs(
assert_that(received_credential).has_role("holder")
assert_that(received_credential["credential_exchange_id"]).starts_with("v2")

# Clean up created offer
cred_ex_id = data["credential_exchange_id"]
await faber_client.delete(f"{CREDENTIALS_BASE_PATH}/{cred_ex_id}")


@pytest.mark.anyio
async def test_send_jsonld_bbs_oob(
Expand Down Expand Up @@ -201,6 +205,10 @@ async def test_send_jsonld_bbs_oob(
},
)

# Clean up created offer
cred_ex_id = data["credential_exchange_id"]
await faber_client.delete(f"{CREDENTIALS_BASE_PATH}/{cred_ex_id}")


@pytest.mark.anyio
async def test_send_jsonld_request(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ async def test_send_jsonld_key_ed25519(
assert_that(received_credential).has_role("holder")
assert_that(received_credential["credential_exchange_id"]).starts_with("v2")

# Clean up created offer
cred_ex_id = data["credential_exchange_id"]
await faber_client.delete(f"{CREDENTIALS_BASE_PATH}/{cred_ex_id}")


@pytest.mark.anyio
async def test_send_jsonld_oob(
Expand Down Expand Up @@ -198,6 +202,10 @@ async def test_send_jsonld_oob(
},
)

# Clean up created offer
cred_ex_id = data["credential_exchange_id"]
await faber_client.delete(f"{CREDENTIALS_BASE_PATH}/{cred_ex_id}")


@pytest.mark.anyio
async def test_send_jsonld_request(
Expand Down
8 changes: 8 additions & 0 deletions app/tests/e2e/issuer/ld_proof/test_ld_proof_did_sov.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ async def test_send_jsonld_credential_sov(
assert_that(received_credential).has_role("holder")
assert_that(received_credential["credential_exchange_id"]).starts_with("v2")

# Clean up created offer
cred_ex_id = data["credential_exchange_id"]
await faber_client.delete(f"{CREDENTIALS_BASE_PATH}/{cred_ex_id}")


@pytest.mark.anyio
async def test_send_jsonld_oob_sov(
Expand Down Expand Up @@ -191,6 +195,10 @@ async def test_send_jsonld_oob_sov(
state="offer-received",
)

# Clean up created offer
cred_ex_id = data["credential_exchange_id"]
await faber_client.delete(f"{CREDENTIALS_BASE_PATH}/{cred_ex_id}")


@pytest.mark.anyio
async def test_send_jsonld_request_sov(
Expand Down
Loading
Loading