diff --git a/bootstrap.py b/bootstrap.py
index fceaed2..47b6b48 100644
--- a/bootstrap.py
+++ b/bootstrap.py
@@ -13,6 +13,8 @@ from core.logger import Logger
from core.registry import Registry
from core.upgrade import run_upgrades
+import faulthandler
+faulthandler.enable()
def get_config_from_env():
config_obj = DictObject()
diff --git a/core/chat_blob.py b/core/chat_blob.py
index aeb5431..14384b3 100644
--- a/core/chat_blob.py
+++ b/core/chat_blob.py
@@ -1,9 +1,10 @@
class ChatBlob:
- def __init__(self, title, msg, prefix="", suffix=""):
+ def __init__(self, title, msg, prefix="", suffix="", embed=True):
self.title = title
self.msg = msg.strip("\n")
self.page_prefix = prefix
self.page_postfix = suffix
+ self.embed = embed
def __str__(self):
return f"ChatBlob('{self.title}', '{self.msg}')"
diff --git a/core/command_service.py b/core/command_service.py
index bffd764..6e4ad5a 100644
--- a/core/command_service.py
+++ b/core/command_service.py
@@ -66,6 +66,10 @@ class CommandService:
self.register_command_channel("Private Message", self.PRIVATE_MESSAGE_CHANNEL)
self.register_command_channel("Org Channel", self.ORG_CHANNEL)
self.register_command_channel("Private Channel", self.PRIVATE_CHANNEL)
+ self.relay_hub_service.register_message_source("tell_logger")
+ self.relay_hub_service.register_message_source("system_logger")
+ self.relay_hub_service.register_message_source("access_denied_logger")
+ self.relay_hub_service.register_message_source("member_logger")
def start(self):
access_levels = {}
@@ -205,16 +209,10 @@ class CommandService:
if not followup:
if channel == "msg":
if message.lower().startswith("mail"):
- self.relay_hub_service.send_message("tell_logger", char_id, "mail |usage hidden|",
- "mail |usage hidden|")
+ self.relay_hub_service.send_message("tell_logger", DictObject({'char_id': char_id, 'name': self.character_service.resolve_char_to_name(char_id)}), f"[FROM] {self.character_service.resolve_char_to_name(char_id)}: mail |usage hidden|",
+ f"[FROM] {self.character_service.resolve_char_to_name(char_id)}: mail |usage hidden|")
else:
- self.relay_hub_service.send_message("tell_logger", char_id, message, message)
- else:
- if message.lower().startswith("mail"):
- self.relay_hub_service.send_message("dc_relay_log", char_id, "mail |usage hidden|",
- "mail |usage hidden|")
- else:
- self.relay_hub_service.send_message("dc_relay_log", char_id, message, message)
+ self.relay_hub_service.send_message("tell_logger", DictObject({'char_id': char_id, 'name': self.character_service.resolve_char_to_name(char_id)}), f"[FROM] {self.character_service.resolve_char_to_name(char_id)}: {message}", f"[FROM] {self.character_service.resolve_char_to_name(char_id)}: {message}")
# message = html.unescape(message)
command_str, command_args = self.get_command_parts(message)
@@ -253,12 +251,15 @@ class CommandService:
self.relay_hub_service.send_message("access_denied_logger", sender,
f"[ERROR] {sender.name}: {message}",
f"[ERROR] {sender.name}: {message}")
- self.bot.send_mass_message(char_id, self.getresp("global", "error_processing"))
+ if channel == "discord":
+ reply(self.getresp("global", "error_processing"))
+ else:
+ self.bot.send_mass_message(char_id, self.getresp("global", "error_processing"))
# record command usage
self.usage_service.add_usage(command_str, handler["callback"].__qualname__, char_id, channel)
else:
- self.access_denied_response(message, sender, cmd_config, reply)
+ self.access_denied_response(message, sender, cmd_config, reply, channel)
else:
# handlers were found, but no handler regex matched
help_text = self.get_help_text(char_id, command_str, channel)
@@ -266,7 +267,7 @@ class CommandService:
reply(self.format_help_text(command_str, help_text))
else:
# the command is known, but no help is returned, therefore user does not have access to command
- self.access_denied_response(message, sender, cmd_config, reply)
+ self.access_denied_response(message, sender, cmd_config, reply, channel)
# if access_level['label'] != "all":
# self.relay_hub_service.send_message("access_denied_logger", sender,
# f"[DENIED] {sender.name}: {message}",
@@ -280,20 +281,29 @@ class CommandService:
0)
self.relay_hub_service.send_message("access_denied_logger", sender, f"[ERROR] {sender.name}: {message}",
f"[ERROR] {sender.name}: {message}")
- self.bot.send_mass_message(char_id, self.getresp("global", "error_processing"))
+ if channel == "discord":
+ reply(self.getresp("global", "error_processing"))
+ else:
+ self.bot.send_mass_message(char_id, self.getresp("global", "error_processing"))
def handle_unknown_command(self, command_str, command_args, channel, sender, reply):
self.relay_hub_service.send_message("access_denied_logger", sender,
f"[UNKNOWN] {sender.name}: {command_str} {command_args}",
f"[UNKNOWN] {sender.name}: {command_str} {command_args}")
if sender.access_level["label"] != "all":
- self.bot.send_mass_message(sender.char_id, self.getresp("global", "unknown_command", {"cmd": command_str}))
+ if channel == "discord":
+ self.getresp("global", "unknown_command", {"cmd": command_str})
+ else:
+ self.bot.send_mass_message(sender.char_id, self.getresp("global", "unknown_command", {"cmd": command_str}))
- def access_denied_response(self, message, sender, cmd_config, reply):
+ def access_denied_response(self, message, sender, cmd_config, reply, channel):
self.relay_hub_service.send_message("access_denied_logger", sender, f"[DENIED] {sender.name}: {message}",
f"[DENIED] {sender.name}: {message}")
if sender.access_level["label"] != "all":
- self.bot.send_mass_message(sender.char_id, self.getresp("global", "access_denied"))
+ if channel == "discord":
+ reply(self.getresp("global", "access_denied"))
+ else:
+ self.bot.send_mass_message(sender.char_id, self.getresp("global", "access_denied"))
def get_command_parts(self, message):
parts = message.split(" ", 1)
diff --git a/core/conn.py b/core/conn.py
index b8844db..b35ddf4 100644
--- a/core/conn.py
+++ b/core/conn.py
@@ -53,8 +53,8 @@ class Conn(Bot):
if num_messages > 30:
self.logger.warning("automatically clearing outgoing message queue (%d messages)" % num_messages)
self.packet_queue.clear()
- elif num_messages > 10:
- self.logger.warning("%d messages in outgoing message queue" % num_messages)
+ # elif num_messages > 10:
+ # self.logger.warning("%d messages in outgoing message queue" % num_messages)
def __str__(self):
return self.id
diff --git a/core/igncore.py b/core/igncore.py
index c98d5c8..7fd7d0c 100644
--- a/core/igncore.py
+++ b/core/igncore.py
@@ -1,6 +1,7 @@
import inspect
import threading
import time
+import typing
from conf.config import BotConfig
from core.aochat import server_packets, client_packets
@@ -11,15 +12,19 @@ from core.conn import Conn
from core.db import DB
from core.decorators import instance
from core.dict_object import DictObject
+
from core.fifo_queue import FifoQueue
from core.job_scheduler import JobScheduler
from core.logger import Logger
-from core.lookup.character_service import CharacterService
-from core.public_channel_service import PublicChannelService
-from core.setting_service import SettingService
-from core.setting_types import BooleanSettingType
from core.text import Text
-from modules.core.accounting.services.access_service import AccessService
+from core.setting_types import BooleanSettingType
+
+if typing.TYPE_CHECKING:
+ from core.lookup.character_service import CharacterService
+ from core.public_channel_service import PublicChannelService
+ from core.setting_service import SettingService
+ from modules.core.accounting.services.access_service import AccessService
+ from core.event_service import EventService
@instance("bot")
@@ -42,8 +47,8 @@ class IgnCore:
self.dimension = None
self.last_timer_event = 0
self.start_time = int(time.time())
- self.major_version = "IGNCore v2.8"
- self.minor_version = "4"
+ self.major_version = "IGNCore v2.9"
+ self.minor_version = "0"
self.incoming_queue = FifoQueue()
self.mass_message_queue = None
self.conns = DictObject()
@@ -55,7 +60,7 @@ class IgnCore:
self.text: Text = registry.get_instance("text")
self.setting_service: SettingService = registry.get_instance("setting_service")
self.access_service: AccessService = registry.get_instance("access_service")
- self.event_service = registry.get_instance("event_service")
+ self.event_service: EventService = registry.get_instance("event_service")
self.job_scheduler: JobScheduler = registry.get_instance("job_scheduler")
self.command_service = registry.get_instance("command_service")
@@ -113,7 +118,7 @@ class IgnCore:
"created_at INT NOT NULL, "
"INDEX `command` (`command`) USING BTREE, "
"INDEX `char_id` (`char_id`) USING BTREE, "
- "INDEX `channel` (`channel`) USING BTREE) ENGINE MEMORY")
+ "INDEX `channel` (`channel`) USING BTREE)")
# self.db.exec("UPDATE db_version SET verified = 0")
self.db.exec("UPDATE db_version SET verified = 1 WHERE file = 'db_version'")
@@ -440,5 +445,8 @@ class IgnCore:
def get_char_name(self):
return self.conns["main"].char_name
+ def get_conn(self):
+ return self.conns["main"]
+
def get_char_id(self):
return self.conns["main"].char_id
diff --git a/core/logger.py b/core/logger.py
index e890e8d..c4558b1 100644
--- a/core/logger.py
+++ b/core/logger.py
@@ -32,6 +32,8 @@ class Logger:
def format_chat_message(self, msg):
msg = re.sub(r"", "[link]", msg, flags=re.UNICODE | re.DOTALL)
msg = re.sub(r"", "[link]", msg, flags=re.UNICODE | re.DOTALL)
+ msg = re.sub(r"(\w+?)", "\1", msg, flags=re.UNICODE | re.DOTALL)
+
msg = re.sub(r"", "", msg, flags=re.UNICODE)
msg = re.sub("", "", msg, flags=re.UNICODE)
msg = re.sub("", "[/link]", msg, flags=re.UNICODE)
diff --git a/core/message_hub_service.py b/core/message_hub_service.py
index 65b0209..ee1c277 100644
--- a/core/message_hub_service.py
+++ b/core/message_hub_service.py
@@ -50,7 +50,9 @@ class MessageHubService:
f"Incorrect number of arguments for handler '{callback.__module__}.{callback.__name__}()'")
if destination in self.hub:
- raise Exception(f"Message hub destination '{destination}' already subscribed")
+ self.logger.error(f"Message hub destination '{destination}' already subscribed")
+ return
+ # raise Exception(f"Message hub destination '{destination}' already subscribed")
for source in default_sources:
if source not in self.sources:
diff --git a/core/setting_service.py b/core/setting_service.py
index 8b3dab2..5de59d8 100644
--- a/core/setting_service.py
+++ b/core/setting_service.py
@@ -39,6 +39,7 @@ class SettingService:
if module.split(".")[0] not in self.bot.modules:
return
setting.set_name(name)
+ setting.module = module
setting.set_description(description)
setting.set_extended_description(extended_description)
diff --git a/core/setting_types.py b/core/setting_types.py
index 19484a2..119df29 100644
--- a/core/setting_types.py
+++ b/core/setting_types.py
@@ -9,6 +9,7 @@ class SettingType:
def __init__(self):
self.setting_service = Registry.get_instance("setting_service")
self.name = None
+ self.module = ""
def set_name(self, name):
self.name = name
diff --git a/modules/core/accounting/account_controller.py b/modules/core/accounting/account_controller.py
index e1d34c0..49201e4 100644
--- a/modules/core/accounting/account_controller.py
+++ b/modules/core/accounting/account_controller.py
@@ -274,4 +274,4 @@ class AccountController:
rows = self.account_service.get_logs(alts[0].char_id, limit=20)
for i in rows:
response += self.account_service.format_entry(i)
- return self.text.format_page(f"{alts[0].name}'s Account", response)
+ return ChatBlob(f"{alts[0].name}'s Account", response)
diff --git a/modules/core/accounting/preference_controller.py b/modules/core/accounting/preference_controller.py
index 454cc41..0d2077d 100644
--- a/modules/core/accounting/preference_controller.py
+++ b/modules/core/accounting/preference_controller.py
@@ -1,3 +1,5 @@
+import typing
+
from core.buddy_service import BuddyService
from core.chat_blob import ChatBlob
from core.command_alias_service import CommandAliasService
@@ -11,8 +13,9 @@ from core.text import Text
from core.translation_service import TranslationService
from core.igncore import IgnCore
from core.util import Util
-from modules.core.accounting.services.account_service import AccountService
-from modules.core.discord.discord_controller import DiscordController
+if typing.TYPE_CHECKING:
+ from modules.core.accounting.services.account_service import AccountService
+ from modules.core.discord.discord_controller import DiscordController
@instance()
diff --git a/modules/core/config/config.msg b/modules/core/config/config.msg
index 52751fe..ebd0b72 100644
--- a/modules/core/config/config.msg
+++ b/modules/core/config/config.msg
@@ -135,6 +135,12 @@
"en_US": "Could not find setting {setting}.",
"de_DE": "Die Einstellung {setting} wurde nicht gefunden."
},
+
+ "setting_owner": {
+ "en_US": "Setting owned by module: {value}\n",
+ "de_DE": "Diese Einstellung gehört zu dem Modul: {value}\n"
+
+ },
"current_value": {
"en_US": "Current Value: {value}\n",
"de_DE": "Aktueller Wert: {value}\n"
diff --git a/modules/core/config/config_controller.py b/modules/core/config/config_controller.py
index a5ae0f1..3a1a1c8 100644
--- a/modules/core/config/config_controller.py
+++ b/modules/core/config/config_controller.py
@@ -160,6 +160,7 @@ class ConfigController:
setting = self.setting_service.get(setting_name)
if setting:
+ blob += self.getresp("module/config", "setting_owner", {"value": str(setting.module)})
blob += self.getresp("module/config", "current_value", {"value": str(setting.get_display_value())})
blob += self.getresp("module/config", "description", {"desc": setting.get_description()})
if setting.get_extended_description():
diff --git a/modules/core/discord/discord_command_handler.py b/modules/core/discord/discord_command_handler.py
new file mode 100644
index 0000000..12944a1
--- /dev/null
+++ b/modules/core/discord/discord_command_handler.py
@@ -0,0 +1,382 @@
+import asyncio
+import threading
+import time
+
+import re
+from mailbox import Message
+from typing import TYPE_CHECKING
+
+from discord import Activity, ActivityType, Message, Embed
+
+from core.aochat.BaseModule import BaseModule
+from core.chat_blob import ChatBlob
+from core.command_param_types import Const
+
+from core.db import DB
+from core.decorators import instance, command, event, timerevent
+from core.dict_object import DictObject
+from core.logger import Logger
+from modules.core.ban.ban_service import BanService
+
+if TYPE_CHECKING:
+ from modules.core.discord.discord_controller import DiscordController
+ from core.message_hub_service import MessageHubService
+ from core.command_service import CommandService
+
+
+@instance()
+class DiscordCommandHandler(BaseModule):
+ DISCORD_CHANNEL = "discord"
+
+ def __init__(self):
+ self.logger = Logger(__name__)
+
+ def inject(self, registry):
+ self.bot = registry.get_instance("bot")
+ self.discord: DiscordController = registry.get_instance("discord_controller")
+ self.db: DB = registry.get_instance("db")
+ self.relay_hub_service: MessageHubService = registry.get_instance("message_hub_service")
+ self.command_service: CommandService = registry.get_instance("command_service")
+
+ def pre_start(self):
+ self.command_service.register_command_channel("Discord", self.DISCORD_CHANNEL)
+
+ @event("discord_command", "should the bot take care of discord commands", False)
+ def discord_command_handler(self, _, event_data):
+ acc = event_data.account
+ ctx: Message = event_data.message
+ message = ctx.clean_content
+ if message.startswith(self.discord.setting_service.get("symbol").get_value()):
+ threading.Thread(target=self.command_service.process_command(
+ self.command_service.trim_command_symbol(message),
+ self.DISCORD_CHANNEL,
+ acc.main,
+ lambda msg: self.send_response(ctx, msg),
+ self.discord.bot.get_conn(),
+ False), daemon=True).start()
+
+ def send_response(self, ctx: Message, reply):
+ rsp = ""
+ embeds = []
+ if type(reply) == str:
+ reply = self.discord.text.format_message(reply)
+ rsp = f"> {self.parseDiscord(reply)}"
+ self.discord.relay_hub_service.send_message(f"Discord_({ctx.channel.name})",
+ DictObject({'char_id': 0, 'name': ctx.author.name,
+ 'discord_handle':
+ f'{ctx.author.name}#{ctx.author.discriminator}'}),
+ reply, reply)
+ if type(reply) == ChatBlob:
+ if reply.embed:
+ embeds.append(Embed(title=self.parseDiscord(f"{reply.page_prefix} {reply.title} {reply.page_postfix}"),
+ color=0x00FF00,
+ description=self.parseDiscord(reply.msg).replace("\n> ", '\n')))
+
+ else:
+ reply: ChatBlob
+ rsp = self.parseDiscord(reply.page_prefix) + "\n"
+ if not (self.discord.text.strip_html_tags(reply.msg) or reply.msg).startswith(reply.title):
+ rsp += f"**__{reply.title}__**\n"
+ rsp += "> " + self.parseDiscord(reply.msg)
+ rsp += f"\n {self.parseDiscord(reply.page_postfix)}"
+ self.discord.relay_hub_service.send_message(f"Discord_({ctx.channel.name})",
+ DictObject({'char_id': 0, 'name': ctx.author.name,
+ 'discord_handle':
+ f'{ctx.author.name}#{ctx.author.discriminator}'}),
+ reply, reply)
+ if len(rsp) > 2000:
+ rsp = self.discord.text.split_by_separators(rsp, 2000)
+ for page in rsp:
+ self.discord.client.loop.create_task(ctx.reply(page))
+ else:
+ self.discord.client.loop.create_task(ctx.reply(rsp, embeds=embeds))
+
+ def parseDiscord(self, ctx: str):
+ proficon = {1: "sold", 2: "ma", 3: "eng", 4: "fixer", 5: "agent", 6: "adv", 7: "trad", 8: "crat", 9: "enf",
+ 10: "doc", 11: "nt", 12: "mp", 14: "keep", 15: "shade"}
+ m = re.findall(r"
", ctx)
+ for match in m:
+ ctx = ctx.replace(f"
",
+ f"#_{self.discord.util.get_profession(proficon.get(int(match)))}#_")
+
+ for x in ["`", ' *', ' _', ' |']:
+ ctx = ctx.replace(x, f' \\{x.strip()}')
+ for pattern, sub in [(r"(
|\n|)", r"\n> "),
+ (r"(.*?)", r"**\1**"),
+ (r"
(.*?)", r"**__\1__**"),
+ (r"", r"**__\1__**"),
+ (r"(.*?)", r"__\1__"),
+ (r"(.*?)", r"*\1*"),
+ (r"(.*?)", r'\2'),
+ (r"", self.bot.get_char_name()),
+ (r"", self.discord.setting_service.get_value("symbol")),
+ (r"(.+?)<\/a>", r"`\2`"),
+ (r"<(.+?)>\s*?<\1>", ''),
+ (r"", ''),
+ (r"(.*?)", r'`\1`'),
+ (r"(.*?)", r":yellow_circle: \1"),
+ (r"(.*?)", r":blue_circle: \1"),
+ (r"(.*?)", r":white_circle: \1"),
+ (r"", "\t"),
+ (r"
", ''),
+ ('#', ''),
+ ('<', '<'),
+ ('>', '>')]:
+ ctx = re.sub(pattern, sub, ctx)
+
+ cnt = 1
+ while cnt > 0:
+ ctx, cnt = re.subn(r"<(black|white|yellow|blue|green|red|orange|grey|cyan|violet)>(.*?|\d+?)\1>", r"\2",
+ ctx)
+
+ ctx.rstrip()
+ ctx.rstrip(">")
+ return ctx
+
+ @command(command="discord", params=[Const("invite")], access_level="member",
+ description="Get a personal Discord invite", sub_command="invite")
+ def discord_invite_cmd(self, request, _):
+ if not self.discord.client:
+ return "Discord module has not been initiated yet. Please try again later."
+ account = self.discord.account_service.get_account(request.sender.char_id)
+ if account is None:
+ return "You do not have an account"
+ if account.disabled == 1:
+ return "Your account is disabled"
+ if account.discord_joined == 1:
+ return "You have already joined the Discord server"
+ if account.discord_invite != "":
+ for ginvite in self.discord.invites:
+ if ginvite.code == account.discord_invite:
+ asyncio.run_coroutine_threadsafe(self.discord.discord_delete_invite(ginvite), self.discord.loop)
+ invite = asyncio.run_coroutine_threadsafe(self.discord.discord_create_invite(account.name), self.discord.loop)
+ invite = invite.result()
+ self.discord.data.set_discord_invite(account.char_id, invite.code)
+ self.bot.send_mass_message(request.sender.char_id,
+ f"Your personal Discord invite is: {invite} \n"
+ f"This invite is only valid for 5 minutes.")
+
+ @command(command="discord", params=[Const("update")], access_level="member",
+ description="Update your discord information", sub_command="update")
+ def discord_update_cmd(self, request, _):
+ if not self.discord.client:
+ return "Discord module has not been initiated yet. Please try again later."
+ return self.discord.discord_update_account(request.sender.char_id)
+
+ @command(command="discord", params=[Const("disconnect")], access_level="admin",
+ description="Disconnect from Discord", sub_command="admin")
+ def discord_disconnect_cmd(self, _, _1):
+ if not self.discord.client:
+ return "Discord module has not been initiated yet. Please try again later."
+ if self.discord.client.is_closed():
+ return "Discord is already disconnected"
+ else:
+ asyncio.run_coroutine_threadsafe(self.discord.discord_disconnect(), self.discord.loop)
+ return "Disconnecting Discord"
+
+ @command(command="discord",
+ params=[Const("members")],
+ access_level="admin",
+ description="Get all discord members",
+ sub_command="members")
+ def discord_members_cmd(self, _, _1):
+ if not self.discord.client:
+ return "Discord module has not been initiated yet. Please try again later."
+ blob = ""
+ for member in self.discord.guild.members:
+ member_roles = []
+ for role in member.roles:
+ if role.name == "@everyone": # Skip @everyone as everyone has it.
+ continue
+ member_roles.append(f"{role.name}")
+ member_roles.sort(key=str.lower)
+ blob += f"{member.name + '#' + member.discriminator} ({', '.join(member_roles)})\n"
+ return ChatBlob(f"Discord Members ({len(self.discord.guild.members):d})", blob)
+
+ @event(event_type="connect", description="Connects the Discord client automatically on startup, if a token exists")
+ def handle_connect_event(self, _, _1):
+ token = self.discord.setting_discord_token().get_value()
+ if token.lower() in ["none", "", "null"]:
+ return
+
+ # noinspection PyTypeChecker
+ self.discord.loop = asyncio.get_event_loop()
+ self.discord.loop.create_task(self.discord.discord_connect(token))
+ self.discord.thread = threading.Thread(target=self.discord.run_it_forever, daemon=True)
+ self.discord.thread.start()
+
+ @event(event_type=BanService.BAN_ADDED_EVENT, description="Ban user from Discord")
+ def ban_added_event(self, _, event_data):
+ token = self.discord.setting_discord_token().get_value()
+ if token.lower() in ["none", "", "null"]:
+ return
+ account = self.discord.account_service.get_account(event_data.char_id)
+ if account.discord_joined == 1 and account.discord_id != "":
+ member = self.discord.guild.get_member(int(account.discord_id))
+ if member is not None:
+ ban = asyncio.run_coroutine_threadsafe(self.discord.discord_ban_user(member, event_data.reason),
+ self.discord.client.loop)
+
+ @event(event_type=BanService.BAN_REMOVED_EVENT, description="Remove Discord ban")
+ def ban_removed_event(self, _, event_data):
+ token = self.discord.setting_discord_token().get_value()
+ if token.lower() in ["none", "", "null"]:
+ return
+ account = self.discord.account_service.get_account(event_data.char_id)
+ if account.discord_id != "":
+ banlist = asyncio.run_coroutine_threadsafe(self.discord.discord_banlist(), self.discord.client.loop)
+ banlist = banlist.result()
+ for ban in banlist:
+ if ban.user.id == int(account.discord_id):
+ unban = asyncio.run_coroutine_threadsafe(self.discord.discord_unban_user(ban.user),
+ self.discord.client.loop)
+
+ @timerevent(budatime="1s", description="Handle Discord queue")
+ def timer_check_discord_queue(self, _, _1):
+ while self.discord.discord_queue:
+ t = int(time.time())
+ obj = self.discord.discord_queue.pop(0)
+ if obj.type == "on_member_remove":
+ member = obj.member
+ handle = member.name + "#" + member.discriminator
+
+ account = self.discord.data.get_account_discord_id(member.id)
+ if not account:
+ log = '**%s** has left discord (**%s**)' % (member.nick or member.name, handle)
+ self.relay_hub_service.send_message("system_logger", 0, log, log)
+ self.logger.info(log)
+ continue
+ main = self.discord.account_service.get_main(account.char_id)
+ if account is None:
+ continue
+ log = '**%s** has left discord (**%s**)' % (main.name, handle)
+ self.relay_hub_service.send_message("system_logger", 0, log, log)
+ self.logger.info(log)
+ # self.bot.send_private_channel_message("%s has left Discord (%s)" % (main.name, handle))
+ self.discord.data.set_discord_left(account.main)
+ if account.discord_handle != handle:
+ self.discord.data.set_discord_handle(member.id, handle)
+ if obj.type == "on_member_join":
+ member = obj.member
+ invite_used = obj.invite
+ handle = member.name + "#" + member.discriminator
+ if invite_used is None:
+ log = '**%s** joined discord with unknown invite' % handle
+ self.relay_hub_service. \
+ send_message("system_logger", 0,
+ log + f" {self.get_role('Administrator', self.guild.roles).mention}'s, "
+ f"check that!",
+ log + f" {self.get_role('Administrator', self.guild.roles).mention}'s, "
+ f"check that!")
+ self.logger.info(log)
+ continue
+ self.discord.guild = self.discord.client.get_guild(self.discord.client.guilds[0].id)
+ account = self.discord.data.get_discord_invite(invite_used.code)
+ if account is None:
+ log = '**%s** joined discord with invite **%s** but couldnt find account!' % (
+ handle, invite_used.code)
+ self.relay_hub_service. \
+ send_message("system_logger", 0,
+ log + f" {self.get_role('Administrator', self.guild.roles).mention}'s, "
+ f"check that!",
+ log + f" {self.get_role('Administrator', self.guild.roles).mention}'s, "
+ f"check that!")
+ self.logger.info(log)
+ asyncio.run_coroutine_threadsafe(self.discord.discord_member_roles(member, None, None),
+ self.discord.loop)
+ continue
+
+ main = self.discord.account_service.get_main(account.main)
+ self.discord.data.set_discord_joined(account.main, handle, member.id)
+ if self.discord.setting_service.get_value('is_alliance_bot') == '1':
+ nick = f"{f'[{self.discord.alias_controller.get_alias(main.org_id)}] '}{main.name}"
+ else:
+ nick = f"{main.name}"
+ nick = asyncio.run_coroutine_threadsafe(self.discord.discord_member_nick(member, nick),
+ self.discord.loop)
+ access_level = access_level = self.discord.access_service.get_access_level(account.main)
+ roles = asyncio.run_coroutine_threadsafe(
+ self.discord.discord_member_roles(member, account, access_level),
+ self.discord.loop)
+ # noinspection LongLine
+ log = '**%s** joined discord with invite **%s** and matches account **%s**' \
+ % (handle, invite_used.code,
+ f"{f'[{self.discord.alias_controller.get_alias(main.org_id)}] ' if self.discord.setting_service.get_value('is_alliance_bot') == '1' else ''}{main.name}")
+ self.relay_hub_service.send_message("system_logger", account.main, log, log)
+ self.logger.info(log)
+
+ @timerevent(budatime="1h", description="Verify Discord members", run_at_startup=True)
+ def timer_check_discord_members(self, event_type, event_data):
+ token = self.discord.setting_discord_token().get_value()
+ if token.lower() in ["none", "", "null"]:
+ return
+ if not self.bot.is_ready():
+ return
+ update = asyncio.run_coroutine_threadsafe(self.discord.discord_update_bot_basic(), self.discord.loop)
+ # Update accounts that have left/joined discord without the bot being online
+ accounts = self.db.query("SELECT * FROM account WHERE discord_id !=''")
+ for account in accounts:
+ match = False
+ for member in self.discord.guild.members:
+ handle = member.name + "#" + member.discriminator
+ if member.id == int(account.discord_id):
+ match = True
+ if account.discord_joined == 0:
+ self.discord.data.set_discord_joined(account.main, handle, member.id)
+ break
+ if match is False:
+ if account.discord_joined == 1:
+ self.discord.data.set_discord_left(account.main)
+ # Update current discord Members
+ accounts = self.discord.db.query("SELECT * FROM account WHERE discord_joined = 1 and char_id = main")
+ for member in self.discord.guild.members:
+ if member.id == self.discord.client.user.id:
+ continue
+ member_account = None
+
+ for account in list(accounts):
+ if int(account.discord_id) == member.id:
+ member_account = account
+ accounts.remove(account)
+ break
+ access_level = 0
+ if member_account is not None:
+ access_level = self.discord.access_service.get_access_level(member_account.main)
+ roles = asyncio.run_coroutine_threadsafe(
+ self.discord.discord_member_roles(member, member_account, access_level),
+ self.discord.loop)
+ if member_account is not None:
+ main = self.discord.pork.get_character_info(member_account.main)
+ # noinspection LongLine
+ nick = f"{f'[{self.discord.alias_controller.get_alias(main.org_id)}] ' if self.discord.setting_service.get_value('is_alliance_bot') == '1' else ''}{main.name}"
+
+ nick = asyncio.run_coroutine_threadsafe(self.discord.discord_member_nick(member, nick),
+ self.discord.loop)
+
+ @event(event_type="main_changed", description="Fix discord names & ranks")
+ def fix_ranks(self, _, data):
+ row = self.db.query_single("SELECT * from account where char_id=?", [data.old_main_id])
+ if row.discord_joined == 0:
+ self.logger.debug(f"{data.old_main_id} was not in discord, ignoring main fixing")
+ return
+ elif row.discord_joined == 1:
+ self.db.exec(
+ "UPDATE account set discord_handle=?, discord_id=?, discord_invite=?, discord_joined=? where char_id=?",
+ [row.discord_handle, row.discord_id, row.discord_invite, row.discord_joined, data.new_main_id])
+ self.db.exec(
+ "UPDATE account set discord_handle='', discord_id=0, discord_invite='', discord_joined=0 "
+ "where char_id=?",
+ [data.old_main_id])
+ self.logger.info(f"{data.old_main_id} was in discord, overwriting {data.new_main_id} with {data}")
+
+ self.discord.discord_update_account(data.new_main_id)
+
+ @timerevent(budatime="5m", description="update activity")
+ def change_count(self, _, _1):
+ if hasattr(self, "loop"):
+ count = self.db.query_single('SELECT count(*) as count from online '
+ 'where char_id NOT IN (select char_id from org_bots) and bot=?',
+ [self.bot.get_char_id()]).count
+ act = Activity(type=ActivityType.listening,
+ name=f"{count} Players")
+ asyncio.run_coroutine_threadsafe(self.discord.client.change_presence(activity=act), self.discord.loop)
diff --git a/modules/core/discord/discord_controller.py b/modules/core/discord/discord_controller.py
index e5c7b6c..25e8345 100644
--- a/modules/core/discord/discord_controller.py
+++ b/modules/core/discord/discord_controller.py
@@ -1,36 +1,38 @@
import asyncio
-import html
import logging
import re
-import threading
import time
-from asyncio import BaseEventLoop
+from datetime import datetime, timedelta
+from functools import partial
from html.parser import HTMLParser
# noinspection PyPackageRequirements
-import discord
-import emojis as emojis
-# noinspection PyPackageRequirements
-from discord import Message, TextChannel, Guild, Embed, Role
+from typing import TYPE_CHECKING
+# noinspection PyPackageRequirements
+import discord
+from discord import Message, TextChannel, Embed, Role, Guild
from core.chat_blob import ChatBlob
-from core.command_param_types import Const
from core.db import DB
-from core.decorators import instance, command, event, timerevent
+from core.decorators import instance, event, timerevent
from core.dict_object import DictObject
from core.logger import Logger
-from core.lookup.character_service import CharacterService
-from core.lookup.pork_service import PorkService
-from core.message_hub_service import MessageHubService
-from core.setting_service import SettingService
-from core.setting_types import HiddenSettingType
+from core.setting_types import HiddenSettingType, NumberSettingType, TextSettingType, BooleanSettingType
from core.text import Text
from core.igncore import IgnCore
from core.util import Util
-from modules.core.accounting.services.access_service import AccessService
-from modules.core.accounting.services.account_service import AccountService
-from modules.core.ban.ban_service import BanService
-from modules.onlinebot.online.org_alias_controller import OrgAliasController
+from modules.core.discord.discord_data import DiscordData
+from modules.core.discord.discord_management import DiscordManager
+
+if TYPE_CHECKING:
+ from modules.core.accounting.services.access_service import AccessService
+ from modules.core.accounting.services.account_service import AccountService
+ from modules.onlinebot.online.org_alias_controller import OrgAliasController
+ from modules.core.discord.discord_command_handler import DiscordCommandHandler
+ from core.lookup.character_service import CharacterService
+ from core.lookup.pork_service import PorkService
+ from core.message_hub_service import MessageHubService
+ from core.setting_service import SettingService
class MLStripper(HTMLParser):
@@ -61,18 +63,11 @@ class DiscordController:
logging.getLogger("discord.gateway").setLevel(logging.WARN)
logging.getLogger("discord.client").setLevel(logging.WARN)
intents = discord.Intents.all()
+ intents.message_content = True
self.client = discord.Client(intents=intents, chunk_guilds_at_startup=True)
- self.client.event(self.on_ready)
- self.client.event(self.on_member_join)
- self.client.event(self.on_member_remove)
- self.client.event(self.on_member_update)
- self.client.event(self.on_guild_role_delete)
- self.client.event(self.on_guild_role_create)
- self.client.event(self.on_guild_role_update)
- self.client.event(self.on_invite_create)
- self.client.event(self.on_invite_delete)
+ self.manager: DiscordManager = DiscordManager(self)
self.client.event(self.on_message)
- self.guild = None
+ self.guild: Guild = None
self.channel = None
self.thread = None
self.invites = None
@@ -106,9 +101,17 @@ class DiscordController:
self.account_service: AccountService = registry.get_instance("account_service")
self.setting_service: SettingService = registry.get_instance("setting_service")
+ self.data: DiscordData = DiscordData(self.db, self.client)
+ self.cmd: DiscordCommandHandler = registry.get_instance("discord_command_handler")
+
def pre_start(self):
self.setting_service.register(self.module_name, "discord_token", "", HiddenSettingType(allow_empty=True),
"Enter your Discord token here")
+ self.setting_service.register(self.module_name, "public_relay", "[0]", TextSettingType(),
+ "Public discord relay (purpose: autodelete messages after 1h)")
+ self.setting_service.register(self.module_name, "channel_blacklist", "[0]", TextSettingType(),
+ "Channels which should not trigger the command handler")
+ self.bot.event_service.register_event_type("discord_command")
def get_name(self, discord_id):
data = self.db.query_single(
@@ -118,242 +121,9 @@ class DiscordController:
def setting_discord_token(self):
return self.setting_service.get("discord_token")
- @command(command="discord", params=[Const("invite")], access_level="member",
- description="Get a personal Discord invite", sub_command="invite")
- def discord_invite_cmd(self, request, _):
- if not self.client:
- return "Discord module has not been initiated yet. Please try again later."
- account = self.account_service.get_account(request.sender.char_id)
- if account is None:
- return "You do not have an account"
- if account.disabled == 1:
- return "Your account is disabled"
- if account.discord_joined == 1:
- return "You have already joined the Discord server"
- if account.discord_invite != "":
- for ginvite in self.invites:
- if ginvite.code == account.discord_invite:
- asyncio.run_coroutine_threadsafe(self.discord_delete_invite(ginvite), self.loop)
- invite = asyncio.run_coroutine_threadsafe(self.discord_create_invite(account.name), self.loop)
- invite = invite.result()
- self.set_discord_invite(account.char_id, invite.code)
- self.bot.send_mass_message(request.sender.char_id,
- f"Your personal Discord invite is: {invite} \n"
- f"This invite is only valid for 5 minutes.")
-
- @command(command="discord", params=[Const("update")], access_level="member",
- description="Update your discord information", sub_command="update")
- def discord_update_cmd(self, request, _):
- if not self.client:
- return "Discord module has not been initiated yet. Please try again later."
- return self.discord_update_account(request.sender.char_id)
-
- @command(command="discord", params=[Const("disconnect")], access_level="admin",
- description="Disconnect from Discord", sub_command="admin")
- def discord_disconnect_cmd(self, _, _1):
- if not self.client:
- return "Discord module has not been initiated yet. Please try again later."
- if self.client.is_closed():
- return "Discord is already disconnected"
- else:
- asyncio.run_coroutine_threadsafe(self.discord_disconnect(), self.loop)
- return "Disconnecting Discord"
-
- @command(command="discord",
- params=[Const("members")],
- access_level="admin",
- description="Get all discord members",
- sub_command="members")
- def discord_members_cmd(self, _, _1):
- if not self.client:
- return "Discord module has not been initiated yet. Please try again later."
- blob = ""
- for member in self.guild.members:
- member_roles = []
- for role in member.roles:
- if role.name == "@everyone": # Skip @everyone as everyone has it.
- continue
- member_roles.append("%s" % role.name)
- member_roles.sort(key=str.lower)
- blob += "%s (%s)\n" % (member.name + "#" + member.discriminator, ", ".join(member_roles))
- return ChatBlob("Discord Members (%d)" % (len(self.guild.members)), blob)
-
- @event(event_type="connect", description="Connects the Discord client automatically on startup, if a token exists")
- def handle_connect_event(self, _, _1):
- token = self.setting_discord_token().get_value()
- if token.lower() in ["none", "", "null"]:
- return
-
- # noinspection PyTypeChecker
- self.loop: BaseEventLoop = asyncio.get_event_loop()
- self.loop.create_task(self.discord_connect(token))
- self.thread = threading.Thread(target=self.run_it_forever, daemon=True)
- self.thread.start()
-
- @event(event_type=BanService.BAN_ADDED_EVENT, description="Ban user from Discord")
- def ban_added_event(self, _, event_data):
- token = self.setting_discord_token().get_value()
- if token.lower() in ["none", "", "null"]:
- return
- account = self.account_service.get_account(event_data.char_id)
- if account.discord_joined == 1 and account.discord_id != "":
- member = self.guild.get_member(int(account.discord_id))
- if member is not None:
- ban = asyncio.run_coroutine_threadsafe(self.discord_ban_user(member, event_data.reason), self.loop)
-
- @event(event_type=BanService.BAN_REMOVED_EVENT, description="Remove Discord ban")
- def ban_removed_event(self, _, event_data):
- token = self.setting_discord_token().get_value()
- if token.lower() in ["none", "", "null"]:
- return
- account = self.account_service.get_account(event_data.char_id)
- if account.discord_id != "":
- banlist = asyncio.run_coroutine_threadsafe(self.discord_banlist(), self.loop)
- banlist = banlist.result()
- for ban in banlist:
- if ban.user.id == int(account.discord_id):
- unban = asyncio.run_coroutine_threadsafe(self.discord_unban_user(ban.user), self.loop)
-
- @timerevent(budatime="1s", description="Handle Discord queue")
- def timer_check_discord_queue(self, _, _1):
- while self.discord_queue:
- t = int(time.time())
- obj = self.discord_queue.pop(0)
- if obj.type == "on_member_remove":
- member = obj.member
- handle = member.name + "#" + member.discriminator
-
- account = self.get_account_discord_id(member.id)
- if not account:
- log = '**%s** has left discord (**%s**)' % (member.nick or member.name, handle)
- self.relay_hub_service.send_message("system_logger", 0, log, log)
- self.logger.info(log)
- continue
- main = self.account_service.get_main(account.char_id)
- if account is None:
- continue
- log = '**%s** has left discord (**%s**)' % (main.name, handle)
- self.relay_hub_service.send_message("system_logger", 0, log, log)
- self.logger.info(log)
- # self.bot.send_private_channel_message("%s has left Discord (%s)" % (main.name, handle))
- self.set_discord_left(account.main)
- if account.discord_handle != handle:
- self.set_discord_handle(member.id, handle)
- if obj.type == "on_member_join":
- member = obj.member
- invite_used = obj.invite
- handle = member.name + "#" + member.discriminator
- if invite_used is None:
- log = '**%s** joined discord with unknown invite' % handle
- self.relay_hub_service. \
- send_message("system_logger", 0,
- log + f" {self.get_role('Administrator', self.guild.roles).mention}'s, "
- f"check that!",
- log + f" {self.get_role('Administrator', self.guild.roles).mention}'s, "
- f"check that!")
- self.logger.info(log)
- continue
- self.guild: Guild = self.client.get_guild(self.client.guilds[0].id)
- account = self.get_discord_invite(invite_used.code)
- if account is None:
- log = '**%s** joined discord with invite **%s** but couldnt find account!' % (
- handle, invite_used.code)
- self.relay_hub_service. \
- send_message("system_logger", 0,
- log + f" {self.get_role('Administrator', self.guild.roles).mention}'s, "
- f"check that!",
- log + f" {self.get_role('Administrator', self.guild.roles).mention}'s, "
- f"check that!")
- self.logger.info(log)
- asyncio.run_coroutine_threadsafe(self.discord_member_roles(member, None, None), self.loop)
- continue
-
- main = self.account_service.get_main(account.main)
- self.set_discord_joined(account.main, handle, member.id)
- if self.setting_service.get_value('is_alliance_bot') == '1':
- nick = f"{f'[{self.alias_controller.get_alias(main.org_id)}] '}{main.name}"
- else:
- nick = f"{main.name}"
- nick = asyncio.run_coroutine_threadsafe(self.discord_member_nick(member, nick), self.loop)
- access_level = access_level = self.access_service.get_access_level(account.main)
- roles = asyncio.run_coroutine_threadsafe(self.discord_member_roles(member, account, access_level),
- self.loop)
- # noinspection LongLine
- log = '**%s** joined discord with invite **%s** and matches account **%s**' \
- % (handle, invite_used.code,
- f"{f'[{self.alias_controller.get_alias(main.org_id)}] ' if self.setting_service.get_value('is_alliance_bot') == '1' else ''}{main.name}")
- self.relay_hub_service.send_message("system_logger", account.main, log, log)
- self.logger.info(log)
-
- @timerevent(budatime="1h", description="Verify Discord members", run_at_startup=True)
- def timer_check_discord_members(self, event_type, event_data):
- token = self.setting_discord_token().get_value()
- if token.lower() in ["none", "", "null"]:
- return
- if not self.bot.is_ready():
- return
- update = asyncio.run_coroutine_threadsafe(self.discord_update_bot_basic(), self.loop)
- # Update accounts that have left/joined discord without the bot being online
- accounts = self.db.query("SELECT * FROM account WHERE discord_id !=''")
- for account in accounts:
- match = False
- for member in self.guild.members:
- handle = member.name + "#" + member.discriminator
- if member.id == int(account.discord_id):
- match = True
- if account.discord_joined == 0:
- self.set_discord_joined(account.main, handle, member.id)
- break
- if match is False:
- if account.discord_joined == 1:
- self.set_discord_left(account.main)
- # Update current discord Members
- accounts = self.db.query("SELECT * FROM account WHERE discord_joined = 1 and char_id = main")
- for member in self.guild.members:
- if member.id == self.client.user.id:
- continue
- member_account = None
-
- for account in list(accounts):
- if int(account.discord_id) == member.id:
- member_account = account
- accounts.remove(account)
- break
- access_level = 0
- if member_account is not None:
- access_level = self.access_service.get_access_level(member_account.main)
- roles = asyncio.run_coroutine_threadsafe(self.discord_member_roles(member, member_account, access_level),
- self.loop)
- if member_account is not None:
- main = self.pork.get_character_info(member_account.main)
- # noinspection LongLine
- nick = f"{f'[{self.alias_controller.get_alias(main.org_id)}] ' if self.setting_service.get_value('is_alliance_bot') == '1' else ''}{main.name}"
-
- nick = asyncio.run_coroutine_threadsafe(self.discord_member_nick(member, nick), self.loop)
-
def run_it_forever(self):
self.loop.run_forever()
- def set_discord_invite(self, char_id, invite):
- return self.db.exec("UPDATE account SET discord_invite = ? WHERE main = ?", [invite, char_id])
-
- def set_discord_joined(self, char_id, handle, discord_id):
- return self.db.exec("UPDATE account SET discord_joined = 1, discord_handle = ?, discord_id = ? WHERE main = ?",
- [handle, discord_id, char_id])
-
- def set_discord_left(self, char_id):
- return self.db.exec("UPDATE account SET discord_joined = 0 WHERE main = ?", [char_id])
-
- def set_discord_handle(self, discord_id, handle):
- return self.db.exec("UPDATE account SET discord_handle = ? WHERE discord_id = ?", [handle, discord_id])
-
- def get_discord_invite(self, invite):
- return self.db.query_single("SELECT * FROM account WHERE discord_invite = ?", [invite])
-
- def get_account_discord_id(self, discord_id):
- return self.db.query_single(
- "SELECT * FROM account a left join player p on a.char_id=p.char_id WHERE discord_id = ?", [discord_id])
-
def discord_update_account(self, char_id):
account = self.account_service.get_account(char_id)
if account is None:
@@ -371,65 +141,12 @@ class DiscordController:
return "Processing..."
return "No Discord account found"
- def discord_invite_used(self, temp_invites):
- for temp_invite in temp_invites:
- # if temp_invite.inviter.id == self.client.user.id:
- # ## Using this line limits it to invite created by the account the Discord bot runs as..
- for invite in self.invites:
- if int(temp_invite.uses) > int(invite.uses) and temp_invite.code == invite.code:
- return temp_invite
- return None
-
def get_role(self, name, roles) -> Role or None:
for role in roles:
if role.name == name:
return role
return None
- async def on_member_join(self, member):
- temp_invites = await self.guild.invites()
- invite_used = self.discord_invite_used(temp_invites)
- self.discord_queue.append(DictObject({"type": "on_member_join", "member": member, "invite": invite_used}))
- await invite_used.delete()
-
- async def on_member_remove(self, member):
- self.discord_queue.append(DictObject({"type": "on_member_remove", "member": member}))
- await self.discord_update_bot_full()
-
- async def on_ready(self):
- await self.discord_update_bot_full()
- count = self.db.query_single('SELECT count(*) as count from online '
- 'where char_id NOT IN (select char_id from org_bots) and bot=?',
- [self.bot.get_char_id()]).count
-
- act = discord.Activity(type=discord.ActivityType.listening,
- name=f"{count} Players")
- asyncio.run_coroutine_threadsafe(self.client.change_presence(activity=act), self.loop)
- await self.clean_channel()
-
- if self.guild.large:
- self.logger.error(
- f"Guild {self.guild.name} is classified as large, "
- f"you need to request offline members to manage roles properly, this is not yet implemented")
-
- async def on_member_update(self, member_before, member_after):
- await self.discord_update_bot_basic()
-
- async def on_guild_role_create(self, role):
- await self.discord_update_bot_full()
-
- async def on_guild_role_delete(self, role):
- await self.discord_update_bot_full()
-
- async def on_guild_role_update(self, role_before, role_after):
- await self.discord_update_bot_full()
-
- async def on_invite_create(self, invite):
- await self.discord_update_bot_full()
-
- async def on_invite_delete(self, invite):
- await self.discord_update_bot_full()
-
async def discord_update_bot_basic(self):
self.guild = self.client.get_guild(self.client.guilds[0].id)
self.channel = self.client.get_channel(self.guild.text_channels[0].id)
@@ -448,7 +165,37 @@ class DiscordController:
await self.client.start(token)
except discord.ClientException as exc:
- self.logger.error("Something broke, I'm out!: %s" % str(exc))
+ self.logger.error(f"Something broke, I'm out!: {str(exc)}")
+
+ async def setup_relayhub(self):
+ for channel in self.guild.channels:
+ if type(channel) == TextChannel:
+ channel: TextChannel
+ self.relay_hub_service.register_message_source(f"Discord_({channel.name.replace(' ', '_')})")
+ self.relay_hub_service.register_message_destination(f"Discord_({channel.name.replace(' ', '_')})",
+ partial(self.relay, channel.id), [], [f"Discord_({channel.name.replace(' ', '_')})"])
+
+ def relay(self, channel, ctx):
+ ch: TextChannel = self.guild.get_channel(channel)
+ msg = ctx.formatted_message
+ del_after = 3600 if f"{ch.id}" in self.setting_service.get_value("public_relay").lstrip("[").rstrip("]").split(',') else None
+ if ctx.source == "alliance":
+ msg = self.cmd.parseDiscord(ctx.message)
+ elif type(msg) == ChatBlob:
+ if msg.embed:
+ msg: ChatBlob
+ blob = Embed(title=msg.title, color=0x00FF00, description=self.cmd.parseDiscord(msg.msg).replace("\n> ", '\n'))
+ asyncio.run_coroutine_threadsafe(ch.send("", delete_after=del_after, embed=blob), self.loop)
+ return
+ rsp = self.cmd.parseDiscord(ctx.formatted_message.page_prefix) + "\n"
+ if not self.text.strip_html_tags(ctx.formatted_message.msg).startswith(ctx.formatted_message.title):
+ rsp += f"**__{ctx.formatted_message.title}__**\n"
+ rsp += "> " + self.cmd.parseDiscord(ctx.formatted_message.msg)
+ rsp += f"\n {self.cmd.parseDiscord(ctx.formatted_message.page_postfix)}"
+ msg = rsp
+ else:
+ msg = self.cmd.parseDiscord(ctx.formatted_message)
+ msg: Message = asyncio.run_coroutine_threadsafe(ch.send(msg, delete_after=del_after), self.loop)
async def discord_create_invite(self, reason=""):
created_invite = await self.channel.create_invite(max_age=300, max_uses=2, reason=reason)
@@ -578,28 +325,29 @@ class DiscordController:
await discord_user.remove_roles(role)
async def on_message(self, msg: Message):
+ if f"{msg.channel.id}" in self.setting_service.get_value("public_relay").lstrip("[").rstrip("]").split(','):
+ await msg.delete(delay=3600)
if msg.author.id == self.client.user.id:
return
- if not self.setting_service.get_value("dc_relay_public"):
- return
channel: TextChannel = msg.channel
- if channel.id == int(self.setting_service.get_value("dc_relay_public")):
-
- if self.setting_service.get_value('is_alliance_bot') == "0":
- response = f"[{html.escape(msg.author.nick if msg.author.nick else msg.author.name, False)}" \
- f"]: " \
- f"{html.escape(emojis.decode(msg.clean_content), False)}"
- else:
- response = f"{html.escape(msg.author.nick if msg.author.nick else msg.author.name, False)}: " \
- f"{html.escape(emojis.decode(msg.clean_content), False)}"
- await msg.delete(delay=3600)
- sender = self.db.query_single("SELECT * from account a left join player p on a.main = p.char_id where a.discord_id = ?", [msg.author.id])
- self.relay_hub_service.send_message("public_relay", sender, html.escape(emojis.decode(msg.clean_content), False), response)
+ acc = self.data.get_account_discord_id(msg.author.id)
+ if acc:
+ acc.discord_nick = msg.author.nick or msg.author.name+'#'+msg.author.discriminator
+ prefix = f"[{self.alias_controller.get_alias(acc.member)}] {acc.name}: " if self.alias_usage().get_value() else f"[DC] {acc.name}: "
+ self.relay_hub_service.send_message("Discord_(" + channel.name+")",
+ DictObject(acc), msg.content,
+ prefix + msg.content)
+ else:
+ prefix = f"[-UNK-] {msg.author.username}: " if self.alias_usage().get_value() else f"[DC] {msg.author.username}: "
+ self.relay_hub_service.send_message("Discord_(" + channel.name+")",
+ DictObject({'char_id': 0, 'name': msg.author.username, 'discord_handle': f'{msg.author.name}#{msg.author.discriminator}'}), msg.content,
+ prefix + msg.content)
+ if str(channel.id) not in self.channel_blacklist().get_value().lstrip("[").rstrip("]").split(','):
+ self.bot.event_service.fire_event("discord_command", DictObject({'account': acc, 'message': msg}))
if self.is_command(msg.content):
admin = self.get_role("Administrator", self.guild.roles)
council = self.get_role("Council", self.guild.roles)
-
if msg.content[:4] == "!pin":
if admin in msg.author.roles:
matches = re.findall(pattern="(.+?)<\/head>(.+)", string=msg.content[4:].strip(),
@@ -611,7 +359,7 @@ class DiscordController:
mess = await channel.send(embed=Embed(color=3066993, description=msg.content[4:]))
await mess.pin()
- if msg.content[:5] == "!note":
+ if msg.content[:6] == "!note ":
if admin in msg.author.roles:
matches = re.findall(pattern="(.+?)<\/head>(.+)", string=msg.content[5:].strip(),
flags=re.DOTALL)
@@ -636,73 +384,23 @@ class DiscordController:
else:
await msg.channel.purge(check=self.check, limit=count)
await msg.delete(delay=0)
- if msg.content[:10] == "!subscribe":
- if admin in msg.author.roles:
- out = msg.content[10:].strip()
- if self.setting_service.get(out) is None:
- await msg.reply(f"The Channel {out} does not exist.")
- else:
- self.setting_service.set_value(out, msg.channel.id)
- self.send_message(msg.channel.id, Embed(color=3066993, title="Channel Guard",
- description=f"This channel has been "
- f"subscribed to the source {out}."))
-
- def send_message(self, channel: int, message, delete=0):
- if self.client.is_ready():
- channel: TextChannel = self.client.get_channel(int(channel)) if type(channel) in [int, str] else channel
- if type(message) == Embed:
- if delete != 0:
- asyncio.run_coroutine_threadsafe(channel.send(embed=message, delete_after=delete), self.loop)
- else:
- asyncio.run_coroutine_threadsafe(channel.send(embed=message), self.loop)
-
- else:
- if delete != 0:
- asyncio.run_coroutine_threadsafe(channel.send(message, delete_after=delete), self.loop)
- else:
- asyncio.run_coroutine_threadsafe(channel.send(message), self.loop)
def is_command(self, message: str):
for x in ["subscribe", "pin", "purge", "note"]:
if message.startswith("!" + x):
return True
- async def clean_channel(self):
- if self.setting_service.get_value("dc_relay_public") not in ["0", None]:
- channel: TextChannel = self.client.get_channel(int(self.setting_service.get_value("dc_relay_public")))
- for i in range(5):
- await channel.purge(check=self.check)
-
def check(self, msg: Message):
- if msg.pinned or len(msg.embeds) > 0:
+ if msg.pinned or (len(msg.embeds) > 0 and (msg.created_at.utcnow() < datetime.utcnow()-timedelta(hours=12))):
return False
else:
return True
- @event(event_type="main_changed", description="Fix discord names & ranks")
- def fix_ranks(self, _, data):
- row = self.db.query_single("SELECT * from account where char_id=?", [data.old_main_id])
- if row.discord_joined == 0:
- self.logger.debug(f"{data.old_main_id} was not in discord, ignoring main fixing")
- return
- elif row.discord_joined == 1:
- self.db.exec(
- "UPDATE account set discord_handle=?, discord_id=?, discord_invite=?, discord_joined=? where char_id=?",
- [row.discord_handle, row.discord_id, row.discord_invite, row.discord_joined, data.new_main_id])
- self.db.exec(
- "UPDATE account set discord_handle='', discord_id=0, discord_invite='', discord_joined=0 "
- "where char_id=?",
- [data.old_main_id])
- self.logger.info(f"{data.old_main_id} was in discord, overwriting {data.new_main_id} with {data}")
+ def alias_usage(self) -> BooleanSettingType:
+ return self.setting_service.get("is_alliance_bot")
- self.discord_update_account(data.new_main_id)
+ def channel_blacklist(self) -> TextSettingType:
+ return self.setting_service.get("channel_blacklist")
- @timerevent(budatime="5m", description="update activity")
- def change_count(self, _, _1):
- if hasattr(self, "loop"):
- count = self.db.query_single('SELECT count(*) as count from online '
- 'where char_id NOT IN (select char_id from org_bots) and bot=?',
- [self.bot.get_char_id()]).count
- act = discord.Activity(type=discord.ActivityType.listening,
- name=f"{count} Players")
- asyncio.run_coroutine_threadsafe(self.client.change_presence(activity=act), self.loop)
+ def public_relay(self) -> TextSettingType:
+ return self.setting_service.get("public_relay")
diff --git a/modules/core/discord/discord_data.py b/modules/core/discord/discord_data.py
new file mode 100644
index 0000000..274d8ac
--- /dev/null
+++ b/modules/core/discord/discord_data.py
@@ -0,0 +1,25 @@
+
+class DiscordData:
+ def __init__(self, db, client):
+ self.db = db
+ self.client = client
+
+ def set_discord_invite(self, char_id, invite):
+ return self.db.exec("UPDATE account SET discord_invite = ? WHERE main = ?", [invite, char_id])
+
+ def set_discord_joined(self, char_id, handle, discord_id):
+ return self.db.exec("UPDATE account SET discord_joined = 1, discord_handle = ?, discord_id = ? WHERE main = ?",
+ [handle, discord_id, char_id])
+
+ def set_discord_left(self, char_id):
+ return self.db.exec("UPDATE account SET discord_joined = 0 WHERE main = ?", [char_id])
+
+ def set_discord_handle(self, discord_id, handle):
+ return self.db.exec("UPDATE account SET discord_handle = ? WHERE discord_id = ?", [handle, discord_id])
+
+ def get_discord_invite(self, invite):
+ return self.db.query_single("SELECT * FROM account WHERE discord_invite = ?", [invite])
+
+ def get_account_discord_id(self, discord_id):
+ return self.db.query_single(
+ "SELECT * FROM account a left join player p on a.char_id=p.char_id WHERE discord_id = ?", [discord_id])
\ No newline at end of file
diff --git a/modules/core/discord/discord_management.py b/modules/core/discord/discord_management.py
new file mode 100644
index 0000000..841ff77
--- /dev/null
+++ b/modules/core/discord/discord_management.py
@@ -0,0 +1,82 @@
+import asyncio
+
+from discord import Activity, ActivityType, TextChannel
+
+from core.dict_object import DictObject
+
+
+class DiscordManager:
+ def __init__(self, client):
+ self.client = client
+ client = client.client
+ client.event(self.on_ready)
+ client.event(self.on_member_join)
+ client.event(self.on_member_remove)
+ client.event(self.on_member_update)
+ client.event(self.on_guild_role_delete)
+ client.event(self.on_guild_role_create)
+ client.event(self.on_guild_role_update)
+ client.event(self.on_invite_create)
+ client.event(self.on_invite_delete)
+
+ async def on_member_update(self, member_before, member_after):
+ await self.client.discord_update_bot_basic()
+
+ async def on_guild_role_create(self, role):
+ await self.client.discord_update_bot_full()
+
+ async def on_guild_role_delete(self, role):
+ await self.client.discord_update_bot_full()
+
+ async def on_guild_role_update(self, role_before, role_after):
+ await self.client.discord_update_bot_full()
+
+ async def on_invite_create(self, invite):
+ await self.client.discord_update_bot_full()
+
+ async def on_invite_delete(self, invite):
+ await self.client.discord_update_bot_full()
+
+ async def on_member_join(self, member):
+ temp_invites = await self.client.guild.invites()
+ invite_used = self.discord_invite_used(temp_invites)
+ self.client.discord_queue.append(
+ DictObject({"type": "on_member_join", "member": member, "invite": invite_used}))
+ await invite_used.delete()
+
+ def discord_invite_used(self, temp_invites):
+ for temp_invite in temp_invites:
+ # if temp_invite.inviter.id == self.client.user.id:
+ # ## Using this line limits it to invite created by the account the Discord bot runs as..
+ for invite in self.client.invites:
+ if int(temp_invite.uses) > int(invite.uses) and temp_invite.code == invite.code:
+ return temp_invite
+ return None
+
+ async def on_member_remove(self, member):
+ self.client.discord_queue.append(DictObject({"type": "on_member_remove", "member": member}))
+ await self.client.discord_update_bot_full()
+
+ async def on_ready(self):
+ await self.client.discord_update_bot_full()
+ count = self.client.db.query_single('SELECT count(*) as count from online '
+ 'where char_id NOT IN (select char_id from org_bots) and bot=?',
+ [self.client.bot.get_char_id()]).count
+
+ act = Activity(type=ActivityType.listening,
+ name=f"{count} Players")
+ asyncio.run_coroutine_threadsafe(self.client.client.change_presence(activity=act), self.client.loop)
+ asyncio.run_coroutine_threadsafe(self.client.setup_relayhub(), self.client.loop)
+ await self.clean_channel()
+
+ if self.client.guild.large:
+ self.client.logger.error(
+ f"Guild {self.client.guild.name} is classified as large, "
+ f"you need to request offline members to manage roles properly, this is not yet implemented")
+
+ async def clean_channel(self):
+ for channel in self.client.setting_service.get_value("public_relay").lstrip("[").rstrip("]").split(','):
+ if ch := self.client.client.get_channel(int(channel)):
+ for i in range(5):
+ await ch.purge(check=self.client.check)
+
diff --git a/modules/core/private_channel/private_channel_controller.py b/modules/core/private_channel/private_channel_controller.py
index ad3fa33..c3a2e76 100644
--- a/modules/core/private_channel/private_channel_controller.py
+++ b/modules/core/private_channel/private_channel_controller.py
@@ -235,22 +235,25 @@ class PrivateChannelController:
@event(event_type=IgnCore.OUTGOING_PRIVATE_CHANNEL_MESSAGE_EVENT,
description="Relay commands from the private channel to the relay hub", is_hidden=True)
def outgoing_private_channel_message_event(self, _, event_data):
+
if isinstance(event_data.message, ChatBlob):
pages = self.text.paginate(event_data.message,
self.setting_service.get("org_channel_max_page_length").get_value())
if len(pages) < 4:
for page in pages:
- message = "{priv}{message}".format(priv=self.PRIVATE_CHANNEL_PREFIX, message=page)
+ # message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=page)
+ event_data.message.page_prefix = self.PRIVATE_CHANNEL_PREFIX
self.message_hub_service.send_message(self.MESSAGE_SOURCE,
None,
page,
- message)
+ event_data.message)
else:
- message = "{priv}{message}".format(priv=self.PRIVATE_CHANNEL_PREFIX, message=event_data.message.title)
+ # message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=event_data.message.title)
+ event_data.message.page_prefix = self.PRIVATE_CHANNEL_PREFIX
self.message_hub_service.send_message(self.MESSAGE_SOURCE,
None,
event_data.message.title,
- message)
+ event_data.message)
else:
message = "{priv}{message}".format(priv=self.PRIVATE_CHANNEL_PREFIX, message=event_data.message)
self.message_hub_service.send_message(self.MESSAGE_SOURCE,
diff --git a/modules/core/riadmin/riadmin_controller.py b/modules/core/riadmin/riadmin_controller.py
index 363fdb9..6bf6899 100644
--- a/modules/core/riadmin/riadmin_controller.py
+++ b/modules/core/riadmin/riadmin_controller.py
@@ -1,20 +1,26 @@
import json
import math
+import typing
from core.buddy_service import BuddyService
from core.chat_blob import ChatBlob
from core.command_param_types import Const, Character, Any, NamedParameters
from core.decorators import instance, command, event
from core.dict_object import DictObject
+
from core.logger import Logger
-from core.lookup.character_service import CharacterService
-from core.lookup.pork_service import PorkService
-from core.private_channel_service import PrivateChannelService
+
from core.setting_service import SettingService
from core.setting_types import TextSettingType
from core.text import Text
from core.translation_service import TranslationService
from core.igncore import IgnCore
+from core.private_channel_service import PrivateChannelService
+
+if typing.TYPE_CHECKING:
+ from core.lookup.character_service import CharacterService
+ from core.lookup.pork_service import PorkService
+ from core.event_service import EventService
# noinspection SqlCaseVsIf,SqlCaseVsCoalesce
@@ -38,6 +44,7 @@ class RIAdminController:
self.getresp = self.ts.get_response
self.buddy_service: BuddyService = registry.get_instance("buddy_service")
self.pork: PorkService = registry.get_instance("pork_service")
+ self.event_service: EventService = registry.get_instance("event_service")
def start(self):
self.db.exec(
@@ -54,6 +61,8 @@ class RIAdminController:
TextSettingType(), "Allowed bots (charID's)",
extended_description="This setting is *NOT* synchronized across the network;"
" this needs to be done manually!")
+ def pre_start(self):
+ self.event_service.register_event_type("RAID_END")
@event(event_type="buddy_logoff", description="Track raiders")
def raider_logoff(self, _, event_data):
diff --git a/modules/onlinebot/alliance/alliance_relay_controller.py b/modules/onlinebot/alliance/alliance_relay_controller.py
index 5ba8517..6a19998 100644
--- a/modules/onlinebot/alliance/alliance_relay_controller.py
+++ b/modules/onlinebot/alliance/alliance_relay_controller.py
@@ -1,112 +1,112 @@
-from core.aochat import server_packets, client_packets
-from core.conn import Conn
-from core.decorators import instance
-from core.igncore import IgnCore
-from core.logger import Logger
-from core.lookup.character_service import CharacterService
-from core.setting_service import SettingService
-from core.setting_types import TextSettingType, BooleanSettingType, ColorSettingType
-from core.text import Text
-from modules.onlinebot.online.org_alias_controller import OrgAliasController
-
-
-@instance("AllianceRelayController")
-class AllianceRelayController:
- relay_channel_id = None
- MESSAGE_SOURCE = "alliance"
-
- def __init__(self):
- self.logger = Logger(__name__)
-
- # noinspection DuplicatedCode
- def inject(self, registry):
- self.bot: IgnCore = registry.get_instance("bot")
- self.setting_service: SettingService = registry.get_instance("setting_service")
- self.character_service: CharacterService = registry.get_instance("character_service")
- self.message_hub_service = registry.get_instance("message_hub_service")
- self.public_channel_service = registry.get_instance("public_channel_service")
- self.text: Text = registry.get_instance("text")
- self.alias_controller: OrgAliasController = registry.get_instance("org_alias_controller")
-
- def pre_start(self):
- self.message_hub_service.register_message_source(self.MESSAGE_SOURCE)
-
- def start(self):
- self.setting_service.register(self.module_name, "arelaybot", "",
- TextSettingType(allow_empty=True), "Bot for alliance relay")
-
- self.setting_service.register(self.module_name, "arelay_enabled", False,
- BooleanSettingType(), "Enable the alliance relay")
-
- self.setting_service.register(self.module_name, "arelay_color", "#C3C3C3",
- ColorSettingType(),
- "Color of messages from relay")
-
- self.message_hub_service.register_message_destination(self.MESSAGE_SOURCE, self.handle_relay_hub_message, [],
- [self.MESSAGE_SOURCE])
-
- self.bot.register_packet_handler(server_packets.PrivateChannelInvited.id, self.handle_private_channel_invite,
- 100)
- self.bot.register_packet_handler(server_packets.PrivateChannelMessage.id, self.handle_private_channel_message)
-
- # noinspection DuplicatedCode
- def handle_private_channel_invite(self, conn: Conn, packet: server_packets.PrivateChannelInvited):
- if conn.id != "main":
- return
-
- if not self.setting_service.get("arelay_enabled").get_value():
- return
-
- channel_name = self.character_service.get_char_name(packet.private_channel_id)
- if self.setting_service.get_value("arelaybot").lower() == channel_name.lower():
- self.bot.send_packet(client_packets.PrivateChannelJoin(packet.private_channel_id))
- self.logger.info("Joined private channel {channel}".format(channel=channel_name))
- self.relay_channel_id = packet.private_channel_id
-
- # noinspection DuplicatedCode
- def handle_private_channel_message(self, conn: Conn, packet: server_packets.PrivateChannelMessage):
- if conn.id != "main":
- return
-
- if not self.setting_service.get("arelay_enabled").get_value():
- return
-
- # ignore packets from the bot's own private channel and from the bot itself
- if packet.private_channel_id == self.bot.get_char_id() or packet.char_id == self.bot.get_char_id():
- return
-
- message = packet.message.lstrip()
- if message[:6] != "!agcr ":
- return
-
- message = message[6:]
- formatted_message = self.setting_service.get("arelay_color").format_text(message)
-
- sender = None
- self.message_hub_service.send_message(self.MESSAGE_SOURCE, sender, message, formatted_message)
-
- def handle_relay_hub_message(self, ctx):
- if not self.setting_service.get("arelay_enabled").get_value():
- return
-
- plain_msg = ctx.message or ctx.formatted_message
- invite = self.text.make_chatcmd("click here", "/tell discord invite",
- style="style='text-decoration:none'")
- name = f"[{self.alias_controller.get_alias(ctx.sender.org_id)}] {ctx.sender.name}"
- blob = self.text.format_page('Info',
- f"
"
- f"This message has been sent to you by:
"
- f"Igncom
"
- f"{ctx.sender.discord_handle}
"
- f"{name} on Alliance Discord.
"
- f"To reply, either respond in the relay or "
- f"contact them directly at the provided handles.
"
- f"Have you joined The Alliance Discord yet? "
- f"If not {invite} to receive an invite.")
- self.send_message_to_alliance(f"{name}: {plain_msg}" + f" [{blob}]")
-
- def send_message_to_alliance(self, msg):
- if self.relay_channel_id:
- packet = client_packets.PrivateChannelMessage(self.relay_channel_id,
- "!agcr " + self.text.format_message(msg, False), "\0")
- self.bot.conns["main"].send_packet(packet)
+# from core.aochat import server_packets, client_packets
+# from core.conn import Conn
+# from core.decorators import instance
+# from core.igncore import IgnCore
+# from core.logger import Logger
+# from core.lookup.character_service import CharacterService
+# from core.setting_service import SettingService
+# from core.setting_types import TextSettingType, BooleanSettingType, ColorSettingType
+# from core.text import Text
+# from modules.onlinebot.online.org_alias_controller import OrgAliasController
+#
+#
+# @instance("AllianceRelayController")
+# class AllianceRelayController:
+# relay_channel_id = None
+# MESSAGE_SOURCE = "alliance"
+#
+# def __init__(self):
+# self.logger = Logger(__name__)
+#
+# # noinspection DuplicatedCode
+# def inject(self, registry):
+# self.bot: IgnCore = registry.get_instance("bot")
+# self.setting_service: SettingService = registry.get_instance("setting_service")
+# self.character_service: CharacterService = registry.get_instance("character_service")
+# self.message_hub_service = registry.get_instance("message_hub_service")
+# self.public_channel_service = registry.get_instance("public_channel_service")
+# self.text: Text = registry.get_instance("text")
+# self.alias_controller: OrgAliasController = registry.get_instance("org_alias_controller")
+#
+# def pre_start(self):
+# self.message_hub_service.register_message_source(self.MESSAGE_SOURCE)
+#
+# def start(self):
+# self.setting_service.register(self.module_name, "arelaybot", "",
+# TextSettingType(allow_empty=True), "Bot for alliance relay")
+#
+# self.setting_service.register(self.module_name, "arelay_enabled", False,
+# BooleanSettingType(), "Enable the alliance relay")
+#
+# self.setting_service.register(self.module_name, "arelay_color", "#C3C3C3",
+# ColorSettingType(),
+# "Color of messages from relay")
+#
+# # self.message_hub_service.register_message_destination(self.MESSAGE_SOURCE, self.handle_relay_hub_message, [],
+# # [self.MESSAGE_SOURCE])
+#
+# self.bot.register_packet_handler(server_packets.PrivateChannelInvited.id, self.handle_private_channel_invite,
+# 100)
+# self.bot.register_packet_handler(server_packets.PrivateChannelMessage.id, self.handle_private_channel_message)
+#
+# # noinspection DuplicatedCode
+# def handle_private_channel_invite(self, conn: Conn, packet: server_packets.PrivateChannelInvited):
+# if conn.id != "main":
+# return
+#
+# if not self.setting_service.get("arelay_enabled").get_value():
+# return
+#
+# channel_name = self.character_service.get_char_name(packet.private_channel_id)
+# if self.setting_service.get_value("arelaybot").lower() == channel_name.lower():
+# self.bot.send_packet(client_packets.PrivateChannelJoin(packet.private_channel_id))
+# self.logger.info("Joined private channel {channel}".format(channel=channel_name))
+# self.relay_channel_id = packet.private_channel_id
+#
+# # noinspection DuplicatedCode
+# def handle_private_channel_message(self, conn: Conn, packet: server_packets.PrivateChannelMessage):
+# if conn.id != "main":
+# return
+#
+# if not self.setting_service.get("arelay_enabled").get_value():
+# return
+#
+# # ignore packets from the bot's own private channel and from the bot itself
+# if packet.private_channel_id == self.bot.get_char_id() or packet.char_id == self.bot.get_char_id():
+# return
+#
+# message = packet.message.lstrip()
+# if message[:6] != "!agcr ":
+# return
+#
+# message = message[6:]
+# formatted_message = self.setting_service.get("arelay_color").format_text(message)
+#
+# sender = None
+# self.message_hub_service.send_message(self.MESSAGE_SOURCE, sender, message, formatted_message)
+#
+# def handle_relay_hub_message(self, ctx):
+# if not self.setting_service.get("arelay_enabled").get_value():
+# return
+#
+# plain_msg = ctx.message or ctx.formatted_message
+# invite = self.text.make_chatcmd("click here", "/tell discord invite",
+# style="style='text-decoration:none'")
+# name = f"[{self.alias_controller.get_alias(ctx.sender.org_id)}] {ctx.sender.name}"
+# blob = self.text.format_page('Info',
+# f"
"
+# f"This message has been sent to you by:
"
+# f"Igncom
"
+# f"{ctx.sender.discord_handle}
"
+# f"{name} on Alliance Discord.
"
+# f"To reply, either respond in the relay or "
+# f"contact them directly at the provided handles.
"
+# f"Have you joined The Alliance Discord yet? "
+# f"If not {invite} to receive an invite.")
+# self.send_message_to_alliance(f"{name}: {plain_msg}" + f" [{blob}]")
+#
+# def send_message_to_alliance(self, msg):
+# if self.relay_channel_id:
+# packet = client_packets.PrivateChannelMessage(self.relay_channel_id,
+# "!agcr " + self.text.format_message(msg, False), "\0")
+# self.bot.conns["main"].send_packet(packet)
diff --git a/modules/onlinebot/online/org_controller.py b/modules/onlinebot/online/org_controller.py
index cae60ba..2889bf2 100644
--- a/modules/onlinebot/online/org_controller.py
+++ b/modules/onlinebot/online/org_controller.py
@@ -3,6 +3,7 @@ import re
import time
from threading import Thread
+import datetime
import requests
from core.buddy_service import BuddyService
@@ -359,4 +360,8 @@ class OrgController:
if len(current) > 10:
out.append(current)
if len(out) > 0:
- self.relay_hub_service.send_message("member_logger", None, out, out)
+ y = 0
+ for x in out:
+ y += 1
+ blob = ChatBlob(f"Recent changes - {datetime.date.today()} - ({y}/{len(out)})", x, embed=True)
+ self.relay_hub_service.send_message("member_logger", None, blob, blob)
diff --git a/modules/orgbot/org/org_controller.py b/modules/orgbot/org/org_controller.py
index 34440ea..1adedb5 100644
--- a/modules/orgbot/org/org_controller.py
+++ b/modules/orgbot/org/org_controller.py
@@ -120,17 +120,19 @@ class OrgChannelController:
self.setting_service.get("org_channel_max_page_length").get_value())
if len(pages) < 4:
for page in pages:
- message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=page)
+ # message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=page)
+ event_data.message.page_prefix = self.ORG_CHANNEL_PREFIX
self.message_hub_service.send_message(self.MESSAGE_SOURCE,
None,
page,
- message)
+ event_data.message)
else:
- message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=event_data.message.title)
+ # message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=event_data.message.title)
+ event_data.message.page_prefix = self.ORG_CHANNEL_PREFIX
self.message_hub_service.send_message(self.MESSAGE_SOURCE,
None,
event_data.message.title,
- message)
+ event_data.message)
else:
message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=event_data.message)
self.message_hub_service.send_message(self.MESSAGE_SOURCE,
diff --git a/modules/raidbot/raid/raidbot_controller.py b/modules/raidbot/raid/raidbot_controller.py
index c792aa8..fe4a00a 100644
--- a/modules/raidbot/raid/raidbot_controller.py
+++ b/modules/raidbot/raid/raidbot_controller.py
@@ -76,9 +76,6 @@ class RaidbotController(BaseModule):
self.account_service: AccountService = registry.get_instance("account_service")
self.buddy_service: BuddyService = registry.get_instance("buddy_service")
- def pre_start(self):
- self.event_service.register_event_type("RAID_END")
-
@event("connect", "Adds all raiders to buddylist")
def connect(self, _, _1):
query = self.db.query("SELECT char_id, member from account where member != -1 and disabled = 0")
diff --git a/modules/standard/MessageDistributor/message_distributor.py b/modules/standard/MessageDistributor/message_distributor.py
index 26cf88e..42806f2 100644
--- a/modules/standard/MessageDistributor/message_distributor.py
+++ b/modules/standard/MessageDistributor/message_distributor.py
@@ -1,137 +1,137 @@
-import asyncio
-import datetime
-import html
-
-# noinspection PyPackageRequirements
-from discord import Embed
-
-from core.command_service import CommandService
-from core.db import DB
-from core.decorators import instance
-from core.logger import Logger
-from core.lookup.character_service import CharacterService
-from core.lookup.pork_service import PorkService
-from core.message_hub_service import MessageHubService
-from core.registry import Registry
-from core.setting_service import SettingService
-from core.setting_types import NumberSettingType
-from core.text import Text
-from core.igncore import IgnCore
-from modules.core.accounting.services.access_service import AccessService
-from modules.core.discord.discord_controller import DiscordController
-
-
-# noinspection DuplicatedCode,PyAttributeOutsideInit
-@instance()
-class MessageDistributor:
- MESSAGE_SOURCE = "discord"
-
- def __init__(self):
- self.logger = Logger(__name__)
-
- def inject(self, registry):
- self.bot: IgnCore = registry.get_instance("bot")
- self.db: DB = registry.get_instance("db")
- self.character_service: CharacterService = registry.get_instance("character_service")
- self.access_service: AccessService = registry.get_instance("access_service")
- self.pork: PorkService = registry.get_instance("pork_service")
- self.relay_hub_service: MessageHubService = registry.get_instance("message_hub_service")
- self.discord: DiscordController = registry.get_instance("discord_controller")
- self.cmd_service: CommandService = registry.get_instance("command_service")
- self.setting_service: SettingService = registry.get_instance("setting_service")
- self.text: Text = registry.get_instance("text")
-
- def pre_start(self):
- self.relay_hub_service.register_message_source("public_relay")
- self.relay_hub_service.register_message_source("tell_logger")
- self.relay_hub_service.register_message_source("system_logger")
- self.relay_hub_service.register_message_source("access_denied_logger")
- self.relay_hub_service.register_message_source("member_logger")
-
- def start(self):
- self.relay_hub_service.register_message_destination("tell_log", self.handle_logging_tell, ["tell_logger"],
- ["tell_log"])
- self.setting_service.register(self.module_name, "dc_tell_log", 0, NumberSettingType(allow_empty=True),
- "ChannelID for the Tell Log")
-
- self.relay_hub_service.register_message_destination("access_denied_log", self.handle_logging_denied,
- ["access_denied_logger"], ["access_denied_log"])
- self.setting_service.register(self.module_name, "dc_denied_log", 0, NumberSettingType(allow_empty=True),
- "ChannelID for the Access Denied Log")
-
- self.relay_hub_service.register_message_destination("relay_log", self.handle_logging_relay,
- ["alliance", "public_relay"], ["relay_log"])
- self.setting_service.register(self.module_name, "dc_relay_log", 0, NumberSettingType(allow_empty=True),
- "ChannelID for the Relay Log")
-
- self.relay_hub_service.register_message_destination("public_relay", self.handle_public_relay, ["alliance"],
- ["public_relay"])
- self.setting_service.register(self.module_name, "dc_relay_public", 0, NumberSettingType(allow_empty=True),
- "ChannelID for the Public Relay Channel")
-
- self.relay_hub_service.register_message_destination("system", self.handle_logging_system, ["system_logger"],
- ["system"])
- self.setting_service.register(self.module_name, "dc_system_log", 0, NumberSettingType(allow_empty=True),
- "ChannelID for the System Channel")
-
- self.relay_hub_service.register_message_destination("dc_member_log", self.handle_logging_members,
- ["member_logger"], ["dc_member_log"])
- self.setting_service.register(self.module_name, "dc_member_log", 0, NumberSettingType(allow_empty=True),
- "ChannelID for the Member Log")
-
- if Registry.get_instance("darknet", is_optional=True):
- self.relay_hub_service.register_message_destination("dc_darknet_log", self.handle_darknet_log, ["darknet"],
- [""])
- self.setting_service.register(self.module_name, "dc_darknet_log", 0, NumberSettingType(allow_empty=True),
- "ChannelID for the Darknet Log")
-
- def handle_public_relay(self, ctx):
- if self.setting_service.get_value("dc_relay_public") != "0":
- message = self.format(ctx.formatted_message)
- self.discord.send_message(self.setting_service.get_value("dc_relay_public"), html.unescape(message),
- delete=3600) # delete after 1h
-
- def handle_logging_tell(self, ctx):
- if self.setting_service.get_value("dc_tell_log") != "0":
- message = self.format(ctx.message)
- self.discord.send_message(self.setting_service.get_value("dc_tell_log"),
- f"[FROM] {self.character_service.get_char_name(ctx.sender)}: {message}")
-
- def handle_logging_denied(self, ctx):
- if self.setting_service.get_value("dc_denied_log") != "0":
- message = self.format(ctx.message)
- self.discord.send_message(self.setting_service.get_value("dc_denied_log"), message)
-
- def handle_darknet_log(self, ctx):
- if self.setting_service.get_value("dc_darknet_log") != "0":
- message = self.format(ctx.message)
- self.discord.send_message(self.setting_service.get_value("dc_darknet_log"), message)
-
- def handle_logging_relay(self, ctx):
- if self.setting_service.get_value("dc_relay_log") != "0":
- message = self.format(ctx.formatted_message)
- self.discord.send_message(self.setting_service.get_value("dc_relay_log"), f"{html.unescape(message)}")
-
- def handle_logging_system(self, ctx):
- if self.setting_service.get_value("dc_system_log") != "0":
- message = self.format(ctx.message)
- self.discord.send_message(self.setting_service.get_value("dc_system_log"), f"{html.unescape(message)}")
-
- def handle_logging_members(self, ctx):
- if self.setting_service.get_value("dc_member_log") != "0":
- channel = self.discord.client.get_channel(int(self.setting_service.get_value("dc_member_log")))
- spam = []
- current = 0
- for message in ctx.message:
- current += 1
- spam.append(Embed(title=f"Recent changes - {datetime.date.today()} - ({current}/{len(ctx.message)})",
- description=message, color=3066993))
- asyncio.run_coroutine_threadsafe(self.send_spam(channel, spam), self.discord.loop)
-
- async def send_spam(self, channel, message):
- if self.discord.client.is_ready():
- for i in message:
- await channel.send(embed=i)
-
- def format(self, message):
- return self.text.strip_html_tags(message)
+# import asyncio
+# import datetime
+# import html
+#
+# # noinspection PyPackageRequirements
+# from discord import Embed
+#
+# from core.command_service import CommandService
+# from core.db import DB
+# from core.decorators import instance
+# from core.logger import Logger
+# from core.lookup.character_service import CharacterService
+# from core.lookup.pork_service import PorkService
+# from core.message_hub_service import MessageHubService
+# from core.registry import Registry
+# from core.setting_service import SettingService
+# from core.setting_types import NumberSettingType
+# from core.text import Text
+# from core.igncore import IgnCore
+# from modules.core.accounting.services.access_service import AccessService
+# from modules.core.discord.discord_controller import DiscordController
+#
+#
+# # noinspection DuplicatedCode,PyAttributeOutsideInit
+# @instance()
+# class MessageDistributor:
+# MESSAGE_SOURCE = "discord"
+#
+# def __init__(self):
+# self.logger = Logger(__name__)
+#
+# def inject(self, registry):
+# self.bot: IgnCore = registry.get_instance("bot")
+# self.db: DB = registry.get_instance("db")
+# self.character_service: CharacterService = registry.get_instance("character_service")
+# self.access_service: AccessService = registry.get_instance("access_service")
+# self.pork: PorkService = registry.get_instance("pork_service")
+# self.relay_hub_service: MessageHubService = registry.get_instance("message_hub_service")
+# self.discord: DiscordController = registry.get_instance("discord_controller")
+# self.cmd_service: CommandService = registry.get_instance("command_service")
+# self.setting_service: SettingService = registry.get_instance("setting_service")
+# self.text: Text = registry.get_instance("text")
+#
+# def pre_start(self):
+# self.relay_hub_service.register_message_source("public_relay")
+# self.relay_hub_service.register_message_source("tell_logger")
+# self.relay_hub_service.register_message_source("system_logger")
+# self.relay_hub_service.register_message_source("access_denied_logger")
+# self.relay_hub_service.register_message_source("member_logger")
+#
+# def start(self):
+# self.relay_hub_service.register_message_destination("tell_log", self.handle_logging_tell, ["tell_logger"],
+# ["tell_log"])
+# self.setting_service.register(self.module_name, "dc_tell_log", 0, NumberSettingType(allow_empty=True),
+# "ChannelID for the Tell Log")
+#
+# self.relay_hub_service.register_message_destination("access_denied_log", self.handle_logging_denied,
+# ["access_denied_logger"], ["access_denied_log"])
+# self.setting_service.register(self.module_name, "dc_denied_log", 0, NumberSettingType(allow_empty=True),
+# "ChannelID for the Access Denied Log")
+#
+# self.relay_hub_service.register_message_destination("relay_log", self.handle_logging_relay,
+# ["alliance", "public_relay"], ["relay_log"])
+# self.setting_service.register(self.module_name, "dc_relay_log", 0, NumberSettingType(allow_empty=True),
+# "ChannelID for the Relay Log")
+#
+# self.relay_hub_service.register_message_destination("public_relay", self.handle_public_relay, ["alliance"],
+# ["public_relay"])
+# self.setting_service.register(self.module_name, "dc_relay_public", 0, NumberSettingType(allow_empty=True),
+# "ChannelID for the Public Relay Channel")
+#
+# self.relay_hub_service.register_message_destination("system", self.handle_logging_system, ["system_logger"],
+# ["system"])
+# self.setting_service.register(self.module_name, "dc_system_log", 0, NumberSettingType(allow_empty=True),
+# "ChannelID for the System Channel")
+#
+# self.relay_hub_service.register_message_destination("dc_member_log", self.handle_logging_members,
+# ["member_logger"], ["dc_member_log"])
+# self.setting_service.register(self.module_name, "dc_member_log", 0, NumberSettingType(allow_empty=True),
+# "ChannelID for the Member Log")
+#
+# if Registry.get_instance("darknet", is_optional=True):
+# self.relay_hub_service.register_message_destination("dc_darknet_log", self.handle_darknet_log, ["darknet"],
+# [""])
+# self.setting_service.register(self.module_name, "dc_darknet_log", 0, NumberSettingType(allow_empty=True),
+# "ChannelID for the Darknet Log")
+#
+# def handle_public_relay(self, ctx):
+# if self.setting_service.get_value("dc_relay_public") != "0":
+# message = self.format(ctx.formatted_message)
+# self.discord.send_message(self.setting_service.get_value("dc_relay_public"), html.unescape(message),
+# delete=3600) # delete after 1h
+#
+# def handle_logging_tell(self, ctx):
+# if self.setting_service.get_value("dc_tell_log") != "0":
+# message = self.format(ctx.message)
+# self.discord.send_message(self.setting_service.get_value("dc_tell_log"),
+# f"[FROM] {self.character_service.get_char_name(ctx.sender)}: {message}")
+#
+# def handle_logging_denied(self, ctx):
+# if self.setting_service.get_value("dc_denied_log") != "0":
+# message = self.format(ctx.message)
+# self.discord.send_message(self.setting_service.get_value("dc_denied_log"), message)
+#
+# def handle_darknet_log(self, ctx):
+# if self.setting_service.get_value("dc_darknet_log") != "0":
+# message = self.format(ctx.message)
+# self.discord.send_message(self.setting_service.get_value("dc_darknet_log"), message)
+#
+# def handle_logging_relay(self, ctx):
+# if self.setting_service.get_value("dc_relay_log") != "0":
+# message = self.format(ctx.formatted_message)
+# self.discord.send_message(self.setting_service.get_value("dc_relay_log"), f"{html.unescape(message)}")
+#
+# def handle_logging_system(self, ctx):
+# if self.setting_service.get_value("dc_system_log") != "0":
+# message = self.format(ctx.message)
+# self.discord.send_message(self.setting_service.get_value("dc_system_log"), f"{html.unescape(message)}")
+#
+# def handle_logging_members(self, ctx):
+# if self.setting_service.get_value("dc_member_log") != "0":
+# channel = self.discord.client.get_channel(int(self.setting_service.get_value("dc_member_log")))
+# spam = []
+# current = 0
+# for message in ctx.message:
+# current += 1
+# spam.append(Embed(title=f"Recent changes - {datetime.date.today()} - ({current}/{len(ctx.message)})",
+# description=message, color=3066993))
+# asyncio.run_coroutine_threadsafe(self.send_spam(channel, spam), self.discord.loop)
+#
+# async def send_spam(self, channel, message):
+# if self.discord.client.is_ready():
+# for i in message:
+# await channel.send(embed=i)
+#
+# def format(self, message):
+# return self.text.strip_html_tags(message)
diff --git a/modules/orgbot/alliance/alliance_relay.py b/modules/standard/alliance/alliance_relay.py
similarity index 81%
rename from modules/orgbot/alliance/alliance_relay.py
rename to modules/standard/alliance/alliance_relay.py
index 41b7f33..d9474cb 100644
--- a/modules/orgbot/alliance/alliance_relay.py
+++ b/modules/standard/alliance/alliance_relay.py
@@ -1,4 +1,5 @@
import re
+import typing
from core.aochat import server_packets, client_packets
from core.aochat.client_packets import PrivateChannelLeave
@@ -16,6 +17,10 @@ from core.igncore import IgnCore
# noinspection DuplicatedCode
+if typing.TYPE_CHECKING:
+ from modules.core.discord.discord_controller import DiscordController
+
+
@instance()
class AllianceRelay:
MESSAGE_SOURCE = "alliance"
@@ -30,6 +35,7 @@ class AllianceRelay:
self.character_service: CharacterService = registry.get_instance("character_service")
self.message_hub_service = registry.get_instance("message_hub_service")
self.public_channel_service = registry.get_instance("public_channel_service")
+ self.discord: DiscordController = registry.get_instance("discord_controller")
self.text: Text = registry.get_instance("text")
def pre_start(self):
@@ -54,17 +60,24 @@ class AllianceRelay:
if color:
return f"{msg}"
return "UNSET"
+
blob = ""
for bot in self.relay_bots().get_value().keys():
- enabled = self.relay_enabled().get_value().get(bot, self.relay_enabled().get_value().get('default', 'UNSET'))
+ enabled = self.relay_enabled().get_value().get(bot,
+ self.relay_enabled().get_value().get('default', 'UNSET'))
prefix = self.relay_symbols().get_value().get(bot, self.relay_symbols().get_value().get('default'))
relay_cmd = self.relay_command().get_value().get(bot, self.relay_command().get_value().get('default'))
- base = self.relay_color_base().get_value().get(bot, self.relay_color_base().get_value().get('default', None))
- sender = self.relay_color_sender().get_value().get(bot, self.relay_color_sender().get_value().get('default', None))
+ base = self.relay_color_base().get_value().get(bot,
+ self.relay_color_base().get_value().get('default', None))
+ sender = self.relay_color_sender().get_value().get(bot, self.relay_color_sender().get_value().get('default',
+ None))
abbrv = self.relay_color_org().get_value().get(bot, self.relay_color_org().get_value().get('default', None))
msg = self.relay_color_msg().get_value().get(bot, self.relay_color_msg().get_value().get('default', None))
- our_abbrv = self.relay_guild_abbreviations().get_value().get(bot, self.relay_guild_abbreviations().get_value().get('default', 'UNSET'))
- example = display_color(base, f'[{display_color(abbrv, our_abbrv)}] {display_color(sender, request.sender.name)}: {display_color(msg, "And I sent you a message")}')
+ our_abbrv = self.relay_guild_abbreviations().get_value().get(bot,
+ self.relay_guild_abbreviations().get_value().get(
+ 'default', 'UNSET'))
+ example = display_color(base,
+ f'[{display_color(abbrv, our_abbrv)}] {display_color(sender, request.sender.name)}: {display_color(msg, "And I sent you a message")}')
blob += f"Relay {self.character_service.get_char_name(int(bot))}:\n"
blob += f" Enabled: {enabled} [{self.text.make_tellcmd('Toggle', f'mrelay status {bot} {not enabled}')}]\n"
blob += f" Prefix: {prefix} [{self.text.make_tellcmd('Edit', f'mrelay prefix {bot}')}]\n"
@@ -148,7 +161,8 @@ class AllianceRelay:
return f"Successfully deleted relay {bot.name}"
@command(command="mrelay",
- params=[Const("rcmd"), Character("relaybot_name"), Any("relay_command", is_optional=True)], access_level="admin",
+ params=[Const("rcmd"), Character("relaybot_name"), Any("relay_command", is_optional=True)],
+ access_level="admin",
description="Change the relay command used in a relay")
def mrelay_rcmd(self, request, _, bot, relay_command):
bots: dict = self.relay_bots().get_value()
@@ -173,7 +187,8 @@ class AllianceRelay:
f"{self.character_service.get_char_name(int(bot))}: {relay_command}"
@command(command="mrelay",
- params=[Const("prefix"), Character("relaybot_name"), Any("prefix", is_optional=True)], access_level="admin",
+ params=[Const("prefix"), Character("relaybot_name"), Any("prefix", is_optional=True)],
+ access_level="admin",
description="Change the prefix setting of the relays")
def mrelay_prefix(self, request, _, bot, prefix):
bots: dict = self.relay_bots().get_value()
@@ -234,7 +249,9 @@ class AllianceRelay:
return f"Successfully changed the status of the relay " \
f"{self.character_service.get_char_name(int(bot))} to: {option}"
- @command(command="mrelay", params=[Const("color"), Character("relaybot_name"), Options(["base", "sender", "org", "msg"]), Any("color_code", is_optional=True)], access_level="admin",
+ @command(command="mrelay",
+ params=[Const("color"), Character("relaybot_name"), Options(["base", "sender", "org", "msg"]),
+ Any("color_code", is_optional=True)], access_level="admin",
description="Change the color settings of the relays")
def mrelay_color(self, request, _, bot, option, color):
bots: dict = self.relay_bots().get_value()
@@ -312,7 +329,8 @@ class AllianceRelay:
return
if str(packet.private_channel_id) not in self.relay_bots().get_value().keys():
return
- if not self.relay_enabled().get_value().get(str(packet.private_channel_id), self.relay_enabled().get_value().get('default', False)):
+ if not self.relay_enabled().get_value().get(str(packet.private_channel_id),
+ self.relay_enabled().get_value().get('default', False)):
return
self.bot.send_packet(client_packets.PrivateChannelJoin(packet.private_channel_id))
self.logger.info(f"Joined private channel {self.character_service.get_char_name(packet.private_channel_id)}")
@@ -344,38 +362,72 @@ class AllianceRelay:
text = text.strip()
plain = f"[{org}] {name}: {text}"
- org = self.format_text(self.relay_color_org().get_value().get(priv, self.relay_color_org().get_value().get("default")), org)
- name = self.format_text(self.relay_color_sender().get_value().get(priv, self.relay_color_sender().get_value().get("default")), name)
- text = self.format_text(self.relay_color_msg().get_value().get(priv, self.relay_color_msg().get_value().get("default")), text)
- formatted = self.format_text(self.relay_color_base().get_value().get(priv, self.relay_color_base().get_value().get("default")), f"[{org}] {name}: {text}")
+ org = self.format_text(
+ self.relay_color_org().get_value().get(priv, self.relay_color_org().get_value().get("default")), org)
+ name = self.format_text(
+ self.relay_color_sender().get_value().get(priv, self.relay_color_sender().get_value().get("default")), name)
+ text = self.format_text(
+ self.relay_color_msg().get_value().get(priv, self.relay_color_msg().get_value().get("default")), text)
+ formatted = self.format_text(
+ self.relay_color_base().get_value().get(priv, self.relay_color_base().get_value().get("default")),
+ f"[{org}] {name}: {text}")
sender = DictObject({"char_id": packet.char_id, "name": self.character_service.get_char_name(packet.char_id)})
- self.message_hub_service.send_message(self.MESSAGE_SOURCE, sender, plain, formatted)
+ self.message_hub_service.send_message(self.MESSAGE_SOURCE, sender, self.text.strip_html_tags(plain), formatted)
def handle_relay_hub_message(self, ctx):
- enabled = lambda x: self.relay_enabled().get_value().get(x, self.relay_enabled().get_value().get('default', False))
+ enabled = lambda x: self.relay_enabled().get_value().get(x,
+ self.relay_enabled().get_value().get('default', False))
if not ctx.message:
return
+ if not ctx.sender:
+ return
+ if type(ctx.message) == ChatBlob:
+ return
for key in self.relay_bots().get_value().keys():
if key not in self.relay_channel:
continue
if not enabled(key):
continue
prefix = self.relay_symbols().get_value().get(key, self.relay_symbols().get_value().get('default', False))
- if not ctx.message.startswith(prefix):
+ if not(ctx.message.startswith(prefix)):
continue
-
+ sender = ctx.sender.name
message = ctx.message[len(prefix):].strip()
if len(message) < 1:
continue
- sender = ctx.sender.name
abbrv = self.relay_guild_abbreviations().get_value().get(key, self.setting_service.get_value("org_name"))
if ctx.source == "private_channel":
abbrv += " - Guest"
- elif ctx.source == "public_relay":
+ elif ctx.source.startswith("Discord_("):
abbrv += " - DC"
+
cmd = self.relay_command().get_value().get(key, self.relay_command().get_value().get("default"))
- msg = f"{cmd} [{abbrv}] {sender}: {message}"
+ # msg = f"{cmd} [{abbrv}] {sender}: {message}"
+ blob = ""
+ if ctx.source.startswith("Discord_("):
+ if self.discord.alias_usage().get_value():
+ abbrv = self.discord.alias_controller.get_alias(ctx.sender.org_id)
+ invite = self.text.make_chatcmd("click here", "/tell discord invite",
+ style="style='text-decoration:none'")
+ # name = ""
+ if self.discord.guild and self.discord.bot:
+ name = f"DC Server: {self.discord.guild.name} - " \
+ f"Bot: "
+ blob = self.text.format_page('Info',
+ f"
"
+ f"This message has been sent to you by:
"
+ f"{name}
"
+ f"Sender: {ctx.sender.name}
"
+ f"Tag: {ctx.sender.discord_nick}
"
+ f"To reply, either respond in the relay or "
+ f"contact them directly at the provided handles.
"
+ f"Have you joined our Discord Server yet? "
+ f"If not {invite} to receive an invite.")
+ blob = f"[{blob}]"
+ # msg = f"{cmd} [{self.discord.alias_controller.get_alias(ctx.sender.org_id)}] {ctx.message} [{blob}]"
+ msg = f"{cmd} [{abbrv}] {sender}: {message} {blob}"
+
self.send_message_to_alliance(key, msg)
def send_message_to_alliance(self, alliance, msg):
@@ -398,7 +450,8 @@ class AllianceRelay:
def relay_enabled(self) -> DictionarySettingType:
return DictionarySettingType()
- @setting(name="relay_guild_abbreviations", value={"default": "UNSET"}, description="Abbreviations used for the relays")
+ @setting(name="relay_guild_abbreviations", value={"default": "UNSET"},
+ description="Abbreviations used for the relays")
def relay_guild_abbreviations(self) -> DictionarySettingType:
return DictionarySettingType()
@@ -431,3 +484,6 @@ class AllianceRelay:
def format_text(self, color, message):
return f"{message}"
+
+ # def alias_usage(self):
+ # return self.setting_service.get("use_prefix")
diff --git a/modules/standard/helpbot/time_controller.py b/modules/standard/helpbot/time_controller.py
index 445b6b5..70edb62 100644
--- a/modules/standard/helpbot/time_controller.py
+++ b/modules/standard/helpbot/time_controller.py
@@ -47,7 +47,7 @@ class TimeController:
day += "rd"
else:
day += "th"
- return f"Currently its {now.hour}:{now.minute}:{now.second} " \
+ return f"Currently its {now.hour:02}:{now.minute:02}:{now.second:02} " \
f"{calendar.month_name[now.month]} {day}, {now.year + 27474} Rubi-Ka Universal Time."
@command(command="time", params=[Any("timezone")], access_level="member",
diff --git a/modules/standard/news/weekly_controller.py b/modules/standard/news/weekly_controller.py
index b3124ad..1d22ff4 100644
--- a/modules/standard/news/weekly_controller.py
+++ b/modules/standard/news/weekly_controller.py
@@ -1,4 +1,5 @@
import time
+import typing
from datetime import datetime
from core.buddy_service import BuddyService
@@ -8,16 +9,17 @@ from core.db import DB
from core.decorators import instance, command
from core.job_scheduler import JobScheduler
from core.logger import Logger
-from core.lookup.pork_service import PorkService
-from core.setting_service import SettingService
from core.text import Text
from core.igncore import IgnCore
from core.util import Util
-from modules.core.accounting.preference_controller import PreferenceController
-from modules.core.accounting.services.account_service import AccountService
-from modules.core.ban.ban_service import BanService
-from modules.core.discord.discord_controller import DiscordController
-from modules.onlinebot.online.org_alias_controller import OrgAliasController
+if typing.TYPE_CHECKING:
+ from core.lookup.pork_service import PorkService
+ from core.setting_service import SettingService
+ from modules.core.accounting.preference_controller import PreferenceController
+ from modules.core.accounting.services.account_service import AccountService
+ from modules.core.ban.ban_service import BanService
+ from modules.core.discord.discord_controller import DiscordController
+ from modules.onlinebot.online.org_alias_controller import OrgAliasController
@instance()
diff --git a/modules/standard/news/worldboss_controller.py b/modules/standard/news/worldboss_controller.py
index db628b9..51858ba 100644
--- a/modules/standard/news/worldboss_controller.py
+++ b/modules/standard/news/worldboss_controller.py
@@ -3,13 +3,14 @@ import time
from core.chat_blob import ChatBlob
from core.command_alias_service import CommandAliasService
from core.command_param_types import Any
-from core.decorators import instance, command, event
+from core.decorators import instance, command, event, setting
from core.dict_object import DictObject
from core.igncore import IgnCore
from core.job_scheduler import JobScheduler
from core.logger import Logger
+from core.message_hub_service import MessageHubService
from core.setting_service import SettingService
-from core.setting_types import BooleanSettingType
+from core.setting_types import BooleanSettingType, TextSettingType
from core.text import Text
from core.util import Util
from modules.standard.datanet.ws_controller import WebsocketRelayController
@@ -35,8 +36,11 @@ class WorldBossController:
self.command_alias_service: CommandAliasService = registry.get_instance("command_alias_service")
self.job_scheduler: JobScheduler = registry.get_instance("job_scheduler")
self.setting_service: SettingService = registry.get_instance("setting_service")
+ self.relay_hub: MessageHubService = registry.get_instance("message_hub_service")
def pre_start(self):
+ self.relay_hub.register_message_source("timers")
+
self.setting_service.register(self.module_name, 'timer_spam', False, BooleanSettingType(),
"should timers be spammed")
self.command_alias_service.add_alias("tara", "wb tara")
@@ -120,7 +124,7 @@ class WorldBossController:
return DictObject({'spawn': last - immortal, 'mortal': last})
def send_warn(self, msg):
- self.bot.send_private_channel_message(f"[WB] {msg}")
+ self.relay_hub.send_message("timers", None, f"[WB] {msg}", f"[WB] {msg}")
def get_next_alert(self, duration):
for alert in self.alerts:
@@ -190,3 +194,8 @@ class WorldBossController:
job['id'] = job_id
return
self.jobs.append({'name': timer.name, 'id': job_id})
+
+ # @setting('alert_times', '[480 * 60, 360 * 60, 240 * 60, 120 * 60, 60 * 60, 60 * 15, 60 * 5, 60 * 3, 60 * 2, 60, 30, 15, 5, 0]', 'Worldboss timer spam messages (ETA and actual)')
+ # def alert_times(self):
+ # return TextSettingType(['[480 * 60, 360 * 60, 240 * 60, 120 * 60, 60 * 60, 60 * 15, 60 * 5, 60 * 3, 60 * 2, 60, 30, 15, 5, 0]'])
+
diff --git a/modules/standard/online/online_display.py b/modules/standard/online/online_display.py
index 59879a8..d7f15b8 100644
--- a/modules/standard/online/online_display.py
+++ b/modules/standard/online/online_display.py
@@ -39,11 +39,11 @@ class OnlineDisplay:
if org > 0:
postfix.append(f"Org: {org}")
if priv > 0:
- postfix.append(f"Priv: {priv}")
+ postfix.append(f"Priv: {priv}")
if notify > 0:
postfix.append(f"Buddylist: {notify}")
blob = ChatBlob(title, blob, suffix=f" ({f', '.join(postfix)})")
- return blob
+ return blob if (org+priv+notify) != 0 else "There's nobody online."
def format_by_channel_main(self, query, params):
query += "order by channel_id, main_name, p.name=main_name, p.name, r_id"
@@ -161,7 +161,7 @@ class OnlineDisplay:
if org_id != temp_blob[key]["id"]:
org_id = temp_blob[key]["id"]
blob += f"\n{temp_blob[key]['name']}" \
- f" ({len(temp_blob[key]['online']): >3} " \
+ f" ({len(temp_blob[key]['online']): >3} " \
f"| {len(temp_blob[key]['online']) / len(query) * 100:.2f}%)\n"
blob += self.format_org(user)
return blob, 0, 0, len(query)
diff --git a/modules/standard/specials/specials_controller.py b/modules/standard/specials/specials_controller.py
index ab003cf..171b433 100644
--- a/modules/standard/specials/specials_controller.py
+++ b/modules/standard/specials/specials_controller.py
@@ -214,18 +214,18 @@ class SpecialsController:
blob += "Martial Artist\n"
blob += f"Speed: {ma_info.ma_speed:.2f} / {ma_info.ma_speed:.2f} secs\n"
- blob += f"Damage: {ma_info.ma_min_dmg:d} - {ma_info.ma_max_dmg:d} " \
- f"({ma_info.ma_crit_dmg:d})\n\n"
+ blob += f"Damage: {ma_info.ma_min_dmg:.2f} - {ma_info.ma_max_dmg:.2f} " \
+ f"({ma_info.ma_crit_dmg:.2f})\n\n"
blob += "Shade\n"
blob += f"Speed: {ma_info.shade_speed:.2f} / {ma_info.shade_speed:.2f} secs\n"
- blob += f"Damage: {ma_info.shade_min_dmg:d} - {ma_info.shade_max_dmg:d} " \
- f"({ma_info.shade_crit_dmg:d})\n\n"
+ blob += f"Damage: {ma_info.shade_min_dmg:.2f} - {ma_info.shade_max_dmg:.2f} " \
+ f"({ma_info.shade_crit_dmg:.2f})\n\n"
blob += "All other professions\n"
blob += f"Speed: {ma_info.gen_speed:.2f} / {ma_info.gen_speed:.2f} secs\n"
- blob += f"Damage: {ma_info.gen_min_dmg:d} - {ma_info.gen_max_dmg:d} " \
- f"({ma_info.gen_crit_dmg:d})\n\n"
+ blob += f"Damage: {ma_info.gen_min_dmg:.2f} - {ma_info.gen_max_dmg:.2f} " \
+ f"({ma_info.gen_crit_dmg:.2f})\n\n"
return ChatBlob("Martial Arts Results", blob)
diff --git a/modules/standard/whois/character_info_controller.py b/modules/standard/whois/character_info_controller.py
index 25e0eee..264e461 100644
--- a/modules/standard/whois/character_info_controller.py
+++ b/modules/standard/whois/character_info_controller.py
@@ -108,12 +108,12 @@ class CharacterInfoController:
blob += self.alts_controller.format_alt_list(alts)
more_info = self.text.paginate_single(ChatBlob("More Info", blob))
-
- msg = self.text.format_char_info(char_info, online_status, True) + " " + more_info
+ msg = ChatBlob("More Info", blob, self.text.format_char_info(char_info, online_status, True)+" ")
+ # msg = self.text.format_char_info(char_info, online_status, True) + " " + more_info
elif char.char_id:
blob = "Note: Could not retrieve detailed info for character.\n\n"
blob += f"Name: {char.name}\n"
- blob += f"Character ID: {char.char_id:d}\n"
+ blob += f"Character ID: {char.char_id}\n"
if online_status is not None:
blob += f"Online status: {'Online' if online_status else 'Offline'}\n"
blob += self.get_name_history(char.char_id)
diff --git a/requirements.txt b/requirements.txt
index 401bb23..3ed08c0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
bbcode==1.1.0
beautifulsoup4==4.10.0
cryptography==3.3.2
-discord.py @ git+https://github.com/Rapptz/discord.py@45d498c1b76deaf3b394d17ccf56112fa691d160
+discord.py @ git+https://github.com/Rapptz/discord.py@1bfe6b2bb160ce802a1f08afed73941a19a0a651
emojis==0.6.0
hjson==3.0.2
mariadb==1.0.7