mirror of
https://github.com/koloideal/DutyLog.git
synced 2026-06-10 10:25:29 +03:00
update
This commit is contained in:
@@ -11,6 +11,7 @@ from dishka.integrations.aiogram import setup_dishka
|
|||||||
from dutylog.application.bot.user_handlers import router as user_router
|
from dutylog.application.bot.user_handlers import router as user_router
|
||||||
from dutylog.application.bot.user_dialogs import main_menu_dialog
|
from dutylog.application.bot.user_dialogs import main_menu_dialog
|
||||||
from dutylog.application.bot.admin_dialogs import admin_menu_dialog
|
from dutylog.application.bot.admin_dialogs import admin_menu_dialog
|
||||||
|
from dutylog.application.bot.creator_dialogs import creator_menu_dialog
|
||||||
from dutylog.application.bot.user_dialogs.registration_dialog import registration_dialog
|
from dutylog.application.bot.user_dialogs.registration_dialog import registration_dialog
|
||||||
from dutylog.infrastructure.ioc import (
|
from dutylog.infrastructure.ioc import (
|
||||||
ConfigProvider,
|
ConfigProvider,
|
||||||
@@ -46,6 +47,7 @@ async def main():
|
|||||||
dp.include_router(user_router)
|
dp.include_router(user_router)
|
||||||
dp.include_router(main_menu_dialog)
|
dp.include_router(main_menu_dialog)
|
||||||
dp.include_router(admin_menu_dialog)
|
dp.include_router(admin_menu_dialog)
|
||||||
|
dp.include_router(creator_menu_dialog)
|
||||||
dp.include_router(registration_dialog)
|
dp.include_router(registration_dialog)
|
||||||
|
|
||||||
setup_dialogs(dp)
|
setup_dialogs(dp)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from dishka import FromDishka
|
|||||||
from dishka.integrations.aiogram_dialog import inject
|
from dishka.integrations.aiogram_dialog import inject
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from dutylog.application.bot.user_dialogs.states import AdminMenuSG
|
from dutylog.application.bot.user_dialogs.states import AdminMenuSG, CreatorMenuSG
|
||||||
from dutylog.infrastructure.database.repositories.users_repository import (
|
from dutylog.infrastructure.database.repositories.users_repository import (
|
||||||
UsersRepository,
|
UsersRepository,
|
||||||
)
|
)
|
||||||
@@ -86,7 +86,7 @@ async def get_admin_menu_data(
|
|||||||
Выберите действие:
|
Выберите действие:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return {"content": content}
|
return {"content": content, "is_creator": is_creator}
|
||||||
|
|
||||||
|
|
||||||
@inject
|
@inject
|
||||||
@@ -137,6 +137,10 @@ async def on_reporting_period_click(callback, button, dialog_manager):
|
|||||||
await dialog_manager.switch_to(AdminMenuSG.reporting_period)
|
await dialog_manager.switch_to(AdminMenuSG.reporting_period)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_admins_click(callback, button, dialog_manager):
|
||||||
|
await dialog_manager.start(CreatorMenuSG.admins_list)
|
||||||
|
|
||||||
|
|
||||||
main_menu_window = Window(
|
main_menu_window = Window(
|
||||||
Format("{content}"),
|
Format("{content}"),
|
||||||
SwitchTo(
|
SwitchTo(
|
||||||
@@ -161,6 +165,12 @@ main_menu_window = Window(
|
|||||||
id="reporting_period_btn",
|
id="reporting_period_btn",
|
||||||
on_click=on_reporting_period_click,
|
on_click=on_reporting_period_click,
|
||||||
),
|
),
|
||||||
|
Button(
|
||||||
|
Const("👨💼 Админы"),
|
||||||
|
id="admins_btn",
|
||||||
|
on_click=on_admins_click,
|
||||||
|
when="is_creator",
|
||||||
|
),
|
||||||
SwitchTo(
|
SwitchTo(
|
||||||
Const("📊 Статистика"),
|
Const("📊 Статистика"),
|
||||||
id="stats_btn",
|
id="stats_btn",
|
||||||
|
|||||||
@@ -63,8 +63,6 @@ async def get_reporting_period_data(
|
|||||||
<b>Дата начала:</b> <code>{start_date.strftime('%d.%m.%Y')}</code>
|
<b>Дата начала:</b> <code>{start_date.strftime('%d.%m.%Y')}</code>
|
||||||
<b>Прошло дней:</b> <code>{days_passed}</code>
|
<b>Прошло дней:</b> <code>{days_passed}</code>
|
||||||
|
|
||||||
━━━━━━━━━━━━━━━━━━━━
|
|
||||||
|
|
||||||
Используйте кнопки ниже для управления периодом.
|
Используйте кнопки ниже для управления периодом.
|
||||||
"""
|
"""
|
||||||
has_active = True
|
has_active = True
|
||||||
@@ -74,8 +72,6 @@ async def get_reporting_period_data(
|
|||||||
|
|
||||||
<b>Статус:</b> ⚪️ Нет активного периода
|
<b>Статус:</b> ⚪️ Нет активного периода
|
||||||
|
|
||||||
━━━━━━━━━━━━━━━━━━━━
|
|
||||||
|
|
||||||
Создайте новый отчётный период, чтобы начать учёт дежурств.
|
Создайте новый отчётный период, чтобы начать учёт дежурств.
|
||||||
"""
|
"""
|
||||||
has_active = False
|
has_active = False
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
from dutylog.application.bot.creator_dialogs.creator_menu_dialog import (
|
||||||
|
creator_menu_dialog,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = ["creator_menu_dialog"]
|
||||||
@@ -0,0 +1,374 @@
|
|||||||
|
from aiogram.types import CallbackQuery
|
||||||
|
from aiogram_dialog import Window, DialogManager
|
||||||
|
from aiogram_dialog.widgets.text import Format, Const
|
||||||
|
from aiogram_dialog.widgets.kbd import SwitchTo, Button, Select, ScrollingGroup, Row
|
||||||
|
from dishka import FromDishka
|
||||||
|
from dishka.integrations.aiogram_dialog import inject
|
||||||
|
|
||||||
|
from dutylog.application.bot.user_dialogs.states import CreatorMenuSG, AdminMenuSG
|
||||||
|
from dutylog.infrastructure.database.repositories.users_repository import UsersRepository
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def get_admins_list_data(
|
||||||
|
users_repository: FromDishka[UsersRepository],
|
||||||
|
**kwargs,
|
||||||
|
) -> dict[str, str | list[tuple[str, int]]]:
|
||||||
|
all_users = await users_repository.get_all_users()
|
||||||
|
admins = [u for u in all_users if u.is_admin]
|
||||||
|
|
||||||
|
if not admins:
|
||||||
|
content = """
|
||||||
|
<blockquote>👨💼 <b>Администраторы</b></blockquote>
|
||||||
|
|
||||||
|
⚠️ Нет администраторов в системе.
|
||||||
|
"""
|
||||||
|
admins_list = []
|
||||||
|
else:
|
||||||
|
content = f"""
|
||||||
|
<blockquote>👨💼 <b>Администраторы</b></blockquote>
|
||||||
|
|
||||||
|
Всего администраторов: <code>{len(admins)}</code>
|
||||||
|
|
||||||
|
Выберите администратора для просмотра информации:
|
||||||
|
"""
|
||||||
|
admins_list = []
|
||||||
|
for admin in admins:
|
||||||
|
display_name = f"@{admin.username}" if admin.username else f"ID: {admin.id}"
|
||||||
|
if admin.first_name:
|
||||||
|
display_name = f"{admin.first_name} ({display_name})"
|
||||||
|
admins_list.append((display_name, admin.id))
|
||||||
|
|
||||||
|
return {
|
||||||
|
"content": content,
|
||||||
|
"admins": admins_list,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def on_admin_selected(
|
||||||
|
callback: CallbackQuery,
|
||||||
|
widget,
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
item_id: str,
|
||||||
|
) -> None:
|
||||||
|
dialog_manager.dialog_data["selected_admin_id"] = int(item_id)
|
||||||
|
await dialog_manager.switch_to(CreatorMenuSG.admin_info)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_add_admin_click(
|
||||||
|
callback: CallbackQuery,
|
||||||
|
button: Button,
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
) -> None:
|
||||||
|
await dialog_manager.switch_to(CreatorMenuSG.add_admin_select_user)
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def get_admin_info_data(
|
||||||
|
users_repository: FromDishka[UsersRepository],
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
**kwargs,
|
||||||
|
) -> dict[str, str]:
|
||||||
|
admin_id = dialog_manager.dialog_data.get("selected_admin_id")
|
||||||
|
if not admin_id:
|
||||||
|
return {"content": "⚠️ Администратор не выбран"}
|
||||||
|
|
||||||
|
admin = await users_repository.get_user_by_id(int(admin_id))
|
||||||
|
|
||||||
|
if not admin:
|
||||||
|
return {"content": "⚠️ Администратор не найден"}
|
||||||
|
|
||||||
|
username = f"@{admin.username}" if admin.username else "—"
|
||||||
|
first_name = admin.first_name or "—"
|
||||||
|
last_name = admin.last_name or "—"
|
||||||
|
|
||||||
|
content = f"""
|
||||||
|
<blockquote>👨💼 <b>Информация об администраторе</b></blockquote>
|
||||||
|
|
||||||
|
<b>ID:</b> <code>{admin.id}</code>
|
||||||
|
<b>Username:</b> {username}
|
||||||
|
<b>Имя:</b> <code>{first_name}</code>
|
||||||
|
<b>Фамилия:</b> <code>{last_name}</code>
|
||||||
|
|
||||||
|
<b>Дата добавления:</b> <code>{admin.created_at.strftime('%d.%m.%Y %H:%M')}</code>
|
||||||
|
"""
|
||||||
|
|
||||||
|
return {"content": content}
|
||||||
|
|
||||||
|
|
||||||
|
async def on_remove_admin_click(
|
||||||
|
callback: CallbackQuery,
|
||||||
|
button: Button,
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
) -> None:
|
||||||
|
await dialog_manager.switch_to(CreatorMenuSG.remove_admin_confirm)
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def get_remove_admin_confirm_data(
|
||||||
|
users_repository: FromDishka[UsersRepository],
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
**kwargs,
|
||||||
|
) -> dict[str, str]:
|
||||||
|
admin_id = dialog_manager.dialog_data.get("selected_admin_id")
|
||||||
|
if not admin_id:
|
||||||
|
return {"content": "⚠️ Администратор не выбран"}
|
||||||
|
|
||||||
|
admin = await users_repository.get_user_by_id(int(admin_id))
|
||||||
|
|
||||||
|
if not admin:
|
||||||
|
return {"content": "⚠️ Администратор не найден"}
|
||||||
|
|
||||||
|
username = f"@{admin.username}" if admin.username else f"ID: {admin.id}"
|
||||||
|
display_name = admin.first_name or username
|
||||||
|
|
||||||
|
content = f"""
|
||||||
|
<blockquote>⚠️ <b>Подтверждение удаления</b></blockquote>
|
||||||
|
|
||||||
|
Вы уверены, что хотите удалить администратора <b>{display_name}</b>?
|
||||||
|
|
||||||
|
Пользователь потеряет права администратора.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return {"content": content}
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def on_remove_admin_confirm(
|
||||||
|
callback: CallbackQuery,
|
||||||
|
button: Button,
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
users_repository: FromDishka[UsersRepository],
|
||||||
|
) -> None:
|
||||||
|
admin_id = dialog_manager.dialog_data.get("selected_admin_id")
|
||||||
|
if not admin_id:
|
||||||
|
await callback.answer("⚠️ Администратор не выбран", show_alert=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
await users_repository.update_user(int(admin_id), is_admin=False)
|
||||||
|
|
||||||
|
await callback.answer("✅ Администратор удалён!")
|
||||||
|
await dialog_manager.switch_to(CreatorMenuSG.admins_list)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_remove_admin_cancel(
|
||||||
|
callback: CallbackQuery,
|
||||||
|
button: Button,
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
) -> None:
|
||||||
|
await dialog_manager.switch_to(CreatorMenuSG.admin_info)
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def get_add_admin_select_user_data(
|
||||||
|
users_repository: FromDishka[UsersRepository],
|
||||||
|
**kwargs,
|
||||||
|
) -> dict[str, str | list[tuple[str, int]]]:
|
||||||
|
all_users = await users_repository.get_all_users()
|
||||||
|
non_admin_users = [u for u in all_users if not u.is_admin]
|
||||||
|
|
||||||
|
if not non_admin_users:
|
||||||
|
content = """
|
||||||
|
<blockquote>➕ <b>Добавить администратора</b></blockquote>
|
||||||
|
|
||||||
|
⚠️ Нет пользователей, которых можно сделать администраторами.
|
||||||
|
|
||||||
|
Все пользователи уже являются администраторами.
|
||||||
|
"""
|
||||||
|
users_list = []
|
||||||
|
else:
|
||||||
|
content = f"""
|
||||||
|
<blockquote>➕ <b>Добавить администратора</b></blockquote>
|
||||||
|
|
||||||
|
Всего пользователей: <code>{len(non_admin_users)}</code>
|
||||||
|
|
||||||
|
Выберите пользователя для назначения администратором:
|
||||||
|
"""
|
||||||
|
users_list = []
|
||||||
|
for user in non_admin_users:
|
||||||
|
display_name = f"@{user.username}" if user.username else f"ID: {user.id}"
|
||||||
|
if user.first_name:
|
||||||
|
display_name = f"{user.first_name} ({display_name})"
|
||||||
|
users_list.append((display_name, user.id))
|
||||||
|
|
||||||
|
return {
|
||||||
|
"content": content,
|
||||||
|
"users": users_list,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def on_user_selected(
|
||||||
|
callback: CallbackQuery,
|
||||||
|
widget,
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
item_id: str,
|
||||||
|
) -> None:
|
||||||
|
dialog_manager.dialog_data["selected_user_id"] = int(item_id)
|
||||||
|
await dialog_manager.switch_to(CreatorMenuSG.add_admin_confirm)
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def get_add_admin_confirm_data(
|
||||||
|
users_repository: FromDishka[UsersRepository],
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
**kwargs,
|
||||||
|
) -> dict[str, str]:
|
||||||
|
user_id = dialog_manager.dialog_data.get("selected_user_id")
|
||||||
|
if not user_id:
|
||||||
|
return {"content": "⚠️ Пользователь не выбран"}
|
||||||
|
|
||||||
|
user = await users_repository.get_user_by_id(int(user_id))
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
return {"content": "⚠️ Пользователь не найден"}
|
||||||
|
|
||||||
|
username = f"@{user.username}" if user.username else f"ID: {user.id}"
|
||||||
|
display_name = user.first_name or username
|
||||||
|
|
||||||
|
content = f"""
|
||||||
|
<blockquote>⚠️ <b>Подтверждение</b></blockquote>
|
||||||
|
|
||||||
|
Вы уверены, что хотите назначить <b>{display_name}</b> администратором?
|
||||||
|
|
||||||
|
Пользователь получит доступ к панели управления.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return {"content": content}
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def on_add_admin_confirm(
|
||||||
|
callback: CallbackQuery,
|
||||||
|
button: Button,
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
users_repository: FromDishka[UsersRepository],
|
||||||
|
) -> None:
|
||||||
|
user_id = dialog_manager.dialog_data.get("selected_user_id")
|
||||||
|
if not user_id:
|
||||||
|
await callback.answer("⚠️ Пользователь не выбран", show_alert=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
await users_repository.update_user(int(user_id), is_admin=True)
|
||||||
|
|
||||||
|
await callback.answer("✅ Администратор добавлен!")
|
||||||
|
await dialog_manager.switch_to(CreatorMenuSG.admins_list)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_add_admin_cancel(
|
||||||
|
callback: CallbackQuery,
|
||||||
|
button: Button,
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
) -> None:
|
||||||
|
await dialog_manager.switch_to(CreatorMenuSG.add_admin_select_user)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_back_to_main(
|
||||||
|
callback: CallbackQuery,
|
||||||
|
button: Button,
|
||||||
|
dialog_manager: DialogManager,
|
||||||
|
) -> None:
|
||||||
|
await dialog_manager.done()
|
||||||
|
|
||||||
|
|
||||||
|
admins_list_window = Window(
|
||||||
|
Format("{content}"),
|
||||||
|
ScrollingGroup(
|
||||||
|
Select(
|
||||||
|
Format("{item[0]}"),
|
||||||
|
id="admin_select",
|
||||||
|
item_id_getter=lambda x: x[1],
|
||||||
|
items="admins",
|
||||||
|
on_click=on_admin_selected,
|
||||||
|
),
|
||||||
|
id="admins_scroll",
|
||||||
|
width=1,
|
||||||
|
height=8,
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
Const("➕ Добавить администратора"),
|
||||||
|
id="add_admin_btn",
|
||||||
|
on_click=on_add_admin_click,
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
Const("◀️ Назад"),
|
||||||
|
id="back_to_main_from_admins",
|
||||||
|
on_click=on_back_to_main,
|
||||||
|
),
|
||||||
|
state=CreatorMenuSG.admins_list,
|
||||||
|
getter=get_admins_list_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
admin_info_window = Window(
|
||||||
|
Format("{content}"),
|
||||||
|
Button(
|
||||||
|
Const("🗑 Удалить администратора"),
|
||||||
|
id="remove_admin_btn",
|
||||||
|
on_click=on_remove_admin_click,
|
||||||
|
),
|
||||||
|
SwitchTo(
|
||||||
|
Const("◀️ Назад"),
|
||||||
|
id="back_to_admins_list",
|
||||||
|
state=CreatorMenuSG.admins_list,
|
||||||
|
),
|
||||||
|
state=CreatorMenuSG.admin_info,
|
||||||
|
getter=get_admin_info_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
remove_admin_confirm_window = Window(
|
||||||
|
Format("{content}"),
|
||||||
|
Row(
|
||||||
|
Button(
|
||||||
|
Const("✅ Да"),
|
||||||
|
id="confirm_remove_admin",
|
||||||
|
on_click=on_remove_admin_confirm,
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
Const("❌ Нет"),
|
||||||
|
id="cancel_remove_admin",
|
||||||
|
on_click=on_remove_admin_cancel,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
state=CreatorMenuSG.remove_admin_confirm,
|
||||||
|
getter=get_remove_admin_confirm_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
add_admin_select_user_window = Window(
|
||||||
|
Format("{content}"),
|
||||||
|
ScrollingGroup(
|
||||||
|
Select(
|
||||||
|
Format("{item[0]}"),
|
||||||
|
id="user_select",
|
||||||
|
item_id_getter=lambda x: x[1],
|
||||||
|
items="users",
|
||||||
|
on_click=on_user_selected,
|
||||||
|
),
|
||||||
|
id="users_scroll",
|
||||||
|
width=1,
|
||||||
|
height=8,
|
||||||
|
),
|
||||||
|
SwitchTo(
|
||||||
|
Const("◀️ Назад"),
|
||||||
|
id="back_to_admins_from_add",
|
||||||
|
state=CreatorMenuSG.admins_list,
|
||||||
|
),
|
||||||
|
state=CreatorMenuSG.add_admin_select_user,
|
||||||
|
getter=get_add_admin_select_user_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
add_admin_confirm_window = Window(
|
||||||
|
Format("{content}"),
|
||||||
|
Row(
|
||||||
|
Button(
|
||||||
|
Const("✅ Да"),
|
||||||
|
id="confirm_add_admin",
|
||||||
|
on_click=on_add_admin_confirm,
|
||||||
|
),
|
||||||
|
Button(
|
||||||
|
Const("❌ Нет"),
|
||||||
|
id="cancel_add_admin",
|
||||||
|
on_click=on_add_admin_cancel,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
state=CreatorMenuSG.add_admin_confirm,
|
||||||
|
getter=get_add_admin_confirm_data,
|
||||||
|
)
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
from aiogram_dialog import Dialog
|
||||||
|
|
||||||
|
from dutylog.application.bot.creator_dialogs.admins_management import (
|
||||||
|
admins_list_window,
|
||||||
|
admin_info_window,
|
||||||
|
remove_admin_confirm_window,
|
||||||
|
add_admin_select_user_window,
|
||||||
|
add_admin_confirm_window,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
creator_menu_dialog = Dialog(
|
||||||
|
admins_list_window,
|
||||||
|
admin_info_window,
|
||||||
|
remove_admin_confirm_window,
|
||||||
|
add_admin_select_user_window,
|
||||||
|
add_admin_confirm_window,
|
||||||
|
)
|
||||||
@@ -116,19 +116,11 @@ async def on_resident_selected(
|
|||||||
widget: Select,
|
widget: Select,
|
||||||
dialog_manager: DialogManager,
|
dialog_manager: DialogManager,
|
||||||
item_id: str,
|
item_id: str,
|
||||||
residents_repository: FromDishka[ResidentsRepository],
|
residents_repository: FromDishka[ResidentsRepository]
|
||||||
users_repository: FromDishka[UsersRepository],
|
|
||||||
):
|
):
|
||||||
user_id = callback.from_user.id
|
user_id = callback.from_user.id
|
||||||
resident_id = int(item_id)
|
resident_id = int(item_id)
|
||||||
|
|
||||||
await users_repository.get_or_create_user(
|
|
||||||
user_id=user_id,
|
|
||||||
username=callback.from_user.username,
|
|
||||||
first_name=callback.from_user.first_name,
|
|
||||||
last_name=callback.from_user.last_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
await residents_repository.bind_user_to_resident(resident_id, user_id)
|
await residents_repository.bind_user_to_resident(resident_id, user_id)
|
||||||
|
|
||||||
await callback.answer("✅ Регистрация успешна!")
|
await callback.answer("✅ Регистрация успешна!")
|
||||||
|
|||||||
@@ -49,6 +49,14 @@ class AdminMenuSG(StatesGroup):
|
|||||||
broadcast_confirm = State()
|
broadcast_confirm = State()
|
||||||
|
|
||||||
|
|
||||||
|
class CreatorMenuSG(StatesGroup):
|
||||||
|
admins_list = State()
|
||||||
|
admin_info = State()
|
||||||
|
remove_admin_confirm = State()
|
||||||
|
add_admin_select_user = State()
|
||||||
|
add_admin_confirm = State()
|
||||||
|
|
||||||
|
|
||||||
class RegistrationSG(StatesGroup):
|
class RegistrationSG(StatesGroup):
|
||||||
select_floor = State()
|
select_floor = State()
|
||||||
select_room = State()
|
select_room = State()
|
||||||
|
|||||||
@@ -29,7 +29,13 @@ async def start_handler(
|
|||||||
config: FromDishka[Config],
|
config: FromDishka[Config],
|
||||||
):
|
):
|
||||||
assert message.from_user is not None
|
assert message.from_user is not None
|
||||||
user = await users_repository.get_user_by_id(message.from_user.id)
|
|
||||||
|
user = await users_repository.get_or_create_user(
|
||||||
|
user_id=message.from_user.id,
|
||||||
|
username=message.from_user.username,
|
||||||
|
first_name=message.from_user.first_name,
|
||||||
|
last_name=message.from_user.last_name,
|
||||||
|
)
|
||||||
|
|
||||||
is_creator = message.from_user.id == config.bot.creator_id
|
is_creator = message.from_user.id == config.bot.creator_id
|
||||||
is_admin = user.is_admin if user else False
|
is_admin = user.is_admin if user else False
|
||||||
|
|||||||
@@ -50,3 +50,6 @@ class UsersRepository:
|
|||||||
|
|
||||||
async def get_all_users(self) -> list[User]:
|
async def get_all_users(self) -> list[User]:
|
||||||
return await self.users_dao.get_all()
|
return await self.users_dao.get_all()
|
||||||
|
|
||||||
|
async def update_user(self, user_id: int, **kwargs) -> User | None:
|
||||||
|
return await self.users_dao.update(user_id, **kwargs)
|
||||||
|
|||||||
Binary file not shown.
@@ -1,79 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
from datetime import date
|
|
||||||
|
|
||||||
from dutylog.infrastructure.database.config import create_engine, create_session_maker
|
|
||||||
from dutylog.infrastructure.database.dao.hours_transactions_dao import HoursTransactionsDAO
|
|
||||||
from dutylog.infrastructure.database.dao.residents_dao import ResidentsDAO
|
|
||||||
from dutylog.infrastructure.database.dao.rooms_dao import RoomsDAO
|
|
||||||
from dutylog.infrastructure.database.dao.floors_dao import FloorsDAO
|
|
||||||
from dutylog.infrastructure.database.dao.reporting_periods_dao import ReportingPeriodsDAO
|
|
||||||
from dutylog.infrastructure.database.dao.users_dao import UsersDAO
|
|
||||||
from dutylog.infrastructure.database.repositories.hours_transactions_repository import (
|
|
||||||
HoursTransactionsRepository,
|
|
||||||
)
|
|
||||||
from dutylog.infrastructure.database.repositories.residents_repository import ResidentsRepository
|
|
||||||
from dutylog.infrastructure.database.repositories.rooms_repository import RoomsRepository
|
|
||||||
from dutylog.infrastructure.database.repositories.floors_repository import FloorsRepository
|
|
||||||
from dutylog.infrastructure.database.repositories.reporting_periods_repository import (
|
|
||||||
ReportingPeriodsRepository,
|
|
||||||
)
|
|
||||||
from dutylog.infrastructure.database.repositories.users_repository import UsersRepository
|
|
||||||
from dutylog.infrastructure.utils.config import load_config
|
|
||||||
from dutylog.services.report_service import ReportService
|
|
||||||
|
|
||||||
|
|
||||||
async def test_report_generation() -> None:
|
|
||||||
config = load_config()
|
|
||||||
engine = create_engine(config.database.url)
|
|
||||||
session_maker = create_session_maker(engine)
|
|
||||||
|
|
||||||
async with session_maker() as session:
|
|
||||||
hours_transactions_dao = HoursTransactionsDAO(session)
|
|
||||||
residents_dao = ResidentsDAO(session)
|
|
||||||
rooms_dao = RoomsDAO(session)
|
|
||||||
floors_dao = FloorsDAO(session)
|
|
||||||
reporting_periods_dao = ReportingPeriodsDAO(session)
|
|
||||||
users_dao = UsersDAO(session)
|
|
||||||
|
|
||||||
hours_transactions_repository = HoursTransactionsRepository(
|
|
||||||
hours_transactions_dao, residents_dao
|
|
||||||
)
|
|
||||||
residents_repository = ResidentsRepository(residents_dao)
|
|
||||||
rooms_repository = RoomsRepository(rooms_dao)
|
|
||||||
floors_repository = FloorsRepository(floors_dao)
|
|
||||||
reporting_periods_repository = ReportingPeriodsRepository(reporting_periods_dao)
|
|
||||||
users_repository = UsersRepository(users_dao)
|
|
||||||
|
|
||||||
report_service = ReportService(
|
|
||||||
hours_transactions_repository,
|
|
||||||
residents_repository,
|
|
||||||
rooms_repository,
|
|
||||||
floors_repository,
|
|
||||||
users_repository,
|
|
||||||
)
|
|
||||||
|
|
||||||
active_period = await reporting_periods_repository.get_active_period()
|
|
||||||
|
|
||||||
if not active_period:
|
|
||||||
print("⚠️ Нет активного периода")
|
|
||||||
return
|
|
||||||
|
|
||||||
print(f"📅 Активный период: с {active_period.start_date}")
|
|
||||||
|
|
||||||
end_date = active_period.end_date if active_period.end_date else date.today()
|
|
||||||
|
|
||||||
print(f"📊 Генерирую отчёт за период {active_period.start_date} - {end_date}")
|
|
||||||
|
|
||||||
report_file = await report_service.generate_period_report(
|
|
||||||
active_period.start_date, end_date
|
|
||||||
)
|
|
||||||
|
|
||||||
filename = f"test_report_{active_period.start_date}_{end_date}.xlsx"
|
|
||||||
with open(filename, "wb") as f:
|
|
||||||
f.write(report_file.read())
|
|
||||||
|
|
||||||
print(f"✅ Отчёт сохранён в файл: {filename}")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
asyncio.run(test_report_generation())
|
|
||||||
Reference in New Issue
Block a user