<commit_before>from plenum.common.constants import *
from plenum.common.messages.fields import *
from plenum.common.messages.message_base import MessageValidator


class ClientNodeOperationData(MessageValidator):
    schema = (
        (NODE_IP, NetworkIpAddressField(optional=True)),
        (NODE_PORT, NetworkPortField(optional=True)),
        (CLIENT_IP, NetworkIpAddressField(optional=True)),
        (CLIENT_PORT, NetworkPortField(optional=True)),
        (ALIAS, NonEmptyStringField()),
        (SERVICES, IterableField(ChooseField(values=(VALIDATOR,)), optional=True)),
    )

    def _validate_message(self, dct):
        # TODO: make ha fields truly optional (needs changes in stackHaChanged)
        required_ha_fields = {NODE_IP, NODE_PORT, CLIENT_IP, CLIENT_PORT}
        ha_fields = {f for f in required_ha_fields if f in dct}
        if ha_fields and len(ha_fields) != len(required_ha_fields):
            self._raise_missed_fields(*list(required_ha_fields - ha_fields))


class ClientNodeOperation(MessageValidator):
    schema = (
        (TXN_TYPE, ConstantField(NODE)),
        (DATA, ClientNodeOperationData()),
        (TARGET_NYM, DestNodeField()),
        (VERKEY, VerkeyField(optional=True)),
    )


class ClientNYMOperation(MessageValidator):
    schema = (
        (TXN_TYPE, ConstantField(NYM)),
        (ALIAS, NonEmptyStringField(optional=True)),
        (VERKEY, VerkeyField(optional=True)),
        (TARGET_NYM, DestNymField()),
        (ROLE, RoleField(optional=True)),
        # TODO: validate role using ChooseField,
        # do roles list expandable form outer context
    )


class ClientOperationField(MessageValidator):

    operations = {
        NODE: ClientNodeOperation(),
        NYM: ClientNYMOperation(),
    }

    def validate(self, dct):
        """
        Choose a schema for client request operation and validate 
        the operation field. If the schema is not found skips validation. 
        :param dct: an operation field from client request 
        :return: raises exception if invalid request 
        """
        if not isinstance(dct, dict):
            # TODO this check should be in side of the validator not here
            self._raise_invalid_fields('', dct, 'wrong type')
        schema_type = dct.get(TXN_TYPE, None)
        if not schema_type:
            self._raise_missed_fields(TXN_TYPE)
        if schema_type in self.operations:
            # check only if the schema is defined
            op = self.operations[schema_type]
            op.validate(dct)


class CatchupOperationField(ClientOperationField):

    def validate(self, dct):
        fields = ["signature", "identifier", "reqId"]
        for field in fields:
            if field not in dct and field != "signature":
                self._raise_missed_fields(field)
            dct.pop(field)
        return super().validate(dct)<commit_msg>update logic in CatchupOperationField<commit_after>from plenum.common.constants import *
from plenum.common.messages.fields import *
from plenum.common.messages.message_base import MessageValidator


class ClientNodeOperationData(MessageValidator):
    schema = (
        (NODE_IP, NetworkIpAddressField(optional=True)),
        (NODE_PORT, NetworkPortField(optional=True)),
        (CLIENT_IP, NetworkIpAddressField(optional=True)),
        (CLIENT_PORT, NetworkPortField(optional=True)),
        (ALIAS, NonEmptyStringField()),
        (SERVICES, IterableField(ChooseField(values=(VALIDATOR,)), optional=True)),
    )

    def _validate_message(self, dct):
        # TODO: make ha fields truly optional (needs changes in stackHaChanged)
        required_ha_fields = {NODE_IP, NODE_PORT, CLIENT_IP, CLIENT_PORT}
        ha_fields = {f for f in required_ha_fields if f in dct}
        if ha_fields and len(ha_fields) != len(required_ha_fields):
            self._raise_missed_fields(*list(required_ha_fields - ha_fields))


class ClientNodeOperation(MessageValidator):
    schema = (
        (TXN_TYPE, ConstantField(NODE)),
        (DATA, ClientNodeOperationData()),
        (TARGET_NYM, DestNodeField()),
        (VERKEY, VerkeyField(optional=True)),
    )


class ClientNYMOperation(MessageValidator):
    schema = (
        (TXN_TYPE, ConstantField(NYM)),
        (ALIAS, NonEmptyStringField(optional=True)),
        (VERKEY, VerkeyField(optional=True)),
        (TARGET_NYM, DestNymField()),
        (ROLE, RoleField(optional=True)),
        # TODO: validate role using ChooseField,
        # do roles list expandable form outer context
    )


class ClientOperationField(MessageValidator):

    operations = {
        NODE: ClientNodeOperation(),
        NYM: ClientNYMOperation(),
    }

    def validate(self, dct):
        """
        Choose a schema for client request operation and validate 
        the operation field. If the schema is not found skips validation. 
        :param dct: an operation field from client request 
        :return: raises exception if invalid request 
        """
        if not isinstance(dct, dict):
            # TODO this check should be in side of the validator not here
            self._raise_invalid_fields('', dct, 'wrong type')
        schema_type = dct.get(TXN_TYPE, None)
        if not schema_type:
            self._raise_missed_fields(TXN_TYPE)
        if schema_type in self.operations:
            # check only if the schema is defined
            op = self.operations[schema_type]
            op.validate(dct)


class CatchupOperationField(ClientOperationField):

    def validate(self, dct):
        fields = [
            ("signature", True),
            ("identifier", True),
            ("reqId", True),
        ]

        dct = dct.copy()
        for field in fields:
            field, optional = field

            if field in dct:
                dct.pop(field)
            elif not optional:
                self._raise_missed_fields(field)


        return super().validate(dct)

{'fraction_non_alphanumeric': 0.09330183904167369, 'fraction_numerical': 0.0, 'mean_word_length': 2.8, 'pattern_counts': {'":': 1, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1676556', 'n_tokens_mistral': 1659, 'n_tokens_neox': 1618, 'n_words': 423}