Skip to content

Commit 06b527d

Browse files
Feature #12: Ability to create data agreements in draft mode.
Signed-off-by: George J Padayatti <[email protected]>
1 parent 48402b2 commit 06b527d

File tree

2 files changed

+272
-60
lines changed

2 files changed

+272
-60
lines changed

mydata_did/v1_0/manager.py

Lines changed: 195 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ class ADAManager:
137137
# Record for keeping metadata about data agreement QR codes (client)
138138
RECORD_TYPE_DATA_AGREEMENT_QR_CODE_METADATA = "data_agreement_qr_code_metadata"
139139

140+
# Temporary record for keeping personal data of unpublished (or draft) data agreements
141+
RECORD_TYPE_TEMPORARY_DATA_AGREEMENT_PERSONAL_DATA = "temporary_data_agreement_personal_data"
142+
140143
DATA_AGREEMENT_RECORD_TYPE = "dataagreement_record"
141144

142145
def __init__(self, context: InjectionContext) -> None:
@@ -1390,10 +1393,11 @@ async def process_read_data_agreement_response_message(self, read_data_agreement
13901393
except (StorageNotFoundError, StorageDuplicateError):
13911394
pass
13921395

1393-
async def create_and_store_data_agreement_in_wallet(self, data_agreement: dict) -> DataAgreementV1Record:
1396+
async def create_and_store_data_agreement_in_wallet(self, data_agreement: dict, draft_mode: bool = False) -> DataAgreementV1Record:
13941397
"""
13951398
Create and store a data agreement in the wallet.
13961399
"""
1400+
storage: IndyStorage = await self.context.inject(BaseStorage)
13971401

13981402
personal_data_list = data_agreement.get("personal_data", [])
13991403

@@ -1445,95 +1449,227 @@ async def create_and_store_data_agreement_in_wallet(self, data_agreement: dict)
14451449
method_of_use=data_agreement.method_of_use,
14461450
state=DataAgreementV1Record.STATE_PREPARATION,
14471451
data_agreement=data_agreement.serialize(),
1448-
published_flag="True"
1452+
published_flag="True" if not draft_mode else "False"
14491453
)
14501454

1451-
if data_agreement.method_of_use == DataAgreementV1Record.METHOD_OF_USE_DATA_SOURCE:
1452-
# If method-of-use is "data-source", then create a schema and credential defintion
1455+
if draft_mode:
1456+
# Save personal data list for proof request in a record.
1457+
# for unpublished or draft data agreement.
1458+
storage_record: StorageRecord = StorageRecord(
1459+
self.RECORD_TYPE_TEMPORARY_DATA_AGREEMENT_PERSONAL_DATA,
1460+
json.dumps(personal_data_new_list_for_proof_request),
1461+
{
1462+
"data_agreement_id": data_agreement.data_agreement_template_id
1463+
}
1464+
)
14531465

1454-
ledger: BaseLedger = await self.context.inject(BaseLedger, required=False)
1455-
if not ledger:
1456-
reason = "No ledger available"
1457-
if not self.context.settings.get_value("wallet.type"):
1458-
reason += ": missing wallet-type?"
1466+
await storage.add_record(storage_record)
14591467

1460-
self._logger.error(
1461-
f"Failed to create data agreement: {reason}")
1468+
if not draft_mode:
1469+
if data_agreement.method_of_use == DataAgreementV1Record.METHOD_OF_USE_DATA_SOURCE:
1470+
# If method-of-use is "data-source", then create a schema and credential defintion
14621471

1463-
return None
1472+
ledger: BaseLedger = await self.context.inject(BaseLedger, required=False)
1473+
if not ledger:
1474+
reason = "No ledger available"
1475+
if not self.context.settings.get_value("wallet.type"):
1476+
reason += ": missing wallet-type?"
14641477

1465-
issuer: BaseIssuer = await self.context.inject(BaseIssuer)
1478+
self._logger.error(
1479+
f"Failed to create data agreement: {reason}")
14661480

1467-
async with ledger:
1468-
try:
1481+
return None
14691482

1470-
# Create schema
1483+
issuer: BaseIssuer = await self.context.inject(BaseIssuer)
14711484

1472-
schema_name = data_agreement.usage_purpose
1473-
schema_version = str(semver.VersionInfo(
1474-
str(data_agreement.data_agreement_template_version)))
1475-
attributes = [
1476-
personal_data.attribute_name
1477-
for personal_data in data_agreement.personal_data
1478-
]
1479-
1480-
schema_id, schema_def = await shield(
1481-
ledger.create_and_send_schema(
1482-
issuer, schema_name, schema_version, attributes
1485+
async with ledger:
1486+
try:
1487+
1488+
# Create schema
1489+
1490+
schema_name = data_agreement.usage_purpose
1491+
schema_version = str(semver.VersionInfo(
1492+
str(data_agreement.data_agreement_template_version)))
1493+
attributes = [
1494+
personal_data.attribute_name
1495+
for personal_data in data_agreement.personal_data
1496+
]
1497+
1498+
schema_id, schema_def = await shield(
1499+
ledger.create_and_send_schema(
1500+
issuer, schema_name, schema_version, attributes
1501+
)
14831502
)
1484-
)
14851503

1486-
# Create credential definition
1504+
# Create credential definition
14871505

1488-
tag = "default"
1489-
support_revocation = False
1506+
tag = "default"
1507+
support_revocation = False
14901508

1491-
(cred_def_id, cred_def, novel) = await shield(
1492-
ledger.create_and_send_credential_definition(
1493-
issuer,
1494-
schema_id,
1495-
signature_type=None,
1496-
tag=tag,
1497-
support_revocation=support_revocation,
1509+
(cred_def_id, cred_def, novel) = await shield(
1510+
ledger.create_and_send_credential_definition(
1511+
issuer,
1512+
schema_id,
1513+
signature_type=None,
1514+
tag=tag,
1515+
support_revocation=support_revocation,
1516+
)
14981517
)
1499-
)
15001518

1501-
# Update the data agreement record with schema and credential definition
1502-
data_agreement_v1_record.schema_id = schema_id
1503-
data_agreement_v1_record.cred_def_id = cred_def_id
1519+
# Update the data agreement record with schema and credential definition
1520+
data_agreement_v1_record.schema_id = schema_id
1521+
data_agreement_v1_record.cred_def_id = cred_def_id
15041522

1505-
except (IssuerError, LedgerError) as err:
1506-
self._logger.error(
1507-
f"Failed to create data agreement: {err.roll_up}")
1508-
return None
1509-
else:
1510-
# If method-of-use is "data-using-service"
1523+
except (IssuerError, LedgerError) as err:
1524+
self._logger.error(
1525+
f"Failed to create data agreement: {err.roll_up}")
1526+
return None
1527+
else:
1528+
# If method-of-use is "data-using-service"
15111529

1512-
# Update data agreement with proof presentation request
1513-
proof_request_dict = await self.construct_proof_presentation_request_dict_from_data_agreement_personal_data(
1514-
personal_data=personal_data_new_list_for_proof_request,
1515-
usage_purpose=data_agreement.usage_purpose,
1516-
usage_purpose_description=data_agreement.usage_purpose_description,
1517-
data_agreement_template_version=str(semver.VersionInfo(
1518-
str(data_agreement.data_agreement_template_version)))
1530+
# Update data agreement with proof presentation request
1531+
proof_request_dict = await self.construct_proof_presentation_request_dict_from_data_agreement_personal_data(
1532+
personal_data=personal_data_new_list_for_proof_request,
1533+
usage_purpose=data_agreement.usage_purpose,
1534+
usage_purpose_description=data_agreement.usage_purpose_description,
1535+
data_agreement_template_version=str(semver.VersionInfo(
1536+
str(data_agreement.data_agreement_template_version)))
15191537

1520-
)
1538+
)
15211539

1522-
data_agreement_v1_record.data_agreement_proof_presentation_request = proof_request_dict
1540+
data_agreement_v1_record.data_agreement_proof_presentation_request = proof_request_dict
15231541

15241542
# Save the data agreement record
15251543
await data_agreement_v1_record.save(self.context)
15261544

15271545
return data_agreement_v1_record
1546+
1547+
async def publish_data_agreement_in_wallet(self, data_agreement_id: str) -> DataAgreementV1Record:
1548+
"""
1549+
Publish a data agreement in the wallet.
1550+
"""
1551+
1552+
storage: IndyStorage = await self.context.inject(BaseStorage)
1553+
1554+
try:
1555+
# Retrieve the data agreement record
1556+
data_agreement_record: DataAgreementV1Record = await DataAgreementV1Record.retrieve_by_tag_filter(self.context, {
1557+
"data_agreement_id": data_agreement_id,
1558+
"delete_flag": "False"
1559+
})
1560+
1561+
# Check if the data agreement is already published
1562+
if data_agreement_record.published_flag == "True":
1563+
raise ADAManagerError(
1564+
f"Failed to publish data agreement: data agreement with id {data_agreement_id} is already published"
1565+
)
1566+
1567+
# Set the data agreement record to published
1568+
data_agreement_record.published_flag = "True"
1569+
1570+
# Fetch personal data list for proof request
1571+
storage_record = await storage.search_records(
1572+
self.RECORD_TYPE_TEMPORARY_DATA_AGREEMENT_PERSONAL_DATA,
1573+
{"data_agreement_id": data_agreement_id}
1574+
).fetch_single()
1575+
1576+
personal_data_new_list_for_proof_request = json.loads(storage_record.value)
1577+
1578+
# Delete the temporary record
1579+
await storage.delete_record(storage_record)
1580+
1581+
# Generate data agreement model class instance
1582+
data_agreement: DataAgreementV1 = DataAgreementV1Schema().load(data_agreement_record.data_agreement)
1583+
1584+
if data_agreement.method_of_use == DataAgreementV1Record.METHOD_OF_USE_DATA_SOURCE:
1585+
# If method-of-use is "data-source", then create a schema and credential defintion
1586+
1587+
ledger: BaseLedger = await self.context.inject(BaseLedger, required=False)
1588+
if not ledger:
1589+
reason = "No ledger available"
1590+
if not self.context.settings.get_value("wallet.type"):
1591+
reason += ": missing wallet-type?"
1592+
1593+
self._logger.error(
1594+
f"Failed to create data agreement: {reason}")
1595+
1596+
return None
1597+
1598+
issuer: BaseIssuer = await self.context.inject(BaseIssuer)
1599+
1600+
async with ledger:
1601+
try:
1602+
1603+
# Create schema
1604+
1605+
schema_name = data_agreement.usage_purpose
1606+
schema_version = str(semver.VersionInfo(
1607+
str(data_agreement.data_agreement_template_version)))
1608+
attributes = [
1609+
personal_data.attribute_name
1610+
for personal_data in data_agreement.personal_data
1611+
]
1612+
1613+
schema_id, schema_def = await shield(
1614+
ledger.create_and_send_schema(
1615+
issuer, schema_name, schema_version, attributes
1616+
)
1617+
)
1618+
1619+
# Create credential definition
1620+
1621+
tag = "default"
1622+
support_revocation = False
1623+
1624+
(cred_def_id, cred_def, novel) = await shield(
1625+
ledger.create_and_send_credential_definition(
1626+
issuer,
1627+
schema_id,
1628+
signature_type=None,
1629+
tag=tag,
1630+
support_revocation=support_revocation,
1631+
)
1632+
)
1633+
1634+
# Update the data agreement record with schema and credential definition
1635+
data_agreement_record.schema_id = schema_id
1636+
data_agreement_record.cred_def_id = cred_def_id
1637+
1638+
except (IssuerError, LedgerError) as err:
1639+
self._logger.error(
1640+
f"Failed to create data agreement: {err.roll_up}")
1641+
return None
1642+
else:
1643+
# If method-of-use is "data-using-service"
1644+
1645+
# Update data agreement with proof presentation request
1646+
proof_request_dict = await self.construct_proof_presentation_request_dict_from_data_agreement_personal_data(
1647+
personal_data=personal_data_new_list_for_proof_request,
1648+
usage_purpose=data_agreement.usage_purpose,
1649+
usage_purpose_description=data_agreement.usage_purpose_description,
1650+
data_agreement_template_version=str(semver.VersionInfo(
1651+
str(data_agreement.data_agreement_template_version)))
1652+
1653+
)
1654+
1655+
data_agreement_record.data_agreement_proof_presentation_request = proof_request_dict
1656+
1657+
# Save the data agreement record
1658+
await data_agreement_record.save(self.context)
1659+
1660+
return data_agreement_record
1661+
1662+
except (StorageNotFoundError, StorageError) as e:
1663+
raise ADAManagerError(
1664+
f"Failed to publish data agreement: {e}"
1665+
)
15281666

15291667
async def query_data_agreements_in_wallet(self, tag_filter: dict = None) -> typing.List[DataAgreementV1Record]:
15301668
"""
15311669
Query data agreements in the wallet.
15321670
"""
15331671

15341672
try:
1535-
# Add the published_flag tag to the filter
1536-
tag_filter["published_flag"] = "True"
15371673

15381674
# If template_version is provided, then data agreements with that version will be returned
15391675
# published_flag flag is not required for this query

0 commit comments

Comments
 (0)