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 __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()
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)
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()
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()
def __init__(self): BaseRedisRepository.__init__(self) self.__tasks_repository = RedisTaskRepository()
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")