Skip to content

Commit

Permalink
[adminutils] add support for 3.5
Browse files Browse the repository at this point in the history
  • Loading branch information
fixator10 committed Jun 1, 2023
1 parent b147a06 commit 27d0288
Show file tree
Hide file tree
Showing 5 changed files with 394 additions and 249 deletions.
4 changes: 2 additions & 2 deletions adminutils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ async def setup_after_ready(bot):
for alias in command.aliases:
if bot.get_command(alias):
command.aliases[command.aliases.index(alias)] = f"a{alias}"
bot.add_cog(cog)
await bot.add_cog(cog)


def setup(bot):
async def setup(bot):
create_task(setup_after_ready(bot))
149 changes: 94 additions & 55 deletions adminutils/adminutils.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,60 @@
import contextlib
import re
from asyncio import TimeoutError as AsyncTimeoutError
from random import choice
from typing import Optional, Union
from typing import Literal, Optional, Union

import aiohttp
import discord
from red_commons.logging import getLogger
from redbot.core import commands
from redbot.core.i18n import Translator, cog_i18n
from redbot.core.utils import chat_formatting as chat
from redbot.core.utils.mod import get_audit_reason
from redbot.core.utils.predicates import MessagePredicate

try:
from redbot import json # support of Draper's branch
except ImportError:
import json

_ = Translator("AdminUtils", __file__)

EMOJI_RE = re.compile(r"(<(a)?:[a-zA-Z0-9_]+:([0-9]+)>)")

CHANNEL_REASONS = {
discord.CategoryChannel: _("You are not allowed to edit this category."),
discord.TextChannel: _("You are not allowed to edit this channel."),
discord.VoiceChannel: _("You are not allowed to edit this channel."),
discord.StageChannel: _("You are not allowed to edit this channel."),
}


async def check_regions(ctx):
"""Check if regions list is populated"""
return ctx.cog.regions


@cog_i18n(_)
class AdminUtils(commands.Cog):
"""Useful commands for server administrators."""

__version__ = "2.5.11"
__version__ = "3.0.0"

# noinspection PyMissingConstructor
def __init__(self, bot):
self.bot = bot
self.session = aiohttp.ClientSession(json_serialize=json.dumps)
self.session = aiohttp.ClientSession()
self.log = getLogger("red.fixator10-cogs.adminutils")
self.regions = []

async def cog_load(self):
try:
regions = await self.bot.http.request(discord.http.Route("GET", "/voice/regions"))
self.regions = [region["id"] for region in regions]
except Exception as e:
self.log.warning(
"Unable to get list of rtc_regions. [p]restartvoice command will be unavailable",
exc_info=e,
)

def cog_unload(self):
self.bot.loop.create_task(self.session.close())
async def cog_unload(self):
await self.session.close()

def format_help_for_context(self, ctx: commands.Context) -> str: # Thanks Sinbad!
pre_processed = super().format_help_for_context(ctx)
Expand All @@ -45,20 +66,19 @@ async def red_delete_data_for_user(self, **kwargs):
@staticmethod
def check_channel_permission(
ctx: commands.Context,
channel_or_category: Union[discord.TextChannel, discord.CategoryChannel],
channel_or_category: Union[
discord.TextChannel,
discord.CategoryChannel,
discord.VoiceChannel,
discord.StageChannel,
],
) -> bool:
"""
Check user's permission in a channel, to be sure he can edit it.
"""
mc = channel_or_category.permissions_for(ctx.author).manage_channels
if mc:
if channel_or_category.permissions_for(ctx.author).manage_channels:
return True
reason = (
_("You are not allowed to edit this channel.")
if not isinstance(channel_or_category, discord.CategoryChannel)
else _("You are not allowed to edit in this category.")
)
raise commands.UserFeedbackCheckFailure(reason)
raise commands.UserFeedbackCheckFailure(CHANNEL_REASONS.get(type(channel_or_category)))

@commands.command(name="prune")
@commands.guild_only()
Expand Down Expand Up @@ -92,10 +112,8 @@ async def cleanup_users(self, ctx, days: Optional[int] = 1, *roles: discord.Role
).format(to_kick=to_kick, days=days, roles=roles_text if roles else "")
)
)
try:
with contextlib.suppress(AsyncTimeoutError):
await self.bot.wait_for("message", check=pred, timeout=30)
except AsyncTimeoutError:
pass
if ctx.assume_yes or pred.result:
cleanup = await ctx.guild.prune_members(
days=days, reason=get_audit_reason(ctx.author), roles=roles or None
Expand All @@ -113,23 +131,20 @@ async def cleanup_users(self, ctx, days: Optional[int] = 1, *roles: discord.Role

@commands.command()
@commands.guild_only()
@commands.admin_or_permissions(manage_guild=True)
@commands.bot_has_permissions(manage_guild=True)
async def restartvoice(self, ctx: commands.Context):
"""Change server's voice region to random and back
@commands.check(check_regions)
@commands.admin_or_permissions(manage_channels=True)
@commands.bot_has_permissions(manage_channels=True)
async def restartvoice(
self, ctx: commands.Context, channel: Union[discord.VoiceChannel, discord.StageChannel]
):
"""Change voice channel's region to random and back
Useful to reinitate all voice connections"""
current_region = ctx.guild.region
random_region = choice(
[
r
for r in discord.VoiceRegion
if not r.value.startswith("vip") and current_region != r
]
)
await ctx.guild.edit(region=random_region)
await ctx.guild.edit(
region=current_region,
current_region = channel.rtc_region
random_region = choice([r for r in self.regions if current_region != r])
await channel.edit(rtc_region=random_region)
await channel.edit(
rtc_region=current_region,
reason=get_audit_reason(ctx.author, _("Voice restart")),
)
await ctx.tick()
Expand All @@ -142,8 +157,8 @@ async def restartvoice(self, ctx: commands.Context):
async def massmove(
self,
ctx: commands.Context,
from_channel: discord.VoiceChannel,
to_channel: discord.VoiceChannel = None,
from_channel: Union[discord.VoiceChannel, discord.StageChannel],
to_channel: Union[discord.VoiceChannel, discord.StageChannel] = None,
):
"""Move all members from one voice channel to another
Expand Down Expand Up @@ -171,6 +186,7 @@ async def massmove(
continue
await ctx.send(_("Finished moving users. {} members could not be moved.").format(fails))

# TODO: Stickers?
@commands.group()
@commands.guild_only()
@commands.admin_or_permissions(manage_emojis=True)
Expand Down Expand Up @@ -207,8 +223,6 @@ async def emoji_add(self, ctx, name: str, url: str, *roles: discord.Role):
else None,
),
)
except discord.InvalidArgument:
await ctx.send(chat.error(_("This image type is unsupported, or link is incorrect")))
except discord.HTTPException as e:
await ctx.send(chat.error(_("An error occurred on adding an emoji: {}").format(e)))
else:
Expand Down Expand Up @@ -251,13 +265,6 @@ async def emote_steal(
),
)
await ctx.tick()
except discord.InvalidArgument:
await ctx.send(
_(
"This image type is not supported anymore or Discord returned incorrect data. Try again later."
)
)
return
except discord.HTTPException as e:
await ctx.send(chat.error(_("An error occurred on adding an emoji: {}").format(e)))

Expand Down Expand Up @@ -301,6 +308,7 @@ async def emoji_remove(self, ctx: commands.Context, *, emoji: discord.Emoji):
await emoji.delete(reason=get_audit_reason(ctx.author))
await ctx.tick()

# TODO: Threads?
@commands.group()
@commands.guild_only()
@commands.admin_or_permissions(manage_channels=True)
Expand Down Expand Up @@ -360,8 +368,8 @@ async def channel_create_voice(
Use double quotes if category has spaces
Examples:
`[p]channel add voice "The Zoo" Awesome Channel` will create under the "The Zoo" category.
`[p]channel add voice Awesome Channel` will create under no category, at the top.
`[p]channel add voice "The Zoo" Awesome Channel` will create voice channel under the "The Zoo" category.
`[p]channel add voice Awesome Channel` will create stage channel under no category, at the top.
"""
if category:
self.check_channel_permission(ctx, category)
Expand All @@ -376,11 +384,41 @@ async def channel_create_voice(
else:
await ctx.tick()

@channel_create.command(name="stage")
async def channel_create_stage(
self,
ctx: commands.Context,
category: Optional[discord.CategoryChannel] = None,
*,
name: str,
):
"""Create a stage channel
You can create the channel under a category if passed, else it is created under no category
Use double quotes if category has spaces
Examples:
`[p]channel add voice "The Zoo" Awesome Channel` will create voice channel under the "The Zoo" category.
`[p]channel add voice Awesome Channel` will create stage channel under no category, at the top.
"""
if category:
self.check_channel_permission(ctx, category)
try:
await ctx.guild.create_stage_channel(
name, category=category, reason=get_audit_reason(ctx.author)
)
except discord.Forbidden:
await ctx.send(chat.error(_("I can't create channel in this category")))
except discord.HTTPException as e:
await ctx.send(chat.error(_("I am unable to create a channel: {}").format(e)))
else:
await ctx.tick()

@channel.command(name="rename")
async def channel_rename(
self,
ctx: commands.Context,
channel: Union[discord.TextChannel, discord.VoiceChannel],
channel: Union[discord.TextChannel, discord.VoiceChannel, discord.StageChannel],
*,
name: str,
):
Expand All @@ -403,7 +441,10 @@ async def channel_rename(

@channel.command(name="delete", aliases=["remove"])
async def channel_delete(
self, ctx: commands.Context, *, channel: Union[discord.TextChannel, discord.VoiceChannel]
self,
ctx: commands.Context,
*,
channel: Union[discord.TextChannel, discord.VoiceChannel, discord.StageChannel],
):
"""Remove a channel from server
Expand All @@ -421,10 +462,8 @@ async def channel_delete(
).format(channel=channel.mention)
)
)
try:
with contextlib.suppress(AsyncTimeoutError):
await self.bot.wait_for("message", check=pred, timeout=30)
except AsyncTimeoutError:
pass
if ctx.assume_yes or pred.result:
try:
await channel.delete(reason=get_audit_reason(ctx.author))
Expand Down
1 change: 0 additions & 1 deletion adminutils/info.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"short": "Useful commands for server administrators.",
"description": "Useful commands for server administrators.",
"min_bot_version": "3.4.0",
"max_bot_version": "3.4.99",
"tags": [
"admin",
"emoji",
Expand Down
Loading

0 comments on commit 27d0288

Please sign in to comment.