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

View File

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

View File

@ -9,28 +9,10 @@ from . import Plugin
class CTCP(Plugin): class CTCP(Plugin):
requires = ['irc3.plugins.async', requires = Plugin.requires + ['irc3.plugins.async']
'irc3.plugins.command']
TIMEOUT = 5 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 @command
async def ping(self, mask: IrcString, target: IrcString, args: Dict): async def ping(self, mask: IrcString, target: IrcString, args: Dict):
"""Sends ping via CTCP to user and sends the time needed """Sends ping via CTCP to user and sends the time needed
@ -70,3 +52,20 @@ class CTCP(Plugin):
%%ver [<nick>] %%ver [<nick>]
""" """
return await self.ctcp('version', mask, args) 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.plugins.command import command
from irc3.utils import IrcString from irc3.utils import IrcString
from . import DatabasePlugin from . import Plugin
class Useless(DatabasePlugin): class Useless(Plugin):
requires = ['irc3.plugins.command',
'bot.plugins.storage']
@command @command
def isup(self, mask: IrcString, target: IrcString, args: Dict): def isup(self, mask: IrcString, target: IrcString, args: Dict):
"""Checks if a address is up or down """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 irc3.utils import IrcString
from . import Plugin 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 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, 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 psycopg2 import Error
from . import DatabasePlugin from . import DatabasePlugin
from ..utils import parse_int from .utils import parse_int
class McManiac(DatabasePlugin): class McManiac(DatabasePlugin):
requires = ['irc3.plugins.command',
'bot.plugins.storage']
@command(options_first=True) @command(options_first=True)
def mcmaniac(self, mask: IrcString, target: IrcString, args: Dict): def mcmaniac(self, mask: IrcString, target: IrcString, args: Dict):
"""Get a random McManiaC or by index. """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 import re
from docopt import Dict from docopt import Dict
from irc3.plugins.command import command from irc3.plugins.command import Commands, command
from irc3.utils import IrcString from irc3.utils import IrcString
from psycopg2 import Error from psycopg2 import Error
from . import DatabasePlugin from . import DatabasePlugin, Bot
from ..utils import parse_int from .utils import parse_int
class Quotes(DatabasePlugin): class Quotes(DatabasePlugin):
requires = ['irc3.plugins.command', def __init__(self, bot: Bot):
'bot.plugins.storage'] super().__init__(bot)
self.guard = bot.get_plugin(Commands).guard
def add_quote(self, mask: IrcString, nick: str, quote: str, channel: IrcString): def add_quote(self, mask: IrcString, nick: str, quote: str, channel: IrcString):
# Parse nick from "<@foobar>" like strings # Parse nick from "<@foobar>" like strings
@ -51,7 +52,7 @@ class Quotes(DatabasePlugin):
quotes quotes
WHERE WHERE
id = ( id = (
SELECT SELECT
id id
FROM FROM
ranked_quotes ranked_quotes

View File

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

View File

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

View File

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

View File

@ -1,17 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
import irc3
import psycopg2 import psycopg2
from psycopg2.extras import DictCursor from psycopg2.extras import DictCursor
from . import Plugin from . import Plugin, Bot
class Storage(Plugin): class Storage(Plugin):
def __init__(self, bot: irc3.IrcBot): def __init__(self, bot: Bot):
super().__init__(bot) super().__init__(bot)
# Create database connection self.bot.sql = self
self.con = psycopg2.connect(os.environ['DATABASE_URI']) 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) 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 irc3.utils import IrcString
from psycopg2 import Error from psycopg2 import Error
from . import DatabasePlugin from . import DatabasePlugin, Bot
class Tell(DatabasePlugin): class Tell(DatabasePlugin):
requires = ['irc3.plugins.command', def __init__(self, bot: Bot):
'bot.plugins.storage']
def __init__(self, bot: irc3.IrcBot):
super().__init__(bot) super().__init__(bot)
self.tell_queue = {} self.tell_queue = {}

View File

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

View File

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

View File

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

View File

@ -8,8 +8,6 @@ from . import Plugin
class Weather(Plugin): class Weather(Plugin):
requires = ['irc3.plugins.command']
URL = 'https://query.yahooapis.com/v1/public/yql?format=json&q=' \ URL = 'https://query.yahooapis.com/v1/public/yql?format=json&q=' \
'select * from weather.forecast where u="c" and woeid in ' \ 'select * from weather.forecast where u="c" and woeid in ' \
'(select woeid from geo.places(1) where text="{}")' '(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 irc3.utils import IrcString
from . import Plugin from . import Plugin
from ..utils import date_from_iso from .utils import date_from_iso
class YouTube(Plugin): class YouTube(Plugin):
requires = ['irc3.plugins.command']
URL = 'https://www.googleapis.com/youtube/v3' URL = 'https://www.googleapis.com/youtube/v3'
API = '{}/videos?part=snippet,statistics,contentDetails'.format(URL) API = '{}/videos?part=snippet,statistics,contentDetails'.format(URL)
SEARCH = '{}/search?part=id'.format(URL) SEARCH = '{}/search?part=id'.format(URL)

View File

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