sopel/modules/admin.py

230 lines
6.7 KiB
Python
Raw Normal View History

2017-11-22 19:26:40 -05:00
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
admin.py - Sopel Admin Module
Copyright 2010-2011, Sean B. Palmer (inamidst.com) and Michael Yanovich
(yanovich.net)
Copyright © 2012, Elad Alfassa, <elad@fedoraproject.org>
Copyright 2013, Ari Koivula <ari@koivu.la>
Licensed under the Eiffel Forum License 2.
http://sopel.chat
"""
from __future__ import unicode_literals, absolute_import, print_function, division
from config.types import (
StaticSection, ValidatedAttribute, FilenameAttribute
)
import module
class AdminSection(StaticSection):
hold_ground = ValidatedAttribute('hold_ground', bool, default=False)
"""Auto re-join on kick"""
auto_accept_invite = ValidatedAttribute('auto_accept_invite', bool,
default=True)
def configure(config):
config.define_section('admin', AdminSection)
config.admin.configure_setting('hold_ground',
"Automatically re-join after being kicked?")
config.admin.configure_setting('auto_accept_invite',
'Automatically join channels when invited?')
def setup(bot):
bot.config.define_section('admin', AdminSection)
@module.require_privmsg
@module.require_admin
@module.commands('join')
@module.priority('low')
@module.example('.join #example or .join #example key')
def join(bot, trigger):
"""Join the specified channel. This is an admin-only command."""
channel, key = trigger.group(3), trigger.group(4)
if not channel:
return
elif not key:
bot.join(channel)
else:
bot.join(channel, key)
@module.require_privmsg
@module.require_admin
@module.commands('part')
@module.priority('low')
@module.example('.part #example')
def part(bot, trigger):
"""Part the specified channel. This is an admin-only command."""
channel, _sep, part_msg = trigger.group(2).partition(' ')
if part_msg:
bot.part(channel, part_msg)
else:
bot.part(channel)
@module.require_owner
@module.commands('quit')
@module.priority('low')
def quit(bot, trigger):
"""Quit from the server. This is an owner-only command."""
quit_message = trigger.group(2)
if not quit_message:
quit_message = 'Quitting on command from %s' % trigger.nick
bot.quit(quit_message)
@module.require_privmsg
@module.require_admin
@module.commands('msg')
@module.priority('low')
@module.example('.msg #YourPants Does anyone else smell neurotoxin?')
def msg(bot, trigger):
"""
Send a message to a given channel or nick. Can only be done in privmsg by an
admin.
"""
if trigger.group(2) is None:
return
channel, _sep, message = trigger.group(2).partition(' ')
message = message.strip()
if not channel or not message:
return
bot.say(message, channel)
2017-11-22 19:26:40 -05:00
@module.require_privmsg
@module.require_admin
@module.commands('me')
@module.priority('low')
def me(bot, trigger):
"""
Send an ACTION (/me) to a given channel or nick. Can only be done in privmsg
by an admin.
"""
if trigger.group(2) is None:
return
channel, _sep, action = trigger.group(2).partition(' ')
action = action.strip()
if not channel or not action:
return
msg = '\x01ACTION %s\x01' % action
bot.say(msg, channel)
2017-11-22 19:26:40 -05:00
@module.event('INVITE')
@module.rule('.*')
@module.priority('low')
def invite_join(bot, trigger):
"""
Join a channel sopel is invited to, if the inviter is an admin.
"""
if trigger.admin or bot.config.admin.auto_accept_invite:
bot.join(trigger.args[1])
return
@module.event('KICK')
@module.rule(r'.*')
@module.priority('low')
def hold_ground(bot, trigger):
"""
This function monitors all kicks across all channels sopel is in. If it
detects that it is the one kicked it'll automatically join that channel.
WARNING: This may not be needed and could cause problems if sopel becomes
annoying. Please use this with caution.
"""
if bot.config.admin.hold_ground:
channel = trigger.sender
if trigger.args[1] == bot.nick:
bot.join(channel)
@module.require_privmsg
@module.require_admin
@module.commands('mode')
@module.priority('low')
def mode(bot, trigger):
"""Set a user mode on Sopel. Can only be done in privmsg by an admin."""
mode = trigger.group(3)
bot.write(('MODE ', bot.nick + ' ' + mode))
@module.require_privmsg("This command only works as a private message.")
@module.require_admin("This command requires admin privileges.")
@module.commands('set')
@module.example('.set core.owner Me')
def set_config(bot, trigger):
"""See and modify values of sopels config object.
Trigger args:
arg1 - section and option, in the form "section.option"
arg2 - value
If there is no section, section will default to "core".
If value is None, the option will be deleted.
"""
# Get section and option from first argument.
arg1 = trigger.group(3).split('.')
if len(arg1) == 1:
section_name, option = "core", arg1[0]
elif len(arg1) == 2:
section_name, option = arg1
else:
bot.reply("Usage: .set section.option value")
return
section = getattr(bot.config, section_name)
static_sec = isinstance(section, StaticSection)
if static_sec and not hasattr(section, option):
bot.say('[{}] section has no option {}.'.format(section_name, option))
return
# Display current value if no value is given.
value = trigger.group(4)
if not value:
if not static_sec and bot.config.parser.has_option(section, option):
bot.reply("Option %s.%s does not exist." % (section_name, option))
return
# Except if the option looks like a password. Censor those to stop them
# from being put on log files.
if option.endswith("password") or option.endswith("pass"):
value = "(password censored)"
else:
value = getattr(section, option)
bot.reply("%s.%s = %s" % (section_name, option, value))
return
# Otherwise, set the value to one given as argument 2.
if static_sec:
descriptor = getattr(section.__class__, option)
try:
if isinstance(descriptor, FilenameAttribute):
value = descriptor.parse(bot.config, descriptor, value)
else:
value = descriptor.parse(value)
except ValueError as exc:
bot.say("Can't set attribute: " + str(exc))
return
setattr(section, option, value)
@module.require_privmsg
@module.require_admin
@module.commands('save')
@module.example('.save')
def save_config(bot, trigger):
"""Save state of sopels config object to the configuration file."""
bot.config.save()