Добавлена смена никнейма при уходе в AFK
All checks were successful
CI / basic-checks (push) Successful in 51s
All checks were successful
CI / basic-checks (push) Successful in 51s
This commit is contained in:
@@ -29,6 +29,7 @@ class Bot(commands.Bot):
|
|||||||
intents.guilds = True
|
intents.guilds = True
|
||||||
intents.message_content = True
|
intents.message_content = True
|
||||||
intents.members = True
|
intents.members = True
|
||||||
|
intents.presences = True
|
||||||
|
|
||||||
command_prefix: str = prefix or getattr(settings, "PREFIX", "!")
|
command_prefix: str = prefix or getattr(settings, "PREFIX", "!")
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,69 @@ class Events(Cog):
|
|||||||
self.check_reminders.start()
|
self.check_reminders.start()
|
||||||
|
|
||||||
@Cog.listener()
|
@Cog.listener()
|
||||||
|
async def on_presence_update(self, before: discord.Member, after: discord.Member) -> None:
|
||||||
|
"""
|
||||||
|
Следим за конкретным пользователем и меняем ник на '[AFK] Ник' при уходе в Idle,
|
||||||
|
а при возвращении восстанавливаем оригинальный ник.
|
||||||
|
"""
|
||||||
|
afk_nickname = getattr(settings, "AFK_NICKNAME", "AFK")
|
||||||
|
# если статус не изменился — выходим
|
||||||
|
if before.status == after.status:
|
||||||
|
return
|
||||||
|
# словарь для хранения оригинального ника
|
||||||
|
if not hasattr(self, 'original_nick'):
|
||||||
|
self.original_nick = {}
|
||||||
|
|
||||||
|
# пользователь ушёл в AFK/Idle
|
||||||
|
if after.status == discord.Status.idle:
|
||||||
|
# если уже AFK, ничего не делаем
|
||||||
|
if after.nick and after.nick.startswith(afk_nickname):
|
||||||
|
return
|
||||||
|
|
||||||
|
# сохраняем оригинальный ник
|
||||||
|
self.original_nick[after.id] = after.nick or after.name
|
||||||
|
|
||||||
|
try:
|
||||||
|
await after.edit(nick=afk_nickname)
|
||||||
|
logger.info(
|
||||||
|
text=f"{after} ушёл в AFK, ник изменён",
|
||||||
|
log_type="PRESENCE",
|
||||||
|
user=str(after),
|
||||||
|
)
|
||||||
|
except discord.Forbidden:
|
||||||
|
logger.warning(
|
||||||
|
text=f"Нет прав изменить ник {after}",
|
||||||
|
log_type="PRESENCE",
|
||||||
|
)
|
||||||
|
except discord.HTTPException as e:
|
||||||
|
logger.error(
|
||||||
|
text=f"Ошибка смены ника {after}: {e!r}",
|
||||||
|
log_type="PRESENCE",
|
||||||
|
)
|
||||||
|
|
||||||
|
# пользователь вернулся из AFK
|
||||||
|
elif before.status == discord.Status.idle and after.status != discord.Status.idle:
|
||||||
|
original = self.original_nick.get(after.id)
|
||||||
|
if original:
|
||||||
|
try:
|
||||||
|
await after.edit(nick=original)
|
||||||
|
logger.info(
|
||||||
|
text=f"{after} вернулся из AFK, ник восстановлен",
|
||||||
|
log_type="PRESENCE",
|
||||||
|
user=str(after),
|
||||||
|
)
|
||||||
|
del self.original_nick[after.id] # убираем из словаря
|
||||||
|
except discord.Forbidden:
|
||||||
|
logger.warning(
|
||||||
|
text=f"Нет прав вернуть ник {after}",
|
||||||
|
log_type="PRESENCE",
|
||||||
|
)
|
||||||
|
except discord.HTTPException as e:
|
||||||
|
logger.error(
|
||||||
|
text=f"Ошибка возврата ника {after}: {e!r}",
|
||||||
|
log_type="PRESENCE",
|
||||||
|
)
|
||||||
|
@Cog.listener()
|
||||||
async def on_ready(self) -> None:
|
async def on_ready(self) -> None:
|
||||||
"""
|
"""
|
||||||
Событие запуска бота.
|
Событие запуска бота.
|
||||||
|
|||||||
@@ -41,5 +41,7 @@ class Slash(commands.Cog):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def setup(bot: commands.Bot) -> None:
|
async def setup(bot: commands.Bot) -> None:
|
||||||
await bot.add_cog(Slash(bot))
|
await bot.add_cog(Slash(bot))
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class _Settings(BaseSettings):
|
|||||||
|
|
||||||
WELCOME_CHANNEL_ID: int = 0
|
WELCOME_CHANNEL_ID: int = 0
|
||||||
ADMIN_ROLE_NAME: str = "Администратор"
|
ADMIN_ROLE_NAME: str = "Администратор"
|
||||||
|
AFK_NICKNAME:str ="AFK"
|
||||||
|
|
||||||
WARNINGS_FILE: Path = Path("data/warnings.json")
|
WARNINGS_FILE: Path = Path("data/warnings.json")
|
||||||
REMINDERS_FILE: Path = Path("data/reminders.json")
|
REMINDERS_FILE: Path = Path("data/reminders.json")
|
||||||
@@ -53,6 +54,13 @@ class _Settings(BaseSettings):
|
|||||||
raise ValueError(f"LOG_LEVEL должен быть одним из: {', '.join(allowed)}")
|
raise ValueError(f"LOG_LEVEL должен быть одним из: {', '.join(allowed)}")
|
||||||
return v.lower()
|
return v.lower()
|
||||||
|
|
||||||
|
@field_validator("AFK_NICKNAME")
|
||||||
|
def validate_afk_nickname(cls, v: str) -> str:
|
||||||
|
# если пустая строка или None, используем дефолт "AFK"
|
||||||
|
if not v or not v.strip():
|
||||||
|
return "AFK"
|
||||||
|
return v.strip()
|
||||||
|
|
||||||
@field_validator("WARNINGS_FILE", "REMINDERS_FILE", "BLACKLIST_FILE", "LOG_FILE_NAME", mode="before")
|
@field_validator("WARNINGS_FILE", "REMINDERS_FILE", "BLACKLIST_FILE", "LOG_FILE_NAME", mode="before")
|
||||||
def validate_paths(cls, v) -> Optional[Path]:
|
def validate_paths(cls, v) -> Optional[Path]:
|
||||||
return Path(v) if isinstance(v, str) else v
|
return Path(v) if isinstance(v, str) else v
|
||||||
|
|||||||
Reference in New Issue
Block a user