diff --git a/SpreadsheetsService/models/assignment.py b/SpreadsheetsService/models/assignment.py
index 4c686b3..3d09cb4 100644
--- a/SpreadsheetsService/models/assignment.py
+++ b/SpreadsheetsService/models/assignment.py
@@ -1,13 +1,20 @@
from logging import addLevelName
+import uuid
class Assignment(dict):
"""Задание."""
- def __init__(self, name: str, points: list, weight: float = 1,
- subject: str = None, allow_to_display: bool = False,
- how_to_display: str = 'z,1,1',
- notes: str = 'Замечаний по работе нет.'):
+ def __init__(
+ self,
+ name: str,
+ points: list,
+ weight: float = 1,
+ subject: str = None,
+ allow_to_display: bool = False,
+ how_to_display: str = "z,1,1",
+ notes: str = "Замечаний по работе нет.",
+ ):
self.name = name
self.subject = subject
self.weight = weight
@@ -15,6 +22,7 @@ class Assignment(dict):
self.allow_to_display = allow_to_display
self.how_to_display = how_to_display
self.notes = notes
+ self.uuid = uuid.uuid3(uuid.NAMESPACE_DNS, f"{name}{subject}")
dict.__init__(
self,
name=self.name,
@@ -25,6 +33,7 @@ class Assignment(dict):
allow_to_display=self.allow_to_display,
how_to_display=self.how_to_display,
notes=self.notes,
+ uuid=self.uuid,
)
@property
diff --git a/TelegramBot/bot.py b/TelegramBot/bot.py
index 16be060..ac23889 100644
--- a/TelegramBot/bot.py
+++ b/TelegramBot/bot.py
@@ -27,7 +27,7 @@ TOKEN = Path(".secrets/bot_token.txt").read_text()
MESSAGES = Messages()
HOST = "http://carolyn-spreadsheets:5000"
BROADCAST_MESSAGE, BROADCAST_PUBLISH_DONE = range(2)
-GRADES_CALLBACK = 1
+GRADES_ASSNT, GRADES_VIEW = range(2)
logging.setLoggerClass(TgLogger)
logging.basicConfig(
@@ -77,118 +77,105 @@ def start(update: Update, context: CallbackContext):
)
-def grades(update: Update, context: CallbackContext):
- """Команда: Получить оценки студента."""
+def grades_start(update: Update, context: CallbackContext):
+ """Сообщение 'Выбери дисциплину'.
+ Обновляет текст сообщения и дает клавиатуру с выбором дисциплины.
+ """
user_id = update.message.from_user.id
-
start = time.monotonic()
# Длинная операция, сообщим о запущенном процессе.
look_msg = update.message.reply_html(MESSAGES.Assignments.START)
+
try:
data = requests.get(f"{HOST}/grades", params={"tg_id": user_id}).json()
-
- subjects = data["subjects"]
- assignments = data["assignments"]
-
- if len(subjects) > 1:
- context.user_data["subjects"] = subjects
- context.user_data["all_assignments"] = assignments
- reply_markup = build_menu_of_subjects(subjects)
- msg = update.message.reply_text(
- text=MESSAGES.Assignments.SELECT_COURSE, reply_markup=reply_markup
- )
- else:
- context.user_data["assignments"] = assignments
- reply_markup = build_menu_of_assignments(assignments)
- msg = update.message.reply_text(
- text=MESSAGES.Assignments.SELECT_ASSNT, reply_markup=reply_markup
- )
-
- context.user_data["msg"] = msg
- return_value = GRADES_CALLBACK
-
except:
LOG.exception("Failed to get grades.")
update.message.reply_sticker(MESSAGES.Stickers.DEAD)
- return_value = ConversationHandler.END
- diff = time.monotonic() - start
- look_msg.edit_text(MESSAGES.Assignments.timeit(diff))
- return return_value
-
-
-def callback(update: Update, context: CallbackContext):
-
- call = update.callback_query.data
-
- # Нажатие кнопок при выборе задания
- if call.startswith("assignment#"):
-
- if "$back$" in call:
- subjects = context.user_data["subjects"]
- reply_markup = build_menu_of_subjects(subjects)
- msg = update.callback_query.message.edit_text(
- text=MESSAGES.Assignments.SELECT_COURSE, reply_markup=reply_markup
- )
- context.user_data["msg"] = msg
- return GRADES_CALLBACK
-
- assignments = context.user_data["assignments"]
- name, subject = call.split("#")[1:3]
-
- reply_markup = build_menu_of_assignments(
- assignments, name, has_back_button=context.user_data["has_back_button"]
- )
-
- f = lambda ass: ass["name"] == name and ass["subject"] == subject
- assignment = next(filter(f, assignments))
- msg = update.callback_query.message.edit_text(
- text=MESSAGES.Assignments.get(assignment['name'],
- assignment['points'],
- assignment['how_to_display'],
- assignment['notes']),
- parse_mode=ParseMode.HTML,
- reply_markup=reply_markup
- )
- context.user_data["msg"] = msg
-
- # Нажатие кнопок при выборе дисциплины
- if call.startswith("subject#"):
- all_assignments = context.user_data["all_assignments"]
- subject = call.split("#")[1]
-
- f = lambda ass: ass["subject"] == subject
- assignments = list(filter(f, all_assignments))
- context.user_data["assignments"] = assignments
- context.user_data["has_back_button"] = True
-
- reply_markup = build_menu_of_assignments(assignments, has_back_button=True)
- msg = update.callback_query.message.edit_text(
- MESSAGES.Assignments.SELECT_ASSNT, reply_markup=reply_markup
- )
- context.user_data["msg"] = msg
-
- if call.startswith("cancel#"):
- update.callback_query.message.edit_text(
- MESSAGES.Assignments.END,
- )
return ConversationHandler.END
- return GRADES_CALLBACK
-
-def timeout(update: Update, context: CallbackContext):
- msg = context.user_data["msg"]
- msg.edit_text(
- MESSAGES.Assignments.TIMEOUT,
- )
- return ConversationHandler.END
-
-def grades_end(update: Update, context: CallbackContext):
- msg = context.user_data["msg"]
- msg.edit_text(
- MESSAGES.Assignments.END
+ context.user_data["subjects"] = data["subjects"]
+ context.user_data["assignments"] = data["assignments"]
+ diff = time.monotonic() - start
+ look_msg.edit_text(MESSAGES.Assignments.timeit(diff))
+ update.message.reply_text(
+ MESSAGES.Assignments.SELECT_COURSE,
+ reply_markup=build_menu_of_subjects(data["subjects"]),
)
- return ConversationHandler.END
+ return GRADES_ASSNT
+
+
+def grades_pick_assignment(update: Update, context: CallbackContext):
+ """Сообщение 'Выбери задание'.
+
+ Обновляет текст сообщения и дает клавиатуру с выбором дисциплины.
+ В `callback_query` содержится имя предмета, либо ключевое слово.
+ Может завершить диалог.
+ """
+ query = update.callback_query
+ query.answer()
+ if query.data == "cancel":
+ query.edit_message_text(MESSAGES.Assignments.END, reply_markup=None)
+ return ConversationHandler.END
+ context.user_data["selected_subject"] = query.data
+ assignments = [
+ a for a in context.user_data["assignments"] if a["subject"] == query.data
+ ]
+ query.edit_message_text(
+ MESSAGES.Assignments.SELECT_ASSNT,
+ reply_markup=build_menu_of_assignments(assignments, has_back_button=True),
+ )
+ return GRADES_VIEW
+
+
+def grades_view(update: Update, context: CallbackContext):
+ """Отображение домашки.
+
+ В `callback_query` содержится UUID, идентификатор задания. Либо команда:
+ cancel или back. Может завершить диалог.
+ """
+ query = update.callback_query
+ query.answer()
+
+ if query.data == "cancel":
+ query.edit_message_text(MESSAGES.Assignments.END, reply_markup=None)
+ return ConversationHandler.END
+
+ if query.data == "back":
+ subjects = context.user_data["subjects"]
+ query.edit_message_text(
+ MESSAGES.Assignments.SELECT_COURSE,
+ reply_markup=build_menu_of_subjects(subjects),
+ )
+ return GRADES_ASSNT
+
+ assignments_map = {a["uuid"]: a for a in context.user_data["assignments"]}
+ assignment = assignments_map[query.data]
+ subject = context.user_data["selected_subject"]
+
+ raw_menu = build_menu(
+ [
+ InlineKeyboardButton("Отмена", callback_data="cancel"),
+ InlineKeyboardButton("⏮ Назад", callback_data=subject),
+ ],
+ 2,
+ )
+
+ reply_markup = InlineKeyboardMarkup(raw_menu)
+
+ query.edit_message_text(
+ text=MESSAGES.Assignments.get(
+ assignment["name"],
+ assignment["points"],
+ assignment["how_to_display"],
+ assignment["notes"],
+ ),
+ parse_mode=ParseMode.HTML,
+ reply_markup=reply_markup,
+ )
+
+ return GRADES_ASSNT
+
def broadcast(update: Update, context: CallbackContext):
"""Команда: разослать студентам."""
@@ -268,18 +255,12 @@ def main() -> None:
start_handler = CommandHandler("start", start)
grades_handler = ConversationHandler(
- entry_points=[CommandHandler("grades", grades)],
+ entry_points=[CommandHandler("grades", grades_start)],
states={
- GRADES_CALLBACK: [CallbackQueryHandler(callback)],
- ConversationHandler.TIMEOUT: [
- MessageHandler(Filters.text | Filters.command, timeout)
- ],
- ConversationHandler.END: [
- MessageHandler(Filters.text | Filters.command, grades_end)
- ]
+ GRADES_ASSNT: [CallbackQueryHandler(grades_pick_assignment)],
+ GRADES_VIEW: [CallbackQueryHandler(grades_view)],
},
fallbacks=[CommandHandler("cancel", cancel)],
- #conversation_timeout=10,
)
broadcast_handler = ConversationHandler(
@@ -294,7 +275,6 @@ def main() -> None:
dispatcher.add_handler(start_handler)
dispatcher.add_handler(grades_handler)
dispatcher.add_handler(broadcast_handler)
- #dispatcher.add_handler(callback_handler)
# Начало работы бота
updater.start_polling()
diff --git a/TelegramBot/messages/messages.py b/TelegramBot/messages/messages.py
index daaa16f..661383e 100644
--- a/TelegramBot/messages/messages.py
+++ b/TelegramBot/messages/messages.py
@@ -30,20 +30,24 @@ class Messages:
@staticmethod
def get(name: str, assignment: list, how_to_display: str, notes: str):
- is_float, n_cols, n_rows = how_to_display.split(',')
+ is_float, n_cols, n_rows = how_to_display.split(",")
n_cols, n_rows = int(n_cols), int(n_rows)
- summary = f'{name}:\n'
- if is_float == 'z':
- d = {0 : '❎', 1 : '✅'}
+ summary = f"{name}:\n"
+ if is_float == "z":
+ d = {0: "🟥", 1: "✅"}
for item in range(0, len(assignment), n_cols):
- summary += ''.join(list(map(d.get,
- assignment[item : item + n_cols]))) + '\n'
- elif is_float == 'r':
- to_str = lambda x: f'{x:.2f}'
+ summary += (
+ "".join(list(map(d.get, assignment[item : item + n_cols])))
+ + "\n"
+ )
+ elif is_float == "r":
+ to_str = lambda x: f"{x:.2f}"
for item in range(0, len(assignment), n_cols):
- summary += ' '.join(list(map(to_str,
- assignment[item: item + n_cols]))) + '\n'
- summary += f'Σ: {to_str(sum(assignment))}\n'
+ summary += (
+ " ".join(list(map(to_str, assignment[item : item + n_cols])))
+ + "\n"
+ )
+ summary += f"Σ: {to_str(sum(assignment))}\n"
summary += f"\n{notes}"
return summary
diff --git a/TelegramBot/utils/inline_keyboard.py b/TelegramBot/utils/inline_keyboard.py
index b443c0c..fc3cd30 100644
--- a/TelegramBot/utils/inline_keyboard.py
+++ b/TelegramBot/utils/inline_keyboard.py
@@ -5,41 +5,36 @@ from telegram import (
def build_menu_of_subjects(subjects: list) -> InlineKeyboardMarkup:
- button_list = []
- for subject in subjects:
- button_list.append(
- InlineKeyboardButton(subject, callback_data=f"subject#{subject}")
- )
- end_button = [InlineKeyboardButton("Отмена", callback_data="cancel#")]
- return InlineKeyboardMarkup(build_menu(button_list, n_cols=2,
- footer_buttons=end_button))
+ button_list = [
+ InlineKeyboardButton(subject, callback_data=subject) for subject in subjects
+ ]
+ end_button = [InlineKeyboardButton("Отмена", callback_data="cancel")]
+ return InlineKeyboardMarkup(
+ build_menu(button_list, n_cols=2, footer_buttons=end_button)
+ )
def build_menu_of_assignments(
- assignments: dict, pressed_name: str = None, has_back_button: bool = False
+ assignments: dict, has_back_button: bool = False
) -> InlineKeyboardMarkup:
button_list = []
for assignment in assignments:
- if not assignment['allow_to_display']:
+ if not assignment["allow_to_display"]:
continue
- if pressed_name and assignment["name"] == pressed_name:
- title = f'💁♀️ {assignment["name"]}'
else:
title = assignment["name"]
button_list.append(
InlineKeyboardButton(
title,
- callback_data=f'assignment#{assignment["name"]}'
- + f'#{assignment["subject"]}',
+ callback_data=assignment["uuid"],
)
)
if has_back_button:
- button_list.append(
- InlineKeyboardButton("Назад", callback_data=f"assignment#$back$")
- )
- end_button = [InlineKeyboardButton("Отмена", callback_data="cancel#")]
- return InlineKeyboardMarkup(build_menu(button_list, n_cols=3,
- footer_buttons=end_button))
+ button_list.append(InlineKeyboardButton("⏮ Назад", callback_data="back"))
+ end_button = [InlineKeyboardButton("Отмена", callback_data="cancel")]
+ return InlineKeyboardMarkup(
+ build_menu(button_list, n_cols=3, footer_buttons=end_button)
+ )
def build_menu(buttons, n_cols, header_buttons=None, footer_buttons=None):