Huge cleanup and refactoring :>

This commit is contained in:
mrhanky 2017-08-22 17:43:48 +02:00
parent 7f5571fc09
commit f33a17038a
No known key found for this signature in database
GPG Key ID: 67D772C481CB41B8
21 changed files with 127 additions and 185 deletions

View File

@ -1,4 +1,56 @@
# -*- coding: utf-8 -*-
import os
import json
import logging
REPO_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
import irc3
from dotenv import load_dotenv
MODULE = __name__
# TODO: ddg
class Bot(irc3.IrcBot):
DEV = 'BOT_DEV' in os.environ
REPO_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CONFIG_DIR = REPO_DIR if DEV else os.path.dirname(REPO_DIR)
@classmethod
def from_json(cls, cfg_file: str = 'config.json', env_file: str = '.env'):
cfg_file = os.path.join(cls.CONFIG_DIR, cfg_file)
env_file = os.path.join(cls.CONFIG_DIR, env_file)
load_dotenv('.env')
with open(cfg_file, 'r') as fp:
conf = json.load(fp)
return cls.from_config(conf)
@irc3.plugin
class BasePlugin:
requires = ['irc3.plugins.command']
def __init__(self, bot: Bot):
self.bot = bot
self.log = logging.getLogger('irc3.{}'.format(self.__class__.__name__.lower()))
class Plugin(BasePlugin):
@classmethod
def reload(cls, old: BasePlugin):
return cls(old.bot)
from .storage import Storage # noqa
class DatabasePlugin(Plugin):
requires = Plugin.requires + ['bot.storage']
def __init__(self, bot: Bot):
super().__init__(bot)
self.db = bot.get_plugin(Storage)
self.con = self.db.con
self.cur = self.db.cur

View File

@ -1,51 +1,8 @@
# -*- coding: utf-8 -*-
import os
import sys
import json
# noinspection PyPackageRequirements
from dotenv import load_dotenv
from irc3 import IrcBot
# This is a development config for use with irc3s server
CFG_DEV = {
'nick': 'nxy',
'autojoins': ['#dev'],
'host': 'localhost',
'port': 6667,
'ssl': False,
'raw': True,
'debug': True,
'verbose': True,
'irc3.plugins.command.masks': {
'*!admin@127.0.0.1': 'all_permissions',
'*': 'view',
}
}
# TODO: ddg
def main(cfg_file):
# Load dotenv from file
load_dotenv('.env')
# Load config from json file
with open(cfg_file, 'r') as fp:
cfg = json.load(fp)
# Apply dev config if env variable is set
if bool(os.environ.get('DEV')):
cfg.update(CFG_DEV)
# If PASSWORD in env set it in config
if 'PASSWORD' in os.environ:
cfg['password'] = os.environ['PASSWORD']
# Start the bot with constructed config
bot = IrcBot.from_config(cfg)
bot.run()
bot.mode(bot.nick, '+R')
from bot import Bot
if __name__ == '__main__':
main(sys.argv[1])
bot = Bot.from_json(*sys.argv[1:])
bot.run()

View File

@ -7,14 +7,13 @@ from docopt import Dict
from irc3.plugins.command import command
from irc3.utils import IrcString
from . import MODULE, Plugin
from .. import REPO_DIR
from . import MODULE, Bot, Plugin
logger = logging.getLogger(__name__)
@command(permission='admin', show_in_help_list=False)
def reload(bot: irc3.IrcBot, mask: IrcString, target: IrcString, args: Dict):
def reload(bot: Bot, mask: IrcString, target: IrcString, args: Dict):
"""Reloads a plugin or the whole bot.
%%reload [<plugin>]
@ -34,9 +33,9 @@ def connected(bot, srv, me, data):
class Admin(Plugin):
def __init__(self, bot: irc3.IrcBot):
def __init__(self, bot: Bot):
super().__init__(bot)
self.repo = Repo(REPO_DIR)
self.repo = Repo(self.bot.REPO_DIR)
@command(permission='all_permissions')
def pull(self, mask: IrcString, target: IrcString, args: Dict):
@ -68,7 +67,10 @@ class Admin(Plugin):
%%join <channel>
"""
self.join_part('join', mask, target, args)
channel = args.get('<channel>', target)
self.bot.join(channel)
self.bot.notice(mask.nick, 'Joined channel {}'.format(channel))
@command(permission='all_permissions')
def part(self, mask: IrcString, target: IrcString, args: Dict):
@ -76,7 +78,10 @@ class Admin(Plugin):
%%part [<channel>]
"""
self.join_part('part', mask, target, args)
channel = args.get('<channel>', target)
self.bot.join(channel)
self.bot.notice(mask.nick, 'Parted channel {}'.format(channel))
@command(permission='all_permissions')
def cycle(self, mask: IrcString, target: IrcString, args: Dict):
@ -84,12 +89,8 @@ class Admin(Plugin):
%%cycle [<channel>]
"""
self.join_part('part', mask, target, args)
self.join_part('join', mask, target, args)
channel = args.get('<channel>', target)
def join_part(self, func: str, mask: IrcString, target: IrcString, args: Dict):
channel = IrcString(args.get('<channel>') or target)
if channel.is_channel:
getattr(self.bot, func)(channel)
self.bot.notice(mask.nick, '{}ed channel {}'.format(func, channel))
self.bot.part(channel)
self.bot.join(channel)
self.bot.notice(mask.nick, 'Cycled channel {}'.format(channel))

View File

@ -8,8 +8,6 @@ from . import Plugin
class Coins(Plugin):
requires = ['irc3.plugins.command']
API_URL = 'https://api.cryptowat.ch/markets/coinbase/{crypto}{currency}/summary'
CURRENCIES = {
'usd': '$',

View File

@ -9,28 +9,10 @@ from . import Plugin
class CTCP(Plugin):
requires = ['irc3.plugins.async',
'irc3.plugins.command']
requires = Plugin.requires + ['irc3.plugins.async']
TIMEOUT = 5
# noinspection PyMethodMayBeStatic
def _ctcp(self, name: str, nick: str, reply: str):
return '\x02[{}]\x02 {}: {}'.format(name.upper(), nick, reply)
async def ctcp(self, name: str, mask: IrcString, args: Dict):
nick = args.get('<nick>', mask.nick)
data = await self.bot.ctcp_async(nick, name.upper(), self.TIMEOUT)
if not data or data['timeout']:
reply = 'timeout'
elif not data['success']:
reply = 'Error: {}'.format(data['reply'])
else:
reply = data['reply']
return self._ctcp(name, nick, reply)
@command
async def ping(self, mask: IrcString, target: IrcString, args: Dict):
"""Sends ping via CTCP to user and sends the time needed
@ -70,3 +52,20 @@ class CTCP(Plugin):
%%ver [<nick>]
"""
return await self.ctcp('version', mask, args)
async def ctcp(self, name: str, mask: IrcString, args: Dict):
nick = args.get('<nick>', mask.nick)
data = await self.bot.ctcp_async(nick, name.upper(), self.TIMEOUT)
if not data or data['timeout']:
reply = 'timeout'
elif not data['success']:
reply = 'Error: {}'.format(data['reply'])
else:
reply = data['reply']
return self._ctcp(name, nick, reply)
# noinspection PyMethodMayBeStatic
def _ctcp(self, name: str, nick: str, reply: str):
return '\x02[{}]\x02 {}: {}'.format(name.upper(), nick, reply)

View File

@ -6,13 +6,10 @@ from docopt import Dict
from irc3.plugins.command import command
from irc3.utils import IrcString
from . import DatabasePlugin
from . import Plugin
class Useless(DatabasePlugin):
requires = ['irc3.plugins.command',
'bot.plugins.storage']
class Useless(Plugin):
@command
def isup(self, mask: IrcString, target: IrcString, args: Dict):
"""Checks if a address is up or down

View File

@ -8,7 +8,7 @@ from irc3.plugins.command import command
from irc3.utils import IrcString
from . import Plugin
from ..utils import re_generator
from .utils import re_generator
GNU_LINUX = """I'd Just Like To Interject For A Moment. What you're referring
to as Linux, is in fact, GNU/Linux, or as I've recently taken to calling it,

View File

@ -6,13 +6,10 @@ from irc3.utils import IrcString
from psycopg2 import Error
from . import DatabasePlugin
from ..utils import parse_int
from .utils import parse_int
class McManiac(DatabasePlugin):
requires = ['irc3.plugins.command',
'bot.plugins.storage']
@command(options_first=True)
def mcmaniac(self, mask: IrcString, target: IrcString, args: Dict):
"""Get a random McManiaC or by index.

View File

@ -1,32 +0,0 @@
# -*- coding: utf-8 -*-
import irc3
from irc3.plugins.command import Commands
MODULE = __name__
@irc3.plugin
class BasePlugin(object):
def __init__(self, bot: irc3.IrcBot):
self.bot = bot
self.log = bot.log
self.guard = bot.get_plugin(Commands).guard
class Plugin(BasePlugin):
@classmethod
def reload(cls, old: BasePlugin):
return cls(old.bot)
# Import the PgSQL storage plugin
from .storage import Storage # noqa
class DatabasePlugin(Plugin):
def __init__(self, bot: irc3.IrcBot):
super().__init__(bot)
# Get PgSQL storage instance and connection + cursor
self.db = bot.get_plugin(Storage)
self.con = self.db.con
self.cur = self.db.cur

View File

@ -2,17 +2,18 @@
import re
from docopt import Dict
from irc3.plugins.command import command
from irc3.plugins.command import Commands, command
from irc3.utils import IrcString
from psycopg2 import Error
from . import DatabasePlugin
from ..utils import parse_int
from . import DatabasePlugin, Bot
from .utils import parse_int
class Quotes(DatabasePlugin):
requires = ['irc3.plugins.command',
'bot.plugins.storage']
def __init__(self, bot: Bot):
super().__init__(bot)
self.guard = bot.get_plugin(Commands).guard
def add_quote(self, mask: IrcString, nick: str, quote: str, channel: IrcString):
# Parse nick from "<@foobar>" like strings
@ -51,7 +52,7 @@ class Quotes(DatabasePlugin):
quotes
WHERE
id = (
SELECT
SELECT
id
FROM
ranked_quotes

View File

@ -9,9 +9,6 @@ from . import DatabasePlugin
class Rape(DatabasePlugin):
requires = ['irc3.plugins.command',
'bot.plugins.storage']
@command
def owe(self, mask: IrcString, target: IrcString, args: Dict):
"""Shows how much a nick owes

View File

@ -8,8 +8,7 @@ from . import DatabasePlugin
class Useless(DatabasePlugin):
requires = ['irc3.plugins.command',
'bot.plugins.storage']
requires = []
@irc3.event(r'^:(?P<mask>\S+) PRIVMSG (?P<target>#\S+) :s/'
r'(?P<search>(?:[^/\\]|\\.)*)/'

View File

@ -10,9 +10,6 @@ from . import DatabasePlugin
class Seen(DatabasePlugin):
requires = ['irc3.plugins.command',
'bot.plugins.storage']
@command
def seen(self, mask: IrcString, target: IrcString, args: Dict):
"""Get last seen date and message for a nick

View File

@ -1,17 +1,15 @@
# -*- coding: utf-8 -*-
import os
import irc3
import psycopg2
from psycopg2.extras import DictCursor
from . import Plugin
from . import Plugin, Bot
class Storage(Plugin):
def __init__(self, bot: irc3.IrcBot):
def __init__(self, bot: Bot):
super().__init__(bot)
# Create database connection
self.bot.sql = self
self.con = psycopg2.connect(os.environ['DATABASE_URI'])
# Create database cursor (with dict factory to access rows by name)
self.cur = self.con.cursor(cursor_factory=DictCursor)

View File

@ -7,14 +7,11 @@ from irc3.plugins.command import command
from irc3.utils import IrcString
from psycopg2 import Error
from . import DatabasePlugin
from . import DatabasePlugin, Bot
class Tell(DatabasePlugin):
requires = ['irc3.plugins.command',
'bot.plugins.storage']
def __init__(self, bot: irc3.IrcBot):
def __init__(self, bot: Bot):
super().__init__(bot)
self.tell_queue = {}

View File

@ -3,7 +3,6 @@ import re
import asyncio
from datetime import datetime
import irc3
from aiocron import crontab
from docopt import Dict
from irc3.plugins.command import command
@ -11,14 +10,11 @@ from irc3.utils import IrcString
from psycopg2 import Error
from psycopg2.extras import DictRow
from . import DatabasePlugin
from . import DatabasePlugin, Bot
class Timer(DatabasePlugin):
requires = ['irc3.plugins.command',
'bot.plugins.storage']
def __init__(self, bot: irc3.IrcBot):
def __init__(self, bot: Bot):
super().__init__(bot)
self.timers = set()
self.set_timers()

View File

@ -8,8 +8,6 @@ from . import Plugin
class Urban(Plugin):
requires = ['irc3.plugins.command']
URL = 'https://api.urbandictionary.com/v0/define'
@command

View File

@ -9,22 +9,17 @@ from irc3.utils import IrcString
from psycopg2 import Error
from . import DatabasePlugin
from ..utils import re_generator
from .utils import re_generator
class Useless(DatabasePlugin):
requires = ['irc3.plugins.command',
'bot.plugins.storage']
RAINBOW = (5, 7, 8, 9, 3, 10, 12, 2, 6, 13)
WOAH = (
'woah',
'woah indeed',
'woah woah woah!',
'keep your woahs to yourself',
)
ISPS = (
't-ipconnect',
'telefonica',
@ -32,7 +27,6 @@ class Useless(DatabasePlugin):
'kabel',
'unity-media',
)
GENDERS = (
'male',
'female',

View File

@ -8,8 +8,6 @@ from . import Plugin
class Weather(Plugin):
requires = ['irc3.plugins.command']
URL = 'https://query.yahooapis.com/v1/public/yql?format=json&q=' \
'select * from weather.forecast where u="c" and woeid in ' \
'(select woeid from geo.places(1) where text="{}")'

View File

@ -9,12 +9,10 @@ from irc3.plugins.command import command
from irc3.utils import IrcString
from . import Plugin
from ..utils import date_from_iso
from .utils import date_from_iso
class YouTube(Plugin):
requires = ['irc3.plugins.command']
URL = 'https://www.googleapis.com/youtube/v3'
API = '{}/videos?part=snippet,statistics,contentDetails'.format(URL)
SEARCH = '{}/search?part=id'.format(URL)

View File

@ -11,22 +11,22 @@
"flood_rate_delay": 1,
"includes": [
"irc3.plugins.uptime",
"bot.plugins.admin",
"bot.plugins.coins",
"bot.plugins.ctcp",
"bot.plugins.isup",
"bot.plugins.linux",
"bot.plugins.mcmaniac",
"bot.plugins.quotes",
"bot.plugins.rape",
"bot.plugins.regex",
"bot.plugins.seen",
"bot.plugins.tell",
"bot.plugins.timer",
"bot.plugins.urban",
"bot.plugins.useless",
"bot.plugins.weather",
"bot.plugins.youtube"
"bot.admin",
"bot.coins",
"bot.ctcp",
"bot.isup",
"bot.linux",
"bot.mcmaniac",
"bot.quotes",
"bot.rape",
"bot.regex",
"bot.seen",
"bot.tell",
"bot.timer",
"bot.urban",
"bot.useless",
"bot.weather",
"bot.youtube"
],
"irc3.plugins.command": {
"guard": "irc3.plugins.command.mask_based_policy",