fix lock and lockdown cogs

This commit is contained in:
Zeva Rose 2022-03-23 01:23:47 -06:00
parent 54dd6f40a8
commit e80afc97ad
2 changed files with 252 additions and 190 deletions

View file

@ -1,113 +1,117 @@
"""J.A.R.V.I.S. LockCog.""" """J.A.R.V.I.S. LockCog."""
# from dis_snek import Scale from typing import Union
#
# # TODO: Uncomment 99% of code once implementation is figured out from dis_snek import InteractionContext, Scale
# from contextlib import suppress from dis_snek.client.utils.misc_utils import get
# from typing import Union from dis_snek.models.discord.channel import GuildText, GuildVoice
# from dis_snek.models.discord.enums import Permissions
# from dis_snek import InteractionContext, Scale, Snake from dis_snek.models.snek.application_commands import (
# from dis_snek.models.discord.enums import Permissions OptionTypes,
# from dis_snek.models.discord.role import Role slash_command,
# from dis_snek.models.discord.user import User slash_option,
# from dis_snek.models.discord.channel import GuildText, GuildVoice, PermissionOverwrite )
# from dis_snek.models.snek.application_commands import ( from dis_snek.models.snek.command import check
# OptionTypes, from jarvis_core.db import q
# PermissionTypes, from jarvis_core.db.models import Lock, Permission
# slash_command,
# slash_option, from jarvis.utils.permissions import admin_or_permissions
# )
# from dis_snek.models.snek.command import check
# class LockCog(Scale):
# from jarvis.db.models import Lock """J.A.R.V.I.S. LockCog."""
# from jarvis.utils.permissions import admin_or_permissions
# @slash_command(name="lock", description="Lock a channel")
# @slash_option(
# class LockCog(Scale): name="reason",
# """J.A.R.V.I.S. LockCog.""" description="Lock Reason",
# opt_type=3,
# @slash_command(name="lock", description="Lock a channel") required=True,
# @slash_option(name="reason", )
# description="Lock Reason", @slash_option(
# opt_type=3, name="duration",
# required=True,) description="Lock duration in minutes (default 10)",
# @slash_option(name="duration", opt_type=4,
# description="Lock duration in minutes (default 10)", required=False,
# opt_type=4, )
# required=False,) @slash_option(
# @slash_option(name="channel", name="channel",
# description="Channel to lock", description="Channel to lock",
# opt_type=7, opt_type=7,
# required=False,) required=False,
# @check(admin_or_permissions(Permissions.MANAGE_CHANNELS)) )
# async def _lock( @check(admin_or_permissions(Permissions.MANAGE_CHANNELS))
# self, async def _lock(
# ctx: InteractionContext, self,
# reason: str, ctx: InteractionContext,
# duration: int = 10, reason: str,
# channel: Union[GuildText, GuildVoice] = None, duration: int = 10,
# ) -> None: channel: Union[GuildText, GuildVoice] = None,
# await ctx.defer(ephemeral=True) ) -> None:
# if duration <= 0: await ctx.defer(ephemeral=True)
# await ctx.send("Duration must be > 0", ephemeral=True) if duration <= 0:
# return await ctx.send("Duration must be > 0", ephemeral=True)
# return
# elif duration > 60 * 12:
# await ctx.send("Duration must be <= 12 hours", ephemeral=True) elif duration > 60 * 12:
# return await ctx.send("Duration must be <= 12 hours", ephemeral=True)
# return
# if len(reason) > 100:
# await ctx.send("Reason must be <= 100 characters", ephemeral=True) if len(reason) > 100:
# return await ctx.send("Reason must be <= 100 characters", ephemeral=True)
# if not channel: return
# channel = ctx.channel if not channel:
# channel = ctx.channel
# # role = ctx.guild.default_role # Uncomment once implemented
# if isinstance(channel, GuildText): # role = ctx.guild.default_role # Uncomment once implemented
# to_deny = Permissions.SEND_MESSAGES if isinstance(channel, GuildText):
# elif isinstance(channel, GuildVoice): to_deny = Permissions.SEND_MESSAGES
# to_deny = Permissions.CONNECT | Permissions.SPEAK elif isinstance(channel, GuildVoice):
# to_deny = Permissions.CONNECT | Permissions.SPEAK
# overwrite = PermissionOverwrite(type=PermissionTypes.ROLE, deny=to_deny)
# # TODO: Get original permissions current = get(channel.permission_overwrites, id=ctx.guild.id)
# # TODO: Apply overwrite if current:
# overwrite = overwrite current = Permission(id=ctx.guild.id, allow=int(current.allow), deny=int(current.deny))
# _ = Lock( role = await ctx.guild.fetch_role(ctx.guild.id)
# channel=channel.id,
# guild=ctx.guild.id, await channel.add_permission(target=role, deny=to_deny, reason="Locked")
# admin=ctx.author.id, await Lock(
# reason=reason, channel=channel.id,
# duration=duration, guild=ctx.guild.id,
# ) # .save() # Uncomment once implemented admin=ctx.author.id,
# # await ctx.send(f"{channel.mention} locked for {duration} minute(s)") reason=reason,
# await ctx.send("Unfortunately, this is not yet implemented", hidden=True) duration=duration,
# original_perms=current,
# @cog_ext.cog_slash( ).commit()
# name="unlock", await ctx.send(f"{channel.mention} locked for {duration} minute(s)")
# description="Unlocks a channel",
# choices=[ @slash_command(name="unlock", description="Unlock a channel")
# create_option( @slash_option(
# name="channel", name="channel",
# description="Channel to lock", description="Channel to unlock",
# opt_type=7, opt_type=OptionTypes.CHANNEL,
# required=False, required=False,
# ), )
# ], @check(admin_or_permissions(Permissions.MANAGE_CHANNELS))
# ) async def _unlock(
# @check(admin_or_permissions(Permissions.MANAGE_CHANNELS)) self,
# async def _unlock( ctx: InteractionContext,
# self, channel: Union[GuildText, GuildVoice] = None,
# ctx: InteractionContext, ) -> None:
# channel: Union[GuildText, GuildVoice] = None, if not channel:
# ) -> None: channel = ctx.channel
# if not channel: lock = await Lock.find_one(q(guild=ctx.guild.id, channel=channel.id, active=True))
# channel = ctx.channel if not lock:
# lock = Lock.objects(guild=ctx.guild.id, channel=channel.id, active=True).first() await ctx.send(f"{channel.mention} not locked.", ephemeral=True)
# if not lock: return
# await ctx.send(f"{channel.mention} not locked.", ephemeral=True)
# return overwrite = get(channel.permission_overwrites, id=ctx.guild.id)
# for role in ctx.guild.roles: if overwrite and lock.original_perms:
# with suppress(Exception): overwrite.allow = lock.original_perms.allow
# await self._unlock_channel(channel, role, ctx.author) overwrite.deny = lock.original_perms.deny
# lock.active = False await channel.edit_permission(overwrite, reason="Unlock")
# lock.save() elif overwrite and not lock.original_perms:
# await ctx.send(f"{channel.mention} unlocked") await channel.delete_permission(target=overwrite, reason="Unlock")
lock.active = False
await lock.commit()
await ctx.send(f"{channel.mention} unlocked")

View file

@ -1,101 +1,159 @@
"""J.A.R.V.I.S. LockdownCog.""" """J.A.R.V.I.S. LockdownCog."""
from contextlib import suppress from dis_snek import InteractionContext, Scale, Snake
from datetime import datetime from dis_snek.client.utils.misc_utils import find_all, get
from dis_snek.models.discord.channel import GuildCategory, GuildChannel
from discord.ext import commands from dis_snek.models.discord.enums import Permissions
from discord_slash import SlashContext, cog_ext from dis_snek.models.discord.guild import Guild
from discord_slash.utils.manage_commands import create_option from dis_snek.models.discord.user import Member
from dis_snek.models.snek.application_commands import (
from jarvis.db.models import Lock OptionTypes,
from jarvis.utils.cachecog import CacheCog slash_command,
slash_option,
# from jarvis.utils.permissions import admin_or_permissions
class LockdownCog(CacheCog):
"""J.A.R.V.I.S. LockdownCog."""
def __init__(self, bot: commands.Bot):
super().__init__(bot)
@cog_ext.cog_subcommand(
base="lockdown",
name="start",
description="Locks a server",
choices=[
create_option(
name="reason",
description="Lockdown Reason",
opt_type=3,
required=True,
),
create_option(
name="duration",
description="Lockdown duration in minutes (default 10)",
opt_type=4,
required=False,
),
],
) )
# @check(admin_or_permissions(manage_channels=True)) from dis_snek.models.snek.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Lock, Lockdown, Permission
from jarvis.utils.permissions import admin_or_permissions
async def lock(bot: Snake, target: GuildChannel, admin: Member, reason: str, duration: int) -> None:
"""
Lock an existing channel
Args:
bot: Bot instance
target: Target channel
admin: Admin who initiated lockdown
"""
to_deny = Permissions.SEND_MESSAGES | Permissions.CONNECT | Permissions.SPEAK
current = get(target.permission_overwrites, id=target.guild.id)
if current:
current = Permission(id=target.guild.id, allow=int(current.allow), deny=int(current.deny))
role = await target.guild.fetch_role(target.guild.id)
await target.add_permission(target=role, deny=to_deny, reason="Lockdown")
await Lock(
channel=target.id,
guild=target.guild.id,
admin=admin.id,
reason=reason,
duration=duration,
original_perms=current,
).commit()
async def lock_all(bot: Snake, guild: Guild, admin: Member, reason: str, duration: int) -> None:
"""
Lock all channels
Args:
bot: Bot instance
guild: Target guild
admin: Admin who initiated lockdown
"""
role = await guild.fetch_role(guild.id)
categories = find_all(lambda x: isinstance(x, GuildCategory), guild.channels)
for category in categories:
await lock(bot, category, admin, reason, duration)
perms = category.permissions_for(role)
for channel in category.channels:
if perms != channel.permissions_for(role):
await lock(bot, channel, admin, reason, duration)
async def unlock_all(bot: Snake, guild: Guild, admin: Member) -> None:
"""
Unlock all locked channels
Args:
bot: Bot instance
target: Target channel
admin: Admin who ended lockdown
"""
locks = Lock.find(q(guild=guild.id, active=True))
async for lock in locks:
target = await guild.fetch_channel(lock.channel)
if target:
overwrite = get(target.permission_overwrites, id=guild.id)
if overwrite and lock.original_perms:
overwrite.allow = lock.original_perms.allow
overwrite.deny = lock.original_perms.deny
await target.edit_permission(overwrite, reason="Lockdown end")
elif overwrite and not lock.original_perms:
await target.delete_permission(target=overwrite, reason="Lockdown end")
lock.active = False
await lock.commit()
lockdown = await Lockdown.find_one(q(guild=guild.id, active=True))
if lockdown:
lockdown.active = False
await lockdown.commit()
class LockdownCog(Scale):
"""J.A.R.V.I.S. LockdownCog."""
@slash_command(
name="lockdown",
description="Manage server-wide lockdown",
sub_cmd_name="start",
sub_cmd_description="Lockdown the server",
)
@slash_option(
name="reason", description="Lockdown reason", opt_type=OptionTypes.STRING, required=True
)
@slash_option(
name="duration",
description="Duration in minutes",
opt_type=OptionTypes.INTEGER,
required=False,
)
@check(admin_or_permissions(Permissions.MANAGE_CHANNELS))
async def _lockdown_start( async def _lockdown_start(
self, self,
ctx: SlashContext, ctx: InteractionContext,
reason: str, reason: str,
duration: int = 10, duration: int = 10,
) -> None: ) -> None:
await ctx.defer(ephemeral=True) await ctx.defer()
if duration <= 0: if duration <= 0:
await ctx.send("Duration must be > 0", ephemeral=True) await ctx.send("Duration must be > 0", ephemeral=True)
return return
elif duration >= 300: elif duration >= 300:
await ctx.send("Duration must be < 5 hours", ephemeral=True) await ctx.send("Duration must be < 5 hours", ephemeral=True)
return return
channels = ctx.guild.channels
roles = ctx.guild.roles
updates = []
for channel in channels:
for role in roles:
with suppress(Exception):
await self._lock_channel(channel, role, ctx.author, reason)
updates.append(
Lock(
channel=channel.id,
guild=ctx.guild.id,
admin=ctx.author.id,
reason=reason,
duration=duration,
active=True,
created_at=datetime.utcnow(),
)
)
if updates:
Lock.objects().insert(updates)
await ctx.send(f"Server locked for {duration} minute(s)")
@cog_ext.cog_subcommand( exists = await Lockdown.find_one(q(guild=ctx.guild.id, active=True))
base="lockdown", if exists:
name="end", await ctx.send("Server already in lockdown", ephemeral=True)
description="Unlocks a server", return
)
@commands.has_permissions(administrator=True) await lock_all(self.bot, ctx.guild, ctx.author, reason, duration)
role = await ctx.guild.fetch_role(ctx.guild.id)
original_perms = role.permissions
new_perms = role.permissions & ~Permissions.SEND_MESSAGES
await role.edit(permissions=new_perms)
await Lockdown(
admin=ctx.author.id,
duration=duration,
guild=ctx.guild.id,
reason=reason,
original_perms=int(original_perms),
).commit()
await ctx.send("Server now in lockdown.")
@slash_command(name="lockdown", sub_cmd_name="end", sub_cmd_description="End a lockdown")
@check(admin_or_permissions(Permissions.MANAGE_CHANNELS))
async def _lockdown_end( async def _lockdown_end(
self, self,
ctx: SlashContext, ctx: InteractionContext,
) -> None: ) -> None:
channels = ctx.guild.channels
roles = ctx.guild.roles
update = False
locks = Lock.objects(guild=ctx.guild.id, active=True)
if not locks:
await ctx.send("No lockdown detected.", ephemeral=True)
return
await ctx.defer() await ctx.defer()
for channel in channels:
for role in roles: lockdown = await Lockdown.find_one(q(guild=ctx.guild.id, active=True))
with suppress(Exception): if not lockdown:
await self._unlock_channel(channel, role, ctx.author) await ctx.send("Server not in lockdown", ephemeral=True)
update = True return
if update:
Lock.objects(guild=ctx.guild.id, active=True).update(set__active=False) await unlock_all(self.bot, ctx.guild, ctx.author)
await ctx.send("Server unlocked") await ctx.send("Server no longer in lockdown.")