diff --git a/bot/event_scenarios/auth.py b/bot/event_scenarios/auth.py index bc8b603..ab2dc42 100644 --- a/bot/event_scenarios/auth.py +++ b/bot/event_scenarios/auth.py @@ -5,8 +5,8 @@ settings = get_settings() beaver = requests.post( - f"{settings.BACKEND_URL}/token", - {"username": settings.BACKEND_USER, "password": settings.BACKEND_PASSWORD}, + f"{settings.BACKEND_URL}/token", + {"username": settings.BACKEND_USER, "password": settings.BACKEND_PASSWORD}, ) auth_data = json.loads(beaver.content) auth_headers = {"Authorization": f"Bearer {auth_data.get('access_token')}"} diff --git a/bot/event_scenarios/event_processors.py b/bot/event_scenarios/event_processors.py index bde84d4..a5165b2 100644 --- a/bot/event_scenarios/event_processors.py +++ b/bot/event_scenarios/event_processors.py @@ -6,9 +6,10 @@ import bot.event_scenarios.msg_reactions as reactions import bot.event_scenarios.spam as spam import bot.event_scenarios.registry as registry +import bot.event_scenarios.workflow as workflow +import bot.event_scenarios.summary as summary import re - settings = get_settings() @@ -25,6 +26,13 @@ def process_registry(vk: VkApiMethod, event: Event): registry.on_start_button(vk, event) if event.text == settings.REGISTRY_MODE: registry.on_mode_change(vk) + elif (len(event.text.split()) >= 2 and + event.text.split()[0] == settings.REGISTRY_MODE and + event.text.split()[1] == 'spam_message' + ): + message = event.text.split(' spam_message ')[-1] + if settings.REGISTRY_MODE not in message: + registry.on_spam_message(vk, message) elif event.text == reactions.Registry.START_BUTTON: registry.on_start_button(vk, event) elif re.match(r"([А-ЯЁ][а-яё]+[\-\s]?){2,}", event.text): @@ -55,21 +63,49 @@ def process_registry(vk: VkApiMethod, event: Event): registry.on_approve(vk, event) elif redis_db.hget(event.user_id, "approved") and not redis_db.hexists( - event.user_id, "registrated" + event.user_id, "registrated" ): # user cv received registry.on_about(vk, event) - elif event.text != "Начать" and redis_db.hexists(event.user_id, 'registrated'): + elif event.text != "Начать" and redis_db.hexists(event.user_id, "registrated"): registry.on_random_end(vk, event) - elif event.text != "Начать" and\ - not redis_db.hexists(event.user_id, 'registrated') and\ - not redis_db.hexists(event.user_id, 'start_button'): + elif ( + event.text != "Начать" + and not redis_db.hexists(event.user_id, "registrated") + and not redis_db.hexists(event.user_id, "start_button") + ): registry.on_random_begin(vk, event) -def process_workflow(vk: VkApiMethod, event: Event, **kwargs): - pass +def process_workflow(vk: VkApiMethod, event: Event): + redis_db = redis.Redis.from_url(settings.REDIS_DSN) + if event.text == "Начать" or event.text == reactions.Registry.START_BUTTON: + workflow.on_registry_expiry(vk, event) + elif event.text == settings.WORKFLOW_MODE: + workflow.on_mode_change(vk) + elif event.text == reactions.Workflow.CONFIRM_BUTTON: + workflow.on_start_button(vk, event) + elif event.text and \ + redis_db.hexists(event.user_id, "workflow") and \ + redis_db.hexists(event.user_id, "workflow_type") and \ + redis_db.hget(event.user_id, "workflow_type").decode('utf-8') == 'none': + workflow.on_none_request_ans(vk, event) + elif event.text and \ + redis_db.hexists(event.user_id, "workflow") and \ + redis_db.hexists(event.user_id, "workflow_type") and \ + redis_db.hget(event.user_id, "workflow_type").decode('utf-8') == 'text': + workflow.on_text_request_ans(vk, event) + elif event.text and \ + redis_db.hexists(event.user_id, "workflow") and \ + redis_db.hexists(event.user_id, "workflow_type") and \ + redis_db.hget(event.user_id, "workflow_type").decode('utf-8') == 'file': + workflow.on_none_request_ans(vk, event) + elif event.text and \ + redis_db.hexists(event.user_id, "workflow") and \ + redis_db.hexists(event.user_id, "workflow_type") and \ + redis_db.hget(event.user_id, "workflow_type").decode('utf-8') == 'video': + workflow.on_none_request_ans(vk, event) -def process_summary(vk: VkApiMethod, event: Event, **kwargs): +def process_summary(vk: VkApiMethod, event: Event): pass diff --git a/bot/event_scenarios/msg_reactions.py b/bot/event_scenarios/msg_reactions.py index 8b695c9..0a8135d 100644 --- a/bot/event_scenarios/msg_reactions.py +++ b/bot/event_scenarios/msg_reactions.py @@ -1,5 +1,7 @@ from bot.schemas.models import Directions +from bot.event_scenarios.registry.utils import get_directions from dataclasses import dataclass +from .registry.utils import get_directions @dataclass @@ -36,3 +38,14 @@ class Registry: APPROVE_FALSE = "Нет" ABOUT_QUESTION = "Расскажи, что ты уже умеешь, есть ли у тебя опыт в этой области?" ON_CV_ANSWER = """Классно, будем знакомы! Мы тебя зарегистрировали, с 15 ноября можно будет начать учиться. А до этого мы пришлём тебе ссылку на чат с кураторами и остальными участниками 😉 """ + + +@dataclass +class Workflow: + @classmethod + def start_message(cls, direction_id: int): + return f"""ARE YOU READYYYY?? Мы уже держим палец над кнопкой, которая откроет тебе доступ к курсу '{get_directions()[direction_id].name}'. Тебе осталось только прочитать небольшую инструкцию и нажать кнопку «Всё понятно». После нажатия кнопки бот пришлет тебе первое видео. Когда посмотришь его, нажимай кнопку “К следующему уроку”. После некоторых уроков тебя будут ждать проверочные задания — делать их или нет, решать тебе. А иногда будут встречаться контрольные задания — они обязательные, их нужно сделать и прислать боту, чтобы открыть доступ к следующим урокам. Внимательно читай, что тебе нужно прислать боту — ссылку на гугл-диск, файл или просто текст. Если у тебя возникнут вопросы по курсу, установке или интерфейсу программ, организационным моментам или чему-то ещё, просто напиши в чат курса, и кураторы помогут тебе. Вот и всё, теперь погнали!” """ + + REGISTRY_EXPIRED = """Ой, кажется уже слишком поздно. Регистрация на ШЭ ЭМ уже закончилась, и мы не можем тебя добавить. Но есть и хорошая новость — скоро здесь будет что-то супер-пупер-дупер интересное! Подпишись на уведомления группы, чтобы не пропустить.""" + CONFIRM_BUTTON = """Всё понятно""" + NEXT_VIDEO_BUTTON = """К следующему уроку""" diff --git a/bot/event_scenarios/registry/__init__.py b/bot/event_scenarios/registry/__init__.py index 3196a6d..a3babe8 100644 --- a/bot/event_scenarios/registry/__init__.py +++ b/bot/event_scenarios/registry/__init__.py @@ -9,6 +9,7 @@ on_about, on_random_begin, on_random_end, + on_spam_message, ) from .utils import get_directions @@ -25,4 +26,5 @@ "on_about", "on_random_begin", "on_random_end", + "on_spam_message", ] diff --git a/bot/event_scenarios/registry/event_handlers.py b/bot/event_scenarios/registry/event_handlers.py index 7065451..26cf7d6 100644 --- a/bot/event_scenarios/registry/event_handlers.py +++ b/bot/event_scenarios/registry/event_handlers.py @@ -1,6 +1,5 @@ import requests import redis -import bot.schemas.models as schemas from logging import getLogger from vk_api.longpoll import Event from vk_api.vk_api import VkApiMethod @@ -19,7 +18,9 @@ def on_random_begin(vk: VkApiMethod, event: Event): - utils.on_start_message_button(vk, event.user_id, message='Привет!', button_txt="Начать") + utils.on_start_message_button( + vk, event.user_id, message="Привет!", button_txt="Начать" + ) def on_mode_change(vk: VkApiMethod) -> None: @@ -40,16 +41,17 @@ def on_mode_change(vk: VkApiMethod) -> None: def on_start_button(vk: VkApiMethod, event: Event) -> None: - redis_db.hdel(event.user_id, - "name", - "union_num", - "year", - "direction_id", - "registrated", - "approved", - "start_button" - ) - redis_db.hset(event.user_id, 'start_button', 'started') + redis_db.hdel( + event.user_id, + "name", + "union_num", + "year", + "direction_id", + "registrated", + "approved", + "start_button", + ) + redis_db.hset(event.user_id, "start_button", "started") utils.send_message(vk, event.user_id, message=reactions.Registry.FIO_QUESTION) redis_db.hset(name=event.user_id, key="social_web_id", value=event.user_id) @@ -57,14 +59,18 @@ def on_start_button(vk: VkApiMethod, event: Event) -> None: def on_fio_ans(vk: VkApiMethod, event: Event): name = Name(event.text) if name.is_valid(): - utils.send_message(vk, event.user_id, message=dedent(reactions.Registry.UNION_QUESTION)) + utils.send_message( + vk, event.user_id, message=dedent(reactions.Registry.UNION_QUESTION) + ) redis_db.hset(name=event.user_id, key="name", value=event.text) else: utils.send_message(vk, event.user_id, message=reactions.Registry.ON_FAILURE) def on_union_ans(vk: VkApiMethod, event: Event) -> None: - utils.send_message(vk, event.user_id, message=dedent(reactions.Registry.YEAR_QUESTION)) + utils.send_message( + vk, event.user_id, message=dedent(reactions.Registry.YEAR_QUESTION) + ) redis_db.hset(name=event.user_id, key="union_num", value=event.text) @@ -81,6 +87,23 @@ def on_year_ans(vk: VkApiMethod, event: Event) -> None: event.user_id, message=dedent(reactions.Registry.DIRECTION_QUESTION), keyboard=kb.get_keyboard(), + attach=None, + ) + + +def on_discard_direction(vk: VkApiMethod, event: Event): + kb = VkKeyboard(one_time=False, inline=True) + + for i in range(len(directions)): + kb.add_button(directions[i].name) + if i + 1 < len(directions): + kb.add_line() + utils.send_message( + vk, + event.user_id, + message=dedent(reactions.Registry.DIRECTION_QUESTION), + keyboard=kb.get_keyboard(), + attach=None, ) @@ -118,13 +141,13 @@ def on_direction_ans(vk: VkApiMethod, event: Event): def on_approve(vk: VkApiMethod, event: Event): if event.text == reactions.Registry.APPROVE_TRUE: - utils.send_message(vk, event.user_id, message=dedent(reactions.Registry.ABOUT_QUESTION)) + utils.send_message( + vk, event.user_id, message=dedent(reactions.Registry.ABOUT_QUESTION) + ) redis_db.hset(event.user_id, "approved", "approved") if event.text == reactions.Registry.APPROVE_FALSE: utils.send_message(vk, event.user_id, message="Ладно, давай снова:") - redis_db.hdel(event.user_id, - "direction_id" - ) + redis_db.hdel(event.user_id, "direction_id") on_discard_direction(vk, event) @@ -137,7 +160,7 @@ def on_about(vk: VkApiMethod, event: Event): if len(fio) == 3: middle_name = fio[2] elif len(fio) == 2: - middle_name = '' + middle_name = "" user = dict( union_id=register_data[b"union_num"].decode("utf-8"), direction_id=register_data[b"direction_id"].decode("utf-8"), @@ -152,21 +175,36 @@ def on_about(vk: VkApiMethod, event: Event): f"{settings.BACKEND_URL}/user/", json=user, headers=auth_headers ) if res.status_code == 200: - utils.send_message(vk, event.user_id, message=dedent(reactions.Registry.ON_CV_ANSWER)) + utils.send_message( + vk, event.user_id, message=dedent(reactions.Registry.ON_CV_ANSWER) + ) elif res.status_code == 409: - utils.send_message(vk, - event.user_id, - message=dedent("Вы уже в базе данных. Для изменения данных обратитесь в поддержку") - ) + utils.send_message( + vk, + event.user_id, + message=dedent( + "Вы уже в базе данных. Для изменения данных обратитесь в поддержку" + ), + ) else: - utils.send_message(vk, - event.user_id, - message="Something went wrong" - ) + utils.send_message(vk, event.user_id, message="Something went wrong") logger.info(f"{res.status_code}-{register_data[b'social_web_id'].decode('utf-8')}") def on_random_end(vk: VkApiMethod, event: Event): - utils.send_message(vk, - event.user_id, - message="Ты уже зарегистрировался, мы сообщим о начале учебы!") \ No newline at end of file + utils.send_message( + vk, + event.user_id, + message="Ты уже зарегистрировался, мы сообщим о начале учебы!", + ) + + +def on_spam_message(vk: VkApiMethod, message): + res = requests.get(f"{settings.BACKEND_URL}/user/", headers=auth_headers) + users = res.json() + for user in users: + utils.send_message( + vk, + int(user["social_web_id"]), + message=message, + ) diff --git a/bot/event_scenarios/registry/utils.py b/bot/event_scenarios/registry/utils.py index 0928777..1ed2597 100644 --- a/bot/event_scenarios/registry/utils.py +++ b/bot/event_scenarios/registry/utils.py @@ -1,12 +1,8 @@ -from bot.schemas.models import Year -from bot.event_scenarios.msg_reactions import Registry - - class Name: def __init__(self, fio: str): self.success = False self.fio = fio.split() - self.middle_name = '-' + self.middle_name = "-" if len(self.fio) == 2: self.name = self.fio[1].capitalize() self.last_name = self.fio[0].capitalize() diff --git a/bot/event_scenarios/summary/event_handlers.py b/bot/event_scenarios/summary/event_handlers.py index e69de29..5e218f3 100644 --- a/bot/event_scenarios/summary/event_handlers.py +++ b/bot/event_scenarios/summary/event_handlers.py @@ -0,0 +1,12 @@ +import requests +import redis +from logging import getLogger +from vk_api.longpoll import Event +from vk_api.vk_api import VkApiMethod +from bot.config import get_settings +import bot.event_scenarios.msg_utils as utils +import bot.event_scenarios.msg_reactions as reactions +from vk_api.keyboard import VkKeyboard, VkKeyboardColor +from bot.event_scenarios.auth import auth_headers +from textwrap import dedent + diff --git a/bot/event_scenarios/workflow/__init__.py b/bot/event_scenarios/workflow/__init__.py index e69de29..9159522 100644 --- a/bot/event_scenarios/workflow/__init__.py +++ b/bot/event_scenarios/workflow/__init__.py @@ -0,0 +1,16 @@ +from .event_handlers import ( + on_registry_expiry, + on_start_button, + on_mode_change, + on_none_request_ans, + on_text_request_ans, + on_text_request_ans, +) + +__all__ = [ + "on_registry_expiry", + "on_start_button", + "on_mode_change", + "on_text_request_ans", + "on_none_request_ans", +] diff --git a/bot/event_scenarios/workflow/event_handlers.py b/bot/event_scenarios/workflow/event_handlers.py index e69de29..77b1b0f 100644 --- a/bot/event_scenarios/workflow/event_handlers.py +++ b/bot/event_scenarios/workflow/event_handlers.py @@ -0,0 +1,81 @@ +import bot.event_scenarios.msg_reactions as reactions +from vk_api.longpoll import Event +from vk_api.vk_api import VkApiMethod +from vk_api.keyboard import VkKeyboard, VkKeyboardColor +from bot.config import get_settings +import bot.event_scenarios.msg_utils as utils +from bot.event_scenarios.auth import auth_headers +from .utils import get_user_db_id +import redis +import requests +from textwrap import dedent + + +settings = get_settings() +redis_db = redis.Redis.from_url(settings.REDIS_DSN) + + +def on_registry_expiry(vk: VkApiMethod, event: Event): + utils.send_message(vk, event.user_id, dedent(reactions.Workflow.REGISTRY_EXPIRED)) + + +def on_mode_change(vk: VkApiMethod): + res = requests.get(f"{settings.BACKEND_URL}/user/", headers=auth_headers) + users = res.json() + kb = VkKeyboard(one_time=True, inline=False) + kb.add_button(reactions.Workflow.CONFIRM_BUTTON, color=VkKeyboardColor.POSITIVE) + for user in users: + utils.send_message( + vk, + int(user["social_web_id"]), + message=reactions.Workflow.start_message(user["direction_id"]), + keyboard=kb.get_keyboard(), + ) + + +def on_start_button(vk: VkApiMethod, event: Event): + redis_db.hdel(event.user_id, + "workflow", + "workflow_type") + redis_db.hset(event.user_id, "workflow", "started") + db_user_id = get_user_db_id(event.user_id) + video = requests.get( + f"{settings.BACKEND_URL}/uservideo/{db_user_id}", headers=auth_headers + ).json() + link = video["link"] + desc = video["request"] + utils.send_message(vk, event.user_id, message=f"{link}\n{desc}") + request_type = video['request_type'] + if request_type is None: + redis_db.hset(event.user_id, "workflow_type", 'none') + else: + redis_db.hset(event.user_id, "workflow_type", request_type) + redis_db.hset(event.user_id, "workflow", "on workflow") + + +def on_none_request_ans(vk: VkApiMethod, event: Event): + utils.send_message(vk, event.user_id, message='null req') + db_user_id = get_user_db_id(event.user_id) + video = requests.get( + f"{settings.BACKEND_URL}/uservideo/{db_user_id}", headers=auth_headers + ).json() + request_type = video['request_type'] + if request_type is None: + redis_db.hset(event.user_id, "workflow_type", 'none') + else: + redis_db.hset(event.user_id, "workflow_type", request_type) + link = video["link"] + desc = video["request"] + utils.send_message(vk, event.user_id, message=f"{link}\n{desc}") + + +def on_text_request_ans(vk: VkApiMethod, event: Event): + utils.send_message(vk, event.user_id, message='text req') + + +def on_video_request_ans(vk: VkApiMethod, event: Event): + utils.send_message(vk, event.user_id, message='video req') + + +def on_file_request_ans(vk: VkApiMethod, event: Event): + utils.send_message(vk, event.user_id, message='video req') diff --git a/bot/event_scenarios/workflow/utils.py b/bot/event_scenarios/workflow/utils.py new file mode 100644 index 0000000..1063475 --- /dev/null +++ b/bot/event_scenarios/workflow/utils.py @@ -0,0 +1,14 @@ +import requests +from bot.config import get_settings +from bot.event_scenarios.auth import auth_headers + +settings = get_settings() + + +def get_user_db_id(social_web_id: int) -> int: + res = requests.get(f"{settings.BACKEND_URL}/user/", headers=auth_headers) + db_user_id = 0 + for user in res.json(): + if int(user["social_web_id"]) == social_web_id: + db_user_id = user["id"] + return db_user_id