@@ -137,6 +137,9 @@ class ADAManager:
137
137
# Record for keeping metadata about data agreement QR codes (client)
138
138
RECORD_TYPE_DATA_AGREEMENT_QR_CODE_METADATA = "data_agreement_qr_code_metadata"
139
139
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
+
140
143
DATA_AGREEMENT_RECORD_TYPE = "dataagreement_record"
141
144
142
145
def __init__ (self , context : InjectionContext ) -> None :
@@ -1390,10 +1393,11 @@ async def process_read_data_agreement_response_message(self, read_data_agreement
1390
1393
except (StorageNotFoundError , StorageDuplicateError ):
1391
1394
pass
1392
1395
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 :
1394
1397
"""
1395
1398
Create and store a data agreement in the wallet.
1396
1399
"""
1400
+ storage : IndyStorage = await self .context .inject (BaseStorage )
1397
1401
1398
1402
personal_data_list = data_agreement .get ("personal_data" , [])
1399
1403
@@ -1445,95 +1449,227 @@ async def create_and_store_data_agreement_in_wallet(self, data_agreement: dict)
1445
1449
method_of_use = data_agreement .method_of_use ,
1446
1450
state = DataAgreementV1Record .STATE_PREPARATION ,
1447
1451
data_agreement = data_agreement .serialize (),
1448
- published_flag = "True"
1452
+ published_flag = "True" if not draft_mode else "False"
1449
1453
)
1450
1454
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
+ )
1453
1465
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 )
1459
1467
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
1462
1471
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?"
1464
1477
1465
- issuer : BaseIssuer = await self .context .inject (BaseIssuer )
1478
+ self ._logger .error (
1479
+ f"Failed to create data agreement: { reason } " )
1466
1480
1467
- async with ledger :
1468
- try :
1481
+ return None
1469
1482
1470
- # Create schema
1483
+ issuer : BaseIssuer = await self . context . inject ( BaseIssuer )
1471
1484
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
+ )
1483
1502
)
1484
- )
1485
1503
1486
- # Create credential definition
1504
+ # Create credential definition
1487
1505
1488
- tag = "default"
1489
- support_revocation = False
1506
+ tag = "default"
1507
+ support_revocation = False
1490
1508
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
+ )
1498
1517
)
1499
- )
1500
1518
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
1504
1522
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"
1511
1529
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 )))
1519
1537
1520
- )
1538
+ )
1521
1539
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
1523
1541
1524
1542
# Save the data agreement record
1525
1543
await data_agreement_v1_record .save (self .context )
1526
1544
1527
1545
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
+ )
1528
1666
1529
1667
async def query_data_agreements_in_wallet (self , tag_filter : dict = None ) -> typing .List [DataAgreementV1Record ]:
1530
1668
"""
1531
1669
Query data agreements in the wallet.
1532
1670
"""
1533
1671
1534
1672
try :
1535
- # Add the published_flag tag to the filter
1536
- tag_filter ["published_flag" ] = "True"
1537
1673
1538
1674
# If template_version is provided, then data agreements with that version will be returned
1539
1675
# published_flag flag is not required for this query
0 commit comments