Added 'admin' attribute for command decorators to specify an admin-only command. Module commands are assigned in a separate dict within the global module map.
This commit is contained in:
parent
e1fbf0e6ef
commit
7744e6c267
63
bot.py
63
bot.py
|
@ -13,16 +13,17 @@ from protocol import IrcProtocol
|
|||
|
||||
import modules
|
||||
|
||||
# global module map, maps registered functions for each loaded module
|
||||
# global module map, maps registered commands for each loaded module
|
||||
# persists across reloads
|
||||
try: _MOD_MAP
|
||||
except NameError:
|
||||
_MOD_MAP = {}
|
||||
|
||||
def command( name ):
|
||||
def command( name, admin=False ):
|
||||
"""
|
||||
Command registering decorator.
|
||||
Passed name is name of command, decorated function's docstring becomes command's help message.
|
||||
Set admin to True to allow only bot's owner/admins to execute.
|
||||
Function's module name is automatically appended to docstring.
|
||||
Command function gets passed reference to bot instance, array of params, and context info
|
||||
containing the nick that sent, channel it was sent in, and reference to connection object.
|
||||
|
@ -30,16 +31,20 @@ def command( name ):
|
|||
def __deco__( func ):
|
||||
# "fixed" module name. removes top-level 'module' package name
|
||||
mod_name = func.__module__[func.__module__.find( '.' ) + 1: ]
|
||||
logging.info( 'Registering \'%s\' module command: \'%s\' (%s)...',
|
||||
mod_name, name, func.__name__ )
|
||||
if mod_name not in _MOD_MAP.keys():
|
||||
logging.info( 'Registering \'%s\' module commands...', # \'%s\' (%s)...',
|
||||
mod_name ) #, name, func.__name__ )
|
||||
|
||||
# set admin flag if needed
|
||||
if admin: func.__dict__['admin'] = True
|
||||
|
||||
if not func.__doc__: func.__doc__ = 'No help available for command'
|
||||
func.__doc__ += ' (Module: {})'.format( mod_name )
|
||||
func.__doc__ += ' {}(Module: {})'.format( admin and '(Admin-Only) ' or '', mod_name )
|
||||
|
||||
if mod_name not in _MOD_MAP.keys():
|
||||
_MOD_MAP[mod_name] = {}
|
||||
_MOD_MAP[mod_name] = {'cmds':{}}
|
||||
|
||||
_MOD_MAP[mod_name][name.lower()] = func
|
||||
_MOD_MAP[mod_name]['cmds'][name.lower()] = func
|
||||
|
||||
return func #__inner__ # func
|
||||
|
||||
|
@ -80,38 +85,43 @@ class Bot:
|
|||
parms = msg_words[1:]
|
||||
# check if command is in a registered module
|
||||
for k, m in _MOD_MAP.items():
|
||||
if cmd in m.keys():
|
||||
con.log( '::CMD:: \'{}\' run in ({}) by <{}> with parms: {}'.format(
|
||||
cmd, chan, nick, parms ) )
|
||||
if cmd in m['cmds'].keys():
|
||||
cmd_func = m['cmds'][cmd]
|
||||
con.log( '::CMD:: \'{}\' run by <{}> in ({}) with parms: {}'.format(
|
||||
cmd, nick, chan, parms ) )
|
||||
# if msg was sent as pm,
|
||||
# change dst to nick so say_to's can respond in pm
|
||||
if chan == self.cfg['user']['nick']: chan = nick
|
||||
self._loop.create_task( m[cmd](
|
||||
# check for admin
|
||||
if 'admin' in cmd_func.__dict__.keys() and nick != con.cfg['usr']['owner']:
|
||||
con.say_to( chan, '> You do not have permission to execute this command.' )
|
||||
break
|
||||
self._loop.create_task( cmd_func(
|
||||
self, parms, {'con': con,'dst': chan,'nick': nick} ) )
|
||||
break
|
||||
|
||||
# core commands
|
||||
|
||||
# join / part
|
||||
@command( 'join' )
|
||||
@command( 'join', True )
|
||||
async def cmd_join( bot, parms, ctx ):
|
||||
""" Joins a channel. """
|
||||
|
||||
nick = ctx['nick']
|
||||
#dst = ctx['dst']
|
||||
con = ctx['con']
|
||||
if nick == con.cfg['usr']['owner'] and parms \
|
||||
if parms \
|
||||
and not (parms[0] in con.cfg['sv']['channels']) and parms[0][0] == '#':
|
||||
con.send( 'JOIN {}'.format( parms[0] ) )
|
||||
con.cfg['sv']['channels'].append( parms[0] )
|
||||
|
||||
@command( 'part' )
|
||||
@command( 'part', True )
|
||||
async def cmd_part( bot, parms, ctx ):
|
||||
""" Leaves a channel. """
|
||||
|
||||
nick = ctx['nick']
|
||||
con = ctx['con']
|
||||
if nick == con.cfg['usr']['owner'] and parms \
|
||||
if parms \
|
||||
and parms[0] in con.cfg['sv']['channels']:
|
||||
con.send( 'PART {}'.format( parms[0] ) )
|
||||
con.cfg['sv']['channels'].remove( parms[0] )
|
||||
|
@ -130,8 +140,8 @@ async def cmd_help( b, p, c ):
|
|||
helpstr = ''
|
||||
|
||||
for k, m in _MOD_MAP.items():
|
||||
if p[0].lower() in m.keys():
|
||||
helpstr = '> {}: {}'.format( p[0].lower(), ' '.join( m[p[0].lower()].__doc__.split() ) )
|
||||
if p[0].lower() in m['cmds'].keys():
|
||||
helpstr = '> {}: {}'.format( p[0].lower(), ' '.join( m['cmds'][p[0].lower()].__doc__.split() ) )
|
||||
|
||||
if helpstr:
|
||||
con.say_to( dst, helpstr )
|
||||
|
@ -149,10 +159,10 @@ async def cmd_list( b, p, c ):
|
|||
for k,v in _MOD_MAP.items():
|
||||
if p:
|
||||
if p[0].lower() == k.lower():
|
||||
cmdlist = list(v.keys())
|
||||
cmdlist = list(v['cmds'].keys())
|
||||
break
|
||||
else:
|
||||
cmdlist.append( list(v.keys()) )
|
||||
cmdlist.append( list(v['cmds'].keys()) )
|
||||
|
||||
cn.say_to( c['dst'], '> {}'.format( (cmdlist and cmdlist or 'Module not found.') ) )
|
||||
|
||||
|
@ -165,19 +175,17 @@ async def cmd_modules( b, p, c ):
|
|||
cn.say_to( c['dst'], '> {}'.format( modlist ) )
|
||||
|
||||
# list active connections
|
||||
@command( 'connections' )
|
||||
@command( 'connections', True )
|
||||
async def cmd_connections( b, p, c ):
|
||||
""" List currently connected connections """
|
||||
if c['nick'] != c['con'].cfg['usr']['owner']: return
|
||||
conlist = [c.cfg['sv']['name'] for c in b._con]
|
||||
c['con'].say_to( c['dst'], '> {}'.format( conlist ) )
|
||||
|
||||
# reload a specified module
|
||||
@command( 'reload' )
|
||||
@command( 'reload', True )
|
||||
async def cmd_import( bot, p, ctx ):
|
||||
""" Reloads a previously loaded module. """
|
||||
con = ctx['con']
|
||||
if ctx['nick'] != con.cfg['usr']['owner']: return
|
||||
dst = ctx['dst']
|
||||
if p and p[0] in _MOD_MAP.keys():
|
||||
prev_mod = _MOD_MAP.pop( p[0], None )
|
||||
|
@ -194,7 +202,7 @@ async def cmd_import( bot, p, ctx ):
|
|||
else: con.say_to( dst, 'Module not found' )
|
||||
|
||||
# connect to a new server
|
||||
@command( 'connect' )
|
||||
@command( 'connect', True )
|
||||
async def cmd_connect( b, p, c ):
|
||||
"""
|
||||
Connects to a new network.
|
||||
|
@ -202,7 +210,6 @@ async def cmd_connect( b, p, c ):
|
|||
"""
|
||||
|
||||
con = c['con']
|
||||
if c['nick'] != con.cfg['usr']['owner']: return
|
||||
if not p and len( p ) < 2: return
|
||||
|
||||
new_sv_cfg = {'host':p[1],'port':6697,'name':p[0]}
|
||||
|
@ -214,20 +221,18 @@ async def cmd_connect( b, p, c ):
|
|||
con.say_to( c['dst'], 'OMW...' )
|
||||
|
||||
# disconnect from currently connected server
|
||||
@command( 'disconnect' )
|
||||
@command( 'disconnect', True )
|
||||
async def cmd_discon( b, p, c ):
|
||||
""" Disconnects from currently connected network """
|
||||
con = c['con']
|
||||
if c['nick'] != con.cfg['usr']['owner']: return
|
||||
con._stop = True
|
||||
con.send( 'QUIT :POOF' )
|
||||
b._con.remove( con )
|
||||
|
||||
# list of names on chan
|
||||
@command( 'names' )
|
||||
@command( 'names', True )
|
||||
async def cmd_names( b, p, c ):
|
||||
cn = c['con']
|
||||
if c['nick'] != cn.cfg['usr']['owner']: return
|
||||
nmstr = ''
|
||||
for k,v in cn.names.items():
|
||||
if c['dst'] in v:
|
||||
|
|
Loading…
Reference in New Issue