This commit is contained in:
2026-02-28 11:20:41 +03:00
parent b9ef6ccf09
commit 3c0d50a1aa
19 changed files with 544 additions and 185 deletions
@@ -9,15 +9,11 @@ class FloorsDAO:
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)
)
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)
)
result = await self.session.execute(select(Floor).where(Floor.number == number))
return result.scalar_one_or_none()
async def get_all(self) -> list[Floor]:
@@ -38,7 +34,5 @@ class FloorsDAO:
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.execute(delete(Floor).where(Floor.id == floor_id))
await self.session.commit()
@@ -50,7 +50,5 @@ class ResidentsDAO:
return await self.get_by_id(resident_id)
async def delete(self, resident_id: int) -> None:
await self.session.execute(
delete(Resident).where(Resident.id == resident_id)
)
await self.session.execute(delete(Resident).where(Resident.id == resident_id))
await self.session.commit()
@@ -9,15 +9,11 @@ class RoomsDAO:
self.session = session
async def get_by_id(self, room_id: int) -> Room | None:
result = await self.session.execute(
select(Room).where(Room.id == room_id)
)
result = await self.session.execute(select(Room).where(Room.id == room_id))
return result.scalar_one_or_none()
async def get_by_number(self, number: int) -> Room | None:
result = await self.session.execute(
select(Room).where(Room.number == number)
)
result = await self.session.execute(select(Room).where(Room.number == number))
return result.scalar_one_or_none()
async def get_by_floor(self, floor_id: int) -> list[Room]:
@@ -44,7 +40,5 @@ class RoomsDAO:
return await self.get_by_id(room_id)
async def delete(self, room_id: int) -> None:
await self.session.execute(
delete(Room).where(Room.id == room_id)
)
await self.session.execute(delete(Room).where(Room.id == room_id))
await self.session.commit()
@@ -9,9 +9,7 @@ class UsersDAO:
self.session = session
async def get_by_id(self, user_id: int) -> User | None:
result = await self.session.execute(
select(User).where(User.id == user_id)
)
result = await self.session.execute(select(User).where(User.id == user_id))
return result.scalar_one_or_none()
async def get_all(self) -> list[User]:
@@ -32,7 +30,5 @@ class UsersDAO:
return await self.get_by_id(user_id)
async def delete(self, user_id: int) -> None:
await self.session.execute(
delete(User).where(User.id == user_id)
)
await self.session.execute(delete(User).where(User.id == user_id))
await self.session.commit()
@@ -17,8 +17,14 @@ class HoursTransaction(Base):
__tablename__ = "hours_transactions"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
resident_id: Mapped[int] = mapped_column(Integer, ForeignKey("residents.id", ondelete="CASCADE"), nullable=False)
resident_id: Mapped[int] = mapped_column(
Integer, ForeignKey("residents.id", ondelete="CASCADE"), nullable=False
)
transaction_type: Mapped[str] = mapped_column(String(50), nullable=False)
amount: Mapped[int] = mapped_column(Integer, nullable=False)
admin_id: Mapped[int] = mapped_column(BigInteger, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=msk_now)
admin_id: Mapped[int] = mapped_column(
BigInteger, ForeignKey("users.id", ondelete="SET NULL"), nullable=True
)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=msk_now
)
@@ -12,10 +12,23 @@ class Resident(Base):
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
real_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
room: Mapped[int] = mapped_column(Integer, ForeignKey("rooms.id", ondelete="CASCADE"), nullable=False)
user_entity: Mapped[int | None] = mapped_column(BigInteger, ForeignKey("users.id", ondelete="SET NULL"), nullable=True, unique=True)
is_busy: Mapped[bool] = mapped_column(Boolean, default=False, server_default="false")
room: Mapped[int] = mapped_column(
Integer, ForeignKey("rooms.id", ondelete="CASCADE"), nullable=False
)
user_entity: Mapped[int | None] = mapped_column(
BigInteger,
ForeignKey("users.id", ondelete="SET NULL"),
nullable=True,
unique=True,
)
is_busy: Mapped[bool] = mapped_column(
Boolean, default=False, server_default="false"
)
active_hours: Mapped[int] = mapped_column(Integer, default=0, server_default="0")
inactive_hours: Mapped[int] = mapped_column(Integer, default=0, server_default="0")
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=msk_now)
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=msk_now, onupdate=msk_now)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=msk_now
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=msk_now, onupdate=msk_now
)
@@ -9,4 +9,6 @@ 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)
on_floor: Mapped[int] = mapped_column(
Integer, ForeignKey("floors.id", ondelete="CASCADE"), nullable=False
)
@@ -14,6 +14,12 @@ class User(Base):
username: Mapped[str | None] = mapped_column(String(255), nullable=True)
first_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
last_name: Mapped[str | None] = mapped_column(String(255), nullable=True)
is_admin: Mapped[bool] = mapped_column(Boolean, default=False, server_default="false")
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=msk_now)
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=msk_now, onupdate=msk_now)
is_admin: Mapped[bool] = mapped_column(
Boolean, default=False, server_default="false"
)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=msk_now
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=msk_now, onupdate=msk_now
)
@@ -1,6 +1,11 @@
from dutylog.infrastructure.database.dao.hours_transactions_dao import HoursTransactionsDAO
from dutylog.infrastructure.database.dao.hours_transactions_dao import (
HoursTransactionsDAO,
)
from dutylog.infrastructure.database.dao.residents_dao import ResidentsDAO
from dutylog.infrastructure.database.models.hours_transaction import HoursTransaction, TransactionType
from dutylog.infrastructure.database.models.hours_transaction import (
HoursTransaction,
TransactionType,
)
from dutylog.infrastructure.database.models.resident import Resident
@@ -32,10 +37,14 @@ class HoursTransactionsRepository:
if resident:
if is_active:
new_hours = resident.active_hours + amount
resident = await self.residents_dao.update(resident_id, active_hours=new_hours)
resident = await self.residents_dao.update(
resident_id, active_hours=new_hours
)
else:
new_hours = resident.inactive_hours + amount
resident = await self.residents_dao.update(resident_id, inactive_hours=new_hours)
resident = await self.residents_dao.update(
resident_id, inactive_hours=new_hours
)
return transaction, resident
@@ -58,10 +67,14 @@ class HoursTransactionsRepository:
if resident:
if is_active:
new_hours = max(0, resident.active_hours - amount)
resident = await self.residents_dao.update(resident_id, active_hours=new_hours)
resident = await self.residents_dao.update(
resident_id, active_hours=new_hours
)
else:
new_hours = max(0, resident.inactive_hours - amount)
resident = await self.residents_dao.update(resident_id, inactive_hours=new_hours)
resident = await self.residents_dao.update(
resident_id, inactive_hours=new_hours
)
return transaction, resident
@@ -71,5 +84,7 @@ class HoursTransactionsRepository:
async def get_all_transactions(self) -> list[HoursTransaction]:
return await self.transactions_dao.get_all()
async def get_transaction_by_id(self, transaction_id: int) -> HoursTransaction | None:
async def get_transaction_by_id(
self, transaction_id: int
) -> HoursTransaction | None:
return await self.transactions_dao.get_by_id(transaction_id)
@@ -17,7 +17,9 @@ class ResidentsRepository:
)
return await self.residents_dao.create(resident)
async def bind_user_to_resident(self, resident_id: int, user_id: int) -> Resident | None:
async def bind_user_to_resident(
self, resident_id: int, user_id: int
) -> Resident | None:
return await self.residents_dao.update(
resident_id,
user_entity=user_id,
@@ -52,7 +54,9 @@ class ResidentsRepository:
resident = await self.residents_dao.get_by_id(resident_id)
if resident:
new_hours = resident.inactive_hours + hours
return await self.residents_dao.update(resident_id, inactive_hours=new_hours)
return await self.residents_dao.update(
resident_id, inactive_hours=new_hours
)
return None
async def get_resident_by_id(self, resident_id: int) -> Resident | None:
+24 -13
View File
@@ -5,15 +5,27 @@ from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
from dutylog.infrastructure.database.config import create_engine, create_session_maker
from dutylog.infrastructure.database.dao.users_dao import UsersDAO
from dutylog.infrastructure.database.dao.hours_transactions_dao import HoursTransactionsDAO
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.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
@@ -29,7 +41,9 @@ class DatabaseProvider(Provider):
return create_engine(config.database.url)
@provide(scope=Scope.APP)
def get_session_maker(self, engine: AsyncEngine) -> async_sessionmaker[AsyncSession]:
def get_session_maker(
self, engine: AsyncEngine
) -> async_sessionmaker[AsyncSession]:
return create_session_maker(engine)
@provide(scope=Scope.REQUEST)
@@ -80,14 +94,11 @@ class RepositoryProvider(Provider):
return RoomsRepository(rooms_dao)
@provide(scope=Scope.REQUEST)
def get_residents_repository(self, residents_dao: ResidentsDAO) -> ResidentsRepository:
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)
+8 -8
View File
@@ -17,11 +17,11 @@ class DatabaseConfig:
user: str
password: str
database: str
@property
def url(self) -> str:
return f"postgresql+asyncpg://{self.user}:{self.password}@{self.host}:{self.port}/{self.database}"
@dataclass
class Config:
@@ -31,30 +31,30 @@ class Config:
def load_config() -> Config:
config_path = Path("config.toml")
if not config_path.exists():
raise FileNotFoundError(f"Config file not found: {config_path}")
with open(config_path, "rb") as f:
data = tomllib.load(f)
if "bot" not in data:
raise KeyError("Missing required section: bot")
if "database" not in data:
raise KeyError("Missing required section: database")
bot_data = data["bot"]
if "token" not in bot_data:
raise KeyError("Missing required field: bot.token")
if "creator_id" not in bot_data:
raise KeyError("Missing required field: bot.creator_id")
database_data = data["database"]
required_db_fields = ["host", "port", "user", "password", "database"]
for field in required_db_fields:
if field not in database_data:
raise KeyError(f"Missing required field: database.{field}")
return Config(
bot=BotConfig(
token=bot_data["token"],