diff --git a/src/hubgw/core/config.py b/src/hubgw/core/config.py index 14d3c8c..40766ea 100644 --- a/src/hubgw/core/config.py +++ b/src/hubgw/core/config.py @@ -53,6 +53,21 @@ class DatabaseSettings(BaseSettings): validation_alias="DATABASE__AZURIOM_SCHEMA", description="Azuriom database schema name", ) + luckperms_schema: str = Field( + default="hubmc", + validation_alias="DATABASE__LUCKPERMS_SCHEMA", + description="LuckPerms tables schema", + ) + hub_schema: str = Field( + default="hubmc", + validation_alias="DATABASE__HUB_SCHEMA", + description="Hub tables schema (cooldowns, homes, warps, etc.)", + ) + users_schema: str = Field( + default="public", + validation_alias="DATABASE__USERS_SCHEMA", + description="Users table schema", + ) pool_size: int = Field( default=10, validation_alias="DATABASE__POOL_SIZE", diff --git a/src/hubgw/models/cooldown.py b/src/hubgw/models/cooldown.py index e76d153..b3a22b9 100644 --- a/src/hubgw/models/cooldown.py +++ b/src/hubgw/models/cooldown.py @@ -4,8 +4,13 @@ from sqlalchemy import (Column, DateTime, ForeignKey, Integer, String, UniqueConstraint) from sqlalchemy.dialects.postgresql import JSONB, UUID +from hubgw.core.config import APP_CONFIG from hubgw.models.base import Base +# Get schemas at module load time +_HUB_SCHEMA = APP_CONFIG.database.hub_schema +_LUCKPERMS_SCHEMA = APP_CONFIG.database.luckperms_schema + class Cooldown(Base): """Cooldown model.""" @@ -15,6 +20,7 @@ class Cooldown(Base): UniqueConstraint( "player_uuid", "cooldown_type", name="idx_hub_cooldowns_player_type" ), + {"schema": _HUB_SCHEMA}, ) id = Column( @@ -22,11 +28,11 @@ class Cooldown(Base): ) player_uuid = Column( String(36), - ForeignKey("luckperms_players.uuid", ondelete="CASCADE"), + ForeignKey(f"{_LUCKPERMS_SCHEMA}.luckperms_players.uuid", ondelete="CASCADE"), nullable=False, index=True, ) cooldown_type = Column(String(50), nullable=False) expires_at = Column(DateTime(timezone=True), nullable=False, index=True) cooldown_seconds = Column(Integer, nullable=False) - data = Column(JSONB) + cooldown_metadata = Column("metadata", JSONB) diff --git a/src/hubgw/models/home.py b/src/hubgw/models/home.py index 0c3aaeb..afb955f 100644 --- a/src/hubgw/models/home.py +++ b/src/hubgw/models/home.py @@ -4,8 +4,13 @@ from sqlalchemy import (REAL, Boolean, Column, Float, ForeignKey, String, Text, UniqueConstraint) from sqlalchemy.dialects.postgresql import UUID +from hubgw.core.config import APP_CONFIG from hubgw.models.base import Base +# Get schemas at module load time +_HUB_SCHEMA = APP_CONFIG.database.hub_schema +_LUCKPERMS_SCHEMA = APP_CONFIG.database.luckperms_schema + class Home(Base): """Home model.""" @@ -13,6 +18,7 @@ class Home(Base): __tablename__ = "hub_homes" __table_args__ = ( UniqueConstraint("player_uuid", "name", name="idx_hub_homes_player_name"), + {"schema": _HUB_SCHEMA}, ) id = Column( @@ -20,7 +26,7 @@ class Home(Base): ) player_uuid = Column( String(36), - ForeignKey("luckperms_players.uuid", ondelete="CASCADE"), + ForeignKey(f"{_LUCKPERMS_SCHEMA}.luckperms_players.uuid", ondelete="CASCADE"), nullable=False, index=True, ) diff --git a/src/hubgw/models/luckperms.py b/src/hubgw/models/luckperms.py index 3e93541..471108f 100644 --- a/src/hubgw/models/luckperms.py +++ b/src/hubgw/models/luckperms.py @@ -4,13 +4,18 @@ from sqlalchemy import (BigInteger, Boolean, Column, ForeignKey, Index, Integer, String) from sqlalchemy.orm import relationship +from hubgw.core.config import APP_CONFIG from hubgw.models.base import Base +# Get schema at module load time +_LUCKPERMS_SCHEMA = APP_CONFIG.database.luckperms_schema + class LuckPermsPlayer(Base): """LuckPerms Player model.""" __tablename__ = "luckperms_players" + __table_args__ = {"schema": _LUCKPERMS_SCHEMA} uuid = Column(String(36), primary_key=True) username = Column(String(16), nullable=False, index=True) @@ -25,6 +30,7 @@ class LuckPermsGroup(Base): """LuckPerms Group model.""" __tablename__ = "luckperms_groups" + __table_args__ = {"schema": _LUCKPERMS_SCHEMA} name = Column(String(36), primary_key=True) @@ -41,20 +47,21 @@ class LuckPermsUserPermission(Base): "server", "world", ), + {"schema": _LUCKPERMS_SCHEMA}, ) id = Column(Integer, primary_key=True, autoincrement=True) uuid = Column( String(36), - ForeignKey("luckperms_players.uuid", ondelete="CASCADE"), + ForeignKey(f"{_LUCKPERMS_SCHEMA}.luckperms_players.uuid", ondelete="CASCADE"), nullable=False, index=True, ) permission = Column(String(200), nullable=False) value = Column(Boolean, nullable=False) - server = Column(String(36)) - world = Column(String(64)) - expiry = Column(BigInteger) - contexts = Column(String(200)) + server = Column(String(36), nullable=False) + world = Column(String(64), nullable=False) + expiry = Column(BigInteger, nullable=False) + contexts = Column(String(200), nullable=False) player = relationship("LuckPermsPlayer", back_populates="permissions") diff --git a/src/hubgw/models/punishment.py b/src/hubgw/models/punishment.py index 7dfff8b..cd0b990 100644 --- a/src/hubgw/models/punishment.py +++ b/src/hubgw/models/punishment.py @@ -4,8 +4,13 @@ from sqlalchemy import (Boolean, CheckConstraint, Column, DateTime, ForeignKey, Index, String, Text) from sqlalchemy.dialects.postgresql import INET, UUID +from hubgw.core.config import APP_CONFIG from hubgw.models.base import Base +# Get schemas at module load time +_HUB_SCHEMA = APP_CONFIG.database.hub_schema +_LUCKPERMS_SCHEMA = APP_CONFIG.database.luckperms_schema + class Punishment(Base): """Punishment model.""" @@ -33,6 +38,7 @@ class Punishment(Base): "player_ip", postgresql_where=Column("player_ip").is_not(None), ), + {"schema": _HUB_SCHEMA}, ) id = Column( @@ -40,7 +46,7 @@ class Punishment(Base): ) player_uuid = Column( String(36), - ForeignKey("luckperms_players.uuid", ondelete="CASCADE"), + ForeignKey(f"{_LUCKPERMS_SCHEMA}.luckperms_players.uuid", ondelete="CASCADE"), nullable=False, index=True, ) @@ -50,7 +56,7 @@ class Punishment(Base): reason = Column(Text, nullable=False) staff_uuid = Column( String(36), - ForeignKey("luckperms_players.uuid", ondelete="SET NULL"), + ForeignKey(f"{_LUCKPERMS_SCHEMA}.luckperms_players.uuid", ondelete="SET NULL"), nullable=False, ) staff_name = Column(String(255), nullable=False) @@ -58,7 +64,7 @@ class Punishment(Base): is_active = Column(Boolean, default=True) revoked_at = Column(DateTime(timezone=True)) revoked_by = Column( - String(36), ForeignKey("luckperms_players.uuid", ondelete="SET NULL") + String(36), ForeignKey(f"{_LUCKPERMS_SCHEMA}.luckperms_players.uuid", ondelete="SET NULL") ) revoked_reason = Column(Text) evidence_url = Column(Text) diff --git a/src/hubgw/models/teleport_history.py b/src/hubgw/models/teleport_history.py index f333c54..7add6a9 100644 --- a/src/hubgw/models/teleport_history.py +++ b/src/hubgw/models/teleport_history.py @@ -4,20 +4,26 @@ from sqlalchemy import Column, DateTime, Float, ForeignKey, String, Text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.sql import func +from hubgw.core.config import APP_CONFIG from hubgw.models.base import Base +# Get schemas at module load time +_HUB_SCHEMA = APP_CONFIG.database.hub_schema +_LUCKPERMS_SCHEMA = APP_CONFIG.database.luckperms_schema + class TeleportHistory(Base): """Teleport History model.""" __tablename__ = "hub_teleport_history" + __table_args__ = {"schema": _HUB_SCHEMA} id = Column( UUID(as_uuid=True), primary_key=True, server_default="gen_random_uuid()" ) player_uuid = Column( String(36), - ForeignKey("luckperms_players.uuid", ondelete="CASCADE"), + ForeignKey(f"{_LUCKPERMS_SCHEMA}.luckperms_players.uuid", ondelete="CASCADE"), nullable=False, index=True, ) diff --git a/src/hubgw/models/users.py b/src/hubgw/models/users.py index 36ef55e..8d2329b 100644 --- a/src/hubgw/models/users.py +++ b/src/hubgw/models/users.py @@ -3,20 +3,28 @@ from sqlalchemy import (Boolean, Column, DateTime, ForeignKey, Index, Integer, Numeric, String) +from hubgw.core.config import APP_CONFIG from hubgw.models.base import Base +# Get schema at module load time +_USERS_SCHEMA = APP_CONFIG.database.users_schema + class User(Base): """User model.""" __tablename__ = "users" + __table_args__ = ( + Index("idx_users_email", "email", unique=True), + {"schema": _USERS_SCHEMA}, + ) id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(191), nullable=False) email = Column(String(191), unique=True, nullable=True) email_verified_at = Column(DateTime(timezone=True), nullable=True) password = Column(String(191), nullable=False) - role_id = Column(Integer, ForeignKey("roles.id"), nullable=False) + role_id = Column(Integer, ForeignKey(f"{_USERS_SCHEMA}.roles.id"), nullable=False) money = Column(Numeric(14, 2), default=0) game_id = Column(String(191), nullable=True) avatar = Column(String, nullable=True) # TEXT поле @@ -31,7 +39,3 @@ class User(Base): updated_at = Column(DateTime(timezone=True), nullable=True) deleted_at = Column(DateTime(timezone=True), nullable=True) password_changed_at = Column(DateTime(timezone=True), nullable=True) - - __table_args__ = ( - Index("idx_users_email", "email", unique=True), - ) diff --git a/src/hubgw/models/warp.py b/src/hubgw/models/warp.py index 0786027..e18d9c1 100644 --- a/src/hubgw/models/warp.py +++ b/src/hubgw/models/warp.py @@ -3,8 +3,12 @@ from sqlalchemy import REAL, Boolean, Column, Float, Index, String, Text from sqlalchemy.dialects.postgresql import UUID +from hubgw.core.config import APP_CONFIG from hubgw.models.base import Base +# Get schema at module load time +_HUB_SCHEMA = APP_CONFIG.database.hub_schema + class Warp(Base): """Warp model.""" @@ -15,6 +19,7 @@ class Warp(Base): Index( "idx_hub_warps_public", "is_public", postgresql_where=Column("is_public") ), + {"schema": _HUB_SCHEMA}, ) id = Column( diff --git a/src/hubgw/models/whitelist.py b/src/hubgw/models/whitelist.py index e54db35..3afcba1 100644 --- a/src/hubgw/models/whitelist.py +++ b/src/hubgw/models/whitelist.py @@ -3,8 +3,12 @@ from sqlalchemy import Boolean, Column, DateTime, Index, String from sqlalchemy.dialects.postgresql import UUID +from hubgw.core.config import APP_CONFIG from hubgw.models.base import Base +# Get schema at module load time +_HUB_SCHEMA = APP_CONFIG.database.hub_schema + class WhitelistEntry(Base): """Whitelist entry model.""" @@ -21,6 +25,7 @@ class WhitelistEntry(Base): "expires_at", postgresql_where=Column("expires_at").is_not(None), ), + {"schema": _HUB_SCHEMA}, ) id = Column( diff --git a/src/hubgw/repositories/cooldowns_repo.py b/src/hubgw/repositories/cooldowns_repo.py index 7fa6f31..b0ed5f9 100644 --- a/src/hubgw/repositories/cooldowns_repo.py +++ b/src/hubgw/repositories/cooldowns_repo.py @@ -23,7 +23,7 @@ class CooldownsRepository: cooldown_type=request.cooldown_type, expires_at=request.expires_at, cooldown_seconds=request.cooldown_seconds, - data=request.data, + cooldown_metadata=request.metadata, ) self.session.add(cooldown) await self.session.commit() diff --git a/src/hubgw/schemas/cooldowns.py b/src/hubgw/schemas/cooldowns.py index a810a83..0a4da2a 100644 --- a/src/hubgw/schemas/cooldowns.py +++ b/src/hubgw/schemas/cooldowns.py @@ -28,15 +28,15 @@ class CooldownBase(BaseModel): """Base cooldown schema.""" cooldown_type: str - expires_at: datetime cooldown_seconds: int - data: Optional[dict] = None + metadata: Optional[dict] = None class CooldownCreate(CooldownBase): """Cooldown creation schema.""" player_uuid: str + expires_at: Optional[datetime] = None class Cooldown(CooldownBase, BaseSchema): @@ -44,6 +44,7 @@ class Cooldown(CooldownBase, BaseSchema): id: UUID player_uuid: str + expires_at: datetime class CooldownQuery(PaginationParams): diff --git a/src/hubgw/services/cooldowns_service.py b/src/hubgw/services/cooldowns_service.py index ead3a82..2f5cfd5 100644 --- a/src/hubgw/services/cooldowns_service.py +++ b/src/hubgw/services/cooldowns_service.py @@ -36,4 +36,10 @@ class CooldownsService: async def create_cooldown(self, request: CooldownCreate) -> None: """Create new cooldown.""" + if request.expires_at is None: + from datetime import timedelta + + request.expires_at = datetime.now(timezone.utc) + timedelta( + seconds=request.cooldown_seconds + ) await self.repo.create(request)