diff --git a/alembic/versions/0f74944ba3bb_add_models.py b/alembic/versions/0f74944ba3bb_add_models.py
new file mode 100644
index 0000000..43aae48
--- /dev/null
+++ b/alembic/versions/0f74944ba3bb_add_models.py
@@ -0,0 +1,74 @@
+"""add models
+
+Revision ID: 0f74944ba3bb
+Revises: fc1269fbc645
+Create Date: 2026-02-28 09:17:21.827677
+
+"""
+from typing import Sequence, Union
+
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision: str = '0f74944ba3bb'
+down_revision: Union[str, Sequence[str], None] = 'fc1269fbc645'
+branch_labels: Union[str, Sequence[str], None] = None
+depends_on: Union[str, Sequence[str], None] = None
+
+
+def upgrade() -> None:
+ """Upgrade schema."""
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('floors',
+ sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
+ sa.Column('number', sa.Integer(), nullable=False),
+ sa.PrimaryKeyConstraint('id'),
+ sa.UniqueConstraint('number')
+ )
+ op.create_table('rooms',
+ sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
+ sa.Column('number', sa.Integer(), nullable=False),
+ sa.Column('on_floor', sa.Integer(), nullable=False),
+ sa.ForeignKeyConstraint(['on_floor'], ['floors.id'], ondelete='CASCADE'),
+ sa.PrimaryKeyConstraint('id'),
+ sa.UniqueConstraint('number')
+ )
+ op.create_table('residents',
+ sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
+ sa.Column('real_name', sa.String(length=255), nullable=True),
+ sa.Column('room', sa.Integer(), nullable=False),
+ sa.Column('user_entity', sa.BigInteger(), nullable=True),
+ sa.Column('is_busy', sa.Boolean(), server_default='false', nullable=False),
+ sa.Column('active_hours', sa.Integer(), server_default='0', nullable=False),
+ sa.Column('inactive_hours', sa.Integer(), server_default='0', nullable=False),
+ sa.Column('created_at', sa.DateTime(timezone=True), nullable=False),
+ sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False),
+ sa.ForeignKeyConstraint(['room'], ['rooms.id'], ondelete='CASCADE'),
+ sa.ForeignKeyConstraint(['user_entity'], ['users.id'], ondelete='SET NULL'),
+ sa.PrimaryKeyConstraint('id'),
+ sa.UniqueConstraint('user_entity')
+ )
+ op.add_column('hours_transactions', sa.Column('resident_id', sa.Integer(), nullable=False))
+ op.drop_constraint(op.f('hours_transactions_user_id_fkey'), 'hours_transactions', type_='foreignkey')
+ op.create_foreign_key(None, 'hours_transactions', 'residents', ['resident_id'], ['id'], ondelete='CASCADE')
+ op.drop_column('hours_transactions', 'user_id')
+ op.drop_column('users', 'inactive_hours')
+ op.drop_column('users', 'active_hours')
+ # ### end Alembic commands ###
+
+
+def downgrade() -> None:
+ """Downgrade schema."""
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('users', sa.Column('active_hours', sa.INTEGER(), server_default=sa.text('0'), autoincrement=False, nullable=False))
+ op.add_column('users', sa.Column('inactive_hours', sa.INTEGER(), server_default=sa.text('0'), autoincrement=False, nullable=False))
+ op.add_column('hours_transactions', sa.Column('user_id', sa.BIGINT(), autoincrement=False, nullable=False))
+ op.drop_constraint(None, 'hours_transactions', type_='foreignkey')
+ op.create_foreign_key(op.f('hours_transactions_user_id_fkey'), 'hours_transactions', 'users', ['user_id'], ['id'], ondelete='CASCADE')
+ op.drop_column('hours_transactions', 'resident_id')
+ op.drop_table('residents')
+ op.drop_table('rooms')
+ op.drop_table('floors')
+ # ### end Alembic commands ###
diff --git a/init_floors_rooms.sql b/init_floors_rooms.sql
new file mode 100644
index 0000000..039311b
--- /dev/null
+++ b/init_floors_rooms.sql
@@ -0,0 +1,25 @@
+-- Массивы имен и фамилий для генерации
+DO $$
+DECLARE
+ first_names TEXT[] := ARRAY['Aleksandr', 'Dmitriy', 'Maksim', 'Ivan', 'Artem', 'Mikhail', 'Daniil', 'Egor', 'Andrey', 'Nikita',
+ 'Anna', 'Mariya', 'Elena', 'Olga', 'Ekaterina', 'Natalya', 'Tatyana', 'Irina', 'Yuliya', 'Svetlana'];
+ last_names TEXT[] := ARRAY['Ivanov', 'Petrov', 'Sidorov', 'Smirnov', 'Kuznetsov', 'Popov', 'Vasilev', 'Sokolov', 'Mikhaylov', 'Novikov',
+ 'Fedorov', 'Morozov', 'Volkov', 'Alekseev', 'Lebedev', 'Semenov', 'Egorov', 'Pavlov', 'Kozlov', 'Stepanov'];
+ room_record RECORD;
+ residents_count INT;
+ i INT;
+ first_name TEXT;
+ last_name TEXT;
+BEGIN
+ FOR room_record IN SELECT id FROM rooms LOOP
+ residents_count := 2 + floor(random() * 2)::INT;
+
+ FOR i IN 1..residents_count LOOP
+ first_name := first_names[1 + floor(random() * array_length(first_names, 1))::INT];
+ last_name := last_names[1 + floor(random() * array_length(last_names, 1))::INT];
+
+ INSERT INTO residents (real_name, room, is_busy, active_hours, inactive_hours, created_at, updated_at)
+ VALUES (first_name || ' ' || last_name, room_record.id, false, 0, 0, NOW(), NOW());
+ END LOOP;
+ END LOOP;
+END $$;
diff --git a/src/dutylog/application/__main__.py b/src/dutylog/application/__main__.py
index ac19c60..70c1709 100644
--- a/src/dutylog/application/__main__.py
+++ b/src/dutylog/application/__main__.py
@@ -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_dialogs import main_menu_dialog
from dutylog.application.bot.user_dialogs.admin_dialogs import admin_menu_dialog
+from dutylog.application.bot.user_dialogs.registration_dialog import registration_dialog
from dutylog.infrastructure.ioc import ConfigProvider, DatabaseProvider, DAOProvider, RepositoryProvider
from dutylog.infrastructure.utils.config import load_config
@@ -24,6 +25,9 @@ async def main():
token=config.bot.token,
default=DefaultBotProperties(parse_mode=ParseMode.HTML)
)
+
+ await bot.delete_webhook(drop_pending_updates=True)
+
dp = Dispatcher()
container = make_async_container(
@@ -36,6 +40,7 @@ async def main():
dp.include_router(user_router)
dp.include_router(main_menu_dialog)
dp.include_router(admin_menu_dialog)
+ dp.include_router(registration_dialog)
setup_dialogs(dp)
setup_dishka(container, dp, auto_inject=True)
diff --git a/src/dutylog/application/bot/user_dialogs/main_menu_dialog.py b/src/dutylog/application/bot/user_dialogs/main_menu_dialog.py
index 0f033ba..5002552 100644
--- a/src/dutylog/application/bot/user_dialogs/main_menu_dialog.py
+++ b/src/dutylog/application/bot/user_dialogs/main_menu_dialog.py
@@ -1,11 +1,11 @@
from aiogram.types import User
from aiogram_dialog import Dialog, Window, DialogManager
from aiogram_dialog.widgets.text import Format, Const
-from aiogram_dialog.widgets.kbd import SwitchTo, Back
+from aiogram_dialog.widgets.kbd import SwitchTo, Back, Start
from dishka import FromDishka
from dishka.integrations.aiogram_dialog import inject
-from dutylog.application.bot.user_dialogs.states import MainMenuSG
+from dutylog.application.bot.user_dialogs.states import MainMenuSG, RegistrationSG
from dutylog.infrastructure.database.repositories.users_repository import UsersRepository
from dutylog.infrastructure.database.repositories.residents_repository import ResidentsRepository
from dutylog.infrastructure.database.repositories.hours_transactions_repository import HoursTransactionsRepository
@@ -49,6 +49,7 @@ async def get_main_menu_data(
Вы еще не привязаны к резиденту.
Обратитесь к администратору для регистрации.
"""
+ has_resident = False
else:
content = f"""
{greeting}
@@ -59,6 +60,7 @@ async def get_main_menu_data(
━━━━━━━━━━━━━━━━
🔴 Неотработанные часы: {resident.inactive_hours} ч
"""
+ has_resident = True
else:
content = f"""
{greeting}
@@ -67,11 +69,12 @@ async def get_main_menu_data(
Добро пожаловать в систему учета дежурств!
"""
+ has_resident = False
return {
"content": content,
"is_regular_user": not is_admin and not is_creator,
- "has_resident": resident is not None if not is_admin and not is_creator else False,
+ "has_resident": has_resident,
}
@@ -128,6 +131,12 @@ main_menu_dialog = Dialog(
state=MainMenuSG.history,
when="has_resident",
),
+ Start(
+ Const("🔄 Перерегистрация"),
+ id="reregister_btn",
+ state=RegistrationSG.select_floor,
+ when="is_regular_user",
+ ),
state=MainMenuSG.main,
getter=get_main_menu_data,
),
@@ -138,3 +147,4 @@ main_menu_dialog = Dialog(
getter=get_history_data,
),
)
+
diff --git a/src/dutylog/application/bot/user_dialogs/registration_dialog.py b/src/dutylog/application/bot/user_dialogs/registration_dialog.py
new file mode 100644
index 0000000..a9f82e4
--- /dev/null
+++ b/src/dutylog/application/bot/user_dialogs/registration_dialog.py
@@ -0,0 +1,169 @@
+from aiogram.types import CallbackQuery
+from magic_filter import F
+from aiogram_dialog import Dialog, Window, DialogManager
+from aiogram_dialog.widgets.text import Format, Const
+from aiogram_dialog.widgets.kbd import Select, Cancel, Group
+from dishka import FromDishka
+from dishka.integrations.aiogram_dialog import inject
+
+from dutylog.application.bot.user_dialogs.states import RegistrationSG, MainMenuSG
+from dutylog.infrastructure.database.repositories.floors_repository import FloorsRepository
+from dutylog.infrastructure.database.repositories.rooms_repository import RoomsRepository
+from dutylog.infrastructure.database.repositories.residents_repository import ResidentsRepository
+
+
+@inject
+async def get_floors_data(
+ floors_repository: FromDishka[FloorsRepository],
+ rooms_repository: FromDishka[RoomsRepository],
+ residents_repository: FromDishka[ResidentsRepository],
+ **kwargs,
+):
+ all_floors = await floors_repository.get_all_floors()
+ available_residents = await residents_repository.get_available_residents()
+
+ if not available_residents:
+ return {
+ "has_available": False,
+ "floors": [],
+ }
+
+ available_room_ids = {r.room for r in available_residents}
+ all_rooms = await rooms_repository.get_all_rooms()
+ available_rooms = [r for r in all_rooms if r.id in available_room_ids]
+ available_floor_ids = {r.on_floor for r in available_rooms}
+
+ available_floors = [f for f in all_floors if f.id in available_floor_ids]
+ available_floors.sort(key=lambda f: f.number)
+
+ return {
+ "has_available": True,
+ "floors": [(f.id, f"Этаж {f.number}") for f in available_floors],
+ }
+
+
+@inject
+async def get_rooms_data(
+ dialog_manager: DialogManager,
+ rooms_repository: FromDishka[RoomsRepository],
+ residents_repository: FromDishka[ResidentsRepository],
+ **kwargs,
+):
+ floor_id = dialog_manager.dialog_data["floor_id"]
+
+ rooms = await rooms_repository.get_rooms_by_floor(floor_id)
+ available_residents = await residents_repository.get_available_residents()
+ available_room_ids = {r.room for r in available_residents}
+
+ available_rooms = [r for r in rooms if r.id in available_room_ids]
+ available_rooms.sort(key=lambda r: r.number)
+
+ return {
+ "rooms": [(r.id, str(r.number)) for r in available_rooms],
+ }
+
+
+@inject
+async def get_residents_data(
+ dialog_manager: DialogManager,
+ residents_repository: FromDishka[ResidentsRepository],
+ **kwargs,
+):
+ room_id = dialog_manager.dialog_data["room_id"]
+
+ residents = await residents_repository.get_residents_by_room(room_id)
+ available_residents = [r for r in residents if not r.is_busy]
+
+ return {
+ "residents": [(r.id, r.real_name or f"Резидент #{r.id}") for r in available_residents],
+ }
+
+
+async def on_floor_selected(
+ callback: CallbackQuery,
+ widget: Select,
+ dialog_manager: DialogManager,
+ floor_id: str,
+):
+ dialog_manager.dialog_data["floor_id"] = int(floor_id)
+ await dialog_manager.switch_to(RegistrationSG.select_room)
+
+
+async def on_room_selected(
+ callback: CallbackQuery,
+ widget: Select,
+ dialog_manager: DialogManager,
+ room_id: str,
+):
+ dialog_manager.dialog_data["room_id"] = int(room_id)
+ await dialog_manager.switch_to(RegistrationSG.select_resident)
+
+
+@inject
+async def on_resident_selected(
+ callback: CallbackQuery,
+ widget: Select,
+ dialog_manager: DialogManager,
+ item_id: str,
+ residents_repository: FromDishka[ResidentsRepository],
+):
+ user_id = callback.from_user.id
+ resident_id = int(item_id)
+
+ await residents_repository.bind_user_to_resident(resident_id, user_id)
+
+ await callback.answer("✅ Вы успешно зарегистрированы!")
+ await dialog_manager.start(MainMenuSG.main)
+
+
+registration_dialog = Dialog(
+ Window(
+ Const("
🏢 Выбор этажа\n\nВыберите этаж, на котором вы живете:", when="has_available"), + Const("
⚠️ Нет доступных резидентов\n\nВсе резиденты уже заняты.\nОбратитесь к администратору.", when=~F["has_available"]), + Group( + Select( + Format("{item[1]}"), + id="floor_select", + item_id_getter=lambda x: x[0], + items="floors", + on_click=on_floor_selected, + ), + width=2, + when="has_available", + ), + state=RegistrationSG.select_floor, + getter=get_floors_data, + ), + Window( + Const("
🚪 Выбор комнаты\n\nВыберите вашу комнату:"), + Group( + Select( + Format("{item[1]}"), + id="room_select", + item_id_getter=lambda x: x[0], + items="rooms", + on_click=on_room_selected, + ), + width=3, + ), + Cancel(Const("◀️ Назад")), + state=RegistrationSG.select_room, + getter=get_rooms_data, + ), + Window( + Const("
👤 Выбор резидента\n\nВыберите себя из списка:"), + Group( + Select( + Format("{item[1]}"), + id="resident_select", + item_id_getter=lambda x: x[0], + items="residents", + on_click=on_resident_selected, + ), + width=1, + ), + Cancel(Const("◀️ Назад")), + state=RegistrationSG.select_resident, + getter=get_residents_data, + ), +) diff --git a/src/dutylog/application/bot/user_dialogs/states.py b/src/dutylog/application/bot/user_dialogs/states.py index 8bdbff6..0037c38 100644 --- a/src/dutylog/application/bot/user_dialogs/states.py +++ b/src/dutylog/application/bot/user_dialogs/states.py @@ -11,3 +11,9 @@ class AdminMenuSG(StatesGroup): users_list = State() statistics = State() broadcast = State() + + +class RegistrationSG(StatesGroup): + select_floor = State() + select_room = State() + select_resident = State() diff --git a/src/dutylog/application/bot/user_handlers.py b/src/dutylog/application/bot/user_handlers.py index aab1f97..6531e57 100644 --- a/src/dutylog/application/bot/user_handlers.py +++ b/src/dutylog/application/bot/user_handlers.py @@ -4,8 +4,9 @@ from aiogram.types import Message from aiogram_dialog import DialogManager, StartMode from dishka import FromDishka -from dutylog.application.bot.user_dialogs.states import MainMenuSG, AdminMenuSG +from dutylog.application.bot.user_dialogs.states import MainMenuSG, AdminMenuSG, RegistrationSG from dutylog.infrastructure.database.repositories.users_repository import UsersRepository +from dutylog.infrastructure.database.repositories.residents_repository import ResidentsRepository from dutylog.infrastructure.utils.config import Config router = Router() @@ -16,20 +17,23 @@ async def start_handler( message: Message, dialog_manager: DialogManager, users_repository: FromDishka[UsersRepository], + residents_repository: FromDishka[ResidentsRepository], config: FromDishka[Config], ): assert message.from_user is not None - 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, - ) + user = await users_repository.get_user_by_id(message.from_user.id) is_creator = message.from_user.id == config.bot.creator_id - is_admin = user.is_admin + is_admin = user.is_admin if user else False if is_admin or is_creator: await dialog_manager.start(AdminMenuSG.main, mode=StartMode.RESET_STACK) - else: - await dialog_manager.start(MainMenuSG.main, mode=StartMode.RESET_STACK) + return + + if user: + resident = await residents_repository.get_resident_by_user_id(message.from_user.id) + if resident: + await dialog_manager.start(MainMenuSG.main, mode=StartMode.RESET_STACK) + return + + await dialog_manager.start(RegistrationSG.select_floor, mode=StartMode.RESET_STACK) diff --git a/src/dutylog/infrastructure/database/dao/floors_dao.py b/src/dutylog/infrastructure/database/dao/floors_dao.py new file mode 100644 index 0000000..9f6c749 --- /dev/null +++ b/src/dutylog/infrastructure/database/dao/floors_dao.py @@ -0,0 +1,44 @@ +from sqlalchemy import select, update, delete +from sqlalchemy.ext.asyncio import AsyncSession + +from dutylog.infrastructure.database.models.floor import Floor + + +class FloorsDAO: + def __init__(self, session: AsyncSession): + self.session = session + + async def get_by_id(self, floor_id: int) -> Floor | None: + result = await self.session.execute( + select(Floor).where(Floor.id == floor_id) + ) + return result.scalar_one_or_none() + + async def get_by_number(self, number: int) -> Floor | None: + result = await self.session.execute( + select(Floor).where(Floor.number == number) + ) + return result.scalar_one_or_none() + + async def get_all(self) -> list[Floor]: + result = await self.session.execute(select(Floor)) + return list(result.scalars().all()) + + async def create(self, floor: Floor) -> Floor: + self.session.add(floor) + await self.session.commit() + await self.session.refresh(floor) + return floor + + async def update(self, floor_id: int, **kwargs) -> Floor | None: + await self.session.execute( + update(Floor).where(Floor.id == floor_id).values(**kwargs) + ) + await self.session.commit() + return await self.get_by_id(floor_id) + + async def delete(self, floor_id: int) -> None: + await self.session.execute( + delete(Floor).where(Floor.id == floor_id) + ) + await self.session.commit() diff --git a/src/dutylog/infrastructure/database/dao/rooms_dao.py b/src/dutylog/infrastructure/database/dao/rooms_dao.py index 3905bba..401494e 100644 --- a/src/dutylog/infrastructure/database/dao/rooms_dao.py +++ b/src/dutylog/infrastructure/database/dao/rooms_dao.py @@ -20,6 +20,12 @@ class RoomsDAO: ) return result.scalar_one_or_none() + async def get_by_floor(self, floor_id: int) -> list[Room]: + result = await self.session.execute( + select(Room).where(Room.on_floor == floor_id) + ) + return list(result.scalars().all()) + async def get_all(self) -> list[Room]: result = await self.session.execute(select(Room)) return list(result.scalars().all()) diff --git a/src/dutylog/infrastructure/database/models/__init__.py b/src/dutylog/infrastructure/database/models/__init__.py index 7ba5b08..a049653 100644 --- a/src/dutylog/infrastructure/database/models/__init__.py +++ b/src/dutylog/infrastructure/database/models/__init__.py @@ -3,5 +3,6 @@ from dutylog.infrastructure.database.models.user import User from dutylog.infrastructure.database.models.hours_transaction import HoursTransaction from dutylog.infrastructure.database.models.room import Room from dutylog.infrastructure.database.models.resident import Resident +from dutylog.infrastructure.database.models.floor import Floor -__all__ = ["Base", "User", "HoursTransaction", "Room", "Resident"] +__all__ = ["Base", "User", "HoursTransaction", "Room", "Resident", "Floor"] diff --git a/src/dutylog/infrastructure/database/models/floor.py b/src/dutylog/infrastructure/database/models/floor.py new file mode 100644 index 0000000..b2363f1 --- /dev/null +++ b/src/dutylog/infrastructure/database/models/floor.py @@ -0,0 +1,11 @@ +from sqlalchemy import Integer +from sqlalchemy.orm import Mapped, mapped_column + +from dutylog.infrastructure.database.models.base import Base + + +class Floor(Base): + __tablename__ = "floors" + + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + number: Mapped[int] = mapped_column(Integer, nullable=False, unique=True) diff --git a/src/dutylog/infrastructure/database/models/room.py b/src/dutylog/infrastructure/database/models/room.py index 0c1766e..f4a4ccd 100644 --- a/src/dutylog/infrastructure/database/models/room.py +++ b/src/dutylog/infrastructure/database/models/room.py @@ -1,4 +1,4 @@ -from sqlalchemy import Integer +from sqlalchemy import Integer, ForeignKey from sqlalchemy.orm import Mapped, mapped_column from dutylog.infrastructure.database.models.base import Base @@ -9,3 +9,4 @@ class Room(Base): id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) number: Mapped[int] = mapped_column(Integer, nullable=False, unique=True) + on_floor: Mapped[int] = mapped_column(Integer, ForeignKey("floors.id", ondelete="CASCADE"), nullable=False) diff --git a/src/dutylog/infrastructure/database/repositories/floors_repository.py b/src/dutylog/infrastructure/database/repositories/floors_repository.py new file mode 100644 index 0000000..87361f8 --- /dev/null +++ b/src/dutylog/infrastructure/database/repositories/floors_repository.py @@ -0,0 +1,26 @@ +from dutylog.infrastructure.database.dao.floors_dao import FloorsDAO +from dutylog.infrastructure.database.models.floor import Floor + + +class FloorsRepository: + def __init__(self, floors_dao: FloorsDAO): + self.floors_dao = floors_dao + + async def get_or_create_floor(self, number: int) -> Floor: + floor = await self.floors_dao.get_by_number(number) + if not floor: + floor = Floor(number=number) + floor = await self.floors_dao.create(floor) + return floor + + async def get_floor_by_id(self, floor_id: int) -> Floor | None: + return await self.floors_dao.get_by_id(floor_id) + + async def get_floor_by_number(self, number: int) -> Floor | None: + return await self.floors_dao.get_by_number(number) + + async def get_all_floors(self) -> list[Floor]: + return await self.floors_dao.get_all() + + async def delete_floor(self, floor_id: int) -> None: + await self.floors_dao.delete(floor_id) diff --git a/src/dutylog/infrastructure/database/repositories/rooms_repository.py b/src/dutylog/infrastructure/database/repositories/rooms_repository.py index 09b4cf2..414982a 100644 --- a/src/dutylog/infrastructure/database/repositories/rooms_repository.py +++ b/src/dutylog/infrastructure/database/repositories/rooms_repository.py @@ -6,12 +6,9 @@ class RoomsRepository: def __init__(self, rooms_dao: RoomsDAO): self.rooms_dao = rooms_dao - async def get_or_create_room(self, number: int) -> Room: - room = await self.rooms_dao.get_by_number(number) - if not room: - room = Room(number=number) - room = await self.rooms_dao.create(room) - return room + async def create_room(self, number: int, floor_id: int) -> Room: + room = Room(number=number, on_floor=floor_id) + return await self.rooms_dao.create(room) async def get_room_by_id(self, room_id: int) -> Room | None: return await self.rooms_dao.get_by_id(room_id) @@ -19,6 +16,9 @@ class RoomsRepository: async def get_room_by_number(self, number: int) -> Room | None: return await self.rooms_dao.get_by_number(number) + async def get_rooms_by_floor(self, floor_id: int) -> list[Room]: + return await self.rooms_dao.get_by_floor(floor_id) + async def get_all_rooms(self) -> list[Room]: return await self.rooms_dao.get_all() diff --git a/src/dutylog/infrastructure/ioc.py b/src/dutylog/infrastructure/ioc.py index 0cfd890..b4b69a6 100644 --- a/src/dutylog/infrastructure/ioc.py +++ b/src/dutylog/infrastructure/ioc.py @@ -8,10 +8,12 @@ from dutylog.infrastructure.database.dao.users_dao import UsersDAO from dutylog.infrastructure.database.dao.hours_transactions_dao import HoursTransactionsDAO from dutylog.infrastructure.database.dao.rooms_dao import RoomsDAO from dutylog.infrastructure.database.dao.residents_dao import ResidentsDAO +from dutylog.infrastructure.database.dao.floors_dao import FloorsDAO from dutylog.infrastructure.database.repositories.users_repository import UsersRepository from dutylog.infrastructure.database.repositories.hours_transactions_repository import HoursTransactionsRepository from dutylog.infrastructure.database.repositories.rooms_repository import RoomsRepository from dutylog.infrastructure.database.repositories.residents_repository import ResidentsRepository +from dutylog.infrastructure.database.repositories.floors_repository import FloorsRepository from dutylog.infrastructure.utils.config import Config, load_config @@ -55,6 +57,10 @@ class DAOProvider(Provider): def get_residents_dao(self, session: AsyncSession) -> ResidentsDAO: return ResidentsDAO(session) + @provide(scope=Scope.REQUEST) + def get_floors_dao(self, session: AsyncSession) -> FloorsDAO: + return FloorsDAO(session) + class RepositoryProvider(Provider): @provide(scope=Scope.REQUEST) @@ -77,6 +83,11 @@ class RepositoryProvider(Provider): def get_residents_repository(self, residents_dao: ResidentsDAO) -> ResidentsRepository: return ResidentsRepository(residents_dao) + @provide(scope=Scope.REQUEST) + def get_floors_repository(self, floors_dao: FloorsDAO) -> FloorsRepository: + return FloorsRepository(floors_dao) + +