def sending_email_keyboard(teacher_email): markup = types.InlineKeyboardMarkup() button = types.InlineKeyboardButton(text="Написать письмо", callback_data=teacher_email) markup.add(button) return markup
async def save_pills_time_list(callback_query: types.CallbackQuery, state: FSMContext): logger.info(f"user_id={callback_query.from_user.id}") _state = await state.get_data() title = _state.get("title") pill_time_list = _state.get("pill_time_list") db = SingletonClient.get_data_base() user = await db.Users.find_one( {"telegram_id": callback_query.from_user.id}) result = await db.Pills.insert_one({ "title": title, "time_list": pill_time_list, "time_status": [], "user": user.get("_id") }) logger.info( f"save pills user_id={callback_query.from_user.id} " f"insert_one result={result.acknowledged} id={result.inserted_id}") await callback_query.message.edit_reply_markup( reply_markup=types.InlineKeyboardMarkup()) await callback_query.message.answer( "The pill is successfully saved, wait for reminders.") await state.finish() await callback_query.answer()
async def handle_pill_callback_query(callback_query: types.CallbackQuery): """ handle pill callback and let user control it :param callback_query: :return: """ logger.info( f"user_id={callback_query.from_user.id} data={callback_query.data}") pill_id = ObjectId(callback_query.data.split(',')[1]) db = SingletonClient.get_data_base() pill = await db.Pills.find_one({"_id": pill_id}) if not pill: return callback_query.answer("I can't find that pill, sorry.") string = "Title: {}\n".format(pill.get("title")) string += "\nList of times for notifications:" for time in pill.get("time_list"): string += "\n{}".format(time) markup = types.InlineKeyboardMarkup() if not pill.get('paused'): pause_text = "Pause pill" else: pause_text = "Unpause pill" markup.add( types.InlineKeyboardButton( pause_text, callback_data=f"{callback_query.data},pause")) markup.add( types.InlineKeyboardButton( "Delete pill", callback_data=f"{callback_query.data},delete")) await callback_query.message.edit_text(string, reply_markup=markup) await callback_query.answer()
def pills_time_list_markup(pill_time_list: list) -> types.InlineKeyboardMarkup: markup = types.InlineKeyboardMarkup() lst = [] for i, pill_time in enumerate(pill_time_list): if i % 5 == 0: lst.append([ types.InlineKeyboardButton( text=pill_time, callback_data=f"delete-pill-time,{pill_time}") ]) else: lst[i // 5].append( types.InlineKeyboardButton( text=pill_time, callback_data=f"delete-pill-time,{pill_time}")) for row in lst: markup.row(*row) one_more_pill_time_button = types.InlineKeyboardButton( text="Add one more time", callback_data="add-pill-time") save_time_button = types.InlineKeyboardButton( text="Save", callback_data="save-pill-time") markup.row(one_more_pill_time_button, save_time_button) return markup
async def handle_pill_pause_callback_query( callback_query: types.CallbackQuery): """ handle pause pill callback and it from db :param callback_query: :return: """ logger.info( f"user_id={callback_query.from_user.id} data={callback_query.data}") pill_id = ObjectId(callback_query.data.split(',')[1]) db = SingletonClient.get_data_base() pill = await db.Pills.find_one({'_id': pill_id}) if pill.get('paused'): pill_paused = False else: pill_paused = True result = await db.Pills.update_one({'_id': pill.get('_id')}, {'$set': { "paused": pill_paused }}) logger.info(f"pause pill user_id={callback_query.from_user.id} " f"pause result={result.acknowledged}") await callback_query.message.edit_reply_markup( reply_markup=types.InlineKeyboardMarkup()) text = "The pill was successfully " if pill_paused: text += "paused." else: text += "unpaused." await callback_query.message.answer(text) await callback_query.answer()
async def get_coming_subjects_string(min_obj, message: types.Message, user): db = SingletonClient.get_data_base() min_subj = min_obj[0] markup = types.InlineKeyboardMarkup() if message.chat.type == 'private': string = '<b>Ваше ближайшее занятие:</b>\n' else: string = f'<b>Ближайшие занятие для {user["second_name"]} {user["first_name"]}:</b>\n' string += f'{min_subj["title"]}\n' string += f'Аудитория: {min_subj["audience"]}\n' string += f'Когда: {min_obj[1].strftime("<b>%H:%M</b> %d.%m.%Y")}\n' # Прикрепление ссылки на зум. zoom_link = await db.ZoomLinks.find_one({ "date": min_obj[1], "subject_id": min_subj['_id'] }) if zoom_link: string += f"Ссылка на <a href=\"{zoom_link['link']}\">zoom</a>." # if teacher_id := min_subj.get('teacher_id'): # teacher = await db.Teachers.find_one({ # '_id': objectid.ObjectId(teacher_id) # }) # teacher_email = teacher['email'] # button = types.InlineKeyboardButton(text="📧 Написать преподавателю", # callback_data=f'SendEmail,{teacher_email}') # markup.add(button) # кнопка подписки на напоминания button = types.InlineKeyboardButton( text="🔔 Подписаться на напоминания", callback_data=f'SubscribeNotifications,{min_subj["_id"]}') markup.add(button) return string, markup
def get_pills_list_markup(markup: types.InlineKeyboardMarkup(), pills: list) -> types.InlineKeyboardMarkup(): for pill in pills: """ Send inline keyboard callback data: pil,pill_id pil - event list - module name pill_id - in string format '5fb05fee9e1ea634f3eecc73' """ callback_data = 'pil,' callback_data += str(pill['_id']) string = pill['title'][0:15] button = types.InlineKeyboardButton(text=string, callback_data=callback_data) markup.row(button) logger.info(markup) return markup
def sending_file_keyboard(): markup = types.InlineKeyboardMarkup() button = types.InlineKeyboardButton(text="Прикрепить файл", callback_data='attach_file') markup.add(button) button = types.InlineKeyboardButton(text="Завершить", callback_data='send') markup.add(button) return markup
async def choose_action_menu(message: types.Message): string = 'Меню добавления домашнего задания / ссылки на zoom.\nДомашнее задание | Ссылка на zoom | Название | Дата' markup = types.ReplyKeyboardMarkup() markup.add(types.KeyboardButton(text='Выйти')) await message.answer(string, reply_markup=markup) telegram_id = message.from_user.id db = SingletonClient.get_data_base() user = await db.Users.find_one({"telegram_id": telegram_id}) markup = types.InlineKeyboardMarkup() min_obj_list = await get_min_obj_list(user, 0) for obj in min_obj_list: subj = obj[0] string = '' hw = await db.Homework.find_one({ "subject_id": ObjectId(subj['_id']), "date": obj[1] }) if hw: string += '✅ | ' else: string += '❌ | ' zm = await db.ZoomLinks.find_one({ "subject_id": ObjectId(subj['_id']), "date": obj[1] }) if zm: string += '✅ | ' else: string += '❌ | ' string += f"{subj['title']} {obj[1].strftime('%H:%M %d.%m.%Y')}" button = types.InlineKeyboardButton( text=string, callback_data=f'cha,{subj["_id"]},{obj[1]}') markup.add(button) """ callback_data: 1) am - название модуля 2) l, r, n - left, right, none 3) int - номер страницы 4) user_id """ if await get_min_obj_list(user, 1): button_1 = types.InlineKeyboardButton( text="❌", callback_data=f'am,n,0,{user["_id"]}') button_2 = types.InlineKeyboardButton( text="➡️", callback_data=f'am,r,1,{user["_id"]}') markup.row(button_1, button_2) string = 'Список ближайших пар и статус домашнего задания:' await message.answer(string, reply_markup=markup, disable_web_page_preview=True)
def under_event_keyboard(): markup = types.InlineKeyboardMarkup() button = types.InlineKeyboardButton(text="✅ Подтвердить", callback_data='Accept') markup.add(button) button = types.InlineKeyboardButton(text="❌ Начать заново", callback_data='Restart') markup.add(button) return markup
async def handle_pill_arrow_callback_query( callback_query: types.CallbackQuery): """ Handle callback with clicks on left and right buttons Args: callback_query (types.CallbackQuery): """ split_data = callback_query.data.split(',') logger.info(f"user_id={callback_query.from_user.id} data={split_data}") if split_data[1] == 'n': return await callback_query.answer(text='Nothing more...') page = int(split_data[2]) parameter = split_data[3] markup = types.InlineKeyboardMarkup() markup = get_pills_list_markup(markup, await get_pills(page, parameter)) string = "List of your current pills:" # Checks pills on previous page. left_list = await get_pills(page - 1, parameter) if left_list: left_button = types.InlineKeyboardButton( text='⬅️', callback_data=f'pl,l,{page - 1},{parameter}') else: left_button = types.InlineKeyboardButton( text='❌', callback_data=f'pl,n,{page},{parameter}') # Checks pills on next page. right_list = await get_pills(page + 1, parameter) if right_list: right_button = types.InlineKeyboardButton( text='➡️', callback_data=f'pl,r,{page + 1},{parameter}') else: right_button = types.InlineKeyboardButton( text='❌', callback_data=f'pl,n,{page},{parameter}') markup.row(left_button, right_button) _message = await callback_query.message.edit_text(string, reply_markup=markup) await callback_query.answer()
async def took_pill_callback_handler(callback_query: types.CallbackQuery): """ handle took pill callback and update in db :param callback_query: :return: """ db = SingletonClient.get_data_base() split_data = callback_query.data.split(',') pill_id = ObjectId(split_data[1]) t = split_data[2] logger.info(f"user_id={callback_query.from_user.id} pill_id={pill_id}") pill = await db.Pills.find_one({"_id": pill_id}) index = pill.get("time_list").index(t) time_status = pill.get("time_status") if time_status[index]: return await callback_query.answer("I've already processed that time.") time_status[index] = True result = await db.Pills.update_one({"_id": pill_id}, {"$set": { "time_status": time_status }}) logger.info( f"user_id={callback_query.from_user.id} pill_id={pill_id} " f"update_one result={result.acknowledged} time_status={time_status}") good_words = [ "You did a great job!", "Awesome!", "Good for you!", "I hope you feel better." ] await callback_query.message.reply( "I've reminded you to take your medicines! {}".format( good_words[random.randint(0, len(good_words) - 1)])) await callback_query.message.edit_reply_markup( reply_markup=types.InlineKeyboardMarkup()) await callback_query.answer()
async def handle_test(callback_query: types.CallbackQuery): """ Обработчик нажатия на кнопку под сообщением со списком транзакций. Лямбда проверяет, чтобы обрабатывалось только stats кнопки Args: callback_query (types.CallbackQuery): Документация на сайте телеграма """ if callback_query.data.split(',')[1] == 'n': return await callback_query.answer(text='Там больше ничего нет...') split_data = callback_query.data.split(',') page = int(split_data[2]) mention = split_data[3] transactions = await get_transcations(page, mention) string = f"Донаты пользователя {mention}:\n" string += get_transcations_string(transactions) markup = types.InlineKeyboardMarkup() # Проверяет, есть ли транзакции на предыдущих страницах. left_list = await get_transcations(page - 1, mention) if left_list: left_button = types.InlineKeyboardButton( text='⬅️', callback_data=f'stats,l,{page-1},{mention}') else: left_button = types.InlineKeyboardButton( text='❌', callback_data=f'stats,n,{page},{mention}') # Проверяет, есть ли транзакции на следующих страницах. right_list = await get_transcations(page + 1, mention) if right_list: right_button = types.InlineKeyboardButton( text='➡️', callback_data=f'stats,r,{page+1},{mention}') else: right_button = types.InlineKeyboardButton( text='❌', callback_data=f'stats,n,{page},{mention}') markup.row(left_button, right_button) _message = await callback_query.message.edit_text(string, reply_markup=markup, parse_mode='HTML') await callback_query.answer()
async def choose_action(callback_query: types.CallbackQuery, state: FSMContext): db = SingletonClient.get_data_base() subject_id = ObjectId(callback_query.data.split(',')[1]) date = callback_query.data.split(',')[2] subject = await db.Subjects.find_one({'_id': ObjectId(subject_id)}) await state.update_data(subject=subject) await state.update_data(date=date) markup = types.InlineKeyboardMarkup() markup.add( types.InlineKeyboardButton(text='Добавить домашнее задание', callback_data='tp,homework')) markup.add( types.InlineKeyboardButton(text='Добавить ссылку на zoom', callback_data='tp,zoom')) await callback_query.message.edit_text( f'Выберите что вы хотите добавить для <b>{subject["title"]}</b>:', reply_markup=markup) await Menu.choose_action.set()
async def pills_list(message: types.Message): """ Send listable list with pills :param message: :return: """ logger.info(f"/pills user_id={message.from_user.id}") db = SingletonClient.get_data_base() user = await db.Users.find_one({"telegram_id": message.from_user.id}) if not user: await start(message) db = SingletonClient.get_data_base() user = await db.Users.find_one({"telegram_id": message.from_user.id}) markup = types.InlineKeyboardMarkup() """ callback_data: 1) pl - module name 2) l, r, n - left, right, none 3) int - page num 4) user_id """ string = "List of your current pills:" markup = get_pills_list_markup(markup, await get_pills(0, user.get("_id"))) if not await get_pills(0, user.get("_id")): return await message.answer( "You haven't added the pills yet. Try via /new.") left_button = types.InlineKeyboardButton( text='❌', callback_data=f'pl,l,0,{user.get("_id")}') right_list = await get_pills(1, user.get("_id")) if right_list: right_button = types.InlineKeyboardButton( text='➡️', callback_data=f'pl,r,1,{user.get("_id")}') markup.row(left_button, right_button) _message = await message.answer(string, reply_markup=markup)
async def handle_pill_delete_callback_query( callback_query: types.CallbackQuery): """ handle delete pill callback and it from db :param callback_query: :return: """ logger.info( f"user_id={callback_query.from_user.id} data={callback_query.data}") pill_id = ObjectId(callback_query.data.split(',')[1]) db = SingletonClient.get_data_base() result = await db.Pills.delete_many({"_id": pill_id}) logger.info( f"delete pill user_id={callback_query.from_user.id} " f"delete_one result={result.acknowledged} count={result.deleted_count}" ) await callback_query.message.edit_reply_markup( reply_markup=types.InlineKeyboardMarkup()) await callback_query.message.answer("The pill was successfully removed.") await callback_query.answer()
async def stats(message: types.Message): """ Создает сообщение со списком транзакций конкретного пользователя. Уточнить пользователя из таблицы можно вторым параметром (/stats username) """ mention = await get_mention(message) transactions = await get_transcations(0, mention) if transactions is None: return await message.reply('Транзакции этого пользователя не найдены') string = f"Донаты пользователя {mention}:\n" string += get_transcations_string(transactions) markup = types.InlineKeyboardMarkup() """ callback_data: 1) stats - название модуля 2) l, r, n - left, right, none 3) int - номер страницы 4) имя пользователя для поиска в таблице """ left_button = types.InlineKeyboardButton( text='❌', callback_data=f'stats,l,0,{mention}') right_list = await get_transcations(1, mention) if right_list: right_button = types.InlineKeyboardButton( text='➡️', callback_data=f'stats,r,1,{mention}' ) markup.row(left_button, right_button) _message = await message.answer(string, reply_markup=markup, parse_mode='HTML') else: _message = await message.answer(string, parse_mode='HTML')
async def handle_am_callback_query(callback_query: types.CallbackQuery): """ Обработчик нажатия на кнопку под сообщением с ближайшими парами. Лямбда проверяет, чтобы обрабатывалось только y кнопки Args: callback_query (types.CallbackQuery): Документация на сайте телеграма """ split_data = callback_query.data.split(',') if split_data[1] == 'n': return await callback_query.answer(text='Там больше ничего нет...') page = int(split_data[2]) user_id = ObjectId(split_data[3]) db = SingletonClient.get_data_base() user = await db.Users.find_one({"_id": user_id}) min_obj_list = await get_min_obj_list(user, page) markup = types.InlineKeyboardMarkup() for obj in min_obj_list: subj = obj[0] string = '' hw = await db.Homework.find_one({ "subject_id": ObjectId(subj['_id']), "date": obj[1] }) if hw: string += '✅ | ' else: string += '❌ | ' zm = await db.ZoomLinks.find_one({ "subject_id": ObjectId(subj['_id']), "date": obj[1] }) if zm: string += '✅ | ' else: string += '❌ | ' string += f"{subj['title']} {obj[1].strftime('%H:%M %d.%m.%Y')}" button = types.InlineKeyboardButton( text=string, callback_data=f'cha,{subj["_id"]},{obj[1]}') markup.add(button) # Проверяет, есть ли пары на предыдущих страницах. min_obj_list = await get_min_obj_list(user, page - 1) if min_obj_list: left_button = types.InlineKeyboardButton( text='⬅️', callback_data=f'am,l,{page - 1},{user_id}') else: left_button = types.InlineKeyboardButton( text='❌', callback_data=f'am,n,{page},{user_id}') # Проверяет, есть ли пары на следующих страницах. min_obj_list = await get_min_obj_list(user, page + 1) if min_obj_list: right_button = types.InlineKeyboardButton( text='➡️', callback_data=f'am,r,{page + 1},{user_id}') else: right_button = types.InlineKeyboardButton( text='❌', callback_data=f'am,n,{page},{user_id}') markup.row(left_button, right_button) string = 'Список ближайших пар и статус домашнего задания:' _message = await callback_query.message.edit_text( string, reply_markup=markup, parse_mode='HTML', disable_web_page_preview=True) await callback_query.answer()
async def pills_check(): """ Check pills from db every 5 minutes and send notifications if need :return: """ logger.info("pills check started") db = SingletonClient.get_data_base() now = datetime(2021, 1, 1, datetime.now().hour, datetime.now().minute) if now.hour == 0 and now.minute == 0: result = await db.Pills.update_many({}, {"$set": {"time_status": []}}) async for pill in db.Pills.find({"paused": {"$ne": True}}): user = await db.Users.find_one({"_id": ObjectId(pill.get("user"))}) time_status = pill.get("time_status") logger.info(pill) for num, ti in enumerate(pill.get("time_list")): t = time.fromisoformat(ti) t = datetime(2021, 1, 1, t.hour, t.minute) if t > now: continue try: status = time_status[num] except IndexError: status = False time_status.append(False) if status: # if user accept time don't send notification continue _t = datetime(2021, 1, 1, t.hour, t.minute) + timedelta(hours=1) if now > _t: # If more than one hour has elapsed after taking the pill and the person has not taken it time_status[num] = True else: text = "You have to take <b>{}</b> pill at {}.".format( pill.get("title"), ti) markup = types.InlineKeyboardMarkup() markup.add( types.InlineKeyboardButton( "I took 💊", callback_data=f"took,{pill.get('_id')},{ti}")) try: await bot.send_message(user.get("telegram_id"), text=text, reply_markup=markup) except BotBlocked: result = await db.Pills.delete_many( {'user': pill.get("user")}) return logger.info( f"Bot blocked by user user_id={user.get('telegram_id')} pill_id={pill.get('_id')} " f"delete result={result.acknowledged} delete count={result.deleted_count}" ) result = await db.Pills.update_one( {"_id": ObjectId(pill.get("_id"))}, {"$set": { "time_status": time_status }}) logger.info( f"user_id={user.get('telegram_id')} pill_id={pill.get('_id')} " f"update_one result={result.acknowledged} time_status={time_status}" )
ecology_keyboard.add(ecology_but2, ecology_but3) ecology_keyboard.row_width = 1 ecology_keyboard.add(ecology_but4) ##### INLINE-КЛАВИАТУРА ПРИ СООБЩЕНИИ ОБ ЭКО-КУЛЬТУРЕ INLINE_CULTURE_BUT1_TEXT = 'Почему необходима эко-культура?' INLINE_CULTURE_BUT2_TEXT = 'Как формировать эко-культуру?' INLINE_CULTURE_BUT3_TEXT = 'Эко-привычки' CALLBACK_CULTURE_BUT1 = '1' CALLBACK_CULTURE_BUT2 = '2' CALLBACK_CULTURE_BUT3 = '3' inline_culture_but1 = types.InlineKeyboardButton(INLINE_CULTURE_BUT1_TEXT, callback_data=CALLBACK_CULTURE_BUT1) inline_culture_but2 = types.InlineKeyboardButton(INLINE_CULTURE_BUT2_TEXT, callback_data=CALLBACK_CULTURE_BUT2) inline_culture_but3 = types.InlineKeyboardButton(INLINE_CULTURE_BUT3_TEXT, callback_data=CALLBACK_CULTURE_BUT3) inline_culture_keyboard = types.InlineKeyboardMarkup(row_width=1) inline_culture_keyboard.add(inline_culture_but1, inline_culture_but2, inline_culture_but3) necessary_keyboard = types.InlineKeyboardMarkup(row_width=1) necessary_keyboard.add(inline_culture_but2, inline_culture_but3) how_to_form_keyboard = types.InlineKeyboardMarkup(row_width=1) how_to_form_keyboard.add(inline_culture_but1, inline_culture_but3) eco_habits_keyboard = types.InlineKeyboardMarkup(row_width=1) eco_habits_keyboard.add(inline_culture_but1, inline_culture_but2) ##### КНОПКА НАЗАД В МЕНЮ ОБ ЭКОЛОГИИ BACK_TO_ECOLOGY_BUT1_TEXT = 'Назад ↩' back_to_ecology_but1 = types.KeyboardButton(BACK_TO_ECOLOGY_BUT1_TEXT)
def send_keyboard(): markup = types.InlineKeyboardMarkup() button = types.InlineKeyboardButton(text="Отправить", callback_data='send') markup.add(button) return markup