create event
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
from aiogram import Bot, Dispatcher
|
||||
from aiogram.client.default import DefaultBotProperties
|
||||
from aiogram.enums import ParseMode
|
||||
from aiogram_dialog import setup_dialogs
|
||||
from structlog import get_logger
|
||||
|
||||
@@ -12,7 +10,6 @@ from config.config import settings
|
||||
logger = get_logger()
|
||||
bot = Bot(
|
||||
token=settings.bot_token,
|
||||
default=DefaultBotProperties(parse_mode=ParseMode.MARKDOWN_V2),
|
||||
)
|
||||
dp = Dispatcher()
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from aiogram import Router
|
||||
|
||||
from .events.dialogs import events_dialog
|
||||
from .new_event.dialogs import new_event_dialog
|
||||
from .profile.dialogs import profile_dialog
|
||||
from .start.dialogs import start_dialog
|
||||
|
||||
@@ -8,3 +9,4 @@ dialogs_router = Router(name="dialogs")
|
||||
dialogs_router.include_router(start_dialog)
|
||||
dialogs_router.include_router(events_dialog)
|
||||
dialogs_router.include_router(profile_dialog)
|
||||
dialogs_router.include_router(new_event_dialog)
|
||||
|
||||
@@ -1,39 +1,34 @@
|
||||
from aiogram_dialog import Dialog, Window
|
||||
from aiogram_dialog.widgets.kbd import Back, Cancel, Column, Select
|
||||
from aiogram_dialog.widgets.text import Const, Format
|
||||
from aiogram_dialog.widgets.text import Const, Format, Jinja
|
||||
|
||||
from .getters import events_getter
|
||||
from app.bot.dialogs.templates import event_template
|
||||
|
||||
from .getters import event_getter, events_list_getter
|
||||
from .handlers import on_event_selected
|
||||
from .states import EventsSG
|
||||
|
||||
|
||||
async def on_event_selected(
|
||||
c,
|
||||
widget: Select,
|
||||
manager,
|
||||
item_id: str,
|
||||
):
|
||||
manager.dialog_data["selected_event"] = item_id
|
||||
await manager.next()
|
||||
|
||||
events_dialog = Dialog(
|
||||
Window(
|
||||
Const("События"),
|
||||
Column(
|
||||
Cancel(Const("Назад")),
|
||||
Select(
|
||||
Format("{item}"),
|
||||
Format("{item[title]}"),
|
||||
id="categ",
|
||||
item_id_getter=lambda x: x,
|
||||
item_id_getter=lambda x: x["id"],
|
||||
items="events",
|
||||
on_click=on_event_selected,
|
||||
),
|
||||
),
|
||||
getter=events_getter,
|
||||
getter=events_list_getter,
|
||||
state=EventsSG.events_list,
|
||||
),
|
||||
Window(
|
||||
Format("{dialog_data[selected_event]}"),
|
||||
Jinja(event_template),
|
||||
Back(Const("Назад")),
|
||||
getter=event_getter,
|
||||
parse_mode="HTML",
|
||||
state=EventsSG.event,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
from aiogram.types import User
|
||||
from aiogram_dialog import DialogManager
|
||||
|
||||
from app.infrastructure.database.crud import get_event_by_id, get_events_list
|
||||
|
||||
async def events_getter(dialog_manager: DialogManager, event_from_user: User, **kwargs) -> dict[str, str]:
|
||||
return {"events": ["ev1", "ev2", "ev3"]}
|
||||
|
||||
async def events_list_getter(
|
||||
dialog_manager: DialogManager, event_from_user: User, **kwargs
|
||||
) -> dict[str, str]:
|
||||
events = await get_events_list(dialog_manager.middleware_data["session"])
|
||||
return {"events": [{"title": event.title, "id": event.id} for event in events]}
|
||||
|
||||
|
||||
async def event_getter(
|
||||
dialog_manager: DialogManager, **kwargs
|
||||
) -> dict[str, str]:
|
||||
return {
|
||||
"event_obj": await get_event_by_id(
|
||||
dialog_manager.middleware_data["session"],
|
||||
int(dialog_manager.dialog_data["selected_event"]),
|
||||
)
|
||||
}
|
||||
|
||||
13
app/bot/dialogs/flows/events/handlers.py
Normal file
13
app/bot/dialogs/flows/events/handlers.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from aiogram.types import CallbackQuery
|
||||
from aiogram_dialog import DialogManager
|
||||
from aiogram_dialog.widgets.kbd import Select
|
||||
|
||||
|
||||
async def on_event_selected(
|
||||
callback: CallbackQuery,
|
||||
widget: Select,
|
||||
manager: DialogManager,
|
||||
item_id: str,
|
||||
):
|
||||
manager.dialog_data["selected_event"] = item_id
|
||||
await manager.next()
|
||||
52
app/bot/dialogs/flows/new_event/dialogs.py
Normal file
52
app/bot/dialogs/flows/new_event/dialogs.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from aiogram_dialog import Dialog, Window
|
||||
from aiogram_dialog.widgets.input import TextInput
|
||||
from aiogram_dialog.widgets.kbd import Back, Button, Calendar, Cancel
|
||||
from aiogram_dialog.widgets.text import Const, Jinja
|
||||
|
||||
from app.bot.dialogs.templates import event_template
|
||||
|
||||
from .getters import event_data_getter
|
||||
from .handlers import (
|
||||
confirm_creation,
|
||||
input_description,
|
||||
input_end_date,
|
||||
input_start_date,
|
||||
input_title,
|
||||
)
|
||||
from .states import NewEventSG
|
||||
|
||||
new_event_dialog = Dialog(
|
||||
Window(
|
||||
Const("Введите название:"),
|
||||
TextInput(id="title", on_success=input_title),
|
||||
Cancel(Const("❌ Отмена")),
|
||||
state=NewEventSG.input_title,
|
||||
),
|
||||
Window(
|
||||
Const("Введите описание:"),
|
||||
TextInput(id="description", on_success=input_description),
|
||||
Back(Const("◀️ Назад")),
|
||||
state=NewEventSG.input_description,
|
||||
),
|
||||
Window(
|
||||
Const("Выберите дату начала:"),
|
||||
Calendar(id="start_date", on_click=input_start_date),
|
||||
Back(Const("◀️ Назад")),
|
||||
state=NewEventSG.input_start_date,
|
||||
),
|
||||
Window(
|
||||
Const("Выберите дату окончания:"),
|
||||
Calendar(id="end_date", on_click=input_end_date),
|
||||
Back(Const("◀️ Назад")),
|
||||
state=NewEventSG.input_end_date,
|
||||
),
|
||||
Window(
|
||||
Jinja(event_template),
|
||||
Back(Const("◀️ Назад")),
|
||||
Cancel(Const("❌ Отмена")),
|
||||
Button(Const("✅ Создать"), id="cancel", on_click=confirm_creation),
|
||||
state=NewEventSG.confirm_creation,
|
||||
getter=event_data_getter,
|
||||
parse_mode="HTML",
|
||||
),
|
||||
)
|
||||
8
app/bot/dialogs/flows/new_event/getters.py
Normal file
8
app/bot/dialogs/flows/new_event/getters.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from aiogram.types import User
|
||||
from aiogram_dialog import DialogManager
|
||||
|
||||
|
||||
async def event_data_getter(
|
||||
dialog_manager: DialogManager, event_from_user: User, **kwargs
|
||||
):
|
||||
return {"event_obj": dialog_manager.dialog_data["event_obj"]}
|
||||
61
app/bot/dialogs/flows/new_event/handlers.py
Normal file
61
app/bot/dialogs/flows/new_event/handlers.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from datetime import date
|
||||
|
||||
from aiogram.types import CallbackQuery
|
||||
from aiogram_dialog import DialogManager
|
||||
from aiogram_dialog.widgets.input import ManagedTextInput
|
||||
from aiogram_dialog.widgets.kbd import Button, Calendar
|
||||
|
||||
from app.infrastructure.database.crud import create_event
|
||||
|
||||
|
||||
async def input_title(
|
||||
callback: CallbackQuery,
|
||||
widget: ManagedTextInput,
|
||||
manager: DialogManager,
|
||||
text: date,
|
||||
):
|
||||
if "event_obj" not in manager.dialog_data:
|
||||
manager.dialog_data["event_obj"] = {}
|
||||
manager.dialog_data["event_obj"]["title"] = text
|
||||
await manager.next()
|
||||
|
||||
|
||||
async def input_description(
|
||||
callback: CallbackQuery,
|
||||
widget: ManagedTextInput,
|
||||
manager: DialogManager,
|
||||
text: date,
|
||||
):
|
||||
manager.dialog_data["event_obj"]["description"] = text
|
||||
await manager.next()
|
||||
|
||||
|
||||
async def input_start_date(
|
||||
callback: CallbackQuery,
|
||||
widget: Calendar,
|
||||
manager: DialogManager,
|
||||
selected_date: date,
|
||||
):
|
||||
manager.dialog_data["event_obj"]["start_date"] = selected_date
|
||||
await manager.next()
|
||||
|
||||
|
||||
async def input_end_date(
|
||||
callback: CallbackQuery,
|
||||
widget: Calendar,
|
||||
manager: DialogManager,
|
||||
selected_date: date,
|
||||
):
|
||||
manager.dialog_data["event_obj"]["end_date"] = selected_date
|
||||
await manager.next()
|
||||
|
||||
|
||||
async def confirm_creation(
|
||||
callback: CallbackQuery,
|
||||
button: Button,
|
||||
manager: DialogManager,
|
||||
):
|
||||
await create_event(
|
||||
manager.middleware_data["session"], **manager.dialog_data["event_obj"]
|
||||
)
|
||||
await manager.done()
|
||||
9
app/bot/dialogs/flows/new_event/states.py
Normal file
9
app/bot/dialogs/flows/new_event/states.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
|
||||
|
||||
class NewEventSG(StatesGroup):
|
||||
input_title = State()
|
||||
input_description = State()
|
||||
input_start_date = State()
|
||||
input_end_date = State()
|
||||
confirm_creation = State()
|
||||
@@ -1,11 +1,11 @@
|
||||
from aiogram_dialog import Dialog, Window
|
||||
from aiogram_dialog.widgets.input import TextInput
|
||||
from aiogram_dialog.widgets.kbd import Cancel, SwitchTo
|
||||
from aiogram_dialog.widgets.text import Const, Format
|
||||
from aiogram_dialog.widgets.text import Const, Jinja
|
||||
|
||||
from app.bot.dialogs.templates import profile_template
|
||||
from app.bot.dialogs.widgets.getters import user_getter
|
||||
|
||||
from .getters import phone_getter
|
||||
from .handlers import (
|
||||
name_type_factory,
|
||||
on_error,
|
||||
@@ -17,9 +17,7 @@ from .states import ProfileSG
|
||||
|
||||
profile_dialog = Dialog(
|
||||
Window(
|
||||
Const("*Профиль*\n"),
|
||||
Format("*Имя*: {user.fullname}"),
|
||||
Format("*Телефон*: {phone}"),
|
||||
Jinja(profile_template),
|
||||
SwitchTo(
|
||||
Const("✏️ изменить имя"),
|
||||
id="change_name",
|
||||
@@ -31,8 +29,9 @@ profile_dialog = Dialog(
|
||||
state=ProfileSG.change_phone,
|
||||
),
|
||||
Cancel(Const("◀️ назад")),
|
||||
getter=user_getter,
|
||||
parse_mode="HTML",
|
||||
state=ProfileSG.profile,
|
||||
getter=[user_getter, phone_getter],
|
||||
),
|
||||
Window(
|
||||
Const("Введите имя"),
|
||||
@@ -55,5 +54,6 @@ profile_dialog = Dialog(
|
||||
on_error=on_error,
|
||||
),
|
||||
state=ProfileSG.change_phone,
|
||||
parse_mode="Markdown",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ def name_type_factory(text: str):
|
||||
|
||||
def phone_type_factory(text: str):
|
||||
if len(re.findall("\d", text)) < 11:
|
||||
raise ValueError("Телефон должен быть в формате \+79991112233")
|
||||
raise ValueError("Телефон должен быть в формате +79991112233")
|
||||
return text
|
||||
|
||||
async def on_error(
|
||||
|
||||
@@ -3,6 +3,7 @@ from aiogram_dialog.widgets.kbd import Button, Start
|
||||
from aiogram_dialog.widgets.text import Const, Format
|
||||
|
||||
from app.bot.dialogs.flows.events.dialogs import EventsSG
|
||||
from app.bot.dialogs.flows.new_event.dialogs import NewEventSG
|
||||
from app.bot.dialogs.flows.profile.dialogs import ProfileSG
|
||||
from app.bot.dialogs.widgets.getters import is_admin_getter, user_getter
|
||||
|
||||
@@ -12,7 +13,12 @@ start_dialog = Dialog(
|
||||
Window(
|
||||
Format("Привет, {user.fullname}"),
|
||||
Start(Const("📃 события"), id="events", state=EventsSG.events_list),
|
||||
Button(Const("✏️ создать событие"), id="create_event", when="is_admin"),
|
||||
Start(
|
||||
Const("✏️ создать событие"),
|
||||
id="create_event",
|
||||
state=NewEventSG.input_title,
|
||||
when="is_admin",
|
||||
),
|
||||
Start(Const("👤 профиль"), id="profile", state=ProfileSG.profile),
|
||||
getter=[user_getter, is_admin_getter],
|
||||
state=StartSG.start,
|
||||
|
||||
10
app/bot/dialogs/templates/__init__.py
Normal file
10
app/bot/dialogs/templates/__init__.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from pathlib import Path
|
||||
path = Path(__file__).parent
|
||||
|
||||
with open(path / "event.jinja2", encoding="utf-8") as f:
|
||||
event_template = f.read()
|
||||
|
||||
with open(path / "profile.jinja2", encoding="utf-8") as f:
|
||||
profile_template = f.read()
|
||||
|
||||
__all__ = ("event_template", "profile_template")
|
||||
5
app/bot/dialogs/templates/event.jinja2
Normal file
5
app/bot/dialogs/templates/event.jinja2
Normal file
@@ -0,0 +1,5 @@
|
||||
<b>{{ event_obj["title"] }}</b>
|
||||
|
||||
{{ event_obj["description"] }}
|
||||
|
||||
{{ event_obj["start_date"].strftime("%d.%m.%Y") }} - {{ event_obj["end_date"].strftime("%d.%m.%Y") }}
|
||||
4
app/bot/dialogs/templates/profile.jinja2
Normal file
4
app/bot/dialogs/templates/profile.jinja2
Normal file
@@ -0,0 +1,4 @@
|
||||
<b>Профиль</b>
|
||||
|
||||
<b>Имя:</b> {{ user.fullname}}
|
||||
<b>Телефон:</b> {% if user.phone %}+{% endif %}{{user.phone}}
|
||||
@@ -1,7 +1,9 @@
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from .models import User
|
||||
from .models import Event, User
|
||||
|
||||
|
||||
async def get_user_by_tg_id(session: AsyncSession, user_tg_id: int) -> User | None:
|
||||
@@ -19,6 +21,7 @@ async def create_user(
|
||||
user = User(tg_id=tg_id, fullname=fullname, role=role, phone=phone)
|
||||
session.add(user)
|
||||
await session.commit()
|
||||
await session.refresh(user)
|
||||
return user
|
||||
|
||||
|
||||
@@ -32,3 +35,63 @@ async def update_user(
|
||||
user.phone = phone
|
||||
await session.commit()
|
||||
return user
|
||||
|
||||
|
||||
async def get_events_list(session: AsyncSession) -> list[Event]:
|
||||
result = await session.execute(
|
||||
select(Event).where(Event.start_date >= datetime.now())
|
||||
)
|
||||
return result.scalars()
|
||||
|
||||
|
||||
async def get_event_by_id(session: AsyncSession, event_id: int) -> Event:
|
||||
result = await session.execute(select(Event).where(Event.id == event_id))
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
|
||||
async def create_event(
|
||||
session: AsyncSession,
|
||||
title: str,
|
||||
description: str,
|
||||
start_date: datetime,
|
||||
end_date: datetime,
|
||||
) -> Event:
|
||||
event = Event(
|
||||
title=title,
|
||||
description=description,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
)
|
||||
session.add(event)
|
||||
await session.commit()
|
||||
await session.refresh(event)
|
||||
return event
|
||||
|
||||
|
||||
async def delete_event(
|
||||
session: AsyncSession,
|
||||
event_id: int,
|
||||
) -> None:
|
||||
session.delete(await get_event_by_id(session, event_id))
|
||||
await session.commit()
|
||||
|
||||
|
||||
async def update_event(
|
||||
session: AsyncSession,
|
||||
event_id: int,
|
||||
title: str = None,
|
||||
description: str = None,
|
||||
start_date: datetime = None,
|
||||
end_date: datetime = None,
|
||||
) -> Event:
|
||||
event = await get_event_by_id(session, event_id)
|
||||
if title:
|
||||
event.title = title
|
||||
if description:
|
||||
event.description = description
|
||||
if start_date:
|
||||
event.start_date = start_date
|
||||
if end_date:
|
||||
event.end_date = end_date
|
||||
await session.commit()
|
||||
return event
|
||||
Reference in New Issue
Block a user