Skip to content

Commit

Permalink
Merge pull request hyperledger#73 from Indicio-tech/feature/credentia…
Browse files Browse the repository at this point in the history
…l-attachments-issuer

Add supplements and attachments to cred issue message
  • Loading branch information
dbluhm committed Sep 2, 2022
2 parents 03a8991 + fb10e80 commit f647b5e
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 12 deletions.
12 changes: 9 additions & 3 deletions aries_cloudagent/messaging/agent_message.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Agent message base class and schema."""

from collections import OrderedDict
from typing import Mapping, Union
from typing import Mapping, Type, TypeVar, Union
import uuid

from marshmallow import (
Expand Down Expand Up @@ -43,6 +43,9 @@ class AgentMessageError(BaseModelError):
"""Base exception for agent message issues."""


MessageType = TypeVar("MessageType", bound="AgentMessage")


class AgentMessage(BaseModel, BaseMessage):
"""Agent message base class."""

Expand Down Expand Up @@ -418,8 +421,11 @@ def serialize(self, msg_format: DIDCommVersion = DIDCommVersion.v1, **kwargs):

@classmethod
def deserialize(
cls, value: dict, msg_format: DIDCommVersion = DIDCommVersion.v1, **kwargs
):
cls: Type[MessageType],
value: dict,
msg_format: DIDCommVersion = DIDCommVersion.v1,
**kwargs,
) -> MessageType:
"""Return message object deserialized from value in format specified."""
if msg_format is DIDCommVersion.v2:
raise NotImplementedError("DIDComm v2 is not yet supported")
Expand Down
9 changes: 7 additions & 2 deletions aries_cloudagent/messaging/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from abc import ABC
from collections import namedtuple
from typing import Mapping, Union
from typing import Mapping, Type, TypeVar, Union

from marshmallow import Schema, post_dump, pre_load, post_load, ValidationError, EXCLUDE

Expand Down Expand Up @@ -70,6 +70,9 @@ class BaseModelError(BaseError):
"""Base exception class for base model errors."""


ModelType = TypeVar("ModelType", bound="BaseModel")


class BaseModel(ABC):
"""Base model that provides convenience methods."""

Expand Down Expand Up @@ -116,7 +119,9 @@ def Schema(self) -> type:
return self._get_schema_class()

@classmethod
def deserialize(cls, obj, unknown: str = None, none2none: str = False):
def deserialize(
cls: Type[ModelType], obj, unknown: str = None, none2none: str = False
) -> ModelType:
"""
Convert from JSON representation to a model instance.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Credential issue message."""

from typing import Sequence
from typing import Optional, Sequence

from marshmallow import EXCLUDE, fields, validates_schema, ValidationError

Expand All @@ -14,6 +14,7 @@
from ..message_types import CRED_20_ISSUE, PROTOCOL_PACKAGE

from .cred_format import V20CredFormat, V20CredFormatSchema
from .inner.supplement import Supplement, SupplementSchema

HANDLER_CLASS = f"{PROTOCOL_PACKAGE}.handlers.cred_issue_handler.V20CredIssueHandler"

Expand All @@ -30,12 +31,14 @@ class Meta:

def __init__(
self,
_id: str = None,
_id: Optional[str] = None,
*,
replacement_id: str = None,
comment: str = None,
formats: Sequence[V20CredFormat] = None,
credentials_attach: Sequence[AttachDecorator] = None,
replacement_id: Optional[str] = None,
comment: Optional[str] = None,
formats: Optional[Sequence[V20CredFormat]] = None,
credentials_attach: Optional[Sequence[AttachDecorator]] = None,
supplements: Optional[Sequence[Supplement]] = None,
attachments: Optional[Sequence[AttachDecorator]] = None,
**kwargs,
):
"""
Expand All @@ -53,6 +56,8 @@ def __init__(
self.comment = comment
self.formats = list(formats) if formats else []
self.credentials_attach = list(credentials_attach) if credentials_attach else []
self.supplements = supplements or []
self.attachments = attachments or []

def attachment(self, fmt: V20CredFormat.Format = None) -> dict:
"""
Expand Down Expand Up @@ -111,6 +116,19 @@ class Meta:
data_key="credentials~attach",
description="Credential attachments",
)
supplements = fields.Nested(
SupplementSchema,
description="Supplements to the credential",
many=True,
required=False,
)
attachments = fields.Nested(
AttachDecoratorSchema,
many=True,
required=False,
description="Attachments of other data associated with the credential",
data_key="~attach",
)

@validates_schema
def validate_fields(self, data, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from uuid import uuid4
from asynctest import mock as async_mock, TestCase as AsyncTestCase

from ......messaging.decorators.attach_decorator import AttachDecorator
from ......messaging.decorators.attach_decorator import (
AttachDecorator,
AttachDecoratorData,
)
from ......messaging.models.base import BaseModelError

from .....didcomm_prefix import DIDCommPrefix
Expand All @@ -10,6 +14,7 @@
from .. import cred_issue as test_module
from ..cred_format import V20CredFormat
from ..cred_issue import V20CredIssue
from ..inner.supplement import Supplement, SupplementAttribute


class TestV20CredIssue(AsyncTestCase):
Expand Down Expand Up @@ -70,6 +75,10 @@ class TestV20CredIssue(AsyncTestCase):
},
}

ATTACHMENT = AttachDecorator(
ident=str(uuid4()), data=AttachDecoratorData(json_={"test": "value"})
)

CRED_ISSUE = V20CredIssue(
replacement_id="0",
comment="Test",
Expand All @@ -85,6 +94,14 @@ class TestV20CredIssue(AsyncTestCase):
ident="indy",
)
],
supplements=[
Supplement(
type="hashlink-data",
ref=ATTACHMENT.ident,
attrs=[SupplementAttribute(key="field", value="legalName")],
)
],
attachments=[ATTACHMENT],
)

async def test_init_type(self):
Expand Down Expand Up @@ -119,8 +136,17 @@ async def test_deserialize(self):
"""Test deserialization."""
obj = TestV20CredIssue.CRED_ISSUE.serialize()

assert obj["~attach"]
assert obj["~attach"][0]["@id"] == TestV20CredIssue.ATTACHMENT.ident

assert obj["supplements"]
assert obj["supplements"][0]["ref"] == TestV20CredIssue.ATTACHMENT.ident

cred_issue = V20CredIssue.deserialize(obj)
assert type(cred_issue) == V20CredIssue
assert isinstance(cred_issue.attachments, list)
assert cred_issue.attachments
assert isinstance(cred_issue.attachments[0], AttachDecorator)

obj["credentials~attach"][0]["data"]["base64"] = "eyJub3QiOiAiaW5keSJ9"
with self.assertRaises(BaseModelError):
Expand Down

0 comments on commit f647b5e

Please sign in to comment.