Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add reroll command. #1568

Merged
merged 19 commits into from
Jun 13, 2022
Merged
Changes from 15 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 162 additions & 18 deletions bot/exts/fun/off_topic_names.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
import asyncio
import difflib
import json
import random
from datetime import timedelta
from functools import partial
from typing import Optional

import arrow
from disnake import Colour, Embed
from disnake import ButtonStyle, Colour, Embed, Interaction
from disnake.ext.commands import Cog, Context, group, has_any_role
from disnake.ui import Button, View
from disnake.utils import sleep_until

from bot.api import ResponseCodeError
from bot.bot import Bot
from bot.constants import Channels, MODERATION_ROLES
from bot.constants import Channels, MODERATION_ROLES, NEGATIVE_REPLIES
from bot.converters import OffTopicName
from bot.log import get_logger
from bot.pagination import LinePaginator
from bot.utils import scheduling

CHANNELS = (Channels.off_topic_0, Channels.off_topic_1, Channels.off_topic_2)

# In case, the off-topic channel name format is modified.
OTN_FORMATTER = "ot{number}-{name}"
OT_NUMBER_INDEX = 2
NAME_START_INDEX = 4

log = get_logger(__name__)


Expand All @@ -32,13 +44,14 @@ async def update_names(bot: Bot) -> None:
'bot/off-topic-channel-names', params={'random_items': 3}
)
except ResponseCodeError as e:
log.error(f"Failed to get new off topic channel names: code {e.response.status}")
log.error(f"Failed to get new off-topic channel names: code {e.response.status}")
continue
channel_0, channel_1, channel_2 = (bot.get_channel(channel_id) for channel_id in CHANNELS)

await channel_0.edit(name=f'ot0-{channel_0_name}')
await channel_1.edit(name=f'ot1-{channel_1_name}')
await channel_2.edit(name=f'ot2-{channel_2_name}')
await channel_0.edit(name=OTN_FORMATTER.format(number=0, name=channel_0_name))
await channel_1.edit(name=OTN_FORMATTER.format(number=1, name=channel_1_name))
await channel_2.edit(name=OTN_FORMATTER.format(number=2, name=channel_2_name))

log.debug(
"Updated off-topic channel names to"
f" {channel_0_name}, {channel_1_name} and {channel_2_name}"
Expand Down Expand Up @@ -66,6 +79,28 @@ async def init_offtopic_updater(self) -> None:
coro = update_names(self.bot)
self.updater_task = scheduling.create_task(coro, event_loop=self.bot.loop)

async def toggle_ot_name_activity(self, ctx: Context, name: str, active: bool) -> None:
"""Toggle active attribute for an off-topic name."""
data = {
"active": active
}
await self.bot.api_client.patch(f"bot/off-topic-channel-names/{name}", data=data)
await ctx.send(f"Off-topic name `{name}` has been {'activated' if active else 'deactivated'}.")

async def list_ot_names(self, ctx: Context, active: bool = True) -> None:
"""Send an embed containing active/deactivated off-topic channel names."""
result = await self.bot.api_client.get('bot/off-topic-channel-names', params={'active': json.dumps(active)})
lines = sorted(f"• {name}" for name in result)
embed = Embed(
title=f"{'Active' if active else 'Deactivated'} off-topic names (`{len(result)}` total)",
colour=Colour.blue()
)
if result:
await LinePaginator.paginate(lines, ctx, embed, max_size=400, empty=False)
else:
embed.description = "Hmmm, seems like there's nothing here yet."
await ctx.send(embed=embed)

@group(name='otname', aliases=('otnames', 'otn'), invoke_without_command=True)
@has_any_role(*MODERATION_ROLES)
async def otname_group(self, ctx: Context) -> None:
Expand Down Expand Up @@ -117,25 +152,134 @@ async def delete_command(self, ctx: Context, *, name: OffTopicName) -> None:
log.info(f"{ctx.author} deleted the off-topic channel name '{name}'")
await ctx.send(f":ok_hand: Removed `{name}` from the names list.")

@otname_group.command(name='list', aliases=('l',))
@otname_group.command(name='activate', aliases=('whitelist',))
@has_any_role(*MODERATION_ROLES)
async def activate_ot_name(self, ctx: Context, name: OffTopicName) -> None:
"""Activate an existing off-topic name."""
await self.toggle_ot_name_activity(ctx, name, True)

@otname_group.command(name='deactivate', aliases=('blacklist',))
@has_any_role(*MODERATION_ROLES)
async def de_activate_ot_name(self, ctx: Context, name: OffTopicName) -> None:
"""Deactivate a specific off-topic name."""
await self.toggle_ot_name_activity(ctx, name, False)

@otname_group.command(name='reroll')
@has_any_role(*MODERATION_ROLES)
async def re_roll_command(self, ctx: Context, ot_channel_index: Optional[int] = None) -> None:
"""
Re-roll an off-topic name for a specific off-topic channel and deactivate the current name.

ot_channel_index: [0, 1, 2, ...]
"""
if ot_channel_index is not None:
try:
channel = self.bot.get_channel(CHANNELS[ot_channel_index])
except IndexError:
await ctx.send(f":x: No off-topic channel found with index {ot_channel_index}.")
return
elif ctx.channel.id in CHANNELS:
channel = ctx.channel

else:
await ctx.send("Please specify channel for which the off-topic name should be re-rolled.")
return

old_channel_name = channel.name
old_ot_name = old_channel_name[NAME_START_INDEX:] # ot1-name-of-ot -> name-of-ot

await self.de_activate_ot_name(ctx, old_ot_name)

response = await self.bot.api_client.get(
'bot/off-topic-channel-names', params={'random_items': 1}
)
try:
new_channel_name = response[0]
except IndexError:
await ctx.send("Out of active off-topic names. Add new names to reroll.")
return

async def rename_channel() -> None:
"""Rename off-topic channel and log events."""
await channel.edit(
name=OTN_FORMATTER.format(number=old_channel_name[OT_NUMBER_INDEX], name=new_channel_name)
)
log.info(
f"{ctx.author} Off-topic channel re-named from `{old_ot_name}` "
f"to `{new_channel_name}`."
)

await ctx.message.reply(
f":ok_hand: Off-topic channel re-named from `{old_ot_name}` "
f"to `{new_channel_name}`. "
)

try:
await asyncio.wait_for(
rename_channel(),
3
)
RohanJnr marked this conversation as resolved.
Show resolved Hide resolved
except asyncio.TimeoutError:
# Channel rename endpoint rate limited. The task was cancelled by asyncio.
btn_yes = Button(label="Yes", style=ButtonStyle.success)
btn_no = Button(label="No", style=ButtonStyle.danger)

embed = Embed(
title=random.choice(NEGATIVE_REPLIES),
description=(
"Re-naming the channel is being rate-limited. "
"Would you like to schedule an asyncio task to rename the channel within the current bot session ?"
),
colour=Colour.blurple()
)

async def btn_call_back(schedule: bool, interaction: Interaction) -> None:
Bluenix2 marked this conversation as resolved.
Show resolved Hide resolved
if ctx.author != interaction.user:
log.info("User is not author, skipping.")
return
message = interaction.message

embed.description = (
"Scheduled a channel re-name process within the current bot session."
if schedule
else
"Channel not re-named due to rate limit. Please try again later."
)
RohanJnr marked this conversation as resolved.
Show resolved Hide resolved
await message.edit(embed=embed, view=None)

if schedule:
await rename_channel()

btn_yes.callback = partial(btn_call_back, True)
btn_no.callback = partial(btn_call_back, False)

view = View()
view.add_item(btn_yes)
view.add_item(btn_no)

await ctx.message.reply(embed=embed, view=view)

@otname_group.group(name='list', aliases=('l',), invoke_without_command=True)
@has_any_role(*MODERATION_ROLES)
async def list_command(self, ctx: Context) -> None:
"""
Lists all currently known off-topic channel names in a paginator.

Restricted to Moderator and above to not spoil the surprise.
"""
result = await self.bot.api_client.get('bot/off-topic-channel-names')
lines = sorted(f"• {name}" for name in result)
embed = Embed(
title=f"Known off-topic names (`{len(result)}` total)",
colour=Colour.blue()
)
if result:
await LinePaginator.paginate(lines, ctx, embed, max_size=400, empty=False)
else:
embed.description = "Hmmm, seems like there's nothing here yet."
await ctx.send(embed=embed)
await self.active_otnames_command(ctx)

@list_command.command(name='active', aliases=('a',))
@has_any_role(*MODERATION_ROLES)
async def active_otnames_command(self, ctx: Context) -> None:
"""List active off-topic channel names."""
await self.list_ot_names(ctx, True)

@list_command.command(name='deactivated', aliases=('d',))
@has_any_role(*MODERATION_ROLES)
async def deactivated_otnames_command(self, ctx: Context) -> None:
"""List deactivated off-topic channel names."""
await self.list_ot_names(ctx, False)

@otname_group.command(name='search', aliases=('s',))
@has_any_role(*MODERATION_ROLES)
Expand Down