From 19e8e0b3882f82604a1bcae8735de573876cf320 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Wed, 2 Jun 2021 11:55:54 +0530 Subject: [PATCH 01/24] feat: Display the look of online players - Display look of online players using the CFM API - Remove badge image because the service is no longer maintained --- src/bots/cmd_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bots/cmd_handler.py b/src/bots/cmd_handler.py index 5720ee0..c8da21c 100644 --- a/src/bots/cmd_handler.py +++ b/src/bots/cmd_handler.py @@ -273,6 +273,6 @@ async def profile(args, msg, client): )} ] - embed["image"] = { "url": "http://santanl.000webhostapp.com/badges.php?row_max=18&badges={}".format(",".join([str(x) for x in tfm_profile.badges.keys()])) } + embed["thumbnail"] = { "url": "https://cheese.formice.com/api/dressroom/mouse/{}".format(tfm_profile.look) } await msg.reply(embed = Embed.from_dict(embed)) From 0087d0ec2c898155a8e8b8f390037bea58c9f9cb Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Wed, 2 Jun 2021 11:39:20 +0000 Subject: [PATCH 02/24] chore: Remove look as SVG are not supported --- src/bots/cmd_handler.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bots/cmd_handler.py b/src/bots/cmd_handler.py index c8da21c..f5a83bb 100644 --- a/src/bots/cmd_handler.py +++ b/src/bots/cmd_handler.py @@ -4,6 +4,7 @@ import requests import asyncio import json +import urllib from bots import translations @@ -272,7 +273,4 @@ async def profile(args, msg, client): tfm_profile.stats.divineModeSaves )} ] - - embed["thumbnail"] = { "url": "https://cheese.formice.com/api/dressroom/mouse/{}".format(tfm_profile.look) } - await msg.reply(embed = Embed.from_dict(embed)) From dc8499bff25a822f170a3395e730bebf1d5e885e Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Thu, 1 Jul 2021 07:53:55 +0000 Subject: [PATCH 03/24] chore: Temporary mafia game additions --- src/bots/Discord.py | 4 ++++ src/data.py | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bots/Discord.py b/src/bots/Discord.py index 9c16f3b..a29c52a 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -39,6 +39,10 @@ async def on_ready(self): self.mod_data = json.loads(self.mod_data.content[7:-3]) async def on_message(self, message): + + if (str(message.channel.id) == os.getenv("GRAVEYARD")) and (self.main_guild.get_role(data["roles"]["mafia_dead"]) in message.author.roles): + await self.get_channel(int(os.getenv("MEDIUM_CHAT"))).send(":speaking_head: **[**<@{}>**]** `{}`".format(message.author.id, message.content)) + if message.content.startswith(">"): content = re.match(r"^>\s*(.+)", message.content).group(1) args = re.split(r"\s+", content) diff --git a/src/data.py b/src/data.py index 77cabc8..181d131 100644 --- a/src/data.py +++ b/src/data.py @@ -12,7 +12,8 @@ "mod": 831316968660795403, "cmder": 702120436279934996, "verified": 677396391189807104, - "member": 678097505975533599 + "member": 678097505975533599, + "mafia_dead": 847742079177719828 }, "ranks": { "Passer-by": 571736272163438650, From 99e5345282d7ee9a6a533c44629afa2c2efae59a Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Sun, 4 Jul 2021 08:12:22 +0000 Subject: [PATCH 04/24] chore: Support periodic tasks - Qotd - Birthdays --- src/bots/Discord.py | 18 ++++++++++++++++++ src/bots/cmd_handler.py | 21 +++++++++++++++++++++ src/data.py | 8 ++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/bots/Discord.py b/src/bots/Discord.py index 9c16f3b..9332c5c 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -4,6 +4,8 @@ import utils import json import requests +import asyncio +from datetime import datetime, timedelta from data import data from bots.cmd_handler import commands @@ -38,6 +40,9 @@ async def on_ready(self): self.mod_data = await self.data_channel.fetch_message(data["data"]["mod"]) self.mod_data = json.loads(self.mod_data.content[7:-3]) + await self.start_period_tasks() + + async def on_message(self, message): if message.content.startswith(">"): content = re.match(r"^>\s*(.+)", message.content).group(1) @@ -163,6 +168,19 @@ async def update_mod_data(self): ``` """.format(json.dumps(self.mod_data))) + async def start_period_tasks(self): + print("[INFO] Checking for periodic tasks...") + # check qotd + await commands["qotd"]["f"](["ask"], None, self) + # other daily tasks + last_daily_data = await self.data_channel.fetch_message(data["data"]["daily"]) + now = datetime.now() + if now > datetime.fromtimestamp(float(last_daily_data.content)) + timedelta(days=1): + await commands["bday"]["f"]([], None, self) + await last_daily_data.edit(content=now.timestamp()) + await asyncio.sleep(1 * 60 * 5) + await self.start_period_tasks() + def search_member(self, name, deep_check=False): if member := self.main_guild.get_member_named(utils.get_discord_nick_format(name)): return member diff --git a/src/bots/cmd_handler.py b/src/bots/cmd_handler.py index f5a83bb..74fefe4 100644 --- a/src/bots/cmd_handler.py +++ b/src/bots/cmd_handler.py @@ -5,6 +5,7 @@ import asyncio import json import urllib +from datetime import datetime from bots import translations @@ -274,3 +275,23 @@ async def profile(args, msg, client): )} ] await msg.reply(embed = Embed.from_dict(embed)) + +@command(discord=True) +async def bday(args, msg, client): + channel = client.main_guild.get_channel(data["channels"]["bday"]) + raw_data = "" + for msg_id in data["data"]["bday"]: + message = await channel.fetch_message(msg_id) + raw_data += message.content + raw_data = re.sub("`", "", raw_data)[20:-86] + today = datetime.now().strftime("%-d %B") + bdays = re.findall("{} - (.+)\n".format(today), raw_data) + if msg is None and len(args) == 0: return + method = msg.reply if msg else client.main_guild.get_channel(data["channels"]["admin"]).send + await method(embed = Embed.from_dict({ + "title": "Today's birthdays :tada:", + "color": 0xccdd33, + "description": "No birthdays today ;c" if len(bdays) == 0 else "• {}".format("\n• ".join(bdays)), + "timestamp": datetime.now().isoformat() + })) + \ No newline at end of file diff --git a/src/data.py b/src/data.py index 77cabc8..6ebb5dc 100644 --- a/src/data.py +++ b/src/data.py @@ -5,7 +5,9 @@ "tribe_chat": 671247476782661632, "lobby": 678770711791140875, "data": 718723565167575061, - "qotd": 626192940364202004 + "qotd": 626192940364202004, + "bday": 592742600058994688, + "admin": 592341953547337739 }, "roles": { "admin": 655909026101723147, @@ -44,6 +46,8 @@ "data": { "ccmds": 718746213385502772, "qotd": 718728423475904562, - "mod": 718747955557040158 + "mod": 718747955557040158, + "daily": 719816851781058670, + "bday": [ 592742900509704205, 592743169863581713 ] } } From 5a3594dcc858d6607c8e1d98964cad887c32a964 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Mon, 5 Jul 2021 08:37:04 +0000 Subject: [PATCH 05/24] feat: Automate daily tribe stats - Add >stats command to check tribe stats - Post stats daily - Ping with Qotd --- src/bots/Discord.py | 6 +++++- src/bots/cmd_handler.py | 29 ++++++++++++++++++++++++++++- src/bots/commands/qotd.py | 2 +- src/data.py | 3 ++- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/bots/Discord.py b/src/bots/Discord.py index 431ea5e..3981ffd 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -180,7 +180,11 @@ async def start_period_tasks(self): last_daily_data = await self.data_channel.fetch_message(data["data"]["daily"]) now = datetime.now() if now > datetime.fromtimestamp(float(last_daily_data.content)) + timedelta(days=1): - await commands["bday"]["f"]([], None, self) + for task in (("bday", []), ("stats", [])): + try: + await commands[task[0]]["f"](task[1], None, self) + except Exception: + pass await last_daily_data.edit(content=now.timestamp()) await asyncio.sleep(1 * 60 * 5) await self.start_period_tasks() diff --git a/src/bots/cmd_handler.py b/src/bots/cmd_handler.py index 74fefe4..450636b 100644 --- a/src/bots/cmd_handler.py +++ b/src/bots/cmd_handler.py @@ -4,7 +4,6 @@ import requests import asyncio import json -import urllib from datetime import datetime from bots import translations @@ -294,4 +293,32 @@ async def bday(args, msg, client): "description": "No birthdays today ;c" if len(bdays) == 0 else "• {}".format("\n• ".join(bdays)), "timestamp": datetime.now().isoformat() })) + +@command(discord=True) +async def stats(args, msg, client): + res = json.loads(requests.get("https://cheese.formice.com/api/tribes/A%20Place%20to%20Call%20Home").text) + method = msg.reply if msg else client.main_guild.get_channel(data["channels"]["stats"]).send + await method(content = + """:calendar_spiral: **Daily tribe stats `[{}]` <:tribehouse:689470787950084154> **\n> ┗ :medal: **Position:** `{}` + > + > :person_running: **Rounds: ** `{}` + > <:cheese:691158951563362314> **Cheese:** `{}` + > <:p7:836550194380275742> **Firsts:** `{}` + > <:bootcamp:836550195683917834> **Bootcamp:** `{}` + > + > <:shaman:836550192387850251> **Gathered cheese/Normal/Hard/Divine: [** `{}`/`{}`/`{}`/`{}` **]** + """.format( + datetime.now().strftime("%d/%m/%y"), + res["position"], + res["stats"]["normal"]["rounds"], + res["stats"]["normal"]["cheese"], + res["stats"]["normal"]["first"], + res["stats"]["normal"]["bootcamp"], + res["stats"]["shaman"]["cheese"], + res["stats"]["shaman"]["saves_normal"], + res["stats"]["shaman"]["saves_hard"], + res["stats"]["shaman"]["saves_divine"] + )) + + \ No newline at end of file diff --git a/src/bots/commands/qotd.py b/src/bots/commands/qotd.py index f21c702..051782a 100644 --- a/src/bots/commands/qotd.py +++ b/src/bots/commands/qotd.py @@ -38,7 +38,7 @@ async def ask(args, msg, client): qotd_channel = client.get_channel(data["channels"]["qotd"]) if force or cooldown_over: if len(client.questions["questions"]) > 0: - await qotd_channel.send(embed = Embed.from_dict({ + await qotd_channel.send(content = "<@&742418187198660719>", embed = Embed.from_dict({ "title": "QOTD #{}".format(client.questions["index"]), "description": client.questions["questions"].pop(0), "color": 0x2987ba diff --git a/src/data.py b/src/data.py index 4320b52..4f198b6 100644 --- a/src/data.py +++ b/src/data.py @@ -7,7 +7,8 @@ "data": 718723565167575061, "qotd": 626192940364202004, "bday": 592742600058994688, - "admin": 592341953547337739 + "admin": 592341953547337739, + "stats": 575328568008114176 }, "roles": { "admin": 655909026101723147, From 677d6ba4095dc039fb7a492e23edb751c03c9c14 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Mon, 5 Jul 2021 08:52:34 +0000 Subject: [PATCH 06/24] chore: Bring back FACTS ON DEMAND!! --- src/bots/Discord.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bots/Discord.py b/src/bots/Discord.py index 3981ffd..8eab680 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -5,6 +5,7 @@ import json import requests import asyncio +import random from datetime import datetime, timedelta from data import data @@ -44,7 +45,8 @@ async def on_ready(self): async def on_message(self, message): - + + # temporary code if (str(message.channel.id) == os.getenv("GRAVEYARD")) and (self.main_guild.get_role(data["roles"]["mafia_dead"]) in message.author.roles): await self.get_channel(int(os.getenv("MEDIUM_CHAT"))).send(":speaking_head: **[**<@{}>**]** `{}`".format(message.author.id, message.content)) @@ -99,6 +101,18 @@ async def on_message(self, message): await message.reply(embed = discord.Embed.from_dict(res)) + elif self.user in message.mentions: + fact = requests.get("https://uselessfacts.jsph.pl/random.md?language=en", headers = { "User-Agent": "Seniru" }).text + await message.reply(embed = discord.Embed.from_dict({ + "title": "{}! Wanna hear a fact? :bulb:".format(random.choice([ + "Hi", "Hello", "Howdy", "Hola", "Yo", "Wassup", "Hola", "Namasthe", "Hi there", "Greetings", + "What's going on", "How's everything", "Good to see you", "Great to see you", "Nice to see you", + "Saluton", "What's new", "How are you feeling today","Hey there" + ])), + "description": fact, + "color": 0x2987ba + })) + async def on_member_join(self, member): error = False try: From 1031539982dee215da4d4e35a3a04a7f9909f571 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Mon, 5 Jul 2021 09:05:11 +0000 Subject: [PATCH 07/24] feat: Add room command --- src/bots/cmd_handler.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bots/cmd_handler.py b/src/bots/cmd_handler.py index 450636b..b0e43dc 100644 --- a/src/bots/cmd_handler.py +++ b/src/bots/cmd_handler.py @@ -69,6 +69,15 @@ async def restart(args, msg, client): await msg.reply(":hourglass_flowing_sand: | Restarting...") sys.exit("Restart") +@command(discord=True, allowed_roles = [data["roles"]["admin"]] ) +async def room(args, msg, client): + try: + await client.tfm.joinRoom(" ".join(args)) + room = await client.tfm.wait_for("on_joined_room", timeout=4) + await msg.reply(":white_check_mark: | Joined the room (name: `{}` | community: `{}`)".format(room.name, room.community)) + except Exception as e: + await msg.reply(f":x: | {e}") + @command(tfm=True, whisper_command=True) async def inv(args, msg, client): await client.recruit(msg.author.username) From 2426f99aded6faba445f687f23f80d1abcf13c15 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Mon, 5 Jul 2021 11:13:42 +0000 Subject: [PATCH 08/24] feat: Add colors to embed based on tfm roles --- src/bots/cmd_handler.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bots/cmd_handler.py b/src/bots/cmd_handler.py index b0e43dc..6d2c236 100644 --- a/src/bots/cmd_handler.py +++ b/src/bots/cmd_handler.py @@ -282,6 +282,10 @@ async def profile(args, msg, client): tfm_profile.stats.divineModeSaves )} ] + roles = json.loads(requests.get(f"https://cheese.formice.com/api/players/{fName}-{disc}").text)["tfm_roles"] + embed["color"] = ({ + "admin": 0xEB1D51, "mod": 0xBABD2F, "sentinel": 0x2ECF73, "mapcrew": 0x2F7FCC, "module": 0x95D9D6, "funcorp": 0xF89F4B + }).get(roles[0] if roles else ("admin" if disc == "0001" else 0), 0x009D9D) await msg.reply(embed = Embed.from_dict(embed)) @command(discord=True) From cdfb7df8b706dc4e6520cba368d58c98a42692c7 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Mon, 5 Jul 2021 12:08:27 +0000 Subject: [PATCH 09/24] fix: Stop sending facts for replies - It's cringe --- src/bots/Discord.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bots/Discord.py b/src/bots/Discord.py index 8eab680..bb91632 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -101,7 +101,7 @@ async def on_message(self, message): await message.reply(embed = discord.Embed.from_dict(res)) - elif self.user in message.mentions: + elif self.user.id in message.raw_mentions: fact = requests.get("https://uselessfacts.jsph.pl/random.md?language=en", headers = { "User-Agent": "Seniru" }).text await message.reply(embed = discord.Embed.from_dict({ "title": "{}! Wanna hear a fact? :bulb:".format(random.choice([ From 08957ccacb5f18ecd41f597d793ae37b56d375a6 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Mon, 12 Jul 2021 11:49:17 +0000 Subject: [PATCH 10/24] chore: Bring back setmsg - Bring back setmsg - Fix breaking the argument list when there is a newline to commands - Remoe a cringe login message --- src/bots/Discord.py | 15 ++++++++------- src/bots/Transformice.py | 8 ++++---- src/bots/cmd_handler.py | 22 ++++++++++++++++------ src/data.py | 1 + 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/bots/Discord.py b/src/bots/Discord.py index bb91632..fe7f0e8 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -1,14 +1,15 @@ -import re -import discord -import os -import utils -import json -import requests import asyncio +import json +import os import random +import re from datetime import datetime, timedelta +import discord +import requests +import utils from data import data + from bots.cmd_handler import commands WANDBOX_ENDPOINT = "https://wandbox.org/api" @@ -51,7 +52,7 @@ async def on_message(self, message): await self.get_channel(int(os.getenv("MEDIUM_CHAT"))).send(":speaking_head: **[**<@{}>**]** `{}`".format(message.author.id, message.content)) if message.content.startswith(">"): - content = re.match(r"^>\s*(.+)", message.content).group(1) + content = re.match(r"^>\s*((.|\n)*)", message.content).group(1) args = re.split(r"\s+", content) if args[0] in commands and commands[args[0]]["discord"]: diff --git a/src/bots/Transformice.py b/src/bots/Transformice.py index d10e04d..12c3b22 100644 --- a/src/bots/Transformice.py +++ b/src/bots/Transformice.py @@ -1,15 +1,16 @@ -import aiotfm import asyncio import json import os import re +import aiotfm import data import utils from bots.cmd_handler import commands from bots.commands.mod import kick + class Transformice(aiotfm.Client): def __init__(self, name, password, loop, discord, community=0): super().__init__(community, True, True, loop) @@ -61,7 +62,7 @@ def run(self, block=True): async def on_login_ready(self, online_players, community, country): print(f"[INFO][TFM] Login Ready [{community}-{country}]") - await self.login(self.name, self.password, encrypted=False, room="*#castle") + await self.login(self.name, self.password, encrypted=False, room="*#bolodefchoco") async def on_logged(self, player_id, username, played_time, community, pid): self.pid = pid @@ -74,7 +75,6 @@ async def on_ready(self): "Beep boop! [>.<]", "Howdy or smth.", "Imagine being a bot in a rat game lol", - "Hey why, thanks :P", "Saluton mundo!", "Hello world!" ])) @@ -93,7 +93,7 @@ async def on_tribe_member_get_role(self, setter, target, role): async def on_tribe_new_member(self, name): name = utils.normalize_name(name) - await self.discord.get_channel(data.data["channels"]["tribe_chat"]).send("> {} just joined the tribe!.".format(utils.normalize_name(name))) + await self.discord.get_channel(data.data["channels"]["tribe_chat"]).send("> {} just joined the tribe!".format(utils.normalize_name(name))) if self.discord.mod_data["blacklist"].get(name): await kick([name], None, self.discord) # passing self.discord is just a hacky approach here return await self.sendTribeMessage(f"{name} is in the blacklist, please do not invite them again!") diff --git a/src/bots/cmd_handler.py b/src/bots/cmd_handler.py index 6d2c236..5d58d39 100644 --- a/src/bots/cmd_handler.py +++ b/src/bots/cmd_handler.py @@ -1,16 +1,16 @@ -import functools -import utils -import re -import requests import asyncio +import functools import json +import re from datetime import datetime -from bots import translations - +import requests +import utils +from aiotfm import Packet from data import data from discord import Embed +from bots import translations commands = {} @@ -41,6 +41,7 @@ def wrapper(*args, **kwargs): from .commands import qotd as qhandler + @command(discord = True, allowed_roles = [ data["roles"]["admin"] ]) async def qotd(args, msg, client): if len(args) > 0: @@ -78,6 +79,15 @@ async def room(args, msg, client): except Exception as e: await msg.reply(f":x: | {e}") +@command(discord=True, allowed_roles = [ data["roles"]["admin"], data["roles"]["event"] ]) +async def setmsg(args, msg, client): + try: + await client.tfm.sendCP(98, Packet().writeUTF(" ".join(args))) + await client.tfm.wait_for("on_raw_cp", lambda tc, packet: tc == 125, 2) + await msg.reply(":white_check_mark: | Changed the message!") + except Exception as e: + await msg.reply(f":x: | Failed to change the message (Error: `{e}`)") + @command(tfm=True, whisper_command=True) async def inv(args, msg, client): await client.recruit(msg.author.username) diff --git a/src/data.py b/src/data.py index 4f198b6..53920ce 100644 --- a/src/data.py +++ b/src/data.py @@ -13,6 +13,7 @@ "roles": { "admin": 655909026101723147, "mod": 831316968660795403, + "event": 831875623118045251, "cmder": 702120436279934996, "verified": 677396391189807104, "member": 678097505975533599, From e81f8cf58b4be3a1039b66428fb501f6d1b0b902 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Mon, 12 Jul 2021 11:56:06 +0000 Subject: [PATCH 11/24] feat: Notify when daily task fails --- src/bots/Discord.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bots/Discord.py b/src/bots/Discord.py index fe7f0e8..c47b8ba 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -198,8 +198,10 @@ async def start_period_tasks(self): for task in (("bday", []), ("stats", [])): try: await commands[task[0]]["f"](task[1], None, self) - except Exception: - pass + except Exception as e: + await self.main_guild.get_channel(data["data"]["channels"]["admin"]).send( + "<@!522972601488900097> [DAILY TASK FAILURE|{}] `{}`\n```\n{}```" + .format(task[0], e, e.with_traceback())) await last_daily_data.edit(content=now.timestamp()) await asyncio.sleep(1 * 60 * 5) await self.start_period_tasks() From 120b5fb90911116155b0e07b6b08bdcef979daff Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Tue, 13 Jul 2021 06:03:11 +0000 Subject: [PATCH 12/24] chore: Add warn and rwarn commands back --- src/bots/cmd_handler.py | 2 ++ src/bots/commands/mod.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/bots/cmd_handler.py b/src/bots/cmd_handler.py index 5d58d39..81ee194 100644 --- a/src/bots/cmd_handler.py +++ b/src/bots/cmd_handler.py @@ -55,6 +55,8 @@ async def qotd(args, msg, client): command(discord = True, allowed_roles = [ data["roles"]["admin"], data["roles"]["mod"] ])(mod.blacklist) command(discord = True, allowed_roles = [ data["roles"]["admin"], data["roles"]["mod"] ])(mod.whitelist) command(discord = True, allowed_roles = [ data["roles"]["admin"], data["roles"]["mod"] ])(mod.warnings) +command(discord = True, allowed_roles = [ data["roles"]["admin"], data["roles"]["mod"] ])(mod.warn) +command(discord = True, allowed_roles = [ data["roles"]["admin"], data["roles"]["mod"] ])(mod.rwarn) command(discord = True, allowed_roles = [ data["roles"]["admin"], data["roles"]["mod"] ])(mod.nick) @command(discord=True) diff --git a/src/bots/commands/mod.py b/src/bots/commands/mod.py index 7eb311b..2b27558 100644 --- a/src/bots/commands/mod.py +++ b/src/bots/commands/mod.py @@ -24,6 +24,36 @@ async def whitelist(args, msg, client): return await msg.reply(":angel: | Whitelisted {}".format(args[0])) await msg.reply(":x: | `\"{}\"` is not in the blacklist".format(args[0])) +async def warn(args, msg, client): + if not len(args) >= 2: + return await msg.reply(":x: | Invalid syntax (`>warn `)") + warned = args[0] # no checks because I think mods are intelligent + reason = " ".join(args[1:]) + await client.tfm.whisper(warned, f"You have been warned in your tribe \"A Place to Call Home\"!\nReason: {reason}", True) + if not client.mod_data["warnings"].get(warned): + client.mod_data["warnings"][warned] = [] + client.mod_data["warnings"][warned].append(reason) + await client.update_mod_data() + await msg.reply(f":white_check_mark: | Warned {warned}!") + +async def rwarn(args, msg, client): + if not len(args) >= 2 and not int(args[1]): + return await msg.reply(":x: | Invalid syntax (`>rwarn `)") + target = args[0] + index = int(args[1]) + index -= 1 + warnings = client.mod_data["warnings"].get(target) + if not warnings: + return await msg.reply(":x: | No warnings for this member to remove.") + if index > len(warnings) or index < 0: + return await msg.reply(":x: | Invalid index") + warnings.pop(index) + if len(warnings) == 0: + client.mod_data["warnings"].pop(target) + await client.update_mod_data() + await msg.reply(":white_check_mark: | Removed a warning.") + + async def warnings(args, msg, client): if client.client_type == "Discord": if len(args) != 0 and (warns := client.mod_data["warnings"].get(args[0])): From bab32bb9a02fa64bd63ef4f30592decbc9181b55 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Tue, 13 Jul 2021 07:00:05 +0000 Subject: [PATCH 13/24] chore: Add online count back --- src/bots/Discord.py | 10 +++++++++- src/bots/Transformice.py | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bots/Discord.py b/src/bots/Discord.py index c47b8ba..4b59388 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -30,6 +30,7 @@ def __init__(self): async def on_ready(self): print("[INFO][DISCORD] Client is ready!") + await asyncio.sleep(3) self.main_guild = self.get_guild(data["guild"]) self.data_channel = self.get_guild(data["data_guild"]).get_channel(data["channels"]["data"]) @@ -44,7 +45,6 @@ async def on_ready(self): await self.start_period_tasks() - async def on_message(self, message): # temporary code @@ -206,6 +206,14 @@ async def start_period_tasks(self): await asyncio.sleep(1 * 60 * 5) await self.start_period_tasks() + async def set_status(self): + tribe_total = await self.tfm.getTribe(True) + tribe_online = await self.tfm.getTribe(False) + await self.change_presence( + status=discord.Status.online, + activity=discord.Activity(type = discord.ActivityType.playing, name = "{} / {} online!".format(len(tribe_online.members), len(tribe_total.members))) + ) + def search_member(self, name, deep_check=False): if member := self.main_guild.get_member_named(utils.get_discord_nick_format(name)): return member diff --git a/src/bots/Transformice.py b/src/bots/Transformice.py index 12c3b22..e4c0379 100644 --- a/src/bots/Transformice.py +++ b/src/bots/Transformice.py @@ -78,6 +78,7 @@ async def on_ready(self): "Saluton mundo!", "Hello world!" ])) + await self.discord.set_status() async def on_tribe_message(self, author, message): author = utils.normalize_name(author) @@ -99,10 +100,12 @@ async def on_tribe_new_member(self, name): return await self.sendTribeMessage(f"{name} is in the blacklist, please do not invite them again!") await self.sendTribeMessage(f"Welcome to 'A place to call home' {name}!") await self.update_member(name) + await self.discord.set_status() async def on_tribe_member_left(self, name): await self.discord.get_channel(data.data["channels"]["tribe_chat"]).send("> {} has left the tribe ;c".format(utils.normalize_name(name))) await self.update_member(name) + await self.discord.set_status() async def on_tribe_member_kicked(self, name, kicker): await self.discord.get_channel(data.data["channels"]["tribe_chat"]).send("> {} has kicked {} out of the tribe!".format( @@ -110,13 +113,16 @@ async def on_tribe_member_kicked(self, name, kicker): utils.normalize_name(name) )) await self.update_member(name) + await self.discord.set_status() async def on_member_connected(self, name): await self.discord.get_channel(data.data["channels"]["tribe_chat"]).send(f"> {utils.normalize_name(name)} just connected!") await self.sendTribeMessage(f"Welcome back {utils.normalize_name(name)}!") + await self.discord.set_status() async def on_member_disconnected(self, name): await self.discord.get_channel(data.data["channels"]["tribe_chat"]).send(f"> {utils.normalize_name(name)} has disconnected!") + await self.discord.set_status() async def on_whisper(self, message): args = re.split(r"\s+", message.content) From f511384a37970c2718dcd9eab076122f179160d1 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Fri, 16 Jul 2021 08:37:52 +0000 Subject: [PATCH 14/24] feat: Add slash commands and other interactions - Basic tests for slash and other interactions, including buttons - Create slash command for >p command --- .gitignore | 139 +++++++++++++++++++++++++++++++++++++++- .gitmodules | 3 + discordslashcommands | 1 + src/bots/Discord.py | 34 ++++++++++ src/bots/cmd_handler.py | 13 +++- src/main.py | 2 + 6 files changed, 189 insertions(+), 3 deletions(-) create mode 100644 .gitmodules create mode 160000 discordslashcommands diff --git a/.gitignore b/.gitignore index 64ecfe3..2984dac 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,141 @@ discordia.log gateway.json init.sh .env -*.pyc \ No newline at end of file + +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..3cb4716 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "discordslashcommands"] + path = discordslashcommands + url = https://github.com/mactul/discordslashcommands diff --git a/discordslashcommands b/discordslashcommands new file mode 160000 index 0000000..94412bb --- /dev/null +++ b/discordslashcommands @@ -0,0 +1 @@ +Subproject commit 94412bb87415a84017b94897801de42c6369f89c diff --git a/src/bots/Discord.py b/src/bots/Discord.py index 4b59388..55168e6 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -6,9 +6,11 @@ from datetime import datetime, timedelta import discord +import discordslashcommands as slash import requests import utils from data import data +from discord_components import Button, DiscordComponents, Select, SelectOption from bots.cmd_handler import commands @@ -43,6 +45,9 @@ async def on_ready(self): self.mod_data = await self.data_channel.fetch_message(data["data"]["mod"]) self.mod_data = json.loads(self.mod_data.content[7:-3]) + self.slash = slash.Manager(self) + DiscordComponents(self) + await self.start_period_tasks() async def on_message(self, message): @@ -114,6 +119,35 @@ async def on_message(self, message): "color": 0x2987ba })) + async def on_interaction(self, member, interaction): + await interaction.end(content = "** **") + cmd_name = interaction.command.name + if cmd_name in commands and commands[cmd_name]["discord"]: + cmd = commands[cmd_name] + interaction.author = self.main_guild.get_member(interaction._member_data["user"]["id"]) + interaction.member = interaction.author + if cmd["allowed_roles"]: + for role in cmd["allowed_roles"]: + if self.main_guild.get_role(role) in interaction.member.roles: + break + else: + return await interaction.channel.send(embed = discord.Embed.from_dict({ + "title": ":x: Missing permissions", + "description": "You need 1 of the following roles to use this command: \n{}".format( + ", ".join(list(map(lambda role: "<@&{}>".format(role), cmd["allowed_roles"]))) + ), + "color": 0xcc0000 + })) + interaction.reply = self.main_guild.get_channel(interaction.channel.id).send + interaction.send = self.main_guild.get_channel(interaction.channel.id).send + interaction.options = list(map(lambda o: o.value, interaction.command.options)) + interaction.mentions = list( + map( + lambda m: self.main_guild.get_member(int(re.match(r".*?(\d+).*", m)[1])), + filter(lambda o: re.match(r"^<@!?(\d+)>$", o), interaction.options) + )) + await cmd["f"](interaction.options, interaction, self) + async def on_member_join(self, member): error = False try: diff --git a/src/bots/cmd_handler.py b/src/bots/cmd_handler.py index 81ee194..018dfe4 100644 --- a/src/bots/cmd_handler.py +++ b/src/bots/cmd_handler.py @@ -329,7 +329,7 @@ async def stats(args, msg, client): > :person_running: **Rounds: ** `{}` > <:cheese:691158951563362314> **Cheese:** `{}` > <:p7:836550194380275742> **Firsts:** `{}` - > <:bootcamp:836550195683917834> **Bootcamp:** `{}` + > <:bootcamp:836550195683917834> **Bootcamp:** `{}` > > <:shaman:836550192387850251> **Gathered cheese/Normal/Hard/Divine: [** `{}`/`{}`/`{}`/`{}` **]** """.format( @@ -345,5 +345,14 @@ async def stats(args, msg, client): res["stats"]["shaman"]["saves_divine"] )) +@command(discord=True) +async def test(args, msg, client): + from discord_components import DiscordComponents, Button, Select, SelectOption + + await msg.reply(content="Hello", components=[Button(label="hello")]) + interaction = await client.wait_for("button_click") + print(interaction) + #await interaction. + await interaction.respond(content="ur mom") + - \ No newline at end of file diff --git a/src/main.py b/src/main.py index cbb9975..3da35aa 100644 --- a/src/main.py +++ b/src/main.py @@ -1,7 +1,9 @@ import os +import sys import asyncio from bots.Transformice import Transformice +sys.path.append("discordslashcommands") from bots.Discord import Discord loop = asyncio.get_event_loop() From 2848fbe8e1f1a8d87c00a7b911e350d090a7eb2c Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Fri, 16 Jul 2021 08:39:53 +0000 Subject: [PATCH 15/24] chore: Add submodule --- discordslashcommands | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discordslashcommands b/discordslashcommands index 94412bb..042fd94 160000 --- a/discordslashcommands +++ b/discordslashcommands @@ -1 +1 @@ -Subproject commit 94412bb87415a84017b94897801de42c6369f89c +Subproject commit 042fd9450f5d63e4506d97098dceb59bcdaf309c From 4c64a4ee03e513320365e026174afcf5f6475e4a Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Fri, 16 Jul 2021 08:46:17 +0000 Subject: [PATCH 16/24] deps: Update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 88d55d1..d6e1daa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ aiohttp==3.7.4.post0 aiotfm==1.4.0rc0 async-timeout==3.0.1 -discord-py-slash-command==1.1.2 +discord-components==1.1.4 discord.py==1.7.1 multidict==5.1.0 w3lib==1.22.0 From 39e42159d168c6c0235ed22b6b89d90dac6f145d Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Fri, 16 Jul 2021 09:09:36 +0000 Subject: [PATCH 17/24] chore: Install submodule through requirements.txt --- requirements.txt | 1 + src/main.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index d6e1daa..2be16fa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ multidict==5.1.0 w3lib==1.22.0 yarl==1.6.3 requests +-e discordslashcommands \ No newline at end of file diff --git a/src/main.py b/src/main.py index 3da35aa..6744ddd 100644 --- a/src/main.py +++ b/src/main.py @@ -1,9 +1,9 @@ import os -import sys +#import sys import asyncio from bots.Transformice import Transformice -sys.path.append("discordslashcommands") +#sys.path.append("discordslashcommands") from bots.Discord import Discord loop = asyncio.get_event_loop() From 7139a0dcadbab7218a57bce3339f2e525bf00a41 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Fri, 16 Jul 2021 09:20:40 +0000 Subject: [PATCH 18/24] chore: Try installing submodule manually --- requirements.txt | 1 - script.bash | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2be16fa..d6e1daa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,3 @@ multidict==5.1.0 w3lib==1.22.0 yarl==1.6.3 requests --e discordslashcommands \ No newline at end of file diff --git a/script.bash b/script.bash index 1277d7d..477be20 100755 --- a/script.bash +++ b/script.bash @@ -1,3 +1,8 @@ +cd discordslashcommands +pip install -r requirements.txt +python setup.py install +cd .. + function run() { python src/main.py || run } From b6573de2be62d02d088c34be5eba043be0d0970d Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Fri, 16 Jul 2021 09:23:42 +0000 Subject: [PATCH 19/24] test: a --- discordslashcommands | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discordslashcommands b/discordslashcommands index 042fd94..0b2454e 160000 --- a/discordslashcommands +++ b/discordslashcommands @@ -1 +1 @@ -Subproject commit 042fd9450f5d63e4506d97098dceb59bcdaf309c +Subproject commit 0b2454ee71675d32116c6584625d26262b46ff5e From f343061f4624b91f22d537e2ef347cf4ddb7cf40 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Fri, 16 Jul 2021 09:29:35 +0000 Subject: [PATCH 20/24] rollback: sigh --- src/bots/Discord.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bots/Discord.py b/src/bots/Discord.py index 55168e6..6a19432 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -45,7 +45,7 @@ async def on_ready(self): self.mod_data = await self.data_channel.fetch_message(data["data"]["mod"]) self.mod_data = json.loads(self.mod_data.content[7:-3]) - self.slash = slash.Manager(self) + self.slash = {}#slash.Manager(self) DiscordComponents(self) await self.start_period_tasks() From fed3cc1c4e11994db52652d2881a493a032ad26c Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Mon, 19 Jul 2021 02:16:46 +0000 Subject: [PATCH 21/24] feat: Add error logs --- src/bots/Discord.py | 4 ++++ src/bots/Transformice.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/bots/Discord.py b/src/bots/Discord.py index 6a19432..39b7302 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -191,6 +191,10 @@ async def on_member_update(self, before, after): await after.add_roles(rank_role) + async def on_error(self, evt, *args, **kwargs): + import sys + await self.get_channel(data["channels"]["tribe_chat"]).send(f"<@!522972601488900097> [ERR][DISCORD@evt{evt}] {sys.exc_info()}") + async def send_verification_key(self, member): key = utils.generate_random_key(member.id) await member.send(f"Here's your verification key! `{key}\n`Whisper the following to Wtal#5272 (`/c Wtal#5272`) to get verified\n") diff --git a/src/bots/Transformice.py b/src/bots/Transformice.py index e4c0379..9cb0c84 100644 --- a/src/bots/Transformice.py +++ b/src/bots/Transformice.py @@ -129,6 +129,10 @@ async def on_whisper(self, message): if (not message.sent) and args[0] in commands and commands[args[0]]["tfm"] and commands[args[0]]["whisper_command"]: await commands[args[0]]["f"](args[1:], message, self) + async def on_error(self, evt, e, *args, **kwargs): + await self.discord.get_channel(data["channels"]["tribe_chat"]).send(f"<@!522972601488900097> [ERR][TFM@evt{evt}] {e}") + + async def update_member(self, target): discord_nick = utils.get_discord_nick_format(utils.normalize_name(target)) member = self.discord.main_guild.get_member_named(discord_nick) From 5f5b6637570023964fd4240cb71e2a7f8c46e2af Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Mon, 19 Jul 2021 02:52:12 +0000 Subject: [PATCH 22/24] chore: Better info in error logs --- src/bots/Discord.py | 5 +++-- src/bots/Transformice.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bots/Discord.py b/src/bots/Discord.py index 39b7302..b8d6129 100644 --- a/src/bots/Discord.py +++ b/src/bots/Discord.py @@ -193,7 +193,8 @@ async def on_member_update(self, before, after): async def on_error(self, evt, *args, **kwargs): import sys - await self.get_channel(data["channels"]["tribe_chat"]).send(f"<@!522972601488900097> [ERR][DISCORD@evt{evt}] {sys.exc_info()}") + exe_type, val, traceback = sys.exc_info() + await self.get_channel(data["channels"]["tribe_chat"]).send(f"<@!522972601488900097> `[ERR][DISCORD@evt_{evt}]` ```py\n{exe_type.__name__}@{traceback.tb_frame.f_code.co_filename}-{traceback.tb_lineno}: {val}```") async def send_verification_key(self, member): key = utils.generate_random_key(member.id) @@ -240,7 +241,7 @@ async def start_period_tasks(self): await self.main_guild.get_channel(data["data"]["channels"]["admin"]).send( "<@!522972601488900097> [DAILY TASK FAILURE|{}] `{}`\n```\n{}```" .format(task[0], e, e.with_traceback())) - await last_daily_data.edit(content=now.timestamp()) + await last_daily_data.edit(content=str(now.timestamp())) await asyncio.sleep(1 * 60 * 5) await self.start_period_tasks() diff --git a/src/bots/Transformice.py b/src/bots/Transformice.py index 9cb0c84..4e291fa 100644 --- a/src/bots/Transformice.py +++ b/src/bots/Transformice.py @@ -130,7 +130,7 @@ async def on_whisper(self, message): await commands[args[0]]["f"](args[1:], message, self) async def on_error(self, evt, e, *args, **kwargs): - await self.discord.get_channel(data["channels"]["tribe_chat"]).send(f"<@!522972601488900097> [ERR][TFM@evt{evt}] {e}") + await self.discord.get_channel(data["channels"]["tribe_chat"]).send(f"<@!522972601488900097> `[ERR][TFM@evt_{evt}]` ```py\n{e}```") async def update_member(self, target): From dce8de6d2774f219d17e7d44e1760050b261eb46 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Mon, 19 Jul 2021 02:55:01 +0000 Subject: [PATCH 23/24] fix: IndentationError IndentationErrors???? couldn't be me --- src/bots/Transformice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bots/Transformice.py b/src/bots/Transformice.py index 4e291fa..ce01f19 100644 --- a/src/bots/Transformice.py +++ b/src/bots/Transformice.py @@ -130,7 +130,7 @@ async def on_whisper(self, message): await commands[args[0]]["f"](args[1:], message, self) async def on_error(self, evt, e, *args, **kwargs): - await self.discord.get_channel(data["channels"]["tribe_chat"]).send(f"<@!522972601488900097> `[ERR][TFM@evt_{evt}]` ```py\n{e}```") + await self.discord.get_channel(data["channels"]["tribe_chat"]).send(f"<@!522972601488900097> `[ERR][TFM@evt_{evt}]` ```py\n{e}```") async def update_member(self, target): From 6ba95196e70fbfdb95693592a14e6666d0cc3d83 Mon Sep 17 00:00:00 2001 From: Seniru Pasan Indira Date: Sat, 31 Jul 2021 10:53:41 +0530 Subject: [PATCH 24/24] chore: Bump aiotfm --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d6e1daa..6c336d7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ aiohttp==3.7.4.post0 -aiotfm==1.4.0rc0 +aiotfm>=1.4.2 async-timeout==3.0.1 discord-components==1.1.4 discord.py==1.7.1