Compare commits
300
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
897c77fee6 | ||
|
|
9c340116eb | ||
|
|
52174175ef | ||
|
|
0858fbc7d5 | ||
|
|
3e75b20c54 | ||
|
|
3dc75dabe6 | ||
|
|
db525d0048 | ||
|
|
35ab455a7c | ||
|
|
66cbaffc7a | ||
|
|
71686b4cc2 | ||
|
|
7ac58a435c | ||
|
|
d596db870b | ||
|
|
69109dc3a9 | ||
|
|
c4a0398a60 | ||
|
|
90ca2d0fac | ||
|
|
4bf8649950 | ||
|
|
70545be638 | ||
|
|
d56fb072bb | ||
|
|
49894b2dd7 | ||
|
|
b4a5f83689 | ||
|
|
63b87bf1c7 | ||
|
|
dd96a9cf90 | ||
|
|
9c281c6d7f | ||
|
|
0c4fd467ff | ||
|
|
f11f53ac81 | ||
|
|
dc51b4e6b6 | ||
|
|
3531459b03 | ||
|
|
31a245a7db | ||
|
|
8c7f33c166 | ||
|
|
512588a34c | ||
|
|
7c3e9726f9 | ||
|
|
95c7bcb928 | ||
|
|
44c8ca1eb5 | ||
|
|
9d894a4438 | ||
|
|
2bdbdb9749 | ||
|
|
9b47aff4b0 | ||
|
|
54d5be24e8 | ||
|
|
d616a94709 | ||
|
|
f8fe207721 | ||
|
|
2259900dcd | ||
|
|
ec6cd95c9e | ||
|
|
d14de7a964 | ||
|
|
a77f976562 | ||
|
|
687c62dce7 | ||
|
|
778e9890ba | ||
|
|
b46d8dd366 | ||
|
|
46c9075397 | ||
|
|
677fc9a60e | ||
|
|
4c70c67f31 | ||
|
|
240d606f2b | ||
|
|
47815c7119 | ||
|
|
b672768ef4 | ||
|
|
576f070cf2 | ||
|
|
ca25f6e07a | ||
|
|
bf89d6f1ba | ||
|
|
f9b2fe0a25 | ||
|
|
5c60a9ec7a | ||
|
|
916e605a6e | ||
|
|
b9689b502d | ||
|
|
ee258bc62f | ||
|
|
eaa8511455 | ||
|
|
2537b8331a | ||
|
|
3791d205de | ||
|
|
011daf3063 | ||
|
|
4963d773e2 | ||
|
|
87566fffcd | ||
|
|
97d7dc7e25 | ||
|
|
b5c0e002ab | ||
|
|
d989591431 | ||
|
|
eab32f3b84 | ||
|
|
1dca5d41bb | ||
|
|
8b5af80bad | ||
|
|
340ab4b140 | ||
|
|
d9f4858485 | ||
|
|
499adbfced | ||
|
|
fc1a6c63d7 | ||
|
|
641cdb7150 | ||
|
|
643a7776df | ||
|
|
7797e8c771 | ||
|
|
d5c5801e3a | ||
|
|
7f37194574 | ||
|
|
98c84c8442 | ||
|
|
2773de1503 | ||
|
|
34183adcfb | ||
|
|
73e5a227a5 | ||
|
|
c2e6495be3 | ||
|
|
5447601cec | ||
|
|
19155577fa | ||
|
|
3f33154606 | ||
|
|
bbee079d2c | ||
|
|
4cd62e1e05 | ||
|
|
f7fab22d81 | ||
|
|
51ac2ba474 | ||
|
|
7d901f55f9 | ||
|
|
1c022ad214 | ||
|
|
f174b0cbfa | ||
|
|
71cf7a44a7 | ||
|
|
103f715969 | ||
|
|
b1574a96d7 | ||
|
|
feefff0a2b | ||
|
|
3d8c3b0d88 | ||
|
|
fc655767f7 | ||
|
|
222159f059 | ||
|
|
cb7290be00 | ||
|
|
88d0af40c5 | ||
|
|
681936b211 | ||
|
|
e83f283e60 | ||
|
|
377201f5ca | ||
|
|
83787333e5 | ||
|
|
34174cb148 | ||
|
|
35d383420f | ||
|
|
c52d708af9 | ||
|
|
d6b53bb07c | ||
|
|
a24749dd63 | ||
|
|
63006cd200 | ||
|
|
910686d80b | ||
|
|
6312d21b00 | ||
|
|
4c52d9eafc | ||
|
|
12db8a520d | ||
|
|
95fce3f636 | ||
|
|
8746cd0bcf | ||
|
|
59a7bb37c6 | ||
|
|
ab14f9da3c | ||
|
|
ee2ebe4274 | ||
|
|
714d5cd229 | ||
|
|
05536052e9 | ||
|
|
ab83f968b9 | ||
|
|
08d8f424be | ||
|
|
82cf5d9856 | ||
|
|
dc98e5eea3 | ||
|
|
4e8bee6785 | ||
|
|
61e774bc5a | ||
|
|
7344187eb1 | ||
|
|
a6273e6856 | ||
|
|
9d6216e344 | ||
|
|
b031adce62 | ||
|
|
38469d38b2 | ||
|
|
077a9e66b3 | ||
|
|
5edc0c98ef | ||
|
|
9799265c0a | ||
|
|
994e257026 | ||
|
|
4801daeafe | ||
|
|
8104302e43 | ||
|
|
0600b883fe | ||
|
|
3700ab2344 | ||
|
|
762984592b | ||
|
|
1c778e4a49 | ||
|
|
08c3d8a79c | ||
|
|
061c39a8eb | ||
|
|
0d45b8b827 | ||
|
|
8a68823f82 | ||
|
|
914ee90f70 | ||
|
|
39bf9c71fb | ||
|
|
b782bf681a | ||
|
|
789eee5b2e | ||
|
|
42388f4b63 | ||
|
|
6c4de0fb58 | ||
|
|
54d631df67 | ||
|
|
1102b54972 | ||
|
|
80a6c0c924 | ||
|
|
96ca3208e8 | ||
|
|
bfa9d7c1ef | ||
|
|
4945ac630b | ||
|
|
5ed3152dc9 | ||
|
|
b56e57d939 | ||
|
|
2b41489bd6 | ||
|
|
1434ac36c4 | ||
|
|
dd1e0d8812 | ||
|
|
679a49d9e4 | ||
|
|
c7532b6ed7 | ||
|
|
84a7734f39 | ||
|
|
cedf030345 | ||
|
|
cd79629340 | ||
|
|
999ebae413 | ||
|
|
127bd483b2 | ||
|
|
bb46a28a1a | ||
|
|
2fdac0b854 | ||
|
|
73ce5de59f | ||
|
|
0fc8d6644d | ||
|
|
d5e4a5dbd7 | ||
|
|
55fb9ae3e7 | ||
|
|
70dbc350c2 | ||
|
|
cf729b094b | ||
|
|
43477595b2 | ||
|
|
f188a145eb | ||
|
|
ca5b862852 | ||
|
|
e2252f7140 | ||
|
|
ea177a3d71 | ||
|
|
73503c9199 | ||
|
|
02f189781f | ||
|
|
352470e364 | ||
|
|
cc9a934fe6 | ||
|
|
70535d0399 | ||
|
|
ec5d1bd1da | ||
|
|
62a58bc1ec | ||
|
|
6e5ad99253 | ||
|
|
fecff7925c | ||
|
|
bb7240689b | ||
|
|
c924412e67 | ||
|
|
c0cb5568d7 | ||
|
|
9dbcff12b4 | ||
|
|
efc73a0119 | ||
|
|
a4dca2de21 | ||
|
|
51d3f32055 | ||
|
|
7949707a3c | ||
|
|
5e5f50bcc0 | ||
|
|
996d7a3ea3 | ||
|
|
7b3b953fea | ||
|
|
8c702a854d | ||
|
|
47ca65da91 | ||
|
|
249e5d94eb | ||
|
|
f992d85d26 | ||
|
|
469cd5a4b1 | ||
|
|
960fbfbcd2 | ||
|
|
fac236ed04 | ||
|
|
b42d0ef35a | ||
|
|
09f3aa538d | ||
|
|
d8e28af901 | ||
|
|
69a0475edd | ||
|
|
b6f3125d30 | ||
|
|
336c8a6906 | ||
|
|
5146c01ba9 | ||
|
|
5b6c94b16f | ||
|
|
fa1c789b40 | ||
|
|
1c04e9fe1a | ||
|
|
e9874bd060 | ||
|
|
05b4bd184f | ||
|
|
b4fd2e5d54 | ||
|
|
5df671a4b1 | ||
|
|
c53fd11789 | ||
|
|
9a82390682 | ||
|
|
3e1f2290cb | ||
|
|
d413f52a5f | ||
|
|
f4962cef77 | ||
|
|
48cdea96ee | ||
|
|
bd34de573c | ||
|
|
c7e0fe017c | ||
|
|
d55b889a3a | ||
|
|
c0834b3ab4 | ||
|
|
f7c4a9f04b | ||
|
|
09b87e8278 | ||
|
|
d37fb816bd | ||
|
|
5924e0f39d | ||
|
|
3da8b579a4 | ||
|
|
b73a2a5016 | ||
|
|
2d345e6891 | ||
|
|
5a2fb878f3 | ||
|
|
7b3a130c91 | ||
|
|
e435b0cbb9 | ||
|
|
dcc61f6546 | ||
|
|
5916f3470c | ||
|
|
ab760af838 | ||
|
|
3d7e32b2d1 | ||
|
|
7fa35bf478 | ||
|
|
c052248cfe | ||
|
|
081b62d267 | ||
|
|
bfe7f5835d | ||
|
|
e62e2c252f | ||
|
|
3dde1eabd4 | ||
|
|
450783b785 | ||
|
|
618c3acf84 | ||
|
|
baaa252c7e | ||
|
|
774f95a70e | ||
|
|
c4148f2cc0 | ||
|
|
d797203a7b | ||
|
|
c93043bf91 | ||
|
|
0c48f345b7 | ||
|
|
9bde33b3c3 | ||
|
|
3bff3e8276 | ||
|
|
d27d85df19 | ||
|
|
2ba7f09065 | ||
|
|
9f0997c492 | ||
|
|
f6864ddc0a | ||
|
|
9b9a4e8227 | ||
|
|
c4fee255dc | ||
|
|
a004c9c70c | ||
|
|
f939df6bc0 | ||
|
|
54eb8abfd6 | ||
|
|
5495aa213e | ||
|
|
dd5dab317d | ||
|
|
fc4529bcba | ||
|
|
9cc1004f38 | ||
|
|
11ac36d5fd | ||
|
|
13d4dc564c | ||
|
|
4958e6ea02 | ||
|
|
6244f8cb77 | ||
|
|
34ed2717d4 | ||
|
|
ab49f3a469 | ||
|
|
da615a54ea | ||
|
|
a38cdfb6e1 | ||
|
|
9f552d76eb | ||
|
|
9f849bdf29 | ||
|
|
005f4ca25d | ||
|
|
6d8f3531a7 | ||
|
|
9ef06824a7 | ||
|
|
0654bd51eb | ||
|
|
3a43e18c61 | ||
|
|
6d49bcea36 | ||
|
|
61f632a359 | ||
|
|
76574f94a7 |
Binary file not shown.
+90
-1
@@ -1,4 +1,93 @@
|
|||||||
bot_secrets.json
|
bot_secrets.json
|
||||||
google_client_secret.json
|
google_client_secret.json
|
||||||
__pycache__/
|
|
||||||
logs/*
|
logs/*
|
||||||
|
*.sh.swp
|
||||||
|
|
||||||
|
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-debug/
|
||||||
|
cmake-build-release/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
Generated
+1
-4
@@ -4,11 +4,8 @@
|
|||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$" />
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="R User Library" level="project" />
|
|
||||||
<orderEntry type="library" name="R Skeletons" level="application" />
|
|
||||||
</component>
|
</component>
|
||||||
<component name="TestRunnerService">
|
<component name="TestRunnerService">
|
||||||
<option name="projectConfiguration" value="py.test" />
|
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||||
<option name="PROJECT_TEST_RUNNER" value="py.test" />
|
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
Generated
+5
@@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
Generated
-7
@@ -1,7 +0,0 @@
|
|||||||
<component name="ProjectDictionaryState">
|
|
||||||
<dictionary name="Dustin.Pianalto">
|
|
||||||
<words>
|
|
||||||
<w>rcon</w>
|
|
||||||
</words>
|
|
||||||
</dictionary>
|
|
||||||
</component>
|
|
||||||
Generated
+1
-1
@@ -3,5 +3,5 @@
|
|||||||
<component name="JavaScriptSettings">
|
<component name="JavaScriptSettings">
|
||||||
<option name="languageLevel" value="ES6" />
|
<option name="languageLevel" value="ES6" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6" project-jdk-type="Python SDK" />
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (Geeksbot)" project-jdk-type="Python SDK" />
|
||||||
</project>
|
</project>
|
||||||
Generated
-6
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
-54
@@ -1,54 +0,0 @@
|
|||||||
import discord
|
|
||||||
from discord.ext import commands
|
|
||||||
import logging
|
|
||||||
from .imports.utils import paginate, run_command
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
owner_id = 351794468870946827
|
|
||||||
embed_color = discord.Colour.from_rgb(49, 107, 111)
|
|
||||||
|
|
||||||
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()
|
|
||||||
@commands.is_owner()
|
|
||||||
async def pull(self, ctx):
|
|
||||||
em = discord.Embed(style='rich',
|
|
||||||
title=f'Git Pull',
|
|
||||||
color=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/master')), 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='', value=f'{page}')
|
|
||||||
await ctx.send(embed=em)
|
|
||||||
|
|
||||||
@git.command()
|
|
||||||
@commands.is_owner()
|
|
||||||
async def status(self, ctx):
|
|
||||||
em = discord.Embed(style='rich',
|
|
||||||
title=f'Git Pull',
|
|
||||||
color=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='', value=f'{page}')
|
|
||||||
await ctx.send(embed=em)
|
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
|
||||||
bot.add_cog(Git(bot))
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
from io import StringIO
|
|
||||||
import sys
|
|
||||||
import asyncio
|
|
||||||
import discord
|
|
||||||
from discord.ext.commands.formatter import Paginator
|
|
||||||
from . import checks
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
async def mute(bot, ctx, admin=0, member_id=None):
|
|
||||||
mute_role = bot.con.one(f'select muted_role from guild_config where guild_id = {ctx.guild.id}')
|
|
||||||
if mute_role:
|
|
||||||
if admin or checks.is_admin(bot, ctx):
|
|
||||||
if ctx.guild.me.guild_permissions.manage_roles:
|
|
||||||
if member_id:
|
|
||||||
ctx.guild.get_member(member_id).edit(roles=[discord.utils.get(ctx.guild.roles, id=mute_role)])
|
|
||||||
|
|
||||||
|
|
||||||
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()
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
until python /home/dusty/bin/geeksbot/geeksbot.py; do
|
until python -m src; do
|
||||||
echo "Geeksbot shutdown with error: $?. Restarting..." >&2
|
echo "Geeksbot shutdown with error: $?. Restarting..." >&2
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
@checks.no_bots()
|
|
||||||
@commands.cooldown(1,5,commands.BucketType.user)
|
|
||||||
@commands.command()
|
|
||||||
async def captcha(self, ctx, type, *, text):
|
|
||||||
type = type.lower()
|
|
||||||
if type not in "checked unchecked loading".split():
|
|
||||||
raise commands.BadArgument(f"Invalid type {type!r}. Available "
|
|
||||||
"types: `unchecked`, `loading`, `checked`")
|
|
||||||
font = ImageFont.truetype("Roboto-Regular.ttf", 14)
|
|
||||||
async with ctx.typing():
|
|
||||||
img = Image.open(f"blank-captcha-{type}.png")
|
|
||||||
img.load()
|
|
||||||
d = ImageDraw.Draw(img)
|
|
||||||
fnc = functools.partial(d.text, (53,30), text, fill=(0,0,0,255),
|
|
||||||
font=font)
|
|
||||||
await self.bot.loop.run_in_executor(None, fnc)
|
|
||||||
img.save("captcha.png")
|
|
||||||
await ctx.send(file=discord.File("captcha.png"))
|
|
||||||
os.system("rm captcha.png")
|
|
||||||
img.close()
|
|
||||||
|
|
||||||
|
|
||||||
import functools, youtube_dl
|
|
||||||
#bot.voice_chan = await ctx.author.voice.channel.connect()
|
|
||||||
bot.voice_chan.stop()
|
|
||||||
opts = {"format": 'webm[abr>0]/bestaudio/best',"ignoreerrors": True,"default_search": "auto","source_address": "0.0.0.0",'quiet': True}
|
|
||||||
ydl = youtube_dl.YoutubeDL(opts)
|
|
||||||
url = 'https://www.youtube.com/watch?v=hjbPszSt5Pc'
|
|
||||||
func = functools.partial(ydl.extract_info, url, download=False)
|
|
||||||
info = func()
|
|
||||||
#bot.voice_chan.play(discord.FFmpegPCMAudio('dead_puppies.mp3'))
|
|
||||||
bot.voice_chan.play(discord.FFmpegPCMAudio(info['url']))
|
|
||||||
#async while bot.voice_chan.is_playing():
|
|
||||||
# pass
|
|
||||||
#await bot.voice_chan.disconnect()
|
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import json
|
import json
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from postgres import Postgres
|
|
||||||
from collections import deque
|
|
||||||
from googleapiclient.discovery import build
|
from googleapiclient.discovery import build
|
||||||
|
from concurrent import futures
|
||||||
|
from src.shared_libs import database
|
||||||
|
|
||||||
|
|
||||||
log_format = '{asctime}.{msecs:03.0f}|{levelname:<8}|{name}::{message}'
|
log_format = '{asctime}.{msecs:03.0f}|{levelname:<8}|{name}::{message}'
|
||||||
date_format = '%Y.%m.%d %H.%M.%S'
|
date_format = '%Y.%m.%d %H.%M.%S'
|
||||||
@@ -23,7 +25,7 @@ formatter = logging.Formatter(log_format, style='{', datefmt=date_format)
|
|||||||
console_handler.setFormatter(formatter)
|
console_handler.setFormatter(formatter)
|
||||||
logging.getLogger('').addHandler(console_handler)
|
logging.getLogger('').addHandler(console_handler)
|
||||||
|
|
||||||
config_dir = 'config/'
|
config_dir = 'src/config/'
|
||||||
admin_id_file = 'admin_ids'
|
admin_id_file = 'admin_ids'
|
||||||
extension_dir = 'exts'
|
extension_dir = 'exts'
|
||||||
owner_id = 351794468870946827
|
owner_id = 351794468870946827
|
||||||
@@ -35,48 +37,70 @@ emojis: Dict[str, str] = {
|
|||||||
'x': '❌',
|
'x': '❌',
|
||||||
'y': '✅',
|
'y': '✅',
|
||||||
'poop': '💩',
|
'poop': '💩',
|
||||||
|
'boom': '💥',
|
||||||
}
|
}
|
||||||
|
|
||||||
description = 'I am Geeksbot v0.1! Fear me!'
|
|
||||||
|
|
||||||
|
|
||||||
class Geeksbot(commands.Bot):
|
class Geeksbot(commands.Bot):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
kwargs["command_prefix"] = self.get_custom_prefix
|
kwargs["command_prefix"] = self.get_custom_prefix
|
||||||
|
self.description = 'I am Geeksbot! Fear me!'
|
||||||
|
kwargs['description'] = self.description
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.aio_session = aiohttp.ClientSession(loop=self.loop)
|
self.aio_session = aiohttp.ClientSession(loop=self.loop)
|
||||||
with open(f'{config_dir}{bot_config_file}') as file:
|
with open(f'{config_dir}{bot_config_file}') as file:
|
||||||
self.bot_config = json.load(file)
|
self.bot_config = json.load(file)
|
||||||
with open(f'{config_dir}{secrets_file}') as file:
|
with open(f'{config_dir}{secrets_file}') as file:
|
||||||
self.bot_secrets = json.load(file)
|
self.bot_secrets = json.load(file)
|
||||||
# with open(f'{config_dir}{profane_words_file}') as file:
|
|
||||||
# self.profane_words = file.readlines()
|
|
||||||
self.guild_config = {}
|
self.guild_config = {}
|
||||||
self.infected = {}
|
self.infected = {}
|
||||||
self.TOKEN = self.bot_secrets['token']
|
self.TOKEN = self.bot_secrets['token']
|
||||||
|
self.embed_color = discord.Colour.from_rgb(49, 107, 111)
|
||||||
|
self.error_color = discord.Colour.from_rgb(142, 29, 31)
|
||||||
del self.bot_secrets['token']
|
del self.bot_secrets['token']
|
||||||
self.con = Postgres(f" host={self.bot_secrets['db_con']['host']}\
|
self.db_con = database.DatabaseConnection(**self.bot_secrets['db_con'])
|
||||||
port={self.bot_secrets['db_con']['port']}\
|
|
||||||
dbname={self.bot_secrets['db_con']['db_name']}\
|
|
||||||
connect_timeout=10 user={self.bot_secrets['db_con']['user']}\
|
|
||||||
password={self.bot_secrets['db_con']['password']}")
|
|
||||||
del self.bot_secrets['db_con']
|
|
||||||
self.default_prefix = 'g$'
|
self.default_prefix = 'g$'
|
||||||
self.voice_chans = {}
|
self.voice_chans = {}
|
||||||
self.spam_list = {}
|
self.spam_list = {}
|
||||||
|
self.owner_id = 351794468870946827
|
||||||
|
self.__version__ = 'v1.0.0'
|
||||||
self.gcs_service = build('customsearch', 'v1', developerKey=self.bot_secrets['google_search_key'])
|
self.gcs_service = build('customsearch', 'v1', developerKey=self.bot_secrets['google_search_key'])
|
||||||
|
self.tpe = futures.ThreadPoolExecutor()
|
||||||
|
self.geo_api = '2d4e419c2be04c8abe91cb5dd1548c72'
|
||||||
|
self.unicode_emojis: Dict[str, str] = {
|
||||||
|
'x': '❌',
|
||||||
|
'y': '✅',
|
||||||
|
'poop': '💩',
|
||||||
|
'boom': '💥',
|
||||||
|
'left_fist': '🤛',
|
||||||
|
'lock': '🔒',
|
||||||
|
}
|
||||||
|
self.book_emojis: Dict[str, str] = {
|
||||||
|
'unlock': '🔓',
|
||||||
|
'start': '⏮',
|
||||||
|
'back': '◀',
|
||||||
|
'hash': '#\N{COMBINING ENCLOSING KEYCAP}',
|
||||||
|
'forward': '▶',
|
||||||
|
'end': '⏭',
|
||||||
|
'close': '🇽',
|
||||||
|
}
|
||||||
|
|
||||||
async def get_custom_prefix(self, bot_inst, message):
|
async def logout(self):
|
||||||
return self.con.one('select prefix from guild_config where guild_id = %(id)s', {'id': message.guild.id})\
|
await self.db_con.close()
|
||||||
or self.default_prefix
|
super().logout()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def get_custom_prefix(bot_inst, message):
|
||||||
|
return await bot_inst.db_con.fetchval('select prefix from guild_config where guild_id = $1',
|
||||||
|
message.guild.id) or bot_inst.default_prefix
|
||||||
|
|
||||||
async def load_ext(self, ctx, mod=None):
|
async def load_ext(self, ctx, mod=None):
|
||||||
self.load_extension('{0}.{1}'.format(extension_dir, mod))
|
self.load_extension('src.{0}.{1}'.format(extension_dir, mod))
|
||||||
if ctx is not None:
|
if ctx is not None:
|
||||||
await ctx.send('{0} loaded.'.format(mod))
|
await ctx.send('{0} loaded.'.format(mod))
|
||||||
|
|
||||||
async def unload_ext(self, ctx, mod=None):
|
async def unload_ext(self, ctx, mod=None):
|
||||||
self.unload_extension('{0}.{1}'.format(extension_dir, mod))
|
self.unload_extension('src.{0}.{1}'.format(extension_dir, mod))
|
||||||
if ctx is not None:
|
if ctx is not None:
|
||||||
await ctx.send('{0} unloaded.'.format(mod))
|
await ctx.send('{0} unloaded.'.format(mod))
|
||||||
|
|
||||||
@@ -85,7 +109,7 @@ class Geeksbot(commands.Bot):
|
|||||||
self.aio_session.close() # aiohttp is drunk and can't decide if it's a coro or not
|
self.aio_session.close() # aiohttp is drunk and can't decide if it's a coro or not
|
||||||
|
|
||||||
|
|
||||||
bot = Geeksbot(description=description, case_insensitive=True)
|
bot = Geeksbot(case_insensitive=True)
|
||||||
|
|
||||||
|
|
||||||
@bot.command(hidden=True)
|
@bot.command(hidden=True)
|
||||||
@@ -120,14 +144,14 @@ async def unload(ctx, mod):
|
|||||||
async def on_message(ctx):
|
async def on_message(ctx):
|
||||||
if not ctx.author.bot:
|
if not ctx.author.bot:
|
||||||
if ctx.guild:
|
if ctx.guild:
|
||||||
if int(bot.con.one(f"select channel_lockdown from guild_config where guild_id = %(id)s",
|
if int(await bot.db_con.fetchval("select channel_lockdown from guild_config where guild_id = $1",
|
||||||
{'id': ctx.guild.id})):
|
ctx.guild.id)):
|
||||||
if ctx.channel.id in json.loads(bot.con.one(f"select allowed_channels from guild_config "
|
if ctx.channel.id in json.loads(await bot.db_con.fetchval("select allowed_channels from guild_config "
|
||||||
f"where guild_id = %(id)s",
|
"where guild_id = $1",
|
||||||
{'id': ctx.guild.id})):
|
ctx.guild.id)):
|
||||||
await bot.process_commands(ctx)
|
await bot.process_commands(ctx)
|
||||||
elif ctx.channel.id == 418452585683484680:
|
elif ctx.channel.id == 418452585683484680:
|
||||||
prefix = bot.con.one('select prefix from guild_config where guild_id = %(id)s', {'id': ctx.guild.id})
|
prefix = await bot.db_con.fetchval('select prefix from guild_config where guild_id = $1', ctx.guild.id)
|
||||||
prefix = prefix[0] if prefix else bot.default_prefix
|
prefix = prefix[0] if prefix else bot.default_prefix
|
||||||
ctx.content = f'{prefix}{ctx.content}'
|
ctx.content = f'{prefix}{ctx.content}'
|
||||||
await bot.process_commands(ctx)
|
await bot.process_commands(ctx)
|
||||||
@@ -139,20 +163,19 @@ async def on_message(ctx):
|
|||||||
|
|
||||||
@bot.event
|
@bot.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
|
bot.remove_command('help')
|
||||||
bot.recent_msgs = {}
|
bot.recent_msgs = {}
|
||||||
for guild in bot.guilds:
|
|
||||||
bot.recent_msgs[guild.id] = deque(maxlen=50)
|
|
||||||
logging.info('Logged in as {0.name}|{0.id}'.format(bot.user))
|
logging.info('Logged in as {0.name}|{0.id}'.format(bot.user))
|
||||||
load_list = bot.bot_config['load_list']
|
load_list = bot.bot_config['load_list']
|
||||||
for load_item in load_list:
|
for load_item in load_list:
|
||||||
await bot.load_ext(None, f'{load_item}')
|
await bot.load_ext(None, f'{load_item}')
|
||||||
logging.info('Extension Loaded: {0}'.format(load_item))
|
logging.info('Extension Loaded: {0}'.format(load_item))
|
||||||
logging.info('Done loading, Geeksbot is active.')
|
|
||||||
with open(f'{config_dir}reboot', 'r') as f:
|
with open(f'{config_dir}reboot', 'r') as f:
|
||||||
reboot = f.readlines()
|
reboot = f.readlines()
|
||||||
if int(reboot[0]) == 1:
|
if int(reboot[0]) == 1:
|
||||||
await bot.get_channel(int(reboot[1])).send('Restart Finished.')
|
await bot.get_channel(int(reboot[1])).send('Restart Finished.')
|
||||||
with open(f'{config_dir}reboot', 'w') as f:
|
with open(f'{config_dir}reboot', 'w') as f:
|
||||||
f.write(f'0')
|
f.write(f'0')
|
||||||
|
logging.info('Done loading, Geeksbot is active.')
|
||||||
|
|
||||||
bot.run(bot.TOKEN)
|
bot.run(bot.TOKEN)
|
||||||
@@ -4,11 +4,10 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
from .imports import checks
|
from src.imports import checks, utils
|
||||||
|
|
||||||
config_dir = 'config/'
|
config_dir = 'src/config/'
|
||||||
admin_id_file = 'admin_ids'
|
admin_id_file = 'admin_ids'
|
||||||
extension_dir = 'extensions'
|
|
||||||
owner_id = 351794468870946827
|
owner_id = 351794468870946827
|
||||||
embed_color = discord.Colour.from_rgb(49, 107, 111)
|
embed_color = discord.Colour.from_rgb(49, 107, 111)
|
||||||
bot_config_file = 'bot_config.json'
|
bot_config_file = 'bot_config.json'
|
||||||
@@ -52,6 +51,7 @@ class Admin:
|
|||||||
await ctx.send('Geeksbot is restarting.')
|
await ctx.send('Geeksbot is restarting.')
|
||||||
with open(f'{config_dir}reboot', 'w') as f:
|
with open(f'{config_dir}reboot', 'w') as f:
|
||||||
f.write(f'1\n{ctx.channel.id}')
|
f.write(f'1\n{ctx.channel.id}')
|
||||||
|
# noinspection PyProtectedMember
|
||||||
os._exit(1)
|
os._exit(1)
|
||||||
|
|
||||||
@commands.command(hidden=True)
|
@commands.command(hidden=True)
|
||||||
@@ -72,20 +72,19 @@ class Admin:
|
|||||||
emoji_code = f'<a:{emoji.name}:{emoji.id}>'
|
emoji_code = f'<a:{emoji.name}:{emoji.id}>'
|
||||||
else:
|
else:
|
||||||
emoji_code = f'<:{emoji.name}:{emoji.id}>'
|
emoji_code = f'<:{emoji.name}:{emoji.id}>'
|
||||||
if self.bot.con.all('select id from geeksbot_emojis where id = %(id)s', {'id': emoji.id}):
|
if await self.bot.db_con.fetch('select id from geeksbot_emojis where id = $1', emoji.id):
|
||||||
self.bot.con.run("update geeksbot_emojis set id = %(id)s, name = %(name)s, code = %(emoji_code)s "
|
await self.bot.db_con.execute("update geeksbot_emojis set id = $2, name = $1, code = $3 "
|
||||||
"where name = %(name)s",
|
"where name = $1", emoji.name, emoji.id, emoji_code)
|
||||||
{'name': emoji.name, 'id': emoji.id, 'emoji_code': emoji_code})
|
|
||||||
else:
|
else:
|
||||||
self.bot.con.run("insert into geeksbot_emojis(id,name,code) values (%(id)s,%(name)s,%(emoji_code)s)",
|
await self.bot.db_con.execute("insert into geeksbot_emojis(id,name,code) values ($2,$1,$3)",
|
||||||
{'name': emoji.name, 'id': emoji.id, 'emoji_code': emoji_code})
|
emoji.name, emoji.id, emoji_code)
|
||||||
await ctx.message.add_reaction('✅')
|
await ctx.message.add_reaction('✅')
|
||||||
await ctx.send(f'Emojis have been updated in the database.')
|
await ctx.send(f'Emojis have been updated in the database.')
|
||||||
|
|
||||||
@commands.command(hidden=True)
|
@commands.command(hidden=True)
|
||||||
@commands.check(checks.is_guild_owner)
|
@commands.check(checks.is_guild_owner)
|
||||||
async def get_guild_config(self, ctx):
|
async def get_guild_config(self, ctx):
|
||||||
config = self.bot.con.one('select * from guild_config where guild_id = %(id)s', {'id': ctx.guild.id})
|
config = await self.bot.db_con.fetchrow('select * from guild_config where guild_id = $1', ctx.guild.id)
|
||||||
configs = [str(config)[i:i+1990] for i in range(0, len(config), 1990)]
|
configs = [str(config)[i:i+1990] for i in range(0, len(config), 1990)]
|
||||||
await ctx.message.author.send(f'The current config for the {ctx.guild.name} guild is:\n')
|
await ctx.message.author.send(f'The current config for the {ctx.guild.name} guild is:\n')
|
||||||
admin_log.info(configs)
|
admin_log.info(configs)
|
||||||
@@ -95,45 +94,49 @@ class Admin:
|
|||||||
|
|
||||||
@commands.group(case_insensitive=True)
|
@commands.group(case_insensitive=True)
|
||||||
async def set(self, ctx):
|
async def set(self, ctx):
|
||||||
"""Run help set for more info"""
|
"""Group for setting configuration options"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@commands.group(case_insensitive=True)
|
@commands.group(case_insensitive=True)
|
||||||
async def add(self, ctx):
|
async def add(self, ctx):
|
||||||
"""Run help set for more info"""
|
"""Group for adding items to guild config"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@commands.group(case_insensitive=True)
|
@commands.group(case_insensitive=True)
|
||||||
async def remove(self, ctx):
|
async def remove(self, ctx):
|
||||||
"""Run help set for more info"""
|
"""Group for removing items from guild config"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@set.command(name='admin_chan', aliases=['ac', 'admin_chat', 'admin chat'])
|
@set.command(name='admin_chan', aliases=['ac', 'admin_chat', 'admin chat'])
|
||||||
async def _admin_channel(self, ctx, channel: discord.TextChannel=None):
|
async def _admin_channel(self, ctx, channel: discord.TextChannel=None):
|
||||||
|
"""Sets the admin notification channel"""
|
||||||
if ctx.guild:
|
if ctx.guild:
|
||||||
if checks.is_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx):
|
||||||
if channel is not None:
|
if channel is not None:
|
||||||
self.bot.con.run('update guild_config set admin_chat = %(chan)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set admin_chat = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'chan': channel.id})
|
ctx.guild.id, channel.id)
|
||||||
await ctx.send(f'{channel.name} is now set as the Admin Chat channel for this guild.')
|
await ctx.send(f'{channel.name} is now set as the Admin Chat channel for this guild.')
|
||||||
|
|
||||||
@set.command(name='channel_lockdown', aliases=['lockdown', 'restrict_access', 'cl'])
|
@set.command(name='channel_lockdown', aliases=['lockdown', 'restrict_access', 'cl'])
|
||||||
async def _channel_lockdown(self, ctx, config='true'):
|
async def _channel_lockdown(self, ctx, config='true'):
|
||||||
|
"""Toggles the channel lockdown restriction
|
||||||
|
When this is active Geeksbot can only respond in channels defined in allowed_channels
|
||||||
|
If you run this before configuring allowed_channels it will tell you to run that command first."""
|
||||||
if ctx.guild:
|
if ctx.guild:
|
||||||
if checks.is_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx):
|
||||||
if str(config).lower() == 'true':
|
if str(config).lower() == 'true':
|
||||||
if self.bot.con.one('select allowed_channels from guild_config where guild_id = %(id)s',
|
if await self.bot.db_con.fetchval('select allowed_channels from guild_config '
|
||||||
{'id': ctx.guild.id}) is []:
|
'where guild_id = $1', ctx.guild.id) is []:
|
||||||
await ctx.send('Please set at least one allowed channel before running this command.')
|
await ctx.send('Please set at least one allowed channel before running this command.')
|
||||||
else:
|
else:
|
||||||
self.bot.con.run('update guild_config set channel_lockdown = True where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set channel_lockdown = True '
|
||||||
{'id': ctx.guild.id})
|
'where guild_id = $1', ctx.guild.id)
|
||||||
await ctx.send('Channel Lockdown is now active.')
|
await ctx.send('Channel Lockdown is now active.')
|
||||||
elif str(config).lower() == 'false':
|
elif str(config).lower() == 'false':
|
||||||
if self.bot.con.one('select channel_lockdown from guild_config where guild_id = %(id)s',
|
if await self.bot.db_con.fetchval('select channel_lockdown from guild_config where guild_id = $1',
|
||||||
{'id': ctx.guild.id}):
|
ctx.guild.id):
|
||||||
self.bot.con.run('update guild_config set channel_lockdown = False where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set channel_lockdown = False '
|
||||||
{'id': ctx.guild.id})
|
'where guild_id = $1', ctx.guild.id)
|
||||||
await ctx.send('Channel Lockdown has been deactivated.')
|
await ctx.send('Channel Lockdown has been deactivated.')
|
||||||
else:
|
else:
|
||||||
await ctx.send('Channel Lockdown is already deactivated.')
|
await ctx.send('Channel Lockdown is already deactivated.')
|
||||||
@@ -144,59 +147,74 @@ class Admin:
|
|||||||
|
|
||||||
@add.command(name='allowed_channels', aliases=['channel', 'ac'])
|
@add.command(name='allowed_channels', aliases=['channel', 'ac'])
|
||||||
async def _allowed_channels(self, ctx, *, channels):
|
async def _allowed_channels(self, ctx, *, channels):
|
||||||
|
"""Defines channels Geeksbot can respond in
|
||||||
|
This only takes effect if channel_lockdown is enabled.
|
||||||
|
If one of the channels passed is not found then it is ignored."""
|
||||||
if ctx.guild:
|
if ctx.guild:
|
||||||
if checks.is_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx):
|
||||||
channels = channels.lower().replace(' ', '').split(',')
|
channels = channels.lower().replace(' ', '').split(',')
|
||||||
added = ''
|
existing_channels = list()
|
||||||
for channel in channels:
|
channels_add = list()
|
||||||
chnl = discord.utils.get(ctx.guild.channels, name=channel)
|
admin_log.info(channels)
|
||||||
if chnl is None:
|
allowed_channels = await self.bot.db_con.fetchval('select allowed_channels from guild_config '
|
||||||
await ctx.send(f'{channel} is not a valid text channel in this guild.')
|
'where guild_id = $1', ctx.guild.id)
|
||||||
else:
|
if allowed_channels == 'null':
|
||||||
admin_log.info('Chan found')
|
allowed_channels = None
|
||||||
if self.bot.con.one('select allowed_channels from guild_config where guild_id = %(id)s',
|
|
||||||
{'id': ctx.guild.id}):
|
channels = [discord.utils.get(ctx.guild.channels, name=channel)
|
||||||
if chnl.id in json.loads(self.bot.con.one('select allowed_channels from guild_config '
|
for channel in channels if channel is not None]
|
||||||
'where guild_id = %(id)s',
|
|
||||||
{'id': ctx.guild.id})):
|
if allowed_channels and channels:
|
||||||
admin_log.info('Chan found in config')
|
allowed_channels = [int(channel) for channel in json.loads(allowed_channels)]
|
||||||
await ctx.send(f'{channel} is already in the list of allowed channels. Skipping...')
|
existing_channels = [channel for channel in channels if channel.id in allowed_channels]
|
||||||
else:
|
channels_add = [channel for channel in channels if channel.id not in allowed_channels]
|
||||||
admin_log.info('Chan not found in config')
|
allowed_channels += [channel.id for channel in channels if channel.id not in allowed_channels]
|
||||||
allowed_channels = json.loads(self.bot.con.one('select allowed_channels from '
|
await self.bot.db_con.execute('update guild_config set allowed_channels = $2 where guild_id = $1',
|
||||||
'guild_config where guild_id = %(id)s',
|
ctx.guild.id, json.dumps(allowed_channels))
|
||||||
{'id': ctx.guild.id})).append(chnl.id)
|
elif channels:
|
||||||
self.bot.con.run('update guild_config set allowed_channels = %(channels)s '
|
admin_log.info('Config is empty')
|
||||||
'where guild_id = %(id)s',
|
allowed_channels = [channel.id for channel in channels]
|
||||||
{'id': ctx.guild.id, 'channels': allowed_channels})
|
await self.bot.db_con.execute('update guild_config set allowed_channels = $2 '
|
||||||
added = f'{added}\n{channel}'
|
'where guild_id = $1', ctx.guild.id,
|
||||||
else:
|
json.dumps(allowed_channels))
|
||||||
admin_log.info('Chan not found in config')
|
else:
|
||||||
allowed_channels = [chnl.id]
|
await ctx.send('None of those are valid text channels for this guild.')
|
||||||
self.bot.con.run('update guild_config set allowed_channels = %(channels)s '
|
return
|
||||||
'where guild_id = %(id)s',
|
|
||||||
{'id': ctx.guild.id, 'channels': allowed_channels})
|
if existing_channels:
|
||||||
added = f'{added}\n{channel}'
|
channel_str = '\n'.join([str(channel.name) for channel in existing_channels])
|
||||||
if added != '':
|
await ctx.send(f'The following channels were skipped because they are already in the config:\n'
|
||||||
await ctx.send(f'The following channels have been added to the allowed channel list: {added}')
|
f'{channel_str}\n')
|
||||||
|
if channels_add:
|
||||||
|
channel_str = '\n'.join([str(channel.name) for channel in channels_add])
|
||||||
|
await ctx.send('The following channels have been added to the allowed channel list:\n'
|
||||||
|
f'{channel_str}\n')
|
||||||
await ctx.message.add_reaction('✅')
|
await ctx.message.add_reaction('✅')
|
||||||
else:
|
else:
|
||||||
await ctx.send(f'You are not authorized to run this command.')
|
await ctx.send(f'You are not authorized to run this command.')
|
||||||
else:
|
else:
|
||||||
await ctx.send('This command must be run from inside a guild.')
|
await ctx.send('This command must be run from inside a guild.')
|
||||||
|
|
||||||
@commands.command()
|
# TODO Fix view_code
|
||||||
|
@commands.command(hidden=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def view_code(self, ctx, code_name):
|
async def view_code(self, ctx, code_name):
|
||||||
await ctx.send(f"```py\n{inspect.getsource(self.bot.get_command(code_name).callback)}\n```")
|
pag = utils.Paginator(self.bot, prefix='```py', suffix='```')
|
||||||
|
pag.add(inspect.getsource(self.bot.all_commands[code_name].callback))
|
||||||
|
for page in pag.pages():
|
||||||
|
await ctx.send(page)
|
||||||
|
|
||||||
@add.command(aliases=['prefix', 'p'])
|
@add.command(aliases=['prefix', 'p'])
|
||||||
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
||||||
async def add_prefix(self, ctx, *, prefix=None):
|
async def add_prefix(self, ctx, *, prefix=None):
|
||||||
|
"""Adds a custom prefix for the current guild
|
||||||
|
Note: This overwrites the default of g$. If you would
|
||||||
|
like to keep using g$ you will need to add it to the
|
||||||
|
Guild config as well."""
|
||||||
if ctx.guild:
|
if ctx.guild:
|
||||||
if checks.is_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx):
|
||||||
prefixes = self.bot.con.one('select prefix from guild_config where guild_id = %(id)s',
|
prefixes = await self.bot.db_con.fetchval('select prefix from guild_config where guild_id = $1',
|
||||||
{'id': ctx.guild.id})
|
ctx.guild.id)
|
||||||
if prefix is None:
|
if prefix is None:
|
||||||
await ctx.send(prefixes)
|
await ctx.send(prefixes)
|
||||||
return
|
return
|
||||||
@@ -208,8 +226,8 @@ class Admin:
|
|||||||
if len(prefixes) > 10:
|
if len(prefixes) > 10:
|
||||||
await ctx.send(f'Only 10 prefixes are allowed per guild.\nPlease remove some before adding more.')
|
await ctx.send(f'Only 10 prefixes are allowed per guild.\nPlease remove some before adding more.')
|
||||||
prefixes = prefixes[:10]
|
prefixes = prefixes[:10]
|
||||||
self.bot.con.run('update guild_config set prefix = %(prefixes)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set prefix = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'prefixes': prefixes})
|
ctx.guild.id, prefixes)
|
||||||
await ctx.guild.me.edit(nick=f'[{prefixes[0]}] Geeksbot')
|
await ctx.guild.me.edit(nick=f'[{prefixes[0]}] Geeksbot')
|
||||||
await ctx.send(f"Updated. You currently have {len(prefixes)} "
|
await ctx.send(f"Updated. You currently have {len(prefixes)} "
|
||||||
f"{'prefix' if len(prefixes) == 1 else 'prefixes'} "
|
f"{'prefix' if len(prefixes) == 1 else 'prefixes'} "
|
||||||
@@ -222,10 +240,13 @@ class Admin:
|
|||||||
@remove.command(aliases=['prefix', 'p'])
|
@remove.command(aliases=['prefix', 'p'])
|
||||||
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
||||||
async def remove_prefix(self, ctx, *, prefix=None):
|
async def remove_prefix(self, ctx, *, prefix=None):
|
||||||
|
"""Removes custom prefix from the current guild
|
||||||
|
If the last prefix is removed then Geeksbot will default
|
||||||
|
Back to g$"""
|
||||||
if ctx.guild:
|
if ctx.guild:
|
||||||
if checks.is_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx):
|
||||||
prefixes = self.bot.con.one('select prefix from guild_config where guild_id = %(id)s',
|
prefixes = await self.bot.db_con.fetchval('select prefix from guild_config where guild_id = $1',
|
||||||
{'id': ctx.guild.id})
|
ctx.guild.id)
|
||||||
found = 0
|
found = 0
|
||||||
if prefix is None:
|
if prefix is None:
|
||||||
await ctx.send(prefixes)
|
await ctx.send(prefixes)
|
||||||
@@ -242,8 +263,8 @@ class Admin:
|
|||||||
else:
|
else:
|
||||||
await ctx.send(f'The prefix {p} is not in the config for this guild.')
|
await ctx.send(f'The prefix {p} is not in the config for this guild.')
|
||||||
if found:
|
if found:
|
||||||
self.bot.con.run('update guild_config set prefix = %(prefixes)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set prefix = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'prefixes': prefixes})
|
ctx.guild.id, prefixes)
|
||||||
await ctx.guild.me.edit(nick=f'[{prefixes[0] if len(prefixes) != 0 else self.bot.default_prefix}] '
|
await ctx.guild.me.edit(nick=f'[{prefixes[0] if len(prefixes) != 0 else self.bot.default_prefix}] '
|
||||||
f'Geeksbot')
|
f'Geeksbot')
|
||||||
await ctx.send(f"Updated. You currently have {len(prefixes)} "
|
await ctx.send(f"Updated. You currently have {len(prefixes)} "
|
||||||
@@ -258,16 +279,19 @@ class Admin:
|
|||||||
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
||||||
@commands.check(checks.is_guild_owner)
|
@commands.check(checks.is_guild_owner)
|
||||||
async def _add_admin_role(self, ctx, role=None):
|
async def _add_admin_role(self, ctx, role=None):
|
||||||
|
"""Adds role to the admin list for current guild
|
||||||
|
Allowing members of that role to run admin commands
|
||||||
|
on the current guild."""
|
||||||
role = discord.utils.get(ctx.guild.roles, name=role)
|
role = discord.utils.get(ctx.guild.roles, name=role)
|
||||||
if role is not None:
|
if role is not None:
|
||||||
roles = json.loads(self.bot.con.one('select admin_roles from guild_config where guild_id = %(id)s',
|
roles = json.loads(await self.bot.db_con.fetchval('select admin_roles from guild_config '
|
||||||
{'id': ctx.guild.id}))
|
'where guild_id = $1', ctx.guild.id))
|
||||||
if role.name in roles:
|
if role.name in roles:
|
||||||
await ctx.send(f'{role.name} is already registered as an admin role in this guild.')
|
await ctx.send(f'{role.name} is already registered as an admin role in this guild.')
|
||||||
else:
|
else:
|
||||||
roles[role.name] = role.id
|
roles[role.name] = role.id
|
||||||
self.bot.con.run('update guild_config set admin_roles = %(roles)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set admin_roles = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'roles': json.dumps(roles)})
|
ctx.guild.id, json.dumps(roles))
|
||||||
await ctx.send(f'{role.name} has been added to the list of admin roles for this guild.')
|
await ctx.send(f'{role.name} has been added to the list of admin roles for this guild.')
|
||||||
else:
|
else:
|
||||||
await ctx.send('You must include a role with this command.')
|
await ctx.send('You must include a role with this command.')
|
||||||
@@ -276,14 +300,15 @@ class Admin:
|
|||||||
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
@commands.cooldown(1, 5, type=commands.BucketType.guild)
|
||||||
@commands.check(checks.is_guild_owner)
|
@commands.check(checks.is_guild_owner)
|
||||||
async def _remove_admin_role(self, ctx, role=None):
|
async def _remove_admin_role(self, ctx, role=None):
|
||||||
|
"""Removes role from admin list in current guild"""
|
||||||
role = discord.utils.get(ctx.guild.roles, name=role)
|
role = discord.utils.get(ctx.guild.roles, name=role)
|
||||||
if role is not None:
|
if role is not None:
|
||||||
roles = json.loads(self.bot.con.one('select admin_roles from guild_config where guild_id = %(id)s',
|
roles = json.loads(await self.bot.db_con.fetchval('select admin_roles from guild_config '
|
||||||
{'id': ctx.guild.id}))
|
'where guild_id = $1', ctx.guild.id))
|
||||||
if role.name in roles:
|
if role.name in roles:
|
||||||
del roles[role.name]
|
del roles[role.name]
|
||||||
self.bot.con.run('update guild_config set admin_roles = %(roles)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set admin_roles = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'roles': roles})
|
ctx.guild.id, json.dumps(roles))
|
||||||
await ctx.send(f'{role.name} has been removed from the list of admin roles for this guild.')
|
await ctx.send(f'{role.name} has been removed from the list of admin roles for this guild.')
|
||||||
else:
|
else:
|
||||||
await ctx.send(f'{role.name} is not registered as an admin role in this guild.')
|
await ctx.send(f'{role.name} is not registered as an admin role in this guild.')
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import discord
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from .imports import utils
|
from src.imports import utils
|
||||||
|
|
||||||
config_dir = 'config/'
|
config_dir = 'config/'
|
||||||
admin_id_file = 'admin_ids'
|
admin_id_file = 'admin_ids'
|
||||||
@@ -50,17 +51,20 @@ class BotEvents:
|
|||||||
config_str = f'{config_str}\n{" "*4}{config}: {guild_config[config]}'
|
config_str = f'{config_str}\n{" "*4}{config}: {guild_config[config]}'
|
||||||
return config_str
|
return config_str
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
async def on_raw_message_delete(self, msg_id, chan_id):
|
async def on_raw_message_delete(self, msg_id, chan_id):
|
||||||
self.bot.con.run('update messages set deleted_at = %(time)s where id = %(id)s',
|
await self.bot.db_con.execute('update messages set deleted_at = $1 where id = $2',
|
||||||
{'time': datetime.utcnow(), 'id': msg_id})
|
datetime.utcnow(), msg_id)
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
async def on_raw_bulk_message_delete(self, msg_ids, chan_id):
|
async def on_raw_bulk_message_delete(self, msg_ids, chan_id):
|
||||||
sql = ''
|
del_time = datetime.utcnow()
|
||||||
for msg_id in msg_ids:
|
for msg_id in msg_ids:
|
||||||
sql += f';update messages set deleted_at = %(time)s where id = {msg_id}'
|
await self.bot.db_con.execute('update messages set deleted_at = $1 where id = $2',
|
||||||
self.bot.con.run(sql, {'time': datetime.utcnow()})
|
del_time, msg_id)
|
||||||
|
|
||||||
async def on_message(self, ctx):
|
async def on_message(self, ctx):
|
||||||
|
# noinspection PyBroadException
|
||||||
try:
|
try:
|
||||||
if ctx.author in self.bot.infected:
|
if ctx.author in self.bot.infected:
|
||||||
if datetime.now().timestamp() > self.bot.infected[ctx.author][1] + 300:
|
if datetime.now().timestamp() > self.bot.infected[ctx.author][1] + 300:
|
||||||
@@ -73,36 +77,22 @@ class BotEvents:
|
|||||||
sql = 'insert into messages (id, tts, type, content, embeds, channel, mention_everyone, mentions,\
|
sql = 'insert into messages (id, tts, type, content, embeds, channel, mention_everyone, mentions,\
|
||||||
channel_mentions, role_mentions, webhook, attachments, pinned, reactions, guild, created_at,\
|
channel_mentions, role_mentions, webhook, attachments, pinned, reactions, guild, created_at,\
|
||||||
system_content, author) \
|
system_content, author) \
|
||||||
values (%(id)s, %(tts)s, %(type)s, %(content)s, %(embeds)s, %(channel)s, %(mention_everyone)s, %(mentions)s,\
|
values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)'
|
||||||
%(channel_mentions)s, %(role_mentions)s, %(webhook)s, %(attachments)s, %(pinned)s, %(reactions)s, %(guild)s,\
|
msg_data = [ctx.id, ctx.tts, str(ctx.type), ctx.content, [json.dumps(e.to_dict()) for e in ctx.embeds],
|
||||||
%(created_at)s, %(system_content)s, %(author)s)'
|
ctx.channel.id, ctx.mention_everyone, [user.id for user in ctx.mentions],
|
||||||
msg_data = dict()
|
[channel.id for channel in ctx.channel_mentions], [role.id for role in ctx.role_mentions],
|
||||||
msg_data['id'] = ctx.id
|
ctx.webhook_id, [json.dumps({'id': a.id, 'size': a.size, 'height': a.height, 'width': a.width,
|
||||||
msg_data['tts'] = ctx.tts
|
'filename': a.filename, 'url': a.url}) for a in ctx.attachments],
|
||||||
msg_data['type'] = str(ctx.type)
|
ctx.pinned, [json.dumps({'emoji': r.emoji, 'count': r.count}) for r in ctx.reactions],
|
||||||
msg_data['content'] = ctx.content
|
ctx.guild.id if ctx.guild else ctx.author.id, ctx.created_at, ctx.system_content, ctx.author.id]
|
||||||
msg_data['embeds'] = [json.dumps(e.to_dict()) for e in ctx.embeds]
|
await self.bot.db_con.execute(sql, *msg_data)
|
||||||
msg_data['channel'] = ctx.channel.id
|
|
||||||
msg_data['mention_everyone'] = ctx.mention_everyone
|
|
||||||
msg_data['mentions'] = [user.id for user in ctx.mentions]
|
|
||||||
msg_data['channel_mentions'] = [channel.id for channel in ctx.channel_mentions]
|
|
||||||
msg_data['role_mentions'] = [role.id for role in ctx.role_mentions]
|
|
||||||
msg_data['webhook'] = ctx.webhook_id
|
|
||||||
msg_data['attachments'] = [json.dumps({'id': a.id, 'size': a.size, 'height': a.height, 'width': a.width,
|
|
||||||
'filename': a.filename, 'url': a.url}) for a in ctx.attachments]
|
|
||||||
msg_data['pinned'] = ctx.pinned
|
|
||||||
msg_data['guild'] = ctx.guild.id
|
|
||||||
msg_data['created_at'] = ctx.created_at
|
|
||||||
msg_data['system_content'] = ctx.system_content
|
|
||||||
msg_data['author'] = ctx.author.id
|
|
||||||
msg_data['reactions'] = [json.dumps({'emoji': r.emoji, 'count': r.count}) for r in ctx.reactions]
|
|
||||||
self.bot.con.run(sql, msg_data)
|
|
||||||
if ctx.guild:
|
if ctx.guild:
|
||||||
if ctx.author != ctx.guild.me:
|
if ctx.author != ctx.guild.me:
|
||||||
if self.bot.con.one(f"select pg_filter from guild_config where guild_id = {ctx.guild.id}"):
|
if await self.bot.db_con.fetchval("select pg_filter from guild_config where guild_id = $1",
|
||||||
|
ctx.guild.id):
|
||||||
profane = 0
|
profane = 0
|
||||||
for word in self.bot.con.one('select profane_words from guild_config where guild_id = %(id)s',
|
for word in await self.bot.db_con.fetchval('select profane_words from guild_config '
|
||||||
{'id': ctx.guild.id}):
|
'where guild_id = $1', ctx.guild.id):
|
||||||
word = word.strip()
|
word = word.strip()
|
||||||
if word in ctx.content.lower():
|
if word in ctx.content.lower():
|
||||||
events_log.info(f'Found non PG word {word}')
|
events_log.info(f'Found non PG word {word}')
|
||||||
@@ -129,57 +119,44 @@ class BotEvents:
|
|||||||
await react.message.channel.send(f"You can't Poop on me {user.mention} :P")
|
await react.message.channel.send(f"You can't Poop on me {user.mention} :P")
|
||||||
reactions = react.message.reactions
|
reactions = react.message.reactions
|
||||||
reacts = [json.dumps({'emoji': r.emoji, 'count': r.count}) for r in reactions]
|
reacts = [json.dumps({'emoji': r.emoji, 'count': r.count}) for r in reactions]
|
||||||
self.bot.con.run('update messages set reactions = %(reacts)s where id = %(id)s',
|
await self.bot.db_con.execute('update messages set reactions = $2 where id = $1',
|
||||||
{'id': react.message.id, 'reacts': reacts})
|
react.message.id, reacts)
|
||||||
|
|
||||||
async def on_message_edit(self, before, ctx):
|
async def on_message_edit(self, before, ctx):
|
||||||
previous_content = self.bot.con.one('select previous_content from messages where id = %(id)s', {'id': ctx.id})
|
previous_content = await self.bot.db_con.fetchval('select previous_content from messages where id = $1', ctx.id)
|
||||||
if previous_content:
|
if previous_content:
|
||||||
previous_content.append(before.content)
|
previous_content.append(before.content)
|
||||||
else:
|
else:
|
||||||
previous_content = [before.content]
|
previous_content = [before.content]
|
||||||
previous_embeds = self.bot.con.one('select previous_embeds from messages where id = %(id)s', {'id': ctx.id})
|
previous_embeds = await self.bot.db_con.fetchval('select previous_embeds from messages where id = $1', ctx.id)
|
||||||
if previous_embeds:
|
if previous_embeds:
|
||||||
previous_embeds.append([json.dumps(e.to_dict()) for e in before.embeds])
|
previous_embeds.append([json.dumps(e.to_dict()) for e in before.embeds])
|
||||||
else:
|
else:
|
||||||
previous_embeds = [[json.dumps(e.to_dict()) for e in before.embeds]]
|
previous_embeds = [[json.dumps(e.to_dict()) for e in before.embeds]]
|
||||||
sql = 'update messages set (edited_at, previous_content, previous_embeds, tts, type, content,\
|
sql = 'update messages set (edited_at, previous_content, previous_embeds, tts, type, content, embeds, ' \
|
||||||
embeds, channel, mention_everyone, mentions, channel_mentions, role_mentions, webhook,\
|
'channel, mention_everyone, mentions, channel_mentions, role_mentions, webhook, attachments, pinned, ' \
|
||||||
attachments, pinned, reactions, guild, created_at, system_content, author) \
|
'reactions, guild, created_at, system_content, author) = ' \
|
||||||
= (%(edited_at)s, %(previous_content)s, %(previous_embeds)s, %(tts)s, %(type)s, %(content)s,\
|
'($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20)' \
|
||||||
%(embeds)s, %(channel)s, %(mention_everyone)s, %(mentions)s, %(channel_mentions)s, %(role_mentions)s,\
|
'where id = $21'
|
||||||
%(webhook)s, %(attachments)s, %(pinned)s, %(reactions)s, %(guild)s, %(created_at)s, %(system_content)s,\
|
msg_data = [datetime.utcnow(), previous_content, previous_embeds, ctx.tts, str(ctx.type), ctx.content,
|
||||||
%(author)s) where id = %(id)s'
|
[json.dumps(e.to_dict()) for e in ctx.embeds], ctx.channel.id, ctx.mention_everyone,
|
||||||
msg_data = dict()
|
[user.id for user in ctx.mentions], [channel.id for channel in ctx.channel_mentions],
|
||||||
msg_data['id'] = ctx.id
|
[role.id for role in ctx.role_mentions], ctx.webhook_id,
|
||||||
msg_data['tts'] = ctx.tts
|
[json.dumps({'id': a.id, 'size': a.size, 'height': a.height, 'width': a.width,
|
||||||
msg_data['type'] = str(ctx.type)
|
'filename': a.filename, 'url': a.url}) for a in ctx.attachments], ctx.pinned,
|
||||||
msg_data['content'] = ctx.content
|
[json.dumps({'emoji': r.emoji, 'count': r.count}) for r in ctx.reactions], ctx.guild.id,
|
||||||
msg_data['embeds'] = [json.dumps(e.to_dict()) for e in ctx.embeds]
|
ctx.created_at, ctx.system_content, ctx.author.id, ctx.id]
|
||||||
msg_data['channel'] = ctx.channel.id
|
await self.bot.db_con.execute(sql, *msg_data)
|
||||||
msg_data['mention_everyone'] = ctx.mention_everyone
|
|
||||||
msg_data['mentions'] = [user.id for user in ctx.mentions]
|
|
||||||
msg_data['channel_mentions'] = [channel.id for channel in ctx.channel_mentions]
|
|
||||||
msg_data['role_mentions'] = [role.id for role in ctx.role_mentions]
|
|
||||||
msg_data['webhook'] = ctx.webhook_id
|
|
||||||
msg_data['attachments'] = ctx.attachments
|
|
||||||
msg_data['pinned'] = ctx.pinned
|
|
||||||
msg_data['guild'] = ctx.guild.id
|
|
||||||
msg_data['created_at'] = ctx.created_at
|
|
||||||
msg_data['system_content'] = ctx.system_content
|
|
||||||
msg_data['author'] = ctx.author.id
|
|
||||||
msg_data['reactions'] = [json.dumps({'emoji': r.emoji, 'count': r.count}) for r in ctx.reactions]
|
|
||||||
msg_data['previous_content'] = previous_content
|
|
||||||
msg_data['previous_embeds'] = previous_embeds
|
|
||||||
msg_data['edited_at'] = datetime.utcnow()
|
|
||||||
self.bot.con.run(sql, msg_data)
|
|
||||||
|
|
||||||
@staticmethod
|
# noinspection PyMethodMayBeStatic
|
||||||
async def on_command_error(ctx, error):
|
async def on_command_error(self, ctx, error):
|
||||||
if ctx.channel.id == 418452585683484680 and type(error) == discord.ext.commands.errors.CommandNotFound:
|
pag = utils.Paginator(ctx.bot, embed=True, max_line_length=48)
|
||||||
return
|
pag.set_embed_meta(title=f'Command Error',
|
||||||
for page in utils.paginate(error):
|
color=self.bot.error_color,
|
||||||
await ctx.send(page)
|
thumbnail=f'{ctx.guild.me.avatar_url}')
|
||||||
|
pag.add(error)
|
||||||
|
book = utils.Book(pag, (None, ctx.channel, self.bot, ctx.message))
|
||||||
|
await book.create_book()
|
||||||
|
|
||||||
async def on_guild_join(self, guild):
|
async def on_guild_join(self, guild):
|
||||||
with open(f"{config_dir}{default_guild_config_file}", 'r') as file:
|
with open(f"{config_dir}{default_guild_config_file}", 'r') as file:
|
||||||
@@ -189,31 +166,25 @@ class BotEvents:
|
|||||||
default_config['name'] = guild.name.replace("'", "\\'")
|
default_config['name'] = guild.name.replace("'", "\\'")
|
||||||
default_config['guild_id'] = guild.id
|
default_config['guild_id'] = guild.id
|
||||||
events_log.info(default_config)
|
events_log.info(default_config)
|
||||||
self.bot.con.run("insert into guild_config(guild_id, guild_name, admin_roles, rcon_enabled, channel_lockdown,\
|
await self.bot.db_con.execute("insert into guild_config(guild_id, guild_name, admin_roles, rcon_enabled, "
|
||||||
raid_status, pg_filter, patreon_enabled, referral_enabled)\
|
"channel_lockdown, raid_status, pg_filter, patreon_enabled, referral_enabled) "
|
||||||
values (%(guild_id)s, %(name)s, %(admin_roles)s, %(rcon_enabled)s, %(channel_lockdown)s,\
|
"values ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
||||||
%(raid_status)s, %(pg_filter)s, %(patreon_enabled)s, %(referral_enabled)s)",
|
default_config['guild_id'], default_config['name'],
|
||||||
{'guild_id': default_config['guild_id'],
|
json.dumps(default_config['admin_roles']), default_config['rcon_enabled'],
|
||||||
'name': default_config['name'],
|
default_config['channel_lockdown'], default_config['raid_status'],
|
||||||
'admin_roles': json.dumps(default_config['admin_roles']),
|
default_config['pg_filter'], default_config['patreon_enabled'],
|
||||||
'rcon_enabled': default_config['rcon_enabled'],
|
default_config['referral_enabled'])
|
||||||
'channel_lockdown': default_config['channel_lockdown'],
|
|
||||||
'raid_status': default_config['raid_status'],
|
|
||||||
'pg_filter': default_config['pg_filter'],
|
|
||||||
'patreon_enabled': default_config['patreon_enabled'],
|
|
||||||
'referral_enabled': default_config['referral_enabled']
|
|
||||||
})
|
|
||||||
events_log.info(f'Entry Created for {guild.name}')
|
events_log.info(f'Entry Created for {guild.name}')
|
||||||
await guild.me.edit(nick='[g$] Geeksbot')
|
await guild.me.edit(nick='[g$] Geeksbot')
|
||||||
|
|
||||||
async def on_guild_remove(self, guild):
|
async def on_guild_remove(self, guild):
|
||||||
self.bot.con.run(f'delete from guild_config where guild_id = %(id)s', {'id': guild.id})
|
await self.bot.db_con.execute(f'delete from guild_config where guild_id = $1', guild.id)
|
||||||
events_log.info(f'Left the {guild.name} guild.')
|
events_log.info(f'Left the {guild.name} guild.')
|
||||||
|
|
||||||
async def on_member_join(self, member):
|
async def on_member_join(self, member):
|
||||||
events_log.info(f'Member joined: {member.name} {member.id} Guild: {member.guild.name} {member.guild.id}')
|
events_log.info(f'Member joined: {member.name} {member.id} Guild: {member.guild.name} {member.guild.id}')
|
||||||
join_chan = self.bot.con.one('select join_leave_chat from guild_config where guild_id = %(id)s',
|
join_chan = await self.bot.db_con.fetchval('select join_leave_chat from guild_config where guild_id = $1',
|
||||||
{'id': member.guild.id})
|
member.guild.id)
|
||||||
if join_chan:
|
if join_chan:
|
||||||
em = discord.Embed(style='rich',
|
em = discord.Embed(style='rich',
|
||||||
color=embed_color
|
color=embed_color
|
||||||
@@ -226,31 +197,30 @@ class BotEvents:
|
|||||||
em.set_footer(text=f"{member.guild.name} | {member.joined_at.strftime('%Y-%m-%d at %H:%M:%S GMT')}",
|
em.set_footer(text=f"{member.guild.name} | {member.joined_at.strftime('%Y-%m-%d at %H:%M:%S GMT')}",
|
||||||
icon_url=member.guild.icon_url)
|
icon_url=member.guild.icon_url)
|
||||||
await discord.utils.get(member.guild.channels, id=join_chan).send(embed=em)
|
await discord.utils.get(member.guild.channels, id=join_chan).send(embed=em)
|
||||||
mem_data = {'id': member.id,
|
mem_data = [member.id,
|
||||||
'name': member.name,
|
member.name,
|
||||||
'discriminator': member.discriminator,
|
member.discriminator,
|
||||||
'bot': member.bot
|
member.bot
|
||||||
}
|
]
|
||||||
mem = self.bot.con.one('select guilds,nicks from user_data where id = %(id)s', {'id': member.id})
|
mem = await self.bot.db_con.fetchval('select guilds,nicks from user_data where id = $1', member.id)
|
||||||
if mem:
|
if mem:
|
||||||
mem[1].append(json.dumps({member.guild.id: member.display_name}))
|
mem[1].append(json.dumps({member.guild.id: member.display_name}))
|
||||||
mem[0].append(member.guild.id)
|
mem[0].append(member.guild.id)
|
||||||
mem_data['nicks'] = mem[1]
|
mem_data.append(mem[1])
|
||||||
mem_data['guilds'] = mem[0]
|
mem_data.append(mem[0])
|
||||||
self.bot.con.run('update user_data set (name, discriminator, bot, nicks, guilds) =\
|
self.bot.con.run('update user_data set (name, discriminator, bot, nicks, guilds) = '
|
||||||
(%(name)s, %(discriminator)s, %(bot)s, %(nicks)s, %(guilds)s) where\
|
'($2, $3, $4, $5, $6) where id = $1', *mem_data)
|
||||||
id = %(id)s', mem_data)
|
|
||||||
else:
|
else:
|
||||||
mem_data['nicks'] = [json.dumps({member.guild.id: member.display_name})]
|
mem_data.append([json.dumps({member.guild.id: member.display_name})])
|
||||||
mem_data['guilds'] = [member.guild.id]
|
mem_data.append([member.guild.id])
|
||||||
self.bot.con.run('insert into user_data (id, name, discriminator, bot, nicks, guilds) values\
|
self.bot.con.run('insert into user_data (id, name, discriminator, bot, nicks, guilds) '
|
||||||
(%(id)s, %(name)s, %(discriminator)s, %(bot)s, %(nicks)s, %(guilds)s)', mem_data)
|
'values ($1, $2, $3, $4, $5, $6)', *mem_data)
|
||||||
|
|
||||||
async def on_member_remove(self, member):
|
async def on_member_remove(self, member):
|
||||||
leave_time = datetime.utcnow()
|
leave_time = datetime.utcnow()
|
||||||
events_log.info(f'Member left: {member.name} {member.id} Guild: {member.guild.name} {member.guild.id}')
|
events_log.info(f'Member left: {member.name} {member.id} Guild: {member.guild.name} {member.guild.id}')
|
||||||
join_chan = self.bot.con.one('select join_leave_chat from guild_config where guild_id = %(id)s',
|
join_chan = await self.bot.db_con.fetchval('select join_leave_chat from guild_config where guild_id = $1',
|
||||||
{'id': member.guild.id})
|
member.guild.id)
|
||||||
if join_chan:
|
if join_chan:
|
||||||
em = discord.Embed(style='rich',
|
em = discord.Embed(style='rich',
|
||||||
color=red_color
|
color=red_color
|
||||||
@@ -273,6 +243,19 @@ class BotEvents:
|
|||||||
em.set_footer(text=f"{member.guild.name} | {datetime.utcnow().strftime('%Y-%m-%d at %H:%M:%S GMT')}",
|
em.set_footer(text=f"{member.guild.name} | {datetime.utcnow().strftime('%Y-%m-%d at %H:%M:%S GMT')}",
|
||||||
icon_url=member.guild.icon_url)
|
icon_url=member.guild.icon_url)
|
||||||
await discord.utils.get(member.guild.channels, id=join_chan).send(embed=em)
|
await discord.utils.get(member.guild.channels, id=join_chan).send(embed=em)
|
||||||
|
mem_data = [member.id,
|
||||||
|
member.name,
|
||||||
|
member.discriminator,
|
||||||
|
member.bot
|
||||||
|
]
|
||||||
|
mem = await self.bot.db_con.fetchrow('select guilds,nicks from user_data where id = $1', member.id)
|
||||||
|
if mem:
|
||||||
|
mem[0].remove(member.guild.id)
|
||||||
|
mem[1].remove(json.dumps({member.guild.id: member.display_name}))
|
||||||
|
mem_data.append(mem[1])
|
||||||
|
mem_data.append(mem[0])
|
||||||
|
self.bot.con.run('update user_data set (name, discriminator, bot, nicks, guilds) = '
|
||||||
|
'($2, $3, $4, $5, $6) where id = $1', *mem_data)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot):
|
||||||
@@ -33,6 +33,9 @@ class Fun:
|
|||||||
@commands.command()
|
@commands.command()
|
||||||
@commands.cooldown(1, 30, type=commands.BucketType.user)
|
@commands.cooldown(1, 30, type=commands.BucketType.user)
|
||||||
async def infect(self, ctx, member: discord.Member, emoji):
|
async def infect(self, ctx, member: discord.Member, emoji):
|
||||||
|
"""Infects a user with the given emoji
|
||||||
|
|
||||||
|
Every time the user sends a message that I am also in I will react to that message with said emoji."""
|
||||||
if member.id == self.bot.user.id and ctx.author.id != owner_id:
|
if member.id == self.bot.user.id and ctx.author.id != owner_id:
|
||||||
await ctx.send(f'You rolled a Critical Fail...\nInfection bounces off and rebounds on the attacker.')
|
await ctx.send(f'You rolled a Critical Fail...\nInfection bounces off and rebounds on the attacker.')
|
||||||
member = ctx.author
|
member = ctx.author
|
||||||
@@ -48,6 +51,7 @@ class Fun:
|
|||||||
@commands.command()
|
@commands.command()
|
||||||
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
async def heal(self, ctx, member: discord.Member):
|
async def heal(self, ctx, member: discord.Member):
|
||||||
|
"""Removes infection from user."""
|
||||||
if ctx.author == member and ctx.author.id != owner_id:
|
if ctx.author == member and ctx.author.id != owner_id:
|
||||||
await ctx.send('You can\'t heal yourself silly...')
|
await ctx.send('You can\'t heal yourself silly...')
|
||||||
else:
|
else:
|
||||||
@@ -57,7 +61,7 @@ class Fun:
|
|||||||
else:
|
else:
|
||||||
await ctx.send(f'{member.display_name} is not infected...')
|
await ctx.send(f'{member.display_name} is not infected...')
|
||||||
|
|
||||||
@commands.command()
|
@commands.command(hidden=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def print_infections(self, ctx):
|
async def print_infections(self, ctx):
|
||||||
await ctx.author.send(f'```{self.bot.infected}```')
|
await ctx.author.send(f'```{self.bot.infected}```')
|
||||||
@@ -65,13 +69,15 @@ class Fun:
|
|||||||
@commands.command()
|
@commands.command()
|
||||||
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
async def slap(self, ctx, member: discord.Member):
|
async def slap(self, ctx, member: discord.Member):
|
||||||
|
"""IRC Style Trout Slap"""
|
||||||
|
trout = await self.bot.db_con.fetchval("select code from geeksbot_emojis where id = 449083238766477312")
|
||||||
if member.id == self.bot.user.id and ctx.author.id != owner_id:
|
if member.id == self.bot.user.id and ctx.author.id != owner_id:
|
||||||
await ctx.send(f'You rolled a Critical Fail...\nThe trout bounces off and rebounds on the attacker.')
|
await ctx.send(f'You rolled a Critical Fail...\nThe trout bounces off and rebounds on the attacker.')
|
||||||
await ctx.send(f'{ctx.author.mention} '
|
await ctx.send(f'{ctx.author.mention} '
|
||||||
f'You slap yourself in the face with a large trout <:trout:408543365085397013>')
|
f'You slap yourself in the face with a large trout {trout}')
|
||||||
else:
|
else:
|
||||||
await ctx.send(f'{ctx.author.display_name} slaps '
|
await ctx.send(f'{ctx.author.display_name} slaps '
|
||||||
f'{member.mention} around a bit with a large trout <:trout:408543365085397013>')
|
f'{member.mention} around a bit with a large trout {trout}')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_factorial(number):
|
def get_factorial(number):
|
||||||
@@ -80,22 +86,23 @@ class Fun:
|
|||||||
a = a * (i + 1)
|
a = a * (i + 1)
|
||||||
return a
|
return a
|
||||||
|
|
||||||
# @commands.command()
|
@commands.command()
|
||||||
# @commands.cooldown(1, 5, type=commands.BucketType.user)
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
# async def fact(self, ctx, number:int):
|
async def fact(self, ctx, number: int):
|
||||||
# if number < 20001 and number > 0:
|
"""Returns the given factorial up to 20,000!"""
|
||||||
# n = 1990
|
if 0 < number < 20001:
|
||||||
# with ctx.channel.typing():
|
n = 1990
|
||||||
# a = await self.bot.loop.run_in_executor(None, self.get_factorial, number)
|
with ctx.channel.typing():
|
||||||
# if len(str(a)) > 6000:
|
a = await self.bot.loop.run_in_executor(None, self.get_factorial, number)
|
||||||
# for b in [str(a)[i:i+n] for i in range(0, len(str(a)), n)]:
|
if len(str(a)) > 6000:
|
||||||
# await ctx.author.send(f'```py\n{b}```')
|
for b in [str(a)[i:i+n] for i in range(0, len(str(a)), n)]:
|
||||||
# await ctx.send(f"{ctx.author.mention} Check your DMs.")
|
await ctx.author.send(f'```py\n{b}```')
|
||||||
# else:
|
await ctx.send(f"{ctx.author.mention} Check your DMs.")
|
||||||
# for b in [str(a)[i:i+n] for i in range(0, len(str(a)), n)]:
|
else:
|
||||||
# await ctx.send(f'```py\n{b}```')
|
for b in [str(a)[i:i+n] for i in range(0, len(str(a)), n)]:
|
||||||
# else:
|
await ctx.send(f'```py\n{b}```')
|
||||||
# await ctx.send("Invalid number. Please enter a number between 0 and 20,000")
|
else:
|
||||||
|
await ctx.send("Invalid number. Please enter a number between 0 and 20,000")
|
||||||
|
|
||||||
@commands.command(hidden=True)
|
@commands.command(hidden=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
@@ -141,11 +148,28 @@ class Fun:
|
|||||||
else:
|
else:
|
||||||
await ctx.send('Not connected to that voice channel.')
|
await ctx.send('Not connected to that voice channel.')
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
@commands.command(hidden=True)
|
@commands.command(hidden=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def volume(self, ctx, volume: float):
|
async def volume(self, ctx, volume: float):
|
||||||
self.bot.player.volume = volume
|
self.bot.player.volume = volume
|
||||||
|
|
||||||
|
@commands.command(name='explode', aliases=['splode'])
|
||||||
|
async def explode_user(self, ctx, member: discord.Member=None):
|
||||||
|
"""Trolls user by punching them to oblivion."""
|
||||||
|
if member is None or member.id == 396588996706304010:
|
||||||
|
member = ctx.author
|
||||||
|
|
||||||
|
trans = await self.bot.db_con.fetchval('select code from geeksbot_emojis where id = 405943174809255956')
|
||||||
|
msg = await ctx.send(f'{member.mention}{trans*20}{self.bot.unicode_emojis["left_fist"]}')
|
||||||
|
for i in range(4):
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
await msg.edit(content=f'{member.mention}{trans*(20-(i*5))}{self.bot.unicode_emojis["left_fist"]}')
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
await msg.edit(content=f'{self.bot.unicode_emojis["boom"]}')
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
await msg.edit(content=f'{self.bot.unicode_emojis["boom"]} <---- {member.mention} that was you...')
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot):
|
||||||
bot.add_cog(Fun(bot))
|
bot.add_cog(Fun(bot))
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
import logging
|
||||||
|
from src.imports.utils import Paginator, run_command, Book
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
owner_id = 351794468870946827
|
||||||
|
embed_color = discord.Colour.from_rgb(49, 107, 111)
|
||||||
|
|
||||||
|
git_log = logging.getLogger('git')
|
||||||
|
|
||||||
|
|
||||||
|
class Git:
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.group(case_insensitive=True, invoke_without_command=True)
|
||||||
|
async def git(self, ctx):
|
||||||
|
"""Shows my Git link"""
|
||||||
|
em = discord.Embed(style='rich',
|
||||||
|
title=f'Here is where you can find my code',
|
||||||
|
url='https://github.com/dustinpianalto/Geeksbot/tree/development',
|
||||||
|
description='I am the development branch of Geeksbot. You can find the master branch here:\n'
|
||||||
|
'https://github.com/dustinpianalto/Geeksbot/',
|
||||||
|
color=embed_color)
|
||||||
|
em.set_thumbnail(url=f'{ctx.guild.me.avatar_url}')
|
||||||
|
await ctx.send(embed=em)
|
||||||
|
|
||||||
|
@git.command()
|
||||||
|
@commands.is_owner()
|
||||||
|
async def pull(self, ctx):
|
||||||
|
"""Pulls updates from GitHub rebasing branch."""
|
||||||
|
pag = Paginator(self.bot, max_line_length=44, embed=True)
|
||||||
|
pag.set_embed_meta(title='Git Pull',
|
||||||
|
color=self.bot.embed_color,
|
||||||
|
thumbnail=f'{ctx.guild.me.avatar_url}')
|
||||||
|
pag.add('\uFFF6' + await asyncio.wait_for(self.bot.loop.create_task(run_command('git fetch --all')), 120))
|
||||||
|
pag.add(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))
|
||||||
|
pag.add('\uFFF7\n\uFFF8')
|
||||||
|
pag.add(await asyncio.wait_for(self.bot.loop.create_task(run_command('git show --stat | '
|
||||||
|
'sed "s/.*@.*[.].*/ /g"')), 10))
|
||||||
|
book = Book(pag, (None, ctx.channel, self.bot, ctx.message))
|
||||||
|
await book.create_book()
|
||||||
|
|
||||||
|
@git.command()
|
||||||
|
@commands.is_owner()
|
||||||
|
async def status(self, ctx):
|
||||||
|
"""Gets status of current branch."""
|
||||||
|
pag = Paginator(self.bot, max_line_length=44, max_lines=30, embed=True)
|
||||||
|
pag.set_embed_meta(title='Git Status',
|
||||||
|
color=self.bot.embed_color,
|
||||||
|
thumbnail=f'{ctx.guild.me.avatar_url}')
|
||||||
|
result = await asyncio.wait_for(self.bot.loop.create_task(run_command('git status')), 10)
|
||||||
|
pag.add(result)
|
||||||
|
book = Book(pag, (None, ctx.channel, self.bot, ctx.message))
|
||||||
|
await book.create_book()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
bot.add_cog(Git(bot))
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
import json
|
import json
|
||||||
from .imports import checks
|
from src.imports import checks
|
||||||
|
|
||||||
config_dir = 'config'
|
config_dir = 'config'
|
||||||
extension_dir = 'extensions'
|
extension_dir = 'extensions'
|
||||||
@@ -17,12 +17,11 @@ class Patreon:
|
|||||||
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
async def get_patreon_links(self, ctx, target: discord.Member=None):
|
async def get_patreon_links(self, ctx, target: discord.Member=None):
|
||||||
"""Prints Patreon information for creators on the server."""
|
"""Prints Patreon information for creators on the server."""
|
||||||
if self.bot.con.one('select patreon_enabled from guild_config where guild_id = %(id)s', {'id': ctx.guild.id}):
|
if await self.bot.db_con.fetchval('select patreon_enabled from guild_config where guild_id = $1', ctx.guild.id):
|
||||||
patreon_info = self.bot.con.one('select patreon_message,patreon_links\
|
patreon_info = await self.bot.db_con.fetchrow('select patreon_message,patreon_links from guild_config '
|
||||||
from guild_config where guild_id = %(id)s',
|
'where guild_id = $1', ctx.guild.id)
|
||||||
{'id': ctx.guild.id})
|
message = patreon_info['patreon_message'].replace('\\n', '\n')
|
||||||
message = patreon_info[0].replace('\\n', '\n')
|
patreon_links = json.loads(patreon_info['patreon_links'])
|
||||||
patreon_links = json.loads(patreon_info[1])
|
|
||||||
for key in patreon_links:
|
for key in patreon_links:
|
||||||
message = message + '\n{0}: {1}'.format(key, patreon_links[key])
|
message = message + '\n{0}: {1}'.format(key, patreon_links[key])
|
||||||
if target is None:
|
if target is None:
|
||||||
@@ -34,23 +33,23 @@ class Patreon:
|
|||||||
|
|
||||||
@commands.command(aliases=['patreon_message'])
|
@commands.command(aliases=['patreon_message'])
|
||||||
async def set_patreon_message(self, ctx, message):
|
async def set_patreon_message(self, ctx, message):
|
||||||
if checks.is_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx):
|
||||||
patreon_message = self.bot.con.one('select patreon_message from guild_config where guild_id = %(id)s',
|
patreon_message = await self.bot.db_con.fetchval('select patreon_message from guild_config '
|
||||||
{'id': ctx.guild.id})
|
'where guild_id = $1', ctx.guild.id)
|
||||||
if message == patreon_message:
|
if message == patreon_message:
|
||||||
await ctx.send('That is already the current message for this guild.')
|
await ctx.send('That is already the current message for this guild.')
|
||||||
else:
|
else:
|
||||||
self.bot.con.run('update guild_config set patreon_message = %(message)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set patreon_message = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'message': message})
|
ctx.guild.id, message)
|
||||||
await ctx.send(f'The patreon message for this guild has been set to:\n{message}')
|
await ctx.send(f'The patreon message for this guild has been set to:\n{message}')
|
||||||
else:
|
else:
|
||||||
await ctx.send(f'You are not authorized to run this command.')
|
await ctx.send(f'You are not authorized to run this command.')
|
||||||
|
|
||||||
@commands.command(aliases=['add_patreon', 'set_patreon'])
|
@commands.command(aliases=['add_patreon', 'set_patreon'])
|
||||||
async def add_patreon_info(self, ctx, name, url):
|
async def add_patreon_info(self, ctx, name, url):
|
||||||
if checks.is_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx):
|
||||||
patreon_info = self.bot.con.one('select patreon_links from guild_config where guild_id = %(id)s',
|
patreon_info = await self.bot.db_con.fetchval('select patreon_links from guild_config where guild_id = $1',
|
||||||
{'id': ctx.guild.id})
|
ctx.guild.id)
|
||||||
patreon_links = {}
|
patreon_links = {}
|
||||||
update = 0
|
update = 0
|
||||||
if patreon_info:
|
if patreon_info:
|
||||||
@@ -58,8 +57,8 @@ class Patreon:
|
|||||||
if name in patreon_links:
|
if name in patreon_links:
|
||||||
update = 1
|
update = 1
|
||||||
patreon_links[name] = url
|
patreon_links[name] = url
|
||||||
self.bot.con.run('update guild_config set patreon_links = %(links)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set patreon_links = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'links': json.dumps(patreon_links)})
|
ctx.guild.id, json.dumps(patreon_links))
|
||||||
await ctx.send(f"The Patreon link for {name} has been "
|
await ctx.send(f"The Patreon link for {name} has been "
|
||||||
f"{'updated to the new url.' if update else'added to the config for this guild.'}")
|
f"{'updated to the new url.' if update else'added to the config for this guild.'}")
|
||||||
else:
|
else:
|
||||||
@@ -67,15 +66,15 @@ class Patreon:
|
|||||||
|
|
||||||
@commands.command(aliases=['remove_patreon'])
|
@commands.command(aliases=['remove_patreon'])
|
||||||
async def remove_patreon_info(self, ctx, name):
|
async def remove_patreon_info(self, ctx, name):
|
||||||
if checks.is_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx):
|
||||||
patreon_info = self.bot.con.one('select patreon_links from guild_config where guild_id = %(id)s',
|
patreon_info = await self.bot.db_con.fetchval('select patreon_links from guild_config where guild_id = $1',
|
||||||
{'id': ctx.guild.id})
|
ctx.guild.id)
|
||||||
if patreon_info:
|
if patreon_info:
|
||||||
patreon_links = json.loads(patreon_info)
|
patreon_links = json.loads(patreon_info)
|
||||||
if name in patreon_links:
|
if name in patreon_links:
|
||||||
del patreon_links[name]
|
del patreon_links[name]
|
||||||
self.bot.con.run('update guild_config set patreon_links = %(links)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set patreon_links = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'links': json.dumps(patreon_links)})
|
ctx.guild.id, json.dumps(patreon_links))
|
||||||
await ctx.send(f'The Patreon link for {name} has been removed from the config for this guild.')
|
await ctx.send(f'The Patreon link for {name} has been removed from the config for this guild.')
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
@@ -87,18 +86,18 @@ class Patreon:
|
|||||||
|
|
||||||
@commands.command()
|
@commands.command()
|
||||||
async def enable_patreon(self, ctx, state: bool=True):
|
async def enable_patreon(self, ctx, state: bool=True):
|
||||||
if checks.is_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx):
|
||||||
patreon_status = self.bot.con.one('select patreon_enabled from guild_config where guild_id = %(id)s',
|
patreon_status = await self.bot.db_con.fetchval('select patreon_enabled from guild_config '
|
||||||
{'id': ctx.guild.id})
|
'where guild_id = $1', ctx.guild.id)
|
||||||
if patreon_status and state:
|
if patreon_status and state:
|
||||||
await ctx.send('Patreon is already enabled for this guild.')
|
await ctx.send('Patreon is already enabled for this guild.')
|
||||||
elif patreon_status and not state:
|
elif patreon_status and not state:
|
||||||
self.bot.con.run('update guild_config set patreon_enabled = %(state)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set patreon_enabled = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'state': state})
|
ctx.guild.id, state)
|
||||||
await ctx.send('Patreon has been disabled for this guild.')
|
await ctx.send('Patreon has been disabled for this guild.')
|
||||||
elif not patreon_status and state:
|
elif not patreon_status and state:
|
||||||
self.bot.con.run('update guild_config set patreon_enabled = %(state)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set patreon_enabled = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'state': state})
|
ctx.guild.id, state)
|
||||||
await ctx.send('Patreon has been enabled for this guild.')
|
await ctx.send('Patreon has been enabled for this guild.')
|
||||||
elif not patreon_status and not state:
|
elif not patreon_status and not state:
|
||||||
await ctx.send('Patreon is already disabled for this guild.')
|
await ctx.send('Patreon is already disabled for this guild.')
|
||||||
@@ -107,9 +106,10 @@ class Patreon:
|
|||||||
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
async def referral_links(self, ctx, target: discord.Member=None):
|
async def referral_links(self, ctx, target: discord.Member=None):
|
||||||
"""Prints G-Portal Referral Links."""
|
"""Prints G-Portal Referral Links."""
|
||||||
if self.bot.con.one('select referral_enabled from guild_config where guild_id = %(id)s', {'id': ctx.guild.id}):
|
if await self.bot.db_con.fetchval('select referral_enabled from guild_config where guild_id = $1',
|
||||||
referral_info = self.bot.con.one('select referral_message,referral_links from guild_config\
|
ctx.guild.id):
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id})
|
referral_info = await self.bot.db_con.fetchval('select referral_message,referral_links from guild_config '
|
||||||
|
'where guild_id = $1', ctx.guild.id)
|
||||||
message = referral_info[0]
|
message = referral_info[0]
|
||||||
referral_links = json.loads(referral_info[1])
|
referral_links = json.loads(referral_info[1])
|
||||||
for key in referral_links:
|
for key in referral_links:
|
||||||
@@ -7,7 +7,7 @@ import logging
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import asyncio
|
import asyncio
|
||||||
import traceback
|
import traceback
|
||||||
from .imports import checks
|
from src.imports import checks
|
||||||
|
|
||||||
config_dir = 'config'
|
config_dir = 'config'
|
||||||
admin_id_file = 'admin_ids'
|
admin_id_file = 'admin_ids'
|
||||||
@@ -120,6 +120,7 @@ class Rcon:
|
|||||||
True)
|
True)
|
||||||
con.exec_command('ServerChatToPlayer "{0}" GeeksBot: Admin Geeks have been notified you need assistance. '
|
con.exec_command('ServerChatToPlayer "{0}" GeeksBot: Admin Geeks have been notified you need assistance. '
|
||||||
'Please be patient.'.format(player))
|
'Please be patient.'.format(player))
|
||||||
|
# noinspection PyProtectedMember
|
||||||
con._sock.close()
|
con._sock.close()
|
||||||
for role in admin_roles:
|
for role in admin_roles:
|
||||||
msg = '{0} {1}'.format(msg, discord.utils.get(ctx.guild.roles, id=admin_roles[role]).mention)
|
msg = '{0} {1}'.format(msg, discord.utils.get(ctx.guild.roles, id=admin_roles[role]).mention)
|
||||||
@@ -137,15 +138,16 @@ class Rcon:
|
|||||||
first_last
|
first_last
|
||||||
"first last"
|
"first last"
|
||||||
To view all the valid ARK servers for this guild see list_ark_servers."""
|
To view all the valid ARK servers for this guild see list_ark_servers."""
|
||||||
if checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_rcon_admin(self.bot, ctx):
|
||||||
if server is not None:
|
if server is not None:
|
||||||
rcon_connections = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
rcon_connections = json.loads(await self.bot.db_con.fetchval('select rcon_connections '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'from guild_config where guild_id = $1',
|
||||||
|
ctx.guild.id))
|
||||||
server = server.replace('_', ' ').title()
|
server = server.replace('_', ' ').title()
|
||||||
if server in rcon_connections:
|
if server in rcon_connections:
|
||||||
rcon_connections[server]["monitoring_chat"] = 1
|
rcon_connections[server]["monitoring_chat"] = 1
|
||||||
self.bot.con.run('update guild_config set rcon_connections = %(json)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set rcon_connections = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'json': json.dumps(rcon_connections)})
|
ctx.guild.id, json.dumps(rcon_connections))
|
||||||
channel = self.bot.get_channel(rcon_connections[server]['game_chat_chan_id'])
|
channel = self.bot.get_channel(rcon_connections[server]['game_chat_chan_id'])
|
||||||
await channel.send('Started monitoring on the {0} server.'.format(server))
|
await channel.send('Started monitoring on the {0} server.'.format(server))
|
||||||
await ctx.message.add_reaction('✅')
|
await ctx.message.add_reaction('✅')
|
||||||
@@ -158,6 +160,7 @@ class Rcon:
|
|||||||
True)
|
True)
|
||||||
messages = await self.bot.loop.run_in_executor(None, self.server_chat_background_process,
|
messages = await self.bot.loop.run_in_executor(None, self.server_chat_background_process,
|
||||||
ctx.guild.id, con)
|
ctx.guild.id, con)
|
||||||
|
# noinspection PyProtectedMember
|
||||||
con._sock.close()
|
con._sock.close()
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
rcon_log.error(traceback.format_exc())
|
rcon_log.error(traceback.format_exc())
|
||||||
@@ -180,8 +183,10 @@ class Rcon:
|
|||||||
message = func(ctx, message, rcon_connections['server'])
|
message = func(ctx, message, rcon_connections['server'])
|
||||||
await channel.send('{0}'.format(message))
|
await channel.send('{0}'.format(message))
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
rcon_connections = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
rcon_connections = json.loads(await self.bot.db_con.fetchval('select rcon_connections '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'from guild_config '
|
||||||
|
'where guild_id = $1',
|
||||||
|
ctx.guild.id))
|
||||||
await channel.send('Monitoring Stopped')
|
await channel.send('Monitoring Stopped')
|
||||||
else:
|
else:
|
||||||
await ctx.send(f'Server not found: {server}')
|
await ctx.send(f'Server not found: {server}')
|
||||||
@@ -195,15 +200,16 @@ class Rcon:
|
|||||||
async def end_monitor_chat(self, ctx, *, server=None):
|
async def end_monitor_chat(self, ctx, *, server=None):
|
||||||
"""Ends chat monitoring on the specified server.
|
"""Ends chat monitoring on the specified server.
|
||||||
Context is the same as monitor_chat"""
|
Context is the same as monitor_chat"""
|
||||||
if checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_rcon_admin(self.bot, ctx):
|
||||||
if server is not None:
|
if server is not None:
|
||||||
rcon_connections = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
rcon_connections = json.loads(await self.bot.db_con.fetchval('select rcon_connections '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'from guild_config where guild_id = $1',
|
||||||
|
ctx.guild.id))
|
||||||
server = server.replace('_', ' ').title()
|
server = server.replace('_', ' ').title()
|
||||||
if server in rcon_connections:
|
if server in rcon_connections:
|
||||||
rcon_connections[server]["monitoring_chat"] = 0
|
rcon_connections[server]["monitoring_chat"] = 0
|
||||||
self.bot.con.run('update guild_config set rcon_connections = %(json)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set rcon_connections = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'json': json.dumps(rcon_connections)})
|
ctx.guild.id, json.dumps(rcon_connections))
|
||||||
else:
|
else:
|
||||||
await ctx.send(f'Server not found: {server}')
|
await ctx.send(f'Server not found: {server}')
|
||||||
else:
|
else:
|
||||||
@@ -223,9 +229,9 @@ class Rcon:
|
|||||||
first_last
|
first_last
|
||||||
"first last"
|
"first last"
|
||||||
To view all the valid ARK servers for this guild see list_ark_servers."""
|
To view all the valid ARK servers for this guild see list_ark_servers."""
|
||||||
if checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_rcon_admin(self.bot, ctx):
|
||||||
rcon_connections = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
rcon_connections = json.loads(await self.bot.db_con.fetchval('select rcon_connections from guild_config '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'where guild_id = $1', ctx.guild.id))
|
||||||
if server is not None:
|
if server is not None:
|
||||||
server = server.replace('_', ' ').title()
|
server = server.replace('_', ' ').title()
|
||||||
if server in rcon_connections:
|
if server in rcon_connections:
|
||||||
@@ -241,9 +247,10 @@ class Rcon:
|
|||||||
'"ip" port "password" if you would like to get info from it.'.format(server))
|
'"ip" port "password" if you would like to get info from it.'.format(server))
|
||||||
else:
|
else:
|
||||||
for server in rcon_connections:
|
for server in rcon_connections:
|
||||||
|
msg = await ctx.send('Getting Data for the {0} server'.format(server.title()))
|
||||||
|
# noinspection PyBroadException
|
||||||
try:
|
try:
|
||||||
connection_info = rcon_connections[server]
|
connection_info = rcon_connections[server]
|
||||||
msg = await ctx.send('Getting Data for the {0} server'.format(server.title()))
|
|
||||||
async with ctx.channel.typing():
|
async with ctx.channel.typing():
|
||||||
message = self._listplayers(connection_info)
|
message = self._listplayers(connection_info)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -260,10 +267,10 @@ class Rcon:
|
|||||||
async def add_rcon_server(self, ctx, server, ip, port, password):
|
async def add_rcon_server(self, ctx, server, ip, port, password):
|
||||||
"""Adds the specified server to the current guild\'s rcon config.
|
"""Adds the specified server to the current guild\'s rcon config.
|
||||||
All strings (<server>, <ip>, <password>) must be contained inside double quotes."""
|
All strings (<server>, <ip>, <password>) must be contained inside double quotes."""
|
||||||
if checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_rcon_admin(self.bot, ctx):
|
||||||
server = server.title()
|
server = server.title()
|
||||||
rcon_connections = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
rcon_connections = json.loads(await self.bot.db_con.fetchval('select rcon_connections from guild_config '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'where guild_id = $1', ctx.guild.id))
|
||||||
if server not in rcon_connections:
|
if server not in rcon_connections:
|
||||||
rcon_connections[server] = {
|
rcon_connections[server] = {
|
||||||
'ip': ip,
|
'ip': ip,
|
||||||
@@ -274,8 +281,8 @@ class Rcon:
|
|||||||
'msg_chan_id': 0,
|
'msg_chan_id': 0,
|
||||||
'monitoring_chat': 0
|
'monitoring_chat': 0
|
||||||
}
|
}
|
||||||
self.bot.con.run('update guild_config set rcon_connections = %(connections)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set rcon_connections = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'connections': json.dumps(rcon_connections)})
|
ctx.guild.id, json.dumps(rcon_connections))
|
||||||
await ctx.send('{0} server has been added to my configuration.'.format(server))
|
await ctx.send('{0} server has been added to my configuration.'.format(server))
|
||||||
else:
|
else:
|
||||||
await ctx.send('This server name is already in my configuration. Please choose another.')
|
await ctx.send('This server name is already in my configuration. Please choose another.')
|
||||||
@@ -289,14 +296,14 @@ class Rcon:
|
|||||||
async def remove_rcon_server(self, ctx, server):
|
async def remove_rcon_server(self, ctx, server):
|
||||||
"""removes the specified server from the current guild\'s rcon config.
|
"""removes the specified server from the current guild\'s rcon config.
|
||||||
All strings <server> must be contained inside double quotes."""
|
All strings <server> must be contained inside double quotes."""
|
||||||
if checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_rcon_admin(self.bot, ctx):
|
||||||
server = server.title()
|
server = server.title()
|
||||||
rcon_connections = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
rcon_connections = json.loads(await self.bot.db_con.fetchval('select rcon_connections from guild_config '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'where guild_id = $1', ctx.guild.id))
|
||||||
if server in rcon_connections:
|
if server in rcon_connections:
|
||||||
del rcon_connections[server]
|
del rcon_connections[server]
|
||||||
self.bot.con.run('update guild_config set rcon_connections = %(connections)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set rcon_connections = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'connections': json.dumps(rcon_connections)})
|
ctx.guild.id, json.dumps(rcon_connections))
|
||||||
await ctx.send('{0} has been removed from my configuration.'.format(server))
|
await ctx.send('{0} has been removed from my configuration.'.format(server))
|
||||||
else:
|
else:
|
||||||
await ctx.send('{0} is not in my configuration.'.format(server))
|
await ctx.send('{0} is not in my configuration.'.format(server))
|
||||||
@@ -309,10 +316,11 @@ class Rcon:
|
|||||||
"""Adds the included Steam 64 IDs to the running whitelist on all the ARK servers in the current guild\'s rcon config.
|
"""Adds the included Steam 64 IDs to the running whitelist on all the ARK servers in the current guild\'s rcon config.
|
||||||
Steam 64 IDs should be a comma seperated list of IDs.
|
Steam 64 IDs should be a comma seperated list of IDs.
|
||||||
Example: 76561198024193239,76561198024193239,76561198024193239"""
|
Example: 76561198024193239,76561198024193239,76561198024193239"""
|
||||||
if checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_rcon_admin(self.bot, ctx):
|
||||||
if steam_ids is not None:
|
if steam_ids is not None:
|
||||||
rcon_connections = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
rcon_connections = json.loads(await self.bot.db_con.fetchval('select rcon_connections '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'from guild_config where guild_id = $1',
|
||||||
|
ctx.guild.id))
|
||||||
error = 0
|
error = 0
|
||||||
error_msg = ''
|
error_msg = ''
|
||||||
success_msg = 'Adding to the running whitelist on all servers.'
|
success_msg = 'Adding to the running whitelist on all servers.'
|
||||||
@@ -356,9 +364,9 @@ class Rcon:
|
|||||||
"""Runs SaveWorld on the specified ARK server.
|
"""Runs SaveWorld on the specified ARK server.
|
||||||
If a server is not specified it will default to running saveworld on all servers in the guild\'s config.
|
If a server is not specified it will default to running saveworld on all servers in the guild\'s config.
|
||||||
Will print out "World Saved" for each server when the command completes successfully."""
|
Will print out "World Saved" for each server when the command completes successfully."""
|
||||||
if checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_rcon_admin(self.bot, ctx):
|
||||||
rcon_connections = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
rcon_connections = json.loads(await self.bot.db_con.fetchval('select rcon_connections from guild_config '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'where guild_id = $1', ctx.guild.id))
|
||||||
success_msg = 'Running saveworld'
|
success_msg = 'Running saveworld'
|
||||||
if server is None:
|
if server is None:
|
||||||
success_msg += ' on all the servers:'
|
success_msg += ' on all the servers:'
|
||||||
@@ -369,7 +377,7 @@ class Rcon:
|
|||||||
await msg.edit(content=success_msg.strip())
|
await msg.edit(content=success_msg.strip())
|
||||||
message = await self.bot.loop.run_in_executor(None, self._saveworld, rcon_connections[server])
|
message = await self.bot.loop.run_in_executor(None, self._saveworld, rcon_connections[server])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
success_msg = '{0}\n{1}'.format(success_msg, e.strip())
|
success_msg = '{0}\n{1}'.format(success_msg, e)
|
||||||
await msg.edit(content=success_msg.strip())
|
await msg.edit(content=success_msg.strip())
|
||||||
else:
|
else:
|
||||||
success_msg = '{0}\n{1}'.format(success_msg, message.strip())
|
success_msg = '{0}\n{1}'.format(success_msg, message.strip())
|
||||||
@@ -398,9 +406,9 @@ class Rcon:
|
|||||||
"""Sends a broadcast message to all servers in the guild config.
|
"""Sends a broadcast message to all servers in the guild config.
|
||||||
The message will be prefixed with the Discord name of the person running the command.
|
The message will be prefixed with the Discord name of the person running the command.
|
||||||
Will print "Success" for each server once the broadcast is sent."""
|
Will print "Success" for each server once the broadcast is sent."""
|
||||||
if checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_rcon_admin(self.bot, ctx):
|
||||||
rcon_connections = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
rcon_connections = json.loads(await self.bot.db_con.fetchval('select rcon_connections from guild_config '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'where guild_id = $1', ctx.guild.id))
|
||||||
if message is not None:
|
if message is not None:
|
||||||
message = f'{ctx.author.display_name}: {message}'
|
message = f'{ctx.author.display_name}: {message}'
|
||||||
success_msg = f'Broadcasting "{message}" to all servers.'
|
success_msg = f'Broadcasting "{message}" to all servers.'
|
||||||
@@ -414,7 +422,7 @@ class Rcon:
|
|||||||
rcon_connections[server],
|
rcon_connections[server],
|
||||||
message)
|
message)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
success_msg = '{0}\n{1}'.format(success_msg, e.strip())
|
success_msg = '{0}\n{1}'.format(success_msg, e)
|
||||||
await msg.edit(content=success_msg.strip())
|
await msg.edit(content=success_msg.strip())
|
||||||
else:
|
else:
|
||||||
for mesg in messages:
|
for mesg in messages:
|
||||||
@@ -435,9 +443,9 @@ class Rcon:
|
|||||||
The message will be prefixed with the Discord name of the person running the command.
|
The message will be prefixed with the Discord name of the person running the command.
|
||||||
If <server> has more than one word in it's name it will either need to be surrounded
|
If <server> has more than one word in it's name it will either need to be surrounded
|
||||||
by double quotes or the words separated by _"""
|
by double quotes or the words separated by _"""
|
||||||
if checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_rcon_admin(self.bot, ctx):
|
||||||
rcon_connections = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
rcon_connections = json.loads(await self.bot.db_con.fetchval('select rcon_connections from guild_config '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'where guild_id = $1', ctx.guild.id))
|
||||||
if server is not None:
|
if server is not None:
|
||||||
server = server.replace('_', ' ').title()
|
server = server.replace('_', ' ').title()
|
||||||
if message is not None:
|
if message is not None:
|
||||||
@@ -473,9 +481,9 @@ class Rcon:
|
|||||||
and these channel's permissions will be synced to the category.
|
and these channel's permissions will be synced to the category.
|
||||||
These channels will be added to the guild's rcon config and are where the
|
These channels will be added to the guild's rcon config and are where the
|
||||||
server chat messages will be sent when monitor_chat is run."""
|
server chat messages will be sent when monitor_chat is run."""
|
||||||
if checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_rcon_admin(self.bot, ctx):
|
||||||
rcon_connections = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
rcon_connections = json.loads(await self.bot.db_con.fetchval('select rcon_connections from guild_config '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'where guild_id = $1', ctx.guild.id))
|
||||||
edited = 0
|
edited = 0
|
||||||
category = discord.utils.get(ctx.guild.categories, name='Server Chats')
|
category = discord.utils.get(ctx.guild.categories, name='Server Chats')
|
||||||
if category is None:
|
if category is None:
|
||||||
@@ -498,8 +506,8 @@ class Rcon:
|
|||||||
rcon_connections[server]['game_chat_chan_id'] = chan.id
|
rcon_connections[server]['game_chat_chan_id'] = chan.id
|
||||||
edited = 1
|
edited = 1
|
||||||
if edited == 1:
|
if edited == 1:
|
||||||
self.bot.con.run('update guild_config set rcon_connections = %(json)s where guild_id = %(id)s',
|
await self.bot.db_con.execute('update guild_config set rcon_connections = $2 where guild_id = $1',
|
||||||
{'id': ctx.guild.id, 'json': json.dumps(rcon_connections)})
|
ctx.guild.id, json.dumps(rcon_connections))
|
||||||
await ctx.message.add_reaction('✅')
|
await ctx.message.add_reaction('✅')
|
||||||
else:
|
else:
|
||||||
await ctx.send(f'You are not authorized to run this command.')
|
await ctx.send(f'You are not authorized to run this command.')
|
||||||
@@ -509,8 +517,8 @@ class Rcon:
|
|||||||
@commands.check(checks.is_restricted_chan)
|
@commands.check(checks.is_restricted_chan)
|
||||||
async def list_ark_servers(self, ctx):
|
async def list_ark_servers(self, ctx):
|
||||||
"""Returns a list of all the ARK servers in the current guild\'s config."""
|
"""Returns a list of all the ARK servers in the current guild\'s config."""
|
||||||
servers = json.loads(self.bot.con.one('select rcon_connections from guild_config\
|
servers = json.loads(await self.bot.db_con.fetchval('select rcon_connections from guild_config '
|
||||||
where guild_id = %(id)s', {'id': ctx.guild.id}))
|
'where guild_id = $1', ctx.guild.id))
|
||||||
em = discord.Embed(style='rich',
|
em = discord.Embed(style='rich',
|
||||||
title=f'__**There are currently {len(servers)} ARK servers in my config:**__',
|
title=f'__**There are currently {len(servers)} ARK servers in my config:**__',
|
||||||
color=discord.Colour.green()
|
color=discord.Colour.green()
|
||||||
@@ -7,7 +7,7 @@ import inspect
|
|||||||
import textwrap
|
import textwrap
|
||||||
from contextlib import redirect_stdout
|
from contextlib import redirect_stdout
|
||||||
import io
|
import io
|
||||||
from .imports.utils import paginate, run_command
|
from src.imports.utils import run_command, format_output, Paginator
|
||||||
|
|
||||||
ownerids = [351794468870946827, 275280442884751360]
|
ownerids = [351794468870946827, 275280442884751360]
|
||||||
ownerid = 351794468870946827
|
ownerid = 351794468870946827
|
||||||
@@ -37,6 +37,7 @@ class Repl:
|
|||||||
async def _eval(self, ctx, *, body: str):
|
async def _eval(self, ctx, *, body: str):
|
||||||
if ctx.author.id != ownerid:
|
if ctx.author.id != ownerid:
|
||||||
return
|
return
|
||||||
|
pag = Paginator(self.bot)
|
||||||
env = {
|
env = {
|
||||||
'bot': self.bot,
|
'bot': self.bot,
|
||||||
'ctx': ctx,
|
'ctx': ctx,
|
||||||
@@ -60,8 +61,10 @@ class Repl:
|
|||||||
with redirect_stdout(stdout):
|
with redirect_stdout(stdout):
|
||||||
ret = await func()
|
ret = await func()
|
||||||
except Exception:
|
except Exception:
|
||||||
value = stdout.getvalue()
|
pag.add(stdout.getvalue())
|
||||||
await ctx.send('```py\n{}{}\n```'.format(value, traceback.format_exc()))
|
pag.add(traceback.format_exc())
|
||||||
|
for page in pag.pages():
|
||||||
|
await ctx.send(page)
|
||||||
else:
|
else:
|
||||||
value = stdout.getvalue()
|
value = stdout.getvalue()
|
||||||
# noinspection PyBroadException
|
# noinspection PyBroadException
|
||||||
@@ -69,17 +72,12 @@ class Repl:
|
|||||||
await ctx.message.add_reaction('✅')
|
await ctx.message.add_reaction('✅')
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
if ret is None:
|
value = format_output(value)
|
||||||
if value:
|
pag.add(value)
|
||||||
for page in paginate(value):
|
pag.add(f'\nReturned: {ret}')
|
||||||
await ctx.send(page)
|
self._last_result = ret
|
||||||
else:
|
for page in pag.pages():
|
||||||
self._last_result = ret
|
await ctx.send(page)
|
||||||
if value:
|
|
||||||
for page in paginate(value):
|
|
||||||
await ctx.send(page)
|
|
||||||
for page in paginate(ret):
|
|
||||||
await ctx.send(page)
|
|
||||||
|
|
||||||
@commands.command(hidden=True)
|
@commands.command(hidden=True)
|
||||||
async def repl(self, ctx):
|
async def repl(self, ctx):
|
||||||
@@ -143,12 +141,11 @@ class Repl:
|
|||||||
fmt = '{}'.format(value)
|
fmt = '{}'.format(value)
|
||||||
try:
|
try:
|
||||||
if fmt is not None:
|
if fmt is not None:
|
||||||
if len(fmt) > 1990:
|
pag = Paginator(self.bot)
|
||||||
for page in paginate(fmt):
|
pag.add(fmt)
|
||||||
await response.channel.send(page)
|
for page in pag.pages():
|
||||||
await ctx.send(response.channel)
|
await response.channel.send(page)
|
||||||
else:
|
await ctx.send(response.channel)
|
||||||
await response.channel.send(f'```py\n{fmt}\n```')
|
|
||||||
except discord.Forbidden:
|
except discord.Forbidden:
|
||||||
pass
|
pass
|
||||||
except discord.HTTPException as e:
|
except discord.HTTPException as e:
|
||||||
@@ -159,16 +156,14 @@ class Repl:
|
|||||||
if ctx.author.id != ownerid:
|
if ctx.author.id != ownerid:
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
body = self.cleanup_code(body).split(' ')
|
body = self.cleanup_code(body)
|
||||||
result = await asyncio.wait_for(self.bot.loop.create_task(run_command(body)), 10)
|
pag = Paginator(self.bot)
|
||||||
value = result
|
pag.add(await asyncio.wait_for(self.bot.loop.create_task(run_command(body)), 10))
|
||||||
for page in paginate(value):
|
for page in pag.pages():
|
||||||
await ctx.send(page)
|
await ctx.send(page)
|
||||||
await ctx.message.add_reaction('✅')
|
await ctx.message.add_reaction('✅')
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
value = f"Command did not complete in the time allowed."
|
await ctx.send(f"Command did not complete in the time allowed.")
|
||||||
for page in paginate(value):
|
|
||||||
await ctx.send(page)
|
|
||||||
await ctx.message.add_reaction('❌')
|
await ctx.message.add_reaction('❌')
|
||||||
|
|
||||||
|
|
||||||
@@ -7,10 +7,19 @@ import psutil
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import asyncio
|
import asyncio
|
||||||
import async_timeout
|
import async_timeout
|
||||||
from .imports import checks
|
from src.imports import checks, utils
|
||||||
import pytz
|
import pytz
|
||||||
import gspread
|
import gspread
|
||||||
from oauth2client.service_account import ServiceAccountCredentials
|
from oauth2client.service_account import ServiceAccountCredentials
|
||||||
|
import matplotlib as mpl
|
||||||
|
mpl.use('Agg')
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from mpl_toolkits.basemap import Basemap
|
||||||
|
from io import BytesIO
|
||||||
|
from itertools import chain
|
||||||
|
import numpy as np
|
||||||
|
from dateutil.parser import parse
|
||||||
|
from copy import copy
|
||||||
|
|
||||||
config_dir = 'config/'
|
config_dir = 'config/'
|
||||||
admin_id_file = 'admin_ids'
|
admin_id_file = 'admin_ids'
|
||||||
@@ -22,6 +31,7 @@ invite_match = '(https?://)?(www.)?discord(app.com/(invite|oauth2)|.gg|.io)/[\w\
|
|||||||
|
|
||||||
utils_log = logging.getLogger('utils')
|
utils_log = logging.getLogger('utils')
|
||||||
clock_emojis = ['🕛', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚']
|
clock_emojis = ['🕛', '🕐', '🕑', '🕒', '🕓', '🕔', '🕕', '🕖', '🕗', '🕘', '🕙', '🕚']
|
||||||
|
replace_tzs = {'MST': 'US/Mountain', 'HST': 'US/Hawaii', 'EST': 'US/Eastern'}
|
||||||
|
|
||||||
|
|
||||||
class Utils:
|
class Utils:
|
||||||
@@ -44,20 +54,20 @@ class Utils:
|
|||||||
msg = await self.bot.wait_for('message', timeout=5, check=check)
|
msg = await self.bot.wait_for('message', timeout=5, check=check)
|
||||||
self.bot.ping_times[i]['rec'] = msg
|
self.bot.ping_times[i]['rec'] = msg
|
||||||
|
|
||||||
@commands.command()
|
@commands.command(hidden=True)
|
||||||
async def channel_ping(self, ctx, wait_time: float=10, message: str='=bump', channel: int=265828729970753537):
|
async def channel_ping(self, ctx, wait_time: float=10, message: str='=bump', channel: int=265828729970753537):
|
||||||
await ctx.send('Starting Background Process.')
|
await ctx.send('Starting Background Process.')
|
||||||
self.bot.loop.create_task(self._4_hour_ping(channel, message, wait_time))
|
self.bot.loop.create_task(self._4_hour_ping(channel, message, wait_time))
|
||||||
|
|
||||||
@commands.command()
|
@commands.command(hidden=True)
|
||||||
@commands.is_owner()
|
@commands.is_owner()
|
||||||
async def sysinfo(self, ctx):
|
async def sysinfo(self, ctx):
|
||||||
await ctx.send(f'''
|
"""Gets system status for my server."""
|
||||||
```ml
|
await ctx.send(f'```ml\n'
|
||||||
CPU Percentages: {psutil.cpu_percent(percpu=True)}
|
f'CPU Percentages: {psutil.cpu_percent(percpu=True)}\n'
|
||||||
Memory Usage: {psutil.virtual_memory().percent}%
|
f'Memory Usage: {psutil.virtual_memory().percent}%\n'
|
||||||
Disc Usage: {psutil.disk_usage("/").percent}%
|
f'Disc Usage: {psutil.disk_usage("/").percent}%\n'
|
||||||
```''')
|
f'```')
|
||||||
|
|
||||||
@commands.command(hidden=True)
|
@commands.command(hidden=True)
|
||||||
async def role(self, ctx, role: str):
|
async def role(self, ctx, role: str):
|
||||||
@@ -168,7 +178,10 @@ class Utils:
|
|||||||
@commands.command()
|
@commands.command()
|
||||||
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
async def ping(self, ctx, mode='normal', count: int=2):
|
async def ping(self, ctx, mode='normal', count: int=2):
|
||||||
"""Check the Bot\'s connection to Discord"""
|
"""Check the Bot\'s connection to Discord
|
||||||
|
|
||||||
|
For more detailed information set the <mode> as comp and it will test the ping
|
||||||
|
<count> number of times."""
|
||||||
em = discord.Embed(style='rich',
|
em = discord.Embed(style='rich',
|
||||||
title=f'Pong 🏓',
|
title=f'Pong 🏓',
|
||||||
color=discord.Colour.green()
|
color=discord.Colour.green()
|
||||||
@@ -176,8 +189,8 @@ class Utils:
|
|||||||
msg = await ctx.send(embed=em)
|
msg = await ctx.send(embed=em)
|
||||||
time1 = ctx.message.created_at
|
time1 = ctx.message.created_at
|
||||||
time = (msg.created_at - time1).total_seconds() * 1000
|
time = (msg.created_at - time1).total_seconds() * 1000
|
||||||
em.description = f'''Response Time: **{math.ceil(time)}ms**
|
em.description = f'Response Time: **{math.ceil(time)}ms**\n' \
|
||||||
Discord Latency: **{math.ceil(self.bot.latency*1000)}ms**'''
|
f'Discord Latency: **{math.ceil(self.bot.latency*1000)}ms**'
|
||||||
await msg.edit(embed=em)
|
await msg.edit(embed=em)
|
||||||
|
|
||||||
if mode == 'comp':
|
if mode == 'comp':
|
||||||
@@ -206,8 +219,8 @@ class Utils:
|
|||||||
time = time.total_seconds()
|
time = time.total_seconds()
|
||||||
times.append(time)
|
times.append(time)
|
||||||
value = f"Message Sent:" \
|
value = f"Message Sent:" \
|
||||||
f"{datetime.strftime(self.bot.ping_times[i]['snd'].created_at, '%H:%M:%S.%f')}" \
|
f"{datetime.strftime(self.bot.ping_times[i]['snd'].created_at, '%H:%M:%S.%f')}\n" \
|
||||||
f"Response Received: {datetime.strftime(now, '%H:%M:%S.%f')}" \
|
f"Response Received: {datetime.strftime(now, '%H:%M:%S.%f')}\n" \
|
||||||
f"Total Time: {math.ceil(time * 1000)}ms"
|
f"Total Time: {math.ceil(time * 1000)}ms"
|
||||||
await self.bot.ping_times[i]['rec'].delete()
|
await self.bot.ping_times[i]['rec'].delete()
|
||||||
em.add_field(name=f'Ping Test {i}', value=value, inline=True)
|
em.add_field(name=f'Ping Test {i}', value=value, inline=True)
|
||||||
@@ -220,11 +233,11 @@ class Utils:
|
|||||||
em.add_field(value=f'Total Time for Comprehensive test: {math.ceil(total_time)}ms',
|
em.add_field(value=f'Total Time for Comprehensive test: {math.ceil(total_time)}ms',
|
||||||
name=f'Average: **{round(total_time/count,1)}ms**',
|
name=f'Average: **{round(total_time/count,1)}ms**',
|
||||||
inline=False)
|
inline=False)
|
||||||
await msg.edit(embed=em)
|
await msg.edit(embed=em)
|
||||||
|
|
||||||
@commands.group(case_insensitive=True)
|
@commands.group(case_insensitive=True)
|
||||||
async def admin(self, ctx):
|
async def admin(self, ctx):
|
||||||
"""Run help admin for more info"""
|
"""Group for Admin help requests"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@admin.command(name='new', aliases=['nr'])
|
@admin.command(name='new', aliases=['nr'])
|
||||||
@@ -236,25 +249,20 @@ class Utils:
|
|||||||
if ctx.guild:
|
if ctx.guild:
|
||||||
if request_msg is not None:
|
if request_msg is not None:
|
||||||
if len(request_msg) < 1000:
|
if len(request_msg) < 1000:
|
||||||
self.bot.con.run('insert into admin_requests (issuing_member_id, guild_orig, request_text,'
|
await self.bot.db_con.execute('insert into admin_requests (issuing_member_id, guild_orig, '
|
||||||
'request_time) values (%(member_id)s, %(guild_id)s, %(text)s, %(time)s)',
|
'request_text, request_time) values ($1, $2, $3, $4)',
|
||||||
{'member_id': ctx.author.id, 'guild_id': ctx.guild.id, 'text': request_msg,
|
ctx.author.id, ctx.guild.id, request_msg, ctx.message.created_at)
|
||||||
'time': ctx.message.created_at})
|
channel = await self.bot.db_con.fetchval(f'select admin_chat from guild_config where guild_id = $1',
|
||||||
channel = self.bot.con.one(f'select admin_chat from guild_config where guild_id = {ctx.guild.id}')
|
ctx.guild.id)
|
||||||
if channel:
|
if channel:
|
||||||
chan = discord.utils.get(ctx.guild.channels, id=channel)
|
chan = discord.utils.get(ctx.guild.channels, id=channel)
|
||||||
msg = ''
|
msg = ''
|
||||||
admin_roles = []
|
roles = await self.bot.db_con.fetchval(f'select admin_roles,rcon_admin_roles from guild_config '
|
||||||
roles = self.bot.con.one(f'select admin_roles,rcon_admin_roles from guild_config where '
|
f'where guild_id = $1', ctx.guild.id)
|
||||||
f'guild_id = %(id)s', {'id': ctx.guild.id})
|
request_id = await self.bot.db_con.fetchval(f'select id from admin_requests where '
|
||||||
request_id = self.bot.con.one(f'select id from admin_requests where '
|
f'issuing_member_id = $1 and request_time = $2',
|
||||||
f'issuing_member_id = %(member_id)s and request_time = %(time)s',
|
ctx.author.id, ctx.message.created_at)
|
||||||
{'member_id': ctx.author.id, 'time': ctx.message.created_at})
|
admin_roles = json.loads(roles).values()
|
||||||
for item in roles:
|
|
||||||
i = json.loads(item)
|
|
||||||
for j in i:
|
|
||||||
if i[j] not in admin_roles:
|
|
||||||
admin_roles.append(i[j])
|
|
||||||
for role in admin_roles:
|
for role in admin_roles:
|
||||||
msg = '{0} {1}'.format(msg, discord.utils.get(ctx.guild.roles, id=role).mention)
|
msg = '{0} {1}'.format(msg, discord.utils.get(ctx.guild.roles, id=role).mention)
|
||||||
msg += f"New Request ID: {request_id} " \
|
msg += f"New Request ID: {request_id} " \
|
||||||
@@ -273,7 +281,7 @@ class Utils:
|
|||||||
@admin.command(name='list', aliases=['lr'])
|
@admin.command(name='list', aliases=['lr'])
|
||||||
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
@commands.cooldown(1, 5, type=commands.BucketType.user)
|
||||||
async def list_admin_requests(self, ctx, assigned_to: discord.Member=None):
|
async def list_admin_requests(self, ctx, assigned_to: discord.Member=None):
|
||||||
"""Returns a list of all active Admin help requests for this guild
|
"""List of all active Admin help requests
|
||||||
|
|
||||||
If a user runs this command it will return all the requests that they have submitted and are still open.
|
If a user runs this command it will return all the requests that they have submitted and are still open.
|
||||||
- The [assigned_to] argument is ignored but will still give an error if an incorrect value is entered.
|
- The [assigned_to] argument is ignored but will still give an error if an incorrect value is entered.
|
||||||
@@ -286,10 +294,10 @@ class Utils:
|
|||||||
title=f'Admin Help Requests',
|
title=f'Admin Help Requests',
|
||||||
color=discord.Colour.green()
|
color=discord.Colour.green()
|
||||||
)
|
)
|
||||||
if checks.is_admin(self.bot, ctx) or checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx) or await checks.is_rcon_admin(self.bot, ctx):
|
||||||
if assigned_to is None:
|
if assigned_to is None:
|
||||||
requests = self.bot.con.all(f'select * from admin_requests where guild_orig = %(guild_id)s '
|
requests = await self.bot.db_con.fetch(f'select * from admin_requests where guild_orig = $1 '
|
||||||
f'and completed_time is null', {'guild_id': ctx.guild.id})
|
f'and completed_time is null', ctx.guild.id)
|
||||||
em.title = f'Admin help requests for {ctx.guild.name}'
|
em.title = f'Admin help requests for {ctx.guild.name}'
|
||||||
if requests:
|
if requests:
|
||||||
for request in requests:
|
for request in requests:
|
||||||
@@ -306,11 +314,11 @@ class Utils:
|
|||||||
else:
|
else:
|
||||||
em.add_field(name='There are no pending requests for this guild.', value='', inline=False)
|
em.add_field(name='There are no pending requests for this guild.', value='', inline=False)
|
||||||
else:
|
else:
|
||||||
if checks.check_admin_role(self.bot, ctx, assigned_to)\
|
if await checks.check_admin_role(self.bot, ctx, assigned_to)\
|
||||||
or checks.check_rcon_role(self.bot, ctx, assigned_to):
|
or await checks.check_rcon_role(self.bot, ctx, assigned_to):
|
||||||
requests = self.bot.con.all('select * from admin_requests where assigned_to = %(admin_id)s '
|
requests = await self.bot.db_con.fetch('select * from admin_requests where assigned_to = $1 '
|
||||||
'and guild_orig = %(guild_id)s and completed_time is null',
|
'and guild_orig = $2 and completed_time is null',
|
||||||
{'admin_id': assigned_to.id, 'guild_id': ctx.guild.id})
|
assigned_to.id, ctx.guild.id)
|
||||||
em.title = f'Admin help requests assigned to {assigned_to.display_name} in {ctx.guild.name}'
|
em.title = f'Admin help requests assigned to {assigned_to.display_name} in {ctx.guild.name}'
|
||||||
if requests:
|
if requests:
|
||||||
for request in requests:
|
for request in requests:
|
||||||
@@ -322,15 +330,16 @@ class Utils:
|
|||||||
"",
|
"",
|
||||||
inline=False)
|
inline=False)
|
||||||
else:
|
else:
|
||||||
em.add_field(name=f'There are no pending requests for {assigned_to.display_name} on this guild.',
|
em.add_field(name=f'There are no pending requests for '
|
||||||
|
f'{assigned_to.display_name} on this guild.',
|
||||||
value='',
|
value='',
|
||||||
inline=False)
|
inline=False)
|
||||||
else:
|
else:
|
||||||
em.title = f'{assigned_to.display_name} is not an admin in this guild.'
|
em.title = f'{assigned_to.display_name} is not an admin in this guild.'
|
||||||
else:
|
else:
|
||||||
requests = self.bot.con.all('select * from admin_requests where issuing_member_id = %(member_id)s '
|
requests = await self.bot.db_con.fetch('select * from admin_requests where issuing_member_id = $1 '
|
||||||
'and guild_orig = %(guild_id)s and completed_time is null',
|
'and guild_orig = $2 and completed_time is null',
|
||||||
{'member_id': ctx.author.id, 'guild_id': ctx.guild.id})
|
ctx.author.id, ctx.guild.id)
|
||||||
em.title = f'Admin help requests for {ctx.author.display_name}'
|
em.title = f'Admin help requests for {ctx.author.display_name}'
|
||||||
if requests:
|
if requests:
|
||||||
for request in requests:
|
for request in requests:
|
||||||
@@ -352,7 +361,7 @@ class Utils:
|
|||||||
"""Allows Admin to close admin help tickets.
|
"""Allows Admin to close admin help tickets.
|
||||||
[request_id] must be a valid integer pointing to an open Request ID
|
[request_id] must be a valid integer pointing to an open Request ID
|
||||||
"""
|
"""
|
||||||
if checks.is_admin(self.bot, ctx) or checks.is_rcon_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx) or await checks.is_rcon_admin(self.bot, ctx):
|
||||||
if request_ids:
|
if request_ids:
|
||||||
request_ids = request_ids.replace(' ', '').split(',')
|
request_ids = request_ids.replace(' ', '').split(',')
|
||||||
for request_id in request_ids:
|
for request_id in request_ids:
|
||||||
@@ -361,14 +370,13 @@ class Utils:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
await ctx.send(f'{request_id} is not a valid request id.')
|
await ctx.send(f'{request_id} is not a valid request id.')
|
||||||
else:
|
else:
|
||||||
request = self.bot.con.one(f'select * from admin_requests where id = %(request_id)s',
|
request = await self.bot.db_con.fetchrow(f'select * from admin_requests where id = $1',
|
||||||
{'request_id': request_id})
|
request_id)
|
||||||
if request:
|
if request:
|
||||||
if request[3] == ctx.guild.id:
|
if request[3] == ctx.guild.id:
|
||||||
if request[6] is None:
|
if request[6] is None:
|
||||||
self.bot.con.run('update admin_requests set completed_time = %(time_now)s where '
|
await self.bot.db_con.execute('update admin_requests set completed_time = $1 where '
|
||||||
'id = %(request_id)s',
|
'id = $2', ctx.message.created_at, request_id)
|
||||||
{'time_now': ctx.message.created_at, 'request_id': request_id})
|
|
||||||
await ctx.send(f'Request {request_id} by '
|
await ctx.send(f'Request {request_id} by '
|
||||||
f'{ctx.guild.get_member(request[1]).display_name}'
|
f'{ctx.guild.get_member(request[1]).display_name}'
|
||||||
f' has been marked complete.')
|
f' has been marked complete.')
|
||||||
@@ -386,7 +394,8 @@ class Utils:
|
|||||||
@commands.command(name='weather', aliases=['wu'])
|
@commands.command(name='weather', aliases=['wu'])
|
||||||
@commands.cooldown(5, 15, type=commands.BucketType.default)
|
@commands.cooldown(5, 15, type=commands.BucketType.default)
|
||||||
async def get_weather(self, ctx, *, location='palmer ak'):
|
async def get_weather(self, ctx, *, location='palmer ak'):
|
||||||
"""Gets the weather data for the location provided,
|
"""Gets the weather data for the location given
|
||||||
|
|
||||||
If no location is included then it will get the weather for the Bot's home location.
|
If no location is included then it will get the weather for the Bot's home location.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
@@ -423,7 +432,12 @@ class Utils:
|
|||||||
@commands.command(name='localtime', aliases=['time', 'lt'])
|
@commands.command(name='localtime', aliases=['time', 'lt'])
|
||||||
@commands.cooldown(1, 3, type=commands.BucketType.user)
|
@commands.cooldown(1, 3, type=commands.BucketType.user)
|
||||||
async def get_localtime(self, ctx, timezone: str='Anchorage'):
|
async def get_localtime(self, ctx, timezone: str='Anchorage'):
|
||||||
|
"""Shows the current time in the timezone given
|
||||||
|
|
||||||
|
This defaults to the Bot's local timezone of Anchorage Alaska USA if none are given."""
|
||||||
|
|
||||||
em = discord.Embed()
|
em = discord.Embed()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
tz = pytz.timezone(timezone)
|
tz = pytz.timezone(timezone)
|
||||||
localtime = datetime.now(tz=tz)
|
localtime = datetime.now(tz=tz)
|
||||||
@@ -444,13 +458,91 @@ class Utils:
|
|||||||
em.colour = discord.Colour.red()
|
em.colour = discord.Colour.red()
|
||||||
await ctx.send(embed=em)
|
await ctx.send(embed=em)
|
||||||
|
|
||||||
|
# noinspection PyUnboundLocalVariable
|
||||||
|
@commands.command(name='gettimein', aliases=['timein', 'gti'])
|
||||||
|
@commands.cooldown(1, 3, type=commands.BucketType.user)
|
||||||
|
async def get_time_in_timezone(self, ctx, timezone: str='US/Eastern', *, time: str=None):
|
||||||
|
"""Convert the time provided to given timezone
|
||||||
|
|
||||||
|
Attempts to process the given time and timezone and convert into the given timezone.
|
||||||
|
Example: g$gti CET Friday June 15 2018 US/Alaska
|
||||||
|
This will be processed into a datetime with US/Alaska set as the timezone and will
|
||||||
|
convert it into CET timezone and return both times."""
|
||||||
|
|
||||||
|
em = discord.Embed()
|
||||||
|
|
||||||
|
if time is None:
|
||||||
|
em.set_footer(text='Time not given... using current UTC time.')
|
||||||
|
in_time = datetime.utcnow()
|
||||||
|
parsed_tz = pytz.timezone('UTC')
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
orig_time = copy(time)
|
||||||
|
split_time = time.split()
|
||||||
|
try:
|
||||||
|
parsed_tz = pytz.timezone(replace_tzs.get(split_time[-1].upper()) or split_time[-1])
|
||||||
|
time = utils.replace_text_ignorecase(time, old=split_time[-1], new='')
|
||||||
|
except pytz.exceptions.UnknownTimeZoneError:
|
||||||
|
for tz in pytz.all_timezones:
|
||||||
|
if split_time[-1].lower() in tz.lower():
|
||||||
|
time = utils.replace_text_ignorecase(time, old=split_time[-1], new='')
|
||||||
|
if tz in replace_tzs:
|
||||||
|
tz = replace_tzs['tz']
|
||||||
|
parsed_tz = pytz.timezone(tz)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
em.set_footer(text='Valid timezone not found in time string. Using UTC...')
|
||||||
|
parsed_tz = pytz.timezone('UTC')
|
||||||
|
if not time.isspace() and not time == '':
|
||||||
|
in_time = parse(time.upper())
|
||||||
|
in_time = parsed_tz.localize(in_time)
|
||||||
|
else:
|
||||||
|
em.set_footer(text='Time not given. Using current time.')
|
||||||
|
in_time = datetime.now(tz=parsed_tz)
|
||||||
|
except ValueError:
|
||||||
|
raise commands.CommandError(f'For some reason I can\'t parse this time string: \n'
|
||||||
|
f'{orig_time} {time} {parsed_tz}\n'
|
||||||
|
f'Examples of valid time strings are in my help documentation.\n'
|
||||||
|
f'Please try again.')
|
||||||
|
try:
|
||||||
|
out_tz = pytz.timezone(timezone)
|
||||||
|
except pytz.exceptions.UnknownTimeZoneError:
|
||||||
|
for tz in pytz.all_timezones:
|
||||||
|
if timezone.lower() in tz.lower():
|
||||||
|
out_tz = pytz.timezone(tz)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
out_tz = None
|
||||||
|
em.title = 'Unknown Timezone.'
|
||||||
|
em.colour = discord.Colour.red()
|
||||||
|
finally:
|
||||||
|
if out_tz:
|
||||||
|
out_time = in_time.astimezone(out_tz)
|
||||||
|
em.add_field(name=f'{parsed_tz}',
|
||||||
|
value=f'{clock_emojis[(in_time.hour % 12)]} {in_time.strftime("%c")}', inline=False)
|
||||||
|
em.add_field(name=f'{out_tz}',
|
||||||
|
value=f'{clock_emojis[(out_time.hour % 12)]} {out_time.strftime("%c")}', inline=False)
|
||||||
|
em.colour = self.bot.embed_color
|
||||||
|
await ctx.send(embed=em)
|
||||||
|
|
||||||
@commands.command(name='purge', aliases=['clean', 'erase'])
|
@commands.command(name='purge', aliases=['clean', 'erase'])
|
||||||
@commands.cooldown(1, 3, type=commands.BucketType.user)
|
@commands.cooldown(1, 3, type=commands.BucketType.user)
|
||||||
async def purge_messages(self, ctx, number: int=20, member: discord.Member=None):
|
async def purge_messages(self, ctx, number: int=20, member: discord.Member=None):
|
||||||
|
"""Purge messages from the current channel
|
||||||
|
By default this will only purge messages sent by Geeksbot and any messages that appear to
|
||||||
|
have called Geeksbot (aka start with one of the Geeksbot's prefixes for this Guild)
|
||||||
|
If you want to purge messages from a different user you must provide a number and member
|
||||||
|
|
||||||
|
Note: Geeksbot will not find <number> of messages by the given member, it will instead
|
||||||
|
search the last <number> messages in the channel and delete any by the given member"""
|
||||||
|
prefixes = await self.bot.db_con.fetchval('select prefix from guild_config '
|
||||||
|
'where guild_id = $1', ctx.guild.id)
|
||||||
|
|
||||||
def is_me(message):
|
def is_me(message):
|
||||||
|
nonlocal prefixes
|
||||||
if message.author == self.bot.user:
|
if message.author == self.bot.user:
|
||||||
return True
|
return True
|
||||||
prefixes = self.bot.con.one('select prefix from guild_config where guild_id = %(id)s', {'id': ctx.guild.id})
|
|
||||||
if prefixes:
|
if prefixes:
|
||||||
for prefix in prefixes:
|
for prefix in prefixes:
|
||||||
if message.content.startswith(prefix):
|
if message.content.startswith(prefix):
|
||||||
@@ -464,7 +556,7 @@ class Utils:
|
|||||||
def is_author(message):
|
def is_author(message):
|
||||||
return message.author == ctx.author
|
return message.author == ctx.author
|
||||||
|
|
||||||
if checks.is_admin(self.bot, ctx):
|
if await checks.is_admin(self.bot, ctx):
|
||||||
if member:
|
if member:
|
||||||
deleted = await ctx.channel.purge(limit=number, check=is_member)
|
deleted = await ctx.channel.purge(limit=number, check=is_member)
|
||||||
if member != ctx.author:
|
if member != ctx.author:
|
||||||
@@ -480,7 +572,12 @@ class Utils:
|
|||||||
@commands.command(name='purge_all', aliases=['cls', 'clear'])
|
@commands.command(name='purge_all', aliases=['cls', 'clear'])
|
||||||
@commands.cooldown(1, 3, type=commands.BucketType.user)
|
@commands.cooldown(1, 3, type=commands.BucketType.user)
|
||||||
async def purge_all(self, ctx, number: int=20, contents: str='all'):
|
async def purge_all(self, ctx, number: int=20, contents: str='all'):
|
||||||
if checks.is_admin(self.bot, ctx):
|
"""Purge all messages from the current channel
|
||||||
|
|
||||||
|
Will delete all of the last <number> of messages from the channel
|
||||||
|
If <contents> is not 'all' then only messages containing <contents>
|
||||||
|
will be deleted."""
|
||||||
|
if await checks.is_admin(self.bot, ctx):
|
||||||
if contents != 'all':
|
if contents != 'all':
|
||||||
deleted = await ctx.channel.purge(limit=number, check=lambda message: message.content == contents)
|
deleted = await ctx.channel.purge(limit=number, check=lambda message: message.content == contents)
|
||||||
else:
|
else:
|
||||||
@@ -493,19 +590,24 @@ class Utils:
|
|||||||
|
|
||||||
@commands.command(name='google', aliases=['g', 'search'])
|
@commands.command(name='google', aliases=['g', 'search'])
|
||||||
async def google_search(self, ctx, *, search):
|
async def google_search(self, ctx, *, search):
|
||||||
|
"""WIP Search Google for the given string"""
|
||||||
res = self.bot.gcs_service.cse().list(q=search, cx=self.bot.bot_secrets['cx']).execute()
|
res = self.bot.gcs_service.cse().list(q=search, cx=self.bot.bot_secrets['cx']).execute()
|
||||||
results = res['items'][:4]
|
results = res['items']
|
||||||
em = discord.Embed()
|
pag = utils.Paginator(self.bot, max_line_length=100, embed=True)
|
||||||
em.title = f'Google Search'
|
pag.set_embed_meta(title='Google Search', description=f'Top results for "{search}"', color=self.bot.embed_color)
|
||||||
em.description = f'Top 4 results for "{search}"'
|
|
||||||
em.colour = embed_color
|
|
||||||
for result in results:
|
for result in results:
|
||||||
em.add_field(name=f'{result["title"]}', value=f'{result["snippet"]}\n{result["link"]}')
|
pag.add(f'\uFFF6{result["title"]}\n{result["link"]}', keep_intact=True)
|
||||||
await ctx.send(embed=em)
|
pag.add(f'{result["snippet"]}')
|
||||||
|
pag.add('\uFFF7\n\uFFF8')
|
||||||
|
msg = await ctx.send('Starting Book')
|
||||||
|
book = utils.Book(pag, (msg, ctx.channel, self.bot, ctx.message))
|
||||||
|
await book.create_book()
|
||||||
|
|
||||||
@commands.command(hidden=True, name='sheets')
|
@commands.command(hidden=True, name='sheets')
|
||||||
async def google_sheets(self, ctx, member: discord.Member):
|
async def google_sheets(self, ctx, member: discord.Member):
|
||||||
if checks.is_admin(self.bot, ctx):
|
"""Access Google Sheets and looks for the member"""
|
||||||
|
|
||||||
|
if await checks.is_admin(self.bot, ctx):
|
||||||
scope = ['https://spreadsheets.google.com/feeds',
|
scope = ['https://spreadsheets.google.com/feeds',
|
||||||
'https://www.googleapis.com/auth/drive']
|
'https://www.googleapis.com/auth/drive']
|
||||||
credentials = ServiceAccountCredentials.from_json_keyfile_name('config/google_client_secret.json', scope)
|
credentials = ServiceAccountCredentials.from_json_keyfile_name('config/google_client_secret.json', scope)
|
||||||
@@ -528,6 +630,152 @@ class Utils:
|
|||||||
value=f'Steam ID: {steam[i]}\nPatreon Level: {tier[i]}\nPatron of: {patron[i]}')
|
value=f'Steam ID: {steam[i]}\nPatreon Level: {tier[i]}\nPatron of: {patron[i]}')
|
||||||
await ctx.send(embed=em)
|
await ctx.send(embed=em)
|
||||||
|
|
||||||
|
@commands.command(name='iss')
|
||||||
|
async def iss_loc(self, ctx):
|
||||||
|
"""Locate the International Space Station
|
||||||
|
|
||||||
|
Gets the location of the ISS and display on a
|
||||||
|
Blue Marble map."""
|
||||||
|
def gen_image(iss_loc):
|
||||||
|
lat = iss_loc['latitude']
|
||||||
|
lon = iss_loc['longitude']
|
||||||
|
plt.figure(figsize=(5, 5))
|
||||||
|
m = Basemap(projection='ortho', resolution=None, lat_0=lat, lon_0=lon)
|
||||||
|
m.bluemarble(scale=0.5)
|
||||||
|
x, y = m(lon, lat)
|
||||||
|
plt.plot(x, y, 'ok', markersize=10, color='red')
|
||||||
|
plt.text(x, y, ' ISS', fontsize=20, color='red')
|
||||||
|
plt.tight_layout()
|
||||||
|
|
||||||
|
img = BytesIO()
|
||||||
|
plt.savefig(img, format='png', transparent=True)
|
||||||
|
img.seek(0)
|
||||||
|
self.bot.loop.create_task(ctx.send('Current ISS Location', file=discord.File(img, 'output.png')))
|
||||||
|
|
||||||
|
async with ctx.typing():
|
||||||
|
async with self.bot.aio_session.get('https://api.wheretheiss.at/v1/satellites/25544') as response:
|
||||||
|
loc = await response.json()
|
||||||
|
await self.bot.loop.run_in_executor(self.bot.tpe, gen_image, loc)
|
||||||
|
|
||||||
|
@commands.command(name='location', aliases=['loc', 'map'])
|
||||||
|
async def map_location(self, ctx, *, location):
|
||||||
|
"""WIP Displays the given location on a map
|
||||||
|
|
||||||
|
Searches for the location provided and plots the Lat Long on a map.
|
||||||
|
Note: This is SLOW!!! Be prepared to wait up to a minute for the result"""
|
||||||
|
|
||||||
|
def draw_map(m, scale=1):
|
||||||
|
# draw a shaded-relief image
|
||||||
|
m.shadedrelief(scale=scale)
|
||||||
|
m.fillcontinents(color="#FFDDCC", lake_color='#DDEEFF')
|
||||||
|
m.drawmapboundary(fill_color="#DDEEFF")
|
||||||
|
m.drawcoastlines(color='gray')
|
||||||
|
m.drawcountries(color='gray')
|
||||||
|
m.drawstates(color='gray')
|
||||||
|
|
||||||
|
# lats and longs are returned as a dictionary
|
||||||
|
lats = m.drawparallels(np.linspace(-90, 90, 30))
|
||||||
|
lons = m.drawmeridians(np.linspace(-180, 180, 90))
|
||||||
|
|
||||||
|
# keys contain the plt.Line2D instances
|
||||||
|
lat_lines = chain(*(tup[1][0] for tup in lats.items()))
|
||||||
|
lon_lines = chain(*(tup[1][0] for tup in lons.items()))
|
||||||
|
all_lines = chain(lat_lines, lon_lines)
|
||||||
|
|
||||||
|
# cycle through these lines and set the desired style
|
||||||
|
for line in all_lines:
|
||||||
|
line.set(linestyle='-', alpha=0.3, color='gray')
|
||||||
|
|
||||||
|
def gen_image(loc):
|
||||||
|
lat = loc['lat']
|
||||||
|
lon = loc['lng']
|
||||||
|
plt.figure(figsize=(4, 4))
|
||||||
|
m = Basemap(projection='lcc', width=2E6, height=2E6, resolution='i', lat_0=lat, lon_0=lon)
|
||||||
|
draw_map(m)
|
||||||
|
x, y = m(lon, lat)
|
||||||
|
plt.plot(x, y, 'ok', markersize=5, color='red')
|
||||||
|
plt.text(x, y, f' {location.title()}', fontsize=12, color='red')
|
||||||
|
plt.tight_layout()
|
||||||
|
|
||||||
|
img = BytesIO()
|
||||||
|
plt.savefig(img, format='png', transparent=True)
|
||||||
|
img.seek(0)
|
||||||
|
self.bot.loop.create_task(ctx.send(file=discord.File(img, f'{location} map.png')))
|
||||||
|
self.bot.loop.create_task(ctx.trigger_typing())
|
||||||
|
|
||||||
|
msg = await ctx.send(f'Checking on location data for {location.title()}')
|
||||||
|
async with ctx.typing():
|
||||||
|
async with self.bot.aio_session.get(
|
||||||
|
f'https://api.opencagedata.com/geocode/v1/json?q={location}&key={self.bot.geo_api}') as result:
|
||||||
|
data = await result.json()
|
||||||
|
if data['total_results'] != 0:
|
||||||
|
location_data = data['results'][0]['geometry']
|
||||||
|
await msg.edit(content=f'Got Location. Please wait, Generating the image can take up to a minute.')
|
||||||
|
async with ctx.typing():
|
||||||
|
await self.bot.loop.run_in_executor(self.bot.tpe, gen_image, location_data)
|
||||||
|
await msg.delete()
|
||||||
|
else:
|
||||||
|
await msg.edit(content=f'I can\'t find any data for that location.\nPlease try again.')
|
||||||
|
|
||||||
|
@commands.command(name='help', aliases=['h'])
|
||||||
|
@commands.cooldown(1, 5, commands.BucketType.user)
|
||||||
|
async def custom_help(self, ctx, *, command: str=None):
|
||||||
|
"""This help message"""
|
||||||
|
pag = utils.Paginator(self.bot, embed=True, max_line_length=48)
|
||||||
|
prefixes = await self.bot.get_custom_prefix(self.bot, ctx.message)
|
||||||
|
if isinstance(prefixes, list):
|
||||||
|
prefixes = ', '.join(prefixes)
|
||||||
|
owner = await self.bot.get_user_info(self.bot.owner_id)
|
||||||
|
if command is None:
|
||||||
|
pag.set_embed_meta(title='Geeksbot Help',
|
||||||
|
description=f'For more information about a command please run\n'
|
||||||
|
f'{prefixes.split(",")[0]}help [group] <command>',
|
||||||
|
thumbnail=f'{ctx.guild.me.avatar_url}')
|
||||||
|
pag.add(f"\uFFF6Welcome to Geeksbot's help command.\n"
|
||||||
|
f"< {self.bot.description} >\n\n"
|
||||||
|
f"Below you will find some basic information about me.\n\n"
|
||||||
|
f"Version: <{self.bot.__version__}>\n\n"
|
||||||
|
f"Owner: <Dusty.P>\n"
|
||||||
|
f"> Username: {owner.name}#{owner.discriminator}\n"
|
||||||
|
f"> ID: {owner.id}\n\n"
|
||||||
|
f"Prefixes available for this guild:\n"
|
||||||
|
f"> {prefixes}\n\uFFF7\n\uFFF8")
|
||||||
|
for cog in sorted(self.bot.cogs):
|
||||||
|
for command in sorted(self.bot.get_cog_commands(cog), key=lambda x: x.name):
|
||||||
|
if not command.hidden:
|
||||||
|
pag.add(f'\uFFF6{command.name}')
|
||||||
|
pag.add(f'> {command.short_doc}', truncate=True)
|
||||||
|
try:
|
||||||
|
for com in sorted(command.commands, key=lambda x: x.name):
|
||||||
|
if not com.hidden:
|
||||||
|
pag.add(f'# {com.name}')
|
||||||
|
pag.add(f'> {com.short_doc}', truncate=True)
|
||||||
|
except AttributeError as e:
|
||||||
|
pass
|
||||||
|
pag.add('\uFFF7')
|
||||||
|
pag.add('\uFFF8')
|
||||||
|
else:
|
||||||
|
pag.set_embed_meta(title='Geeksbot Help',
|
||||||
|
thumbnail=f'{ctx.guild.me.avatar_url}')
|
||||||
|
command = command.split(maxsplit=1)
|
||||||
|
if command[0] in self.bot.all_commands:
|
||||||
|
if len(command) > 1 and self.bot.all_commands[command[0]].group:
|
||||||
|
command = self.bot.all_commands[command[0]].all_commands.get(command[1], None)
|
||||||
|
else:
|
||||||
|
command = self.bot.all_commands[command[0]]
|
||||||
|
else:
|
||||||
|
command = None
|
||||||
|
|
||||||
|
if command and not command.hidden:
|
||||||
|
pag.add(f'\uFFF6{command.name}')
|
||||||
|
pag.add(f'Usage: {prefixes.split()[0]}{command.signature}\n')
|
||||||
|
pag.add(f'\uFFF0\n{command.help}')
|
||||||
|
else:
|
||||||
|
pag.add('\uFFF6There is no command by that name.\n>')
|
||||||
|
|
||||||
|
book = utils.Book(pag, (None, ctx.channel, self.bot, ctx.message))
|
||||||
|
await book.create_book()
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot):
|
||||||
bot.add_cog(Utils(bot))
|
bot.add_cog(Utils(bot))
|
||||||
@@ -1,46 +1,46 @@
|
|||||||
import discord
|
import discord
|
||||||
import json
|
import json
|
||||||
from . import utils
|
from src.imports import utils
|
||||||
|
|
||||||
owner_id = 351794468870946827
|
owner_id = 351794468870946827
|
||||||
|
|
||||||
|
|
||||||
def check_admin_role(bot, ctx, member):
|
async def check_admin_role(bot, ctx, member):
|
||||||
admin_roles = json.loads(bot.con.one(f"select admin_roles from guild_config where guild_id = %(id)s",
|
admin_roles = json.loads(await bot.db_con.fetchval(f"select admin_roles from guild_config where guild_id = $1",
|
||||||
{'id': ctx.guild.id}))
|
ctx.guild.id))
|
||||||
for role in admin_roles:
|
for role in admin_roles:
|
||||||
if discord.utils.get(ctx.guild.roles, id=admin_roles[role]) in member.roles:
|
if discord.utils.get(ctx.guild.roles, id=admin_roles[role]) in member.roles:
|
||||||
return True
|
return True
|
||||||
return member.id == ctx.guild.owner.id or member.id == owner_id
|
return member.id == ctx.guild.owner.id or member.id == owner_id
|
||||||
|
|
||||||
|
|
||||||
def check_rcon_role(bot, ctx, member):
|
async def check_rcon_role(bot, ctx, member):
|
||||||
rcon_admin_roles = json.loads(bot.con.one("select rcon_admin_roles from guild_config where guild_id = %(id)s",
|
rcon_admin_roles = json.loads(await bot.db_con.fetchval("select rcon_admin_roles from guild_config "
|
||||||
{'id': ctx.guild.id}))
|
"where guild_id = $1", ctx.guild.id))
|
||||||
for role in rcon_admin_roles:
|
for role in rcon_admin_roles:
|
||||||
if discord.utils.get(ctx.guild.roles, id=rcon_admin_roles[role]) in member.roles:
|
if discord.utils.get(ctx.guild.roles, id=rcon_admin_roles[role]) in member.roles:
|
||||||
return True
|
return True
|
||||||
return member.id == ctx.guild.owner.id or member.id == owner_id
|
return member.id == ctx.guild.owner.id or member.id == owner_id
|
||||||
|
|
||||||
|
|
||||||
def is_admin(bot, ctx):
|
async def is_admin(bot, ctx):
|
||||||
admin_roles = json.loads(bot.con.one("select admin_roles from guild_config where guild_id = %(id)s",
|
admin_roles = json.loads(await bot.db_con.fetchval("select admin_roles from guild_config where guild_id = $1",
|
||||||
{'id': ctx.guild.id}))
|
ctx.guild.id))
|
||||||
for role in admin_roles:
|
for role in admin_roles:
|
||||||
if discord.utils.get(ctx.guild.roles, id=admin_roles[role]) in ctx.message.author.roles:
|
if discord.utils.get(ctx.guild.roles, id=admin_roles[role]) in ctx.message.author.roles:
|
||||||
return True
|
return True
|
||||||
return ctx.message.author.id == ctx.guild.owner.id or ctx.message.author.id == owner_id
|
return ctx.message.author.id == ctx.guild.owner.id or ctx.message.author.id == owner_id
|
||||||
|
|
||||||
|
|
||||||
def is_guild_owner(ctx):
|
async def is_guild_owner(ctx):
|
||||||
if ctx.guild:
|
if ctx.guild:
|
||||||
return ctx.message.author.id == ctx.guild.owner.id or ctx.message.author.id == owner_id
|
return ctx.message.author.id == ctx.guild.owner.id or ctx.message.author.id == owner_id
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def is_rcon_admin(bot, ctx):
|
async def is_rcon_admin(bot, ctx):
|
||||||
rcon_admin_roles = json.loads(bot.con.one("select rcon_admin_roles from guild_config where guild_id = %(id)s",
|
rcon_admin_roles = json.loads(await bot.db_con.fetchval("select rcon_admin_roles from guild_config "
|
||||||
{'id': ctx.guild.id}))
|
"where guild_id = $1", ctx.guild.id))
|
||||||
for role in rcon_admin_roles:
|
for role in rcon_admin_roles:
|
||||||
if discord.utils.get(ctx.guild.roles, id=rcon_admin_roles[role]) in ctx.message.author.roles:
|
if discord.utils.get(ctx.guild.roles, id=rcon_admin_roles[role]) in ctx.message.author.roles:
|
||||||
return True
|
return True
|
||||||
@@ -0,0 +1,449 @@
|
|||||||
|
from io import StringIO
|
||||||
|
import sys
|
||||||
|
import asyncio
|
||||||
|
import discord
|
||||||
|
from discord.ext.commands.formatter import Paginator as DannyPag
|
||||||
|
from src.imports import checks
|
||||||
|
import re
|
||||||
|
import typing
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
async def mute(bot, ctx, admin=0, member_id=None):
|
||||||
|
mute_role = bot.db_con.fetchval(f'select muted_role from guild_config where guild_id = $1', ctx.guild.id)
|
||||||
|
if mute_role:
|
||||||
|
if admin or await checks.is_admin(bot, ctx):
|
||||||
|
if ctx.guild.me.guild_permissions.manage_roles:
|
||||||
|
if member_id:
|
||||||
|
ctx.guild.get_member(member_id).edit(roles=[discord.utils.get(ctx.guild.roles, id=mute_role)])
|
||||||
|
|
||||||
|
|
||||||
|
def to_list_of_str(items, out: list=list(), level=1, recurse=0):
|
||||||
|
# noinspection PyShadowingNames
|
||||||
|
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 format_output(text):
|
||||||
|
if type(text) == list:
|
||||||
|
text = to_list_of_str(text)
|
||||||
|
elif type(text) == dict:
|
||||||
|
text = to_list_of_str(text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def replace_text_ignorecase(in_str: str, old: str, new: str='') -> str:
|
||||||
|
re_replace = re.compile(re.escape(old), re.IGNORECASE)
|
||||||
|
return re_replace.sub(f'{new}', in_str)
|
||||||
|
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
|
||||||
|
class Paginator:
|
||||||
|
def __init__(self,
|
||||||
|
bot: discord.ext.commands.Bot,
|
||||||
|
*,
|
||||||
|
max_chars: int=1970,
|
||||||
|
max_lines: int=20,
|
||||||
|
prefix: str='```md',
|
||||||
|
suffix: str='```',
|
||||||
|
page_break: str='\uFFF8',
|
||||||
|
field_break: str='\uFFF7',
|
||||||
|
field_name_char: str='\uFFF6',
|
||||||
|
inline_char: str='\uFFF5',
|
||||||
|
max_line_length: int=100,
|
||||||
|
embed=False):
|
||||||
|
_max_len = 6000 if embed else 1980
|
||||||
|
assert 0 < max_lines <= max_chars
|
||||||
|
assert 0 < max_line_length < 120
|
||||||
|
|
||||||
|
self._parts = list()
|
||||||
|
self._prefix = prefix
|
||||||
|
self._suffix = suffix
|
||||||
|
self._max_chars = max_chars if max_chars + len(prefix) + len(suffix) + 2 <= _max_len \
|
||||||
|
else _max_len - len(prefix) - len(suffix) - 2
|
||||||
|
self._max_lines = max_lines - (prefix + suffix).count('\n') + 1
|
||||||
|
self._page_break = page_break
|
||||||
|
self._max_line_length = max_line_length
|
||||||
|
self._pages = list()
|
||||||
|
self._max_field_chars = 1014
|
||||||
|
self._max_field_name = 256
|
||||||
|
self._max_description = 2048
|
||||||
|
self._embed = embed
|
||||||
|
self._field_break = field_break
|
||||||
|
self._field_name_char = field_name_char
|
||||||
|
self._inline_char = inline_char
|
||||||
|
self._embed_title = ''
|
||||||
|
self._embed_description = ''
|
||||||
|
self._embed_color = None
|
||||||
|
self._embed_thumbnail = None
|
||||||
|
self._embed_url = None
|
||||||
|
self._bot = bot
|
||||||
|
|
||||||
|
def set_embed_meta(self, title: str='\uFFF0',
|
||||||
|
description: str='\uFFF0',
|
||||||
|
color: discord.Colour=None,
|
||||||
|
thumbnail: str=None,
|
||||||
|
url: str=None):
|
||||||
|
if len(title) <= self._max_field_name:
|
||||||
|
self._embed_title = title
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Provided Title is too long')
|
||||||
|
if len(description) <= self._max_description:
|
||||||
|
self._embed_description = description
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Provided Description is too long')
|
||||||
|
self._embed_color = color
|
||||||
|
self._embed_thumbnail = thumbnail
|
||||||
|
self._embed_url = url
|
||||||
|
|
||||||
|
def pages(self) -> typing.List[str]:
|
||||||
|
_pages = list()
|
||||||
|
_fields = list()
|
||||||
|
_page = ''
|
||||||
|
_lines = 0
|
||||||
|
_field_name = ''
|
||||||
|
_field_value = ''
|
||||||
|
_inline = False
|
||||||
|
|
||||||
|
def open_page():
|
||||||
|
nonlocal _page, _lines, _fields
|
||||||
|
if not self._embed:
|
||||||
|
_page = self._prefix
|
||||||
|
_lines = 0
|
||||||
|
else:
|
||||||
|
_fields = list()
|
||||||
|
|
||||||
|
def close_page():
|
||||||
|
nonlocal _page, _lines, _fields
|
||||||
|
if not self._embed:
|
||||||
|
_page += self._suffix
|
||||||
|
_pages.append(_page)
|
||||||
|
else:
|
||||||
|
if _fields:
|
||||||
|
_pages.append(_fields)
|
||||||
|
open_page()
|
||||||
|
|
||||||
|
open_page()
|
||||||
|
|
||||||
|
if not self._embed:
|
||||||
|
for part in [str(p) for p in self._parts]:
|
||||||
|
if part == self._page_break:
|
||||||
|
close_page()
|
||||||
|
|
||||||
|
new_chars = len(_page) + len(part)
|
||||||
|
|
||||||
|
if new_chars > self._max_chars:
|
||||||
|
close_page()
|
||||||
|
elif (_lines + (part.count('\n') + 1 or 1)) > self._max_lines:
|
||||||
|
close_page()
|
||||||
|
|
||||||
|
_lines += (part.count('\n') + 1 or 1)
|
||||||
|
_page += '\n' + part
|
||||||
|
else:
|
||||||
|
def open_field(name: str):
|
||||||
|
nonlocal _field_value, _field_name
|
||||||
|
_field_name = name
|
||||||
|
_field_value = self._prefix
|
||||||
|
|
||||||
|
def close_field(next_name: str=None):
|
||||||
|
nonlocal _field_name, _field_value, _fields
|
||||||
|
_field_value += self._suffix
|
||||||
|
if _field_value != self._prefix + self._suffix:
|
||||||
|
_fields.append({'name': _field_name, 'value': _field_value, 'inline': _inline})
|
||||||
|
if next_name:
|
||||||
|
open_field(next_name)
|
||||||
|
|
||||||
|
open_field('\uFFF0')
|
||||||
|
|
||||||
|
for part in [str(p) for p in self._parts]:
|
||||||
|
if part == self._page_break:
|
||||||
|
close_page()
|
||||||
|
continue
|
||||||
|
elif part == self._field_break:
|
||||||
|
if len(_fields) + 1 < 25:
|
||||||
|
close_field(next_name='\uFFF0')
|
||||||
|
else:
|
||||||
|
close_field()
|
||||||
|
close_page()
|
||||||
|
continue
|
||||||
|
|
||||||
|
if part.startswith(self._field_name_char):
|
||||||
|
part = part.replace(self._field_name_char, '')
|
||||||
|
if part.startswith(self._inline_char):
|
||||||
|
_inline = True
|
||||||
|
part = part.replace(self._inline_char, '')
|
||||||
|
else:
|
||||||
|
_inline = False
|
||||||
|
if _field_value and _field_value != self._prefix:
|
||||||
|
close_field(part)
|
||||||
|
else:
|
||||||
|
_field_name = part
|
||||||
|
continue
|
||||||
|
|
||||||
|
_field_value += '\n' + part
|
||||||
|
|
||||||
|
close_field()
|
||||||
|
|
||||||
|
close_page()
|
||||||
|
self._pages = _pages
|
||||||
|
return _pages
|
||||||
|
|
||||||
|
def process_pages(self) -> typing.List[str]:
|
||||||
|
_pages = self._pages or self.pages()
|
||||||
|
_len_pages = len(_pages)
|
||||||
|
_len_page_str = len(f'{_len_pages}/{_len_pages}')
|
||||||
|
if not self._embed:
|
||||||
|
for i, page in enumerate(_pages):
|
||||||
|
if len(page) + _len_page_str <= 2000:
|
||||||
|
_pages[i] = f'{i + 1}/{_len_pages}\n{page}'
|
||||||
|
else:
|
||||||
|
for i, page in enumerate(_pages):
|
||||||
|
em = discord.Embed(title=self._embed_title,
|
||||||
|
description=self._embed_description,
|
||||||
|
color=self._bot.embed_color,
|
||||||
|
)
|
||||||
|
if self._embed_thumbnail:
|
||||||
|
em.set_thumbnail(url=self._embed_thumbnail)
|
||||||
|
if self._embed_url:
|
||||||
|
em.url = self._embed_url
|
||||||
|
if self._embed_color:
|
||||||
|
em.color = self._embed_color
|
||||||
|
em.set_footer(text=f'{i + 1}/{_len_pages}')
|
||||||
|
for field in page:
|
||||||
|
em.add_field(name=field['name'], value=field['value'], inline=field['inline'])
|
||||||
|
_pages[i] = em
|
||||||
|
return _pages
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return sum(len(p) for p in self._parts)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
# noinspection PyProtectedMember
|
||||||
|
return self.__class__ == other.__class__ and self._parts == other._parts
|
||||||
|
|
||||||
|
def add_page_break(self, *, to_beginning: bool=False) -> None:
|
||||||
|
self.add(self._page_break, to_beginning=to_beginning)
|
||||||
|
|
||||||
|
def add(self, item: typing.Any, *, to_beginning: bool=False, keep_intact: bool=False, truncate=False) -> None:
|
||||||
|
item = str(item)
|
||||||
|
i = 0
|
||||||
|
if not keep_intact and not item == self._page_break:
|
||||||
|
item_parts = item.strip('\n').split('\n')
|
||||||
|
for part in item_parts:
|
||||||
|
if len(part) > self._max_line_length:
|
||||||
|
if not truncate:
|
||||||
|
length = 0
|
||||||
|
out_str = ''
|
||||||
|
|
||||||
|
def close_line(line):
|
||||||
|
nonlocal i, out_str, length
|
||||||
|
self._parts.insert(i, out_str) if to_beginning else self._parts.append(out_str)
|
||||||
|
i += 1
|
||||||
|
out_str = line + ' '
|
||||||
|
length = len(out_str)
|
||||||
|
|
||||||
|
bits = part.split(' ')
|
||||||
|
for bit in bits:
|
||||||
|
next_len = length + len(bit) + 1
|
||||||
|
if next_len <= self._max_line_length:
|
||||||
|
out_str += bit + ' '
|
||||||
|
length = next_len
|
||||||
|
elif len(bit) > self._max_line_length:
|
||||||
|
if out_str:
|
||||||
|
close_line(line='')
|
||||||
|
for out_str in [bit[i:i + self._max_line_length]
|
||||||
|
for i in range(0, len(bit), self._max_line_length)]:
|
||||||
|
close_line('')
|
||||||
|
else:
|
||||||
|
close_line(bit)
|
||||||
|
close_line('')
|
||||||
|
else:
|
||||||
|
line = f'{part:.{self._max_line_length-3}}...'
|
||||||
|
self._parts.insert(i, line) if to_beginning else self._parts.append(line)
|
||||||
|
else:
|
||||||
|
self._parts.insert(i, part) if to_beginning else self._parts.append(part)
|
||||||
|
i += 1
|
||||||
|
elif keep_intact and not item == self._page_break:
|
||||||
|
if len(item) >= self._max_chars or item.count('\n') > self._max_lines:
|
||||||
|
raise RuntimeError('{item} is too long to keep on a single page and is marked to keep intact.')
|
||||||
|
if to_beginning:
|
||||||
|
self._parts.insert(0, item)
|
||||||
|
else:
|
||||||
|
self._parts.append(item)
|
||||||
|
else:
|
||||||
|
if to_beginning:
|
||||||
|
self._parts.insert(0, item)
|
||||||
|
else:
|
||||||
|
self._parts.append(item)
|
||||||
|
|
||||||
|
|
||||||
|
class Book:
|
||||||
|
def __init__(self, pag: Paginator, ctx: typing.Tuple[typing.Optional[discord.Message],
|
||||||
|
discord.TextChannel,
|
||||||
|
discord.ext.commands.Bot,
|
||||||
|
discord.Message]) -> None:
|
||||||
|
self._pages = pag.process_pages()
|
||||||
|
self._len_pages = len(self._pages)
|
||||||
|
self._current_page = 0
|
||||||
|
self._message, self._channel, self._bot, self._calling_message = ctx
|
||||||
|
self._locked = True
|
||||||
|
if pag == Paginator(self._bot):
|
||||||
|
raise RuntimeError('Cannot create a book out of an empty Paginator.')
|
||||||
|
|
||||||
|
def advance_page(self) -> None:
|
||||||
|
self._current_page += 1
|
||||||
|
if self._current_page >= self._len_pages:
|
||||||
|
self._current_page = 0
|
||||||
|
|
||||||
|
def reverse_page(self) -> None:
|
||||||
|
self._current_page += -1
|
||||||
|
if self._current_page < 0:
|
||||||
|
self._current_page = self._len_pages - 1
|
||||||
|
|
||||||
|
async def display_page(self) -> None:
|
||||||
|
if isinstance(self._pages[self._current_page], discord.Embed):
|
||||||
|
if self._message:
|
||||||
|
await self._message.edit(content=None, embed=self._pages[self._current_page])
|
||||||
|
else:
|
||||||
|
self._message = await self._channel.send(embed=self._pages[self._current_page])
|
||||||
|
else:
|
||||||
|
if self._message:
|
||||||
|
await self._message.edit(content=self._pages[self._current_page], embed=None)
|
||||||
|
else:
|
||||||
|
self._message = await self._channel.send(self._pages[self._current_page])
|
||||||
|
|
||||||
|
async def create_book(self) -> None:
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
|
async def reaction_checker():
|
||||||
|
# noinspection PyShadowingNames
|
||||||
|
def check(reaction, user):
|
||||||
|
if self._locked:
|
||||||
|
return str(reaction.emoji) in self._bot.book_emojis.values() \
|
||||||
|
and user == self._calling_message.author \
|
||||||
|
and reaction.message.id == self._message.id
|
||||||
|
else:
|
||||||
|
return str(reaction.emoji) in self._bot.book_emojis.values() \
|
||||||
|
and reaction.message.id == self._message.id
|
||||||
|
|
||||||
|
await self.display_page()
|
||||||
|
|
||||||
|
if len(self._pages) > 1:
|
||||||
|
for emoji in self._bot.book_emojis.values():
|
||||||
|
try:
|
||||||
|
await self._message.add_reaction(emoji)
|
||||||
|
except (discord.Forbidden, KeyError):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
await self._message.add_reaction(self._bot.book_emojis['unlock'])
|
||||||
|
await self._message.add_reaction(self._bot.book_emojis['close'])
|
||||||
|
except (discord.Forbidden, KeyError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
reaction, user = await self._bot.wait_for('reaction_add', timeout=60, check=check)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
try:
|
||||||
|
await self._message.clear_reactions()
|
||||||
|
except discord.Forbidden:
|
||||||
|
pass
|
||||||
|
raise asyncio.CancelledError
|
||||||
|
else:
|
||||||
|
await self._message.remove_reaction(reaction, user)
|
||||||
|
if str(reaction.emoji) == self._bot.book_emojis['close']:
|
||||||
|
await self._calling_message.delete()
|
||||||
|
await self._message.delete()
|
||||||
|
raise asyncio.CancelledError
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['forward']:
|
||||||
|
self.advance_page()
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['back']:
|
||||||
|
self.reverse_page()
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['end']:
|
||||||
|
self._current_page = self._len_pages - 1
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['start']:
|
||||||
|
self._current_page = 0
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['hash']:
|
||||||
|
m = await self._channel.send(f'Please enter a number in range 1 to {self._len_pages}')
|
||||||
|
|
||||||
|
def num_check(message):
|
||||||
|
if self._locked:
|
||||||
|
return message.content.isdigit() \
|
||||||
|
and 0 < int(message.content) <= self._len_pages \
|
||||||
|
and message.author == self._calling_message.author
|
||||||
|
else:
|
||||||
|
return message.content.isdigit() \
|
||||||
|
and 0 < int(message.content) <= self._len_pages
|
||||||
|
|
||||||
|
try:
|
||||||
|
msg = await self._bot.wait_for('message', timeout=30, check=num_check)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
await m.edit(content='Message Timed out.')
|
||||||
|
else:
|
||||||
|
self._current_page = int(msg.content) - 1
|
||||||
|
try:
|
||||||
|
await m.delete()
|
||||||
|
await msg.delete()
|
||||||
|
except discord.Forbidden:
|
||||||
|
pass
|
||||||
|
elif str(reaction.emoji) == self._bot.book_emojis['unlock']:
|
||||||
|
self._locked = False
|
||||||
|
await self._message.remove_reaction(reaction, self._channel.guild.me)
|
||||||
|
continue
|
||||||
|
await self.display_page()
|
||||||
|
|
||||||
|
self._bot.loop.create_task(reaction_checker())
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import asyncpg
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseConnection:
|
||||||
|
def __init__(self, host: str='localhost', port: int=5432, database: str='', user: str='', password: str=''):
|
||||||
|
if user == '' or password == '' or database == '':
|
||||||
|
raise RuntimeError('Username or Password are blank')
|
||||||
|
self.kwargs = {'host': host, 'port': port, 'database': database, 'user': user, 'password': password}
|
||||||
|
self._conn = None
|
||||||
|
asyncio.get_event_loop().run_until_complete(self.acquire())
|
||||||
|
self.fetchval = self._conn.fetchval
|
||||||
|
self.execute = self._conn.execute
|
||||||
|
self.fetch = self._conn.fetch
|
||||||
|
self.fetchrow = self._conn.fetchrow
|
||||||
|
|
||||||
|
async def acquire(self):
|
||||||
|
if not self._conn:
|
||||||
|
self._conn = await asyncpg.create_pool(**self.kwargs)
|
||||||
|
|
||||||
|
async def close(self):
|
||||||
|
await self._conn.close()
|
||||||
|
self._conn = None
|
||||||
Reference in New Issue
Block a user