| @@ -0,0 +1,70 @@ | |||
| #! /usr/bin/env python | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot | |||
| This is a thin wrapper for EarwigBot's main bot code, specified by bot_script. | |||
| The wrapper will automatically restart the bot when it shuts down (from | |||
| !restart, for example). It requests the bot's password at startup and reuses it | |||
| every time the bot restarts internally, so you do not need to re-enter the | |||
| password after using !restart. | |||
| For information about the bot as a whole, see the attached README.md file (in | |||
| markdown format!), the docs/ directory, and the LICENSE file for licensing | |||
| information. EarwigBot is released under the MIT license. | |||
| """ | |||
| from getpass import getpass | |||
| from subprocess import Popen, PIPE | |||
| from os import path | |||
| from sys import executable | |||
| from time import sleep | |||
| import earwigbot | |||
| bot_script = path.join(earwigbot.__path__[0], "runner.py") | |||
| def main(): | |||
| print "EarwigBot v{0}\n".format(earwigbot.__version__) | |||
| is_encrypted = earwigbot.config.config.load() | |||
| if is_encrypted: # Passwords in the config file are encrypted | |||
| key = getpass("Enter key to unencrypt bot passwords: ") | |||
| else: | |||
| key = None | |||
| while 1: | |||
| bot = Popen([executable, bot_script], stdin=PIPE) | |||
| print >> bot.stdin, path.dirname(path.abspath(__file__)) | |||
| if is_encrypted: | |||
| print >> bot.stdin, key | |||
| return_code = bot.wait() | |||
| if return_code == 1: | |||
| exit() # Let critical exceptions in the subprocess cause us to | |||
| # exit as well | |||
| else: | |||
| sleep(5) # Sleep between bot runs following a non-critical | |||
| # subprocess exit | |||
| if __name__ == "__main__": | |||
| main() | |||
| @@ -1,5 +0,0 @@ | |||
| from base_command import * | |||
| from base_task import * | |||
| from connection import * | |||
| from data import * | |||
| from rc import * | |||
| @@ -1,35 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| from classes import BaseCommand | |||
| import config | |||
| class Command(BaseCommand): | |||
| """Voice, devoice, op, or deop users in the channel.""" | |||
| name = "chanops" | |||
| def check(self, data): | |||
| commands = ["chanops", "voice", "devoice", "op", "deop"] | |||
| if data.is_command and data.command in commands: | |||
| return True | |||
| return False | |||
| def process(self, data): | |||
| if data.command == "chanops": | |||
| msg = "available commands are !voice, !devoice, !op, and !deop." | |||
| self.connection.reply(data, msg) | |||
| return | |||
| if data.host not in config.irc["permissions"]["admins"]: | |||
| msg = "you must be a bot admin to use this command." | |||
| self.connection.reply(data, msg) | |||
| return | |||
| # If it is just !op/!devoice/whatever without arguments, assume they | |||
| # want to do this to themselves: | |||
| if not data.args: | |||
| target = data.nick | |||
| else: | |||
| target = data.args[0] | |||
| msg = " ".join((data.command, data.chan, target)) | |||
| self.connection.say("ChanServ", msg) | |||
| @@ -1,38 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| from urllib import quote_plus | |||
| from classes import BaseCommand | |||
| import wiki | |||
| class Command(BaseCommand): | |||
| """Return a user's edit count.""" | |||
| name = "editcount" | |||
| def check(self, data): | |||
| commands = ["ec", "editcount"] | |||
| if data.is_command and data.command in commands: | |||
| return True | |||
| return False | |||
| def process(self, data): | |||
| if not data.args: | |||
| name = data.nick | |||
| else: | |||
| name = ' '.join(data.args) | |||
| site = wiki.get_site() | |||
| site._maxlag = None | |||
| user = site.get_user(name) | |||
| try: | |||
| count = user.editcount() | |||
| except wiki.UserNotFoundError: | |||
| msg = "the user \x0302{0}\x0301 does not exist." | |||
| self.connection.reply(data, msg.format(name)) | |||
| return | |||
| safe = quote_plus(user.name()) | |||
| url = "http://toolserver.org/~soxred93/pcount/index.php?name={0}&lang=en&wiki=wikipedia" | |||
| msg = "\x0302{0}\x0301 has {1} edits ({2})." | |||
| self.connection.reply(data, msg.format(name, count, url.format(safe))) | |||
| @@ -1,31 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| import random | |||
| from classes import BaseCommand | |||
| class Command(BaseCommand): | |||
| """Praise people!""" | |||
| name = "praise" | |||
| def check(self, data): | |||
| commands = ["praise", "earwig", "leonard", "leonard^bloom", "groove", | |||
| "groovedog"] | |||
| return data.is_command and data.command in commands | |||
| def process(self, data): | |||
| if data.command == "earwig": | |||
| msg = "\x02Earwig\x0F is the bestest Python programmer ever!" | |||
| elif data.command in ["leonard", "leonard^bloom"]: | |||
| msg = "\x02Leonard^Bloom\x0F is the biggest slacker ever!" | |||
| elif data.command in ["groove", "groovedog"]: | |||
| msg = "\x02GrooveDog\x0F is the bestest heh evar!" | |||
| else: | |||
| if not data.args: | |||
| msg = "You use this command to praise certain people. Who they are is a secret." | |||
| else: | |||
| msg = "You're doing it wrong." | |||
| self.connection.reply(data, msg) | |||
| return | |||
| self.connection.say(data.chan, msg) | |||
| @@ -1,29 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| from os.path import expanduser | |||
| import oursql | |||
| from classes import BaseCommand | |||
| class Command(BaseCommand): | |||
| """Return the replag for a specific database on the Toolserver.""" | |||
| name = "replag" | |||
| def process(self, data): | |||
| args = {} | |||
| if not data.args: | |||
| args["db"] = "enwiki_p" | |||
| else: | |||
| args["db"] = data.args[0] | |||
| args["host"] = args["db"].replace("_", "-") + ".rrdb.toolserver.org" | |||
| args["read_default_file"] = expanduser("~/.my.cnf") | |||
| conn = oursql.connect(**args) | |||
| with conn.cursor() as cursor: | |||
| cursor.execute("SELECT NOW() - MAX(rev_timestamp) FROM revision") | |||
| replag = int(cursor.fetchall()[0][0]) | |||
| conn.close() | |||
| msg = "Replag on \x0302{0}\x0301 is \x02{1}\x0F seconds." | |||
| self.connection.reply(data, msg.format(args["db"], replag)) | |||
| @@ -1,38 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| from classes import BaseCommand | |||
| import wiki | |||
| class Command(BaseCommand): | |||
| """Retrieve a list of rights for a given username.""" | |||
| name = "rights" | |||
| def check(self, data): | |||
| commands = ["rights", "groups", "permissions", "privileges"] | |||
| if data.is_command and data.command in commands: | |||
| return True | |||
| return False | |||
| def process(self, data): | |||
| if not data.args: | |||
| name = data.nick | |||
| else: | |||
| name = ' '.join(data.args) | |||
| site = wiki.get_site() | |||
| site._maxlag = None | |||
| user = site.get_user(name) | |||
| try: | |||
| rights = user.groups() | |||
| except wiki.UserNotFoundError: | |||
| msg = "the user \x0302{0}\x0301 does not exist." | |||
| self.connection.reply(data, msg.format(name)) | |||
| return | |||
| try: | |||
| rights.remove("*") # Remove the '*' group given to everyone | |||
| except ValueError: | |||
| pass | |||
| msg = "the rights for \x0302{0}\x0301 are {1}." | |||
| self.connection.reply(data, msg.format(name, ', '.join(rights))) | |||
| @@ -1,16 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| import random | |||
| from classes import BaseCommand | |||
| class Command(BaseCommand): | |||
| """Test the bot!""" | |||
| name = "test" | |||
| def process(self, data): | |||
| hey = random.randint(0, 1) | |||
| if hey: | |||
| self.connection.say(data.chan, "Hey \x02%s\x0F!" % data.nick) | |||
| else: | |||
| self.connection.say(data.chan, "'sup \x02%s\x0F?" % data.nick) | |||
| @@ -1,228 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| """ | |||
| EarwigBot's JSON Config File Parser | |||
| This handles all tasks involving reading and writing to our config file, | |||
| including encrypting and decrypting passwords and making a new config file from | |||
| scratch at the inital bot run. | |||
| Usually you'll just want to do "from core import config" and access config data | |||
| from within config's global variables and functions: | |||
| * config.components - a list of enabled components | |||
| * config.wiki - a dict of information about wiki-editing | |||
| * config.tasks - a dict of information for bot tasks | |||
| * config.irc - a dict of information about IRC | |||
| * config.metadata - a dict of miscellaneous information | |||
| * config.schedule() - returns a list of tasks scheduled to run at a given time | |||
| Additionally, there are functions used in config loading: | |||
| * config.load() - loads and parses our config file, returning True if | |||
| passwords are stored encrypted or False otherwise | |||
| * config.decrypt() - given a key, decrypts passwords inside our config | |||
| variables; won't work if passwords aren't encrypted | |||
| """ | |||
| import json | |||
| import logging | |||
| import logging.handlers | |||
| from os import mkdir, path | |||
| import blowfish | |||
| script_dir = path.dirname(path.abspath(__file__)) | |||
| root_dir = path.split(script_dir)[0] | |||
| config_path = path.join(root_dir, "config.json") | |||
| log_dir = path.join(root_dir, "logs") | |||
| _config = None # Holds data loaded from our config file | |||
| # Set our easy-config-access global variables to None | |||
| components, wiki, tasks, irc, metadata = None, None, None, None, None | |||
| def _load(): | |||
| """Load data from our JSON config file (config.json) into _config.""" | |||
| global _config | |||
| with open(config_path, 'r') as fp: | |||
| try: | |||
| _config = json.load(fp) | |||
| except ValueError as error: | |||
| print "Error parsing config file {0}:".format(config_path) | |||
| print error | |||
| exit(1) | |||
| def _setup_logging(): | |||
| """Configures the logging module so it works the way we want it to.""" | |||
| logger = logging.getLogger() | |||
| logger.setLevel(logging.DEBUG) | |||
| if metadata.get("enableLogging"): | |||
| hand = logging.handlers.TimedRotatingFileHandler | |||
| formatter = BotFormatter() | |||
| color_formatter = BotFormatter(color=True) | |||
| logfile = lambda f: path.join(log_dir, f) | |||
| if not path.isdir(log_dir): | |||
| if not path.exists(log_dir): | |||
| mkdir(log_dir, 0700) | |||
| else: | |||
| msg = "log_dir ({0}) exists but is not a directory!" | |||
| print msg.format(log_dir) | |||
| exit(1) | |||
| main_handler = hand(logfile("bot.log"), "midnight", 1, 7) | |||
| error_handler = hand(logfile("error.log"), "W6", 1, 4) | |||
| debug_handler = hand(logfile("debug.log"), "H", 1, 6) | |||
| main_handler.setLevel(logging.INFO) | |||
| error_handler.setLevel(logging.WARNING) | |||
| debug_handler.setLevel(logging.DEBUG) | |||
| for h in (main_handler, error_handler, debug_handler): | |||
| h.setFormatter(formatter) | |||
| logger.addHandler(h) | |||
| stream_handler = logging.StreamHandler() | |||
| stream_handler.setLevel(logging.DEBUG) | |||
| stream_handler.setFormatter(color_formatter) | |||
| logger.addHandler(stream_handler) | |||
| else: | |||
| logger.addHandler(logging.NullHandler()) | |||
| def _make_new(): | |||
| """Make a new config file based on the user's input.""" | |||
| encrypt = raw_input("Would you like to encrypt passwords stored in config.json? [y/n] ") | |||
| if encrypt.lower().startswith("y"): | |||
| is_encrypted = True | |||
| else: | |||
| is_encrypted = False | |||
| return is_encrypted | |||
| def is_loaded(): | |||
| """Return True if our config file has been loaded, otherwise False.""" | |||
| return _config is not None | |||
| def load(): | |||
| """Load, or reload, our config file. | |||
| First, check if we have a valid config file, and if not, notify the user. | |||
| If there is no config file at all, offer to make one, otherwise exit. | |||
| Store data from our config file in five global variables (components, wiki, | |||
| tasks, irc, metadata) for easy access (as well as the internal _config | |||
| variable). | |||
| If everything goes well, return True if stored passwords are | |||
| encrypted in the file, or False if they are not. | |||
| """ | |||
| global components, wiki, tasks, irc, metadata | |||
| if not path.exists(config_path): | |||
| print "You haven't configured the bot yet!" | |||
| choice = raw_input("Would you like to do this now? [y/n] ") | |||
| if choice.lower().startswith("y"): | |||
| return _make_new() | |||
| else: | |||
| exit(1) | |||
| _load() | |||
| components = _config.get("components", []) | |||
| wiki = _config.get("wiki", {}) | |||
| tasks = _config.get("tasks", {}) | |||
| irc = _config.get("irc", {}) | |||
| metadata = _config.get("metadata", {}) | |||
| _setup_logging() | |||
| # Are passwords encrypted? | |||
| return metadata.get("encryptPasswords", False) | |||
| def decrypt(key): | |||
| """Use the key to decrypt passwords in our config file. | |||
| Call this if load() returns True. Catch password decryption errors and | |||
| report them to the user. | |||
| """ | |||
| global irc, wiki | |||
| try: | |||
| item = wiki.get("password") | |||
| if item: | |||
| wiki["password"] = blowfish.decrypt(key, item) | |||
| item = irc.get("frontend").get("nickservPassword") | |||
| if item: | |||
| irc["frontend"]["nickservPassword"] = blowfish.decrypt(key, item) | |||
| item = irc.get("watcher").get("nickservPassword") | |||
| if item: | |||
| irc["watcher"]["nickservPassword"] = blowfish.decrypt(key, item) | |||
| except blowfish.BlowfishError as error: | |||
| print "\nError decrypting passwords:" | |||
| print "{0}: {1}.".format(error.__class__.__name__, error) | |||
| exit(1) | |||
| def schedule(minute, hour, month_day, month, week_day): | |||
| """Return a list of tasks scheduled to run at the specified time. | |||
| The schedule data comes from our config file's 'schedule' field, which is | |||
| stored as _config["schedule"]. Call this function as config.schedule(args). | |||
| """ | |||
| # Tasks to run this turn, each as a list of either [task_name, kwargs], or | |||
| # just the task_name: | |||
| tasks = [] | |||
| now = {"minute": minute, "hour": hour, "month_day": month_day, | |||
| "month": month, "week_day": week_day} | |||
| data = _config.get("schedule", []) | |||
| for event in data: | |||
| do = True | |||
| for key, value in now.items(): | |||
| try: | |||
| requirement = event[key] | |||
| except KeyError: | |||
| continue | |||
| if requirement != value: | |||
| do = False | |||
| break | |||
| if do: | |||
| try: | |||
| tasks.extend(event["tasks"]) | |||
| except KeyError: | |||
| pass | |||
| return tasks | |||
| class BotFormatter(logging.Formatter): | |||
| def __init__(self, color=False): | |||
| self._format = super(BotFormatter, self).format | |||
| if color: | |||
| fmt = "[%(asctime)s %(lvl)s] %(name)s: %(message)s" | |||
| self.format = lambda record: self._format(self.format_color(record)) | |||
| else: | |||
| fmt = "[%(asctime)s %(levelname)-8s] %(name)s: %(message)s" | |||
| self.format = self._format | |||
| datefmt = "%Y-%m-%d %H:%M:%S" | |||
| super(BotFormatter, self).__init__(fmt=fmt, datefmt=datefmt) | |||
| def format_color(self, record): | |||
| l = record.levelname.ljust(8) | |||
| if record.levelno == logging.DEBUG: | |||
| record.lvl = l.join(("\x1b[34m", "\x1b[0m")) # Blue | |||
| if record.levelno == logging.INFO: | |||
| record.lvl = l.join(("\x1b[32m", "\x1b[0m")) # Green | |||
| if record.levelno == logging.WARNING: | |||
| record.lvl = l.join(("\x1b[33m", "\x1b[0m")) # Yellow | |||
| if record.levelno == logging.ERROR: | |||
| record.lvl = l.join(("\x1b[31m", "\x1b[0m")) # Red | |||
| if record.levelno == logging.CRITICAL: | |||
| record.lvl = l.join(("\x1b[1m\x1b[31m", "\x1b[0m")) # Bold red | |||
| return record | |||
| @@ -1,14 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| from classes import BaseTask | |||
| class Task(BaseTask): | |||
| """A task to delink mainspace categories in declined [[WP:AFC]] | |||
| submissions.""" | |||
| name = "afc_catdelink" | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -1,15 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| from classes import BaseTask | |||
| class Task(BaseTask): | |||
| """A task to check newly-edited [[WP:AFC]] submissions for copyright | |||
| violations.""" | |||
| name = "afc_copyvios" | |||
| number = 1 | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -1,14 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| from classes import BaseTask | |||
| class Task(BaseTask): | |||
| """ A task to create daily categories for [[WP:AFC]].""" | |||
| name = "afc_dailycats" | |||
| number = 3 | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -1,13 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| from classes import BaseTask | |||
| class Task(BaseTask): | |||
| """A task to clear [[Category:Undated AfC submissions]].""" | |||
| name = "afc_undated" | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -1,14 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| from classes import BaseTask | |||
| class Task(BaseTask): | |||
| """A task to add |blp=yes to {{WPB}} or {{WPBS}} when it is used along with | |||
| {{WP Biography}}.""" | |||
| name = "blptag" | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -1,13 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| from classes import BaseTask | |||
| class Task(BaseTask): | |||
| """A task to create daily categories for [[WP:FEED]].""" | |||
| name = "feed_dailycats" | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -1,14 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| from classes import BaseTask | |||
| class Task(BaseTask): | |||
| """A task to tag files whose extensions do not agree with their MIME | |||
| type.""" | |||
| name = "wrongmime" | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -1,24 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| """ | |||
| EarwigBot's Wiki Toolset | |||
| This is a collection of classes and functions to read from and write to | |||
| Wikipedia and other wiki sites. No connection whatsoever to python-wikitools | |||
| written by Mr.Z-man, other than a similar purpose. We share no code. | |||
| Import the toolset with `import wiki`. | |||
| """ | |||
| import logging | |||
| logger = logging.getLogger("wiki") | |||
| logger.addHandler(logging.NullHandler()) | |||
| from wiki.constants import * | |||
| from wiki.exceptions import * | |||
| from wiki.functions import * | |||
| from wiki.category import Category | |||
| from wiki.page import Page | |||
| from wiki.site import Site | |||
| from wiki.user import User | |||
| @@ -1,35 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| """ | |||
| EarwigBot's Wiki Toolset: Constants | |||
| This module defines some useful constants: | |||
| * USER_AGENT - our default User Agent when making API queries | |||
| * NS_* - default namespace IDs for easy lookup | |||
| Import with `from wiki import constants` or `from wiki.constants import *`. | |||
| """ | |||
| # Default User Agent when making API queries: | |||
| import platform | |||
| USER_AGENT = "EarwigBot/0.1-dev (Python/{0}; https://github.com/earwig/earwigbot)".format(platform.python_version()) | |||
| # Default namespace IDs: | |||
| NS_MAIN = 0 | |||
| NS_TALK = 1 | |||
| NS_USER = 2 | |||
| NS_USER_TALK = 3 | |||
| NS_PROJECT = 4 | |||
| NS_PROJECT_TALK = 5 | |||
| NS_FILE = 6 | |||
| NS_FILE_TALK = 7 | |||
| NS_MEDIAWIKI = 8 | |||
| NS_MEDIAWIKI_TALK = 9 | |||
| NS_TEMPLATE = 10 | |||
| NS_TEMPLATE_TALK = 11 | |||
| NS_HELP = 12 | |||
| NS_HELP_TALK = 13 | |||
| NS_CATEGORY = 14 | |||
| NS_CATEGORY_TALK = 15 | |||
| NS_SPECIAL = -1 | |||
| NS_MEDIA = -2 | |||
| @@ -1,57 +0,0 @@ | |||
| #! /usr/bin/env python | |||
| # -*- coding: utf-8 -*- | |||
| """ | |||
| EarwigBot | |||
| A thin wrapper for EarwigBot's main bot code, specified by bot_script. This | |||
| wrapper will automatically restart the bot when it shuts down (from !restart, | |||
| for example). It requests the bot's password at startup and reuses it every | |||
| time the bot restarts internally, so you do not need to re-enter the password | |||
| after using !restart. | |||
| For information about the bot as a whole, see the attached README.md file (in | |||
| markdown format!) and the LICENSE for licensing information. | |||
| """ | |||
| from getpass import getpass | |||
| from subprocess import Popen, PIPE | |||
| from os import path | |||
| from sys import executable | |||
| from time import sleep | |||
| from bot import config | |||
| __author__ = "Ben Kurtovic" | |||
| __copyright__ = "Copyright (C) 2009, 2010, 2011 by Ben Kurtovic" | |||
| __license__ = "MIT License" | |||
| __version__ = "0.1-dev" | |||
| __email__ = "ben.kurtovic@verizon.net" | |||
| bot_script = path.join(path.dirname(path.abspath(__file__)), "bot", "main.py") | |||
| def main(): | |||
| print "EarwigBot v{0}\n".format(__version__) | |||
| is_encrypted = config.load() | |||
| if is_encrypted: # passwords in the config file are encrypted | |||
| key = getpass("Enter key to unencrypt bot passwords: ") | |||
| else: | |||
| key = None | |||
| while 1: | |||
| bot = Popen([executable, bot_script], stdin=PIPE) | |||
| bot.communicate(key) # give the key to core.config.decrypt() | |||
| return_code = bot.wait() | |||
| if return_code == 1: | |||
| exit() # let critical exceptions in the subprocess cause us to | |||
| # exit as well | |||
| else: | |||
| sleep(5) # sleep between bot runs following a non-critical | |||
| # subprocess exit | |||
| if __name__ == "__main__": | |||
| try: | |||
| main() | |||
| except KeyboardInterrupt: | |||
| print "\nKeyboardInterrupt: stopping bot wrapper." | |||
| @@ -0,0 +1,37 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot - http://earwig.github.com/earwig/earwigbot | |||
| See README.md for a basic overview, or the docs/ directory for details. | |||
| """ | |||
| __author__ = "Ben Kurtovic" | |||
| __copyright__ = "Copyright (C) 2009, 2010, 2011 by Ben Kurtovic" | |||
| __license__ = "MIT License" | |||
| __version__ = "0.1.dev" | |||
| __email__ = "ben.kurtovic@verizon.net" | |||
| from earwigbot import ( | |||
| blowfish, config, classes, commands, config, frontend, main, rules, tasks, | |||
| tests, watcher, wiki | |||
| ) | |||
| @@ -1,3 +1,4 @@ | |||
| #! /usr/bin/env python | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # blowfish.py | |||
| @@ -0,0 +1,27 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from earwigbot.classes.base_command import * | |||
| from earwigbot.classes.base_task import * | |||
| from earwigbot.classes.connection import * | |||
| from earwigbot.classes.data import * | |||
| from earwigbot.classes.rc import * | |||
| @@ -1,15 +1,37 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import logging | |||
| __all__ = ["BaseCommand"] | |||
| class BaseCommand(object): | |||
| """A base class for commands on IRC. | |||
| This docstring is reported to the user when they use !help <command>. | |||
| """ | |||
| # This is the command's name, as reported to the user when they use !help: | |||
| name = "base_command" | |||
| name = None | |||
| # Hooks are "msg", "msg_private", "msg_public", and "join". "msg" is the | |||
| # default behavior; if you wish to override that, change the value in your | |||
| # command subclass: | |||
| @@ -24,7 +46,8 @@ class BaseCommand(object): | |||
| from within a method. | |||
| """ | |||
| self.connection = connection | |||
| self.logger = logging.getLogger(".".join(("commands", self.name))) | |||
| logger_name = ".".join(("earwigbot", "commands", self.name)) | |||
| self.logger = logging.getLogger(logger_name) | |||
| self.logger.setLevel(logging.DEBUG) | |||
| def check(self, data): | |||
| @@ -1,9 +1,31 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import logging | |||
| import config | |||
| import wiki | |||
| from earwigbot.config import config | |||
| from earwigbot import wiki | |||
| __all__ = ["BaseTask"] | |||
| class BaseTask(object): | |||
| """A base class for bot tasks that edit Wikipedia.""" | |||
| @@ -20,7 +42,8 @@ class BaseTask(object): | |||
| def _setup_logger(self): | |||
| """Set up a basic module-level logger.""" | |||
| self.logger = logging.getLogger(".".join(("tasks", self.name))) | |||
| logger_name = ".".join(("earwigbot", "tasks", self.name)) | |||
| self.logger = logging.getLogger(logger_name) | |||
| self.logger.setLevel(logging.DEBUG) | |||
| def run(self, **kwargs): | |||
| @@ -1,8 +1,30 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import socket | |||
| import threading | |||
| __all__ = ["BrokenSocketException", "Connection"] | |||
| class BrokenSocketException(Exception): | |||
| """A socket has broken, because it is not sending data. Raised by | |||
| Connection.get().""" | |||
| @@ -1,7 +1,29 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import re | |||
| __all__ = ["KwargParseException", "Data"] | |||
| class KwargParseException(Exception): | |||
| """Couldn't parse a certain keyword argument in self.args, probably because | |||
| it was given incorrectly: e.g., no value (abc), just a value (=xyz), just | |||
| @@ -1,7 +1,29 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import re | |||
| __all__ = ["RC"] | |||
| class RC(object): | |||
| """A class to store data on an event received from our IRC watcher.""" | |||
| re_color = re.compile("\x03([0-9]{1,2}(,[0-9]{1,2})?)?") | |||
| @@ -1,4 +1,24 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's IRC Command Manager | |||
| @@ -11,20 +31,20 @@ import logging | |||
| import os | |||
| import sys | |||
| from classes import BaseCommand | |||
| import config | |||
| from earwigbot.classes import BaseCommand | |||
| from earwigbot.config import config | |||
| __all__ = ["load", "get_all", "check"] | |||
| # Base directory when searching for commands: | |||
| base_dir = os.path.join(config.root_dir, "bot", "commands") | |||
| base_dir = os.path.dirname(os.path.abspath(__file__)) | |||
| # Store commands in a dict, where the key is the command's name and the value | |||
| # is an instance of the command's class: | |||
| _commands = {} | |||
| # Logger for this module: | |||
| logger = logging.getLogger("tasks") | |||
| logger = logging.getLogger("earwigbot.tasks") | |||
| def _load_command(connection, filename): | |||
| """Try to load a specific command from a module, identified by file name. | |||
| @@ -1,10 +1,30 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import re | |||
| from classes import BaseCommand | |||
| import tasks | |||
| import wiki | |||
| from earwigbot.classes import BaseCommand | |||
| from earwigbot import tasks | |||
| from earwigbot import wiki | |||
| class Command(BaseCommand): | |||
| """Get information about an AFC submission by name.""" | |||
| @@ -1,10 +1,30 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import re | |||
| from classes import BaseCommand | |||
| import config | |||
| import wiki | |||
| from earwigbot import wiki | |||
| from earwigbot.classes import BaseCommand | |||
| from earwigbot.config import config | |||
| class Command(BaseCommand): | |||
| """Get the number of pending AfC submissions, open redirect requests, and | |||
| @@ -1,9 +1,29 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import re | |||
| import urllib | |||
| from classes import BaseCommand | |||
| from earwigbot.classes import BaseCommand | |||
| class Command(BaseCommand): | |||
| """A somewhat advanced calculator: see http://futureboy.us/fsp/frink.fsp | |||
| @@ -0,0 +1,55 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from earwigbot.classes import BaseCommand | |||
| from earwigbot.config import config | |||
| class Command(BaseCommand): | |||
| """Voice, devoice, op, or deop users in the channel.""" | |||
| name = "chanops" | |||
| def check(self, data): | |||
| commands = ["chanops", "voice", "devoice", "op", "deop"] | |||
| if data.is_command and data.command in commands: | |||
| return True | |||
| return False | |||
| def process(self, data): | |||
| if data.command == "chanops": | |||
| msg = "available commands are !voice, !devoice, !op, and !deop." | |||
| self.connection.reply(data, msg) | |||
| return | |||
| if data.host not in config.irc["permissions"]["admins"]: | |||
| msg = "you must be a bot admin to use this command." | |||
| self.connection.reply(data, msg) | |||
| return | |||
| # If it is just !op/!devoice/whatever without arguments, assume they | |||
| # want to do this to themselves: | |||
| if not data.args: | |||
| target = data.nick | |||
| else: | |||
| target = data.args[0] | |||
| msg = " ".join((data.command, data.chan, target)) | |||
| self.connection.say("ChanServ", msg) | |||
| @@ -1,9 +1,29 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import hashlib | |||
| from classes import BaseCommand | |||
| import blowfish | |||
| from earwigbot.classes import BaseCommand | |||
| from earwigbot import blowfish | |||
| class Command(BaseCommand): | |||
| """Provides hash functions with !hash (!hash list for supported algorithms) | |||
| @@ -1,10 +1,30 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import platform | |||
| import time | |||
| from classes import BaseCommand | |||
| import config | |||
| from earwigbot.classes import BaseCommand | |||
| from earwigbot.config import config | |||
| class Command(BaseCommand): | |||
| """Not an actual command, this module is used to respond to the CTCP | |||
| @@ -0,0 +1,58 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from urllib import quote_plus | |||
| from earwigbot.classes import BaseCommand | |||
| from earwigbot import wiki | |||
| class Command(BaseCommand): | |||
| """Return a user's edit count.""" | |||
| name = "editcount" | |||
| def check(self, data): | |||
| commands = ["ec", "editcount"] | |||
| if data.is_command and data.command in commands: | |||
| return True | |||
| return False | |||
| def process(self, data): | |||
| if not data.args: | |||
| name = data.nick | |||
| else: | |||
| name = ' '.join(data.args) | |||
| site = wiki.get_site() | |||
| site._maxlag = None | |||
| user = site.get_user(name) | |||
| try: | |||
| count = user.editcount() | |||
| except wiki.UserNotFoundError: | |||
| msg = "the user \x0302{0}\x0301 does not exist." | |||
| self.connection.reply(data, msg.format(name)) | |||
| return | |||
| safe = quote_plus(user.name()) | |||
| url = "http://toolserver.org/~soxred93/pcount/index.php?name={0}&lang=en&wiki=wikipedia" | |||
| msg = "\x0302{0}\x0301 has {1} edits ({2})." | |||
| self.connection.reply(data, msg.format(name, count, url.format(safe))) | |||
| @@ -1,11 +1,31 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import shlex | |||
| import subprocess | |||
| import re | |||
| from classes import BaseCommand | |||
| import config | |||
| from earwigbot.classes import BaseCommand | |||
| from earwigbot.config import config | |||
| class Command(BaseCommand): | |||
| """Commands to interface with the bot's git repository; use '!git' for a | |||
| @@ -1,9 +1,29 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import re | |||
| from classes import BaseCommand, Data | |||
| import commands | |||
| from earwigbot.classes import BaseCommand, Data | |||
| from earwigbot import commands | |||
| class Command(BaseCommand): | |||
| """Displays help information.""" | |||
| @@ -1,9 +1,29 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import re | |||
| from urllib import quote | |||
| from classes import BaseCommand | |||
| from earwigbot.classes import BaseCommand | |||
| class Command(BaseCommand): | |||
| """Convert a Wikipedia page name into a URL.""" | |||
| @@ -0,0 +1,51 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import random | |||
| from earwigbot.classes import BaseCommand | |||
| class Command(BaseCommand): | |||
| """Praise people!""" | |||
| name = "praise" | |||
| def check(self, data): | |||
| commands = ["praise", "earwig", "leonard", "leonard^bloom", "groove", | |||
| "groovedog"] | |||
| return data.is_command and data.command in commands | |||
| def process(self, data): | |||
| if data.command == "earwig": | |||
| msg = "\x02Earwig\x0F is the bestest Python programmer ever!" | |||
| elif data.command in ["leonard", "leonard^bloom"]: | |||
| msg = "\x02Leonard^Bloom\x0F is the biggest slacker ever!" | |||
| elif data.command in ["groove", "groovedog"]: | |||
| msg = "\x02GrooveDog\x0F is the bestest heh evar!" | |||
| else: | |||
| if not data.args: | |||
| msg = "You use this command to praise certain people. Who they are is a secret." | |||
| else: | |||
| msg = "You're doing it wrong." | |||
| self.connection.reply(data, msg) | |||
| return | |||
| self.connection.say(data.chan, msg) | |||
| @@ -1,9 +1,29 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import time | |||
| from classes import BaseCommand | |||
| import wiki | |||
| from earwigbot.classes import BaseCommand | |||
| from earwigbot import wiki | |||
| class Command(BaseCommand): | |||
| """Return when a user registered.""" | |||
| @@ -1,9 +1,29 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import threading | |||
| import time | |||
| from classes import BaseCommand | |||
| from earwigbot.classes import BaseCommand | |||
| class Command(BaseCommand): | |||
| """Set a message to be repeated to you in a certain amount of time.""" | |||
| @@ -0,0 +1,50 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from os.path import expanduser | |||
| import oursql | |||
| from earwigbot.classes import BaseCommand | |||
| class Command(BaseCommand): | |||
| """Return the replag for a specific database on the Toolserver.""" | |||
| name = "replag" | |||
| def process(self, data): | |||
| args = {} | |||
| if not data.args: | |||
| args["db"] = "enwiki_p" | |||
| else: | |||
| args["db"] = data.args[0] | |||
| args["host"] = args["db"].replace("_", "-") + ".rrdb.toolserver.org" | |||
| args["read_default_file"] = expanduser("~/.my.cnf") | |||
| conn = oursql.connect(**args) | |||
| with conn.cursor() as cursor: | |||
| query = "SELECT UNIX_TIMESTAMP() - UNIX_TIMESTAMP(rc_timestamp) FROM recentchanges ORDER BY rc_timestamp DESC LIMIT 1" | |||
| cursor.execute(query) | |||
| replag = int(cursor.fetchall()[0][0]) | |||
| conn.close() | |||
| msg = "Replag on \x0302{0}\x0301 is \x02{1}\x0F seconds." | |||
| self.connection.reply(data, msg.format(args["db"], replag)) | |||
| @@ -0,0 +1,58 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from earwigbot.classes import BaseCommand | |||
| from earwigbot import wiki | |||
| class Command(BaseCommand): | |||
| """Retrieve a list of rights for a given username.""" | |||
| name = "rights" | |||
| def check(self, data): | |||
| commands = ["rights", "groups", "permissions", "privileges"] | |||
| if data.is_command and data.command in commands: | |||
| return True | |||
| return False | |||
| def process(self, data): | |||
| if not data.args: | |||
| name = data.nick | |||
| else: | |||
| name = ' '.join(data.args) | |||
| site = wiki.get_site() | |||
| site._maxlag = None | |||
| user = site.get_user(name) | |||
| try: | |||
| rights = user.groups() | |||
| except wiki.UserNotFoundError: | |||
| msg = "the user \x0302{0}\x0301 does not exist." | |||
| self.connection.reply(data, msg.format(name)) | |||
| return | |||
| try: | |||
| rights.remove("*") # Remove the '*' group given to everyone | |||
| except ValueError: | |||
| pass | |||
| msg = "the rights for \x0302{0}\x0301 are {1}." | |||
| self.connection.reply(data, msg.format(name, ', '.join(rights))) | |||
| @@ -0,0 +1,36 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import random | |||
| from earwigbot.classes import BaseCommand | |||
| class Command(BaseCommand): | |||
| """Test the bot!""" | |||
| name = "test" | |||
| def process(self, data): | |||
| hey = random.randint(0, 1) | |||
| if hey: | |||
| self.connection.say(data.chan, "Hey \x02%s\x0F!" % data.nick) | |||
| else: | |||
| self.connection.say(data.chan, "'sup \x02%s\x0F?" % data.nick) | |||
| @@ -1,11 +1,31 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import threading | |||
| import re | |||
| from classes import BaseCommand, Data, KwargParseException | |||
| import tasks | |||
| import config | |||
| from earwigbot import tasks | |||
| from earwigbot.classes import BaseCommand, Data, KwargParseException | |||
| from earwigbot.config import config | |||
| class Command(BaseCommand): | |||
| """Manage wiki tasks from IRC, and check on thread status.""" | |||
| @@ -0,0 +1,335 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's JSON Config File Parser | |||
| This handles all tasks involving reading and writing to our config file, | |||
| including encrypting and decrypting passwords and making a new config file from | |||
| scratch at the inital bot run. | |||
| Usually you'll just want to do "from earwigbot.config import config", which | |||
| returns a singleton _BotConfig object, with data accessible from various | |||
| attributes and functions: | |||
| * config.components - enabled components | |||
| * config.wiki - information about wiki-editing | |||
| * config.tasks - information for bot tasks | |||
| * config.irc - information about IRC | |||
| * config.metadata - miscellaneous information | |||
| * config.schedule() - tasks scheduled to run at a given time | |||
| Additionally, _BotConfig has some functions used in config loading: | |||
| * config.load() - loads and parses our config file, returning True if | |||
| passwords are stored encrypted or False otherwise | |||
| * config.decrypt() - given a key, decrypts passwords inside our config | |||
| variables; won't work if passwords aren't encrypted | |||
| """ | |||
| import json | |||
| import logging | |||
| import logging.handlers | |||
| from os import mkdir, path | |||
| from earwigbot import blowfish | |||
| __all__ = ["config"] | |||
| class _ConfigNode(object): | |||
| def __iter__(self): | |||
| for key in self.__dict__.iterkeys(): | |||
| yield key | |||
| def __getitem__(self, item): | |||
| return self.__dict__.__getitem__(item) | |||
| def _dump(self): | |||
| data = self.__dict__.copy() | |||
| for key, val in data.iteritems(): | |||
| if isinstance(val, _ConfigNode): | |||
| data[key] = val.dump() | |||
| return data | |||
| def _load(self, data): | |||
| self.__dict__ = data.copy() | |||
| def _decrypt(self, key, intermediates, item): | |||
| base = self.__dict__ | |||
| try: | |||
| for inter in intermediates: | |||
| base = base[inter] | |||
| except KeyError: | |||
| return | |||
| if item in base: | |||
| base[item] = blowfish.decrypt(key, base[item]) | |||
| def get(self, *args, **kwargs): | |||
| return self.__dict__.get(*args, **kwargs) | |||
| class _BotConfig(object): | |||
| def __init__(self): | |||
| self._script_dir = path.dirname(path.abspath(__file__)) | |||
| self._root_dir = path.split(self._script_dir)[0] | |||
| self._config_path = path.join(self._root_dir, "config.json") | |||
| self._log_dir = path.join(self._root_dir, "logs") | |||
| self._decryption_key = None | |||
| self._data = None | |||
| self._components = _ConfigNode() | |||
| self._wiki = _ConfigNode() | |||
| self._tasks = _ConfigNode() | |||
| self._irc = _ConfigNode() | |||
| self._metadata = _ConfigNode() | |||
| self._nodes = [self._components, self._wiki, self._tasks, self._irc, | |||
| self._metadata] | |||
| def _load(self): | |||
| """Load data from our JSON config file (config.json) into _config.""" | |||
| filename = self._config_path | |||
| with open(filename, 'r') as fp: | |||
| try: | |||
| self._data = json.load(fp) | |||
| except ValueError as error: | |||
| print "Error parsing config file {0}:".format(filename) | |||
| print error | |||
| exit(1) | |||
| def _setup_logging(self): | |||
| """Configures the logging module so it works the way we want it to.""" | |||
| log_dir = self._log_dir | |||
| logger = logging.getLogger("earwigbot") | |||
| logger.setLevel(logging.DEBUG) | |||
| if self.metadata.get("enableLogging"): | |||
| hand = logging.handlers.TimedRotatingFileHandler | |||
| formatter = _BotFormatter() | |||
| color_formatter = _BotFormatter(color=True) | |||
| logfile = lambda f: path.join(log_dir, f) | |||
| if not path.isdir(log_dir): | |||
| if not path.exists(log_dir): | |||
| mkdir(log_dir, 0700) | |||
| else: | |||
| msg = "log_dir ({0}) exists but is not a directory!" | |||
| print msg.format(log_dir) | |||
| exit(1) | |||
| main_handler = hand(logfile("bot.log"), "midnight", 1, 7) | |||
| error_handler = hand(logfile("error.log"), "W6", 1, 4) | |||
| debug_handler = hand(logfile("debug.log"), "H", 1, 6) | |||
| main_handler.setLevel(logging.INFO) | |||
| error_handler.setLevel(logging.WARNING) | |||
| debug_handler.setLevel(logging.DEBUG) | |||
| for h in (main_handler, error_handler, debug_handler): | |||
| h.setFormatter(formatter) | |||
| logger.addHandler(h) | |||
| stream_handler = logging.StreamHandler() | |||
| stream_handler.setLevel(logging.DEBUG) | |||
| stream_handler.setFormatter(color_formatter) | |||
| logger.addHandler(stream_handler) | |||
| else: | |||
| logger.addHandler(logging.NullHandler()) | |||
| def _make_new(self): | |||
| """Make a new config file based on the user's input.""" | |||
| encrypt = raw_input("Would you like to encrypt passwords stored in config.json? [y/n] ") | |||
| if encrypt.lower().startswith("y"): | |||
| is_encrypted = True | |||
| else: | |||
| is_encrypted = False | |||
| return is_encrypted | |||
| @property | |||
| def script_dir(self): | |||
| return self._script_dir | |||
| @property | |||
| def root_dir(self): | |||
| return self._root_dir | |||
| @property | |||
| def config_path(self): | |||
| return self._config_path | |||
| @property | |||
| def log_dir(self): | |||
| return self._log_dir | |||
| @property | |||
| def components(self): | |||
| """A dict of enabled components.""" | |||
| return self._components | |||
| @property | |||
| def wiki(self): | |||
| """A dict of information about wiki-editing.""" | |||
| return self._wiki | |||
| @property | |||
| def tasks(self): | |||
| """A dict of information for bot tasks.""" | |||
| return self._tasks | |||
| @property | |||
| def irc(self): | |||
| """A dict of information about IRC.""" | |||
| return self._irc | |||
| @property | |||
| def metadata(self): | |||
| """A dict of miscellaneous information.""" | |||
| return self._metadata | |||
| def is_loaded(self): | |||
| """Return True if our config file has been loaded, otherwise False.""" | |||
| return self._data is not None | |||
| def is_encrypted(self): | |||
| """Return True if passwords are encrypted, otherwise False.""" | |||
| return self.metadata.get("encryptPasswords", False) | |||
| def load(self, config_path=None, log_dir=None): | |||
| """Load, or reload, our config file. | |||
| First, check if we have a valid config file, and if not, notify the | |||
| user. If there is no config file at all, offer to make one, otherwise | |||
| exit. | |||
| Store data from our config file in five _ConfigNodes (components, | |||
| wiki, tasks, irc, metadata) for easy access (as well as the internal | |||
| _data variable). | |||
| If everything goes well, return True if stored passwords are | |||
| encrypted in the file, or False if they are not. | |||
| """ | |||
| if config_path: | |||
| self._config_path = config_path | |||
| if log_dir: | |||
| self._log_dir = log_dir | |||
| if not path.exists(self._config_path): | |||
| print "You haven't configured the bot yet!" | |||
| choice = raw_input("Would you like to do this now? [y/n] ") | |||
| if choice.lower().startswith("y"): | |||
| return self._make_new() | |||
| else: | |||
| exit(1) | |||
| self._load() | |||
| data = self._data | |||
| self.components._load(data.get("components", {})) | |||
| self.wiki._load(data.get("wiki", {})) | |||
| self.tasks._load(data.get("tasks", {})) | |||
| self.irc._load(data.get("irc", {})) | |||
| self.metadata._load(data.get("metadata", {})) | |||
| self._setup_logging() | |||
| return self.is_encrypted() | |||
| def decrypt(self, node, *nodes): | |||
| """Use self._decryption_key to decrypt an object in our config tree. | |||
| If this is called when passwords are not encrypted (check with | |||
| config.is_encrypted()), nothing will happen. | |||
| An example usage would be: | |||
| config.decrypt(config.irc, "frontend", "nickservPassword") | |||
| """ | |||
| if not self.is_encrypted(): | |||
| return | |||
| try: | |||
| node._decrypt(self._decryption_key, nodes[:-1], nodes[-1]) | |||
| except blowfish.BlowfishError as error: | |||
| print "\nError decrypting passwords:" | |||
| print "{0}: {1}.".format(error.__class__.__name__, error) | |||
| exit(1) | |||
| def schedule(self, minute, hour, month_day, month, week_day): | |||
| """Return a list of tasks scheduled to run at the specified time. | |||
| The schedule data comes from our config file's 'schedule' field, which | |||
| is stored as self._data["schedule"]. Call this function as | |||
| config.schedule(args). | |||
| """ | |||
| # Tasks to run this turn, each as a list of either [task_name, kwargs], | |||
| # or just the task_name: | |||
| tasks = [] | |||
| now = {"minute": minute, "hour": hour, "month_day": month_day, | |||
| "month": month, "week_day": week_day} | |||
| data = self._data.get("schedule", []) | |||
| for event in data: | |||
| do = True | |||
| for key, value in now.items(): | |||
| try: | |||
| requirement = event[key] | |||
| except KeyError: | |||
| continue | |||
| if requirement != value: | |||
| do = False | |||
| break | |||
| if do: | |||
| try: | |||
| tasks.extend(event["tasks"]) | |||
| except KeyError: | |||
| pass | |||
| return tasks | |||
| class _BotFormatter(logging.Formatter): | |||
| def __init__(self, color=False): | |||
| self._format = super(_BotFormatter, self).format | |||
| if color: | |||
| fmt = "[%(asctime)s %(lvl)s] %(name)s: %(message)s" | |||
| self.format = lambda record: self._format(self.format_color(record)) | |||
| else: | |||
| fmt = "[%(asctime)s %(levelname)-8s] %(name)s: %(message)s" | |||
| self.format = self._format | |||
| datefmt = "%Y-%m-%d %H:%M:%S" | |||
| super(_BotFormatter, self).__init__(fmt=fmt, datefmt=datefmt) | |||
| def format_color(self, record): | |||
| l = record.levelname.ljust(8) | |||
| if record.levelno == logging.DEBUG: | |||
| record.lvl = l.join(("\x1b[34m", "\x1b[0m")) # Blue | |||
| if record.levelno == logging.INFO: | |||
| record.lvl = l.join(("\x1b[32m", "\x1b[0m")) # Green | |||
| if record.levelno == logging.WARNING: | |||
| record.lvl = l.join(("\x1b[33m", "\x1b[0m")) # Yellow | |||
| if record.levelno == logging.ERROR: | |||
| record.lvl = l.join(("\x1b[31m", "\x1b[0m")) # Red | |||
| if record.levelno == logging.CRITICAL: | |||
| record.lvl = l.join(("\x1b[1m\x1b[31m", "\x1b[0m")) # Bold red | |||
| return record | |||
| config = _BotConfig() | |||
| @@ -1,4 +1,24 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's IRC Frontend Component | |||
| @@ -12,14 +32,14 @@ imported by irc/command_handler.py if they are in irc/commands. | |||
| import logging | |||
| import re | |||
| import config | |||
| import commands | |||
| from classes import Connection, Data, BrokenSocketException | |||
| from earwigbot import commands | |||
| from earwigbot.classes import Connection, Data, BrokenSocketException | |||
| from earwigbot.config import config | |||
| __all__ = ["get_connection", "startup", "main"] | |||
| connection = None | |||
| logger = logging.getLogger("frontend") | |||
| logger = logging.getLogger("earwigbot.frontend") | |||
| sender_regex = re.compile(":(.*?)!(.*?)@(.*?)\Z") | |||
| def get_connection(): | |||
| @@ -1,12 +1,27 @@ | |||
| #! /usr/bin/env python | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's Core | |||
| This should not be run directly; the wrapper in "earwigbot.py" is preferred, | |||
| but it should work fine alone, as long as you enter the password-unlock key at | |||
| the initial hidden prompt if one is needed. | |||
| EarwigBot's Main Module | |||
| The core is essentially responsible for starting the various bot components | |||
| (irc, scheduler, etc) and making sure they are all happy. An explanation of the | |||
| @@ -34,11 +49,12 @@ import logging | |||
| import threading | |||
| import time | |||
| import config | |||
| import frontend | |||
| import tasks | |||
| import watcher | |||
| from earwigbot import frontend | |||
| from earwigbot import tasks | |||
| from earwigbot import watcher | |||
| from earwigbot.config import config | |||
| logger = logging.getLogger("earwigbot") | |||
| f_conn = None | |||
| w_conn = None | |||
| @@ -52,9 +68,9 @@ def irc_watcher(f_conn=None): | |||
| try: | |||
| watcher.main(w_conn, f_conn) | |||
| except: | |||
| logging.exception("Watcher had an error") | |||
| logger.exception("Watcher had an error") | |||
| time.sleep(5) # sleep a bit before restarting watcher | |||
| logging.warn("Watcher has stopped; restarting component") | |||
| logger.warn("Watcher has stopped; restarting component") | |||
| def wiki_scheduler(): | |||
| """Function to handle the wiki scheduler as another thread, or as the | |||
| @@ -75,13 +91,12 @@ def irc_frontend(): | |||
| enable the wiki scheduler and IRC watcher on new threads if they are | |||
| enabled.""" | |||
| global f_conn | |||
| logging.info("Starting IRC frontend") | |||
| logger.info("Starting IRC frontend") | |||
| f_conn = frontend.get_connection() | |||
| frontend.startup(f_conn) | |||
| if "wiki_schedule" in config.components: | |||
| logging.info("Starting wiki scheduler") | |||
| logger.info("Starting wiki scheduler") | |||
| tasks.load() | |||
| t_scheduler = threading.Thread(target=wiki_scheduler) | |||
| t_scheduler.name = "wiki-scheduler" | |||
| @@ -89,7 +104,7 @@ def irc_frontend(): | |||
| t_scheduler.start() | |||
| if "irc_watcher" in config.components: | |||
| logging.info("Starting IRC watcher") | |||
| logger.info("Starting IRC watcher") | |||
| t_watcher = threading.Thread(target=irc_watcher, args=(f_conn,)) | |||
| t_watcher.name = "irc-watcher" | |||
| t_watcher.daemon = True | |||
| @@ -101,50 +116,31 @@ def irc_frontend(): | |||
| w_conn.close() | |||
| f_conn.close() | |||
| def run(): | |||
| config.load() | |||
| try: | |||
| # Wait for our password decrypt key from the bot's wrapper, then | |||
| # decrypt passwords: | |||
| key = raw_input() | |||
| except EOFError: | |||
| pass | |||
| else: | |||
| config.decrypt(key) | |||
| enabled = config.components | |||
| if "irc_frontend" in enabled: | |||
| def main(): | |||
| if "irc_frontend" in config.components: | |||
| # Make the frontend run on our primary thread if enabled, and enable | |||
| # additional components through that function | |||
| irc_frontend() | |||
| elif "wiki_schedule" in enabled: | |||
| elif "wiki_schedule" in config.components: | |||
| # Run the scheduler on the main thread, but also run the IRC watcher on | |||
| # another thread iff it is enabled | |||
| logging.info("Starting wiki scheduler") | |||
| logger.info("Starting wiki scheduler") | |||
| tasks.load() | |||
| if "irc_watcher" in enabled: | |||
| logging.info("Starting IRC watcher") | |||
| logger.info("Starting IRC watcher") | |||
| t_watcher = threading.Thread(target=irc_watcher) | |||
| t_watcher.name = "irc-watcher" | |||
| t_watcher.daemon = True | |||
| t_watcher.start() | |||
| wiki_scheduler() | |||
| elif "irc_watcher" in enabled: | |||
| elif "irc_watcher" in config.components: | |||
| # The IRC watcher is our only enabled component, so run its function | |||
| # only and don't worry about anything else: | |||
| logging.info("Starting IRC watcher") | |||
| logger.info("Starting IRC watcher") | |||
| irc_watcher() | |||
| else: # Nothing is enabled! | |||
| logging.critical("No bot parts are enabled; stopping") | |||
| exit(1) | |||
| if __name__ == "__main__": | |||
| try: | |||
| run() | |||
| except KeyboardInterrupt: | |||
| logging.critical("KeyboardInterrupt: stopping main bot loop") | |||
| logger.critical("No bot parts are enabled; stopping") | |||
| exit(1) | |||
| @@ -1,4 +1,24 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's IRC Watcher Rules | |||
| @@ -9,7 +29,7 @@ recieves an event from IRC. | |||
| import re | |||
| import tasks | |||
| from earwigbot import tasks | |||
| afc_prefix = "wikipedia( talk)?:(wikiproject )?articles for creation" | |||
| @@ -0,0 +1,63 @@ | |||
| #! /usr/bin/env python | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot Runner | |||
| This is a very simple script that can be run from anywhere. It will add the | |||
| 'earwigbot' package to sys.path if it's not already in there (i.e., it hasn't | |||
| been "installed"), accept a root_dir (the directory in which bot.py is located) | |||
| and a decryption key from raw_input (if passwords are encrypted), then call | |||
| config.load() and decrypt any passwords, and finally call the main() function | |||
| of earwigbot.main. | |||
| """ | |||
| from os import path | |||
| import sys | |||
| def run(): | |||
| pkg_dir = path.split(path.dirname(path.abspath(__file__)))[0] | |||
| if pkg_dir not in sys.path: | |||
| sys.path.insert(0, pkg_dir) | |||
| from earwigbot.config import config | |||
| from earwigbot import main | |||
| root_dir = raw_input() | |||
| config_path = path.join(root_dir, "config.json") | |||
| log_dir = path.join(root_dir, "logs") | |||
| is_encrypted = config.load(config_path, log_dir) | |||
| if is_encrypted: | |||
| config._decryption_key = raw_input() | |||
| config.decrypt(config.wiki, "password") | |||
| config.decrypt(config.irc, "frontend", "nickservPassword") | |||
| config.decrypt(config.irc, "watcher", "nickservPassword") | |||
| try: | |||
| main.main() | |||
| except KeyboardInterrupt: | |||
| main.logger.critical("KeyboardInterrupt: stopping main bot loop") | |||
| exit(1) | |||
| if __name__ == "__main__": | |||
| run() | |||
| @@ -1,4 +1,24 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's Wiki Task Manager | |||
| @@ -13,20 +33,20 @@ import sys | |||
| import threading | |||
| import time | |||
| from classes import BaseTask | |||
| import config | |||
| from earwigbot.classes import BaseTask | |||
| from earwigbot.config import config | |||
| __all__ = ["load", "schedule", "start", "get", "get_all"] | |||
| # Base directory when searching for tasks: | |||
| base_dir = os.path.join(config.root_dir, "bot", "tasks") | |||
| base_dir = os.path.dirname(os.path.abspath(__file__)) | |||
| # Store loaded tasks as a dict where the key is the task name and the value is | |||
| # an instance of the task class: | |||
| _tasks = {} | |||
| # Logger for this module: | |||
| logger = logging.getLogger("commands") | |||
| logger = logging.getLogger("earwigbot.commands") | |||
| def _load_task(filename): | |||
| """Try to load a specific task from a module, identified by file name.""" | |||
| @@ -0,0 +1,34 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from earwigbot.classes import BaseTask | |||
| class Task(BaseTask): | |||
| """A task to delink mainspace categories in declined [[WP:AFC]] | |||
| submissions.""" | |||
| name = "afc_catdelink" | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -0,0 +1,38 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from earwigbot.classes import BaseTask | |||
| from earwigbot.config import config | |||
| class Task(BaseTask): | |||
| """A task to check newly-edited [[WP:AFC]] submissions for copyright | |||
| violations.""" | |||
| name = "afc_copyvios" | |||
| number = 1 | |||
| def __init__(self): | |||
| self.cfg = cfg = config.tasks.get(self.name, {}) | |||
| config.decrypt(config.tasks, self.name, "search", "credentials", "key") | |||
| config.decrypt(config.tasks, self.name, "search", "credentials", "secret") | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -0,0 +1,34 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from earwigbot.classes import BaseTask | |||
| class Task(BaseTask): | |||
| """ A task to create daily categories for [[WP:AFC]].""" | |||
| name = "afc_dailycats" | |||
| number = 3 | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -1,4 +1,24 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from collections import OrderedDict | |||
| from datetime import datetime, timedelta | |||
| @@ -11,9 +31,9 @@ from matplotlib import pyplot as plt | |||
| from numpy import arange | |||
| import oursql | |||
| from classes import BaseTask | |||
| import config | |||
| import wiki | |||
| from earwigbot import wiki | |||
| from earwigbot.classes import BaseTask | |||
| from earwigbot.config import config | |||
| # Valid submission statuses: | |||
| STATUS_NONE = 0 | |||
| @@ -1,4 +1,24 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from datetime import datetime | |||
| import logging | |||
| @@ -9,9 +29,9 @@ from time import sleep | |||
| import oursql | |||
| from classes import BaseTask | |||
| import config | |||
| import wiki | |||
| from earwigbot import wiki | |||
| from earwigbot.classes import BaseTask | |||
| from earwigbot.config import config | |||
| # Chart status number constants: | |||
| CHART_NONE = 0 | |||
| @@ -178,6 +198,7 @@ class Task(BaseTask): | |||
| if replag > 600 and not kwargs.get("ignore_replag"): | |||
| msg = "Sync canceled as replag ({0} secs) is greater than ten minutes." | |||
| self.logger.warn(msg.format(replag)) | |||
| return | |||
| with self.conn.cursor() as cursor: | |||
| self.update_tracked(cursor) | |||
| @@ -0,0 +1,33 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from earwigbot.classes import BaseTask | |||
| class Task(BaseTask): | |||
| """A task to clear [[Category:Undated AfC submissions]].""" | |||
| name = "afc_undated" | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -0,0 +1,34 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from earwigbot.classes import BaseTask | |||
| class Task(BaseTask): | |||
| """A task to add |blp=yes to {{WPB}} or {{WPBS}} when it is used along with | |||
| {{WP Biography}}.""" | |||
| name = "blptag" | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -0,0 +1,33 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from earwigbot.classes import BaseTask | |||
| class Task(BaseTask): | |||
| """A task to create daily categories for [[WP:FEED]].""" | |||
| name = "feed_dailycats" | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -0,0 +1,34 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from earwigbot.classes import BaseTask | |||
| class Task(BaseTask): | |||
| """A task to tag files whose extensions do not agree with their MIME | |||
| type.""" | |||
| name = "wrongmime" | |||
| def __init__(self): | |||
| pass | |||
| def run(self, **kwargs): | |||
| pass | |||
| @@ -1,12 +1,29 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's Unit Test Support | |||
| EarwigBot's Unit Tests | |||
| This module provides some support code for unit tests. | |||
| Importing this module will "fix" your path so that EarwigBot code from bot/ can | |||
| be imported normally. | |||
| This module __init__ file provides some support code for unit tests. | |||
| CommandTestCase is a subclass of unittest.TestCase that provides setUp() for | |||
| creating a fake connection and some other helpful methods. It uses | |||
| @@ -14,16 +31,10 @@ FakeConnection, a subclass of classes.Connection, but with an internal string | |||
| instead of a socket for data. | |||
| """ | |||
| from os import path | |||
| import re | |||
| import sys | |||
| from unittest import TestCase | |||
| root_dir = path.split(path.dirname(path.abspath(__file__)))[0] | |||
| code_dir = path.join(root_dir, "bot") | |||
| sys.path.insert(0, code_dir) | |||
| from classes import Connection, Data | |||
| from earwigbot.classes import Connection, Data | |||
| class CommandTestCase(TestCase): | |||
| re_sender = re.compile(":(.*?)!(.*?)@(.*?)\Z") | |||
| @@ -1,11 +1,30 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import unittest | |||
| import random | |||
| import string | |||
| import support | |||
| import blowfish | |||
| from earwigbot import blowfish | |||
| class TestBlowfish(unittest.TestCase): | |||
| @@ -0,0 +1,58 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import unittest | |||
| from earwigbot.commands.calc import Command | |||
| class TestCalc(support.CommandTestCase): | |||
| def setUp(self): | |||
| super(TestCalc, self).setUp(Command) | |||
| def test_check(self): | |||
| self.assertFalse(self.command.check(self.make_msg("bloop"))) | |||
| self.assertFalse(self.command.check(self.make_join())) | |||
| self.assertTrue(self.command.check(self.make_msg("calc"))) | |||
| self.assertTrue(self.command.check(self.make_msg("CALC", "foo"))) | |||
| def test_ignore_empty(self): | |||
| self.command.process(self.make_msg("calc")) | |||
| self.assertReply("what do you want me to calculate?") | |||
| def test_maths(self): | |||
| tests = [ | |||
| ("2 + 2", "2 + 2 = 4"), | |||
| ("13 * 5", "13 * 5 = 65"), | |||
| ("80 / 42", "80 / 42 = 40/21 (approx. 1.9047619047619047)"), | |||
| ("2/0", "2/0 = undef"), | |||
| ("π", "π = 3.141592653589793238"), | |||
| ] | |||
| for test in tests: | |||
| q = test[0].strip().split() | |||
| self.command.process(self.make_msg("calc", *q)) | |||
| self.assertReply(test[1]) | |||
| if __name__ == "__main__": | |||
| unittest.main(verbosity=2) | |||
| @@ -0,0 +1,48 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| import unittest | |||
| from earwigbot.commands.test import Command | |||
| class TestTest(support.CommandTestCase): | |||
| def setUp(self): | |||
| super(TestTest, self).setUp(Command) | |||
| def test_check(self): | |||
| self.assertFalse(self.command.check(self.make_msg("bloop"))) | |||
| self.assertFalse(self.command.check(self.make_join())) | |||
| self.assertTrue(self.command.check(self.make_msg("test"))) | |||
| self.assertTrue(self.command.check(self.make_msg("TEST", "foo"))) | |||
| def test_process(self): | |||
| def _test(): | |||
| self.command.process(self.make_msg("test")) | |||
| self.assertSaidIn(["Hey \x02Foo\x0F!", "'sup \x02Foo\x0F?"]) | |||
| for i in xrange(64): | |||
| _test() | |||
| if __name__ == "__main__": | |||
| unittest.main(verbosity=2) | |||
| @@ -1,4 +1,24 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's IRC Watcher Component | |||
| @@ -12,12 +32,12 @@ frontend. | |||
| import logging | |||
| import config | |||
| from classes import Connection, RC, BrokenSocketException | |||
| import rules | |||
| from earwigbot import rules | |||
| from earwigbot.classes import Connection, RC, BrokenSocketException | |||
| from earwigbot.config import config | |||
| frontend_conn = None | |||
| logger = logging.getLogger("watcher") | |||
| logger = logging.getLogger("earwigbot.watcher") | |||
| def get_connection(): | |||
| """Return a new Connection() instance with connection information. | |||
| @@ -0,0 +1,44 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's Wiki Toolset | |||
| This is a collection of classes and functions to read from and write to | |||
| Wikipedia and other wiki sites. No connection whatsoever to python-wikitools | |||
| written by Mr.Z-man, other than a similar purpose. We share no code. | |||
| Import the toolset with `from earwigbot import wiki`. | |||
| """ | |||
| import logging as _log | |||
| logger = _log.getLogger("earwigbot.wiki") | |||
| logger.addHandler(_log.NullHandler()) | |||
| from earwigbot.wiki.constants import * | |||
| from earwigbot.wiki.exceptions import * | |||
| from earwigbot.wiki.functions import * | |||
| from earwigbot.wiki.category import Category | |||
| from earwigbot.wiki.page import Page | |||
| from earwigbot.wiki.site import Site | |||
| from earwigbot.wiki.user import User | |||
| @@ -1,6 +1,26 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from wiki.page import Page | |||
| from earwigbot.wiki.page import Page | |||
| class Category(Page): | |||
| """ | |||
| @@ -0,0 +1,55 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's Wiki Toolset: Constants | |||
| This module defines some useful constants: | |||
| * USER_AGENT - our default User Agent when making API queries | |||
| * NS_* - default namespace IDs for easy lookup | |||
| Import with `from earwigbot.wiki import constants` or `from earwigbot.wiki.constants import *`. | |||
| """ | |||
| # Default User Agent when making API queries: | |||
| from platform import python_version as _p | |||
| USER_AGENT = "EarwigBot/0.1-dev (Python/{0}; https://github.com/earwig/earwigbot)".format(_p()) | |||
| # Default namespace IDs: | |||
| NS_MAIN = 0 | |||
| NS_TALK = 1 | |||
| NS_USER = 2 | |||
| NS_USER_TALK = 3 | |||
| NS_PROJECT = 4 | |||
| NS_PROJECT_TALK = 5 | |||
| NS_FILE = 6 | |||
| NS_FILE_TALK = 7 | |||
| NS_MEDIAWIKI = 8 | |||
| NS_MEDIAWIKI_TALK = 9 | |||
| NS_TEMPLATE = 10 | |||
| NS_TEMPLATE_TALK = 11 | |||
| NS_HELP = 12 | |||
| NS_HELP_TALK = 13 | |||
| NS_CATEGORY = 14 | |||
| NS_CATEGORY_TALK = 15 | |||
| NS_SPECIAL = -1 | |||
| NS_MEDIA = -2 | |||
| @@ -1,4 +1,24 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's Wiki Toolset: Exceptions | |||
| @@ -1,4 +1,24 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| """ | |||
| EarwigBot's Wiki Toolset: Misc Functions | |||
| @@ -7,7 +27,7 @@ This module, a component of the wiki package, contains miscellaneous functions | |||
| that are not methods of any class, like get_site(). | |||
| There's no need to import this module explicitly. All functions here are | |||
| automatically available from wiki. | |||
| automatically available from earwigbot.wiki. | |||
| """ | |||
| from cookielib import LWPCookieJar, LoadError | |||
| @@ -17,11 +37,11 @@ from os import chmod, path | |||
| import platform | |||
| import stat | |||
| import config | |||
| from wiki.exceptions import SiteNotFoundError | |||
| from wiki.site import Site | |||
| from earwigbot.config import config | |||
| from earwigbot.wiki.exceptions import SiteNotFoundError | |||
| from earwigbot.wiki.site import Site | |||
| __all__ = ["get_site"] | |||
| __all__ = ["get_site", "add_site", "del_site"] | |||
| _cookiejar = None | |||
| @@ -1,11 +1,31 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from hashlib import md5 | |||
| import re | |||
| from time import gmtime, strftime | |||
| from urllib import quote | |||
| from wiki.exceptions import * | |||
| from earwigbot.wiki.exceptions import * | |||
| class Page(object): | |||
| """ | |||
| @@ -1,4 +1,24 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from cookielib import CookieJar | |||
| from gzip import GzipFile | |||
| @@ -16,12 +36,12 @@ try: | |||
| except ImportError: | |||
| oursql = None | |||
| from wiki import logger | |||
| from wiki.category import Category | |||
| from wiki.constants import * | |||
| from wiki.exceptions import * | |||
| from wiki.page import Page | |||
| from wiki.user import User | |||
| from earwigbot.wiki import logger | |||
| from earwigbot.wiki.category import Category | |||
| from earwigbot.wiki.constants import * | |||
| from earwigbot.wiki.exceptions import * | |||
| from earwigbot.wiki.page import Page | |||
| from earwigbot.wiki.user import User | |||
| class Site(object): | |||
| """ | |||
| @@ -531,7 +551,8 @@ class Site(object): | |||
| large number of edits (ideally, at least one per second), or the result | |||
| may be larger than expected. | |||
| """ | |||
| query = "SELECT NOW() - MAX(rev_timestamp) FROM revision" | |||
| query = """SELECT UNIX_TIMESTAMP() - UNIX_TIMESTAMP(rc_timestamp) FROM | |||
| recentchanges ORDER BY rc_timestamp DESC LIMIT 1""" | |||
| result = list(self.sql_query(query)) | |||
| return result[0][0] | |||
| @@ -1,10 +1,30 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # | |||
| # Copyright (C) 2009, 2010, 2011 by Ben Kurtovic <ben.kurtovic@verizon.net> | |||
| # | |||
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |||
| # of this software and associated documentation files (the "Software"), to deal | |||
| # in the Software without restriction, including without limitation the rights | |||
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
| # copies of the Software, and to permit persons to whom the Software is | |||
| # furnished to do so, subject to the following conditions: | |||
| # | |||
| # The above copyright notice and this permission notice shall be included in | |||
| # all copies or substantial portions of the Software. | |||
| # | |||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
| # SOFTWARE. | |||
| from time import gmtime, strptime | |||
| from wiki.constants import * | |||
| from wiki.exceptions import UserNotFoundError | |||
| from wiki.page import Page | |||
| from earwigbot.wiki.constants import * | |||
| from earwigbot.wiki.exceptions import UserNotFoundError | |||
| from earwigbot.wiki.page import Page | |||
| class User(object): | |||
| """ | |||
| @@ -1,39 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| import unittest | |||
| import support | |||
| from commands.calc import Command | |||
| class TestCalc(support.CommandTestCase): | |||
| def setUp(self): | |||
| super(TestCalc, self).setUp(Command) | |||
| def test_check(self): | |||
| self.assertFalse(self.command.check(self.make_msg("bloop"))) | |||
| self.assertFalse(self.command.check(self.make_join())) | |||
| self.assertTrue(self.command.check(self.make_msg("calc"))) | |||
| self.assertTrue(self.command.check(self.make_msg("CALC", "foo"))) | |||
| def test_ignore_empty(self): | |||
| self.command.process(self.make_msg("calc")) | |||
| self.assertReply("what do you want me to calculate?") | |||
| def test_maths(self): | |||
| tests = [ | |||
| ("2 + 2", "2 + 2 = 4"), | |||
| ("13 * 5", "13 * 5 = 65"), | |||
| ("80 / 42", "80 / 42 = 40/21 (approx. 1.9047619047619047)"), | |||
| ("2/0", "2/0 = undef"), | |||
| ("π", "π = 3.141592653589793238"), | |||
| ] | |||
| for test in tests: | |||
| q = test[0].strip().split() | |||
| self.command.process(self.make_msg("calc", *q)) | |||
| self.assertReply(test[1]) | |||
| if __name__ == "__main__": | |||
| unittest.main(verbosity=2) | |||
| @@ -1,29 +0,0 @@ | |||
| # -*- coding: utf-8 -*- | |||
| import unittest | |||
| import support | |||
| from commands.test import Command | |||
| class TestTest(support.CommandTestCase): | |||
| def setUp(self): | |||
| super(TestTest, self).setUp(Command) | |||
| def test_check(self): | |||
| self.assertFalse(self.command.check(self.make_msg("bloop"))) | |||
| self.assertFalse(self.command.check(self.make_join())) | |||
| self.assertTrue(self.command.check(self.make_msg("test"))) | |||
| self.assertTrue(self.command.check(self.make_msg("TEST", "foo"))) | |||
| def test_process(self): | |||
| def _test(): | |||
| self.command.process(self.make_msg("test")) | |||
| self.assertSaidIn(["Hey \x02Foo\x0F!", "'sup \x02Foo\x0F?"]) | |||
| for i in xrange(64): | |||
| _test() | |||
| if __name__ == "__main__": | |||
| unittest.main(verbosity=2) | |||