diff --git a/SpreadsheetsService/app.py b/SpreadsheetsService/app.py index d0b7a63..9cfde8d 100644 --- a/SpreadsheetsService/app.py +++ b/SpreadsheetsService/app.py @@ -88,7 +88,7 @@ def grades(): @superuser def broadcast(student): """Выполняет рассылку студентам.""" - return flask.jsonify(student) + return flask.jsonify(app.db.get_all_groups()) @app.errorhandler(StudentAlreadyAuthed) diff --git a/SpreadsheetsService/manager/manager.py b/SpreadsheetsService/manager/manager.py index 600a465..f1791bc 100644 --- a/SpreadsheetsService/manager/manager.py +++ b/SpreadsheetsService/manager/manager.py @@ -1,3 +1,4 @@ +from collections import defaultdict import os.path import pathlib from sys import path @@ -24,11 +25,13 @@ ASSIGNMENT_ALLOWS = 6 TOKEN_FILE = pathlib.Path() / ".secrets" / "token.json" CLIENT_SECRET_FILE = pathlib.Path() / ".secrets" / "client_secret.json" + class StudentAlreadyAuthed(Exception): def __init__(self, message): self.message = message super().__init__(self.message) + class AnotherStudentAlreadyAuthed(Exception): def __init__(self, message): self.message = message @@ -41,11 +44,13 @@ class Manager: def __init__( self, spreadsheet_id: str = "1GKfmLwDVGjcpXFQAUyxM4RMQ5Nx6HAZ5VWenz2z--d0", - scopes: list = ['https://www.googleapis.com/auth/spreadsheets.readonly', - 'https://www.googleapis.com/auth/spreadsheets', - 'https://www.googleapis.com/auth/drive.file', - 'https://www.googleapis.com/auth/drive.readonly', - 'https://www.googleapis.com/auth/drive'], + scopes: list = [ + "https://www.googleapis.com/auth/spreadsheets.readonly", + "https://www.googleapis.com/auth/spreadsheets", + "https://www.googleapis.com/auth/drive.file", + "https://www.googleapis.com/auth/drive.readonly", + "https://www.googleapis.com/auth/drive", + ], ): self.spreadsheet_id = spreadsheet_id @@ -74,7 +79,11 @@ class Manager: def get_values( self, range_name: str = "StudentList" ) -> list: # TODO: change subject - """Получить значения с таблицы.""" + """Получить значения с таблицы. + + Returns: + list of rows [[val1, val2, ...], [], ...] + """ result = ( self.sheet.values() @@ -87,11 +96,17 @@ class Manager: def write_values(self, values: list, range_name: str): """Записать значения в таблицу.""" - body = {'values' : values} - result = self.sheet.values().update( - spreadsheetId=self.spreadsheet_id, range=range_name, - valueInputOption='USER_ENTERED', body=body).execute() - + body = {"values": values} + result = ( + self.sheet.values() + .update( + spreadsheetId=self.spreadsheet_id, + range=range_name, + valueInputOption="USER_ENTERED", + body=body, + ) + .execute() + ) def get_group(self, group_id: str) -> Group: """Получить группу со студентами.""" @@ -113,6 +128,23 @@ class Manager: return group + def get_all_groups(self) -> list: + """Получить список всех групп.""" + values = self.get_values() + groups = defaultdict(lambda: Group("0")) + for row in values: + groups[row[GROUP_IDS]].group_id = row[GROUP_IDS] + groups[row[GROUP_IDS]].add_student( + Student( + int(row[STUDENT_NUMBERS]), + row[STUDENT_NAMES], + row[GROUP_IDS], + row[TELEGRAM_IDS], + ) + ) + + return groups + def get_student_by_name(self, name: str) -> Student: """Получить студента по имени.""" @@ -149,14 +181,14 @@ class Manager: f = lambda row: student.group_id == row[GROUP_IDS] # TODO add subject for row in filter(f, values): assignment_value = self.get_values(row[ASSIGNMENT_RANGES]) - toFloat = lambda x: float(x.replace(',','.')) + toFloat = lambda x: float(x.replace(",", ".")) ass_values = list(map(toFloat, assignment_value[student.number])) student.add_assignment( - Assignment(row[ASSIGNMENT_NAMES], ass_values, - toFloat(row[ASSIGNMENT_WEIGHTS])) + Assignment( + row[ASSIGNMENT_NAMES], ass_values, toFloat(row[ASSIGNMENT_WEIGHTS]) + ) ) - def auth_by_token(self, token: str, tg_id: str) -> Student: """Аутентификация пользователя через token.""" @@ -166,10 +198,11 @@ class Manager: try: row = next(filter(f, values)) if row[TELEGRAM_IDS] == tg_id: - raise StudentAlreadyAuthed('Студент уже зарегистрировался') + raise StudentAlreadyAuthed("Студент уже зарегистрировался") elif row[TELEGRAM_IDS]: raise AnotherStudentAlreadyAuthed( - 'Другой студент зарегистрировался по token') + "Другой студент зарегистрировался по token" + ) row[TELEGRAM_IDS] = tg_id self.write_values(values, "StudentList") return Student( diff --git a/SpreadsheetsService/models/group.py b/SpreadsheetsService/models/group.py index e7c1ed3..c6f8bf3 100644 --- a/SpreadsheetsService/models/group.py +++ b/SpreadsheetsService/models/group.py @@ -7,15 +7,21 @@ class StudentNotFound(Exception): super().__init__(self.message) -class Group: +class Group(dict): """Объект "Группа" для работы со списком студентов. Используется для работы с множеством студентов. """ def __init__(self, group_id: str): - self.group_id: str = group_id + self._group_id: str = group_id self._students: Student = [] + dict.__init__( + self, + group_id=self.group_id, + students=self._students, + ) + def __iter__(self): """Делегирует итератор на список студентов. @@ -26,6 +32,15 @@ class Group: """ return iter(self._students) + @property + def group_id(self): + return self._group_id + + @group_id.setter + def group_id(self, value): + self["group_id"] = value + self._group_id = value + def add_student(self, student: Student): """Добавить студента в группу.""" self._students.append(student) diff --git a/TelegramBot/bot.py b/TelegramBot/bot.py index 951ced8..4c925c0 100644 --- a/TelegramBot/bot.py +++ b/TelegramBot/bot.py @@ -168,13 +168,21 @@ def broadcast(update: Update, context: CallbackContext): r = requests.get(f"{HOST}/broadcast", params={"tg_id": user_id}) assert r.status_code == 200, "Доступ запрещен к /broadcast" data = r.json() - access_message.edit_text(f"👨‍💻 {data['name']}") + context.bot_data["groups"] = data + access_message.edit_text(f"✅ Доступ получен") + groups_list = [k for k in data.keys()] + n = 5 # кол-во кнопок в строке + summary_keyboard = [] + LOG.info(groups_list) + for i in range((len(groups_list) // n) + 1): + LOG.debug(groups_list[i * n : i * n + n]) + keyboard_row = groups_list[i * n : i * n + n] + summary_keyboard.append(keyboard_row) + + LOG.info(f"{summary_keyboard}") reply_keyboard = telegram.ReplyKeyboardMarkup( - [ - [telegram.KeyboardButton("5374"), telegram.KeyboardButton("5371")], - [telegram.KeyboardButton("1337")], - ], + summary_keyboard, one_time_keyboard=True, ) update.message.reply_text("Выбери группу", reply_markup=reply_keyboard) @@ -187,15 +195,26 @@ def broadcast(update: Update, context: CallbackContext): def publish_message(update: Update, context: CallbackContext): """Чел выбирает группу и для нее готовится сообщение.""" + message = update.message.text + context.user_data["broadcast_to"] = message update.message.reply_html( - "🖋 Сообщение для группы:", reply_markup=telegram.ReplyKeyboardRemove() + f"🖋 Сообщение для группы {message}:", + reply_markup=telegram.ReplyKeyboardRemove(), ) return BROADCAST_PUBLISH_DONE def publish_done(update: Update, context: CallbackContext): """Рассылка выполняется здесь.""" - update.message.reply_html("📨 Сообщения разосланы") + # TODO: код работает с диктом, а не с классом. Переделать. + message = update.message.text + group = context.user_data["broadcast_to"] + LOG.info(f"send {group} a message {message}") + + for student in context.bot_data["groups"][group]: + LOG.info(f"{student} send message: {message}") + if student.tg_id: + context.bot.send_message(chat_id=student.tg_id, text=message) return ConversationHandler.END