mirror of
https://github.com/Faridik/Carolyn.git
synced 2026-07-08 13:21:53 +00:00
Добавил sub и unsub
This commit is contained in:
parent
549aaeafd2
commit
9a89cde748
@ -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):
|
||||||
|
|||||||
@ -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")
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user