270 lines
10 KiB
Python
270 lines
10 KiB
Python
import io
|
||
import disnake
|
||
from sqlalchemy import Column, Integer, BigInteger, Text, Float, ForeignKey, UniqueConstraint, MetaData, Boolean
|
||
from sqlalchemy.orm import declarative_base, relationship, Mapped, mapped_column
|
||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
||
from sqlalchemy.orm import sessionmaker, relationship, DeclarativeBase
|
||
from sqlalchemy.schema import CreateTable
|
||
from sqlalchemy.sql import text
|
||
import datetime
|
||
from typing import Annotated
|
||
|
||
class Base(DeclarativeBase):
|
||
|
||
def get_table_name(self):
|
||
return self.__tablename__
|
||
|
||
def to_dict(self, exclude: list[str] | None = None):
|
||
"""Конвертирует модель в словарь, исключая указанные поля."""
|
||
if exclude is None:
|
||
exclude = []
|
||
|
||
return {
|
||
c.name: getattr(self, c.name)
|
||
for c in self.__table__.columns
|
||
if c.name not in exclude
|
||
}
|
||
|
||
discord_identificator_pk = Annotated[int, mapped_column(BigInteger, primary_key=True, nullable=False, index = True)]
|
||
identificator_pk = Annotated[int, mapped_column(Integer, primary_key=True, nullable=False, autoincrement=True, index = True)]
|
||
discord_identificator = Annotated[int, mapped_column(BigInteger, nullable=False, index=True)]
|
||
|
||
# Модели для системы наказаний
|
||
class PunishmentTextMute(Base):
|
||
__tablename__ = 'punishment_mutes_text'
|
||
id: Mapped[identificator_pk]
|
||
user_id: Mapped[discord_identificator]
|
||
reason: Mapped[str | None] = mapped_column(Text)
|
||
time_end: Mapped[float | None] = mapped_column(Float)
|
||
time_warn: Mapped[float | None] = mapped_column(Float)
|
||
|
||
time_begin: Mapped[float] = mapped_column(Float, nullable=False, server_default=text("EXTRACT(EPOCH FROM NOW())"))
|
||
moderator_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True, default = None)
|
||
|
||
|
||
class PunishmentVoiceMute(Base):
|
||
__tablename__ = 'punishment_mutes_voice'
|
||
id: Mapped[identificator_pk]
|
||
user_id: Mapped[discord_identificator]
|
||
reason: Mapped[str | None] = mapped_column(Text)
|
||
time_end: Mapped[float | None] = mapped_column(Float)
|
||
time_warn: Mapped[float | None] = mapped_column(Float)
|
||
|
||
time_begin: Mapped[float] = mapped_column(Float, nullable=False, server_default=text("EXTRACT(EPOCH FROM NOW())"))
|
||
moderator_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True, default = None)
|
||
|
||
|
||
class PunishmentWarn(Base):
|
||
__tablename__ = 'punishment_warns'
|
||
id: Mapped[identificator_pk]
|
||
user_id: Mapped[discord_identificator]
|
||
reason: Mapped[str | None] = mapped_column(Text)
|
||
time_warn: Mapped[float] = mapped_column(Float)
|
||
|
||
time_begin: Mapped[float] = mapped_column(Float, nullable=False, server_default=text("EXTRACT(EPOCH FROM NOW())"))
|
||
moderator_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True, default = None)
|
||
|
||
|
||
class PunishmentBan(Base):
|
||
__tablename__ = 'punishment_bans'
|
||
id: Mapped[identificator_pk]
|
||
user_id: Mapped[discord_identificator]
|
||
reason: Mapped[str | None] = mapped_column(Text)
|
||
time_end: Mapped[float | None] = mapped_column(Float)
|
||
|
||
time_begin: Mapped[float] = mapped_column(Float, nullable=False, server_default=text("EXTRACT(EPOCH FROM NOW())"))
|
||
moderator_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True, default = None)
|
||
|
||
|
||
class PunishmentPerm(Base):
|
||
__tablename__ = 'punishment_perms'
|
||
id: Mapped[identificator_pk]
|
||
user_id: Mapped[discord_identificator]
|
||
reason: Mapped[str | None] = mapped_column(Text)
|
||
|
||
time_begin: Mapped[float] = mapped_column(Float, nullable=False, server_default=text("EXTRACT(EPOCH FROM NOW())"))
|
||
moderator_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True, default = None)
|
||
|
||
|
||
class PunishmentReprimand(Base):
|
||
__tablename__ = 'punishment_reprimands'
|
||
id: Mapped[identificator_pk]
|
||
user_id: Mapped[discord_identificator]
|
||
reason: Mapped[str | None] = mapped_column(Text)
|
||
time_warn: Mapped[float] = mapped_column(Float)
|
||
branch_id: Mapped[int] = mapped_column(ForeignKey('staff_branches.id', ondelete='CASCADE'))
|
||
|
||
time_begin: Mapped[float] = mapped_column(Float, nullable=False, server_default=text("EXTRACT(EPOCH FROM NOW())"))
|
||
designated_user_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True, default = None)
|
||
|
||
|
||
# Модели для системы персонала
|
||
class StaffBranch(Base):
|
||
__tablename__ = 'staff_branches'
|
||
id: Mapped[identificator_pk]
|
||
layer: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
purpose: Mapped[str] = mapped_column(Text)
|
||
is_admin: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||
is_moder: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
||
|
||
roles: Mapped[list["StaffRole"]] = relationship(
|
||
back_populates="branch",
|
||
primaryjoin="StaffBranch.id==StaffRole.branch_id"
|
||
)
|
||
users: Mapped[list["StaffUserRole"]] = relationship(
|
||
back_populates="branch",
|
||
primaryjoin="StaffBranch.id==StaffUserRole.branch_id"
|
||
)
|
||
curations: Mapped[list["StaffCuration"]] = relationship(
|
||
back_populates="branch",
|
||
primaryjoin="StaffBranch.id==StaffCuration.branch_id"
|
||
)
|
||
|
||
class StaffRole(Base):
|
||
__tablename__ = 'staff_roles'
|
||
id: Mapped[discord_identificator_pk]
|
||
layer: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
staff_salary: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
branch_id: Mapped[int] = mapped_column(ForeignKey('staff_branches.id', ondelete='CASCADE'))
|
||
|
||
branch: Mapped["StaffBranch"] = relationship(
|
||
back_populates="roles",
|
||
primaryjoin="StaffRole.branch_id==StaffBranch.id"
|
||
)
|
||
users: Mapped[list["StaffUserRole"]] = relationship(
|
||
back_populates="role",
|
||
primaryjoin="StaffRole.id==StaffUserRole.role_id"
|
||
)
|
||
|
||
class StaffUser(Base):
|
||
__tablename__ = 'staff_users'
|
||
id: Mapped[discord_identificator_pk]
|
||
|
||
roles: Mapped[list["StaffUserRole"]] = relationship(back_populates="user")
|
||
curators: Mapped[list["StaffCuration"]] = relationship(
|
||
back_populates="apprentice",
|
||
primaryjoin="StaffUser.id==StaffCuration.apprentice_id"
|
||
)
|
||
apprentices: Mapped[list["StaffCuration"]] = relationship(
|
||
back_populates="curator",
|
||
primaryjoin="StaffUser.id==StaffCuration.curator_id"
|
||
)
|
||
|
||
async def is_admin_or_moder(self, DBManager, session):
|
||
return await self.__class__.is_admin_or_moder_by_id(self.id, DBManager, session)
|
||
|
||
@staticmethod
|
||
async def is_admin_or_moder_by_id(member_id, DBManager, session, *, is_admin=True, is_moder=True):
|
||
staff_branches_model = DBManager.model_classes['staff_branches']
|
||
staff_users_roles_model = DBManager.model_classes['staff_users_roles']
|
||
|
||
stmt = (
|
||
DBManager.select(staff_users_roles_model)
|
||
.join(staff_branches_model, staff_branches_model.id == staff_users_roles_model.branch_id)
|
||
.where(
|
||
DBManager.and_(
|
||
DBManager.or_(
|
||
(staff_branches_model.is_admin == True) if is_admin else False,
|
||
(staff_branches_model.is_moder == True) if is_moder else False,
|
||
),
|
||
staff_users_roles_model.user_id == member_id
|
||
)
|
||
)
|
||
)
|
||
|
||
result = await session.execute(stmt)
|
||
return result.scalars().first() is not None
|
||
|
||
|
||
class StaffUserRole(Base):
|
||
__tablename__ = 'staff_users_roles'
|
||
id: Mapped[identificator_pk]
|
||
user_id: Mapped[int] = mapped_column(ForeignKey('staff_users.id', ondelete='CASCADE'))
|
||
role_id: Mapped[int] = mapped_column(ForeignKey('staff_roles.id', ondelete='CASCADE'))
|
||
branch_id: Mapped[int] = mapped_column(ForeignKey('staff_branches.id', ondelete='CASCADE'))
|
||
description: Mapped[str | None] = mapped_column(Text)
|
||
update_time: Mapped[float] = mapped_column(Float,
|
||
server_default=text("EXTRACT(EPOCH FROM NOW())"),
|
||
server_onupdate=text("EXTRACT(EPOCH FROM NOW())")
|
||
)
|
||
|
||
user: Mapped["StaffUser"] = relationship(back_populates="roles")
|
||
branch: Mapped["StaffBranch"] = relationship(back_populates="users")
|
||
role: Mapped["StaffRole"] = relationship(back_populates="users")
|
||
|
||
__table_args__ = (
|
||
UniqueConstraint('user_id', 'branch_id', name='uq_user_branch'),
|
||
)
|
||
|
||
@classmethod
|
||
async def create_with_auto_branch(cls, session, user_id: int, role_id: int, **kwargs):
|
||
# Получаем роль
|
||
role = await session.get(StaffRole, role_id)
|
||
if not role:
|
||
raise ValueError("Роль не найдена")
|
||
|
||
return cls(user_id=user_id, role_id=role_id, branch_id=role.branch_id, **kwargs)
|
||
|
||
|
||
class StaffCuration(Base):
|
||
__tablename__ = 'staff_curation'
|
||
id: Mapped[identificator_pk]
|
||
apprentice_id: Mapped[int] = mapped_column(ForeignKey('staff_users.id', ondelete='CASCADE'))
|
||
curator_id: Mapped[int] = mapped_column(ForeignKey('staff_users.id', ondelete='CASCADE'))
|
||
branch_id: Mapped[int] = mapped_column(ForeignKey('staff_branches.id', ondelete='CASCADE'))
|
||
|
||
apprentice: Mapped["StaffUser"] = relationship(
|
||
back_populates="curators",
|
||
foreign_keys=[apprentice_id]
|
||
)
|
||
curator: Mapped["StaffUser"] = relationship(
|
||
back_populates="apprentices",
|
||
foreign_keys=[curator_id]
|
||
)
|
||
branch: Mapped["StaffBranch"] = relationship(back_populates="curations")
|
||
|
||
__table_args__ = (
|
||
UniqueConstraint('apprentice_id', 'curator_id', 'branch_id', name='uq_apprentice_curator_branch'),
|
||
)
|
||
|
||
class AllowedDomain(Base):
|
||
__tablename__ = "аllowed_domains"
|
||
id: Mapped[identificator_pk]
|
||
domain: Mapped[str] = mapped_column(Text, index=True, nullable=False, unique=True)
|
||
initiator_id: Mapped[discord_identificator]
|
||
|
||
class ScheduledMessage(Base):
|
||
__tablename__ = "scheduled_messages"
|
||
source_message_id: Mapped[discord_identificator_pk]
|
||
source_channel_id: Mapped[discord_identificator]
|
||
webhook_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True)
|
||
timestamp: Mapped[float | None] = mapped_column(Float, nullable=True, index=True)
|
||
|
||
async def parse_message(self, client, *, preview=False):
|
||
krekchat = await client.fetch_guild(client.krekchat.id)
|
||
source_channel = await krekchat.fetch_channel(self.source_channel_id)
|
||
source_message = await source_channel.fetch_message(self.source_message_id)
|
||
|
||
files = []
|
||
for attachment in source_message.attachments:
|
||
file_bytes = await attachment.read()
|
||
files.append(disnake.File(io.BytesIO(file_bytes), filename=attachment.filename))
|
||
|
||
content = source_message.content if not preview else source_message.clean_content
|
||
|
||
def make_dict(**kwargs):
|
||
return kwargs
|
||
|
||
args = make_dict(content=content,
|
||
embeds=source_message.embeds,
|
||
components=source_message.components,
|
||
files=files if files else None
|
||
)
|
||
|
||
return args
|
||
|
||
all_data = {
|
||
'base': Base
|
||
}
|
||
|