From 62ec1b5aecaa32f6437f854cf08eb0a96ec32f5b Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Mon, 21 May 2018 04:37:01 +0200 Subject: [PATCH 01/23] add avatar --- avatar.png | Bin 0 -> 16872 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 avatar.png diff --git a/avatar.png b/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..25d011552c34729c1c429db4052d8285d2c9a963 GIT binary patch literal 16872 zcmV)aK&roqP)*ouy%K6HMyUUGUB1N@27_YDF5wdVVk1^8c_1po4Q@jAT{ zfR~(J1%dwy(RZefKY(6YfIm?ZLVy(Ru_nv^d~JPY0sffuL!GyM!Fzuo7hh!oe{v+A zjqElSzyj8M>)W0eg72f`>__GxNflG1R?QzM@*KfpgarL+4S%Uih zifcy%i0hgsggXa&dGj~_^yV)i5Yjkzt}G~lKq8b6$^&14Cy_>BB@ii)3M%jmOJypw zD4{4(R%0o#rUKz1tp%%{rx2jDyEOeR_vz1804!f)@3SOc@al6KVXv)A)pjc0lIQO*nZm&|2qBo3cxcQ z{C;=DUgPfb;vsOs+GR{8+<#V>TA;4K@jBzh)%i*|&G)R+{>XO zHjmc=FM|sf>ImHm;XY6SN`farDMSDw46uy`w%LY80~;mSW&@%I!jJHp4g7ACt!9&6 z9J4SPr(b5k9BYE`k(S zZ)UZb~ z+~LO7O?HR7bo(9llLoyg=6E^h=l}Tke6me4YhFWtYQL}-JRwY5MZtiWRUwlMHd zUI2br8doy``;7u*ubq1NDC)dh3CHM79xia2i*ynB=D4g)gOUiTu$#Qx0Ht5xo_sa*=9Cd@YVf$ zl%o+Mt6-I5*Dg~-?zeQW@wvo z)-J*#rN9O;M)-h7tJUGnTX*<3x8LP2P}~MQ1Equ%m|!W$Y2nea9ygjzh6no`^*S)k zv0jJ>BdkfGs6doXpf3Z{Zx?|-I{~d4%K&a;;w4DmX{)zksKUzHtouH~^RR&j ze&7T_C%SIrC0HYD50b{W146@7#fi9se(ZV7_g^E2)D8XuUn$oa_ zzEH##=7r@eX?Y|nCOYG`uXsZRG=aS&;b3Q*PunfZaDoVZ2t%j>kZGND*h?2^zr%_C z=?lR3jRK#?)9tmI=_Yu)H0{cnbERqq`{4PtiC2gybkCIsVTgz$2mFI~YsgafcTs=<6DkNR@GG)>#cDQ17X>!-nFzS=Y5tGt z1%E#}K?uoz-oC|Fr$H0w1wJ=AUHXGAXN@y#JBBQP++D8}9@yN)f!_lP`qLMHZ=z=^ zXjcUlAw(VjT*KR;765e>&;>sDA;J%lp$}nziDSp$Xv1(1;usr+?)}XMqS+*DwP<#` zB#kD6R)NK#!@U$1X2a81U$?#9vQ>CC=y_&(Pn!v|AGs1fsEcfc=i?(_Gb-s9}! zFR|w*?)!@Zh!D0wsWs>8Irkv%k-9 zutnPwbUoNrg08FGVG$0Z6&68-Zvs3C4GW=E+-S7fNh0D#3!QZM$od?8qA?e1C&)Ge zv&L2##cILvY{pqx@n+!B6oOvl(+vVH@{F~ucrslu3Iy9Kpd}PL-67rHkW~~RBOjE& zr~s6~dYk&dci(UCg#z*&QnRtJ*Pn0jkE;^wWgzmlmeJp7+Jwomskm*uqX=+0S8!yD0(8H)l7))Bt%8Q|Ghk8 zT#SGm3W2rK;moTw7bnM@EElBx9xWt2FQA_!$Yn-l4QI0v<6c6c0@_ltKj_lybvX1R zj0zB80Dj>ZP+LkXG~ZPR`9T)oS%bY{pLnkJd>sYj#g^c@|JeX2YJ z^Im_*judREkY@cmN+1IkLNLRypk!HA%rnbzQE{jX=2(nS2rFnu9ygjX?@7VCC~jMi zZQz3-Vt(@`4{zOKadt+Tja*hBJ%kD%D_D-l94)3S`aOD9FjO(Sag5ZUO~rV%=p@@%dB&ZG+&fFEOn02}!b;RGO1E|?1

%W53$ZeA$7KmrPy{f^U^zpI60Hgs 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 literal 0 HcmV?d00001 From 8ec62c188e5f0ef8a52609811b78e24df411af86 Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Mon, 21 May 2018 04:53:36 +0200 Subject: [PATCH 02/23] What is a sebi bot without sebisauce? --- cogs.txt | 3 ++- src/cogs/fun.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/cogs/fun.py diff --git a/cogs.txt b/cogs.txt index 5069854..2f73a9d 100644 --- a/cogs.txt +++ b/cogs.txt @@ -1,3 +1,4 @@ example upload -git \ No newline at end of file +git +fun \ No newline at end of file diff --git a/src/cogs/fun.py b/src/cogs/fun.py new file mode 100644 index 0000000..d2295ac --- /dev/null +++ b/src/cogs/fun.py @@ -0,0 +1,42 @@ +#!/usr/bin/python +# -*- coding: -*- + +from discord.ext import commands +import discord +import random + +class Fun: + """ + CogName should be the name of the cog + """ + def __init__(self, bot): + self.bot = bot + + @commands.command() + async def sebisauce(self, ctx): + """ + Get a image related to Sebi. + Sebi is a random guy with perfect code related jokes. + + Usage: + - sebisauce + """ + await ctx.trigger_typing() + source = await self.bot.brequest.aio_json('http://ikbengeslaagd.com/API/sebisauce.json') + + total_sebi = 0 + for key in dict.keys(source): + total_sebi += 1 + + im = random.randint(0, int(total_sebi) - 1) + + msg = await ctx.send( + embed=discord.Embed( + title='\t', + description='\t', + color=0xf20006).set_image( + url=source[str(im)])) + return await msg.add_reaction(self.bot.success) + +def setup(bot): + bot.add_cog(Fun(bot)) From 3f0919d2a824dc76c1840ae4ef12bd4238746b5e Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Mon, 21 May 2018 04:56:02 +0200 Subject: [PATCH 03/23] Remove missing util from sebisauce and replaced it with a static fix --- src/cogs/fun.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cogs/fun.py b/src/cogs/fun.py index d2295ac..3df55ca 100644 --- a/src/cogs/fun.py +++ b/src/cogs/fun.py @@ -4,6 +4,7 @@ from discord.ext import commands import discord import random +import aiohttp class Fun: """ @@ -22,7 +23,10 @@ class Fun: - sebisauce """ await ctx.trigger_typing() - source = await self.bot.brequest.aio_json('http://ikbengeslaagd.com/API/sebisauce.json') + url = 'http://ikbengeslaagd.com/API/sebisauce.json' + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + source = await response.json(encoding='utf8') total_sebi = 0 for key in dict.keys(source): From 7c31e1faed2c0996bf398a2cafeec4387e97fe2e Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Mon, 21 May 2018 04:57:14 +0200 Subject: [PATCH 04/23] Fix reaction which is not needed --- src/cogs/fun.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/cogs/fun.py b/src/cogs/fun.py index 3df55ca..8797dbf 100644 --- a/src/cogs/fun.py +++ b/src/cogs/fun.py @@ -34,13 +34,11 @@ class Fun: im = random.randint(0, int(total_sebi) - 1) - msg = await ctx.send( - embed=discord.Embed( - title='\t', - description='\t', - color=0xf20006).set_image( - url=source[str(im)])) - return await msg.add_reaction(self.bot.success) + await ctx.send(embed=discord.Embed( + title='\t', + description='\t', + color=0xf20006).set_image( + url=source[str(im)])) def setup(bot): bot.add_cog(Fun(bot)) From 24727fe8f11758800d944e8ad69a9d94d83af37c Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Mon, 21 May 2018 04:57:52 +0200 Subject: [PATCH 05/23] Add embed color --- src/cogs/fun.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cogs/fun.py b/src/cogs/fun.py index 8797dbf..09f328d 100644 --- a/src/cogs/fun.py +++ b/src/cogs/fun.py @@ -37,7 +37,7 @@ class Fun: await ctx.send(embed=discord.Embed( title='\t', description='\t', - color=0xf20006).set_image( + color=self.bot.embed_color).set_image( url=source[str(im)])) def setup(bot): From 14d35dc6d4af1401b8c75b96b89da156265c7a2e Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Mon, 21 May 2018 05:03:53 +0200 Subject: [PATCH 06/23] Add exec command --- cogs.txt | 3 +- src/cogs/code.py | 131 ++++++++++++++++++++++++ src/cogs/{upload.py => contributors.py} | 2 + 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/cogs/code.py rename src/cogs/{upload.py => contributors.py} (99%) diff --git a/cogs.txt b/cogs.txt index 2f73a9d..9529ab0 100644 --- a/cogs.txt +++ b/cogs.txt @@ -1,4 +1,5 @@ example -upload +contributors +code git fun \ No newline at end of file diff --git a/src/cogs/code.py b/src/cogs/code.py new file mode 100644 index 0000000..7f07fdd --- /dev/null +++ b/src/cogs/code.py @@ -0,0 +1,131 @@ +from discord.ext import commands +import traceback +import discord +import inspect +import textwrap +from contextlib import redirect_stdout +from discord.errors import HTTPException +import psycopg2 +import io +import asyncio +import re + +class REPL: + """Python in Discords""" + def __init__(self, bot): + self.bot = bot + self._last_result = None + self.sessions = set() + + def cleanup_code(self, content): + """ + Automatically removes code blocks from the code. + """ + # remove ```py\n``` + if content.startswith('```') and content.endswith('```'): + return '\n'.join(content.split('\n')[1:-1]) + + # remove `foo` + return content.strip('` \n') + + def get_syntax_error(self, e): + if e.text is None: + return '{0.__class__.__name__}: {0}'.format(e) + return '{0.text}{1:>{0.offset}}\n{2}: {0}'.format(e, '^', type(e).__name__) + + + @commands.command(hidden=True, name='exec') + async def _eval(self, ctx, *, body: str = None): + """ + Execute python code in discord chat. + Only the owner of this bot can use this command. + + Alias: + - exec + Usage: + - exec < python code > + Example: + - exec print(546132) + """ + if ctx.message.author.id not in self.bot.ownerlist: + return await ctx.send('Only the owner of this bot can use this command') + + if body is None: + return await ctx.send( + 'Please, use\n' + f'`{self.bot.config["prefix"]}exec`\n\n' + '\n`\\`\\`\\`py\n[python code]\n\\`\\`\\`\n' + 'to get the most out of the command') + + env = { + 'bot': self.bot, + 'ctx': ctx, + 'channel': ctx.message.channel, + 'author': ctx.message.author, + 'server': ctx.message.guild, + 'message': ctx.message, + '_': self._last_result + } + + env.update(globals()) + + body = self.cleanup_code(body) + stdout = io.StringIO() + + to_compile = 'async def func():\n%s' % textwrap.indent(body, ' ') + + try: + exec(to_compile, env) + except SyntaxError as e: + try: + msg = 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)] + for i in error: + msg = await ctx.send(f'```py\n{i}\n```') + + func = env['func'] + try: + with redirect_stdout(stdout): + ret = await func() + except Exception as e: + value = stdout.getvalue() + try: + msg = 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)] + for i in tracebackerror: + msg = 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```') + 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```') + 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```') + 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```') + + +def setup(bot): + bot.add_cog(REPL(bot)) \ No newline at end of file diff --git a/src/cogs/upload.py b/src/cogs/contributors.py similarity index 99% rename from src/cogs/upload.py rename to src/cogs/contributors.py index fa8b66e..3933f9d 100644 --- a/src/cogs/upload.py +++ b/src/cogs/contributors.py @@ -83,5 +83,7 @@ class Upload: """triggers error to test traceback""" await ctx.send(a) + + def setup(bot): bot.add_cog(Upload(bot)) \ No newline at end of file From 9b410e0b4862c91b16466f37db94070c931fb491 Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Mon, 21 May 2018 05:13:35 +0200 Subject: [PATCH 07/23] cleanup git commit -m cleanup --- README.md | 21 ++++++++++++++------- run.py | 2 +- src/cogs/code.py | 7 +------ src/config/config.py | 3 ++- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 1e0e30f..4d98aa9 100644 --- a/README.md +++ b/README.md @@ -7,32 +7,39 @@ http://discord.gg/GWdhBSp 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.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.defaultprefix +> self.bot.defaultprefix self.defaultprefix can be used to retrieve a `str` object of the default prefix. -> self.version +> self.bot.version self.version can be used to retrieve a `float` which represent the version number of the bot. -> self.display_name +> self.bot.display_name self.display_name returns a `str` which represent the display_name of the bot. -> self.mainenance +> 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: ```py -if self.mainenance: +if self.bot.mainenance: print('I am in the development branch') -if not self.mainenance: +if not self.bot.mainenance: print('I am in the master branch) ``` With other words. self.mainenance returns False in production and True in developer modus. +> self.bot.embed_color + +self.embed_color can be used to use the default color of out embed theme. +``` +discord.Embed(title='Foo', description='bar', color=self.bot.embed_color) +``` + ## Initialize a cog Cogs can be placed in `./src/cogs`. Overall the `src` folder is the place to put code in. Make sure to update the `requirements.txt` and it is important to add the name of your cog file into the `cogs.txt` list. Otherwise it may turn out that your cog wont load. diff --git a/run.py b/run.py index 3342e7d..c3235a1 100644 --- a/run.py +++ b/run.py @@ -19,7 +19,7 @@ class SebiMachine(commands.Bot, LoadConfig): # Initialize and attach config / settings LoadConfig.__init__(self) commands.Bot.__init__(self, command_prefix=self.defaultprefix) - self.embed_color = discord.Color(0x00FFFF) + # Load plugins # Add your cog file name in this list diff --git a/src/cogs/code.py b/src/cogs/code.py index 7f07fdd..c288ee8 100644 --- a/src/cogs/code.py +++ b/src/cogs/code.py @@ -1,14 +1,9 @@ from discord.ext import commands import traceback -import discord -import inspect import textwrap from contextlib import redirect_stdout -from discord.errors import HTTPException -import psycopg2 import io -import asyncio -import re + class REPL: """Python in Discords""" diff --git a/src/config/config.py b/src/config/config.py index f32d0f6..b6f5acf 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -2,7 +2,7 @@ # -*- coding: -*- import json - +import discord class LoadConfig: """ @@ -19,6 +19,7 @@ class LoadConfig: self.version = self.config["version"] self.display_name = self.config["display_name"] self.maintenance = self.config["maintenance"] + self.embed_color = discord.Color(0x00FFFF) if self.maintenance == 'False': self.maintenance = False else: From 42d8c2e7c86f8a6a6f486d4ff23300fad2d59f46 Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Mon, 21 May 2018 05:20:47 +0200 Subject: [PATCH 08/23] Change in contributers only --- src/cogs/code.py | 6 +++--- src/cogs/contributors.py | 15 +++++++++------ src/cogs/git.py | 4 ++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/cogs/code.py b/src/cogs/code.py index c288ee8..45cf0b6 100644 --- a/src/cogs/code.py +++ b/src/cogs/code.py @@ -29,7 +29,7 @@ class REPL: return '{0.text}{1:>{0.offset}}\n{2}: {0}'.format(e, '^', type(e).__name__) - @commands.command(hidden=True, name='exec') + @commands.command(name='exec') async def _eval(self, ctx, *, body: str = None): """ Execute python code in discord chat. @@ -42,8 +42,8 @@ class REPL: Example: - exec print(546132) """ - if ctx.message.author.id not in self.bot.ownerlist: - return await ctx.send('Only the owner of this bot can use this command') + 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( diff --git a/src/cogs/contributors.py b/src/cogs/contributors.py index 3933f9d..b64824e 100644 --- a/src/cogs/contributors.py +++ b/src/cogs/contributors.py @@ -16,9 +16,9 @@ class Upload: @commands.command() async def reload(self, ctx, *, extension: str): """Reload an extension.""" - + await ctx.trigger_typing() if ctx.author.id not in self.bot.ownerlist: - return await ctx.send('Only my creator can use me like this :blush:', delete_after=10) + return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) extension = extension.lower() try: @@ -33,8 +33,9 @@ class Upload: @commands.command() async def reloadall(self, ctx): """Reload all extensions.""" + await ctx.trigger_typing() if ctx.author.id not in self.bot.ownerlist: - return await ctx.send('Only my creator can use me like this :blush:', delete_after=10) + return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) try: for extension in self.bot.extensions: @@ -47,8 +48,9 @@ class Upload: @commands.command() async def unload(self, ctx, *, extension: str): """Unload an extension.""" + await ctx.trigger_typing() if ctx.author.id not in self.bot.ownerlist: - return await ctx.send('Only my creator can use me like this :blush:', delete_after=10) + return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) extension = extension.lower() try: @@ -65,8 +67,9 @@ class Upload: @commands.command() async def load(self, ctx, *, extension: str): """Load an extension.""" + await ctx.trigger_typing() if ctx.author.id not in self.bot.ownerlist: - return await ctx.send('Only my creator can use me like this :blush:', delete_after=10) + return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) extension = extension.lower() try: @@ -83,7 +86,7 @@ class Upload: """triggers error to test traceback""" await ctx.send(a) - + def setup(bot): bot.add_cog(Upload(bot)) \ No newline at end of file diff --git a/src/cogs/git.py b/src/cogs/git.py index 7c83f98..fa1e3b5 100644 --- a/src/cogs/git.py +++ b/src/cogs/git.py @@ -49,7 +49,7 @@ class Git: async def pull(self, ctx): await ctx.trigger_typing() if ctx.author.id not in self.bot.ownerlist: - return await ctx.send('Only my creator can use me like this :blush:', delete_after=10) + return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) em = discord.Embed(style='rich', title=f'Git Pull', color=self.bot.embed_color) @@ -73,7 +73,7 @@ class Git: async def status(self, ctx): await ctx.trigger_typing() if ctx.author.id not in self.bot.ownerlist: - return await ctx.send('Only my creator can use me like this :blush:', delete_after=10) + return await ctx.send('Only my contributors can use me like this :blush:', delete_after=10) em = discord.Embed(style='rich', title=f'Git Pull', color=self.bot.embed_color) From e5858fecb3eb0713e9c6ab66b52c1a98cb800ffa Mon Sep 17 00:00:00 2001 From: 404 <34942042+neko404notfound@users.noreply.github.com> Date: Mon, 21 May 2018 13:54:54 +0100 Subject: [PATCH 09/23] Added optional uvloop support. uvloop uses libs used by node.js and has been shown to be a much more efficient event loop policy than the default Python asyncio implementation. If uvloop is installed, this is quietly changed before the bot is initialised. If uvloop cannot be set, either from not being installed, or from being used on an unsupported system such as Windoze, then nothing is changed. The only change should be a slight increase in throughput if it is detected. Please test first. --- run.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/run.py b/run.py index 3342e7d..5b81fb4 100644 --- a/run.py +++ b/run.py @@ -2,6 +2,7 @@ # -*- coding: utf8 -*- # Import packages +import asyncio import discord from discord.ext import commands import json @@ -11,6 +12,18 @@ import random # Import custom files from src.config.config import LoadConfig +# 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 +except BaseException as ex: + print(f'Could not load uvloop. {type(ex).__name__}: {ex};', + 'reverting to default impl.') +else: + print(f'Using uvloop for asyncio event loop policy.') + # Bot Class class SebiMachine(commands.Bot, LoadConfig): @@ -67,4 +80,4 @@ if __name__ == '__main__': with open('src/config/PrivateConfig.json') as fp: PrivateConfig = json.load(fp) fp.close() - client.run(PrivateConfig["bot-key"]) \ No newline at end of file + client.run(PrivateConfig["bot-key"]) From 03ba535354792e6fa13c1bbd764ec1bc3dad58f7 Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Mon, 21 May 2018 15:23:42 +0200 Subject: [PATCH 10/23] add uvloop --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index fac7406..0927ad0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ yarl<1.2 numpy==1.14.0 +uvloop From 582beb2a4256a8b8e38545b753124ff31f484f6c Mon Sep 17 00:00:00 2001 From: "Dusty.P" Date: Tue, 22 May 2018 00:06:21 -0800 Subject: [PATCH 11/23] 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 fa1e3b5..a6b2bb0 100644 --- a/src/cogs/git.py +++ b/src/cogs/git.py @@ -75,7 +75,7 @@ class Git: 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) em = discord.Embed(style='rich', - title=f'Git Pull', + title=f'Git Status', color=self.bot.embed_color) em.set_thumbnail(url=f'{ctx.guild.me.avatar_url}') result = await asyncio.wait_for(self.bot.loop.create_task( From 30e9fc328f791b8f933dba3051cb87d6329b26e2 Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Tue, 22 May 2018 21:17:36 +1200 Subject: [PATCH 12/23] ping with times --- src/cogs/example.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cogs/example.py b/src/cogs/example.py index b8e88c8..7390442 100644 --- a/src/cogs/example.py +++ b/src/cogs/example.py @@ -14,7 +14,11 @@ class CogName: @commands.command() async def ping(self, ctx): """Say pong""" - await ctx.send('Pong') + now = ctx.message.created_at + msg = await ctx.send('Pong') + sub = msg.created_at - now + await ctx.edit(content=f'Pong, {sub.total_seconds() * 1000}) + def setup(bot): - bot.add_cog(CogName(bot)) \ No newline at end of file + bot.add_cog(CogName(bot)) From a08f6f5556d8cf49def687a87c772eadb7be97ce Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Tue, 22 May 2018 21:24:24 +1200 Subject: [PATCH 13/23] round two ping with time --- 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 7390442..fe80d0d 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 ctx.edit(content=f'Pong, {sub.total_seconds() * 1000}) + await ctx.edit(content=f'Pong, {sub.total_seconds() * 1000}') def setup(bot): From 7f60b136d44c37509086d5467f9b1819dcd218cf Mon Sep 17 00:00:00 2001 From: Nicholas Date: Tue, 22 May 2018 17:26:07 +0800 Subject: [PATCH 14/23] added djs command for sar --- .vscode/settings.json | 3 ++ run.js | 47 +++++++++++++++++++++++++ run.py | 3 +- src/cogs/sar.js | 67 ++++++++++++++++++++++++++++++++++++ src/shared_libs/aliases.json | 6 ++++ 5 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json create mode 100644 run.js create mode 100644 src/cogs/sar.js create mode 100644 src/shared_libs/aliases.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..cfdb08c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "/usr/bin/python3.6" +} \ No newline at end of file diff --git a/run.js b/run.js new file mode 100644 index 0000000..39901ae --- /dev/null +++ b/run.js @@ -0,0 +1,47 @@ +const Discord = require("discord.js"); +const client = new Discord.Client(); + +const config = require("./src/config/Config.json"); +const prefix = config.prefix; + +const aliases = require("./src/shared_libs/aliases.json"); +const privateConfig = require("./src/config/PrivateConfig.json"); + +const fs = require("fs"); +const commands = fs.readdirSync("./src/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(`./src/cogs/${command}.js`).run(client, message, args); + } + + } catch (err) { + + // handling errors + + } + +}); + +client.login(privateConfig["bot-key"]); \ No newline at end of file diff --git a/run.py b/run.py index dffb7a8..dff506f 100644 --- a/run.py +++ b/run.py @@ -70,7 +70,8 @@ class SebiMachine(commands.Bot, LoadConfig): 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}`**' + # unused variable + # simple_fmt = f'**`{self.defaultprefix}{ctx.command}`**\n{joke}\n\n**{type(error).__name__}:**:\n**`{error}`**' await ctx.send(fmt) diff --git a/src/cogs/sar.js b/src/cogs/sar.js new file mode 100644 index 0000000..19b3639 --- /dev/null +++ b/src/cogs/sar.js @@ -0,0 +1,67 @@ +const Discord = require("discord.js"); + +exports.run = async function(client, message, args) { + + /* + aliases: sar, selfrole, selfroles + + examples: + - S!selfrole get 1 (adds async helper role) + - S!sar remove 4 (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. Async Helper", "S!sar get 1", true) + .addField("2. Heroku Helper", "S!sar get 2", true) + .addField("3. JS Helper", "S!sar get 3", true) + .addField("4. Rewrite Helper", "S!sar get 4", true); + + return message.channel.send({ + embed: embed + }); + + } + + const roles = [roleFinder("Async"), roleFinder("Heroku"), roleFinder("JS"), roleFinder("Rewrite")]; + + let choice = args[1]; // can be 1, 2, 3 or 4 + + // if the choice is not 1, 2, 3 or 4 + if (/^[1234]$/.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/shared_libs/aliases.json b/src/shared_libs/aliases.json new file mode 100644 index 0000000..99e41c5 --- /dev/null +++ b/src/shared_libs/aliases.json @@ -0,0 +1,6 @@ +{ + "sar": "sar", + "selfrole": "sar", + "selfroles": "sar" + +} \ No newline at end of file From c6c2a742696b8173d388dbff961d40e037390522 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Tue, 22 May 2018 17:26:29 +0800 Subject: [PATCH 15/23] added djs command for sar --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 916052a..1982764 100644 --- a/.gitignore +++ b/.gitignore @@ -105,4 +105,5 @@ venv.bak/ /src/config/Config.json /src/config/PrivateConfig.json -.idea/ \ No newline at end of file +.idea/ +.vscode/ \ No newline at end of file From 160737a9abc55df7c10803aaa7a93d62f25dff2e Mon Sep 17 00:00:00 2001 From: Raatty <39517058+Raatty@users.noreply.github.com> Date: Tue, 22 May 2018 21:26:54 +1200 Subject: [PATCH 16/23] i totally know what im doing i promise \s --- 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 fe80d0d..dfdfb7d 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 ctx.edit(content=f'Pong, {sub.total_seconds() * 1000}') + await msg.edit(content=f'Pong, {sub.total_seconds() * 1000}') def setup(bot): From 202cbd4af95a37b83ed85b973326d978bb531770 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Tue, 22 May 2018 17:37:26 +0800 Subject: [PATCH 17/23] updated dockerfile --- dockerfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dockerfile b/dockerfile index 3cce367..29393dd 100644 --- a/dockerfile +++ b/dockerfile @@ -12,8 +12,12 @@ RUN add-apt-repository ppa:deadsnakes/ppa && \ apt-get update && apt-get install python3.6 && \ apt-get install python3-pip -y RUN apt install git -y +RUN apt install curl -y +RUN curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - && \ + apt install nodejs -y +RUN npm install discord.js 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 ['bash', '-c', 'entrypoint.sh'] From 50f9330b6fe69ccc61fcc0ee8c3ce053845d02b1 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Tue, 22 May 2018 17:47:32 +0800 Subject: [PATCH 18/23] added entrypoint.sh --- entrypoint.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 entrypoint.sh diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..e8f1738 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/bash +python3.6 bot.py > bot-log.txt 2>&1 & +nodejs foobar.js > node-log.txt 2>&1 & + +for job in $(jobs -p); do + echo Waiting for ${job} to terminate. + wait ${job} +done \ No newline at end of file From 1bcc04fe948ee3a697c72f36af84cf41bc1bd68f Mon Sep 17 00:00:00 2001 From: Mike Kist Date: Tue, 22 May 2018 12:55:52 +0200 Subject: [PATCH 19/23] fix bot run --- entrypoint.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index e8f1738..6933ab4 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,8 +1,8 @@ #!/bin/bash -python3.6 bot.py > bot-log.txt 2>&1 & +python3.6 run.py > bot-log.txt 2>&1 & nodejs foobar.js > node-log.txt 2>&1 & for job in $(jobs -p); do echo Waiting for ${job} to terminate. wait ${job} -done \ No newline at end of file +done From 626379488d757bd306b144943be1ab1c0036fcd8 Mon Sep 17 00:00:00 2001 From: PuffDip Date: Tue, 22 May 2018 15:41:21 +0200 Subject: [PATCH 20/23] lazy cheeze :^) --- entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/entrypoint.sh b/entrypoint.sh index 6933ab4..f35e484 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,6 +1,6 @@ #!/bin/bash python3.6 run.py > bot-log.txt 2>&1 & -nodejs foobar.js > node-log.txt 2>&1 & +nodejs run.js > node-log.txt 2>&1 & for job in $(jobs -p); do echo Waiting for ${job} to terminate. From 5f9368e03701da35f366108929c74417816e4e56 Mon Sep 17 00:00:00 2001 From: PuffDip Date: Tue, 22 May 2018 16:09:13 +0200 Subject: [PATCH 21/23] Add Trello to readme --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d98aa9..169f2a7 100644 --- a/README.md +++ b/README.md @@ -46,4 +46,7 @@ Make sure to update the `requirements.txt` and it is important to add the name o ## Update source code There is a git command available provided by Dusty. `S!git pull` should pull the latest commits into the docker container. Make sure afterwards to reload the cog. -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`. \ No newline at end of file +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`. + +## Trello +We do make use of Trello which can be found here: https://trello.com/b/x02goBbW/sebis-bot-tutorial-roadmap \ No newline at end of file From b8f5f0da0c05b25895dfdaf55fa7f62e06f525b8 Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Tue, 22 May 2018 22:35:12 +0200 Subject: [PATCH 22/23] Rebase project v0.1 --- .gitignore | 5 +- .vscode/settings.json | 3 - README.md | 19 ++- dockerfile | 6 +- entrypoint.sh | 8 -- run.js | 47 ------- run.py | 3 +- src/cogs/code.py | 250 +++++++++++++++++----------------- src/cogs/contributors.py | 182 ++++++++++++------------- src/cogs/example.py | 48 +++---- src/cogs/fun.py | 88 ++++++------ src/cogs/git.py | 180 ++++++++++++------------ src/cogs/sar.js | 67 --------- src/config/Config.json | 7 + src/config/PrivateConfig.json | 3 + src/shared_libs/aliases.json | 10 +- src/shared_libs/utils.py | 224 +++++++++++++++--------------- 17 files changed, 519 insertions(+), 631 deletions(-) delete mode 100644 .vscode/settings.json delete mode 100644 entrypoint.sh delete mode 100644 run.js delete mode 100644 src/cogs/sar.js create mode 100644 src/config/Config.json create mode 100644 src/config/PrivateConfig.json diff --git a/.gitignore b/.gitignore index 1982764..4ad6467 100644 --- a/.gitignore +++ b/.gitignore @@ -103,7 +103,4 @@ venv.bak/ # mypy .mypy_cache/ -/src/config/Config.json -/src/config/PrivateConfig.json -.idea/ -.vscode/ \ No newline at end of file +.idea/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index cfdb08c..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.pythonPath": "/usr/bin/python3.6" -} \ No newline at end of file diff --git a/README.md b/README.md index 169f2a7..eea3036 100644 --- a/README.md +++ b/README.md @@ -39,14 +39,25 @@ self.embed_color can be used to use the default color of out embed theme. ``` 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. + +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 ## Initialize a cog -Cogs can be placed in `./src/cogs`. Overall the `src` folder is the place to put code in. -Make sure to update the `requirements.txt` and it is important to add the name of your cog file into the `cogs.txt` list. Otherwise it may turn out that your cog wont load. +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. ## Update source code There is a git command available provided by Dusty. `S!git pull` should pull the latest commits into the docker container. Make sure afterwards to reload the cog. 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`. -## Trello -We do make use of Trello which can be found here: https://trello.com/b/x02goBbW/sebis-bot-tutorial-roadmap \ No newline at end of file +## Project links: + - http://discord.gg/GWdhBSp + - http://chillout.ueuo.com + - http://trello.com/b/x02goBbW/sebis-bot-tutorial-roadmap + diff --git a/dockerfile b/dockerfile index 29393dd..3cce367 100644 --- a/dockerfile +++ b/dockerfile @@ -12,12 +12,8 @@ RUN add-apt-repository ppa:deadsnakes/ppa && \ apt-get update && apt-get install python3.6 && \ apt-get install python3-pip -y RUN apt install git -y -RUN apt install curl -y -RUN curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash - && \ - apt install nodejs -y -RUN npm install discord.js 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 ['bash', '-c', 'entrypoint.sh'] +cmd ["python3.6","run.py"] diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100644 index f35e484..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -python3.6 run.py > bot-log.txt 2>&1 & -nodejs run.js > node-log.txt 2>&1 & - -for job in $(jobs -p); do - echo Waiting for ${job} to terminate. - wait ${job} -done diff --git a/run.js b/run.js deleted file mode 100644 index 39901ae..0000000 --- a/run.js +++ /dev/null @@ -1,47 +0,0 @@ -const Discord = require("discord.js"); -const client = new Discord.Client(); - -const config = require("./src/config/Config.json"); -const prefix = config.prefix; - -const aliases = require("./src/shared_libs/aliases.json"); -const privateConfig = require("./src/config/PrivateConfig.json"); - -const fs = require("fs"); -const commands = fs.readdirSync("./src/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(`./src/cogs/${command}.js`).run(client, message, args); - } - - } catch (err) { - - // handling errors - - } - -}); - -client.login(privateConfig["bot-key"]); \ No newline at end of file diff --git a/run.py b/run.py index dff506f..dffb7a8 100644 --- a/run.py +++ b/run.py @@ -70,8 +70,7 @@ class SebiMachine(commands.Bot, LoadConfig): 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```' - # unused variable - # simple_fmt = f'**`{self.defaultprefix}{ctx.command}`**\n{joke}\n\n**{type(error).__name__}:**:\n**`{error}`**' + simple_fmt = f'**`{self.defaultprefix}{ctx.command}`**\n{joke}\n\n**{type(error).__name__}:**:\n**`{error}`**' await ctx.send(fmt) diff --git a/src/cogs/code.py b/src/cogs/code.py index 45cf0b6..69bea4d 100644 --- a/src/cogs/code.py +++ b/src/cogs/code.py @@ -1,126 +1,126 @@ -from discord.ext import commands -import traceback -import textwrap -from contextlib import redirect_stdout -import io - - -class REPL: - """Python in Discords""" - def __init__(self, bot): - self.bot = bot - self._last_result = None - self.sessions = set() - - def cleanup_code(self, content): - """ - Automatically removes code blocks from the code. - """ - # remove ```py\n``` - if content.startswith('```') and content.endswith('```'): - return '\n'.join(content.split('\n')[1:-1]) - - # remove `foo` - return content.strip('` \n') - - def get_syntax_error(self, e): - if e.text is None: - return '{0.__class__.__name__}: {0}'.format(e) - return '{0.text}{1:>{0.offset}}\n{2}: {0}'.format(e, '^', type(e).__name__) - - - @commands.command(name='exec') - async def _eval(self, ctx, *, body: str = None): - """ - Execute python code in discord chat. - Only the owner of this bot can use this command. - - Alias: - - exec - Usage: - - exec < python code > - Example: - - exec print(546132) - """ - 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' - f'`{self.bot.config["prefix"]}exec`\n\n' - '\n`\\`\\`\\`py\n[python code]\n\\`\\`\\`\n' - 'to get the most out of the command') - - env = { - 'bot': self.bot, - 'ctx': ctx, - 'channel': ctx.message.channel, - 'author': ctx.message.author, - 'server': ctx.message.guild, - 'message': ctx.message, - '_': self._last_result - } - - env.update(globals()) - - body = self.cleanup_code(body) - stdout = io.StringIO() - - to_compile = 'async def func():\n%s' % textwrap.indent(body, ' ') - - try: - exec(to_compile, env) - except SyntaxError as e: - try: - msg = 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)] - for i in error: - msg = await ctx.send(f'```py\n{i}\n```') - - func = env['func'] - try: - with redirect_stdout(stdout): - ret = await func() - except Exception as e: - value = stdout.getvalue() - try: - msg = 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)] - for i in tracebackerror: - msg = 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```') - 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```') - 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```') - 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```') - - -def setup(bot): +from discord.ext import commands +import traceback +import textwrap +from contextlib import redirect_stdout +import io + + +class REPL: + """Python in Discords""" + def __init__(self, bot): + self.bot = bot + self._last_result = None + self.sessions = set() + + def cleanup_code(self, content): + """ + Automatically removes code blocks from the code. + """ + # remove ```py\n``` + if content.startswith('```') and content.endswith('```'): + return '\n'.join(content.split('\n')[1:-1]) + + # remove `foo` + return content.strip('` \n') + + def get_syntax_error(self, e): + if e.text is None: + return '{0.__class__.__name__}: {0}'.format(e) + return '{0.text}{1:>{0.offset}}\n{2}: {0}'.format(e, '^', type(e).__name__) + + + @commands.command(name='exec') + async def _eval(self, ctx, *, body: str = None): + """ + Execute python code in discord chat. + Only the owner of this bot can use this command. + + Alias: + - exec + Usage: + - exec < python code > + Example: + - exec print(546132) + """ + 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' + f'`{self.bot.config["prefix"]}exec`\n\n' + '\n`\\`\\`\\`py\n[python code]\n\\`\\`\\`\n' + 'to get the most out of the command') + + env = { + 'bot': self.bot, + 'ctx': ctx, + 'channel': ctx.message.channel, + 'author': ctx.message.author, + 'server': ctx.message.guild, + 'message': ctx.message, + '_': self._last_result + } + + env.update(globals()) + + body = self.cleanup_code(body) + stdout = io.StringIO() + + to_compile = 'async def func():\n%s' % textwrap.indent(body, ' ') + + try: + exec(to_compile, env) + except SyntaxError as e: + try: + msg = 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)] + for i in error: + msg = await ctx.send(f'```py\n{i}\n```') + + func = env['func'] + try: + with redirect_stdout(stdout): + ret = await func() + except Exception as e: + value = stdout.getvalue() + try: + msg = 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)] + for i in tracebackerror: + msg = 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```') + 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```') + 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```') + 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```') + + +def setup(bot): bot.add_cog(REPL(bot)) \ No newline at end of file diff --git a/src/cogs/contributors.py b/src/cogs/contributors.py index b64824e..f546128 100644 --- a/src/cogs/contributors.py +++ b/src/cogs/contributors.py @@ -1,92 +1,92 @@ -#!/usr/bin/python -# -*- coding: -*- - -from discord.ext import commands -import os -import traceback - -class Upload: - """ - CogName should be the name of the cog - """ - def __init__(self, bot): - self.bot = bot - print('upload loaded') - - @commands.command() - async def reload(self, ctx, *, extension: str): - """Reload an extension.""" - 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) - - extension = extension.lower() - try: - self.bot.unload_extension("src.cogs.{}".format(extension)) - self.bot.load_extension("src.cogs.{}".format(extension)) - except Exception as e: - traceback.print_exc() - await ctx.send(f'Could not reload `{extension}` -> `{e}`') - else: - await ctx.send(f'Reloaded `{extension}`.') - - @commands.command() - async def reloadall(self, ctx): - """Reload all extensions.""" - 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) - - try: - for extension in self.bot.extensions: - self.bot.unload_extension(extension) - self.bot.load_extension(extension) - await ctx.send(f"Reload success! :thumbsup:\n") - except Exception as e: - await ctx.send(f"Could not reload `{extension}` -> `{e}`.\n") - - @commands.command() - async def unload(self, ctx, *, extension: str): - """Unload an extension.""" - 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) - - extension = extension.lower() - try: - self.bot.unload_extension("src.cogs.{}".format(extension)) - - except Exception as e: - traceback.print_exc() - if ctx.message.author.id not in self.bot.owner_list: - await ctx.send(f'Could not unload `{extension}` -> `{e}`') - - else: - await ctx.send(f'Unloaded `{extension}`.') - - @commands.command() - async def load(self, ctx, *, extension: str): - """Load an extension.""" - 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) - - extension = extension.lower() - try: - self.bot.load_extension("src.cogs.{}".format(extension)) - - except Exception as e: - traceback.print_exc() - await ctx.send(f'Could not unload `{extension}` -> `{e}`') - else: - await ctx.send(f'Loaded `{extension}`.') - - @commands.command() - async def err(self, ctx): - """triggers error to test traceback""" - await ctx.send(a) - - - -def setup(bot): +#!/usr/bin/python +# -*- coding: -*- + +from discord.ext import commands +import os +import traceback + +class Upload: + """ + CogName should be the name of the cog + """ + def __init__(self, bot): + self.bot = bot + print('upload loaded') + + @commands.command() + async def reload(self, ctx, *, extension: str): + """Reload an extension.""" + 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) + + extension = extension.lower() + try: + self.bot.unload_extension("src.cogs.{}".format(extension)) + self.bot.load_extension("src.cogs.{}".format(extension)) + except Exception as e: + traceback.print_exc() + await ctx.send(f'Could not reload `{extension}` -> `{e}`') + else: + await ctx.send(f'Reloaded `{extension}`.') + + @commands.command() + async def reloadall(self, ctx): + """Reload all extensions.""" + 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) + + try: + for extension in self.bot.extensions: + self.bot.unload_extension(extension) + self.bot.load_extension(extension) + await ctx.send(f"Reload success! :thumbsup:\n") + except Exception as e: + await ctx.send(f"Could not reload `{extension}` -> `{e}`.\n") + + @commands.command() + async def unload(self, ctx, *, extension: str): + """Unload an extension.""" + 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) + + extension = extension.lower() + try: + self.bot.unload_extension("src.cogs.{}".format(extension)) + + except Exception as e: + traceback.print_exc() + if ctx.message.author.id not in self.bot.owner_list: + await ctx.send(f'Could not unload `{extension}` -> `{e}`') + + else: + await ctx.send(f'Unloaded `{extension}`.') + + @commands.command() + async def load(self, ctx, *, extension: str): + """Load an extension.""" + 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) + + extension = extension.lower() + try: + self.bot.load_extension("src.cogs.{}".format(extension)) + + except Exception as e: + traceback.print_exc() + await ctx.send(f'Could not unload `{extension}` -> `{e}`') + else: + await ctx.send(f'Loaded `{extension}`.') + + @commands.command() + async def err(self, ctx): + """triggers error to test traceback""" + await ctx.send(a) + + + +def setup(bot): bot.add_cog(Upload(bot)) \ No newline at end of file diff --git a/src/cogs/example.py b/src/cogs/example.py index dfdfb7d..de1c1da 100644 --- a/src/cogs/example.py +++ b/src/cogs/example.py @@ -1,24 +1,24 @@ -#!/usr/bin/python -# -*- coding: -*- - -from discord.ext import commands -import discord - -class CogName: - """ - CogName should be the name of the cog - """ - def __init__(self, bot): - self.bot = bot - - @commands.command() - async def ping(self, ctx): - """Say pong""" - 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}') - - -def setup(bot): - bot.add_cog(CogName(bot)) +#!/usr/bin/python +# -*- coding: -*- + +from discord.ext import commands +import discord + +class CogName: + """ + CogName should be the name of the cog + """ + def __init__(self, bot): + self.bot = bot + + @commands.command() + async def ping(self, ctx): + """Say pong""" + 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}') + + +def setup(bot): + bot.add_cog(CogName(bot)) diff --git a/src/cogs/fun.py b/src/cogs/fun.py index 09f328d..d066435 100644 --- a/src/cogs/fun.py +++ b/src/cogs/fun.py @@ -1,44 +1,44 @@ -#!/usr/bin/python -# -*- coding: -*- - -from discord.ext import commands -import discord -import random -import aiohttp - -class Fun: - """ - CogName should be the name of the cog - """ - def __init__(self, bot): - self.bot = bot - - @commands.command() - async def sebisauce(self, ctx): - """ - Get a image related to Sebi. - Sebi is a random guy with perfect code related jokes. - - Usage: - - sebisauce - """ - await ctx.trigger_typing() - url = 'http://ikbengeslaagd.com/API/sebisauce.json' - async with aiohttp.ClientSession() as session: - async with session.get(url) as response: - source = await response.json(encoding='utf8') - - total_sebi = 0 - for key in dict.keys(source): - total_sebi += 1 - - im = random.randint(0, int(total_sebi) - 1) - - await ctx.send(embed=discord.Embed( - title='\t', - description='\t', - color=self.bot.embed_color).set_image( - url=source[str(im)])) - -def setup(bot): - bot.add_cog(Fun(bot)) +#!/usr/bin/python +# -*- coding: -*- + +from discord.ext import commands +import discord +import random +import aiohttp + +class Fun: + """ + CogName should be the name of the cog + """ + def __init__(self, bot): + self.bot = bot + + @commands.command() + async def sebisauce(self, ctx): + """ + Get a image related to Sebi. + Sebi is a random guy with perfect code related jokes. + + Usage: + - sebisauce + """ + await ctx.trigger_typing() + url = 'http://ikbengeslaagd.com/API/sebisauce.json' + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + source = await response.json(encoding='utf8') + + total_sebi = 0 + for key in dict.keys(source): + total_sebi += 1 + + im = random.randint(0, int(total_sebi) - 1) + + await ctx.send(embed=discord.Embed( + title='\t', + description='\t', + color=self.bot.embed_color).set_image( + url=source[str(im)])) + +def setup(bot): + bot.add_cog(Fun(bot)) diff --git a/src/cogs/git.py b/src/cogs/git.py index a6b2bb0..b1072a3 100644 --- a/src/cogs/git.py +++ b/src/cogs/git.py @@ -1,90 +1,90 @@ -""" -=== - -MIT License - -Copyright (c) 2018 Dusty.P https://github.com/dustinpianalto - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -""" - - -import discord -from discord.ext import commands -import logging -from ..shared_libs.utils import paginate, run_command -import asyncio - -git_log = logging.getLogger('git') - - -class Git: - def __init__(self, bot): - self.bot = bot - - @commands.group(case_insensitive=True) - async def git(self, ctx): - """Run help git for more info""" - pass - - @git.command() - async def pull(self, ctx): - 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) - em = discord.Embed(style='rich', - title=f'Git Pull', - color=self.bot.embed_color) - em.set_thumbnail(url=f'{ctx.guild.me.avatar_url}') - - 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( - run_command('git reset --hard origin/$(git rev-parse ' - '--symbolic-full-name --abbrev-ref HEAD)')), - 120) + '\n\n' - result += await asyncio.wait_for(self.bot.loop.create_task( - run_command('git show --stat | sed "s/.*@.*[.].*/ /g"')), 10) - - results = paginate(result, maxlen=1014) - for page in results[:5]: - em.add_field(name='\uFFF0', value=f'{page}') - await ctx.send(embed=em) - - @git.command() - async def status(self, ctx): - 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) - em = discord.Embed(style='rich', - title=f'Git Status', - color=self.bot.embed_color) - em.set_thumbnail(url=f'{ctx.guild.me.avatar_url}') - result = await asyncio.wait_for(self.bot.loop.create_task( - run_command('git status')), 10) - results = paginate(result, maxlen=1014) - for page in results[:5]: - em.add_field(name='\uFFF0', value=f'{page}') - await ctx.send(embed=em) - - -def setup(bot): - bot.add_cog(Git(bot)) +""" +=== + +MIT License + +Copyright (c) 2018 Dusty.P https://github.com/dustinpianalto + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +""" + + +import discord +from discord.ext import commands +import logging +from ..shared_libs.utils import paginate, run_command +import asyncio + +git_log = logging.getLogger('git') + + +class Git: + def __init__(self, bot): + self.bot = bot + + @commands.group(case_insensitive=True) + async def git(self, ctx): + """Run help git for more info""" + pass + + @git.command() + async def pull(self, ctx): + 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) + em = discord.Embed(style='rich', + title=f'Git Pull', + color=self.bot.embed_color) + em.set_thumbnail(url=f'{ctx.guild.me.avatar_url}') + + 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( + run_command('git reset --hard origin/$(git rev-parse ' + '--symbolic-full-name --abbrev-ref HEAD)')), + 120) + '\n\n' + result += await asyncio.wait_for(self.bot.loop.create_task( + run_command('git show --stat | sed "s/.*@.*[.].*/ /g"')), 10) + + results = paginate(result, maxlen=1014) + for page in results[:5]: + em.add_field(name='\uFFF0', value=f'{page}') + await ctx.send(embed=em) + + @git.command() + async def status(self, ctx): + 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) + em = discord.Embed(style='rich', + title=f'Git Status', + color=self.bot.embed_color) + em.set_thumbnail(url=f'{ctx.guild.me.avatar_url}') + result = await asyncio.wait_for(self.bot.loop.create_task( + run_command('git status')), 10) + results = paginate(result, maxlen=1014) + for page in results[:5]: + em.add_field(name='\uFFF0', value=f'{page}') + await ctx.send(embed=em) + + +def setup(bot): + bot.add_cog(Git(bot)) diff --git a/src/cogs/sar.js b/src/cogs/sar.js deleted file mode 100644 index 19b3639..0000000 --- a/src/cogs/sar.js +++ /dev/null @@ -1,67 +0,0 @@ -const Discord = require("discord.js"); - -exports.run = async function(client, message, args) { - - /* - aliases: sar, selfrole, selfroles - - examples: - - S!selfrole get 1 (adds async helper role) - - S!sar remove 4 (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. Async Helper", "S!sar get 1", true) - .addField("2. Heroku Helper", "S!sar get 2", true) - .addField("3. JS Helper", "S!sar get 3", true) - .addField("4. Rewrite Helper", "S!sar get 4", true); - - return message.channel.send({ - embed: embed - }); - - } - - const roles = [roleFinder("Async"), roleFinder("Heroku"), roleFinder("JS"), roleFinder("Rewrite")]; - - let choice = args[1]; // can be 1, 2, 3 or 4 - - // if the choice is not 1, 2, 3 or 4 - if (/^[1234]$/.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/config/Config.json b/src/config/Config.json new file mode 100644 index 0000000..62c06ae --- /dev/null +++ b/src/config/Config.json @@ -0,0 +1,7 @@ +{ + "version": 0.1, + "display_name" : "[S!] Sebi-Machine", + "maintenance": "True", + "ownerlist": [], + "prefix": "S!" +} \ No newline at end of file diff --git a/src/config/PrivateConfig.json b/src/config/PrivateConfig.json new file mode 100644 index 0000000..9fa108b --- /dev/null +++ b/src/config/PrivateConfig.json @@ -0,0 +1,3 @@ +{ + "bot-key": "" +} \ No newline at end of file diff --git a/src/shared_libs/aliases.json b/src/shared_libs/aliases.json index 99e41c5..2890f82 100644 --- a/src/shared_libs/aliases.json +++ b/src/shared_libs/aliases.json @@ -1,6 +1,6 @@ -{ - "sar": "sar", - "selfrole": "sar", - "selfroles": "sar" - +{ + "sar": "sar", + "selfrole": "sar", + "selfroles": "sar" + } \ No newline at end of file diff --git a/src/shared_libs/utils.py b/src/shared_libs/utils.py index 47a8ff4..9ba5998 100644 --- a/src/shared_libs/utils.py +++ b/src/shared_libs/utils.py @@ -1,113 +1,113 @@ -""" -=== - -MIT License - -Copyright (c) 2018 Dusty.P https://github.com/dustinpianalto - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -""" - - -from io import StringIO -import sys -import asyncio -import discord -from discord.ext.commands.formatter import Paginator -import numpy as np - - -class Capturing(list): - def __enter__(self): - self._stdout = sys.stdout - sys.stdout = self._stringio = StringIO() - return self - - def __exit__(self, *args): - self.extend(self._stringio.getvalue().splitlines()) - del self._stringio # free up some memory - sys.stdout = self._stdout - - -def to_list_of_str(items, out: list=list(), level=1, recurse=0): - def rec_loop(item, key, out, level): - quote = '"' - if type(item) == list: - out.append(f'{" "*level}{quote+key+quote+": " if key else ""}[') - new_level = level + 1 - out = to_list_of_str(item, out, new_level, 1) - out.append(f'{" "*level}]') - elif type(item) == dict: - out.append(f'{" "*level}{quote+key+quote+": " if key else ""}{{') - new_level = level + 1 - out = to_list_of_str(item, out, new_level, 1) - out.append(f'{" "*level}}}') - else: - out.append(f'{" "*level}{quote+key+quote+": " if key else ""}{repr(item)},') - - if type(items) == list: - if not recurse: - out = list() - out.append('[') - for item in items: - rec_loop(item, None, out, level) - if not recurse: - out.append(']') - elif type(items) == dict: - if not recurse: - out = list() - out.append('{') - for key in items: - rec_loop(items[key], key, out, level) - if not recurse: - out.append('}') - - return out - - -def paginate(text, maxlen=1990): - paginator = Paginator(prefix='```py', max_size=maxlen+10) - if type(text) == list: - data = to_list_of_str(text) - elif type(text) == dict: - data = to_list_of_str(text) - else: - data = str(text).split('\n') - for line in data: - if len(line) > maxlen: - n = maxlen - for l in [line[i:i+n] for i in range(0, len(line), n)]: - paginator.add_line(l) - else: - paginator.add_line(line) - return paginator.pages - - -async def run_command(args): - # Create subprocess - process = await asyncio.create_subprocess_shell( - args, - # stdout must a pipe to be accessible as process.stdout - stdout=asyncio.subprocess.PIPE) - # Wait for the subprocess to finish - stdout, stderr = await process.communicate() - # Return stdout +""" +=== + +MIT License + +Copyright (c) 2018 Dusty.P https://github.com/dustinpianalto + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +""" + + +from io import StringIO +import sys +import asyncio +import discord +from discord.ext.commands.formatter import Paginator +import numpy as np + + +class Capturing(list): + def __enter__(self): + self._stdout = sys.stdout + sys.stdout = self._stringio = StringIO() + return self + + def __exit__(self, *args): + self.extend(self._stringio.getvalue().splitlines()) + del self._stringio # free up some memory + sys.stdout = self._stdout + + +def to_list_of_str(items, out: list=list(), level=1, recurse=0): + def rec_loop(item, key, out, level): + quote = '"' + if type(item) == list: + out.append(f'{" "*level}{quote+key+quote+": " if key else ""}[') + new_level = level + 1 + out = to_list_of_str(item, out, new_level, 1) + out.append(f'{" "*level}]') + elif type(item) == dict: + out.append(f'{" "*level}{quote+key+quote+": " if key else ""}{{') + new_level = level + 1 + out = to_list_of_str(item, out, new_level, 1) + out.append(f'{" "*level}}}') + else: + out.append(f'{" "*level}{quote+key+quote+": " if key else ""}{repr(item)},') + + if type(items) == list: + if not recurse: + out = list() + out.append('[') + for item in items: + rec_loop(item, None, out, level) + if not recurse: + out.append(']') + elif type(items) == dict: + if not recurse: + out = list() + out.append('{') + for key in items: + rec_loop(items[key], key, out, level) + if not recurse: + out.append('}') + + return out + + +def paginate(text, maxlen=1990): + paginator = Paginator(prefix='```py', max_size=maxlen+10) + if type(text) == list: + data = to_list_of_str(text) + elif type(text) == dict: + data = to_list_of_str(text) + else: + data = str(text).split('\n') + for line in data: + if len(line) > maxlen: + n = maxlen + for l in [line[i:i+n] for i in range(0, len(line), n)]: + paginator.add_line(l) + else: + paginator.add_line(line) + return paginator.pages + + +async def run_command(args): + # Create subprocess + process = await asyncio.create_subprocess_shell( + args, + # stdout must a pipe to be accessible as process.stdout + stdout=asyncio.subprocess.PIPE) + # Wait for the subprocess to finish + stdout, stderr = await process.communicate() + # Return stdout return stdout.decode().strip() \ No newline at end of file From 557879451cdae31b8b3d5c9b7e4eff4e105a74ed Mon Sep 17 00:00:00 2001 From: annihilator708 Date: Tue, 22 May 2018 22:38:26 +0200 Subject: [PATCH 23/23] secure config files to block them in ignore file --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4ad6467..5f2b3dc 100644 --- a/.gitignore +++ b/.gitignore @@ -103,4 +103,6 @@ venv.bak/ # mypy .mypy_cache/ -.idea/ \ No newline at end of file +/src/config/Config.json +/src/config/PrivateConfig.json +.idea/