Beispiel #1
0
 def __init__(self, xmpp_client):
     self.xmpp_client = xmpp_client
     if Config.db_type == Config.DB_TYPE_REDIS:
         from repositories.list_repository import RedisListRepository
         from repositories.task_repository import RedisTaskRepository
         self.__list_repository = RedisListRepository()
         self.__task_repository = RedisTaskRepository()
Beispiel #2
0
 def __init__(self, xmpp_message: Message):
     BaseRouter.__init__(self, xmpp_message)
     if Config.db_type == Config.DB_TYPE_REDIS:
         from repositories.list_repository import RedisListRepository
         from repositories.task_repository import RedisTaskRepository
         self.__list_repository = RedisListRepository()
         self.__task_repository = RedisTaskRepository()
Beispiel #3
0
class ScheduleRouter:
    def __init__(self, xmpp_client):
        self.xmpp_client = xmpp_client
        if Config.db_type == Config.DB_TYPE_REDIS:
            from repositories.list_repository import RedisListRepository
            from repositories.task_repository import RedisTaskRepository
            self.__list_repository = RedisListRepository()
            self.__task_repository = RedisTaskRepository()

    def route(self):
        # TODO: Remove duplicated code between list and schedule router
        current_timestamp = int(datetime.datetime.now().timestamp())
        scheduled_tasks_info = self.__list_repository.get_scheduled_tasks_info(
        )
        for task_info in scheduled_tasks_info:
            for task_id, task_params_str in task_info.items():
                task = self.__task_repository.get_task(task_id)
                task_list = self.__list_repository.get_list(task.list_id)
                for task_str in task_params_str:
                    task_params = json.loads(task_str)
                    for task_timestamp, for_jid in task_params.items():
                        task_timestamp = int(task_timestamp)
                        if current_timestamp > task_timestamp:
                            task_datetime = self.__task_repository.task_local_datetime(
                                task_timestamp)
                            m = Message()
                            m["to"] = for_jid
                            m["body"] = _(
                                "Reminder for task %s from list %s, scheduled to %s"
                            ) % (task.title, task_list.name, task_datetime)
                            m['type'] = "chat"
                            self.xmpp_client.send(m)
                            self.__task_repository.unschedule_task(
                                task, for_jid, task_timestamp)
Beispiel #4
0
class TaskRouter(BaseRouter):

    def __init__(self, xmpp_message: Message):
        BaseRouter.__init__(self, xmpp_message)
        if Config.db_type == Config.DB_TYPE_REDIS:
            from repositories.list_repository import RedisListRepository
            from repositories.task_repository import RedisTaskRepository
            self.__list_repository = RedisListRepository()
            self.__task_repository = RedisTaskRepository()

    @property
    def xmpp_message(self):
        """
        Return the same value
        as in the base class
        :return:
        """
        return super().xmmp_message

    @property
    def reply_message(self):
        return super().reply_message

    def __is_list_contain_only_digits(self, some_list: list) -> bool:
        for i in some_list:
            if not i.isdigit():
                return False
        return True

    def __set_single_task_complete(self, the_list: ListModel, task_sequential_number: int):
        task_number = int(task_sequential_number) - 1
        task = self.__task_repository.get_task_from_list_number(the_list, task_number_in_list=task_number)
        if not task:
            self.add_reply_message(
                _(u"No task #%s found in the %s list") % (task_sequential_number, the_list.name))
            return None
        self.__task_repository.set_task_complete(task)
        self.add_reply_message(_(u"Set task #%s complete") % task_sequential_number)

    def __set_multiple_tasks_complete(self, the_list: ListModel, task_sequential_numbers_list: list):
        print(task_sequential_numbers_list.split(" "))
        try:
            numbers_list_raw = task_sequential_numbers_list.split(" ")
            if not self.__is_list_contain_only_digits(numbers_list_raw):
                self.add_reply_message(
                    _(u"Please send numbers like !3 5 7 if you want to set multiple tasks complete."))
                return None
            numbers_list = list(map(int, numbers_list_raw))
        except ValueError:
            self.add_reply_message(
                _(u"Please send task number or space-separated numbers (i.e. !33) to set task 33 complete."
                  u" See current list tasks with ."))
            return None
        # Reverse sort task numbers to complete tasks from the bottom of the list
        task_sequential_numbers_list_sorted = sorted(numbers_list, reverse=True)
        for task_sequential_number in task_sequential_numbers_list_sorted:
            self.__set_single_task_complete(the_list, task_sequential_number)

    def __set_task_complete_action(self, message):
        the_list = self.__list_repository.get_active(self.current_jid)
        if not the_list:
            self.add_reply_message(
                _(u"No active list found. See lists with .. or choose one by name .<list_name>"))
            return None
        if not message:
            self.add_reply_message(_(u"Text number(s) to comlete task(s) (◔_◔)"))
            return None
        if message.isdigit():
            self.__set_single_task_complete(the_list, message)
        else:
            self.__set_multiple_tasks_complete(the_list, message)

    def __remove_task_action(self, task_sequential_number):
        """
        Removes task number (sequential)
        :param sequential: str Sequential number of task in active list
        :return:
        """
        the_list = self.__list_repository.get_active(self.current_jid)
        if not the_list:
            self.add_reply_message(
                _(u"No active list found. See lists with .. or choose one by name .<list_name>"))
            return None
        if not task_sequential_number.isdigit():
            self.add_reply_message(_(u"Please send task number (i.e. #-33) to delete. See current list tasks with ."))
            return None
        task_number = int(task_sequential_number) - 1
        task = self.__task_repository.get_task_from_list_number(the_list, task_number_in_list=task_number)
        if not task:
            self.add_reply_message(_("uNo task #%s found in the %s list") % (task_sequential_number, the_list.name))
            return None
        self.__task_repository.remove_task(task)
        self.add_reply_message(_(u"Remove task #%s") % task_sequential_number)

    def __add_tasks_multiline_action(self, message):
        the_list = self.__list_repository.get_active(self.current_jid)
        if not the_list:
            self.add_reply_message(
                _(u"No active list found. See lists with .. or choose one by name .<list_name>"))
            return None
        for line in message.splitlines():
            self.__task_repository.add_task(line, the_list)
        self.add_reply_message(_(u"(ʘ‿ʘ)╯ alot of tasks added"))

    def __schedule_task_action(self, message):
        the_list = self.__list_repository.get_active(self.current_jid)
        if not the_list:
            self.add_reply_message(
                _(u"No active list found. See lists with .. or choose one by name .<list_name>"))
            return None
        try:
            task_sequential_number, date_andor_time = message.split(" ", 1)
        except ValueError:
            self.add_reply_message(_(u"No date time provided ٩(͡๏̯͡๏)۶"))
            return None
        if not task_sequential_number.isdigit():
            self.add_reply_message(
                _(u"Please send task number (i.e. #*33) to schedule. See current list tasks with ."))
            return None
        task_number = int(task_sequential_number)-1
        if not date_andor_time:
            self.add_reply_message(_(u"No date time provided ٩(͡๏̯͡๏)۶"))
            return None
        datetime = parse(date_andor_time)
        if not datetime:
            self.add_reply_message(_(u"Error convert date ಠ_ಠ"))
            return None
        timestamp = int(datetime.timestamp())
        task = self.__task_repository.get_task_from_list_number(the_list, task_number)
        if task:
            self.__task_repository.schedule_task(task, self.current_jid, timestamp)
            self.add_reply_message(_(u"⏰ Task #%s scheduled to %s") % (task_sequential_number, datetime))
        else:
            self.add_reply_message(
                _(u"No task #%s found in the %s list") % (task_number, the_list.name))

    def __unschedule_task_action(self, message):
        if not message:
            self.add_reply_message(_(u"٩(͡๏̯͡๏)۶ Please provide task number to unschedule ⏰"))
            return None
        if not message.isdigit():
            self.add_reply_message(_(u"⏰ can unschedule only task number ಠ_ಠ"))
            return None
        task = self.__task_repository.get_task(message)
        self.__task_repository.unschedule_task_at_all(task)


    def __update_task_action(self, message):
        the_list = self.__list_repository.get_active(self.current_jid)
        if not the_list:
            self.add_reply_message(
                _(u"No active list found. See lists with .. or choose one by name .<list_name>"))
            return None
        try:
            task_sequential_number, task_title = message.split(" ", 1)
        except ValueError:
            self.add_reply_message(_(u"No date time provided ٩(͡๏̯͡๏)۶"))
            return None
        if not task_sequential_number.isdigit():
            self.add_reply_message(
                _(u"Please send task number (i.e. #*33) to schedule. See current list tasks with ."))
            return None
        task_number = int(task_sequential_number)-1
        if not task_title:
            self.add_reply_message(_(u"No task provided ٩(͡๏̯͡๏)۶"))
            return None
        task = self.__task_repository.get_task_from_list_number(the_list, task_number)
        task.title = task_title
        self.__task_repository.save_task(task)
        self.add_reply_message(_(u"🖍️ Task %s updated") % task_sequential_number)

    def __move_task_to_list_action(self, message):
        current_list = self.__list_repository.get_active(self.current_jid)
        if not current_list:
            self.add_reply_message(
                _(u"No active list found. See lists with .. or choose one by name .<list_name>"))
            return None
        try:
            task_sequential_number, list_name_to_move = message.split(" ", 1)
        except ValueError:
            self.add_reply_message(_(u"No list name provided ٩(͡๏̯͡๏)۶"))
            return None
        if not task_sequential_number.isdigit():
            self.add_reply_message(
                _(u"Please send task number (i.e. #*33) to schedule. See current list tasks with ."))
            return None
        task_number = int(task_sequential_number) - 1
        if not list_name_to_move:
            self.add_reply_message(_(u"No list name provided ٩(͡๏̯͡๏)۶"))
            return None
        task = self.__task_repository.get_task_from_list_number(current_list, task_number)
        if not task:
            self.add_reply_message(
                _(u"No task #%s found in active list") % task_number)
            return None
        to_list = self.__list_repository.get_list_by_name(list_name_to_move)
        if not to_list:
            self.add_reply_message(_(u"List %s not found") % message)
            return None
        self.__task_repository.move_task(task, to_list)
        self.add_reply_message(
            _(u"➡️ Task %s moved to list %s") % (task_sequential_number, list_name_to_move))

    def __add_task_action(self, message):
        the_list = self.__list_repository.get_active(self.current_jid)
        if not the_list:
            self.add_reply_message(_(u"No active list found. See lists with .. or choose one by name .<list_name>"))
            return None
        self.__task_repository.add_task(message, the_list)
        self.add_reply_message(_(u"Task %s added to list %s") % (message, the_list.name))

    def route(self, message):
        command = self.extract_command(message)
        if command == "!":
            message = self.extract_command_message(command, message)
            self.__set_task_complete_action(message)
        elif command == "-":
            message = self.extract_command_message(command, message)
            self.__remove_task_action(task_sequential_number=message)
        elif command == ":":
            message = self.extract_command_message(command, message)
            if message:
                self.__add_tasks_multiline_action(message)
            else:
                self.add_reply_message(_(u"Text something (◔_◔)"))
        elif command == ">":
            message = self.extract_command_message(command, message)
            if message:
                self.__update_task_action(message)
            else:
                self.add_reply_message(_(u"Text number to edit task (◔_◔)"))
        elif command == "^":
            message = self.extract_command_message(command, message)
            if message:
                self.__move_task_to_list_action(message)
            else:
                self.add_reply_message(_(u"Text number and list to move task (◔_◔)"))
        elif command == "*":
            message = self.extract_command_message(command, message)
            command = self.extract_command(message)
            if command == "-":
                message = self.extract_command_message(command, message)
                self.__unschedule_task_action(message)
            else:
                if message:
                    self.__schedule_task_action(message)
                else:
                    self.add_reply_message(_(u"Text number (◔_◔) to ⏰ the task"))
        else:
            # Get active list and add task to it
            self.__add_task_action(message)
        print(self.reply_message)
        return self.xmpp_message.reply(self.reply_message).send()
Beispiel #5
0
class ListRouter(BaseRouter):
    def __init__(self, xmpp_message: Message):
        BaseRouter.__init__(self, xmpp_message)
        if Config.db_type == Config.DB_TYPE_REDIS:
            from repositories.list_repository import RedisListRepository
            from repositories.task_repository import RedisTaskRepository
            self.__task_repository = RedisTaskRepository()
            self.__list_repository = RedisListRepository()

    @property
    def xmpp_message(self):
        """
        Return the same value
        as in the base class
        :return:
        """
        return super().xmmp_message

    @property
    def reply_message(self):
        return super().reply_message

    def __display_list_tasks_action(self,
                                    the_list,
                                    no_tasks_message,
                                    tasks_type="tasks"):
        list_tasks_of_type = getattr(the_list, tasks_type)
        if not list_tasks_of_type:
            self.add_reply_message(no_tasks_message)
            return None
        for idx, task in enumerate(list_tasks_of_type):
            self.add_reply_message("%i. %s" % (idx + 1, task.title))

    def __display_active_list_action(self):
        the_list = self.__list_repository.get_active(self.current_jid)
        if not the_list:
            self.add_reply_message(
                _(u"No active list found. See lists with .. or choose one by name .<list_name>"
                  ))
            return None
        self.add_reply_message(_(u"Active list is %s") % the_list.name)
        no_tasks_messsage = _(
            u"List is empty. Add task to it by send some message.")
        self.__display_list_tasks_action(the_list, no_tasks_messsage)

    def __display_schedule_list_action(self):
        scheduled_tasks_info = self.__list_repository.get_scheduled_tasks_info(
        )
        if not scheduled_tasks_info:
            self.add_reply_message(_(u"No ⏰ tasks"))
            return None
        for task_info in scheduled_tasks_info:
            for task_id, task_params_str in task_info.items():
                task = self.__task_repository.get_task(task_id)
                for task_str in task_params_str:
                    task_params = json.loads(task_str)
                    for task_timestamp, for_jid in task_params.items():
                        task_timestamp = int(task_timestamp)
                        task_datetime = self.__task_repository.task_local_datetime(
                            task_timestamp)
                        self.add_reply_message(
                            "%s: %s. %s" %
                            (task_datetime, task.id_, task.title))

    def __display_all_list_names_action(self):
        all_list_names = self.__list_repository.get_all_lists_names()
        if not all_list_names:
            self.add_reply_message(
                _(u"No lists. Add one by typing .<list_name>"))
            return None
        self.add_reply_message(_(u"All the lists:"))
        for list_name in all_list_names:
            self.add_reply_message(list_name)

    def __clear_list_tasks_action(self):
        the_list = self.__list_repository.get_active(self.current_jid)
        if not the_list:
            self.add_reply_message(
                _(u"No active list found. See lists with .. or choose one by name .<list_name>"
                  ))
            return None
        self.__list_repository.remove_list_tasks(the_list)
        self.add_reply_message(
            _(u"Clear tasks of the %s list") % the_list.name)

    def __remove_list_action(self, list_name: str):
        if not list_name:
            self.add_reply_message(_(u"Need a list name to delete"))
            return None
        # Delete list and remove from current jid active lists
        result = self.__list_repository.remove_list(list_name)
        if result:
            self.add_reply_message(_(u"Delete list %s") % list_name)
        else:
            self.add_reply_message(_(u"List %s not found") % list_name)

    def __process_list_action(self, list_name: str):
        # Check if list exits
        is_list_exists = self.__list_repository.is_list_exists(list_name)
        # If not add
        if not is_list_exists:
            self.__list_repository.add_list(list_name)
            self.add_reply_message(_(u"Added list %s") % list_name)
        # Set active for current user & display
        self.__list_repository.set_active(list_name, self.current_jid)
        self.__display_active_list_action()

    def __clear_list_completed_taks_action(self, the_list: ListModel):
        self.__list_repository.remove_list_completed_tasks(the_list)
        self.add_reply_message(
            _(u"Clear completed tasks of the %s list") % the_list.name)

    def __display_completed_task_action(self, the_list: ListModel):
        self.add_reply_message(
            _(u"Completed tasks of the %s list:") % the_list.name)
        no_tasks_messsage = _(
            u"No completed tasks for this list. Complete one with !<number>.")
        self.__display_list_tasks_action(the_list, no_tasks_messsage,
                                         "completed_tasks")

    def route(self, message: str):
        if message:
            command = self.extract_command(message)
            if command == ".":
                self.__display_all_list_names_action()
            elif command == '*':
                self.__display_schedule_list_action()
            elif command == "-":
                message = self.extract_command_message(command, message)
                command = self.extract_command(message)
                if command == "-":
                    self.__clear_list_tasks_action()
                else:
                    self.__remove_list_action(message)
            elif command == "!":
                message = self.extract_command_message(command, message)
                command = self.extract_command(message)
                the_list = self.__list_repository.get_active(self.current_jid)
                if not the_list:
                    self.add_reply_message(
                        _(u"No active list found. See lists with .. or choose one by name .<list_name>"
                          ))
                    return None
                # Clear completed tasks
                if command == "-":
                    self.__clear_list_completed_taks_action(the_list)
                # Display completed tasks
                else:
                    self.__display_completed_task_action(the_list)
            else:
                self.__process_list_action(message)
        else:
            # Display active list
            self.__display_active_list_action()

        print(self.reply_message)
        return self.xmpp_message.reply(self.reply_message).send()
Beispiel #6
0
 def __init__(self):
     BaseRedisRepository.__init__(self)
     self.__tasks_repository = RedisTaskRepository()
Beispiel #7
0
class RedisListRepository(BaseRedisRepository):
    def __init__(self):
        BaseRedisRepository.__init__(self)
        self.__tasks_repository = RedisTaskRepository()

    @property
    def redis_connection(self):
        return super().redis_connection

    def __get_id_by_name(self, list_name):
        list_id = self.redis_connection.zscore("lists:names", list_name)
        return int(list_id) if list_id else None

    def __create_id(self):
        return super().create_id("lists:index")

    def __get_list_tasks(self, list_id, tasks_type="tasks"):
        list_tasks_ids = self.redis_connection.lrange(
            "list:%s:%s" % (list_id, tasks_type), 0, -1)
        tasks = []
        for task_id in list_tasks_ids:
            task = self.__tasks_repository.get_task(task_id)
            tasks.append(task)
        return tasks

    def is_list_exists(self, list_name):
        list_id = self.__get_id_by_name(list_name)
        return self.redis_connection.exists("list:%s" % list_id)

    def get_list_by_name(self, list_name):
        list_id = self.__get_id_by_name(list_name)
        return self.get_list(list_id)

    def get_list(self, list_id):
        list_dict = self.redis_connection.hgetall("list:%s" % list_id)
        if not list_dict:
            return None
        the_list = self.unserialize(list_dict, ListModel)
        list_tasks = self.__get_list_tasks(the_list.id_)
        for task in list_tasks:
            the_list.add_task(task)
        list_completed_tasks = self.__get_list_tasks(the_list.id_,
                                                     "tasks:completed")
        for task in list_completed_tasks:
            the_list.add_completed_task(task)
        return the_list

    def get_all_lists_names(self):
        list_names_raw = self.redis_connection.zrange("lists:names", 0, -1)
        return sorted(list_names_raw)

    def add_list(self, list_name):
        """
        Creates list if not exist
        :param list_name: str Name of the list to add
        :return: bool
        """
        list_id = self.__create_id()
        the_list = ListModel(list_id, list_name)
        list_dict = self.serialize(the_list, ["tasks", "completed_tasks"])
        self.redis_connection.zadd("lists:names",
                                   {the_list.name: the_list.id_})
        self.redis_connection.lpush("lists", the_list.id_)
        self.redis_connection.incr("lists:index")
        result = self.redis_connection.hmset("list:%s" % the_list.id_,
                                             list_dict)  # Update list itself
        return result

    def set_active(self, list_name, current_jid):
        if not self.is_list_exists(list_name):
            return False
        list_id = self.__get_id_by_name(list_name)
        transaction = self.redis_connection.pipeline()
        transaction.sadd("list:%s:active_for" % list_id, current_jid)
        transaction.set("%s:active:list" % current_jid, list_id)
        return transaction.execute()

    def get_active(self, current_jid):
        list_id = self.redis_connection.get("%s:active:list" % current_jid)
        return self.get_list(list_id)

    def remove_list_completed_tasks(self, the_list):
        for task in the_list.completed_tasks[:]:  # [:] Iterate over list copy to delete from source list
            self.__tasks_repository.remove_task(task, "tasks:completed")
            the_list.remove_completed_task(task)
        self.redis_connection.delete("list:%s:tasks:completed" % the_list.id_)

    def remove_list_tasks(self, the_list):
        for task in the_list.tasks[:]:  # [:] Iterate over list copy to delete from source list
            self.__tasks_repository.remove_task(task)
            the_list.remove_task(task)
        self.redis_connection.delete("list:%s:tasks" % the_list.id_)

    def remove_list(self, list_name):
        # Remove lists tasks
        the_list = self.get_list_by_name(list_name)
        if not the_list:
            return False
        self.remove_list_tasks(the_list)
        self.remove_list_completed_tasks(the_list)
        list_active_for = self.redis_connection.smembers("list:%s:active_for" %
                                                         the_list.id_)
        # Remove list from active user lists
        transaction = self.redis_connection.pipeline()
        for user_jid in list_active_for:
            transaction.delete("%s:active:list" % user_jid)
        transaction.delete("list:%s:active_for" % the_list.id_)
        # Remove list from indexes and itself
        transaction.lrem("lists", 0, the_list.id_)
        transaction.zrem("lists:names", the_list.name)
        transaction.delete("list:%s" % the_list.id_)
        return transaction.execute()

    def get_scheduled_tasks_info(self):
        scheduled_ids = self.get_scheduled_tasks_ids()
        scheduled_tasks_info = []
        for task_id in scheduled_ids:
            task_info = self.redis_connection.lrange("scheduled:%s" % task_id,
                                                     0, -1)
            scheduled_tasks_info.append({task_id: task_info})
        return scheduled_tasks_info

    def get_scheduled_tasks_ids(self):
        return self.redis_connection.smembers("scheduled")