Добавил sub и unsub

This commit is contained in:
faridik 2021-09-03 22:52:16 +03:00
parent 549aaeafd2
commit 9a89cde748
4 changed files with 198 additions and 15 deletions

View File

@ -87,7 +87,23 @@ def grades():
@superuser @superuser
def broadcast(student): def broadcast(student):
"""Выполняет рассылку студентам.""" """Выполняет рассылку студентам."""
return flask.jsonify(app.db.get_all_groups()) return flask.jsonify(app.db.get_all_groups_only_sub_students())
@app.route("/sub")
@availability
def sub():
tg_id = flask.request.args.get("tg_id", None)
is_subbed = app.db.sub_by_tg_id(tg_id)
return flask.jsonify(dict(is_subbed=is_subbed))
@app.route("/unsub")
@availability
def unsub():
tg_id = flask.request.args.get("tg_id", None)
is_unsubbed = app.db.unsub_by_tg_id(tg_id)
return flask.jsonify(dict(is_unsubbed=is_unsubbed))
@app.errorhandler(StudentAlreadyAuthed) @app.errorhandler(StudentAlreadyAuthed)
@ -104,6 +120,13 @@ def show_error(err):
def show_error(err): def show_error(err):
return flask.jsonify({"error": type(err).__name__, "message": err.message}), 404 return flask.jsonify({"error": type(err).__name__, "message": err.message}), 404
@app.errorhandler(StudentAlreadySubbed)
def show_error(err):
return flask.jsonify({"error": type(err).__name__, "message": err.message}), 405
@app.errorhandler(StudentAlreadyUnsubbed)
def show_error(err):
return flask.jsonify({"error": type(err).__name__, "message": err.message}), 406
@app.errorhandler(BadRequest) @app.errorhandler(BadRequest)
def show_error(err): def show_error(err):

View File

@ -18,8 +18,9 @@ STUDENT_NUMBERS = 0
STUDENT_NAMES = 1 STUDENT_NAMES = 1
GROUP_IDS = 2 # for StudentList and AssignmentList GROUP_IDS = 2 # for StudentList and AssignmentList
STUDENT_SUBJECTS = 3 STUDENT_SUBJECTS = 3
TELEGRAM_IDS = 4 STUDENT_TELEGRAM_IDS = 4
AUTH_TOKEN = 5 AUTH_TOKEN = 5
STUDENT_SUBSCRIPTION = 6
ASSIGNMENT_NAMES = 1 ASSIGNMENT_NAMES = 1
ASSIGNMENT_GROUP = 2 ASSIGNMENT_GROUP = 2
ASSIGNMENT_SUBJECT = 3 ASSIGNMENT_SUBJECT = 3
@ -62,6 +63,15 @@ class AnotherStudentAlreadyAuthed(Exception):
self.message = message self.message = message
super().__init__(self.message) super().__init__(self.message)
class StudentAlreadySubbed(Exception):
def __init__(self, message):
self.message = message
super().__init__(self.message)
class StudentAlreadyUnsubbed(Exception):
def __init__(self, message):
self.message = message
super().__init__(self.message)
class Manager: class Manager:
"""Позволяет выполнять операции с Google таблицами.""" """Позволяет выполнять операции с Google таблицами."""
@ -148,7 +158,7 @@ class Manager:
int(row[STUDENT_NUMBERS]), int(row[STUDENT_NUMBERS]),
row[STUDENT_NAMES], row[STUDENT_NAMES],
group_id, group_id,
row[TELEGRAM_IDS], row[STUDENT_TELEGRAM_IDS],
) )
) )
@ -162,11 +172,32 @@ class Manager:
groups[row[GROUP_IDS]].group_id = row[GROUP_IDS] groups[row[GROUP_IDS]].group_id = row[GROUP_IDS]
groups[row[GROUP_IDS]].add_student( groups[row[GROUP_IDS]].add_student(
Student( Student(
int(row[STUDENT_NUMBERS]), number=int(row[STUDENT_NUMBERS]),
row[STUDENT_NAMES], name=row[STUDENT_NAMES],
row[GROUP_IDS], group_id=row[GROUP_IDS],
row[TELEGRAM_IDS], tg_id=row[STUDENT_TELEGRAM_IDS],
row[STUDENT_SUBJECTS].split(',') subjects=row[STUDENT_SUBJECTS].split(','),
is_subbed=bool(int(row[STUDENT_SUBSCRIPTION])),
)
)
return groups
def get_all_groups_only_sub_students(self) -> list:
"""Получить список всех групп."""
values = self.get_values()
groups = defaultdict(lambda: Group("0"))
f = lambda row: row[STUDENT_SUBSCRIPTION] == '1'
for row in filter(f,values):
groups[row[GROUP_IDS]].group_id = row[GROUP_IDS]
groups[row[GROUP_IDS]].add_student(
Student(
number=int(row[STUDENT_NUMBERS]),
name=row[STUDENT_NAMES],
group_id=row[GROUP_IDS],
tg_id=row[STUDENT_TELEGRAM_IDS],
subjects=row[STUDENT_SUBJECTS].split(','),
is_subbed=bool(int(row[STUDENT_SUBSCRIPTION])),
) )
) )
@ -183,7 +214,7 @@ class Manager:
return Student( return Student(
int(row[STUDENT_NUMBERS]), name, int(row[STUDENT_NUMBERS]), name,
row[GROUP_IDS], row[GROUP_IDS],
row[TELEGRAM_IDS], row[STUDENT_TELEGRAM_IDS],
row[STUDENT_SUBJECTS].split(',') row[STUDENT_SUBJECTS].split(',')
) )
except StopIteration: except StopIteration:
@ -194,7 +225,7 @@ class Manager:
values = self.get_values("StudentList") values = self.get_values("StudentList")
f = lambda row: tg_id == row[TELEGRAM_IDS] f = lambda row: tg_id == row[STUDENT_TELEGRAM_IDS]
try: try:
row = next(filter(f, values)) row = next(filter(f, values))
return Student( return Student(
@ -242,13 +273,13 @@ class Manager:
f = lambda row: token == row[AUTH_TOKEN] f = lambda row: token == row[AUTH_TOKEN]
try: try:
row = next(filter(f, values)) row = next(filter(f, values))
if row[TELEGRAM_IDS] == tg_id: if row[STUDENT_TELEGRAM_IDS] == tg_id:
raise StudentAlreadyAuthed("Студент уже зарегистрировался") raise StudentAlreadyAuthed("Студент уже зарегистрировался")
elif row[TELEGRAM_IDS]: elif row[STUDENT_TELEGRAM_IDS]:
raise AnotherStudentAlreadyAuthed( raise AnotherStudentAlreadyAuthed(
"Другой студент зарегистрировался по token" "Другой студент зарегистрировался по token"
) )
row[TELEGRAM_IDS] = tg_id row[STUDENT_TELEGRAM_IDS] = tg_id
self.write_values(values, "StudentList") self.write_values(values, "StudentList")
return Student( return Student(
int(row[STUDENT_NUMBERS]), int(row[STUDENT_NUMBERS]),
@ -258,3 +289,40 @@ class Manager:
) )
except StopIteration: except StopIteration:
raise StudentNotFound("Не могу найти студента по token") raise StudentNotFound("Не могу найти студента по token")
def sub_by_tg_id(self, tg_id: str) -> bool:
"""Подписка пользователя по tg_id"""
values = self.get_values("StudentList")
f = lambda row: tg_id == row[STUDENT_TELEGRAM_IDS]
try:
row = next(filter(f, values))
if row[STUDENT_SUBSCRIPTION] == '1':
raise StudentAlreadySubbed("Студент уже подписался")
row[STUDENT_SUBSCRIPTION] = 1
self.write_values(values, "StudentList")
return True
except StopIteration:
raise StudentNotFound("Не могу найти студента по tg_id")
def unsub_by_tg_id(self, tg_id: str) -> bool:
"""Подписка пользователя по tg_id"""
values = self.get_values("StudentList")
f = lambda row: tg_id == row[STUDENT_TELEGRAM_IDS]
try:
row = next(filter(f, values))
if row[STUDENT_SUBSCRIPTION] == '0':
raise StudentAlreadyUnsubbed(
"Студент уже не подписан (или никогда не был)"
)
row[STUDENT_SUBSCRIPTION] = 0
self.write_values(values, "StudentList")
return True
except StopIteration:
raise StudentNotFound("Не могу найти студента по tg_id")

View File

@ -66,7 +66,7 @@ def start(update: Update, context: CallbackContext):
return return
if req.status_code != 200: if req.status_code != 200:
LOG.error(f"Ошибка авторизации, у пользователя @{username} {data}") LOG.error(f"Ошибка авторизации у пользователя @{username} {data}")
err = data.get("error", "") err = data.get("error", "")
update.message.reply_text(text=MESSAGES.Auth.failure(err)) update.message.reply_text(text=MESSAGES.Auth.failure(err))
update.message.reply_sticker(MESSAGES.Stickers.DEAD) update.message.reply_sticker(MESSAGES.Stickers.DEAD)
@ -176,7 +176,6 @@ def grades_view(update: Update, context: CallbackContext):
return GRADES_ASSNT return GRADES_ASSNT
def broadcast(update: Update, context: CallbackContext): def broadcast(update: Update, context: CallbackContext):
"""Команда: разослать студентам.""" """Команда: разослать студентам."""
access_message = update.message.reply_text("🔐 Проверка доступа...") access_message = update.message.reply_text("🔐 Проверка доступа...")
@ -244,6 +243,68 @@ def cancel(update: Update, context: CallbackContext):
return ConversationHandler.END return ConversationHandler.END
def sub(update: Update, context: CallbackContext):
"""Стартовое сообщение (к команде /start)"""
user_id = update.message.from_user.id
username = update.message.from_user.username
# Длинная операция, сообщим о запущенном процессе.
update.message.reply_text(text=MESSAGES.Sub.START)
LOG.info(f"Subcripting {user_id}")
try:
req = requests.get(
f"{HOST}/sub",
params={"tg_id": user_id},
)
data = req.json()
except requests.exceptions.RequestException:
LOG.exception("@{user_id} вызвал: Ошибка подключения к сервису Spreadsheets.")
update.message.reply_sticker(MESSAGES.Stickers.DEAD)
return
if req.status_code != 200:
LOG.error(f"Ошибка подписки, у пользователя @{username} {data}")
err = data.get("error", "")
update.message.reply_text(text=MESSAGES.Sub.failure(err))
update.message.reply_sticker(MESSAGES.Stickers.bad())
return
update.message.reply_text(text=MESSAGES.Sub.SUBBED)
def unsub(update: Update, context: CallbackContext):
"""Стартовое сообщение (к команде /start)"""
user_id = update.message.from_user.id
username = update.message.from_user.username
# Длинная операция, сообщим о запущенном процессе.
update.message.reply_text(text=MESSAGES.Unsub.START)
LOG.info(f"Unsubcripting {user_id}")
try:
req = requests.get(
f"{HOST}/unsub",
params={"tg_id": user_id},
)
data = req.json()
except requests.exceptions.RequestException:
LOG.exception("@{user_id} вызвал: Ошибка подключения к сервису Spreadsheets.")
update.message.reply_sticker(MESSAGES.Stickers.DEAD)
return
if req.status_code != 200:
LOG.error(f"Ошибка отписки, у пользователя @{username} {data}")
err = data.get("error", "")
update.message.reply_text(text=MESSAGES.Unsub.failure(err))
update.message.reply_sticker(MESSAGES.Stickers.bad())
return
update.message.reply_text(text=MESSAGES.Unsub.UNSUBBED)
# ==================================================================== HANDLERS # ==================================================================== HANDLERS
@ -272,9 +333,14 @@ def main() -> None:
fallbacks=[CommandHandler("cancel", cancel)], fallbacks=[CommandHandler("cancel", cancel)],
) )
sub_handler = CommandHandler("sub", sub)
unsub_handler = CommandHandler("unsub", unsub)
dispatcher.add_handler(start_handler) dispatcher.add_handler(start_handler)
dispatcher.add_handler(grades_handler) dispatcher.add_handler(grades_handler)
dispatcher.add_handler(broadcast_handler) dispatcher.add_handler(broadcast_handler)
dispatcher.add_handler(sub_handler)
dispatcher.add_handler(unsub_handler)
# Начало работы бота # Начало работы бота
updater.start_polling() updater.start_polling()

View File

@ -55,6 +55,32 @@ class Messages:
def timeit(t: float): def timeit(t: float):
return f"⏱ Посмотрели за {t:.2f}с" return f"⏱ Посмотрели за {t:.2f}с"
class Sub:
START = "📜✍ Оформляю подписку на уведомления..."
SUBBED = "👌 Подписка на уведомления оформлена"
@staticmethod
def failure(err: str):
cases = {
"StudentNotFound": "⛔ Для подписки нужно зарегистрироваться."
+ "Команда /start поможет с регистрацией",
"StudentAlreadySubbed": "💁‍♀️ Подписка уже оформлена ранее",
}
return cases.get(err, "😟 Возникли неполадки")
class Unsub:
START = "📜✍ Оформляю отписку от уведомлений..."
UNSUBBED = "🙄 Подписка на уведомления отменена"
@staticmethod
def failure(err: str):
cases = {
"StudentNotFound": "⛔ Для отпидски от уведомлений нужно зарегистрироваться."
+ "Команда /start поможет с регистрацией",
"StudentAlreadyUnsubbed": "💁‍♀️ Подписка на уведомления не была оформлена или уже отменена",
}
return cases.get(err, "😟 Возникли неполадки")
class Spreadsheets: class Spreadsheets:
pass pass