コード例 #1
0
ファイル: base.py プロジェクト: tbrodbeck/toggl-cli
    def save(self, config=None):  # type: (utils.Config) -> None
        """
        Main method for saving the entity.

        If it is a new entity (eq. entity.id is not set), then calling this method will result in creation of new object using POST call.
        If this is already existing entity, then calling this method will result in updating of the object using PUT call.

        For updating the entity, only changed fields are sent (this is tracked using self.__change_dict__).

        Before the API call validations are performed on the instance and only after successful validation, the call is made.

        :raises exceptions.TogglNotAllowedException: When action (create/update) is not allowed.
        """
        if not self._can_update and self.id is not None:
            raise exceptions.TogglNotAllowedException('Updating this entity is not allowed!')

        if not self._can_create and self.id is None:
            raise exceptions.TogglNotAllowedException('Creating this entity is not allowed!')

        config = config or self._config

        self.validate()

        if self.id is not None:  # Update
            utils.toggl('/{}/{}'.format(self.get_url(), self.id), 'put', self.json(update=True), config=config)
            self.__change_dict__ = {}  # Reset tracking changes
        else:  # Create
            data = utils.toggl('/{}'.format(self.get_url()), 'post', self.json(), config=config)
            self.id = data['data']['id']  # Store the returned ID
コード例 #2
0
    def __set__(self, instance, value):  # type: (base.Entity, T) -> None
        """
        Main TogglField's method that defines how the value of the field is stored in the TogglEntity's instance.

        :raises RuntimeError: If the field does not have 'name' attribute set.
        :raises exceptions.TogglNotAllowedException: If the field does not support write operation or is only available
                only for admin's and the user does not have admin role in the assigned Workspace.
        :raises TypeError: If the value to be set is of wrong type.
        """
        if not self.name:
            raise RuntimeError('Name of the field is not defined!')

        if not self.write:
            raise exceptions.TogglNotAllowedException(
                'You are not allowed to write into \'{}\' attribute!'.format(
                    self.name))

        if self.admin_only or self.premium:
            from .models import WorkspacedEntity, Workspace
            workspace = instance.workspace if isinstance(
                instance, WorkspacedEntity) else instance

            if self.admin_only and not workspace.admin:
                raise exceptions.TogglNotAllowedException(
                    'You are trying edit field \'{}.{}\' which is admin only field, '
                    'but you are not an admin in workspace \'{}\'!'.format(
                        instance.__class__.__name__, self.name,
                        workspace.name))

            if self.premium and not workspace.premium:
                raise exceptions.TogglPremiumException(
                    'You are trying to edit field \'{}.{}\' which is premium only field, '
                    'but the associated workspace \'{}\' is not premium!'.
                    format(instance.__class__.__name__, self.name,
                           workspace.name))

        if value is None:
            if not self.required:
                self._set_value(instance, value)
                return
            else:
                raise TypeError(
                    'Field \'{}\' is required! None value is not allowed!'.
                    format(self.name))

        try:
            value = self.parse(value, instance)
        except ValueError:
            raise TypeError('Expected for field \'{}\' type {} got {}'.format(
                self.name, self._field_type, type(value)))

        self._set_value(instance, value)
コード例 #3
0
    def __set__(self, instance, value):
        if not self.name:
            raise RuntimeError('Name of the field is not defined!')

        if not self.write:
            raise exceptions.TogglException(
                'You are not allowed to write into \'{}\' attribute!'.format(
                    self.name))

        if self.admin_only:
            from .models import WorkspacedEntity, Workspace
            workspace = instance.workspace if isinstance(
                instance, WorkspacedEntity) else instance  # type: Workspace
            if not workspace.admin:
                raise exceptions.TogglNotAllowedException(
                    'You are trying edit field \'{}.{}\' which is admin only field, '
                    'but you are not an admin in workspace \'{}\'!'.format(
                        instance.__class__.__name__, self.name,
                        workspace.name))

        has_updated_state = self.setter(self.name, instance, value, init=False)

        if not isinstance(has_updated_state, bool):
            raise TypeError('Setter must return bool!')

        if has_updated_state is True:
            instance.__change_dict__[self.name] = value
コード例 #4
0
ファイル: base.py プロジェクト: tbrodbeck/toggl-cli
    def filter(self, order='asc', config=None, contain=False, **conditions):  # type: (str, utils.Config, bool, **typing.Any) -> typing.List[Entity]
        """
        Method that fetches all entries and filter them out based on specified conditions.

        :param order: Strings 'asc' or 'desc' which specifies how the results will be sorted (
        :param config: Config instance
        :param contain: Specify how evaluation of conditions is performed. If True condition is evaluated using 'in' operator, otherwise hard equality (==) is enforced.
        :param conditions: Dict of conditions to filter the results. It has structure 'name of property' => 'value'
        """
        config = config or utils.Config.factory()

        if self.entity_cls is None:
            raise exceptions.TogglException('The TogglSet instance is not binded to any TogglEntity!')

        if not self.can_get_list:
            raise exceptions.TogglNotAllowedException('Entity {} is not allowed to fetch list from the API!'
                                            .format(self.entity_cls))

        url = self.build_list_url('filter', config, conditions)
        fetched_entities = self._fetch_all(url, order, config)

        if fetched_entities is None:
            return []

        # There are no specified conditions ==> return all
        if not conditions:
            return fetched_entities

        return [entity for entity in fetched_entities if evaluate_conditions(conditions, entity, contain)]
コード例 #5
0
    def all(
        self,
        order='asc',
        config=None,
        **kwargs
    ):  # type: (str, utils.Config, **typing.Any) -> typing.List[Entity]
        """
        Method that fetches all entries and deserialize them into instances of the binded entity.

        :param order: Strings 'asc' or 'desc' which specifies how the results will be sorted.
        :param config: Config instance
        :raises exceptions.TogglNotAllowedException: When retrieving a list of objects is not allowed.
        """
        if self.entity_cls is None:
            raise exceptions.TogglException(
                'The TogglSet instance is not binded to any TogglEntity!')

        if not self.can_get_list:
            raise exceptions.TogglNotAllowedException(
                'Entity {} is not allowed to fetch list from the API!'.format(
                    self.entity_cls))

        config = config or utils.Config.factory()
        url = self.build_list_url('all', config, kwargs)

        return self._fetch_all(url, order, config)
コード例 #6
0
ファイル: base.py プロジェクト: tbrodbeck/toggl-cli
    def delete(self, config=None):  # type: (utils.Config) -> None
        """
        Method for deletion of the entity through API using DELETE call.

        This will not delete the instance's object in Python, therefore calling save() method after deletion will
        result in new object created using POST call.

        :raises exceptions.TogglNotAllowedException: When action is not allowed.
        """
        if not self._can_delete:
            raise exceptions.TogglNotAllowedException('Deleting this entity is not allowed!')

        if not self.id:
            raise exceptions.TogglException('This instance has not been saved yet!')

        utils.toggl('/{}/{}'.format(self.get_url(), self.id), 'delete', config=config or self._config)
        self.id = None  # Invalidate the object, so when save() is called after delete a new object is created
コード例 #7
0
    def __get__(
            self, instance,
            owner):  # type: (typing.Optional['base.Entity'], typing.Any) -> T
        """
        Main TogglField's method that defines how the value of the field is retrieved from TogglEntity's instance.

        :raises RuntimeError: If the field does not have 'name' attribute set.
        :raises AttributeError: If the instance does not have set the corresponding attribute.
        :raises exceptions.TogglNotAllowedException: If read is not supported by the field
        """
        if not self.name:
            raise RuntimeError('Name of the field is not defined!')

        if not self.read and not self._has_value(instance):
            raise exceptions.TogglNotAllowedException(
                'You are not allowed to read from \'{}\' attribute!'.format(
                    self.name))

        # When instance is None, then the descriptor as accessed directly from class and not its instance
        # ==> return the descriptors instance.
        if instance is None:
            return self

        return self._get_value(instance)