diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..15477c7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.env +.venv/ +__pycache__/ \ No newline at end of file diff --git a/.env-example b/.env-example new file mode 100644 index 0000000..47b0cab --- /dev/null +++ b/.env-example @@ -0,0 +1 @@ +DISCORD_TOKEN= diff --git a/.gitignore b/.gitignore index 942f591..67b5e38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -.idea/ -node_modules/ -dist/ -src/config.json \ No newline at end of file +.venv/ +.env +__pycache__/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..57e3876 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.10-slim + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +CMD ["python", "main.py"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8533423 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,6 @@ +services: + conjure_bot: + build: . + restart: unless-stopped + environment: + - DISCORD_TOKEN=${DISCORD_TOKEN} \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..bbe954a --- /dev/null +++ b/main.py @@ -0,0 +1,34 @@ +import os +import discord +from discord import app_commands +from dotenv import load_dotenv + + +load_dotenv() +TOKEN = os.getenv('DISCORD_TOKEN') + +def main(): + class MyBot(discord.Client): + def __init__(self): + intents = discord.Intents.default() + super().__init__(intents=intents) + self.tree = app_commands.CommandTree(self) + + async def setup_hook(self): + # This is the "clean" way for production bots + await self.tree.sync() + + async def on_ready(self): + print(f'Logged in as {self.user} (ID: {self.user.id})') + + bot = MyBot() + + @bot.tree.command(name="ping", description="Check the bot's speed") + async def ping(interaction: discord.Interaction): + # Modern bots use interaction.response instead of ctx.send + await interaction.response.send_message(f'Pong! Latency: {round(bot.latency * 1000)} ms') + + bot.run(TOKEN) + +if __name__ == '__main__': + main() diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index bc41729..0000000 --- a/package-lock.json +++ /dev/null @@ -1,443 +0,0 @@ -{ - "name": "conjurebot", - "version": "0.0.1", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@discordjs/collection": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.5.tgz", - "integrity": "sha512-CU1q0UXQUpFNzNB7gufgoisDHP7n+T3tkqTsp3MNUkVJ5+hS3BCvME8uCXAUFlz+6T2FbTCu75A+yQ7HMKqRKw==" - }, - "@sindresorhus/is": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.0.tgz", - "integrity": "sha512-lXKXfypKo644k4Da4yXkPCrwcvn6SlUW2X2zFbuflKHNjf0w9htru01bo26uMhleMXsDmnZ12eJLdrAZa9MANg==" - }, - "@szmarczak/http-timer": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", - "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", - "requires": { - "defer-to-connect": "^2.0.0" - } - }, - "@types/cacheable-request": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", - "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "*", - "@types/node": "*", - "@types/responselike": "*" - } - }, - "@types/http-cache-semantics": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", - "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==" - }, - "@types/keyv": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", - "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", - "requires": { - "@types/node": "*" - } - }, - "@types/mysql": { - "version": "2.15.9", - "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.9.tgz", - "integrity": "sha512-rB3w3/YEV11oIoL56iP4OPt6uLkcuu6oIqbUy8T2bSm/ZUYN0fvyyzzrZBDNYL//zRStdmSsUPZDtHXjdR1hTA==", - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.0.tgz", - "integrity": "sha512-0ARSQootUG1RljH2HncpsY2TJBfGQIKOOi7kxzUY6z54ePu/ZD+wJA8zI2Q6v8rol2qpG/rvqsReco8zNMPvhQ==" - }, - "@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "requires": { - "@types/node": "*" - } - }, - "@types/ws": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.2.2.tgz", - "integrity": "sha512-oqnI3DbGCVI9zJ/WHdFo3CUE8jQ8CVQDUIKaDtlTcNeT4zs6UCg9Gvk5QrFx2QPkRszpM6yc8o0p4aGjCsTi+w==", - "requires": { - "@types/node": "*" - } - }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" - }, - "cacheable-lookup": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.0.tgz", - "integrity": "sha512-s2piO6LvA7xnL1AR03wuEdSx3BZT3tIJpZ56/lcJwzO/6DTJZlTs7X3lrvPxk6d1PlDe6PrVe2TjlUIZNFglAQ==", - "requires": { - "keyv": "^4.0.0" - } - }, - "cacheable-request": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz", - "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==", - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^2.0.0" - } - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "requires": { - "mimic-response": "^1.0.0" - }, - "dependencies": { - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - } - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "decompress-response": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", - "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", - "requires": { - "mimic-response": "^2.0.0" - } - }, - "defer-to-connect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz", - "integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg==" - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "discord.js": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.0.2.tgz", - "integrity": "sha512-iZiEA4Y61gqq/EjFfLXnkRK9pLapnax/vTVDUhs/mAhyqozAy0GOlk/MZI9rSa1iIoKTWRq6P9CRKhLNT2wUnA==", - "requires": { - "@discordjs/collection": "^0.1.5", - "abort-controller": "^3.0.0", - "form-data": "^3.0.0", - "node-fetch": "^2.6.0", - "prism-media": "^1.2.0", - "setimmediate": "^1.0.5", - "tweetnacl": "^1.0.3", - "ws": "^7.2.1" - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "requires": { - "pump": "^3.0.0" - } - }, - "got": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-10.6.0.tgz", - "integrity": "sha512-3LIdJNTdCFbbJc+h/EH0V5lpNpbJ6Bfwykk21lcQvQsEcrzdi/ltCyQehFHLzJ/ka0UMH4Slg0hkYvAZN9qUDg==", - "requires": { - "@sindresorhus/is": "^2.0.0", - "@szmarczak/http-timer": "^4.0.0", - "@types/cacheable-request": "^6.0.1", - "cacheable-lookup": "^2.0.0", - "cacheable-request": "^7.0.1", - "decompress-response": "^5.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^5.0.0", - "lowercase-keys": "^2.0.0", - "mimic-response": "^2.1.0", - "p-cancelable": "^2.0.0", - "p-event": "^4.0.0", - "responselike": "^2.0.0", - "to-readable-stream": "^2.0.0", - "type-fest": "^0.10.0" - } - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" - }, - "keyv": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.0.tgz", - "integrity": "sha512-U7ioE8AimvRVLfw4LffyOIRhL2xVgmE8T22L6i0BucSnBUyv4w+I7VN/zVZwRKHOI6ZRUcdMdWHQ8KSUvGpEog==", - "requires": { - "json-buffer": "3.0.1" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" - }, - "mime-db": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" - }, - "mime-types": { - "version": "2.1.26", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", - "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", - "requires": { - "mime-db": "1.43.0" - } - }, - "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" - }, - "mysql": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", - "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", - "requires": { - "bignumber.js": "9.0.0", - "readable-stream": "2.3.7", - "safe-buffer": "5.1.2", - "sqlstring": "2.3.1" - } - }, - "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" - }, - "normalize-url": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", - "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "p-cancelable": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", - "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==" - }, - "p-event": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz", - "integrity": "sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==", - "requires": { - "p-timeout": "^2.0.1" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-timeout": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", - "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", - "requires": { - "p-finally": "^1.0.0" - } - }, - "prism-media": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.1.tgz", - "integrity": "sha512-R3EbKwJiYlTvGwcG1DpUt+06DsxOGS5W4AMEHT7oVOjG93MjpdhGX1whHyjnqknylLMupKAsKMEXcTNRbPe6Vw==" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", - "requires": { - "lowercase-keys": "^2.0.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "sqlstring": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", - "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "to-readable-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", - "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==" - }, - "tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "type-fest": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", - "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==" - }, - "typescript": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", - "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "ws": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.2.tgz", - "integrity": "sha512-2qj/tYkDPDSVf7JiHanwEBwkhxi7DchFewIsSnR33MQtG3O/BPAJjqs4g6XEuayuRqIExSQMHZlmyDLbuSrXYw==" - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 4c754c5..0000000 --- a/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "conjurebot", - "version": "0.0.1", - "description": "Discord bot for Conjure", - "scripts": { - "build": "tsc", - "start": "node dist/index.js" - }, - "author": "misabiko", - "license": "ISC", - "dependencies": { - "@types/mysql": "^2.15.9", - "@types/node": "^13.9.0", - "@types/ws": "^7.2.2", - "discord.js": "^12.0.2", - "got": "^10.6.0", - "mysql": "^2.18.1", - "typescript": "^3.8.3" - } -} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..95004ae --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +discord.py +python-dotenv \ No newline at end of file diff --git a/src/Command.ts b/src/Command.ts deleted file mode 100644 index 782ccad..0000000 --- a/src/Command.ts +++ /dev/null @@ -1,94 +0,0 @@ -import {Message} from 'discord.js'; -import {CustomClient} from "./index"; - -export class CommandCollection { - private commands : { [commandName : string] : Command } = {}; - - get(commandName : string, aliased = true) : Command { - let command = this.commands[commandName]; - - if (!command && aliased) - command = Object.values(this.commands).find( - (cmd : Command) => cmd.checkName(commandName) - ) as Command; - - return command; - } - - has(commandName : string, aliased = true) : boolean { - return !!this.get(commandName, aliased); - } - - add(command : Command) { - if (this.commands[command.name]) - return console.error(`Command ${command.name} is already in the collection`); - - this.commands[command.name] = command; - } - - clear(exceptions : Command[]) { - for (const commandName in this.commands) - if (!exceptions.find(cmd => cmd.checkName(commandName))) - delete this.commands[commandName]; - } - - getNames() { - return Object.keys(this.commands); - } -} - -interface Permissions { - users: string[]; - groups: string[]; -} - -export class Command { - name : string; - description? : string; - args? : string[]; - guildOnly? : boolean; - cooldown? : number; - aliases? : string[]; - usage? : string; - permissions? : Permissions; - - constructor( - name : string, - public execute : (message? : Message, args? : string[], client? : CustomClient) => void, - { - description = null as string, - args = null as string[], - guildOnly = false, - cooldown = 0, - aliases = null as string[], - usage = null as string, - permissions = null as Permissions, - } - ) { - this.name = name.toLowerCase(); - this.description = description; - this.args = args; - this.guildOnly = guildOnly; - this.cooldown = cooldown; - this.aliases = aliases; - this.usage = usage; - this.permissions = permissions; - } - - checkName(commandName : string) { - return commandName === this.name || (this.aliases && this.aliases.includes(commandName)); - } - - checkPermission(userId : string) : boolean { - if (!this.permissions) return true; - - if (this.permissions.users.includes(userId)) - return true; - - for (const group of this.permissions.groups) - if (group.includes(userId)) - return true; - - return false; - } -} \ No newline at end of file diff --git a/src/commands/addcrowduser.ts b/src/commands/addcrowduser.ts deleted file mode 100644 index 93fe5ae..0000000 --- a/src/commands/addcrowduser.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {Command} from "../Command"; -import got from 'got'; - -const {userDict, crowd, groupDict} = require("../config.json"); - -const addcrowduser = new Command( - 'addcrowduser', - async (message, args) => { - const email = args[0]; - const firstName = args[1]; - const lastName = args.splice(2).join(' '); - const firstNameLetter = firstName[0].toLowerCase(); - const lastNameLowercase = lastName.toLowerCase().replace(/\s/g, '');; - - const username = firstNameLetter + lastNameLowercase; - const password = lastNameLowercase + firstNameLetter; - - try { - await got.post("https://conjure.etsmtl.ca/crowd/rest/usermanagement/1/user", { - responseType: 'json', - username: crowd.username, - password: crowd.password, - headers: { - Accept: 'application/json' - }, - json: { - "name": username, - "password": { - "value": password - }, - "active": true, - "email": email, - "first-name": firstName, - "last-name": lastName - } - }); - } catch (error) { - console.error(error.response.body); - message.channel.send("Couldn't add the new member."); - return; - } - - try { - await got.post("https://conjure.etsmtl.ca/crowd/rest/usermanagement/1/user/group/direct", { - responseType: 'json', - username: crowd.username, - password: crowd.password, - headers: { - Accept: 'application/json' - }, - json: { - name: 'conjure-member' - }, - searchParams: new URLSearchParams([ - ['username', username] - ]) - }); - } catch (error) { - console.error(error.response.body); - message.channel.send("Couldn't add the user to conjure-member."); - return; - } - - message.channel.send(`Member added.\nUsername: ${username}\nPassword: ${password}`); - }, { - description: "Adds a member to Crowd.", - permissions: { - users: [], - groups: [groupDict.admin] - }, - args: ['email', 'first name', 'last name'] - } -); -export default addcrowduser; \ No newline at end of file diff --git a/src/commands/echo.ts b/src/commands/echo.ts deleted file mode 100644 index 2277b65..0000000 --- a/src/commands/echo.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {Command} from "../Command"; - -const echo = new Command( - 'echo', - (message, args) => { - message.channel.send(args.join(' ')); - }, - { - description: "Echo's the arguments as a message" - } -); -export default echo; \ No newline at end of file diff --git a/src/commands/echolog.ts b/src/commands/echolog.ts deleted file mode 100644 index fedc1ff..0000000 --- a/src/commands/echolog.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {Command} from "../Command"; - -const echolog = new Command( - 'echolog', - (message, args) => { - console.log("Echolog:"); - for (const arg of args) - console.log(arg); - }, - { - description: "Echo's the arguments on the console" - }); -export default echolog; \ No newline at end of file diff --git a/src/commands/help.ts b/src/commands/help.ts deleted file mode 100644 index e06339f..0000000 --- a/src/commands/help.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {Command} from "../Command"; -import {CustomClient} from "../index"; - -const {prefix} = require("../config.json"); - -const help = new Command( - 'help', - (message, args) => { - const data = []; - const {commandCollection} = message.client as CustomClient; - - if (!args.length) { - data.push("Here's a list of the commands:"); - data.push(commandCollection.getNames().join(", ")); - data.push(`\nSend \`${prefix}help [command name]\` for info on a specific command.`); - - return message.channel.send(data, {split: true}); - } - - const name = args[0].toLowerCase(); - const command = commandCollection.get(name); - - if (!command) - return message.reply(`${name} isn't not a valid command, call ${prefix}help for the list of available commands.`); - - data.push(`**Name:** ${command.name}`); - - if (command.aliases) data.push(`**Aliases:** ${command.aliases.join(', ')}`); - if (command.description) data.push(`**Description:** ${command.description}`); - if (command.usage) data.push(`**Usage:** ${prefix}${command.name} ${command.usage}`); - - data.push(`**Cooldown:** ${command.cooldown || 1} second(s)`); - - message.channel.send(data, {split: true}); - }, - { - description: "List every commands or info about a specific command.", - aliases: ["commands"], - usage: "[command name]" - } -); -export default help; \ No newline at end of file diff --git a/src/commands/listdiscordusers.ts b/src/commands/listdiscordusers.ts deleted file mode 100644 index b6ed19f..0000000 --- a/src/commands/listdiscordusers.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {Command} from "../Command"; -import { TextChannel } from "discord.js"; -import * as mysql from 'mysql'; - -const {userDict, channels, mysql: mysqlCreds, groupDict} = require("../config.json"); - -const listdiscordusers = new Command( - 'listdiscordusers', - async (message, args, client) => { - const general : TextChannel = await client.channels.fetch(channels.general) as TextChannel; - const members = new Set(general.members.array().map(user => `${user.user.username}#${user.user.discriminator}`)); - let dbDiscords; - - const connection = mysql.createConnection({ - host: 'localhost', - database: 'conjure', - user: mysqlCreds.username, - password: mysqlCreds.password - }); - - connection.connect(); - - try { - connection.query('select * from contactDiscord where discord is not null', function (error : any, results : any, fields : any) { - if (error) throw error; - - dbDiscords = new Set(results.map((row : any) => row.discord)); - - for (const member of members.values()) - if (dbDiscords.has(member)) - members.delete(member); - - console.dir(members); - message.channel.send(Array.from(members)); - }); - - connection.end(); - } catch (error) { - console.error(error); - message.channel.send("Couldn't query to database."); - return; - } - }, { - description: "Lists discord missing from database.", - permissions: { - users: [], - groups: [groupDict.admin] - } - } -); -export default listdiscordusers; \ No newline at end of file diff --git a/src/commands/reloadcommand.ts b/src/commands/reloadcommand.ts deleted file mode 100644 index dc29271..0000000 --- a/src/commands/reloadcommand.ts +++ /dev/null @@ -1,61 +0,0 @@ -import * as fs from "fs"; -import * as path from "path"; -import {Message} from "discord.js"; -import {Command} from "../Command"; -import {CustomClient} from "../index"; - -const {userDict} = require("../config.json"); - -const reloadcommand = new Command( - 'reloadcommand', - async (message, args, client) => { - if (args.length) - await reloadSingleCommand(args[0].toLowerCase(), client, message); - else - await reloadCommands(client, message); - }, { - description: "Reloads either every, or a given command module.", - aliases: ["reload"], - usage: "[commandName]", - permissions: { - users: [userDict.misabiko], - groups: [] - } - } -); -export default reloadcommand; - -async function reloadSingleCommand(commandName : string, client : CustomClient, message : Message) { - const {commandCollection} = client; - - if (commandName === 'reloadcommand') - return message.channel.send("You have to restart the bot to reload this command."); - - if (!commandCollection.has(commandName)) - return message.channel.send(`The ${commandName} command doesn't exist.`); - - if (await client.importCommand(`./${commandName}.js`, message)) - await message.channel.send(`Successfully reloaded the ${commandName} command.`); - else - await message.channel.send(`Failed to reload the ${commandName} command.`); -} - -async function reloadCommands(client : CustomClient, message : Message) { - const {commandCollection} = client; - - commandCollection.clear([ - commandCollection.get('reloadcommand') - ]); - - const commandFiles = fs.readdirSync(__dirname).filter(file => file.endsWith(".js")); - - let hadErrors = false; - for (const file of commandFiles) - if (file !== "reloadcommand.js") - hadErrors = hadErrors || !(await client.importCommand(path.join(__dirname, file), message)); - - if (hadErrors) - await message.channel.send(`Failed to reload some commands.`); - else - await message.channel.send(`Successfully reloaded the commands.`); -} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 6cd3978..0000000 --- a/src/index.ts +++ /dev/null @@ -1,108 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs'; -import * as Discord from "discord.js"; -import {Message, Snowflake} from "discord.js"; -import {Command, CommandCollection} from "./Command"; -import {prefix, token, userDict} from "./config.json"; - -export class CustomClient extends Discord.Client { - commandCollection = new CommandCollection(); - cooldowns : { [name : string] : Discord.Collection } = {}; - prefix = prefix; - - async importCommand(commandPath : string, message? : Message) : Promise { - try { - this.commandCollection.add((await import(commandPath)).default); - }catch(error) { - const errorMessage = "Error while importing command " + commandPath; - console.error(errorMessage); - console.error(error); - - if (message) - await message.reply(errorMessage); - else { - const user = await this.users.fetch(userDict.misabiko); - await user.send(errorMessage); - } - - return false; - } - - return true; - } - - handleMessage(message : Message) { - //If message doesn't have prefix or is bot-made, ignore - if (!message.content.startsWith(prefix) || message.author.bot) return; - - const args = message.content.slice(prefix.length).split(/ +/); - const commandName = args.shift().toLowerCase(); - - const command = client.commandCollection.get(commandName); - if (!command) return; - - if (command.args && !args.length) { - let reply = `You didn't provide any arguments, ${message.author}.`; - - if (command.usage) - reply += `\nUsage: \`${prefix}${command.name} ${command.usage}\``; - - return message.channel.send(reply); - } - - if (command.guildOnly && message.channel.type !== 'text') - return message.reply(`You can only call the ${command} commmand on a server.`); - - if (!command.checkPermission(message.author.id)) - return message.reply(`You don't have the permission for that command, ask <@${userDict.misabiko}> for help.`); - - if (!this.cooldowns[command.name]) - this.cooldowns[command.name] = new Discord.Collection(); - - const timeLeft = this.getTimeLeft(command, message.author.id); - if (timeLeft) - return message.reply(`Please wait ${timeLeft.toFixed(1)} more second(s) before reusing the \`${command.name}\` command.`); - - try { - command.execute(message, args, client); - }catch (error) { - console.error(error); - message.reply("There was an error trying to execute the command."); - } - } - - getTimeLeft(command : Command, authorId : string) { - const now = Date.now(); - const timestamps : Discord.Collection = this.cooldowns[command.name]; - const cooldownAmount = command.cooldown * 1000; - - if (!timestamps.has(authorId)) { - timestamps.set(authorId, now); - setTimeout(() => timestamps.delete(authorId), cooldownAmount); - }else { - const expirationTime = timestamps.get(authorId) + cooldownAmount; - - if (now < expirationTime) - return (expirationTime - now) / 1000; - - timestamps.set(authorId, now); - setTimeout(() => timestamps.delete(authorId), cooldownAmount); - } - } - - getCommand(message : string) { - return message.substring(this.prefix.length); - } -} - -const client = new CustomClient(); -const commandFiles = fs.readdirSync(path.join(__dirname, "commands")).filter((file : string) => file.endsWith(".js")); - -for (const file of commandFiles) - client.importCommand(path.join(__dirname, "commands", file)).then(); - -client.on("message", message => client.handleMessage(message as Message)); - -client.on("ready", () => console.log("Ready!")); - -client.login(token).then(() => console.log("ConjureBot logged in!")); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index dc6b129..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "sourceMap": true, - "noImplicitAny": true, - "noImplicitUseStrict": true, - "resolveJsonModule": true, - "moduleResolution": "node", - "outDir": "dist", - "rootDir": "src", - "module": "commonjs" - }, - "include": [ - "src/*.ts", - "src/commands/*.ts", - "src/config.json" - ] -} \ No newline at end of file