MVP системы отложенных сообщений

This commit is contained in:
2025-08-07 17:24:48 +03:00
parent e44cb15248
commit 618b2b7fbc
3 changed files with 73 additions and 7 deletions

View File

@@ -288,6 +288,8 @@ class MainBot(AnyBots):
self.MakeBackups.start() self.MakeBackups.start()
self.CheckDataBases.start() self.CheckDataBases.start()
else:
self.SendingDeferredMessages.start()
async def BotOff(self): async def BotOff(self):
if self.task_start: if self.task_start:
@@ -303,6 +305,25 @@ class MainBot(AnyBots):
print(f"{datetime.datetime.now().strftime('%H:%M:%S %d-%m-%Y')}:: Соединение с дискордом разорвано") print(f"{datetime.datetime.now().strftime('%H:%M:%S %d-%m-%Y')}:: Соединение с дискордом разорвано")
await self.BotOff() await self.BotOff()
@tasks.loop(seconds=60)
async def SendingDeferredMessages(self):
try:
async with self.DataBaseManager.session() as session:
async with session.begin():
stmt = self.DataBaseManager.select(self.DataBaseManager.model_classes['scheduled_messages']).where(
self.DataBaseManager.model_classes['scheduled_messages'].timestamp - datetime.datetime.now().timestamp() <= 0
).with_for_update()
messages = (await session.execute(stmt)).scalars().all()
for message in messages:
webhook = await self.fetch_webhook(message.webhook_id)
await webhook.send(await message.parse_message(self))
await session.delete(message)
except Exception as error:
print(f"{datetime.datetime.now().strftime('%H:%M:%S %d-%m-%Y')}:: err SendingDeferredMessages: {error}")
@tasks.loop(seconds=60) @tasks.loop(seconds=60)
async def CheckDataBases(self): async def CheckDataBases(self):
try: try:

View File

@@ -1,3 +1,4 @@
import re
import disnake import disnake
from disnake.ext import commands from disnake.ext import commands
from disnake.ext import tasks from disnake.ext import tasks
@@ -208,3 +209,39 @@ class AdminModule(commands.Cog):
session.add(user_role) session.add(user_role)
await ctx.send(embed = self.client.SuccessEmbed(description = f'Пользователю <@{userid}> успешно назначена роль <@&{roleid}>. \n```diff\n- Эта функция не выдаёт роли автоматически, поэтому требуется выдача вручную.```', colour = 0xff9900)) await ctx.send(embed = self.client.SuccessEmbed(description = f'Пользователю <@{userid}> успешно назначена роль <@&{roleid}>. \n```diff\n- Эта функция не выдаёт роли автоматически, поэтому требуется выдача вручную.```', colour = 0xff9900))
return 0 return 0
@commands.slash_command(name="запланировать_сообщение", description="Позволяет запланировать отправку анонсов и других сообщений")
async def schedule_message(self, ctx: disnake.AppCmdInter,
message_id: str = commands.Param(description="Укажите id сообщения, которое будет отложено", name="сообщение"),
webhook_link: str = commands.Param(description="Укажите ссылку на вебхук, от которого будет отправлено сообщение(по умолчанию от лица бота)", name="вебхук", default=None),
timestamp: int = commands.Param(description="Временная метка для отправки сообщения", name="таймстамп", default=None)):
await ctx.response.defer()
def extract_webhook_id(webhook_url: str) -> int | None:
pattern = r"^https:\/\/(?:canary\.|ptb\.)?discord(?:app)?\.com\/api\/webhooks\/(\d+)\/[\w\-]+$"
match = re.match(pattern, webhook_url)
if match:
return int(match.group(1))
return None
if webhook_link is None:
webhook_id = None
else:
webhook_id = extract_webhook_id(webhook_link)
if webhook_id is None:
await ctx.edit_original_response(embed = self.client.ErrEmbed(description = f'Некорректная ссылка'))
return 1
async with self.DataBaseManager.session() as session:
async with session.begin():
if not (await self.DataBaseManager.model_classes['staff_users'].is_admin_or_moder_by_id(ctx.author.id, self.DataBaseManager, session, is_admin=True, is_moder=False)):
await ctx.edit_original_response(embed = self.client.ErrEmbed(description = f'У вас недостаточно полномочий, чтобы оставлять отложенные сообщения.'))
return 1
else:
scheduled_message_model = self.DataBaseManager.model_classes['scheduled_messages']
message = scheduled_message_model(source_channel_id=ctx.channel.id, source_message_id=int(message_id), webhook_id=webhook_id, timestamp=timestamp)
session.add(message)
await ctx.edit_original_response(embed = self.client.SuccessEmbed(description = f'Успешно! Текст сообщения:\n {await message.parse_message(self.client)}', colour = 0xff9900))
return 0

View File

@@ -152,7 +152,7 @@ class StaffUser(Base):
return await self.__class__.is_admin_or_moder_by_id(self.id, DBManager, session) return await self.__class__.is_admin_or_moder_by_id(self.id, DBManager, session)
@staticmethod @staticmethod
async def is_admin_or_moder_by_id(member_id, DBManager, session): 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_branches_model = DBManager.model_classes['staff_branches']
staff_users_roles_model = DBManager.model_classes['staff_users_roles'] staff_users_roles_model = DBManager.model_classes['staff_users_roles']
@@ -162,8 +162,8 @@ class StaffUser(Base):
.where( .where(
DBManager.and_( DBManager.and_(
DBManager.or_( DBManager.or_(
staff_branches_model.is_admin == True, (staff_branches_model.is_admin == True) if is_admin else False,
staff_branches_model.is_moder == True, (staff_branches_model.is_moder == True) if is_moder else False,
), ),
staff_users_roles_model.user_id == member_id staff_users_roles_model.user_id == member_id
) )
@@ -233,10 +233,18 @@ class AllowedDomain(Base):
class ScheduledMessage(Base): class ScheduledMessage(Base):
__tablename__ = "scheduled_messages" __tablename__ = "scheduled_messages"
message_id: Mapped[discord_identificator_pk] source_message_id: Mapped[discord_identificator_pk]
webhook_id: Mapped[discord_identificator] source_channel_id: Mapped[discord_identificator]
timestamp: Mapped[float | None] = mapped_column(Float) 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):
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)
content = source_message.content
return content
all_data = { all_data = {
'base': Base 'base': Base