Beispiel #1
0
    def tasks(self,
              refresh=False,
              include_deleted=False,
              include_done=False,
              include_checked=True,
              include_unchecked=True):
        """Return a remote or chached task list for user."""
        if not self.tasks_list or refresh:
            params = {
                'includeDeleted': str(include_deleted).lower(),
                'includeDone': str(include_done).lower(),
            }

            tasks_data = request.get(url=CONSTANTS.get('TASKS_URL'),
                                     session=self.session(),
                                     params=params)

            self.tasks_list = [
                Task(data_dict=task, user=self) for task in tasks_data
            ]

        return Task.filter_tasks(self.tasks_list,
                                 include_deleted=include_deleted,
                                 include_done=include_done,
                                 include_checked=include_checked,
                                 include_unchecked=include_unchecked)
Beispiel #2
0
    def tasks(self,
              refresh=False,
              include_deleted=False,
              include_done=False,
              include_checked=True,
              include_unchecked=True):
        """Return a remote or chached task list for user."""
        if not self.tasks_list or refresh:
            params = {
                'includeDeleted': str(include_deleted).lower(),
                'includeDone': str(include_done).lower(),
            }

            tasks_data = request.get(
                url=CONSTANTS.get('TASKS_URL'),
                session=self.session(),
                params=params
            )

            self.tasks_list = [Task(data_dict=task, user=self) for task in tasks_data]

        return Task.filter_tasks(self.tasks_list,
                                 include_deleted=include_deleted,
                                 include_done=include_done,
                                 include_checked=include_checked,
                                 include_unchecked=include_unchecked)
Beispiel #3
0
    def get_user(self, refresh=False):
        """Return a user object currently logged in."""
        if not self.user or refresh:
            data = request.get(url=CONSTANTS.get('ME_URL'),
                               session=self.session)

            data.update({'password': self.password})
            self.password = None
            self.user = User(data_dict=data, session=self.session)

        return self.user
Beispiel #4
0
    def get_user(self, refresh=False):
        """Return a user object currently logged in."""
        if not self.user or refresh:
            data = request.get(
                url=CONSTANTS.get('ME_URL'),
                session=self.session
            )

            data.update({'password': self.password})
            self.password = None
            self.user = User(data_dict=data, session=self.session)

        return self.user
Beispiel #5
0
    def create_user(cls, **fields):
        """Create new user by required parameters."""
        User.check_for_missed_fields(fields)

        json_data = {
            'name': fields.get('name'),
            'username': fields.get('email'),
            'password': fields.get('password'),
            'emails': fields.get('emails', fields.get('email')),
            'phoneNumbers': fields.get('phone_numbers', [])
        }

        request.post(url=CONSTANTS.get('USER_URL'), json=json_data)

        user = Client(email=fields.get('email'),
                      password=fields.get('password')).get_user()
        return user
Beispiel #6
0
    def create_user(cls, **fields):
        """Create new user by required parameters."""
        User.check_for_missed_fields(fields)

        json_data = {
            'name': fields.get('name'),
            'username': fields.get('email'),
            'password': fields.get('password'),
            'emails': fields.get('emails', fields.get('email')),
            'phoneNumbers': fields.get('phone_numbers', [])
        }

        request.post(
            url=CONSTANTS.get('USER_URL'),
            json=json_data
        )

        user = Client(email=fields.get('email'), password=fields.get('password')).get_user()
        return user
Beispiel #7
0
    def categories(self, refresh=False, include_deleted=False):
        """Return a remote or cached categories list for user."""
        if not self.categories_list or refresh:
            params = {
                'includeDeleted': str(include_deleted).lower(),
            }

            categories_data = request.get(url=CONSTANTS.get('CATEGORIES_URL'),
                                          session=self.session(),
                                          params=params)

            self.categories_list = [
                Category(data_dict=category, user=self)
                for category in categories_data
            ]

        result = self.categories_list
        if not include_deleted:
            result = [cat for cat in result if not cat['isDeleted']]

        return result
Beispiel #8
0
    def __log_in(self, email, password):
        """
        Authentication base on `email` and `password`.

        Return an actual session, used internally for all following requests to API.
        """
        credentials = {
            'j_username': email,
            'j_password': password,
            '_spring_security_remember_me': 'on'
        }

        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        self.session = requests.Session()

        request.post(url=CONSTANTS.get('LOGIN_URL'),
                     session=self.session,
                     headers=headers,
                     data=credentials,
                     response_json=False)

        return self.session
Beispiel #9
0
    def categories(self, refresh=False, include_deleted=False):
        """Return a remote or cached categories list for user."""
        if not self.categories_list or refresh:
            params = {
                'includeDeleted': str(include_deleted).lower(),
            }

            categories_data = request.get(
                url=CONSTANTS.get('CATEGORIES_URL'),
                session=self.session(),
                params=params
            )

            self.categories_list = [
                Category(data_dict=category, user=self) for category in categories_data
            ]

        result = self.categories_list
        if not include_deleted:
            result = [cat for cat in result if not cat['isDeleted']]

        return result
Beispiel #10
0
    def __log_in(self, email, password):
        """
        Authentication base on `email` and `password`.

        Return an actual session, used internally for all following requests to API.
        """
        credentials = {
            'j_username': email,
            'j_password': password,
            '_spring_security_remember_me': 'on'
        }

        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        self.session = requests.Session()

        request.post(
            url=CONSTANTS.get('LOGIN_URL'),
            session=self.session,
            headers=headers,
            data=credentials,
            response_json=False
        )

        return self.session
Beispiel #11
0
class User(Resource):
    """
    `User` is the class representing User object.

    It wraps user-related JSON into class instances and
    responsible for user management.
    """

    _endpoint = CONSTANTS.get('ME_URL')
    _reserved_attrs = ('data_dict', 'session_obj', 'is_dirty')
    __alternate_endpoint = CONSTANTS.get('USER_URL')

    def __init__(self, data_dict, session):
        """Constructor for User."""
        super(User, self).__init__(data_dict)
        self.session_obj = session
        self.categories_list = None
        self.tasks_list = None
        self._pending_tasks = None

    def save(self, alternate_endpoint=None):
        """
        Pushe updated attributes to the server.

        If nothing was changed we dont hit the API.
        """
        super(User, self).save(alternate_endpoint=self.get_endpoint())

    def session(self):
        """Shortcut to retrive object session for requests."""
        return self.session_obj

    def destroy(self, alternate_endpoint=None):
        """
        Hit the API to destroy the user.

        Pass a changed alternate endpoint as it is differ from the class one.
        """
        super(User, self).destroy(alternate_endpoint=self.__alternate_endpoint)

    delete = destroy

    def refresh(self, alternate_endpoint=None):
        """
        Reload resource data from remote API.

        Pass a changed alternate endpoint as it is differ from the class one.
        """
        super(User, self).refresh(alternate_endpoint=self.get_endpoint())

    # pylint: disable=too-many-arguments
    def tasks(self,
              refresh=False,
              include_deleted=False,
              include_done=False,
              include_checked=True,
              include_unchecked=True):
        """Return a remote or chached task list for user."""
        if not self.tasks_list or refresh:
            params = {
                'includeDeleted': str(include_deleted).lower(),
                'includeDone': str(include_done).lower(),
            }

            tasks_data = request.get(url=CONSTANTS.get('TASKS_URL'),
                                     session=self.session(),
                                     params=params)

            self.tasks_list = [
                Task(data_dict=task, user=self) for task in tasks_data
            ]

        return Task.filter_tasks(self.tasks_list,
                                 include_deleted=include_deleted,
                                 include_done=include_done,
                                 include_checked=include_checked,
                                 include_unchecked=include_unchecked)

    def categories(self, refresh=False, include_deleted=False):
        """Return a remote or cached categories list for user."""
        if not self.categories_list or refresh:
            params = {
                'includeDeleted': str(include_deleted).lower(),
            }

            categories_data = request.get(url=CONSTANTS.get('CATEGORIES_URL'),
                                          session=self.session(),
                                          params=params)

            self.categories_list = [
                Category(data_dict=category, user=self)
                for category in categories_data
            ]

        result = self.categories_list
        if not include_deleted:
            result = [cat for cat in result if not cat['isDeleted']]

        return result

    def add_task(self, task):
        """Add new task into internal storage."""
        if self.tasks_list:
            self.tasks_list.append(task)
        else:
            self.tasks_list = [task]

    def add_category(self, category):
        """Add new category into internal storage."""
        if self.categories_list:
            self.categories_list.append(category)
        else:
            self.categories_list = [category]

    def default_category(self):
        """Return default category for user if exist."""
        return next((cat for cat in self.categories() if cat.isDefault), None)

    def pending_tasks(self, refresh=False):
        """
        Return a list of dicts representing a pending task that was shared with current user.

        Empty list otherwise.
        """
        if not self._pending_tasks or refresh:
            response_obj = request.get(url=self.get_endpoint() + '/pending',
                                       session=self.session())

            self._pending_tasks = response_obj['pendingTasks']

        return self._pending_tasks or []

    def pending_tasks_ids(self, refresh=False):
        """
        Return a list of pending tasks ids shared with user.

        Empty list otherwise.
        """
        return [task['id'] for task in self.pending_tasks(refresh=refresh)]

    def approve_pending_task(self, pending_task_id=None, pending_task=None):
        """
        Approve pending task via API call.

        Accept pending_task_id or pending_task dict (in format of pending_tasks.
        """
        task_id = pending_task_id or pending_task['id']
        if not task_id:
            raise errors.ModelAttributeError(
                'Eather :pending_task_id or :pending_task argument is required.'
            )

        response_obj = request.post(url=self.get_endpoint() + '/pending/' +
                                    task_id + '/accept',
                                    session=self.session())

        return response_obj

    @staticmethod
    def required_attributes():
        """
        Return a set of required fields for valid user creation.

        This tuple is checked to prevent unnecessary API calls.
        """
        return {'name', 'email', 'password'}
Beispiel #12
0
class Task(Resource):
    """
    `Task` is the class representing user task object.

    It wraps task-related JSON into class instances and responsible for task management.
    """

    _endpoint = CONSTANTS.get('TASKS_URL')
    _reserved_attrs = ('user', 'data_dict', 'is_dirty')

    def __init__(self, data_dict, user):
        """Constructor for Task."""
        super(Task, self).__init__(data_dict)
        self.user = user

    def check(self):
        """
        Mark task as CHECKED.

        Using update functionality under the hood.
        """
        self['status'] = 'CHECKED'
        self.is_dirty = True
        self.save()

    def done(self):
        """
        Mark task as DONE.

        Using update functionality under the hood.
        """
        self['status'] = 'DONE'
        self.save()

    def session(self):
        """Shortcut to retrive user session for requests."""
        return self.user.session()

    def subtasks(self):
        """Return a list with subtasks of current task for same user."""
        return [task for task in self.user.tasks() if task['parentGlobalTaskId'] == self['id']]

    def create_subtask(self, **fields):
        """Create a new tasks from provided fields and makes it an subtask of current one."""
        subtask_attrs = fields.copy()
        subtask_attrs.update({'parentGlobalTaskId': self['id']})
        subtask = Task.create(user=self.user, **subtask_attrs)
        self.user.add_task(subtask)
        return subtask

    def add_subtask(self, subtask):
        """
        Add subtask to current task.

        Change synhronized remotly.
        """
        # Currently we don't support task reassignment from one user to another
        subtask['parentGlobalTaskId'] = self['id']
        subtask.save()

    def notes(self):
        """Return a parsed list of notes for the task."""
        if self.note:
            return [note for note in self.note.split('\n') if note]

        return []

    def add_note(self, text_note):
        """Add a text note to current task.

        Change synhronized remotly.
        """
        note = self['note'] or ''
        if not note.endswith('\n'):
            note = note + '\n'
        self['note'] = note + text_note
        self.save()

    def members(self):
        """
        Return a list of dicts {username:email} representing the task members, including owner.

        If the task is not share returns only owner info.
        """
        objects_list = self['sharedMembers']
        if objects_list:
            return [{member['target']: member['name']} for member in objects_list]

        return [{self.user['email']: self.user['name']}]

    def share_with(self, new_member, message=None):
        """
        Share a task with new member.

        Pushes changes to server.
        Updates task members list and new member tasks list.
        """
        json_data = {
            'invitees': [{'email': new_member['email']}],
            'message': message
        }

        response_obj = request.post(
            url=self.get_endpoint() + '/' + self['id'] + '/share',
            json=json_data,
            session=self.session()
        )

        self.data_dict = response_obj

        return self

    def category(self):
        """Return a category object based mapped to selected task."""
        return next(
            (cat for cat in self.user.categories() if cat['id'] == self['categoryId']),
            None
        )

    def parent(self):
        """Return parent task object for subtask and None for first-level task."""
        return next(
            (task for task in self.user.tasks() if task['id'] == self['parentGlobalTaskId']),
            None
        )

    @staticmethod
    def required_attributes():
        """
        Return a set of required fields for valid task creation.

        This tuple is checked to prevent unnecessary API calls.

        Seems that :id and :title attributes are required for now, where
        :id is set automatically.
        """
        return {'title'}

    @staticmethod
    def filter_tasks(tasks_list, **filters):
        """
        Filter tasks by their status.

        Returns a new filtered list.
        """
        result = tasks_list[:]
        statuses = list(TASK_STATUSES)

        if not filters.get('include_deleted', False):
            statuses.remove('DELETED')
        if not filters.get('include_done', False):
            statuses.remove('DONE')
        if not filters.get('include_checked', False):
            statuses.remove('CHECKED')
        if not filters.get('include_unchecked', False):
            statuses.remove('UNCHECKED')

        result = [task for task in result if task['status'] in statuses]
        return list(result)


    @classmethod
    def _create_callback(cls, resource_json, user):
        """
        Callback method that is called automaticly after each successfull creation via remote API.

        Return an task instance.
        """
        task = cls(data_dict=resource_json[0], user=user)
        user.add_task(task)

        return task
Beispiel #13
0
class Category(Resource):
    """
    `Category` is the class representing user category object.

    It wraps task-related JSON into class instances and
    responsible for categories management.
    """

    _reserved_attrs = ('user', 'data_dict', 'is_dirty')
    _endpoint = CONSTANTS.get('CATEGORIES_URL')

    def __init__(self, data_dict, user):
        """Constructor for Category."""
        super(Category, self).__init__(data_dict)
        self.user = user

    def session(self):
        """Shortcut to retrive user session for requests."""
        return self.user.session()

    def mark_default(self):
        """
        Shortcut to mark a category as default one locally.

        Mark previous default one as not default.
        """
        previous = self.user.default_category()
        previous.default = False
        previous.isDefault = False
        previous.save()

        self['default'] = True
        self['isDefault'] = True
        self.save()
        return self

    def tasks(self):
        """Return a list of the user tasks that belongs to selected category."""
        tasks = self.user.tasks()
        return [task for task in tasks if task.categoryId == self['id']]

    def add_task(self, task):
        """
        Add new task into category.

        Update task and pushes changes remotly.
        """
        task.categoryId = self['id']
        task.save()

    def remove_task(self, task):
        """
        Remove a task from the category and move to default one.

        Updates task and pushes changes remotly.
        If category already default do nothing.
        """
        if task.category()['isDefault']:
            raise errors.ModelError(
                'Can not remove task from default category')

        task.categoryId = self.user.default_category()['id']
        task.save()

    @staticmethod
    def required_attributes():
        """
        Return a set of required fields for valid task creation.

        This tuple is checked to prevent unnecessary API calls.

        Seems that :id and :title attributes are required for now, where
        :id is set automatically.
        """
        return {'name'}

    @classmethod
    def _create_callback(cls, resource_json, user):
        """
        Callback method that is called automaticly after each successfull creation via remote API.

        Return an category instance.
        """
        category = cls(data_dict=resource_json[0], user=user)
        user.add_category(category)
        return category