mirror of
https://github.com/Faridik/Carolyn.git
synced 2026-07-08 05:11:52 +00:00
Переделан подход к работе с ошибками
This commit is contained in:
parent
9e85748a82
commit
471cf43f60
@ -1,27 +1,12 @@
|
||||
from functools import wraps
|
||||
|
||||
from werkzeug.exceptions import *
|
||||
from manager import *
|
||||
import flask
|
||||
import logging
|
||||
import models
|
||||
import time
|
||||
|
||||
UNEXPECTED_ERROR_DICT = dict(
|
||||
error=True,
|
||||
desc='UnexpectedError'
|
||||
)
|
||||
STUDENT_NOT_FOUND_DICT = dict(
|
||||
error=True,
|
||||
desc='StudentNotFound'
|
||||
)
|
||||
STUDENT_ALREADY_AUTHED_DICT = dict(
|
||||
error = True,
|
||||
desc='StudentAlreadyAuthed'
|
||||
)
|
||||
ANOTHER_STUDENT_ALREADY_AUTHED_DICT = dict(
|
||||
error = True,
|
||||
desc='AnotherStudentAlreadyAuthed'
|
||||
)
|
||||
|
||||
logging.basicConfig()
|
||||
LOG = logging.getLogger(__name__)
|
||||
LOG.setLevel(logging.DEBUG)
|
||||
@ -60,22 +45,12 @@ def hello_world():
|
||||
@app.route("/auth")
|
||||
@availability
|
||||
def auth():
|
||||
token = flask.request.args.get("token")
|
||||
tg_id = flask.request.args.get("tg_id")
|
||||
try:
|
||||
student = app.db.auth_by_token(token, tg_id)
|
||||
return flask.jsonify(dict(
|
||||
student=student,
|
||||
error=False
|
||||
))
|
||||
except StudentAlreadyAuthed:
|
||||
return flask.jsonify(STUDENT_ALREADY_AUTHED_DICT)
|
||||
except AnotherStudentAlreadyAuthed:
|
||||
return flask.jsonify(ANOTHER_STUDENT_ALREADY_AUTHED_DICT)
|
||||
except StudentNotFound:
|
||||
return flask.jsonify(STUDENT_NOT_FOUND_DICT)
|
||||
except:
|
||||
return flask.jsonify(UNEXPECTED_ERROR_DICT)
|
||||
token = flask.request.args.get("token", None)
|
||||
tg_id = flask.request.args.get("tg_id", None)
|
||||
if token is None or tg_id is None:
|
||||
raise BadRequest("Не предоставлены token и tg_id!")
|
||||
student = app.db.auth_by_token(token, tg_id)
|
||||
return flask.jsonify(dict(student=student))
|
||||
|
||||
|
||||
@app.route("/grades")
|
||||
@ -83,24 +58,41 @@ def auth():
|
||||
def grades():
|
||||
"""Возвращает оценки по id пользователя из телеграма."""
|
||||
tg_id = flask.request.args.get("tg_id")
|
||||
|
||||
try:
|
||||
student = app.db.get_student_by_tg_id(tg_id)
|
||||
app.db.set_assignments_for_student(student)
|
||||
return flask.jsonify(
|
||||
student = app.db.get_student_by_tg_id(tg_id)
|
||||
app.db.set_assignments_for_student(student)
|
||||
return flask.jsonify(
|
||||
dict(
|
||||
error=False,
|
||||
score=student.score,
|
||||
grade=student.grade,
|
||||
assignments=student.assignments,
|
||||
)
|
||||
)
|
||||
except StudentNotFound:
|
||||
return flask.jsonify(STUDENT_NOT_FOUND_DICT)
|
||||
except:
|
||||
return flask.jsonify(UNEXPECTED_ERROR_DICT)
|
||||
|
||||
|
||||
|
||||
@app.errorhandler(StudentAlreadyAuthed)
|
||||
def show_error(err):
|
||||
return flask.jsonify({"error": type(err).__name__, "message": err.message}), 409
|
||||
|
||||
|
||||
@app.errorhandler(AnotherStudentAlreadyAuthed)
|
||||
def show_error(err):
|
||||
return flask.jsonify({"error": type(err).__name__, "message": err.message}), 403
|
||||
|
||||
|
||||
@app.errorhandler(StudentNotFound)
|
||||
def show_error(err):
|
||||
return flask.jsonify({"error": type(err).__name__, "message": err.message}), 404
|
||||
|
||||
|
||||
@app.errorhandler(BadRequest)
|
||||
def show_error(err):
|
||||
return flask.jsonify({"error": type(err).__name__, "message": err.description}), 400
|
||||
|
||||
|
||||
# Любая другая ошибка вылетит вот здесь
|
||||
@app.errorhandler(Exception)
|
||||
def show_error(err):
|
||||
return flask.jsonify({"error": type(err).__name__, "message": str(err)}), 500
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import logging
|
||||
from typing import Any, Optional
|
||||
import requests
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@ -18,21 +20,82 @@ from messages import Messages
|
||||
TOKEN = Path(".secrets/bot_token.txt").read_text()
|
||||
MESSAGES = Messages()
|
||||
HOST = "http://carolyn-spreadsheets:5000"
|
||||
"""ID канала где собираются логи"""
|
||||
CHAT_LOG_ID = -507530583
|
||||
|
||||
|
||||
class TgLogger(logging.Logger):
|
||||
"""Обертка на логгер, чтобы можно было использовать обычные лог-функции,
|
||||
но при этом получать логи в телеграм чат.
|
||||
|
||||
Есть баг, который не позволяет вызывать лог с ленивыми аргументами. Если
|
||||
вызывать
|
||||
```python
|
||||
LOG.warning("%s", var)
|
||||
```
|
||||
, то можно получить такую ошибку:
|
||||
```python
|
||||
TypeError: _log_to_telegram() got multiple values for argument 'msg'
|
||||
```
|
||||
Поэтому используйте,
|
||||
```
|
||||
LOG.warning(f"{var}")
|
||||
```
|
||||
"""
|
||||
|
||||
def __init__(self, name, level=logging.NOTSET):
|
||||
self._bot = None
|
||||
self._chat_log_id = CHAT_LOG_ID
|
||||
return super(TgLogger, self).__init__(name, level)
|
||||
|
||||
@property
|
||||
def bot(self):
|
||||
return self._bot
|
||||
|
||||
@bot.setter
|
||||
def bot(self, value):
|
||||
self._bot = value
|
||||
|
||||
def _log_to_telegram(
|
||||
self,
|
||||
msg: str,
|
||||
*args,
|
||||
emoji: str,
|
||||
):
|
||||
if self._bot is not None:
|
||||
txt = f"{emoji} {msg};"
|
||||
self._bot.send_message(chat_id=CHAT_LOG_ID, text=txt)
|
||||
|
||||
def warning(self, msg: Any, *args: Any, **kwargs: Any) -> None:
|
||||
self._log_to_telegram(msg=msg, emoji="⚠", *args)
|
||||
return super().warning(
|
||||
msg,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def error(self, msg: Any, *args: Any, **kwargs: Any) -> None:
|
||||
self._log_to_telegram(msg=msg, emoji="💢", *args)
|
||||
return super().error(
|
||||
msg,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def exception(self, msg, *args: Any, **kwargs: Any) -> None:
|
||||
self._log_to_telegram(msg=msg, emoji="💥", *args)
|
||||
return super().exception(msg, *args, **kwargs)
|
||||
|
||||
|
||||
updater = Updater(token=TOKEN, use_context=True)
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
logging.setLoggerClass(TgLogger)
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
|
||||
)
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
LOG.debug("Token is %s", TOKEN)
|
||||
updater = Updater(token=TOKEN, use_context=True)
|
||||
dispatcher = updater.dispatcher
|
||||
|
||||
|
||||
def log_to_group_chat(update: Update, text: str):
|
||||
update.message.bot.send_message(chat_id=CHAT_LOG_ID, text=text)
|
||||
|
||||
LOG.bot = updater.bot
|
||||
|
||||
# ================================================================ BOT COMMANDS
|
||||
|
||||
@ -41,45 +104,38 @@ def start(update: Update, context: CallbackContext):
|
||||
"""Стартовое сообщение (к команде /start)"""
|
||||
|
||||
user_id = update.message.from_user.id
|
||||
username = update.message.from_user.username
|
||||
student_token = context.args[0] if len(context.args) > 0 else None
|
||||
|
||||
p = context.args[0] if len(context.args) > 0 else None
|
||||
|
||||
if p is None:
|
||||
if student_token is None:
|
||||
update.message.reply_markdown_v2(text=MESSAGES.auth.NO_AUTH)
|
||||
return
|
||||
|
||||
# Длинная операция, сообщим о запущенном процессе.
|
||||
update.message.reply_text(text=MESSAGES.auth.START)
|
||||
|
||||
LOG.info(f"Authenticanting {user_id}")
|
||||
|
||||
try:
|
||||
data = requests.get(
|
||||
req = requests.get(
|
||||
f"{HOST}/auth",
|
||||
params={"token": p, "tg_id": user_id},
|
||||
).json()
|
||||
except requests.exceptions.ConnectionError:
|
||||
log_to_group_chat(update,
|
||||
text=MESSAGES.auth.failure_log(
|
||||
{'desc':'ConnectionError'})
|
||||
params={"token": student_token, "tg_id": user_id},
|
||||
)
|
||||
data = req.json()
|
||||
except requests.exceptions.RequestException:
|
||||
LOG.exception("@{username} вызвал: Ошибка подключения к сервису Spreadsheets.")
|
||||
update.message.reply_sticker(MESSAGES.stickers.DEAD)
|
||||
return
|
||||
|
||||
if data['error']:
|
||||
log_to_group_chat(update,
|
||||
text=MESSAGES.auth.failure_log(data)
|
||||
)
|
||||
update.message.reply_text(
|
||||
text=MESSAGES.auth.failure(data)
|
||||
)
|
||||
if req.status_code != 200:
|
||||
LOG.error(f"Ошибка авторизации, у пользователя @{username} {data}")
|
||||
err = data.get("error", "")
|
||||
update.message.reply_text(text=MESSAGES.auth.failure(err))
|
||||
update.message.reply_sticker(MESSAGES.stickers.DEAD)
|
||||
return
|
||||
|
||||
log_to_group_chat(update,
|
||||
text=MESSAGES.auth.success_log(data['student'])
|
||||
)
|
||||
update.message.reply_text(
|
||||
text=MESSAGES.auth.hello(data['student']),
|
||||
text=MESSAGES.auth.hello(data["student"]),
|
||||
)
|
||||
|
||||
|
||||
@ -87,6 +143,10 @@ def grades(update: Update, context: CallbackContext):
|
||||
"""Команда: Получить оценки студента."""
|
||||
|
||||
user_id = update.message.from_user.id
|
||||
|
||||
start = time.monotonic()
|
||||
# Длинная операция, сообщим о запущенном процессе.
|
||||
look_msg = update.message.reply_html(MESSAGES.score.START)
|
||||
try:
|
||||
data = requests.get(f"{HOST}/grades", params={"tg_id": user_id}).json()
|
||||
score = data["score"]
|
||||
@ -99,6 +159,8 @@ def grades(update: Update, context: CallbackContext):
|
||||
except:
|
||||
LOG.exception("Failed to get grades.")
|
||||
update.message.reply_sticker(MESSAGES.stickers.DEAD)
|
||||
diff = time.monotonic() - start
|
||||
look_msg.edit_text(MESSAGES.score.timeit(diff))
|
||||
|
||||
|
||||
def echo(update: Update, context: CallbackContext):
|
||||
|
||||
@ -11,15 +11,13 @@ class Messages:
|
||||
def hello(self, data):
|
||||
return f"Привет, {data['name']} 👋"
|
||||
|
||||
def failure(self, data):
|
||||
if data['desc'] == 'StudentNotFound':
|
||||
return "⛔ Ссылка больше не работает"
|
||||
elif data['desc'] == 'StudentAlreadyAuthed':
|
||||
return "⛔ Регистрация по этой ссылке уже прошла"
|
||||
elif data['desc'] == 'AnotherStudentAlreadyAuthed':
|
||||
return "😨 Кто-то другой уже зерегистрировался по этой ссылке"
|
||||
else:
|
||||
return "😟 Возникли неполадки"
|
||||
def failure(self, err: str):
|
||||
cases = {
|
||||
"StudentNotFound": "⛔ Ссылка больше не работает",
|
||||
"StudentAlreadyAuthed": "⛔ Регистрация по этой ссылке уже прошла",
|
||||
"AnotherStudentAlreadyAuthed": "😨 Кто-то другой уже зерегистрировался по этой ссылке",
|
||||
}
|
||||
return cases.get(err, "😟 Возникли неполадки")
|
||||
|
||||
def success_log(self, data):
|
||||
return f"✅ AUTH: {data['name']} "
|
||||
@ -28,6 +26,8 @@ class Messages:
|
||||
return f"🟥 AUTH: {data['desc']}"
|
||||
|
||||
class Score:
|
||||
START = "👀 Посмотрим (~3с) ..."
|
||||
|
||||
def get(self, grade, score, n_of_assignments):
|
||||
summary = (
|
||||
f"Ранг: <b>{score:.2f}</b> {n_of_assignments} зад.\n"
|
||||
@ -35,6 +35,10 @@ class Messages:
|
||||
)
|
||||
return summary
|
||||
|
||||
@staticmethod
|
||||
def timeit(t: float):
|
||||
return f"⏱ Посмотрели за {t:.2f}с"
|
||||
|
||||
class Spreadsheets:
|
||||
def __init__(self):
|
||||
self.DEAD = "⚰ Сервис «таблицы» недоступен"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user