Текст сообщений вынесен в отдельный класс. Перемещены секретные файлы. Налажено развертывание контейнеров.

This commit is contained in:
serafim.urukov 2021-07-31 23:36:46 +03:00
parent 815bb0e471
commit b0bca6433f
11 changed files with 241 additions and 66 deletions

3
.gitignore vendored
View File

@ -5,3 +5,6 @@ SpreadsheetsService/tests/__pycache__
SpreadsheetsService/manager/__pycache__
SpreadsheetsService/manager/client_secret.json
SpreadsheetsService/manager/token.json
TelegramBot/.secrets
SpreadsheetsService/.secrets
TelegramBot/messages/__pycache__

View File

@ -1,9 +1,34 @@
import flask
import time
import models
from functools import wraps
from manager import *
import flask
import logging
import models
import time
LOG = logging.getLogger(__name__)
app = flask.Flask(__name__)
app.db = None
try:
app.db = Manager()
except Exception as e:
app.db_error = e.args
LOG.exception("Cannot init manager")
def availability(func):
"""Декоратор, который проверяет доступность менеджера по работе с Google
Spreadsheets.
Если инициализация менеджера обвалилась, то сервер выдает ошибку 500 и ее
содержимое в JSON."""
@wraps(func)
def wrapper(*args, **kwargs):
if app.db is None:
return flask.jsonify(dict(error=True, message=app.db_error)), 500
func(*args, **kwargs)
return wrapper
@app.route("/")
@ -12,13 +37,32 @@ def hello_world():
@app.route("/auth")
@availability
def auth():
# TODO: return json text instead of text/html.
token = flask.request.args.get("token")
tg_id = flask.request.args.get("tg_id")
manager = Manager()
student = manager.get_student_by_name("Дзюба")
return str(student)
student = app.db.get_student_by_name("Дзюба")
student = Student(1, "Фарид Михайлов", 5374)
return flask.jsonify(student)
@app.route("/grades")
@availability
def grades():
"""Возвращает оценки по id пользователя из телеграма."""
tg_id = flask.request.args.get("tg_id")
student = models.Student(1, "Фарид Михайлов", 5374)
student.add_assignment(models.Assignment("ИДЗ 1", [1, 1, 0, 0, 1]))
student.add_assignment(models.Assignment("КР 1", [0.4, 0.8, 1, 0.5, 1], 5))
student.add_assignment(models.Assignment("ИДЗ 2", [1, 1, 1, 0, 1]))
return flask.jsonify(
dict(
score=student.score,
grade=student.grade,
assignments=student.assignments,
)
)
if __name__ == "__main__":

View File

@ -20,8 +20,8 @@ ASSIGNMENT_SUBJECT = 3
ASSIGNMENT_WEIGHTS = 4
ASSIGNMENT_RANGES = 5
ASSIGNMENT_ALLOWS = 6
TOKEN_FILE = pathlib.Path() / "manager" / "token.json"
CLIENT_SECRET_FILE = pathlib.Path() / "manager" / "client_secret.json"
TOKEN_FILE = pathlib.Path() / ".secrets" / "token.json"
CLIENT_SECRET_FILE = pathlib.Path() / ".secrets" / "client_secret.json"
class Manager:

View File

@ -1,10 +1,17 @@
class Assignment:
class Assignment(dict):
"""Задание."""
def __init__(self, name: str, values: list, weight: float=1):
def __init__(self, name: str, points: list, weight: float = 1):
self.name = name
self.weight = weight
self.values = values
self.points = points
dict.__init__(
self,
name=self.name,
weight=self.weight,
points=self.points,
total=self.total,
)
@property
def total(self) -> float:
@ -12,4 +19,4 @@ class Assignment:
`вес*СУММ(рез-ты)`
"""
return sum(self.values) * self.weight
return sum(self.points) * self.weight

View File

@ -1,8 +1,7 @@
from .assignment import Assignment
import json
class Student:
class Student(dict):
"""Позволяет выполнять операции над студентами."""
def __init__(self, number: int, name: str, group_id: int, tg_id: int = None):
@ -12,6 +11,15 @@ class Student:
self.tg_id: int = tg_id
self.assignments = []
dict.__init__(
self,
number=self.number,
name=self.name,
group_id=self.group_id,
tg_id=self.tg_id,
assignments=self.assignments,
)
def add_assignment(self, assignment: Assignment):
self.assignments.append(assignment)
@ -24,13 +32,3 @@ class Student:
def score(self):
"""Количество баллов у студента."""
return sum([a.total for a in self.assignments])
def __str__(self):
return json.dumps(
{
"number": self.number,
"name": self.name,
"group_id": self.group_id,
"tg_id": self.tg_id,
}
)

View File

@ -1 +1,3 @@
Flask==2.0.0
google-api-python-client==2.15.0
google-auth-oauthlib==0.4.5

View File

@ -12,7 +12,6 @@ COPY requirements.txt .
RUN python -m pip install -r requirements.txt
WORKDIR /app
COPY . /app
# Creates a non-root user with an explicit UID and adds permission to access the /app folder
# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers

View File

@ -1,58 +1,97 @@
import logging
import os
import platform
import time
import requests
from pathlib import Path
from telegram.ext import Updater
from telegram.ext import CommandHandler
from telegram.ext import MessageHandler, Filters
TOKEN = "1903048555:AAFK-d7prKvOvwwXo0IPzeRwJ1ZcuOT5ty8" # os.environ["TOKEN"]
from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, Update
from telegram.ext import (
Updater,
CommandHandler,
MessageHandler,
Filters,
ConversationHandler,
CallbackContext,
)
from messages import Messages
TOKEN = Path(".secrets/bot_token.txt").read_text()
MESSAGES = Messages()
HOST = "http://carolyn-spreadsheets:5000"
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
# ================================================================ BOT COMMANDS
# Стартовое сообщение (к команде /start)
def start(update, context):
def start(update: Update, context: CallbackContext):
"""Стартовое сообщение (к команде /start)"""
user_id = update.message.from_user.id
p = context.args[0] if len(context.args) > 0 else None
if p is None:
context.bot.send_message(
chat_id=update.effective_chat.id,
text="Нет доступа к боту",
)
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(
"http://127.0.0.1:5000/auth",
params={"token": p, "tg_id": update.effective_chat.id},
f"{HOST}/auth",
params={"token": p, "tg_id": user_id},
).json()
except requests.exceptions.ConnectionError:
update.message.reply_sticker(MESSAGES.stickers.DEAD)
return
context.bot.send_message(
chat_id=update.effective_chat.id,
text=f"Привет, {data}",
text=MESSAGES.auth.hello(data),
)
# Ответ на не командное сообщение (отвечает тем же сообщением)
def echo(update, context):
def grades(update: Update, context: CallbackContext):
"""Команда: Получить оценки студента."""
user_id = update.message.from_user.id
try:
data = requests.get(f"{HOST}/grades", params={"tg_id": user_id}).json()
score = data["score"]
grade = data["grade"]
n_of_assignments = len(data["assignments"])
score_message = MESSAGES.score.get(grade, score, n_of_assignments)
update.message.reply_html(score_message)
update.message.reply_sticker(MESSAGES.stickers.bad())
except:
LOG.exception("Failed to get grades.")
update.message.reply_sticker(MESSAGES.stickers.DEAD)
def echo(update: Update, context: CallbackContext):
"""Ответ на не командное сообщение (отвечает тем же сообщением)"""
context.bot.send_message(chat_id=update.effective_chat.id, text=update.message.text)
# ==================================================================== HANDLERS
start_handler = CommandHandler("start", start)
grades_handler = CommandHandler("grades", grades)
echo_handler = MessageHandler(Filters.text & (~Filters.command), echo)
dispatcher.add_handler(start_handler)
dispatcher.add_handler(grades_handler)
dispatcher.add_handler(echo_handler)
# Начало работы бота

View File

@ -0,0 +1 @@
from .messages import Messages

View File

@ -0,0 +1,84 @@
import random
class Messages:
class Auth:
def __init__(self):
self.NO_AUTH = "[Правила авторизации](https://github.com/Faridik/Carolyn/wiki/%F0%9F%A6%B8%E2%80%8D%E2%99%82%EF%B8%8F-%D0%90%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F)"
self.START = "🔑 Авторизация..."
self.NO_ACCESS = "⛔ Нет доступа"
def hello(self, data):
return f"Привет, {data} 👋"
class Score:
def get(self, grade, score, n_of_assignments):
summary = (
f"Ранг: <b>{score:.2f}</b> {n_of_assignments} зад.\n"
+ f"Оценка: <b>{grade:.2f}</b>"
)
return summary
class Spreadsheets:
def __init__(self):
self.DEAD = "⚰ Сервис «таблицы» недоступен"
class Stickers:
def __init__(self):
# Воробей павлик с колокольчиком и надписью "позор"
self.POZOR = "CAACAgIAAxkBAAEm1RhhBZg-2D6NypUeTsnbToD8_LMFTAACuUcAAulVBRjfnofQTkeMnCAE"
# кот Сима в петле плачет и показывает палец вверх
self.ROPE = "CAACAgIAAxkBAAEm1SFhBZjLaZgFIkvyxfBmAplwUWQFwwACBS0AAulVBRiIaSQ42WLoyyAE"
# Акио смотрит на брокколи
self.BROCCOLI = "CAACAgIAAxkBAAEm1SVhBZkd24Dy2B_wYSCi6UrNuUjgwQACEUkAAulVBRiykDzrzywbmiAE"
# Ян показывает палец вниз
self.THUMB_DOWN = "CAACAgIAAxkBAAEm1SthBZlcos0_TbJo8W7mAcqGLNAh2wACJ5cAAp7OCwABDddMclD7Tf8gBA"
# Тигр закатывает глаза
self.EYES_UP = "CAACAgEAAxkBAAEm1TBhBZmIZTrwzhGSzC47rNFbewQe6QAC4gADOA6CEeTgk4YIcTeWIAQ"
# Нутри большими глазами и надписью "пипец"
self.PPTS = "CAACAgIAAxkBAAEm1TZhBZnNVwLXmrbZwvdGjxiSwefzDAACn0sAAulVBRhECmBPSGCXHSAE"
# Попугай Кент с недовольной мордахой
self.GRUMPY_KENT = "CAACAgIAAxkBAAEm1UBhBZn1gXmRfxaK_RqFTj1aFxLY-gACy0EAAulVBRhgQdlH2rd0uyAE"
# wojak
self.WOJAK = "CAACAgIAAxkBAAEm1UJhBZpfHNYVT_ZLrxUpyi8qRLWJGgACPAADB7lDCi2YrzAEyxJeIAQ"
# Лэтишный котик и надпись "ОЙ"
self.OOPS = "CAACAgIAAxkBAAEm1URhBZp2li7w2E1M6PirG7UnqLOc2QACSxEAAlTE4UoR1Olz8RANZCAE"
# Мем "оп ахах неловко вышло"
self.NELOVKO = "CAACAgIAAxkBAAEm1UZhBZqZ94SFa1e6d-Zy5I-6_SC_fQACgwgAAh8MqEiLbHl9nugoYSAE"
# Попугай смотрит в зеркало "посмотри что с тобой стало"
self.MIRROR = "CAACAgIAAxkBAAEm1VFhBZudma_FmFhybGgXikz3csc0BQAC2UEAAulVBRgkdje995ir7iAE"
# Попугай с сигаретой
self.CIG = "CAACAgIAAxkBAAEm1VZhBZv6p7GsHS6wcyt2mCXoHJCo-wAC0UEAAulVBRghLLSQAcU6rSAE"
# Попугай и песок
self.SAND = "CAACAgIAAxkBAAEm1VhhBZwbw83_UVS8A5Crsf3EVAABvWIAAshBAALpVQUYl51K7ci-ClIgBA"
# Акио падает в обморок
self.PANIC = "CAACAgIAAxkBAAEm1VxhBZxwqRUJmVXDtzmsPJUIIGJgegACB0kAAulVBRiMI-hzK3GcKiAE"
# Эникей надпись "умер"
self.DEAD = "CAACAgIAAxkBAAEm1aRhBaWXRb_tcI03O1onx0jW0bHmuAACejcAAulVBRi1oSUXeBATmiAE"
def bad(self):
"""Возвращает стикер с грустным смыслом."""
return random.choice(
[
self.POZOR,
self.ROPE,
self.BROCCOLI,
self.THUMB_DOWN,
self.EYES_UP,
self.PPTS,
self.GRUMPY_KENT,
self.WOJAK,
self.OOPS,
self.NELOVKO,
self.MIRROR,
self.CIG,
self.SAND,
self.PANIC,
]
)
def __init__(self):
self.auth = self.Auth()
self.score = self.Score()
self.spreadsheets = self.Spreadsheets()
self.stickers = self.Stickers()

View File

@ -13,7 +13,5 @@ services:
telegrambot:
container_name: "carolyn-telegrambot"
build: ./TelegramBot
environment:
TOKEN: "1903048555:AAFK-d7prKvOvwwXo0IPzeRwJ1ZcuOT5ty8"
volumes:
- ./TelegramBot:/app