riddle_bot.py
1 import io 2 import json 3 import os 4 import random 5 import re 6 import time 7 from typing import Optional, List, Tuple 8 9 from discord import ( 10 Client, 11 Message, 12 Member, 13 Guild, 14 CategoryChannel, 15 utils, 16 Embed, 17 Role, 18 PermissionOverwrite, 19 User, 20 DMChannel, 21 Color, 22 TextChannel, 23 File, 24 ) 25 26 BELL = "đ" 27 THUMBSUP = "đ" 28 THUMBSDOWN = "đ" 29 30 config: dict = json.load(open("config.json")) 31 GUILD: int = config["guild"] 32 NOTIFICATION_ROLE: int = config["notification_role"] 33 SETTINGS_CHANNEL: int = config["settings_channel"] 34 MASTER_OF_EVERYTHING_ROLE: int = config["master_of_everything_role"] 35 GENERAL_CHAT: int = config["general_chat"] 36 PREFIX = config["prefix"] 37 38 39 def create_embed(**kwargs): 40 embed = Embed(**kwargs) 41 embed.set_footer(text="Bot by @Defelo#2022") 42 return embed 43 44 45 def level_name(level_id): 46 return f"level-{level_id}" 47 48 49 def solution_name(level_id): 50 return f"solution-{level_id}" 51 52 53 def role_name(category, level_id): 54 return f"{category} - Level {level_id}" 55 56 57 def riddle_master_name(category): 58 return f"Master of {category}" 59 60 61 def category_name(category_id, category, escaped=False): 62 if escaped: 63 return fr"\[{category_id}\] {category} - Levels" 64 else: 65 return f"[{category_id}] {category} - Levels" 66 67 68 class Bot(Client): 69 def __init__(self): 70 super().__init__() 71 72 self.guild: Optional[Guild] = None 73 self.notification_role: Optional[Role] = None 74 self.settings_channel: Optional[TextChannel] = None 75 self.master_of_everything_role: Optional[Role] = None 76 self.general_chat: Optional[TextChannel] = None 77 self.settings_message: Optional[Message] = None 78 79 self.cooldowns = {} 80 81 async def on_ready(self): 82 print(f"Logged in as {self.user}") 83 84 self.guild: Guild = self.get_guild(GUILD) 85 self.notification_role: Role = self.guild.get_role(NOTIFICATION_ROLE) 86 self.settings_channel: TextChannel = self.guild.get_channel(SETTINGS_CHANNEL) 87 self.master_of_everything_role: Role = self.guild.get_role(MASTER_OF_EVERYTHING_ROLE) 88 self.general_chat: TextChannel = self.guild.get_channel(GENERAL_CHAT) 89 async for msg in self.settings_channel.history(): 90 self.settings_message: Message = msg 91 break 92 93 def get_levels(self, category: str) -> List[int]: 94 out = [] 95 for role in self.guild.roles: 96 if role.id == MASTER_OF_EVERYTHING_ROLE: 97 continue 98 match = re.match("^" + role_name(category, r"(\d+)") + "$", role.name) 99 if match: 100 out.append(int(match.group(1))) 101 return sorted(out) 102 103 def get_categories(self) -> List[Tuple[int, str]]: 104 out = [] 105 for category in self.guild.categories: 106 match = re.match("^" + category_name(r"(\d+)", "(.*)", escaped=True) + "$", category.name) 107 if match: 108 category_id, name = match.groups() 109 out.append((int(category_id), name)) 110 return out 111 112 def get_next_category_id(self) -> int: 113 return max((cat_id for cat_id, _ in self.get_categories()), default=0) + 1 114 115 def get_max_level_id(self, category: str) -> int: 116 return max(self.get_levels(category), default=0) 117 118 def get_level_count(self, category: str) -> int: 119 return len(self.get_levels(category)) 120 121 async def is_authorized(self, user: User) -> bool: 122 member: Optional[Member] = self.guild.get_member(user.id) 123 return member and member.guild_permissions.administrator 124 125 def get_level(self, category, level_id): 126 _, _, category_channel, _, _ = self.get_category(name=category) 127 if category_channel is None: 128 return None, None, None 129 130 level_channel: Optional[TextChannel] = utils.get(category_channel.channels, name=level_name(level_id)) 131 solution_channel: Optional[TextChannel] = utils.get(category_channel.channels, name=solution_name(level_id)) 132 role: Optional[Role] = utils.get(self.guild.roles, name=role_name(category, level_id)) 133 return level_channel, solution_channel, role 134 135 def get_category(self, *, name=None, category_id=None): 136 assert name is not None or category_id is not None 137 category_channel: Optional[CategoryChannel] = None 138 139 regex_id = str(category_id or r"\d+") 140 regex_name = name or ".*" 141 for cat in self.guild.categories: 142 match = re.match("^" + category_name(f"({regex_id})", f"({regex_name})", escaped=True) + "$", cat.name) 143 if match: 144 category_id, name = match.groups() 145 category_id = int(category_id) 146 category_channel = cat 147 riddle_master_role: Optional[Role] = utils.get(self.guild.roles, name=riddle_master_name(name)) 148 leaderboard_channel: Optional[TextChannel] = category_channel and utils.get( 149 category_channel.channels, name="leaderboard" 150 ) 151 return category_id, name, category_channel, riddle_master_role, leaderboard_channel 152 153 async def on_member_join(self, member: Member): 154 if member.guild.id != self.guild.id: 155 return 156 157 await member.send(open("texts/welcome_dm.txt").read().format(user=member.mention)) 158 159 master_of_everything = True 160 for _, cat_name in self.get_categories(): 161 _, _, role = self.get_level(cat_name, 1) 162 if role is not None: 163 master_of_everything = False 164 await member.add_roles(role) 165 else: 166 _, _, _, riddle_master_role, _ = self.get_category(name=cat_name) 167 await member.add_roles(riddle_master_role) 168 await self.update_leaderboard(cat_name) 169 if master_of_everything: 170 await member.add_roles(self.master_of_everything_role) 171 172 async def on_raw_reaction_add(self, payload): 173 if self.settings_message is None or self.settings_message.id != payload.message_id: 174 return 175 if str(payload.emoji) != BELL or payload.user_id == self.user.id: 176 return 177 178 member: Message = self.guild.get_member(payload.user_id) 179 await member.add_roles(self.notification_role) 180 181 async def on_raw_reaction_remove(self, payload): 182 if self.settings_message is None or self.settings_message.id != payload.message_id: 183 return 184 if str(payload.emoji) != BELL or payload.user_id == self.user.id: 185 return 186 187 member: Message = self.guild.get_member(payload.user_id) 188 await member.remove_roles(self.notification_role) 189 190 async def update_leaderboard(self, category): 191 _, _, _, riddle_master_role, leaderboard_channel = self.get_category(name=category) 192 async for message in leaderboard_channel.history(): 193 if message.author == self.user: 194 break 195 else: 196 message = await leaderboard_channel.send(embed=create_embed()) 197 198 level_count = self.get_level_count(category) 199 200 leaderboard = [] 201 for member in self.guild.members: 202 if await self.is_authorized(member): 203 continue 204 205 for role in member.roles: 206 match = re.match("^" + role_name(category, r"(\d+)") + "$", role.name) 207 if role.id == riddle_master_role.id: 208 leaderboard.append((level_count, f"@{member}")) 209 elif match: 210 leaderboard.append((int(match.group(1)) - 1, f"@{member}")) 211 leaderboard.sort(reverse=True) 212 max_width = max((len(member) for _, member in leaderboard), default=0) 213 description = ["```", "MEMBER".ljust(max_width) + " SCORE"] 214 for score, member in leaderboard[:20]: 215 description.append(member.ljust(max_width) + f" {score}") 216 description.append("```") 217 218 embed = create_embed(title="Leaderboard", description="\n".join(description)) 219 220 await message.edit(embed=embed) 221 222 async def update_master_of_everything_role(self, member: Member): 223 master_of_everything = True 224 for _, cat_name in self.get_categories(): 225 _, _, _, riddle_master_role, _ = self.get_category(name=cat_name) 226 if riddle_master_role not in member.roles: 227 master_of_everything = False 228 break 229 if master_of_everything: 230 await member.add_roles(self.master_of_everything_role) 231 else: 232 await member.remove_roles(self.master_of_everything_role) 233 234 async def on_message(self, message: Message): 235 if message.author == self.user: 236 return 237 238 if message.content.startswith(PREFIX): 239 cmd, *args = message.content[1:].split() 240 if cmd == "add": 241 if not await self.is_authorized(message.author): 242 await message.channel.send("You are not authorized to use this command!") 243 return 244 245 if len(args) < 2 or args[0] not in ("category", "level"): 246 await message.channel.send(f"usage: {PREFIX}add category|level <category>") 247 return 248 category = " ".join(args[1:]) 249 if args[0] == "level": 250 _, cat_name, category_channel, riddle_master_role, _ = self.get_category(category_id=category) 251 if category_channel is None: 252 await message.channel.send("Category does not exist!") 253 return 254 255 level_id = self.get_max_level_id(cat_name) + 1 256 await message.channel.send(f"Creating Level {level_id}") 257 258 role: Role = await self.guild.create_role(name=role_name(cat_name, level_id)) 259 260 for level in self.get_levels(cat_name): 261 if level == level_id: 262 continue 263 264 level_channel, _, _ = self.get_level(cat_name, level) 265 await level_channel.set_permissions( 266 role, read_messages=True, send_messages=False, 267 ) 268 269 level_channel: TextChannel = await category_channel.create_text_channel( 270 level_name(level_id), 271 overwrites={ 272 self.guild.default_role: PermissionOverwrite(read_messages=False), 273 role: PermissionOverwrite(read_messages=True, send_messages=False, add_reactions=False), 274 riddle_master_role: PermissionOverwrite( 275 read_messages=True, send_messages=False, add_reactions=False 276 ), 277 self.guild.me: PermissionOverwrite(read_messages=True, send_messages=True), 278 }, 279 ) 280 solution_channel: TextChannel = await category_channel.create_text_channel( 281 solution_name(level_id), 282 overwrites={ 283 self.guild.default_role: PermissionOverwrite(read_messages=False), 284 self.guild.me: PermissionOverwrite(read_messages=True), 285 }, 286 ) 287 await message.channel.send( 288 f"Level {level_id} has been created.\n" 289 f"Level channel: {level_channel.mention}\n" 290 f"Solution channel: {solution_channel.mention}\n" 291 f"Role: {role.mention}" 292 ) 293 await message.channel.send("Now send me the riddle!") 294 riddle = await self.wait_for( 295 "message", check=lambda m: m.channel == message.channel and m.author == message.author 296 ) 297 riddle_message: Message = await level_channel.send( 298 embed=( 299 create_embed( 300 title=f"[{category}] {cat_name} - Level {level_id}", description=riddle.content 301 ) 302 ) 303 ) 304 await riddle_message.add_reaction(THUMBSUP) 305 await riddle_message.add_reaction(THUMBSDOWN) 306 await message.channel.send("Riddle has been created! :+1:") 307 await message.channel.send(f"Now go to {solution_channel.mention} and send the solution.") 308 await message.channel.send( 309 f"After that type `{PREFIX}notify {category} {level_id}` to notify the Riddle Masters :wink:" 310 ) 311 else: 312 category_channel: CategoryChannel = await self.guild.create_category( 313 category_name(self.get_next_category_id(), category) 314 ) 315 await category_channel.create_text_channel( 316 "leaderboard", 317 overwrites={ 318 self.guild.default_role: PermissionOverwrite(read_messages=True, send_messages=False), 319 self.guild.me: PermissionOverwrite(read_messages=True, send_messages=True), 320 }, 321 ) 322 323 riddle_master_role: Role = await self.guild.create_role( 324 name=riddle_master_name(category), color=Color(random.randint(0, 0xFFFFFF)), hoist=True 325 ) 326 for member in self.guild.members: 327 if member.id != self.user.id: 328 await member.add_roles(riddle_master_role) 329 await self.update_leaderboard(category) 330 await message.channel.send("Category has been created!") 331 elif cmd == "notify": 332 if not await self.is_authorized(message.author): 333 await message.channel.send("You are not authorized to use this command!") 334 return 335 336 if len(args) != 2: 337 await message.channel.send(f"usage: {PREFIX}notify <category-id> <level-id>") 338 return 339 else: 340 if not args[-1].isnumeric(): 341 await message.channel.send("Level ID has to be numeric!") 342 return 343 category = args[0] 344 level_id = int(args[1]) 345 346 _, cat_name, _, riddle_master_role, _ = self.get_category(category_id=category) 347 level_channel, _, role = self.get_level(cat_name, level_id) 348 notify_count = 0 349 for member in self.guild.members: 350 if riddle_master_role in member.roles: 351 await member.remove_roles(riddle_master_role, self.master_of_everything_role) 352 await member.add_roles(role) 353 if self.notification_role in member.roles: 354 await member.send( 355 "Hey! Es gibt jetzt ein neues RĂ€tsel auf dem Riddle Server :wink:\n" 356 f"Schau mal hier: {level_channel.mention}" 357 ) 358 notify_count += 1 359 await self.update_leaderboard(cat_name) 360 await message.channel.send( 361 f"{notify_count} member{[' has', 's have'][notify_count != 1]} been notified about the new level." 362 ) 363 elif cmd == "delete": 364 if not await self.is_authorized(message.author): 365 await message.channel.send("You are not authorized to use this command!") 366 return 367 368 if not ( 369 (len(args) == 2 and args[0] == "category") 370 or (len(args) == 3 and args[0] == "level") 371 or (len(args) == 4 and args[0] == "levels") 372 ): 373 await message.channel.send( 374 f"usage: {PREFIX}delete category <category-id>\n" 375 f" or: {PREFIX}delete level[s] <category-id> <level-id> [<level-id>]" 376 ) 377 return 378 379 category = args[1] 380 _, cat_name, category_channel, riddle_master_role, leaderboard = self.get_category(category_id=category) 381 if args[0] == "category": 382 for level in self.get_levels(cat_name): 383 level_channel, solution_channel, role = self.get_level(cat_name, level) 384 if level_channel: 385 await level_channel.delete() 386 if solution_channel: 387 await solution_channel.delete() 388 if role: 389 await role.delete() 390 if leaderboard: 391 await leaderboard.delete() 392 if category_channel: 393 await category_channel.delete() 394 if riddle_master_role: 395 await riddle_master_role.delete() 396 397 await message.channel.send("Category has been deleted") 398 else: 399 if args[0] == "level": 400 if not args[2].isnumeric(): 401 await message.channel.send("Level ID has to be numeric!") 402 return 403 from_level_id = int(args[2]) 404 to_level_id = from_level_id 405 else: 406 if (not args[2].isnumeric()) or (not args[3].isnumeric()): 407 await message.channel.send("Level ID has to be numeric!") 408 return 409 from_level_id = int(args[2]) 410 to_level_id = int(args[3]) 411 412 for level_id in range(from_level_id, to_level_id + 1): 413 level_channel, solution_channel, role = self.get_level(cat_name, level_id) 414 existed = False 415 if level_channel: 416 await level_channel.delete() 417 existed = True 418 if solution_channel: 419 await solution_channel.delete() 420 existed = True 421 if role: 422 await role.delete() 423 existed = True 424 425 if existed: 426 await message.channel.send(f"Level {level_id} has been deleted") 427 else: 428 await message.channel.send(f"Level {level_id} does not exist") 429 for level in self.get_levels(cat_name): 430 if level <= to_level_id: 431 continue 432 level_channel, solution_channel, role = self.get_level(cat_name, level) 433 await level_channel.edit(name=level_name(level - (to_level_id - from_level_id + 1))) 434 await solution_channel.edit(name=solution_name(level - (to_level_id - from_level_id + 1))) 435 await role.edit(name=role_name(cat_name, level - (to_level_id - from_level_id + 1))) 436 await self.update_leaderboard(cat_name) 437 438 for member in self.guild.members: 439 if member != self.user: 440 await self.update_master_of_everything_role(member) 441 442 await message.channel.send("Done") 443 elif cmd == "rename": 444 if not await self.is_authorized(message.author): 445 await message.channel.send("You are not authorized to use this command!") 446 return 447 448 if len(args) < 2 or not args[0].isnumeric(): 449 await message.channel.send(f"usage: {PREFIX}rename <category-id> <name>") 450 return 451 452 category = args[0] 453 new_name = " ".join(args[1:]) 454 cat_id, cat_name, category_channel, riddle_master_role, leaderboard = self.get_category( 455 category_id=category 456 ) 457 for level in self.get_levels(cat_name): 458 level_channel, _, role = self.get_level(cat_name, level) 459 await role.edit(name=role_name(new_name, level)) 460 async for msg in level_channel.history(oldest_first=True): 461 if msg.author == self.user and msg.embeds: 462 embed: Embed = msg.embeds[0] 463 embed.title = f"[{category}] {new_name} - Level {level}" 464 await msg.edit(embed=embed) 465 break 466 467 await category_channel.edit(name=category_name(cat_id, new_name)) 468 await riddle_master_role.edit(name=riddle_master_name(new_name)) 469 await message.channel.send("Done!") 470 elif cmd == "info": 471 embed = create_embed(title="Info") 472 for cat_id, cat_name in self.get_categories(): 473 count = self.get_level_count(cat_name) 474 embed.add_field( 475 name=f"[{cat_id}] {cat_name}", value=f"{count} Level" + "s" * (count != 1), inline=False 476 ) 477 await message.channel.send(embed=embed) 478 elif cmd == "setup": 479 if not await self.is_authorized(message.author): 480 await message.channel.send("You are not authorized to use this command!") 481 return 482 483 self.settings_message = await self.settings_channel.send( 484 embed=create_embed(title="Settings", description=open("texts/settings.txt").read()) 485 ) 486 await self.settings_message.add_reaction(BELL) 487 elif cmd in ("solve", "lösen"): 488 if not isinstance(message.channel, DMChannel): 489 await message.delete() 490 await message.channel.send( 491 f"Hey, {message.author.mention}! Schick mir deine Lösung bitte privat :wink:" 492 ) 493 return 494 495 if not args: 496 await message.channel.send(f"usage: {PREFIX}solve <category-id> [<solution>]") 497 return 498 499 member: Member = self.guild.get_member(message.author.id) 500 501 now = time.time() 502 cooldown, wrong_answers = self.cooldowns.get(member.id, (0, 0)) 503 seconds = round(cooldown - now) 504 if seconds > 0: 505 minutes, seconds = divmod(seconds, 60) 506 hours, minutes = divmod(minutes, 60) 507 await message.channel.send( 508 f"Da deine letzte Antwort falsch war, musst du noch etwas warten, " 509 f"bevor du es noch einmal versuchen kannst.\n" 510 f"Verbleibende Zeit: `{hours:02d}:{minutes:02d}:{seconds:02d}`" 511 ) 512 return 513 514 answer = " ".join(args[1:]) 515 _, cat_name, _, riddle_master_role, _ = self.get_category(category_id=args[0]) 516 if riddle_master_role is None: 517 await message.channel.send("Tut mir leid, diese Kategorie kenne ich nicht :shrug:") 518 return 519 520 for role in member.roles: 521 if role.id == riddle_master_role.id: 522 await message.channel.send("Hey, du hast bereits alle RĂ€tsel in dieser Kategorie gelöst :wink:") 523 return 524 525 if re.match("^" + role_name(cat_name, r"(\d+)") + "$", role.name): 526 level_id = int(re.match("^" + role_name(cat_name, r"(\d+)") + "$", role.name).group(1)) 527 break 528 else: 529 level_channel, _, role = self.get_level(cat_name, 1) 530 if role is not None: 531 await member.add_roles(role) 532 await message.channel.send( 533 "Sorry, du hattest anscheinend noch keine Level-Rolle.\n" 534 f"Schau jetzt mal in {level_channel.mention} :wink:" 535 ) 536 return 537 538 if not answer: 539 await message.channel.send("Ok, jetzt schick mir bitte die Lösung!") 540 answer = ( 541 await self.wait_for( 542 "message", check=lambda m: m.channel == message.channel and m.author == message.author 543 ) 544 ).content 545 546 _, solution_channel, old_role = self.get_level(cat_name, level_id) 547 async for msg in solution_channel.history(): 548 if re.match(f"^{msg.content.lower()}$", answer.lower()): 549 level_channel, _, new_role = self.get_level(cat_name, level_id + 1) 550 await member.remove_roles(old_role) 551 if new_role is not None: 552 await member.add_roles(new_role) 553 await message.channel.send(f"Richtig! Du hast jetzt Zugriff auf {level_channel.mention}!") 554 else: 555 await member.add_roles(riddle_master_role) 556 await self.update_master_of_everything_role(member) 557 await message.channel.send( 558 f"Richtig! Leider war das aber schon das letzte RĂ€tsel dieser Kategorie." 559 ) 560 if self.master_of_everything_role in member.roles: 561 await self.general_chat.send( 562 f"{member.mention} hat jetzt **alle RĂ€tsel aller Kategorien gelöst!**\n" 563 f"**Herzlichen GlĂŒckwunsch!** :tada:" 564 ) 565 else: 566 await self.general_chat.send( 567 f"{member.mention} hat jetzt alle RĂ€tsel der Kategorie {cat_name} gelöst! :tada:" 568 ) 569 cooldown = wrong_answers = 0 570 break 571 else: 572 await message.channel.send(f"Deine Antwort zu Level {level_id} ist leider falsch.") 573 cooldown = now + min(2 ** wrong_answers, 24 * 60 * 60) 574 wrong_answers += 1 575 self.cooldowns[member.id] = (cooldown, wrong_answers) 576 await self.update_leaderboard(cat_name) 577 elif cmd == "fix": 578 await self.fix_member(self.guild.get_member(message.author.id)) 579 for _, cat_name in self.get_categories(): 580 await self.update_leaderboard(cat_name) 581 await message.channel.send("Done") 582 elif cmd == "fixall": 583 if not await self.is_authorized(message.author): 584 await message.channel.send("You are not authorized to use this command!") 585 return 586 587 for member in self.guild.members: 588 if member != self.user: 589 await self.fix_member(member) 590 for _, cat_name in self.get_categories(): 591 await self.update_leaderboard(cat_name) 592 await message.channel.send("Done") 593 elif cmd == "score": 594 member: Member = self.guild.get_member(message.author.id) 595 embed = create_embed(title=f"Score of @{member}") 596 total = 0 597 for _, cat_name in self.get_categories(): 598 _, _, _, riddle_master_role, _ = self.get_category(name=cat_name) 599 level_count = self.get_level_count(cat_name) 600 for role in member.roles: 601 match = re.match("^" + role_name(cat_name, r"(\d+)") + "$", role.name) 602 points = None 603 if role.id == riddle_master_role.id: 604 points = level_count 605 elif match: 606 points = int(match.group(1)) - 1 607 if points is not None: 608 embed.add_field(name=cat_name, value=f"{points} Points", inline=False) 609 total += points 610 break 611 embed.add_field(name="TOTAL", value=f"{total} Points", inline=False) 612 await message.channel.send(embed=embed) 613 elif cmd == "send": 614 if not await self.is_authorized(message.author): 615 await message.channel.send("You are not authorized to use this command!") 616 return 617 618 if len(args) != 2 or args[0] not in ("text", "embed"): 619 await message.channel.send(f"usage: {PREFIX}send text|embed <channel>") 620 return 621 622 channel_id = int(re.match(r"^(<#)?(\d+)(?(1)>)$", args[1]).group(2)) 623 channel: TextChannel = self.get_channel(channel_id) 624 if channel is None: 625 await message.channel.send("Channel does not exist.") 626 return 627 628 if args[0] == "text": 629 await message.channel.send("Now send me the message!") 630 msg: Message = await self.wait_for( 631 "message", check=lambda m: m.channel == message.channel and m.author == message.author 632 ) 633 files = [] 634 for attachment in msg.attachments: 635 file = io.BytesIO() 636 await attachment.save(file) 637 files.append(File(file, filename=attachment.filename, spoiler=attachment.is_spoiler())) 638 await channel.send(content=msg.content, files=files) 639 else: 640 await message.channel.send("Send me the title of the embed!") 641 title = ( 642 await self.wait_for( 643 "message", check=lambda m: m.channel == message.channel and m.author == message.author 644 ) 645 ).content 646 await message.channel.send("Ok, now send me the content of the embed!") 647 content = ( 648 await self.wait_for( 649 "message", check=lambda m: m.channel == message.channel and m.author == message.author 650 ) 651 ).content 652 await channel.send(embed=create_embed(title=title, description=content)) 653 elif cmd == "edit": 654 if not await self.is_authorized(message.author): 655 await message.channel.send("You are not authorized to use this command!") 656 return 657 658 if len(args) != 3 or args[0] not in ("text", "embed") or not args[2].isnumeric(): 659 await message.channel.send(f"usage: {PREFIX}edit text|embed <channel> <message-id>") 660 return 661 662 channel_id = int(re.match(r"^(<#)?(\d+)(?(1)>)$", args[1]).group(2)) 663 channel: TextChannel = self.get_channel(channel_id) 664 if channel is None: 665 await message.channel.send("Channel does not exist.") 666 return 667 msg_to_edit: Optional[Message] = await channel.fetch_message(int(args[2])) 668 if msg_to_edit is None: 669 await msg_to_edit.channel.send("Message does not exist.") 670 return 671 672 if args[0] == "text": 673 await message.channel.send("Now send me the new message!") 674 msg: Message = await self.wait_for( 675 "message", check=lambda m: m.channel == message.channel and m.author == message.author 676 ) 677 files = [] 678 for attachment in msg.attachments: 679 file = io.BytesIO() 680 await attachment.save(file) 681 files.append(File(file, filename=attachment.filename, spoiler=attachment.is_spoiler())) 682 await msg_to_edit.edit(content=msg.content, files=files) 683 else: 684 await message.channel.send("Send me the new title of the embed!") 685 title = ( 686 await self.wait_for( 687 "message", check=lambda m: m.channel == message.channel and m.author == message.author 688 ) 689 ).content 690 await message.channel.send("Ok, now send me the new content of the embed!") 691 content = ( 692 await self.wait_for( 693 "message", check=lambda m: m.channel == message.channel and m.author == message.author 694 ) 695 ).content 696 await msg_to_edit.edit(embed=create_embed(title=title, description=content)) 697 elif cmd == "help": 698 response = "```\n" 699 if await self.is_authorized(message.author): 700 response += open("texts/admin_commands.txt").read().format(prefix=PREFIX) + "\n" 701 response += open("texts/user_commands.txt").read().format(prefix=PREFIX) + "\n```" 702 await message.channel.send(response) 703 else: 704 await message.channel.send(f"Unknown command! Type `{PREFIX}help` to get a list of commands!") 705 706 async def fix_member(self, member: Member): 707 for cat_id, cat_name in self.get_categories(): 708 _, _, _, riddle_master_role, _ = self.get_category(category_id=cat_id) 709 710 for role in member.roles: 711 if role.id == riddle_master_role.id: 712 break 713 elif re.match("^" + role_name(cat_name, r"(\d+)") + "$", role.name): 714 break 715 else: 716 _, _, role = self.get_level(cat_name, 1) 717 await member.add_roles(role or riddle_master_role) 718 719 720 Bot().run(os.environ["TOKEN"])