Huge cleanup and refactoring :>
This commit is contained in:
		| @@ -1,4 +1,56 @@ | ||||
| # -*- coding: utf-8 -*- | ||||
| import os | ||||
| import json | ||||
| import logging | ||||
|  | ||||
| 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 | ||||
|   | ||||
| @@ -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() | ||||
|   | ||||
| @@ -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)) | ||||
| @@ -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': '$', | ||||
| @@ -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) | ||||
| @@ -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 | ||||
| @@ -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, | ||||
| @@ -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. | ||||
| @@ -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 | ||||
| @@ -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 | ||||
| @@ -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 | ||||
| @@ -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>(?:[^/\\]|\\.)*)/' | ||||
| @@ -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 | ||||
| @@ -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) | ||||
| @@ -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 = {} | ||||
| 
 | ||||
| @@ -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() | ||||
| @@ -8,8 +8,6 @@ from . import Plugin | ||||
| 
 | ||||
| 
 | ||||
| class Urban(Plugin): | ||||
|     requires = ['irc3.plugins.command'] | ||||
| 
 | ||||
|     URL = 'https://api.urbandictionary.com/v0/define' | ||||
| 
 | ||||
|     @command | ||||
| @@ -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', | ||||
| @@ -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="{}")' | ||||
| @@ -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) | ||||
| @@ -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", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user