From 8201f2c3c4371ea0cb4e29f55606d4c71c6e8e6c Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 21:44:28 +0100 Subject: [PATCH 01/65] Added stuff to gitignore Pycache will be ignored recursively. Added rest of IJ ignore bits and pieces. Fixed something else and added ST3 stuff you don't want upstream. --- .gitignore | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 916052a..e59dfb0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,15 @@ # Byte-compiled / optimized / DLL files -__pycache__/ + +# Recurse +**/__pycache__ + *.py[cod] *$py.class # C extensions *.so +# Object files +*.o # Distribution / packaging .Python @@ -105,4 +110,21 @@ venv.bak/ /src/config/Config.json /src/config/PrivateConfig.json -.idea/ \ No newline at end of file + +# IntelliJ stuff +.idea/ +*.iml + +# Sublime stuff +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +# *.sublime-project + From f46753ed306232a679a79b1987af7b063fd68d68 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 22:08:01 +0100 Subject: [PATCH 02/65] Update run.py --- run.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/run.py b/run.py index dffb7a8..a6723d3 100644 --- a/run.py +++ b/run.py @@ -6,12 +6,15 @@ import asyncio import discord from discord.ext import commands import json +import logging import traceback import random # Import custom files from src.config.config import LoadConfig +logging.basicConfig(level='INFO') + # If uvloop is installed, change to that eventloop policy as it # is more efficient try: @@ -19,34 +22,36 @@ try: asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) del uvloop except BaseException as ex: - print(f'Could not load uvloop. {type(ex).__name__}: {ex};', - 'reverting to default impl.') + logging.warning(f'Could not load uvloop. {type(ex).__name__}: {ex};', + 'reverting to default impl.')) else: - print(f'Using uvloop for asyncio event loop policy.') + logging.info(print(f'Using uvloop for asyncio event loop policy.')) # Bot Class -class SebiMachine(commands.Bot, LoadConfig): +class SebiMachine(commands.Bot, LoadConfig, Loggable): """This discord is dedicated to http://www.discord.gg/GWdhBSp""" def __init__(self): # Initialize and attach config / settings LoadConfig.__init__(self) commands.Bot.__init__(self, command_prefix=self.defaultprefix) - # Load plugins # Add your cog file name in this list with open('cogs.txt', 'r') as cog_file: cogs = cog_file.readlines() + for cog in cogs: - print(f'Loaded:{cog}') + # Could this just be replaced with `strip()`? cog = cog.replace('\n', '') self.load_extension(f'src.cogs.{cog}') + self.logger.info(f'Loaded: {cog}') + async def on_ready(self): """On ready function""" if self.maintenance: - print('MAINTENANCE ACTIVE') + self.logger.warning('MAINTENANCE ACTIVE') async def on_command_error(self, ctx, error): """ @@ -79,5 +84,5 @@ if __name__ == '__main__': # Make sure the key stays private. with open('src/config/PrivateConfig.json') as fp: PrivateConfig = json.load(fp) - fp.close() + client.run(PrivateConfig["bot-key"]) From f898302d97c10a139cb392d8c9ee2f085b5d0c64 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 22:16:03 +0100 Subject: [PATCH 03/65] Create loggable --- src/shared_libs/loggable | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/shared_libs/loggable diff --git a/src/shared_libs/loggable b/src/shared_libs/loggable new file mode 100644 index 0000000..10e9e59 --- /dev/null +++ b/src/shared_libs/loggable @@ -0,0 +1,21 @@ +#!/usr/bin/env python3.6 +# -*- coding: utf-8 -*- +""" +Neko404NotFound 2018, MIT + +A mixin class that injects a suitably named logger into class scope +at runtime. + +Chosen to make this a slotted class, which means (as far as I can remember) +that it is not suitable to be made into an abc.ABC class. Slots will +enable derived slotted classes to be a bit more efficient at runtime and +boast faster lookups. +""" +import logging + + +class Loggable: + __slots__ = ('logger',) + + def __init_subclass__(cls, **_): + cls.logger = logging.getLogger(cls.__qualname__) From 83cee5c1a660ec210847761f539d0791981eff67 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 22:16:43 +0100 Subject: [PATCH 04/65] Rename loggable to loggable.py --- src/shared_libs/{loggable => loggable.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/shared_libs/{loggable => loggable.py} (100%) diff --git a/src/shared_libs/loggable b/src/shared_libs/loggable.py similarity index 100% rename from src/shared_libs/loggable rename to src/shared_libs/loggable.py From 88d94529ad72c731c091fdaf1edc683659a9fd22 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 22:21:05 +0100 Subject: [PATCH 05/65] Update run.py --- run.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/run.py b/run.py index a6723d3..3c16799 100644 --- a/run.py +++ b/run.py @@ -12,6 +12,7 @@ import random # Import custom files from src.config.config import LoadConfig +from src.shared_libs.loggable import Loggable logging.basicConfig(level='INFO') @@ -23,9 +24,9 @@ try: del uvloop except BaseException as ex: logging.warning(f'Could not load uvloop. {type(ex).__name__}: {ex};', - 'reverting to default impl.')) + 'reverting to default impl.') else: - logging.info(print(f'Using uvloop for asyncio event loop policy.')) + logging.info(f'Using uvloop for asyncio event loop policy.') # Bot Class @@ -47,11 +48,9 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): self.load_extension(f'src.cogs.{cog}') self.logger.info(f'Loaded: {cog}') - async def on_ready(self): """On ready function""" - if self.maintenance: - self.logger.warning('MAINTENANCE ACTIVE') + self.maintenance and self.logger.warning('MAINTENANCE ACTIVE') async def on_command_error(self, ctx, error): """ @@ -76,7 +75,12 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): joke = random.choice(jokes) fmt = f'**`{self.defaultprefix}{ctx.command}`**\n{joke}\n\n**{type(error).__name__}:**:\n```py\n{tb}\n```' simple_fmt = f'**`{self.defaultprefix}{ctx.command}`**\n{joke}\n\n**{type(error).__name__}:**:\n**`{error}`**' - await ctx.send(fmt) + + # Stops the error handler erroring. + try: + await ctx.send(fmt) + except: + traceback.print_exc() if __name__ == '__main__': From 4ce771d0eaaa0653d451bac8481d155d6d8ad117 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 22:22:06 +0100 Subject: [PATCH 06/65] Init files (#10) * Create __init__.py * Create __init__.py * Update __init__.py * Update __init__.py * Create __init__.py * Create __init__.py --- src/__init__.py | 15 +++++++++++++++ src/cogs/__init__.py | 2 ++ src/config/__init__.py | 2 ++ src/shared_libs/__init__.py | 2 ++ 4 files changed, 21 insertions(+) create mode 100644 src/__init__.py create mode 100644 src/cogs/__init__.py create mode 100644 src/config/__init__.py create mode 100644 src/shared_libs/__init__.py diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..0f704d9 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3.6 +# -*- coding: utf-8 -*- +""" +Sebi-Machine. +""" + +__author__ = 'Annihilator708' +# TODO: add yourselves here. I can't remember everyones handles. +__contributors__ = (__author__, 'Neko404NotFound',) +__license__ = 'MIT' +__title__ = 'Sebi-Machine' +__version__ = 'tbd' + +__repository__ = f'https://github.com/{__author__}/{__title__}' +__url__ = __repository__ diff --git a/src/cogs/__init__.py b/src/cogs/__init__.py new file mode 100644 index 0000000..ed9dcc7 --- /dev/null +++ b/src/cogs/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3.6 +# -*- coding: utf-8 -*- diff --git a/src/config/__init__.py b/src/config/__init__.py new file mode 100644 index 0000000..ed9dcc7 --- /dev/null +++ b/src/config/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3.6 +# -*- coding: utf-8 -*- diff --git a/src/shared_libs/__init__.py b/src/shared_libs/__init__.py new file mode 100644 index 0000000..ed9dcc7 --- /dev/null +++ b/src/shared_libs/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3.6 +# -*- coding: utf-8 -*- From c7f77241e281e6433e6890dcd88afb7042d385ec Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 22:53:18 +0100 Subject: [PATCH 07/65] Didn't know a good branch name... --- run.py => src/__main__.py | 48 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) rename run.py => src/__main__.py (66%) diff --git a/run.py b/src/__main__.py similarity index 66% rename from run.py rename to src/__main__.py index 3c16799..16b076e 100644 --- a/run.py +++ b/src/__main__.py @@ -1,21 +1,27 @@ # !/usr/bin/python # -*- coding: utf8 -*- +""" +App entry point. -# Import packages +Something meaningful here, eventually. +""" import asyncio -import discord -from discord.ext import commands import json import logging -import traceback import random +import traceback + +import discord +from discord.ext import commands -# Import custom files from src.config.config import LoadConfig from src.shared_libs.loggable import Loggable + +# Init logging to output on INFO level to stderr. logging.basicConfig(level='INFO') + # If uvloop is installed, change to that eventloop policy as it # is more efficient try: @@ -23,13 +29,14 @@ try: asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) del uvloop except BaseException as ex: - logging.warning(f'Could not load uvloop. {type(ex).__name__}: {ex};', - 'reverting to default impl.') + logging.warning(f'Could not load uvloop. {type(ex).__qualname__}: {ex};', + 'reverting to default impl.') else: logging.info(f'Using uvloop for asyncio event loop policy.') # Bot Class +# Might be worth moving this to it's own file? class SebiMachine(commands.Bot, LoadConfig, Loggable): """This discord is dedicated to http://www.discord.gg/GWdhBSp""" def __init__(self): @@ -39,13 +46,13 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): # Load plugins # Add your cog file name in this list - with open('cogs.txt', 'r') as cog_file: + with open('cogs.txt') as cog_file: cogs = cog_file.readlines() for cog in cogs: # Could this just be replaced with `strip()`? cog = cog.replace('\n', '') - self.load_extension(f'src.cogs.{cog}') + self.load_extension(f'{__name__}.cogs.{cog}') self.logger.info(f'Loaded: {cog}') async def on_ready(self): @@ -59,16 +66,18 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): error : Exception """ jokes = ["I\'m a bit tipsy, I took to many screenshots...", - "I am rushing to the 24/7 store to get myself anti-bug spray...", - "Organizing turtle race...", - "There is no better place then 127.0.0.1...", - "Recycling Hex Decimal...", - "No worry, I get fixed :^)...", - "R.I.P, press F for respect...", - "The bug repellent dit not work...", - "You found a bug in the program. Unfortunately the joke did not fit here, better luck next time..."] + "I am rushing to the 24/7 store to get myself anti-bug spray...", + "Organizing turtle race...", + "There is no better place then 127.0.0.1...", + "Recycling Hex Decimal...", + "No worry, I get fixed :^)...", + "R.I.P, press F for respect...", + "The bug repellent dit not work...", + "You found a bug in the program. Unfortunately the joke did not fit here, better luck next time..."] - # catch error + # CommandErrors triggered by other propagating errors tend to get wrapped. This means + # if we have a cause, we should probably consider unwrapping that so we get a useful + # message. error = error.__cause__ or error tb = traceback.format_exception(type(error), error, error.__traceback__, limit=2, chain=False) tb = ''.join(tb) @@ -86,7 +95,8 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): if __name__ == '__main__': client = SebiMachine() # Make sure the key stays private. - with open('src/config/PrivateConfig.json') as fp: + # I am 99% certain this is valid! + with open(f'{__name__}/config/PrivateConfig.json') as fp: PrivateConfig = json.load(fp) client.run(PrivateConfig["bot-key"]) From 0a66e5d78fd916745f2eec6cb5fb658848cd6d2c Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 22:55:42 +0100 Subject: [PATCH 08/65] Updated docker file Hope I did this right? Googled "docking" and I am not gonna do that again any time soon... --- dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dockerfile b/dockerfile index 3cce367..87c38ca 100644 --- a/dockerfile +++ b/dockerfile @@ -16,4 +16,4 @@ RUN python3.6 -m pip install --upgrade pip && \ python3.6 -m pip install -r requirements.txt && \ python3.6 -m pip install -U git+https://github.com/Rapptz/discord.py@rewrite#egg=discord.py[voice] -cmd ["python3.6","run.py"] +cmd ["python3.6","-m","src"] From 54d4577567c12f8407e5afcfb7dc448b700f4153 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 22:56:15 +0100 Subject: [PATCH 09/65] Moved cogs into your `src` --- cogs.txt => src/cogs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename cogs.txt => src/cogs.txt (88%) diff --git a/cogs.txt b/src/cogs.txt similarity index 88% rename from cogs.txt rename to src/cogs.txt index 9529ab0..cbb47e8 100644 --- a/cogs.txt +++ b/src/cogs.txt @@ -2,4 +2,4 @@ example contributors code git -fun \ No newline at end of file +fun From b4040956f19b58176b1da2b5420a2044c60a42a8 Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Tue, 22 May 2018 13:58:45 -0800 Subject: [PATCH 10/65] Moved avatar.png --- avatar.png => src/avatar.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename avatar.png => src/avatar.png (100%) diff --git a/avatar.png b/src/avatar.png similarity index 100% rename from avatar.png rename to src/avatar.png From 1da3add7d3ca937758c87401a97574e23a0071a9 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 23:08:44 +0100 Subject: [PATCH 11/65] Create ioutils.py --- src/shared_libs/ioutils.py | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/shared_libs/ioutils.py diff --git a/src/shared_libs/ioutils.py b/src/shared_libs/ioutils.py new file mode 100644 index 0000000..0d6b22b --- /dev/null +++ b/src/shared_libs/ioutils.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3.6 +# -*- coding: utf-8 -*- +""" +IO stuff. +""" +import inspect +import os + + +__all__ = ('in_here',) + + +def in_here(*path_bits: str, stack_depth: int=0) -> str: + """ + A somewhat voodooish and weird piece of code. This enables us to + directly refer to a file in the same directory as the code that + calls this method, without any due regard for where in the file + system tree it is. + + Apart from that, this will behave just like os.path.join, meaning + that varaidic strings will be joined with the appropriate + directory separator for the current platform. + + This works by inspecting the stack frame for the caller. + If you are planning on nesting this call in another utility and wish + for the stack to refer to that caller, you should increment + the ``stack_depth`` arg for each nested call you make. By default, + you can ignore this and it will default to 0. + """ + try: + frame = inspect.stack()[1 + nested_by] + except IndexError: + raise RuntimeError('Could not find a stack record. Interpreter has ' + 'been shot.') + else: + module = inspect.getmodule(frame[0]) + assert hasattr(module, '__file__'), 'No __file__ attr, whelp.' + + file = module.__file__ + + dir_name = os.path.dirname(file) + abs_dir_name = os.path.abspath(dir_name) + + return os.path.join(abs_dir_name, *paths) + From 1b1edc14a486452a5a28d6be7894519330716b3d Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 23:09:03 +0100 Subject: [PATCH 12/65] Update loggable.py --- src/shared_libs/loggable.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shared_libs/loggable.py b/src/shared_libs/loggable.py index 10e9e59..a32b3b3 100644 --- a/src/shared_libs/loggable.py +++ b/src/shared_libs/loggable.py @@ -14,6 +14,9 @@ boast faster lookups. import logging +__all__ = ('Loggable',) + + class Loggable: __slots__ = ('logger',) From 552fa1ba93c5edebae4232fbcbc9f446f5e394a6 Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Wed, 23 May 2018 00:09:21 +0200 Subject: [PATCH 13/65] Extend repl --- src/cogs/code.py | 125 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 10 deletions(-) diff --git a/src/cogs/code.py b/src/cogs/code.py index 69bea4d..4c51f5b 100644 --- a/src/cogs/code.py +++ b/src/cogs/code.py @@ -1,5 +1,7 @@ from discord.ext import commands import traceback +import discord +import inspect import textwrap from contextlib import redirect_stdout import io @@ -45,6 +47,7 @@ class REPL: if ctx.author.id not in self.bot.ownerlist: return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) + if body is None: return await ctx.send( 'Please, use\n' @@ -73,12 +76,13 @@ class REPL: exec(to_compile, env) except SyntaxError as e: try: - msg = await ctx.send(f'```py\n{self.get_syntax_error(e)}\n```') + await ctx.send(f'```py\n{self.get_syntax_error(e)}\n```') except Exception as e: - error = [self.get_syntax_error(e)[i:i+2000] for i in range(0, len(self.get_syntax_error(e)), 2000)] + error = [self.get_syntax_error(e)[i:i + 2000] for i in + range(0, len(self.get_syntax_error(e)), 2000)] for i in error: - msg = await ctx.send(f'```py\n{i}\n```') + await ctx.send(f'```py\n{i}\n```') func = env['func'] try: @@ -87,40 +91,141 @@ class REPL: except Exception as e: value = stdout.getvalue() try: - msg = await ctx.send(f'```py\n{value}{traceback.format_exc()}\n```') + await ctx.send(f'```py\n{value}{traceback.format_exc()}\n```') except Exception as e: error = [value[i:i + 2000] for i in range(0, len(value), 2000)] for i in error: await ctx.send(f'```py\n{i}\n```') - tracebackerror = [traceback.format_exc()[i:i + 2000] for i in range(0, len(traceback.format_exc()), 2000)] + tracebackerror = [traceback.format_exc()[i:i + 2000] for i in + range(0, len(traceback.format_exc()), 2000)] for i in tracebackerror: - msg = await ctx.send(f'```py\n{i}\n```') + await ctx.send(f'```py\n{i}\n```') else: value = stdout.getvalue() if ret is None: if value: try: - msg = await ctx.send(f'```py\n{value}\n```') + await ctx.send(f'```py\n{value}\n```') except Exception as e: code = [value[i:i + 1980] for i in range(0, len(value), 1980)] for i in code: - msg = await ctx.send(f'```py\n{i}\n```') + await ctx.send(f'```py\n{i}\n```') else: self._last_result = ret try: code = [value[i:i + 1980] for i in range(0, len(value), 1980)] for i in code: - msg = await ctx.send(f'```py\n{i}\n```') + await ctx.send(f'```py\n{i}\n```') except Exception as e: code = [value[i:i + 1980] for i in range(0, len(value), 1980)] for i in code: await ctx.send(f'```py\n{i}\n```') modifyd_ret = [ret[i:i + 1980] for i in range(0, len(ret), 1980)] for i in modifyd_ret: - msg = await ctx.send(f'```py\n{i}\n```') + await ctx.send(f'```py\n{i}\n```') + @commands.command(hidden=True) + async def repl(self, ctx): + """ + Start a interactive python shell in chat. + Only the owner of this bot can use this command. + + Usage: + - repl < python code > + Example: + - repl print(205554) + """ + if ctx.author.id not in self.bot.ownerlist: + return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) + + msg = ctx.message + + variables = { + 'ctx': ctx, + 'bot': self.bot, + 'message': msg, + 'server': msg.guild, + 'channel': msg.channel, + 'author': msg.author, + '_': None, + } + + if msg.channel.id in self.sessions: + msg = await ctx.send('Already running a REPL session in this channel. Exit it with `quit`.') + + self.sessions.add(msg.channel.id) + + await ctx.send('Enter code to execute or evaluate. `exit()` or `quit` to exit.') + + while True: + response = await self.bot.wait_for('message', check=lambda m: m.content.startswith( + '`') and m.author == ctx.author and m.channel == ctx.channel) + + cleaned = self.cleanup_code(response.content) + + if cleaned in ('quit', 'exit', 'exit()'): + msg = await ctx.send('Exiting.') + self.sessions.remove(msg.channel.id) + return + + executor = exec + if cleaned.count('\n') == 0: + # single statement, potentially 'eval' + try: + code = compile(cleaned, '', 'eval') + except SyntaxError: + pass + else: + executor = eval + + if executor is exec: + try: + code = compile(cleaned, '', 'exec') + except SyntaxError as e: + try: + await ctx.send(f'```Python\n{self.get_syntax_error(e)}\n```') + except Exception as e: + error = [self.get_syntax_error(e)[i:i + 2000] for i in + range(0, len(self.get_syntax_error(e)), 2000)] + for i in error: + await ctx.send(f'```Python\n{i}\n```') + + variables['message'] = response + fmt = None + stdout = io.StringIO() + try: + with redirect_stdout(stdout): + result = executor(code, variables) + if inspect.isawaitable(result): + result = await result + + except Exception as e: + value = stdout.getvalue() + await ctx.send(f'```Python\n{value}{traceback.format_exc()}\n```') + continue + else: + value = stdout.getvalue() + if result is not None: + fmt = '{}{}'.format(value, result) + variables['_'] = result + elif value: + fmt = value + + try: + if fmt is not None: + if len(fmt) > 1980: + code = [fmt[i:i + 1980] for i in range(0, len(fmt), 1980)] + for i in code: + await ctx.send(f'```py\n{i}\n```') + else: + await ctx.send(fmt) + + except discord.Forbidden: + pass + except discord.HTTPException as e: + await ctx.send(f'Unexpected error: `{e}`') def setup(bot): bot.add_cog(REPL(bot)) \ No newline at end of file From ad750c947c66052768f82a3c068ecf0579e37a2c Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 23:09:47 +0100 Subject: [PATCH 14/65] Update __main__.py --- src/__main__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/__main__.py b/src/__main__.py index 16b076e..468225c 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -16,6 +16,7 @@ from discord.ext import commands from src.config.config import LoadConfig from src.shared_libs.loggable import Loggable +from src.shared_libs.ioutil import in_here # Init logging to output on INFO level to stderr. @@ -46,7 +47,7 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): # Load plugins # Add your cog file name in this list - with open('cogs.txt') as cog_file: + with open(in_here('cogs.txt')) as cog_file: cogs = cog_file.readlines() for cog in cogs: From 2c033518366fec92bbc0eb91b73244ef6a80986f Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 23:13:48 +0100 Subject: [PATCH 15/65] Spelling mistake? BAKA! --- src/shared_libs/ioutils.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/shared_libs/ioutils.py b/src/shared_libs/ioutils.py index 0d6b22b..c0642fb 100644 --- a/src/shared_libs/ioutils.py +++ b/src/shared_libs/ioutils.py @@ -10,7 +10,7 @@ import os __all__ = ('in_here',) -def in_here(*path_bits: str, stack_depth: int=0) -> str: +def in_here(first_path_bit: str, *path_bits: str, stack_depth: int=0) -> str: """ A somewhat voodooish and weird piece of code. This enables us to directly refer to a file in the same directory as the code that @@ -26,7 +26,16 @@ def in_here(*path_bits: str, stack_depth: int=0) -> str: for the stack to refer to that caller, you should increment the ``stack_depth`` arg for each nested call you make. By default, you can ignore this and it will default to 0. - """ + + :param first_path_bit: the initial path bit to operate with. This is + required. + :param path_bits: additional bits of path to construct relative to here. + These are entirely optional. + :param stack_depth: optional, defaults to 0. How many nested calls + we expect this to be called in. Affects the relative directory + that is used. + :returns: the absolute path to the given relative path provided. + """ try: frame = inspect.stack()[1 + nested_by] except IndexError: @@ -34,12 +43,12 @@ def in_here(*path_bits: str, stack_depth: int=0) -> str: 'been shot.') else: module = inspect.getmodule(frame[0]) - assert hasattr(module, '__file__'), 'No __file__ attr, whelp.' + assert hasattr(module, '__file__'), 'No `__file__\' attr, welp.' file = module.__file__ dir_name = os.path.dirname(file) abs_dir_name = os.path.abspath(dir_name) - return os.path.join(abs_dir_name, *paths) - + pathish = os.path.join(abs_dir_name, first_path_bit, *path_bits) + return pathish From 5261a520028e2b1b9ffd6ff50e00aed20b05e907 Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Wed, 23 May 2018 00:16:56 +0200 Subject: [PATCH 16/65] Add kick command --- src/cogs/contributors.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/cogs/contributors.py b/src/cogs/contributors.py index f546128..4a888a6 100644 --- a/src/cogs/contributors.py +++ b/src/cogs/contributors.py @@ -2,7 +2,7 @@ # -*- coding: -*- from discord.ext import commands -import os +import discord import traceback class Upload: @@ -82,11 +82,28 @@ class Upload: await ctx.send(f'Loaded `{extension}`.') @commands.command() - async def err(self, ctx): - """triggers error to test traceback""" - await ctx.send(a) + async def kick(self, ctx, member: discord.Member = None): + """ + Kick a discord member from your server. + Only contributors can use this command + Usage: + - kick + """ + await ctx.trigger_typing() + if ctx.author.id not in self.bot.ownerlist: + return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) + + if member is None: + await ctx.send('Are you sure you are capable of this command?') + try: + await member.kick() + await ctx.send(f'You kicked **`{member.name}`** from **`{ctx.guild.name}`**') + + except Exception as e: + await ctx.send('You may not use this command you do not have permission in server:\n\n**`{ctx.guild.name}`**' + f'\n\n```py\n{e}\n```') def setup(bot): bot.add_cog(Upload(bot)) \ No newline at end of file From f2fa13162833a60597ea0667ddd1443a85b1627a Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Tue, 22 May 2018 23:34:57 +0100 Subject: [PATCH 17/65] >.> --- src/shared_libs/ioutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared_libs/ioutils.py b/src/shared_libs/ioutils.py index c0642fb..284f156 100644 --- a/src/shared_libs/ioutils.py +++ b/src/shared_libs/ioutils.py @@ -37,7 +37,7 @@ def in_here(first_path_bit: str, *path_bits: str, stack_depth: int=0) -> str: :returns: the absolute path to the given relative path provided. """ try: - frame = inspect.stack()[1 + nested_by] + frame = inspect.stack()[1 + stack_depth] except IndexError: raise RuntimeError('Could not find a stack record. Interpreter has ' 'been shot.') From 54923788c74ff431e68c4319c438c730508501a7 Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Wed, 23 May 2018 01:08:11 +0200 Subject: [PATCH 18/65] Fix for logging --- .gitignore | 5 ++++- src/__main__.py | 18 ++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 941ff36..e9d30ac 100644 --- a/.gitignore +++ b/.gitignore @@ -109,4 +109,7 @@ venv.bak/ .mypy_cache/ /src/config/Config.json -/src/config/PrivateConfig.json \ No newline at end of file +/src/config/PrivateConfig.json + +# Ignore dockerfiles +docker-compose.yml \ No newline at end of file diff --git a/src/__main__.py b/src/__main__.py index 468225c..8b4ecd8 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -16,7 +16,7 @@ from discord.ext import commands from src.config.config import LoadConfig from src.shared_libs.loggable import Loggable -from src.shared_libs.ioutil import in_here +from src.shared_libs.ioutils import in_here # Init logging to output on INFO level to stderr. @@ -53,7 +53,7 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): for cog in cogs: # Could this just be replaced with `strip()`? cog = cog.replace('\n', '') - self.load_extension(f'{__name__}.cogs.{cog}') + self.load_extension(f'src.cogs.{cog}') self.logger.info(f'Loaded: {cog}') async def on_ready(self): @@ -93,11 +93,9 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): traceback.print_exc() -if __name__ == '__main__': - client = SebiMachine() - # Make sure the key stays private. - # I am 99% certain this is valid! - with open(f'{__name__}/config/PrivateConfig.json') as fp: - PrivateConfig = json.load(fp) - - client.run(PrivateConfig["bot-key"]) +client = SebiMachine() +# Make sure the key stays private. +# I am 99% certain this is valid! +with open(in_here('config', 'PrivateConfig.json')) as fp: + PrivateConfig = json.load(fp) +client.run(PrivateConfig["bot-key"]) From 6bcae420806542d659155599d5038cdfaff8540c Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Wed, 23 May 2018 12:04:31 +1200 Subject: [PATCH 19/65] Styling ping command --- src/cogs/example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cogs/example.py b/src/cogs/example.py index de1c1da..4c62f25 100644 --- a/src/cogs/example.py +++ b/src/cogs/example.py @@ -17,7 +17,7 @@ class CogName: now = ctx.message.created_at msg = await ctx.send('Pong') sub = msg.created_at - now - await msg.edit(content=f'Pong, {sub.total_seconds() * 1000}') + await msg.edit(content=f'🏓Pong, **{sub.total_seconds() * 1000}**') def setup(bot): From 523485461f32a150cca828988be1350ada781c53 Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Wed, 23 May 2018 12:07:57 +1200 Subject: [PATCH 20/65] Units added to ping --- src/cogs/example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cogs/example.py b/src/cogs/example.py index 4c62f25..4a73cbc 100644 --- a/src/cogs/example.py +++ b/src/cogs/example.py @@ -17,7 +17,7 @@ class CogName: now = ctx.message.created_at msg = await ctx.send('Pong') sub = msg.created_at - now - await msg.edit(content=f'🏓Pong, **{sub.total_seconds() * 1000}**') + await msg.edit(content=f'🏓Pong, **{sub.total_seconds() * 1000}ms**') def setup(bot): From 88f2c4d0872f9c1a4cc86e61f921bd327105aa8b Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Wed, 23 May 2018 20:32:20 +1200 Subject: [PATCH 21/65] Development (#16) * heroku yml * owner list from env * bot key from enviroment var * app json * heroku button * again * Update README.md * fixing syntax hopefully * error fixing * enviroments added * opsy forgot a } * trying again * Update app.json * Update app.json * Update app.json * Update app.json * Update app.json * Update __main__.py * Update app.json * Update __main__.py * removed prints --- README.md | 2 +- app.json | 15 +++++++++++++++ heroku.yml | 3 +++ src/__main__.py | 4 ++++ src/config/config.py | 6 +++++- 5 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 app.json create mode 100644 heroku.yml diff --git a/README.md b/README.md index eea3036..0e1e939 100644 --- a/README.md +++ b/README.md @@ -60,4 +60,4 @@ If you are stuck in any way shape or form you can always contact anyone who work - http://discord.gg/GWdhBSp - http://chillout.ueuo.com - http://trello.com/b/x02goBbW/sebis-bot-tutorial-roadmap - +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Raatty/Sebi-Machine/tree/development) diff --git a/app.json b/app.json new file mode 100644 index 0000000..d5d8b35 --- /dev/null +++ b/app.json @@ -0,0 +1,15 @@ +{ + "name":"sebi-machine", + "stack":"container", + "env": { + + "ownerlist": { + "description": "comma seperated list of owner ids", + "required": true + }, + "botkey": { + "description": "bot token", + "required": true + } + } +} diff --git a/heroku.yml b/heroku.yml new file mode 100644 index 0000000..2d41892 --- /dev/null +++ b/heroku.yml @@ -0,0 +1,3 @@ +build: + docker: + worker: dockerfile diff --git a/src/__main__.py b/src/__main__.py index 8b4ecd8..e6b15ea 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -10,6 +10,7 @@ import json import logging import random import traceback +import os import discord from discord.ext import commands @@ -98,4 +99,7 @@ client = SebiMachine() # I am 99% certain this is valid! with open(in_here('config', 'PrivateConfig.json')) as fp: PrivateConfig = json.load(fp) +if PrivateConfig["bot-key"] == '': + PrivateConfig["bot-key"] = os.getenv('botkey') + client.run(PrivateConfig["bot-key"]) diff --git a/src/config/config.py b/src/config/config.py index b6f5acf..fe00265 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -3,6 +3,7 @@ import json import discord +import os class LoadConfig: """ @@ -14,7 +15,10 @@ class LoadConfig: self.config = json.load(fp) # Initialize config - self.ownerlist = self.config["ownerlist"] + if self.config["ownerlist"] != []: + self.ownerlist = self.config["ownerlist"] + else: + self.ownerlist = [int(i) for i in os.getenv('ownerlist').split(',')] self.defaultprefix = self.config["prefix"] self.version = self.config["version"] self.display_name = self.config["display_name"] From bc8e8d62de4582f31c834773f432fe3c454df780 Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Wed, 23 May 2018 20:33:11 +1200 Subject: [PATCH 22/65] updated link to point to this repo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e1e939..b07651e 100644 --- a/README.md +++ b/README.md @@ -60,4 +60,4 @@ If you are stuck in any way shape or form you can always contact anyone who work - http://discord.gg/GWdhBSp - http://chillout.ueuo.com - http://trello.com/b/x02goBbW/sebis-bot-tutorial-roadmap -[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Raatty/Sebi-Machine/tree/development) +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Annihilator708/Sebi-Machine/tree/development) From 437da83d86fab917c0791689c03441469a3568c5 Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Wed, 23 May 2018 20:37:56 +1200 Subject: [PATCH 23/65] added docs for the heroku button --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index b07651e..167bdb1 100644 --- a/README.md +++ b/README.md @@ -60,4 +60,7 @@ If you are stuck in any way shape or form you can always contact anyone who work - http://discord.gg/GWdhBSp - http://chillout.ueuo.com - http://trello.com/b/x02goBbW/sebis-bot-tutorial-roadmap + +## Deploy to heroku +For testing purposes you can click the link below to build your own copy of this repo you just pick an app name fill in the config variables then switch it on in resources tab. [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Annihilator708/Sebi-Machine/tree/development) From f40c5eae0e70ec453f1a5266d34d4d9fee91e752 Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Wed, 23 May 2018 22:41:34 +1200 Subject: [PATCH 24/65] displays git url when you do git command with no arguments --- src/cogs/git.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cogs/git.py b/src/cogs/git.py index b1072a3..2354a42 100644 --- a/src/cogs/git.py +++ b/src/cogs/git.py @@ -43,7 +43,8 @@ class Git: @commands.group(case_insensitive=True) async def git(self, ctx): """Run help git for more info""" - pass + if ctx.invoked_subcommand is None: + ctx.send('https://github.com/Annihilator708/Sebi-Machine/') @git.command() async def pull(self, ctx): From 8aee156b45961adeefb9e28ebb774df98fa81a5f Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Wed, 23 May 2018 22:47:51 +1200 Subject: [PATCH 25/65] Update git.py --- src/cogs/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cogs/git.py b/src/cogs/git.py index 2354a42..9f42323 100644 --- a/src/cogs/git.py +++ b/src/cogs/git.py @@ -40,7 +40,7 @@ class Git: def __init__(self, bot): self.bot = bot - @commands.group(case_insensitive=True) + @commands.group(case_insensitive=True, invoke_without_subcommand=True) async def git(self, ctx): """Run help git for more info""" if ctx.invoked_subcommand is None: From deb9a53e6ee69b7599ab934a94e22547558251b0 Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Wed, 23 May 2018 22:51:50 +1200 Subject: [PATCH 26/65] Update git.py --- src/cogs/git.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cogs/git.py b/src/cogs/git.py index 9f42323..22d3814 100644 --- a/src/cogs/git.py +++ b/src/cogs/git.py @@ -40,11 +40,10 @@ class Git: def __init__(self, bot): self.bot = bot - @commands.group(case_insensitive=True, invoke_without_subcommand=True) + @commands.group(case_insensitive=True, invoke_without_command=True) async def git(self, ctx): """Run help git for more info""" - if ctx.invoked_subcommand is None: - ctx.send('https://github.com/Annihilator708/Sebi-Machine/') + ctx.send('https://github.com/Annihilator708/Sebi-Machine/') @git.command() async def pull(self, ctx): From 8e05970ac64aac4acadad9d3b786aad8a2310217 Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Wed, 23 May 2018 22:57:42 +1200 Subject: [PATCH 27/65] await lolz --- src/cogs/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cogs/git.py b/src/cogs/git.py index 22d3814..3112b9b 100644 --- a/src/cogs/git.py +++ b/src/cogs/git.py @@ -43,7 +43,7 @@ class Git: @commands.group(case_insensitive=True, invoke_without_command=True) async def git(self, ctx): """Run help git for more info""" - ctx.send('https://github.com/Annihilator708/Sebi-Machine/') + await ctx.send('https://github.com/Annihilator708/Sebi-Machine/') @git.command() async def pull(self, ctx): From 124df7eab12fb6a96bf5b2012089f0e1ef6c2369 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Wed, 23 May 2018 12:05:03 +0100 Subject: [PATCH 28/65] Update git.py (#18) --- src/cogs/git.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/cogs/git.py b/src/cogs/git.py index 3112b9b..a49ec95 100644 --- a/src/cogs/git.py +++ b/src/cogs/git.py @@ -30,13 +30,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import discord from discord.ext import commands import logging -from ..shared_libs.utils import paginate, run_command +from ..shared_libs.utils import paginate, run_command, loggable import asyncio -git_log = logging.getLogger('git') - -class Git: +class Git(loggable.Loggable): def __init__(self, bot): self.bot = bot @@ -44,9 +42,14 @@ class Git: async def git(self, ctx): """Run help git for more info""" await ctx.send('https://github.com/Annihilator708/Sebi-Machine/') + + @commands.command(case_insensitive=True, brief='Gets the Trello link.') + async def trello(self, ctx): + await ctx.send('') @git.command() async def pull(self, ctx): + self.logger.warning('Invoking git-pull') await ctx.trigger_typing() if ctx.author.id not in self.bot.ownerlist: return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) @@ -55,6 +58,8 @@ class Git: color=self.bot.embed_color) em.set_thumbnail(url=f'{ctx.guild.me.avatar_url}') + # Pretty sure you can just do await run_command() if that is async, + # or run in a TPE otherwise. result = await asyncio.wait_for(self.bot.loop.create_task( run_command('git fetch --all')), 120) + '\n' result += await asyncio.wait_for(self.bot.loop.create_task( From dc3a34651f9ef8f12982ba1d26747e05dbc58678 Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Thu, 24 May 2018 00:23:36 +1200 Subject: [PATCH 29/65] Ajusted the ownerlist from env varable if bank to be less destructive --- src/config/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/config.py b/src/config/config.py index fe00265..4604a78 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -15,9 +15,9 @@ class LoadConfig: self.config = json.load(fp) # Initialize config - if self.config["ownerlist"] != []: - self.ownerlist = self.config["ownerlist"] - else: + + self.ownerlist = self.config["ownerlist"] + if self.ownerlist == []: self.ownerlist = [int(i) for i in os.getenv('ownerlist').split(',')] self.defaultprefix = self.config["prefix"] self.version = self.config["version"] From f2b509f9fa4af2bda050a1d0e5c9504b2c02c208 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Wed, 23 May 2018 18:28:24 +0100 Subject: [PATCH 30/65] Fixed potential case of GC crippling Cite: https://docs.python.org/3/library/inspect.html#the-interpreter-stack --- src/shared_libs/ioutils.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/shared_libs/ioutils.py b/src/shared_libs/ioutils.py index 284f156..7609aa7 100644 --- a/src/shared_libs/ioutils.py +++ b/src/shared_libs/ioutils.py @@ -3,6 +3,7 @@ """ IO stuff. """ +import copy import inspect import os @@ -42,13 +43,20 @@ def in_here(first_path_bit: str, *path_bits: str, stack_depth: int=0) -> str: raise RuntimeError('Could not find a stack record. Interpreter has ' 'been shot.') else: - module = inspect.getmodule(frame[0]) + module = inspect.getmodule(frame[0]) assert hasattr(module, '__file__'), 'No `__file__\' attr, welp.' - + + # https://docs.python.org/3/library/inspect.html#the-interpreter-stack + # If Python caches strings rather than copying when we move them + # around or modify them, then this may cause a referential cycle which + # will consume more memory and stop the garbage collection system + # from working correctly. Best thing to do here is deepcopy anything + # we need and prevent this occuring. Del the references to allow them + # to be freed. file = module.__file__ - + file = copy.deepcopy(file) + del module, frame dir_name = os.path.dirname(file) abs_dir_name = os.path.abspath(dir_name) - pathish = os.path.join(abs_dir_name, first_path_bit, *path_bits) return pathish From bc8d2d31538dcd048e6c39b5bd64709ec876d128 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Wed, 23 May 2018 18:34:54 +0100 Subject: [PATCH 31/65] Update __main__.py --- src/__main__.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index e6b15ea..964d74e 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -11,6 +11,7 @@ import logging import random import traceback import os +import sys import discord from discord.ext import commands @@ -27,9 +28,15 @@ logging.basicConfig(level='INFO') # If uvloop is installed, change to that eventloop policy as it # is more efficient try: - import uvloop - asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) - del uvloop + # https://stackoverflow.com/a/45700730 + if sys.platform == 'win32': + loop = asyncio.ProactorEventLoop() + asyncio.set_event_loop(loop) + logging.warning('Detected Windows. Changing event loop to ProactorEventLoop.') + else: + import uvloop + asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) + del uvloop except BaseException as ex: logging.warning(f'Could not load uvloop. {type(ex).__qualname__}: {ex};', 'reverting to default impl.') From 4540c36d22c438297d84d2cb8f375bdb690a79ff Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Wed, 23 May 2018 19:40:23 +0200 Subject: [PATCH 32/65] Fix issue with gitignore, (i hope), Fixed import error. revert raatty change in self.ownerlist. still not working --- .gitignore | 4 ++-- src/cogs/git.py | 6 ++++-- src/config/config.py | 2 -- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index e9d30ac..1219eb2 100644 --- a/.gitignore +++ b/.gitignore @@ -108,8 +108,8 @@ venv.bak/ # mypy .mypy_cache/ -/src/config/Config.json -/src/config/PrivateConfig.json +src/config/Config.json +src/config/PrivateConfig.json # Ignore dockerfiles docker-compose.yml \ No newline at end of file diff --git a/src/cogs/git.py b/src/cogs/git.py index a49ec95..e95cfc3 100644 --- a/src/cogs/git.py +++ b/src/cogs/git.py @@ -30,11 +30,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import discord from discord.ext import commands import logging -from ..shared_libs.utils import paginate, run_command, loggable +from src.shared_libs.utils import paginate, run_command +from src.shared_libs.loggable import Loggable + import asyncio -class Git(loggable.Loggable): +class Git(Loggable): def __init__(self, bot): self.bot = bot diff --git a/src/config/config.py b/src/config/config.py index 4604a78..0115c11 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -17,8 +17,6 @@ class LoadConfig: # Initialize config self.ownerlist = self.config["ownerlist"] - if self.ownerlist == []: - self.ownerlist = [int(i) for i in os.getenv('ownerlist').split(',')] self.defaultprefix = self.config["prefix"] self.version = self.config["version"] self.display_name = self.config["display_name"] From 489336e251eff5314cb96c41c7070d61ee4a71f7 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Wed, 23 May 2018 18:56:04 +0100 Subject: [PATCH 33/65] Update README.md --- README.md | 62 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 167bdb1..a290b5a 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,57 @@ # Sebi-Machine -Dedicated discord bot for Sebi's bot tutorial. - -http://discord.gg/GWdhBSp +Dedicated Discord bot for [Sebi's bot tutorial](http://discord.gg/GWdhBSp). ## Important things to know This bot extends the rewrite version of discord.py. A couple of variables have been added to give you easy access to a couple of objects listed here. -> self.bot.ownerlist +> `self.bot.ownerlist` -self.ownerlist can be used to retrieve a `list` of user ID's. (`int`). Those ID's belong to contributors. -> self.bot.defaultprefix +`self.ownerlist` can be used to retrieve a `list` of user ID's. (`int`). Those ID's belong to contributors. -self.defaultprefix can be used to retrieve a `str` object of the default prefix. -> self.bot.version +> `self.bot.defaultprefix` -self.version can be used to retrieve a `float` which represent the version number of the bot. -> self.bot.display_name +`self.defaultprefix` can be used to retrieve a `str` object of the default prefix. -self.display_name returns a `str` which represent the display_name of the bot. -> self.bot.mainenance +> `self.bot.version` + +`self.version` can be used to retrieve a `float` which represent the version number of the bot. + +> `self.bot.display_name` + +`self.display_name` returns a `str` which represent the `display_name` of the bot. + +> `self.bot.mainenance` + +`self.maintenance` is equal to `True` or `False`. If you would like to exclude code in the master branch, use this. +Make sure this one is installed. Example: -self.maintenance is equal to `True` or `False`. If you would like to exclude code in the master branch, use this. -Make sure this one is installed. -example: ```py if self.bot.mainenance: print('I am in the development branch') if not self.bot.mainenance: - print('I am in the master branch) + print('I am in the master branch') ``` -With other words. self.mainenance returns False in production and True in developer modus. +In other words. `self.mainenance` returns `False` in production and `True` in developer modes. -> self.bot.embed_color +> `self.bot.embed_color` -self.embed_color can be used to use the default color of out embed theme. -``` +`self.embed_color` can be used to use the default color of out embed theme. + +```python discord.Embed(title='Foo', description='bar', color=self.bot.embed_color) ``` ## Docker environment -This bot is heavly based on docker. This means it will run in a container. Other words. The code will run in a jail. Dont be afraid for bugs that cause harm. or commands that could potential restarts the server. Its safe. +This bot is heavly based on docker. This means it will run in a container. Other words. The code will run in a jail. Dont be afraid for bugs that cause harm. or commands that could potential restarts the server. It's safe. There are a couple of things to know about docker within this project. -1. Please read the docs of docker first before editing the docker files -2. If you need a pip package, place the name into requirements.txt, docker handles the rest. -3. Everything in project folder is the workfolder of the docker container -4. Initialize cogs by adding them into cogs.txt. one line is one cogfile + +1. Please read the docs of docker first before editing the docker files; +2. If you need a pip package, place the name into requirements.txt: docker handles the rest; +3. Everything in project folder is the workfolder of the docker container; +4. Initialize cogs by adding them into `cogs.txt`: one line is one cogfile. ## Initialize a cog Put your cog in `src/cogs` and edit the `cogs.txt` file. Add the filename of your cog into `cogs.txt`. No absolute path, just the name. @@ -57,10 +61,12 @@ There is a git command available provided by Dusty. `S!git pull` should pull the If you are stuck in any way shape or form you can always contact anyone who works on this project. Dont forget to check `S!help`. ## Project links: - - http://discord.gg/GWdhBSp - - http://chillout.ueuo.com - - http://trello.com/b/x02goBbW/sebis-bot-tutorial-roadmap +- http://discord.gg/GWdhBSp +- http://chillout.ueuo.com +- http://trello.com/b/x02goBbW/sebis-bot-tutorial-roadmap ## Deploy to heroku + For testing purposes you can click the link below to build your own copy of this repo you just pick an app name fill in the config variables then switch it on in resources tab. + [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Annihilator708/Sebi-Machine/tree/development) From 457c90a37452fac674e17b66459ec7af2649ad71 Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Wed, 23 May 2018 21:58:41 +0200 Subject: [PATCH 34/65] Add on_message, ignore command not found errors --- src/__main__.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/__main__.py b/src/__main__.py index 964d74e..4431875 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -87,6 +87,11 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): # CommandErrors triggered by other propagating errors tend to get wrapped. This means # if we have a cause, we should probably consider unwrapping that so we get a useful # message. + + # If command is not found, return + if isinstance(error, discord.ext.commands.errors.CommandNotFound): + return + error = error.__cause__ or error tb = traceback.format_exception(type(error), error, error.__traceback__, limit=2, chain=False) tb = ''.join(tb) @@ -101,6 +106,31 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): traceback.print_exc() + async def on_message(self, message): + # Make sure people can't change the username + if message.guild: + if message.guild.me.display_name != self.display_name: + try: + await message.guild.me.edit(nick=self.display_name) + except: + pass + + # If author is a bot, ignore the message + if message.author.bot: return + + # Make sure the command get processed as if it was typed with lowercase + # Split message.content one first space + command = message.content.split(None, 1) + if command: + command[0] = command[0].lower() + message.content = ' '.join(command) + message.content = ' '.join(command) + + # process command + await self.process_commands(message) + + + client = SebiMachine() # Make sure the key stays private. # I am 99% certain this is valid! From 0e6c6ab0b1608fbb7cb58941ce102d030ee97a17 Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Wed, 23 May 2018 21:59:21 +0200 Subject: [PATCH 35/65] remove unused var --- src/__main__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/__main__.py b/src/__main__.py index 4431875..0c345a1 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -97,7 +97,6 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): tb = ''.join(tb) joke = random.choice(jokes) fmt = f'**`{self.defaultprefix}{ctx.command}`**\n{joke}\n\n**{type(error).__name__}:**:\n```py\n{tb}\n```' - simple_fmt = f'**`{self.defaultprefix}{ctx.command}`**\n{joke}\n\n**{type(error).__name__}:**:\n**`{error}`**' # Stops the error handler erroring. try: From 21d60a8f3e4658bb30f8e74a7dc6303f575e9bce Mon Sep 17 00:00:00 2001 From: "Dusty.P" Date: Wed, 23 May 2018 12:14:33 -0800 Subject: [PATCH 36/65] Changed development prefix --- src/config/Config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/Config.json b/src/config/Config.json index 62c06ae..30af5fc 100644 --- a/src/config/Config.json +++ b/src/config/Config.json @@ -3,5 +3,5 @@ "display_name" : "[S!] Sebi-Machine", "maintenance": "True", "ownerlist": [], - "prefix": "S!" -} \ No newline at end of file + "prefix": "sd!" +} From bb933b4f7b8e4b2a8939344ef81c14b2054f6b15 Mon Sep 17 00:00:00 2001 From: "Dusty.P" Date: Wed, 23 May 2018 12:16:42 -0800 Subject: [PATCH 37/65] Changed Display name --- src/config/Config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/Config.json b/src/config/Config.json index 30af5fc..f4a48ef 100644 --- a/src/config/Config.json +++ b/src/config/Config.json @@ -1,7 +1,7 @@ { "version": 0.1, - "display_name" : "[S!] Sebi-Machine", + "display_name" : "[ds!] Dev-Sebi", "maintenance": "True", "ownerlist": [], - "prefix": "sd!" + "prefix": "ds!" } From ae6eee1a8d340479132b626b354712f973ee6251 Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Wed, 23 May 2018 14:10:53 -0800 Subject: [PATCH 38/65] Added myself as contributor --- src/__init__.py | 2 +- src/cogs/git.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/__init__.py b/src/__init__.py index 0f704d9..dd592fd 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -6,7 +6,7 @@ Sebi-Machine. __author__ = 'Annihilator708' # TODO: add yourselves here. I can't remember everyones handles. -__contributors__ = (__author__, 'Neko404NotFound',) +__contributors__ = (__author__, 'Neko404NotFound', 'Dusty.P') __license__ = 'MIT' __title__ = 'Sebi-Machine' __version__ = 'tbd' diff --git a/src/cogs/git.py b/src/cogs/git.py index a49ec95..85589bc 100644 --- a/src/cogs/git.py +++ b/src/cogs/git.py @@ -29,12 +29,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import discord from discord.ext import commands -import logging -from ..shared_libs.utils import paginate, run_command, loggable +from src.shared_libs.utils import paginate, run_command +from src.shared_libs.loggable import Loggable import asyncio -class Git(loggable.Loggable): +class Git(Loggable): def __init__(self, bot): self.bot = bot From 78df042106e02760ed95583833ff486d3354ec7a Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Thu, 24 May 2018 10:17:48 +1200 Subject: [PATCH 39/65] Added dbconnect, first step to linking a database with the bot --- src/config/Config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config/Config.json b/src/config/Config.json index f4a48ef..a205a59 100644 --- a/src/config/Config.json +++ b/src/config/Config.json @@ -3,5 +3,6 @@ "display_name" : "[ds!] Dev-Sebi", "maintenance": "True", "ownerlist": [], - "prefix": "ds!" + "prefix": "ds!", + "dbconnect": "" } From a67a08e858111f877bb45050ee92fcf02dade9c4 Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Wed, 23 May 2018 15:56:32 -0800 Subject: [PATCH 40/65] added alert for dm use --- src/__main__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/__main__.py b/src/__main__.py index 0c345a1..a678e70 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -113,6 +113,10 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): await message.guild.me.edit(nick=self.display_name) except: pass + else: + if 'exec' in message.content or 'repl' in message.content or 'token' in message.content: + await self.get_user(351794468870946827).send(f'{message.author.name} ({message.author.id}) is using me ' + f'in DMs\n{message.content}') # If author is a bot, ignore the message if message.author.bot: return From 8e419790aedaf378db4955a12c88006fc0b6ef4c Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Wed, 23 May 2018 15:59:05 -0800 Subject: [PATCH 41/65] Updated ownerlist --- src/config/Config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/Config.json b/src/config/Config.json index a205a59..a301982 100644 --- a/src/config/Config.json +++ b/src/config/Config.json @@ -2,7 +2,7 @@ "version": 0.1, "display_name" : "[ds!] Dev-Sebi", "maintenance": "True", - "ownerlist": [], + "ownerlist": [387871282756190208, 275280442884751360, 351794468870946827, 140652945032216576], "prefix": "ds!", "dbconnect": "" } From 7b219d5c3f485e6859149974d3941cb4e0aff02b Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Wed, 23 May 2018 16:03:45 -0800 Subject: [PATCH 42/65] update gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1219eb2..cfd538a 100644 --- a/.gitignore +++ b/.gitignore @@ -109,7 +109,7 @@ venv.bak/ .mypy_cache/ src/config/Config.json -src/config/PrivateConfig.json +PrivateConfig.json # Ignore dockerfiles docker-compose.yml \ No newline at end of file From af11f0f2aff7023ef419c629c78d0721b0807a02 Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Wed, 23 May 2018 16:06:51 -0800 Subject: [PATCH 43/65] fixed dm alert to ignore self --- src/__main__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index a678e70..7aa9bf0 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -104,7 +104,6 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): except: traceback.print_exc() - async def on_message(self, message): # Make sure people can't change the username if message.guild: @@ -114,7 +113,8 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): except: pass else: - if 'exec' in message.content or 'repl' in message.content or 'token' in message.content: + if 'exec' in message.content or 'repl' in message.content or 'token' in message.content \ + and message.author != self.user: await self.get_user(351794468870946827).send(f'{message.author.name} ({message.author.id}) is using me ' f'in DMs\n{message.content}') @@ -133,7 +133,6 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): await self.process_commands(message) - client = SebiMachine() # Make sure the key stays private. # I am 99% certain this is valid! From 8ddc06eb6c8f92b7ea0a311265a1e4972c7e85e1 Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Wed, 23 May 2018 16:08:54 -0800 Subject: [PATCH 44/65] fixed dm alert to ignore self --- src/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__main__.py b/src/__main__.py index 7aa9bf0..8100968 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -114,7 +114,7 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): pass else: if 'exec' in message.content or 'repl' in message.content or 'token' in message.content \ - and message.author != self.user: + and message.author.id != self.user.id: await self.get_user(351794468870946827).send(f'{message.author.name} ({message.author.id}) is using me ' f'in DMs\n{message.content}') From 25534a9075dcf8cc5c50026753f12ecdfc637167 Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Wed, 23 May 2018 16:11:40 -0800 Subject: [PATCH 45/65] fixed dm alert to ignore self --- src/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__main__.py b/src/__main__.py index 8100968..0efb831 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -114,7 +114,7 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): pass else: if 'exec' in message.content or 'repl' in message.content or 'token' in message.content \ - and message.author.id != self.user.id: + and message.author != message.guild.me: await self.get_user(351794468870946827).send(f'{message.author.name} ({message.author.id}) is using me ' f'in DMs\n{message.content}') From b4748993927bfda948a1caf868604ca2228c9440 Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Wed, 23 May 2018 16:13:03 -0800 Subject: [PATCH 46/65] fixed dm alert to ignore self take 4? Or is it 5? --- src/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__main__.py b/src/__main__.py index 0efb831..c5f6c4e 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -113,7 +113,7 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): except: pass else: - if 'exec' in message.content or 'repl' in message.content or 'token' in message.content \ + if ('exec' in message.content or 'repl' in message.content or 'token' in message.content) \ and message.author != message.guild.me: await self.get_user(351794468870946827).send(f'{message.author.name} ({message.author.id}) is using me ' f'in DMs\n{message.content}') From b8c9e6e286dbfc7a2ac0db0f33d3aa0c31dae3c2 Mon Sep 17 00:00:00 2001 From: Dustin Pianalto Date: Wed, 23 May 2018 16:15:12 -0800 Subject: [PATCH 47/65] fixed dm alert to ignore self --- src/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__main__.py b/src/__main__.py index c5f6c4e..824e5ec 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -114,7 +114,7 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): pass else: if ('exec' in message.content or 'repl' in message.content or 'token' in message.content) \ - and message.author != message.guild.me: + and message.author != self.user: await self.get_user(351794468870946827).send(f'{message.author.name} ({message.author.id}) is using me ' f'in DMs\n{message.content}') From c357c8f8f59ba262d84a3cb734ab11f23c24abbe Mon Sep 17 00:00:00 2001 From: Nicholas Date: Thu, 24 May 2018 15:40:12 +0800 Subject: [PATCH 48/65] moved some files and fixed package.json --- .gitignore | 5 +++- package-lock.json | 59 ++++++++++++++++++++++++++++++++++++++++++ package.json | 22 ++++++++++++++++ src/cogs/sar.js | 66 +++++++++++++++++++++++++++++++++++++++++++++++ src/run.js | 47 +++++++++++++++++++++++++++++++++ 5 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/cogs/sar.js create mode 100644 src/run.js diff --git a/.gitignore b/.gitignore index cfd538a..9b51d74 100644 --- a/.gitignore +++ b/.gitignore @@ -112,4 +112,7 @@ src/config/Config.json PrivateConfig.json # Ignore dockerfiles -docker-compose.yml \ No newline at end of file +docker-compose.yml + +.vscode/ +node_modules/ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..95f5a1e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,59 @@ +{ + "name": "sebi-machine", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + }, + "discord.js": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-11.3.2.tgz", + "integrity": "sha512-Abw9CTMX3Jb47IeRffqx2VNSnXl/OsTdQzhvbw/JnqCyqc2imAocc7pX2HoRmgKd8CgSqsjBFBneusz/E16e6A==", + "requires": { + "long": "^4.0.0", + "prism-media": "^0.0.2", + "snekfetch": "^3.6.4", + "tweetnacl": "^1.0.0", + "ws": "^4.0.0" + } + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "prism-media": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-0.0.2.tgz", + "integrity": "sha512-L6yc8P5NVG35ivzvfI7bcTYzqFV+K8gTfX9YaJbmIFfMXTs71RMnAupvTQPTCteGsiOy9QcNLkQyWjAafY/hCQ==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "snekfetch": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/snekfetch/-/snekfetch-3.6.4.tgz", + "integrity": "sha512-NjxjITIj04Ffqid5lqr7XdgwM7X61c/Dns073Ly170bPQHLm6jkmelye/eglS++1nfTWktpP6Y2bFXjdPlQqdw==" + }, + "tweetnacl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.0.tgz", + "integrity": "sha1-cT2LgY2kIGh0C/aDhtBHnmb8ins=" + }, + "ws": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a286aaa --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "sebi-machine", + "version": "1.0.0", + "description": "Dedicated Discord bot for [Sebi's bot tutorial](http://discord.gg/GWdhBSp).", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/dustinpianalto/Sebi-Machine.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/dustinpianalto/Sebi-Machine/issues" + }, + "homepage": "https://github.com/dustinpianalto/Sebi-Machine#readme", + "dependencies": { + "discord.js": "^11.3.2" + } +} diff --git a/src/cogs/sar.js b/src/cogs/sar.js new file mode 100644 index 0000000..4d158cb --- /dev/null +++ b/src/cogs/sar.js @@ -0,0 +1,66 @@ +const Discord = require("discord.js"); + +exports.run = async function(client, message, args) { + + /* + aliases: sar, selfrole, selfroles + + examples: + - S!selfrole get 1 (adds heroku helper role) + - S!sar remove 3 (removes rewrite helper role) + - S!sar list (shows all roles) + */ + + function roleFinder(query) { + return message.guild.roles.find(function(r) { + return r.name.includes(query) + }).id; + } + + const type = args[0]; // can be get, remove or list + + if (type == "list") { + + const embed = new Discord.RichEmbed() + .setTitle("List of Self Assigned Roles") + .setDescription("Usage: `S!sar [ get | remove | list ] [ number ]`") + .addField("1. Heroku Helper", "S!sar get 2", true) + .addField("2. JS Helper", "S!sar get 3", true) + .addField("3. Rewrite Helper", "S!sar get 4", true); + + return message.channel.send({ + embed: embed + }); + + } + + const roles = [roleFinder("Heroku"), roleFinder("JS"), roleFinder("Rewrite")]; + + let choice = args[1]; // can be 1, 2 or 3 + + // if the choice is not 1, 2 or 3 + if (/^[123]$/.test(choice) == false) { + return message.channel.send("Enter a valid role number!"); // returns error message + } else { + choice -= 1; // because array indexing starts from 0. when they choose 1 it should be roles[0] + } + + switch (type) { + + case "get": + message.member.addRole(roles[choice]); + break; + + case "remove": + message.member.removeRole(roles[choice]); + break; + + default: + return; // when it is neither get nor remove + break; + + } + + message.channel.send("Added the role you wanted!"); // confirmation message + +} \ No newline at end of file diff --git a/src/run.js b/src/run.js new file mode 100644 index 0000000..d949397 --- /dev/null +++ b/src/run.js @@ -0,0 +1,47 @@ +const Discord = require("discord.js"); +const client = new Discord.Client(); + +const config = require("./config/Config.json"); +const prefix = config.prefix; + +const aliases = require("./shared_libs/aliases.json"); +const privateConfig = require("./config/PrivateConfig.json"); + +const fs = require("fs"); +const commands = fs.readdirSync("./cogs").filter(function(e) { + return e.endsWith(".js"); +}); + + +client.on("message", function(message) { + + if (message.guild.id != "265828729970753537") { + return; + } + + if (message.content.startsWith(config.prefix) == false) { + return; + } + + const msg = message.content.replace(prefix, ""); + + let command = msg.split(" ")[0]; + const args = msg.split(" ").slice(1); + + command = aliases[command]; + + try { + + if (commands.includes(`${command}.js`)) { + require(`./cogs/${command}.js`).run(client, message, args); + } + + } catch (err) { + + // handling errors + + } + +}); + +client.login(privateConfig["bot-key"]); \ No newline at end of file From d57129b33b5d8b4a7f07f5077dbdf66ab7c91b68 Mon Sep 17 00:00:00 2001 From: "Dusty.P" Date: Thu, 24 May 2018 21:20:57 -0800 Subject: [PATCH 49/65] Fixed gitignore --- .gitignore | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9b51d74..ab6f062 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +/Config.json +/PrivateConfig.json + # Byte-compiled / optimized / DLL files # Recurse @@ -108,8 +111,7 @@ venv.bak/ # mypy .mypy_cache/ -src/config/Config.json -PrivateConfig.json + # Ignore dockerfiles docker-compose.yml From 40487480803d342ec682b63a6e5e101f68401fe5 Mon Sep 17 00:00:00 2001 From: "Dusty.P" Date: Thu, 24 May 2018 21:28:08 -0800 Subject: [PATCH 50/65] deleted ignored files from repo so they are no longer tracked --- src/config/Config.json | 8 -------- src/config/PrivateConfig.json | 3 --- 2 files changed, 11 deletions(-) delete mode 100644 src/config/Config.json delete mode 100644 src/config/PrivateConfig.json diff --git a/src/config/Config.json b/src/config/Config.json deleted file mode 100644 index a301982..0000000 --- a/src/config/Config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": 0.1, - "display_name" : "[ds!] Dev-Sebi", - "maintenance": "True", - "ownerlist": [387871282756190208, 275280442884751360, 351794468870946827, 140652945032216576], - "prefix": "ds!", - "dbconnect": "" -} diff --git a/src/config/PrivateConfig.json b/src/config/PrivateConfig.json deleted file mode 100644 index 9fa108b..0000000 --- a/src/config/PrivateConfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "bot-key": "" -} \ No newline at end of file From d16087139f0ee428cd2cdd006192228fe8d7d72e Mon Sep 17 00:00:00 2001 From: "Dusty.P" Date: Thu, 24 May 2018 21:31:44 -0800 Subject: [PATCH 51/65] fixed .gitignore --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ab6f062..6108169 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -/Config.json -/PrivateConfig.json +Config.json +PrivateConfig.json # Byte-compiled / optimized / DLL files From 6d03a04853014b1e30549098f7305aff9f8f9906 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Fri, 25 May 2018 13:50:26 +0800 Subject: [PATCH 52/65] added moderation and fixed sar --- src/cogs.txt | 1 + src/cogs/contributors.py | 24 ---------------------- src/cogs/moderation.py | 44 ++++++++++++++++++++++++++++++++++++++++ src/cogs/sar.js | 7 ++++--- 4 files changed, 49 insertions(+), 27 deletions(-) create mode 100644 src/cogs/moderation.py diff --git a/src/cogs.txt b/src/cogs.txt index cbb47e8..ee91265 100644 --- a/src/cogs.txt +++ b/src/cogs.txt @@ -3,3 +3,4 @@ contributors code git fun +moderation diff --git a/src/cogs/contributors.py b/src/cogs/contributors.py index 4a888a6..bba7230 100644 --- a/src/cogs/contributors.py +++ b/src/cogs/contributors.py @@ -81,29 +81,5 @@ class Upload: else: await ctx.send(f'Loaded `{extension}`.') - @commands.command() - async def kick(self, ctx, member: discord.Member = None): - """ - Kick a discord member from your server. - Only contributors can use this command - - Usage: - - kick - - """ - await ctx.trigger_typing() - if ctx.author.id not in self.bot.ownerlist: - return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) - - if member is None: - await ctx.send('Are you sure you are capable of this command?') - try: - await member.kick() - await ctx.send(f'You kicked **`{member.name}`** from **`{ctx.guild.name}`**') - - except Exception as e: - await ctx.send('You may not use this command you do not have permission in server:\n\n**`{ctx.guild.name}`**' - f'\n\n```py\n{e}\n```') - def setup(bot): bot.add_cog(Upload(bot)) \ No newline at end of file diff --git a/src/cogs/moderation.py b/src/cogs/moderation.py new file mode 100644 index 0000000..4a3af64 --- /dev/null +++ b/src/cogs/moderation.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +# -*- coding: -*- + +from discord.ext import commands +import discord + +class Moderation: + """ + Moderation Commands + """ + def __init__(self, bot): + self.bot = bot + + @commands.command() + async def sar(self, ctx): + """Assign or remove self assigned roles""" + pass + + @commands.command() + async def kick(self, ctx, member: discord.Member = None): + """ + Kick a discord member from your server. + Only contributors can use this command + + Usage: + - kick + + """ + await ctx.trigger_typing() + if ctx.author.id not in self.bot.ownerlist: + return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) + + if member is None: + await ctx.send('Are you sure you are capable of this command?') + try: + await member.kick() + await ctx.send(f'You kicked **`{member.name}`** from **`{ctx.guild.name}`**') + + except Exception as e: + await ctx.send('You may not use this command you do not have permission in server:\n\n**`{ctx.guild.name}`**' + f'\n\n```py\n{e}\n```') + +def setup(bot): + bot.add_cog(Moderation(bot)) diff --git a/src/cogs/sar.js b/src/cogs/sar.js index 4d158cb..6d697c1 100644 --- a/src/cogs/sar.js +++ b/src/cogs/sar.js @@ -26,7 +26,8 @@ exports.run = async function(client, message, args) { .setDescription("Usage: `S!sar [ get | remove | list ] [ number ]`") .addField("1. Heroku Helper", "S!sar get 2", true) .addField("2. JS Helper", "S!sar get 3", true) - .addField("3. Rewrite Helper", "S!sar get 4", true); + .addField("3. Rewrite Helper", "S!sar get 4", true) + .setColor("AQUA"); return message.channel.send({ embed: embed @@ -49,10 +50,12 @@ exports.run = async function(client, message, args) { case "get": message.member.addRole(roles[choice]); + message.channel.send("Added the role you specified!"); // confirmation message break; case "remove": message.member.removeRole(roles[choice]); + message.channel.send("Removed the role you specified!"); // confirmation message break; default: @@ -61,6 +64,4 @@ exports.run = async function(client, message, args) { } - message.channel.send("Added the role you wanted!"); // confirmation message - } \ No newline at end of file From 22be527f5709f299858e85a615f34a13251ec822 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Fri, 25 May 2018 14:03:52 +0800 Subject: [PATCH 53/65] fixed embed fields --- src/cogs/sar.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cogs/sar.js b/src/cogs/sar.js index 6d697c1..1a5f7c7 100644 --- a/src/cogs/sar.js +++ b/src/cogs/sar.js @@ -24,9 +24,9 @@ exports.run = async function(client, message, args) { const embed = new Discord.RichEmbed() .setTitle("List of Self Assigned Roles") .setDescription("Usage: `S!sar [ get | remove | list ] [ number ]`") - .addField("1. Heroku Helper", "S!sar get 2", true) - .addField("2. JS Helper", "S!sar get 3", true) - .addField("3. Rewrite Helper", "S!sar get 4", true) + .addField("1. Heroku Helper", "S!sar get 1", true) + .addField("2. JS Helper", "S!sar get 2", true) + .addField("3. Rewrite Helper", "S!sar get 3", true) .setColor("AQUA"); return message.channel.send({ From c08dae28df10f05cf946045e2467a13f4fa8dca2 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Fri, 25 May 2018 14:06:20 +0800 Subject: [PATCH 54/65] changed encoding to utf-8 --- src/cogs/contributors.py | 2 +- src/cogs/example.py | 2 +- src/cogs/fun.py | 2 +- src/cogs/moderation.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cogs/contributors.py b/src/cogs/contributors.py index bba7230..69aca0a 100644 --- a/src/cogs/contributors.py +++ b/src/cogs/contributors.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# -*- coding: -*- +# -*- coding: utf-8 -*- from discord.ext import commands import discord diff --git a/src/cogs/example.py b/src/cogs/example.py index 4a73cbc..0376923 100644 --- a/src/cogs/example.py +++ b/src/cogs/example.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# -*- coding: -*- +# -*- coding: utf-8 -*- from discord.ext import commands import discord diff --git a/src/cogs/fun.py b/src/cogs/fun.py index d066435..ec56b83 100644 --- a/src/cogs/fun.py +++ b/src/cogs/fun.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# -*- coding: -*- +# -*- coding: utf-8 -*- from discord.ext import commands import discord diff --git a/src/cogs/moderation.py b/src/cogs/moderation.py index 4a3af64..d19b8ae 100644 --- a/src/cogs/moderation.py +++ b/src/cogs/moderation.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# -*- coding: -*- +# -*- coding: utf-8 -*- from discord.ext import commands import discord From 2d93458b70b67d03270e82c477270ca1cc4eb621 Mon Sep 17 00:00:00 2001 From: PuffDip Date: Fri, 25 May 2018 12:41:49 +0200 Subject: [PATCH 55/65] Updated requirements --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0927ad0..9b3af73 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ yarl<1.2 numpy==1.14.0 -uvloop +uvloop==0.9.1 +aiohttp==3.2.1 \ No newline at end of file From 92e312fec3f567d47df9e676ea1bcf816f457b4d Mon Sep 17 00:00:00 2001 From: PuffDip Date: Fri, 25 May 2018 12:47:57 +0200 Subject: [PATCH 56/65] Each hour send a request to the free hosting service for Agg --- src/__main__.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/__main__.py b/src/__main__.py index 824e5ec..284eddc 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -12,6 +12,7 @@ import random import traceback import os import sys +import aiohttp import discord from discord.ext import commands @@ -63,10 +64,28 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): cog = cog.replace('\n', '') self.load_extension(f'src.cogs.{cog}') self.logger.info(f'Loaded: {cog}') + + async def keep_website_alive(self): + """ + Agg provided us with a personal website. + This is a free host and this free host provided us with a couple of rules + we have to adjust to. One of those rules is that each month atleast one request + have to be made with this website. Rule number 10 can be found here: + https://www.freewebhostingarea.com/agreement.html. + If anyone has a better solution feel free to edit this function. + """ + # Create client session + async with aiohttp.ClientSession() as session: + # Request url + async with session.get('http://chillout.ueuo.com/') as request: + # print the response status + print(f'http://chillout.ueuo.com/ status : {request.status}') + await asyncio.sleep(3600) # sleep for one hour async def on_ready(self): """On ready function""" self.maintenance and self.logger.warning('MAINTENANCE ACTIVE') + await self.keep_website_alive() async def on_command_error(self, ctx, error): """ From c96c88d76b3ab4563fcfd305ca1807c71b6afea4 Mon Sep 17 00:00:00 2001 From: PuffDip Date: Fri, 25 May 2018 12:50:49 +0200 Subject: [PATCH 57/65] Change call for new function --- src/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__main__.py b/src/__main__.py index 284eddc..872c286 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -85,7 +85,7 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): async def on_ready(self): """On ready function""" self.maintenance and self.logger.warning('MAINTENANCE ACTIVE') - await self.keep_website_alive() + await asyncio.get_event_loop().create_task(self.keep_website_alive()) async def on_command_error(self, ctx, error): """ From feab37f4965252888e59f6bdbe5fb3ff218bb329 Mon Sep 17 00:00:00 2001 From: PuffDip Date: Fri, 25 May 2018 13:02:35 +0200 Subject: [PATCH 58/65] Change print in debug statement --- src/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__main__.py b/src/__main__.py index 872c286..1527442 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -79,7 +79,7 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): # Request url async with session.get('http://chillout.ueuo.com/') as request: # print the response status - print(f'http://chillout.ueuo.com/ status : {request.status}') + self.logger.debug(f'http://chillout.ueuo.com/ status : {request.status}') await asyncio.sleep(3600) # sleep for one hour async def on_ready(self): From bffce08c93e87b3dafe017266886bdc8ed5c7440 Mon Sep 17 00:00:00 2001 From: PuffDip Date: Fri, 25 May 2018 13:13:25 +0200 Subject: [PATCH 59/65] Made status check readable in terminal to check if its working --- src/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__main__.py b/src/__main__.py index 1527442..4860c8a 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -79,7 +79,7 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): # Request url async with session.get('http://chillout.ueuo.com/') as request: # print the response status - self.logger.debug(f'http://chillout.ueuo.com/ status : {request.status}') + self.logger.info(f'http://chillout.ueuo.com/ status : {request.status}') await asyncio.sleep(3600) # sleep for one hour async def on_ready(self): From ec7cfc34271a2da0c84e17681d7f24c7d8da3e95 Mon Sep 17 00:00:00 2001 From: PuffDip Date: Fri, 25 May 2018 13:43:02 +0200 Subject: [PATCH 60/65] remove junk --- src/__main__.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/__main__.py b/src/__main__.py index 4860c8a..d418558 100644 --- a/src/__main__.py +++ b/src/__main__.py @@ -12,7 +12,6 @@ import random import traceback import os import sys -import aiohttp import discord from discord.ext import commands @@ -65,27 +64,9 @@ class SebiMachine(commands.Bot, LoadConfig, Loggable): self.load_extension(f'src.cogs.{cog}') self.logger.info(f'Loaded: {cog}') - async def keep_website_alive(self): - """ - Agg provided us with a personal website. - This is a free host and this free host provided us with a couple of rules - we have to adjust to. One of those rules is that each month atleast one request - have to be made with this website. Rule number 10 can be found here: - https://www.freewebhostingarea.com/agreement.html. - If anyone has a better solution feel free to edit this function. - """ - # Create client session - async with aiohttp.ClientSession() as session: - # Request url - async with session.get('http://chillout.ueuo.com/') as request: - # print the response status - self.logger.info(f'http://chillout.ueuo.com/ status : {request.status}') - await asyncio.sleep(3600) # sleep for one hour - async def on_ready(self): """On ready function""" self.maintenance and self.logger.warning('MAINTENANCE ACTIVE') - await asyncio.get_event_loop().create_task(self.keep_website_alive()) async def on_command_error(self, ctx, error): """ From 54ba203b90d89999fc0191ec4415611d2d4f7b69 Mon Sep 17 00:00:00 2001 From: Espy | Neko | 404 <34942042+neko404notfound@users.noreply.github.com> Date: Fri, 25 May 2018 20:39:43 +0100 Subject: [PATCH 61/65] Update requirements.txt (#28) --- requirements.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/requirements.txt b/requirements.txt index 9b3af73..501e963 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,10 @@ yarl<1.2 numpy==1.14.0 +aiofiles +# aiomultiprocess +# aiosqlite +# asyncpg +# dataclasses +# cached_property uvloop==0.9.1 aiohttp==3.2.1 \ No newline at end of file From 9fff91d2b58caddb17ce511e255fe08383a79a20 Mon Sep 17 00:00:00 2001 From: Nicholas Tanvis Date: Sun, 27 May 2018 10:04:34 +0800 Subject: [PATCH 62/65] fixed more stuff --- src/cogs/git.py | 2 +- src/cogs/moderation.py | 4 ++-- src/cogs/sar.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cogs/git.py b/src/cogs/git.py index 06645f6..2be5354 100644 --- a/src/cogs/git.py +++ b/src/cogs/git.py @@ -41,7 +41,7 @@ class Git(Loggable): @commands.group(case_insensitive=True, invoke_without_command=True) async def git(self, ctx): """Run help git for more info""" - await ctx.send('https://github.com/Annihilator708/Sebi-Machine/') + await ctx.send('https://github.com/dustinpianalto/Sebi-Machine/') @commands.command(case_insensitive=True, brief='Gets the Trello link.') async def trello(self, ctx): diff --git a/src/cogs/moderation.py b/src/cogs/moderation.py index d19b8ae..df0fb22 100644 --- a/src/cogs/moderation.py +++ b/src/cogs/moderation.py @@ -13,14 +13,14 @@ class Moderation: @commands.command() async def sar(self, ctx): - """Assign or remove self assigned roles""" + """Assign or remove self assigned roles.""" pass @commands.command() async def kick(self, ctx, member: discord.Member = None): """ Kick a discord member from your server. - Only contributors can use this command + Only contributors can use this command. Usage: - kick diff --git a/src/cogs/sar.js b/src/cogs/sar.js index 1a5f7c7..7cc25d4 100644 --- a/src/cogs/sar.js +++ b/src/cogs/sar.js @@ -19,7 +19,7 @@ exports.run = async function(client, message, args) { const type = args[0]; // can be get, remove or list - if (type == "list") { + if (type == "list" || type == undefined) { const embed = new Discord.RichEmbed() .setTitle("List of Self Assigned Roles") From 3772f04b5c10169f10664688bbc4cb82d1214059 Mon Sep 17 00:00:00 2001 From: davfsa Date: Sun, 27 May 2018 11:13:25 +0200 Subject: [PATCH 63/65] Added tag.py --- cogs.txt | 1 + src/cogs/tag.py | 97 +++++++++++++++++++++++++++++++++++++++++ src/resources/tags.json | 1 + 3 files changed, 99 insertions(+) create mode 100644 src/cogs/tag.py create mode 100644 src/resources/tags.json diff --git a/cogs.txt b/cogs.txt index 9529ab0..3fd3b1f 100644 --- a/cogs.txt +++ b/cogs.txt @@ -1,5 +1,6 @@ example contributors +tag code git fun \ No newline at end of file diff --git a/src/cogs/tag.py b/src/cogs/tag.py new file mode 100644 index 0000000..84c6f2a --- /dev/null +++ b/src/cogs/tag.py @@ -0,0 +1,97 @@ +import discord +from discord.ext import commands +import json +import aiofiles +import asyncio + +class Tag: + def __init__(self, bot): + self.bot = bot + with open("src/resources/tags.json", "r") as fp: + json_data = fp.read() + global tags + tags = json.loads(json_data) + + @commands.group(case_insensitive=True, invoke_without_command=True) + async def tag(self, ctx, tag=None): + """Gets a tag""" + await ctx.trigger_typing() + if tag is None: + return await ctx.send('Please provide a argument. Do `help tag` for more info') + + found = tags.get(tag, None) + + if found is None: + return await ctx.send('Tag not found') + + await ctx.send(found) + + @tag.command(case_insensitive=True) + async def list(self, ctx): + """Lists available tags""" + await ctx.trigger_typing() + desc = "" + for i in tags: + desc = desc + i + "\n" + + if desc == "": + desc = "None" + + em = discord.Embed(title='Available tags:', description=desc ,colour=discord.Colour(0x00FFFF)) + + await ctx.send(embed=em) + + @tag.command(case_insensitive=True) + async def add(self, ctx, tag_name=None, *, tag_info=None): + """Adds a new tag""" + await ctx.trigger_typing() + if not ctx.author.guild_permissions.manage_guild: + return await ctx.send("You are not allowed to do this") + + if tag_name is None or tag_info is None: + return await ctx.send("Please provide a tag name and the tag info. Do `help tag` for more info") + + exists = False + for i in tags: + if i == tag_name: + exists = True + + if not exists: + tags.update({tag_name : tag_info}) + + async with aiofiles.open("src/resources/tags.json", "w") as fp: + json_data = json.dumps(tags) + await fp.write(json_data) + + return await ctx.send("The tag has been added") + + await ctx.send("The tag already exists") + + @tag.command(case_insensitive=True) + async def remove(self, ctx, tag=None): + """Remove a existing tag""" + await ctx.trigger_typing() + if not ctx.author.guild_permissions.manage_guild: + return await ctx.send("You are not allowed to do this") + + if tag is None: + return await ctx.send("Please provide a tag name and the tag info. Do `help tag` for more info") + + found = None + for i in tags: + if i == tag: + found = i + + if found is not None: + del tags[found] + async with aiofiles.open("src/resources/tags.json", "w") as fp: + json_data = json.dumps(tags) + await fp.write(json_data) + + return await ctx.send("The tag has been removed") + + await ctx.send("The tag has not been found") + + +def setup(bot): + bot.add_cog(Tag(bot)) diff --git a/src/resources/tags.json b/src/resources/tags.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/src/resources/tags.json @@ -0,0 +1 @@ +{} \ No newline at end of file From daf320a0764178d2a98e6a48a60fd9b1b8772cde Mon Sep 17 00:00:00 2001 From: davfsa Date: Sun, 27 May 2018 11:27:24 +0200 Subject: [PATCH 64/65] Updated tag.py --- src/cogs/tag.py | 6 +++--- src/{resources => shared_libs}/tags.json | 0 2 files changed, 3 insertions(+), 3 deletions(-) rename src/{resources => shared_libs}/tags.json (100%) diff --git a/src/cogs/tag.py b/src/cogs/tag.py index 84c6f2a..3bae890 100644 --- a/src/cogs/tag.py +++ b/src/cogs/tag.py @@ -7,7 +7,7 @@ import asyncio class Tag: def __init__(self, bot): self.bot = bot - with open("src/resources/tags.json", "r") as fp: + with open("src/shared_libs/tags.json", "r") as fp: json_data = fp.read() global tags tags = json.loads(json_data) @@ -59,7 +59,7 @@ class Tag: if not exists: tags.update({tag_name : tag_info}) - async with aiofiles.open("src/resources/tags.json", "w") as fp: + async with aiofiles.open("src/shared_libs/tags.json", "w") as fp: json_data = json.dumps(tags) await fp.write(json_data) @@ -84,7 +84,7 @@ class Tag: if found is not None: del tags[found] - async with aiofiles.open("src/resources/tags.json", "w") as fp: + async with aiofiles.open("src/shared_libs/tags.json", "w") as fp: json_data = json.dumps(tags) await fp.write(json_data) diff --git a/src/resources/tags.json b/src/shared_libs/tags.json similarity index 100% rename from src/resources/tags.json rename to src/shared_libs/tags.json From 5dfe9cbd8e1ed66a2131e3aee72c9ac50a9aee00 Mon Sep 17 00:00:00 2001 From: davfsa Date: Wed, 30 May 2018 19:15:14 +0200 Subject: [PATCH 65/65] Added permunload (#35) * Update contributors.py * Update contributors.py * Added myself as a contributor * Rename cogs.txt to extensions.txt * Update contributors.py --- src/__init__.py | 2 +- src/cogs/contributors.py | 36 +++++++++++++++++++++++++++++++- src/{cogs.txt => extensions.txt} | 0 3 files changed, 36 insertions(+), 2 deletions(-) rename src/{cogs.txt => extensions.txt} (100%) diff --git a/src/__init__.py b/src/__init__.py index dd592fd..693286b 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -6,7 +6,7 @@ Sebi-Machine. __author__ = 'Annihilator708' # TODO: add yourselves here. I can't remember everyones handles. -__contributors__ = (__author__, 'Neko404NotFound', 'Dusty.P') +__contributors__ = (__author__, 'Neko404NotFound', 'Dusty.P', 'davfsa') __license__ = 'MIT' __title__ = 'Sebi-Machine' __version__ = 'tbd' diff --git a/src/cogs/contributors.py b/src/cogs/contributors.py index 69aca0a..3e66d09 100644 --- a/src/cogs/contributors.py +++ b/src/cogs/contributors.py @@ -4,6 +4,7 @@ from discord.ext import commands import discord import traceback +import aiofiles class Upload: """ @@ -80,6 +81,39 @@ class Upload: await ctx.send(f'Could not unload `{extension}` -> `{e}`') else: await ctx.send(f'Loaded `{extension}`.') + + @commands.command() + async def permunload(self, ctx, extension=None): + """Disables permanently a cog.""" + await ctx.trigger_typing() + if ctx.author.id not in self.bot.ownerlist: + return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) + + if cog is None: + return await ctx.send("Please provide a extension. Do `help permunload` for more info") + + extension = extension.lower() + + async with aiofiles.open("extension.txt") as fp: + lines=fp.readlines() + + removed = False + async with aiofiles.open("extension.txt", "w") as fp: + for i in lines: + if i.replace("\n", "") != extension: + fp.write(i) + else: + removed = True + break + + if removed is True: + try: + self.bot.unload_extension(extension) + except: + pass + return await ctx.send("Extension removed successfully") + + await ctx.send("Extension not found") def setup(bot): - bot.add_cog(Upload(bot)) \ No newline at end of file + bot.add_cog(Upload(bot)) diff --git a/src/cogs.txt b/src/extensions.txt similarity index 100% rename from src/cogs.txt rename to src/extensions.txt