2018-03-31 16:36:30 -04:00
import asyncio
import traceback as tb
from contextlib import suppress
from datetime import datetime as dt
import discord as d
from discord import errors as err
from discord . ext import commands as cmds
from discord . ext . commands import errors as errext
from misc import exceptions as exc
from misc import checks
from utils import utils as u
class Administration :
def __init__ ( self , bot ) :
self . bot = bot
self . queue = asyncio . Queue ( )
self . deleting = False
if u . tasks [ ' auto_del ' ] :
for channel in u . tasks [ ' auto_del ' ] :
temp = self . bot . get_channel ( channel )
self . bot . loop . create_task ( self . queue_for_deletion ( temp ) )
print ( ' STARTED : auto-deleting in # {} ' . format ( temp . name ) )
self . deleting = True
self . bot . loop . create_task ( self . delete ( ) )
@cmds.group ( aliases = [ ' pru ' , ' purge ' , ' pur ' , ' clear ' , ' cl ' ] , hidden = True )
@cmds.is_owner ( )
async def prune ( self , ctx ) :
pass
@prune.group ( name = ' user ' , aliases = [ ' u ' , ' member ' , ' m ' ] )
async def _prune_user ( self , ctx ) :
pass
@_prune_user.command ( name = ' channel ' , aliases = [ ' channels ' , ' chans ' , ' chan ' , ' ch ' , ' c ' ] )
async def _prune_user_channel ( self , ctx , user : d . User , * channels : d . TextChannel ) :
def confirm ( r , u ) :
if u is ctx . author :
if r . emoji == ' \N{OCTAGONAL SIGN} ' :
raise exc . Abort
if r . emoji == ' \N{THUMBS UP SIGN} ' :
return True
return False
if not channels :
channels = [ ctx . channel ]
try :
pruning = await ctx . send ( f ' \N{HOURGLASS} **Pruning** { user . mention } ** \' s messages from** { " **,** " . join ( [ channel . mention for channel in channels ] ) } **might take some time.** Proceed, { ctx . author . mention } ? ' )
await pruning . add_reaction ( ' \N{THUMBS UP SIGN} ' )
await pruning . add_reaction ( ' \N{OCTAGONAL SIGN} ' )
await asyncio . sleep ( 1 )
await self . bot . wait_for ( ' reaction_add ' , check = confirm , timeout = 10 * 60 )
deleting = await ctx . send ( f ' \N{WASTEBASKET} **Deleting** { user . mention } ** \' s messages...** ' )
await asyncio . sleep ( 1 )
c = 0
for channel in channels :
await deleting . edit ( content = f ' \N{WASTEBASKET} **Deleting** { user . mention } ** \' s messages from** { channel . mention } ' )
deleted = await channel . purge ( check = lambda m : m . author . id == user . id , before = pruning , limit = None )
c + = len ( deleted )
await asyncio . sleep ( 1 )
for channel in channels :
missed = 0
async for message in channel . history ( before = pruning , limit = None ) :
if message . author . id == user . id :
missed + = 1
if missed > 0 :
await ctx . send ( f ' \N{DOUBLE EXCLAMATION MARK} ` { missed } ` **messages were not deleted in** { channel . mention } ' )
await ctx . send ( f ' \N{WHITE HEAVY CHECK MARK} **Finished deleting** ` { c } ` **of** { user . mention } ** \' s messages** ' )
except exc . Abort :
2018-11-06 02:55:08 -05:00
await ctx . send ( ' **Deletion aborted** ' )
2018-03-31 16:36:30 -04:00
await ctx . message . add_reaction ( ' \N{CROSS MARK} ' )
except TimeoutError :
2018-11-06 02:55:08 -05:00
await ctx . send ( ' **Deletion timed out** ' )
2018-03-31 16:36:30 -04:00
await ctx . message . add_reaction ( ' \N{CROSS MARK} ' )
@_prune_user.command ( name = ' all ' , aliases = [ ' a ' ] , brief = ' Prune a user \' s messages from the guild ' , description = ' about flag centers on message 50 of 101 messages \n \n pfg \ { user id \ } [before|after|about] [ \ { message id \ }] \n \n Example: \n pfg \ { user id \ } before \ { message id \ } ' , hidden = True )
@cmds.is_owner ( )
async def _prune_user_all ( self , ctx , user : d . User ) :
def confirm ( r , u ) :
if u is ctx . author :
if r . emoji == ' \N{OCTAGONAL SIGN} ' :
raise exc . Abort
if r . emoji == ' \N{THUMBS UP SIGN} ' :
return True
return False
try :
pruning = await ctx . send ( f ' \N{HOURGLASS} **Pruning** { user . mention } ** \' s messages might take some time.** Proceed, { ctx . author . mention } ? ' )
await pruning . add_reaction ( ' \N{THUMBS UP SIGN} ' )
await pruning . add_reaction ( ' \N{OCTAGONAL SIGN} ' )
await asyncio . sleep ( 1 )
await self . bot . wait_for ( ' reaction_add ' , check = confirm , timeout = 10 * 60 )
deleting = await ctx . send ( f ' \N{WASTEBASKET} **Deleting** { user . mention } ** \' s messages...** ' )
await asyncio . sleep ( 1 )
c = 0
for channel in ctx . guild . text_channels :
await deleting . edit ( content = f ' \N{WASTEBASKET} **Deleting** { user . mention } ** \' s messages from** { channel . mention } ' )
deleted = await channel . purge ( check = lambda m : m . author . id == user . id , before = pruning , limit = None )
c + = len ( deleted )
await asyncio . sleep ( 1 )
for channel in ctx . guild . text_channels :
missed = 0
async for message in channel . history ( before = pruning , limit = None ) :
if message . author . id == user . id :
missed + = 1
if missed > 0 :
await ctx . send ( f ' \N{DOUBLE EXCLAMATION MARK} ` { missed } ` **messages were not deleted in** { channel . mention } ' )
await ctx . send ( f ' \N{WHITE HEAVY CHECK MARK} **Finished deleting** ` { c } ` **of** { user . mention } ** \' s messages** ' )
except exc . Abort :
2018-11-06 02:55:08 -05:00
await ctx . send ( ' **Deletion aborted** ' )
2018-03-31 16:36:30 -04:00
await ctx . message . add_reaction ( ' \N{CROSS MARK} ' )
except TimeoutError :
2018-11-06 02:55:08 -05:00
await ctx . send ( ' **Deletion timed out** ' )
2018-03-31 16:36:30 -04:00
await ctx . message . add_reaction ( ' \N{CROSS MARK} ' )
@cmds.group ( aliases = [ ' task ' , ' tsk ' ] )
async def tasks ( self ) :
pass
async def delete ( self ) :
while self . deleting :
message = await self . queue . get ( )
with suppress ( err . NotFound ) :
if not message . pinned :
await message . delete ( )
print ( ' STOPPED : deleting ' )
async def queue_for_deletion ( self , channel ) :
def check ( msg ) :
if ' stop d ' in msg . content . lower ( ) and msg . channel is channel and msg . author . guild_permissions . administrator :
raise exc . Abort
elif msg . channel is channel and not msg . pinned :
return True
return False
try :
async for message in channel . history ( limit = None ) :
if ' stop d ' in message . content . lower ( ) and message . author . guild_permissions . administrator :
raise exc . Abort
if not message . pinned :
await self . queue . put ( message )
while not self . bot . is_closed ( ) :
message = await self . bot . wait_for ( ' message ' , check = check )
await self . queue . put ( message )
except exc . Abort :
u . tasks [ ' auto_del ' ] . remove ( channel . id )
u . dump ( u . tasks , ' cogs/tasks.pkl ' )
if not u . tasks [ ' auto_del ' ] :
self . deleting = False
print ( ' STOPPED : deleting # {} ' . format ( channel . name ) )
2018-11-06 02:55:08 -05:00
await channel . send ( ' **Stopped queueing messages for deletion in** {} ' . format ( channel . mention ) )
2018-03-31 16:36:30 -04:00
@cmds.command ( name = ' autodelete ' , aliases = [ ' autodel ' ] )
@cmds.has_permissions ( administrator = True )
async def auto_delete ( self , ctx ) :
try :
if ctx . channel . id not in u . tasks [ ' auto_del ' ] :
u . tasks [ ' auto_del ' ] . append ( ctx . channel . id )
u . dump ( u . tasks , ' cogs/tasks.pkl ' )
self . bot . loop . create_task ( self . queue_for_deletion ( ctx . channel ) )
if not self . deleting :
self . bot . loop . create_task ( self . delete ( ) )
self . deleting = True
print ( ' STARTED : auto-deleting in # {} ' . format ( ctx . channel . name ) )
2018-11-06 02:55:08 -05:00
await ctx . send ( ' **Auto-deleting all messages in {} ** ' . format ( ctx . channel . mention ) )
2018-03-31 16:36:30 -04:00
else :
raise exc . Exists
except exc . Exists :
2018-11-06 02:55:08 -05:00
await ctx . send ( ' **Already auto-deleting in {} .** Type `stop d(eleting)` to stop. ' . format ( ctx . channel . mention ) )
2018-03-31 16:36:30 -04:00
await ctx . message . add_reaction ( ' \N{CROSS MARK} ' )
@cmds.group ( aliases = [ ' setting ' , ' set ' , ' s ' ] )
@cmds.has_permissions ( administrator = True )
async def settings ( self , ctx ) :
pass
@settings.command ( name = ' deletecommands ' , aliases = [ ' delcmds ' , ' delcmd ' ] )
async def _settings_deletecommands ( self , ctx ) :
if ctx . guild . id not in u . settings [ ' del_ctx ' ] :
u . settings [ ' del_ctx ' ] . append ( ctx . guild . id )
else :
u . settings [ ' del_ctx ' ] . remove ( ctx . guild . id )
u . dump ( u . settings , ' settings.pkl ' )
await ctx . send ( ' **Delete command invocations:** ` {} ` ' . format ( ctx . guild . id in u . settings [ ' del_ctx ' ] ) )
@settings.command ( name = ' prefix ' , aliases = [ ' pre ' , ' p ' ] )
async def _settings_prefix ( self , ctx , * prefixes ) :
if prefixes :
u . settings [ ' prefixes ' ] [ ctx . guild . id ] = prefixes
else :
with suppress ( KeyError ) :
del u . settings [ ' prefixes ' ] [ ctx . guild . id ]
await ctx . send ( f ' **Prefix set to:** ` { " ` or ` " . join ( prefixes if ctx . guild . id in u . settings [ " prefixes " ] else u . config [ " prefix " ] ) } ` ' )
@settings.command ( name = ' deleteresponses ' , aliases = [ ' delresps ' , ' delresp ' ] )
async def _settings_deleteresponses ( self , ctx ) :
if ctx . guild . id not in u . settings [ ' del_resp ' ] :
u . settings [ ' del_resp ' ] . append ( ctx . guild . id )
else :
u . settings [ ' del_resp ' ] . remove ( ctx . guild . id )
u . dump ( u . settings , ' settings.pkl ' )
await ctx . send ( f ' **Delete command responses:** ` { ctx . guild . id in u . settings [ " del_resp " ] } ` ' )