Example #1
0
def ret_task(update, context):
    """Return task to the vacant pool"""
    user_data = context.user_data
    if 'chat id' in user_data:
        chat_id = user_data['chat id']
    else:
        chat_id = update.message.chat.id
    user_id = update.message.from_user.id
    try:
        handler = db_connector.DataBaseConnector()
        task_id = user_data['task id']
        success = handler.rem_worker(task_id, chat_id, user_id)
    except (ValueError, ConnectionError):
        update.message.reply_text(_ERR_MSG,
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
        _LOGGER.exception('Unable to return task to the vacant pool')
        return end_conversation(update, context)

    if not success:
        update.message.reply_text('Вы не можете отказаться от этой задачи',
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
    else:
        update.message.reply_text('Вы отказались от задачи',
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
    return end_conversation(update, context)
Example #2
0
def rem_deadline(update, context):
    """Removes task deadline"""
    user_data = context.user_data
    if 'chat id' in user_data:
        chat_id = user_data['chat id']
    else:
        chat_id = update.message.chat.id
    user_id = update.message.from_user.id
    try:
        task_id = user_data['task id']
        handler = db_connector.DataBaseConnector()
        success = handler.set_deadline(task_id, chat_id, user_id)
    except (ValueError, ConnectionError):
        update.message.reply_text(_ERR_MSG,
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
        _LOGGER.exception('Unable to remove task deadline')
        return end_conversation(update, context)
    if not success:
        update.message.reply_text(
            'Вы не можете изменить срок выполнения для этой задачи',
            disable_notification=True,
            reply_markup=ReplyKeyboardRemove())
    else:
        update.message.reply_text('Срок выполнения отменен',
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
    return end_conversation(update, context)
Example #3
0
def update_deadline(update, context):
    """Updates task deadline"""
    handler = db_connector.DataBaseConnector()
    user_id = update.message.from_user.id
    user_data = context.user_data
    try:
        task_id = user_data['task id']
        task_info = handler.task_info(task_id)

        success = (task_info['creator_id'] == user_id
                   or user_id in task_info['workers']
                   or not task_info['workers'])
    except (ValueError, ConnectionError, KeyError):
        update.message.reply_text(_ERR_MSG,
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
        _LOGGER.exception('Unable to update deadline')
        return end_conversation(update, context)

    if not success:
        update.message.reply_text(
            'Вы не можете установить срок '
            'для этой задачи',
            disable_notification=True,
            reply_markup=ReplyKeyboardRemove())
    else:
        update.message.reply_text(
            'Пожалуйста, выберите дату',
            reply_markup=calendar_keyboard.create_calendar())
        return CHOOSING_DL_DATE
Example #4
0
def take_task(update, context):
    """Assign task to the current user"""
    user_id = update.message.from_user.id
    user_data = context.user_data
    if 'chat id' in user_data:
        chat_id = user_data['chat id']
    else:
        chat_id = update.message.chat.id
    try:
        handler = db_connector.DataBaseConnector()
        task_id = user_data['task id']
        success = handler.assign_task(task_id, chat_id, user_id, [user_id])
    except (ValueError, ConnectionError):
        update.message.reply_text(_ERR_MSG,
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
        _LOGGER.exception('Unable to add worker')
        return end_conversation(update, context)

    if not success:
        update.message.reply_text('Вы не можете взять эту задачу',
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
    else:
        update.message.reply_text('Задача взята на исполнение',
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
    return end_conversation(update, context)
Example #5
0
def close_task(update, context):
    """Mark the task as closed"""
    handler = db_connector.DataBaseConnector()
    user_id = update.message.from_user.id
    user_data = context.user_data
    if 'chat id' in user_data:
        chat_id = user_data['chat id']
    else:
        chat_id = update.message.chat.id
    try:
        admin = user_id in update.message.bot.get_chat_administrators(chat_id)
    except TelegramError:
        admin = False
    try:
        task_id = user_data['task id']
        success = handler.close_task(task_id, chat_id, user_id, admin)
    except (ValueError, ConnectionError):
        update.message.reply_text(_ERR_MSG,
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
        _LOGGER.exception('Unable to close task')
        return end_conversation(update, context)
    if not success:
        update.message.reply_text('Вы не можете закрыть эту задачу',
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
    else:
        update.message.reply_text('Задача успешно закрыта',
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
    return end_conversation(update, context)
Example #6
0
def get_list(update, context, for_user=False, free_only=False):
    """Sends the task list"""
    chat = update.message.chat
    user_id = update.message.from_user.id

    if for_user and user_id != chat.id:
        msg = 'Список Ваших задач доступен в личном диалоге'
        update.message.reply_text(msg)
        return

    try:
        handler = db_connector.DataBaseConnector()
        if for_user:
            rows = handler.get_user_tasks(user_id)
        else:
            rows = handler.get_tasks(chat.id, free_only=free_only)
    except (ValueError, ConnectionError):
        update.message.reply_text(_ERR_MSG, disable_notification=True)
        _LOGGER.exception('Unable to get list of tasks')
        return

    if not rows:
        resp_text = 'Ваш список задач пуст!'
        update.message.bot.send_message(chat_id=chat.id,
                                        text=resp_text,
                                        disable_notification=True)
        return

    tasks_lst = _compile_list(rows,
                              chat,
                              update.message.bot,
                              for_user=for_user)
    context.chat_data['pages'] = tasks_lst
    context.chat_data['page ind'] = 0
    if len(tasks_lst) > 1:
        r_nav = 'nav:r'
        r_text = '>>'
    else:
        r_nav = 'nav:-'
        r_text = '  '
    cl_nav = 'nav:cl'
    keyboard = [[
        InlineKeyboardButton('  ', callback_data='-'),
        InlineKeyboardButton('Закрыть', callback_data=cl_nav),
        InlineKeyboardButton(r_text, callback_data=r_nav)
    ]]
    markup = InlineKeyboardMarkup(keyboard)
    _clean_msg(update, context, keys=('rem lst', ))
    msg = update.message.bot.send_message(chat_id=chat.id,
                                          text=tasks_lst[0],
                                          parse_mode=ParseMode.HTML,
                                          disable_web_page_preview=True,
                                          disable_notification=True,
                                          reply_markup=markup)
    context.chat_data['rem lst'] = {msg.message_id}
Example #7
0
def deadline_cal_handler(update, context):
    selected, full_date, update.message = \
        calendar_keyboard.process_calendar_selection(update, context)

    if selected:
        user_data = context.user_data
        if 'chat id' in user_data:
            chat_id = user_data['chat id']
        else:
            chat_id = update.message.chat.id

        user_id = update.callback_query.from_user.id

        full_date = full_date.replace(hour=23, minute=59, second=59)
        full_date = DEF_TZ.localize(full_date)
        try:
            handler = db_connector.DataBaseConnector()
            task_id = user_data['task id']
            success = handler.set_deadline(task_id, chat_id, user_id,
                                           full_date)
            del user_data['task id']
        except (ValueError, ConnectionError, KeyError):
            update.message.reply_text(_ERR_MSG,
                                      disable_notification=True,
                                      reply_markup=ReplyKeyboardRemove())
            _LOGGER.exception('Unable to add task')
            return end_conversation(update, context)

        if not success:
            msg = 'Вы не можете установить срок для этой задачи'
            update.message.reply_text(msg,
                                      disable_notification=True,
                                      reply_markup=ReplyKeyboardRemove())
            return end_conversation(update, context)
        else:
            user_data['deadline'] = full_date
            user_data['dl task'] = task_id
            update.message.bot.delete_message(update.message.chat.id,
                                              update.message.message_id)
            user_name = update.callback_query.from_user.username
            msg = (f'@{user_name}, Вы выбрали дату '
                   f'{full_date.strftime("%d/%m/%Y")}\n'
                   'Для уточнения времени отправьте его в формате "hh:mm" '
                   'в ответном сообщении')
            update.message.bot.sendMessage(
                update.message.chat.id,
                msg,
                disable_notification=True,
                reply_markup=ForceReply(selective=True))
            return TYPING_DL_TIME
Example #8
0
def add_task(update, context):
    """Adds new task to the list"""
    chat_id = update.message.chat.id
    creator_id = update.message.from_user.id
    msg_text = update.message.text.strip()
    if not msg_text:
        update.message.reply_text('Вы не можете добавить пустую задачу')
        return end_conversation(update, context)
    try:
        handler = db_connector.DataBaseConnector()
        task_id = handler.add_task(chat_id, creator_id, msg_text)
        context.user_data['task id'] = task_id
    except (ValueError, ConnectionError):
        update.message.reply_text(_ERR_MSG,
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
        _LOGGER.exception('Unable to add task')
        return end_conversation(update, context)
    update.message.reply_text('Задача успешно добавлена.\n'
                              f'Управление доступно по команде /act_{task_id}')
    return act_task(update, context, newly_created=True)
Example #9
0
def set_marked_status(update, context):
    user_data = context.user_data
    if 'chat id' in user_data:
        chat_id = user_data['chat id']
    else:
        chat_id = update.message.chat.id
    user_id = update.message.from_user.id
    try:
        task_id = user_data['task id']
        handler = db_connector.DataBaseConnector()
        marked = not handler.task_info(task_id)['marked']
        success = handler.set_marked_status(task_id, chat_id, user_id, marked)
    except (ValueError, ConnectionError):
        update.message.reply_text(_ERR_MSG,
                                  disable_notification=True,
                                  reply_markup=ReplyKeyboardRemove())
        _LOGGER.exception('Unable to update task marked status')
        return end_conversation(update, context)
    if not success:
        if marked:
            update.message.reply_text('Вы не можете отметить эту задачу',
                                      disable_notification=True,
                                      reply_markup=ReplyKeyboardRemove())
        else:
            update.message.reply_text(
                'Вы не можете снять отметку '
                'с этой задачи',
                disable_notification=True,
                reply_markup=ReplyKeyboardRemove())
    else:
        if marked:
            update.message.reply_text('Отметка успешно добавлена',
                                      disable_notification=True,
                                      reply_markup=ReplyKeyboardRemove())
        else:
            update.message.reply_text('Отметка успешно удалена',
                                      disable_notification=True,
                                      reply_markup=ReplyKeyboardRemove())
    return end_conversation(update, context)
Example #10
0
def get_dl_time(update, context):
    user_data = context.user_data
    try:
        handler = db_connector.DataBaseConnector()
        chat_id = user_data['chat id']
        user_id = update.message.from_user.id
        task_id = user_data['dl task']
        due_date = user_data['deadline']
        try:
            time = re.search(r'\d{1,2}:\d{2}', update.message.text).group()
            hours = int(time[:time.find(':')].strip())
            minutes = int(time[time.find(':') + 1:].strip())
            due_date = due_date.replace(hour=hours,
                                        minute=minutes,
                                        second=0,
                                        tzinfo=None)
        except (ValueError, AttributeError):
            msg = 'Извините, введенное Вами время не соответствует формату'
            update.message.reply_text(msg, disable_notification=True)
            return end_conversation(update, context)

        due_date = DEF_TZ.localize(due_date)

        success = handler.set_deadline(task_id, chat_id, user_id, due_date)
        if not success:
            update.message.reply_text(
                'Вы не можете установить срок для этой задачи.',
                disable_notification=True)
        else:
            update.message.reply_text('Время выполнения установлено',
                                      disable_notification=True)

    except (ValueError, ConnectionError, AttributeError):
        update.message.reply_text(_ERR_MSG, disable_notification=True)
        _LOGGER.exception('Unable to process task deadline time')
    return end_conversation(update, context)
Example #11
0
def act_task(update, context, newly_created=False):
    handler = db_connector.DataBaseConnector()
    chat_id = update.message.chat.id
    user_id = update.message.from_user.id
    user_data = context.user_data
    try:
        text_task_id = _get_task_id(update.message.text)
        if text_task_id and not newly_created:
            task_id = int(text_task_id)
            user_data['task id'] = task_id
        else:
            task_id = user_data['task id']
        task_info = handler.task_info(task_id)
        user_data['chat id'] = task_info['chat_id']
        task_chat = update.message.bot.get_chat(task_info['chat_id'])

        if task_chat.id != chat_id and user_id not in task_info['workers']:
            update.message.reply_text('Вы не можете управлять этой задачей',
                                      disable_notification=True,
                                      reply_markup=ReplyKeyboardRemove())
            return end_conversation(update, context)

        if task_chat.type == 'private':
            is_admin = False
        else:
            is_admin = user_id in [
                admin.user.id
                for admin in update.message.bot.get_chat_administrators(
                    task_info['chat_id'])
            ]
        buttons = [[]]
        cols = 0
        if (user_id in task_info['workers'] or is_admin
                or task_info['chat_id'] == chat_id and not task_info['workers']
                or task_info['creator_id'] == user_id):
            buttons[-1] += ['Закрыть задачу']
            cols += 1

        if user_id in task_info['workers']:
            cols += 1
            buttons[-1] += ['Отказаться']

        elif task_info['chat_id'] == chat_id and not task_info['workers']:
            if not cols % 2:
                buttons.append([])
            cols += 1
            buttons[-1] += ['Взять']

        if task_info['creator_id'] == user_id or is_admin:
            if task_info['deadline']:
                buttons.append([])
                buttons[-1] += ['Изменить срок']
                buttons[-1] += ['Удалить срок']
                cols = 0
            else:
                if not cols % 2:
                    buttons.append([])
                buttons[-1] += ['Установить срок']
                cols += 1

            if not cols % 2:
                buttons.append([])
            if task_info['marked']:
                buttons[-1] += ['Снять отметку']
            else:
                buttons[-1] += ['Отметить']
            cols += 1

        if not cols % 2:
            buttons.append([])
        buttons[-1] += ['Создать напоминание']

        buttons.append([])
        buttons[-1] += ['Покинуть меню']

        markup = ReplyKeyboardMarkup(buttons,
                                     selective=True,
                                     resize_keyboard=True,
                                     one_time_keyboard=True)
        if newly_created:
            msg = 'Вы можете выбрать действие для этой задачи'
        else:
            msg = 'Выберите действие с задачей'

    except (ValueError, ConnectionError, TelegramError, KeyError):
        update.message.reply_text(_ERR_MSG, disable_notification=True)
        log_msg = 'Unable to create task action menu'
        _LOGGER.exception(log_msg)
        return end_conversation(update, context)

    update.message.reply_text(msg,
                              reply_markup=markup,
                              disable_notification=True)
    return CHOOSING_COMMAND
Example #12
0
def _compile_list(rows, chat, bot, for_user=False):
    """
    Creates list of task pages for the chat
    :raises TelegramError if some chat does not exist
    :raises Value error if rows are corrupted
    :returns List of strings with task info
    """
    lines_lim = 20
    line_len = 30
    task_lst = ['']
    cur_lines = 0
    for row in (sorted(rows, key=_row_sort_key)):
        task_chat_id = row['chat_id'] if 'chat_id' in row else chat.id
        resp_text = ''
        task_lines = 0
        task_mark = u'<b>[ ! ]</b> ' if row['marked'] else u'\u25b8 '
        resp_text += f'{task_mark} {html.escape(row["task_text"])}\n\n'
        task_lines += len(resp_text) // line_len
        task_lines += 1 if len(resp_text) % line_len else 0
        if for_user:
            try:
                task_chat = bot.get_chat(task_chat_id)
                if task_chat.title:
                    resp_text += f'<b>Чат:</b> {task_chat.title}\n'
                    task_lines += 1
            except TelegramError:
                _LOGGER.exception('Could not get chat info')

        # Parse workers list
        if row['workers']:
            workers = ''
            for w_id in row['workers']:
                try:
                    w_info = chat.get_member(w_id)
                    f_name = w_info['user']['first_name']
                    l_name = w_info['user']['last_name']
                    username = w_info['user']['username']
                    tg_link = f'https://t.me/{username}'
                    workers += f'<a href="{tg_link}">{l_name} {f_name}</a>\n'
                except TelegramError:  # Worker is no longer in this chat
                    try:
                        handler = db_connector.DataBaseConnector()
                        handler.rem_worker(row['id'], task_chat_id, w_id)
                    except (ValueError, ConnectionError):
                        _LOGGER.exception('Could not remove invalid worker')
            if workers:
                resp_text += f'<b>Исполнитель:</b> {workers}'
                task_lines += 1

        # Localize UTC time
        if row['deadline']:
            dl_format = ' %a %d.%m'
            today = datetime.now(timezone.utc).astimezone(DEF_TZ)
            if today.year != row['deadline'].year:
                dl_format += '.%Y'
            if row['deadline'].second == 0:  # if time is not default
                dl_format += '.%H:%M'
            dl = row['deadline'].astimezone(DEF_TZ).strftime(dl_format)
            resp_text += f'<b>Срок:</b> <code>{dl}</code>\n'
            task_lines += 1

        resp_text += f'<b>Действия:</b>  /act_{row["id"]}\n'
        resp_text += u'-' * 16 + '\n\n'
        task_lines += 2

        if cur_lines and cur_lines + task_lines > lines_lim:
            task_lst.append(resp_text)
            cur_lines = task_lines
        else:
            task_lst[-1] += resp_text
            cur_lines += task_lines
    return task_lst
Example #13
0
 def setUp(self):
     self.db = db_connector.DataBaseConnector()
     self.db._log = MagicMock()
Example #14
0
 def setUpClass(cls):
     cls.db = db_connector.DataBaseConnector()
     cls.db._log = MagicMock()
     cls.chat_id = 1
     cls.user_id = 1
     cls.task_id = cls.db.add_task(cls.chat_id, cls.user_id, 'Test task')