@@ -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) |