diff --git a/aleph_message/models/__init__.py b/aleph_message/models/__init__.py index 03a377f..33330d7 100644 --- a/aleph_message/models/__init__.py +++ b/aleph_message/models/__init__.py @@ -202,37 +202,43 @@ def check_item_content(cls, v: Optional[str], values) -> Optional[str]: return v @validator("content") - def check_content(cls, v, values): + def check_content(self, v, values): + """Check that the content matches the serialized item_content""" item_type = values["item_type"] - if item_type == ItemType.inline: - try: - item_content = json.loads(values["item_content"]) - except JSONDecodeError: - raise ValueError( - "Field 'item_content' does not appear to be valid JSON" - ) - json_dump = json.loads(v.json()) - for key, value in json_dump.items(): - if value != item_content[key]: - if isinstance(value, list): - for item in value: - if item not in item_content[key]: - raise ValueError( - f"Field 'content.{key}' does not match 'item_content.{key}': {item} != {item_content[key]}" - ) - if isinstance(value, dict): - for item in value.items(): - if item not in item_content[key].items(): - raise ValueError( - f"Field 'content.{key}' does not match 'item_content.{key}': {value} != {item_content[key]}" - ) + if item_type != ItemType.inline: + return v + + try: + item_content = json.loads(values["item_content"]) + except JSONDecodeError: + raise ValueError("Field 'item_content' does not appear to be valid JSON") + json_dump = json.loads(v.json()) + for key, value in json_dump.items(): + if value != item_content[key]: + self._raise_value_error(item_content, key, value) + + @staticmethod + def _raise_value_error(item_content, key, value): + """Raise a ValueError with a message that explains the content/item_content mismatch""" + if isinstance(value, list): + for item in value: + if item not in item_content[key]: raise ValueError( - f"Field 'content.{key}' does not match 'item_content.{key}': {value} != {item_content[key]} or type mismatch ({type(value)} != {type(item_content[key])})" + f"Field 'content.{key}' does not match 'item_content.{key}': {item} != {item_content[key]}" ) - return v + if isinstance(value, dict): + for item in value.items(): + if item not in item_content[key].items(): + raise ValueError( + f"Field 'content.{key}' does not match 'item_content.{key}': {value} != {item_content[key]}" + ) + raise ValueError( + f"Field 'content.{key}' does not match 'item_content.{key}': {value} != {item_content[key]} or type mismatch ({type(value)} != {type(item_content[key])})" + ) @validator("item_hash") def check_item_hash(cls, v: ItemHash, values) -> ItemHash: + """Check that the 'item_hash' matches the 'item_content's SHA256 hash""" item_type = values["item_type"] if item_type == ItemType.inline: item_content: str = values["item_content"] @@ -256,6 +262,7 @@ def check_item_hash(cls, v: ItemHash, values) -> ItemHash: @validator("confirmed") def check_confirmed(cls, v, values): + """Check that 'confirmed' is not True without 'confirmations'""" confirmations = values["confirmations"] if v is True and not bool(confirmations): raise ValueError("Message cannot be 'confirmed' without 'confirmations'") @@ -263,6 +270,7 @@ def check_confirmed(cls, v, values): @validator("time") def convert_float_to_datetime(cls, v, values): + """Converts a Unix timestamp to a datetime object""" if isinstance(v, float): v = datetime.datetime.fromtimestamp(v) assert isinstance(v, datetime.datetime)