Added the option to !opt-in/opt-out [onlinebot only]

Fixed command & event threading
Events are now threaded by event_type (i.e. all buddy_logon events get ran in the same one)
Added default preferences
Fixed recipe loading for multiple installs (i.e. on different machines)
This commit is contained in:
2021-08-27 13:58:47 +02:00
parent d0c8c1744c
commit c04f76c0db
24 changed files with 258 additions and 122 deletions
+4 -4
View File
@@ -17,7 +17,7 @@ from core.upgrade import run_upgrades
def get_config_from_env(): def get_config_from_env():
config_obj = DictObject() config_obj = DictObject()
for k, v in os.environ.items(): for k, v in os.environ.items():
if k.startswith("TYRBOT_"): if k.startswith("IGNCORE_"):
keys = k[7:].lower().split("_") keys = k[7:].lower().split("_")
temp_config = config_obj temp_config = config_obj
for key in keys[:-1]: for key in keys[:-1]:
@@ -26,7 +26,7 @@ def get_config_from_env():
if key not in temp_config: if key not in temp_config:
temp_config[key] = DictObject() temp_config[key] = DictObject()
temp_config = temp_config.get(key) temp_config = temp_config.get(key)
logger.debug("overriding config value from env var '%s'" % k) logger.debug(f"overriding config value from env var '{k}'")
if v.lower() == "true": if v.lower() == "true":
v = True v = True
elif v.lower() == "false": elif v.lower() == "false":
@@ -46,7 +46,7 @@ try:
print("Unknown bot specified. Please edit your ##botname##.start.sh accordingly to the instructions found in the README.") print("Unknown bot specified. Please edit your ##botname##.start.sh accordingly to the instructions found in the README.")
exit(0) exit(0)
logger = Logger("core.bootstrap") logger = Logger("core.bootstrap")
logger.info("Starting Tyrbot...") logger.info("Starting Bot...")
mod = __import__(f'conf.{bot}', fromlist=['BotConfig']) mod = __import__(f'conf.{bot}', fromlist=['BotConfig'])
config: BotConfig = getattr(mod, 'BotConfig') config: BotConfig = getattr(mod, 'BotConfig')
if sys.version_info < (3, 9): if sys.version_info < (3, 9):
@@ -72,7 +72,7 @@ try:
config.server.dimension = int(config.server.dimension) config.server.dimension = int(config.server.dimension)
if platform.system() == "Windows": if platform.system() == "Windows":
os.system("title %s.%d" % (config.character, config.server.dimension)) os.system(f"title {config.character}.{config.server.dimension:d}")
# paths to search for instances: core + module_paths # paths to search for instances: core + module_paths
paths = ["core"] paths = ["core"]
+2 -2
View File
@@ -41,10 +41,10 @@ class Bot:
# read character list # read character list
character_list_packet: LoginCharacterList = self.read_packet() character_list_packet: LoginCharacterList = self.read_packet()
if isinstance(character_list_packet, LoginError): if isinstance(character_list_packet, LoginError):
self.logger.error("Error logging in: %s" % character_list_packet.message) self.logger.error(f"Error logging in: {character_list_packet.message}")
return False return False
if character not in character_list_packet.names: if character not in character_list_packet.names:
self.logger.error("Character '%s' does not exist on this account" % character) self.logger.error(f"Character '{character}' does not exist on this account")
return False return False
index = character_list_packet.names.index(character) index = character_list_packet.names.index(character)
+3 -3
View File
@@ -1,9 +1,9 @@
class ChatBlob: class ChatBlob:
def __init__(self, title, msg): def __init__(self, title, msg, prefix="", suffix=""):
self.title = title self.title = title
self.msg = msg.strip("\n") self.msg = msg.strip("\n")
self.page_prefix = "" self.page_prefix = prefix
self.page_postfix = "" self.page_postfix = suffix
def __str__(self): def __str__(self):
return f"ChatBlob('{self.title}', '{self.msg}')" return f"ChatBlob('{self.title}', '{self.msg}')"
+17 -16
View File
@@ -86,7 +86,7 @@ class CommandService:
al = access_levels.get(command_key, None) al = access_levels.get(command_key, None)
if al is not None and al != access_level.lower(): if al is not None and al != access_level.lower():
print(handler) print(handler)
raise Exception("Different access levels specified for forms of command '%s'" % command_key) raise Exception(f"Different access levels specified for forms of command '{command_key}'")
access_levels[command_key] = access_level access_levels[command_key] = access_level
self.register(handler, cmd_name, params, access_level, description, inst.module_name, help_text, self.register(handler, cmd_name, params, access_level, description, inst.module_name, help_text,
@@ -182,10 +182,10 @@ class CommandService:
""" """
if value in self.channels: if value in self.channels:
self.logger.error("Could not register command channel '%s': command channel already registered" % value) self.logger.error(f"Could not register command channel '{value}': command channel already registered")
return return
self.logger.debug("Registering command channel '%s'" % value) self.logger.debug(f"Registering command channel '{value}'")
self.channels[value] = label self.channels[value] = label
def is_command_channel(self, channel): def is_command_channel(self, channel):
@@ -228,11 +228,11 @@ class CommandService:
command_alias = self.command_alias_service.check_for_alias(command_str) command_alias = self.command_alias_service.check_for_alias(command_str)
if alias_depth_count > 20: if alias_depth_count > 20:
raise Exception("Command alias infinite recursion detected for command '%s'" % message) raise Exception(f"Command alias infinite recursion detected for command '{message}'")
cmd_configs = self.get_command_configs(command_str, channel) cmd_configs = self.get_command_configs(command_str, channel)
access_level = self.access_service.get_access_level(char_id) access_level = self.access_service.get_access_level(char_id)
sender = SenderObj(char_id, self.character_service.resolve_char_to_name(char_id, "Unknown(%d)" % char_id), sender = SenderObj(char_id, self.character_service.resolve_char_to_name(char_id, f"Unknown({char_id:d})"),
access_level) access_level)
if cmd_configs: if cmd_configs:
# given a list of cmd_configs that are enabled, see if one has regex that matches incoming command_str # given a list of cmd_configs that are enabled, see if one has regex that matches incoming command_str
@@ -245,7 +245,7 @@ class CommandService:
if response is not None: if response is not None:
reply(response) reply(response)
except Exception as e: except Exception as e:
self.logger.error("error processing command: %s" % message, e) self.logger.error(f"error processing command: {message}", e)
self.relay_hub_service.send_message("access_denied_logger", sender, self.relay_hub_service.send_message("access_denied_logger", sender,
f"[ERROR] {sender.name}: {message}", f"[ERROR] {sender.name}: {message}",
f"[ERROR] {sender.name}: {message}") f"[ERROR] {sender.name}: {message}")
@@ -262,16 +262,17 @@ class CommandService:
reply(self.format_help_text(command_str, help_text)) reply(self.format_help_text(command_str, help_text))
else: else:
# the command is known, but no help is returned, therefore user does not have access to command # the command is known, but no help is returned, therefore user does not have access to command
if access_level['label'] != "all": self.access_denied_response(message, sender, cmd_config, reply)
self.relay_hub_service.send_message("access_denied_logger", sender, # if access_level['label'] != "all":
f"[DENIED] {sender.name}: {message}", # self.relay_hub_service.send_message("access_denied_logger", sender,
f"[DENIED] {sender.name}: {message}") # f"[DENIED] {sender.name}: {message}",
self.bot.send_mass_message(char_id, self.getresp("global", "access_denied")) # f"[DENIED] {sender.name}: {message}")
# self.bot.send_mass_message(char_id, self.getresp("global", "access_denied"))
else: else:
self.handle_unknown_command(command_str, command_args, channel, sender, reply) self.handle_unknown_command(command_str, command_args, channel, sender, reply)
except Exception as e: except Exception as e:
self.logger.error("error processing command: %s" % message, e) self.logger.error(f"error processing command: {message}", e)
sender = SenderObj(char_id, self.character_service.resolve_char_to_name(char_id, "Unknown(%d)" % char_id), sender = SenderObj(char_id, self.character_service.resolve_char_to_name(char_id, f"Unknown({char_id:d})"),
0) 0)
self.relay_hub_service.send_message("access_denied_logger", sender, f"[ERROR] {sender.name}: {message}", self.relay_hub_service.send_message("access_denied_logger", sender, f"[ERROR] {sender.name}: {message}",
f"[ERROR] {sender.name}: {message}") f"[ERROR] {sender.name}: {message}")
@@ -426,7 +427,7 @@ class CommandService:
False) False)
t: Thread = Thread(target=i, daemon=True) t: Thread = Thread(target=i, daemon=True)
t.run() t.start()
def handle_private_channel_message(self, conn: Conn, packet: server_packets.PrivateChannelMessage): def handle_private_channel_message(self, conn: Conn, packet: server_packets.PrivateChannelMessage):
if not self.setting_service.get("accept_commands_from_slave_bots").get_value() and conn.id != "main": if not self.setting_service.get("accept_commands_from_slave_bots").get_value() and conn.id != "main":
@@ -449,7 +450,7 @@ class CommandService:
lambda msg: self.bot.send_private_channel_message(msg, private_channel_id=conn.char_id, lambda msg: self.bot.send_private_channel_message(msg, private_channel_id=conn.char_id,
conn_id=conn.id), conn_id=conn.id),
conn, conn,
False), daemon=True).run() False), daemon=True).start()
def handle_public_channel_message(self, conn: Conn, packet: server_packets.PublicChannelMessage): def handle_public_channel_message(self, conn: Conn, packet: server_packets.PublicChannelMessage):
if not self.setting_service.get("accept_commands_from_slave_bots").get_value() and conn.id != "main": if not self.setting_service.get("accept_commands_from_slave_bots").get_value() and conn.id != "main":
@@ -472,7 +473,7 @@ class CommandService:
packet.char_id, packet.char_id,
lambda msg: self.bot.send_org_message(msg, conn_id=conn.id), lambda msg: self.bot.send_org_message(msg, conn_id=conn.id),
conn, conn,
False), daemon=True).run() False), daemon=True).start()
def trim_command_symbol(self, s): def trim_command_symbol(self, s):
symbol = self.setting_service.get("symbol").get_value() symbol = self.setting_service.get("symbol").get_value()
+3 -4
View File
@@ -75,13 +75,12 @@ class DB:
if string.__contains__("UPDATE ") or string.__contains__("INSERT "): if string.__contains__("UPDATE ") or string.__contains__("INSERT "):
conn.commit() conn.commit()
except Exception as e: except Exception as e:
raise SqlException("SQL Error: '%s' for '%s' [%s]" % ( raise SqlException( f"SQL Error: '{str(e)}' for '{sql}' "
str(e), sql, ", ".join(map(lambda x: str(x), params)))) from e f"[{', '.join(map(lambda x: str(x), params))}]") from e
elapsed = time.time() - start_time elapsed = time.time() - start_time
result = callback(cur) result = callback(cur)
if elapsed > 5: if elapsed > 5:
self.logger.warning("slow query (%fs) '%s' for params: %s" % (elapsed, sql, str(params))) self.logger.warning(f"slow query ({elapsed:f}s) '{sql}' for params: {str(params)}")
return result return result
def query_single(self, sql, params=None, extended_like=False) -> DictObject: def query_single(self, sql, params=None, extended_like=False) -> DictObject:
+19 -13
View File
@@ -72,7 +72,7 @@ class EventService:
""" """
if len(inspect.signature(handler).parameters) != 2: if len(inspect.signature(handler).parameters) != 2:
raise Exception( raise Exception(
"Incorrect number of arguments for handler '%s.%s()'" % (handler.__module__, handler.__name__)) f"Incorrect number of arguments for handler '{handler.__module__}.{handler.__name__}()'")
event_base_type, event_sub_type = self.get_event_type_parts(event_type) event_base_type, event_sub_type = self.get_event_type_parts(event_type)
module = module.lower() module = module.lower()
@@ -80,12 +80,12 @@ class EventService:
is_hidden = 1 if is_hidden else 0 is_hidden = 1 if is_hidden else 0
is_enabled = 1 if is_enabled else 0 is_enabled = 1 if is_enabled else 0
if event_base_type not in self.event_types: if event_base_type not in self.event_types:
self.logger.error("Could not register handler '%s' for event type '%s': event type does not exist" % ( self.logger.error(
handler_name, event_type)) f"Could not register handler '{handler_name}' for event type '{event_type}': event type does not exist")
return return
if not description: if not description:
self.logger.warning("No description for event_type '%s' and handler '%s'" % (event_type, handler_name)) self.logger.warning(f"No description for event_type '{event_type}' and handler '{handler_name}'")
row = self.db.query_single("SELECT 1 FROM event_config WHERE event_type = ? AND handler = ?", row = self.db.query_single("SELECT 1 FROM event_config WHERE event_type = ? AND handler = ?",
[event_base_type, handler_name]) [event_base_type, handler_name])
@@ -117,28 +117,34 @@ class EventService:
event_base_type, event_sub_type = self.get_event_type_parts(event_type) event_base_type, event_sub_type = self.get_event_type_parts(event_type)
if event_base_type not in self.event_types: if event_base_type not in self.event_types:
self.logger.error("Could not fire event type '%s': event type does not exist" % event_type) self.logger.error(f"Could not fire event type '{event_type}': event type does not exist")
return return
data = self.get_handlers(event_base_type, event_sub_type) data = self.get_handlers(event_base_type, event_sub_type)
for row in data:
if event_type != "connect": # We dont want to spawn a new Thread for each event handler, but only per event type.
t = Thread(target=self.call_handler, args=(row.handler, event_type, event_data), daemon=True) def i():
t.run() for row in data:
else: if event_type != "connect":
self.call_handler(row.handler, event_type, event_data) self.call_handler(row.handler, event_type, event_data)
else:
self.call_handler(row.handler, event_type, event_data)
if event_type != "connect":
Thread(target=i, daemon=True).start()
else:
i()
def call_handler(self, handler_method, event_type, event_data): def call_handler(self, handler_method, event_type, event_data):
handler = self.handlers.get(handler_method, None) handler = self.handlers.get(handler_method, None)
if not handler: if not handler:
self.logger.error( self.logger.error(
"Could not find handler callback for event type '%s' and handler '%s'" % (event_type, handler_method)) f"Could not find handler callback for event type '{event_type}' and handler '{handler_method}'")
return return
try: try:
handler(event_type, event_data) handler(event_type, event_data)
except Exception as e: except Exception as e:
self.logger.error("error processing event '%s'" % event_type, e) self.logger.error(f"error processing event '{event_type}'", e)
def get_event_type_parts(self, event_type): def get_event_type_parts(self, event_type):
parts = event_type.lower().split(":", 1) parts = event_type.lower().split(":", 1)
+4 -4
View File
@@ -41,13 +41,13 @@ class CharacterHistoryService:
# with TorRequests() as tor_request: # with TorRequests() as tor_request:
# with tor_request.get_session(1) as session: # with tor_request.get_session(1) as session:
# r = session.get(url, timeout=5) # r = session.get(url, timeout=5)
r = requests.get(url, timeout=5, headers={"User-Agent": self.bot.major_version}) # r = requests.get(url, timeout=5, headers={"User-Agent": self.bot.major_version})
result = r.json() result = json.loads(r)
except ReadTimeout: except ReadTimeout:
self.logger.warning("Timeout while requesting '%s'" % url) self.logger.warning(f"Timeout while requesting '{url}'")
result = None result = None
except Exception as e: except Exception as e:
self.logger.error("Error requesting history for url '%s'" % url, e) self.logger.error(f"Error requesting history for url '{url}'", e)
result = None result = None
if result: if result:
+1 -1
View File
@@ -33,7 +33,7 @@ class PrivateChannelService:
self.bot.register_packet_handler(server_packets.PrivateChannelMessage.id, self.bot.register_packet_handler(server_packets.PrivateChannelMessage.id,
self.handle_private_channel_message, priority=30) self.handle_private_channel_message, priority=30)
self.access_service.register_access_level("guest", 95, self.in_private_channel) self.access_service.register_access_level("guest", 94, self.in_private_channel)
def handle_private_channel_message(self, conn: Conn, packet: server_packets.PrivateChannelMessage): def handle_private_channel_message(self, conn: Conn, packet: server_packets.PrivateChannelMessage):
if conn.id != "main": if conn.id != "main":
+1 -1
View File
@@ -207,7 +207,7 @@ class Text:
label2 = self.format_message(label) label2 = self.format_message(label)
else: else:
label2 = self.format_message(label) + " (Page " + str(index) + " / " + str(num_pages) + ")" label2 = self.format_message(label) + " (Page " + str(index) + " / " + str(num_pages) + ")"
return chatblob.page_prefix + self.format_page(label2, page) + chatblob.page_postfix return self.format_message(chatblob.page_prefix) + self.format_page(label2, page) + self.format_message(chatblob.page_postfix)
return list(map(mapper, zip(pages, range(1, num_pages + 1)))) return list(map(mapper, zip(pages, range(1, num_pages + 1))))
+1 -1
View File
@@ -42,7 +42,7 @@ class Tyrbot:
self.last_timer_event = 0 self.last_timer_event = 0
self.start_time = int(time.time()) self.start_time = int(time.time())
self.major_version = "IGNCore v2.5" self.major_version = "IGNCore v2.5"
self.minor_version = "1" self.minor_version = "2"
self.incoming_queue = FifoQueue() self.incoming_queue = FifoQueue()
self.mass_message_queue = None self.mass_message_queue = None
self.conns = DictObject() self.conns = DictObject()
@@ -2,6 +2,7 @@ import inspect
from typing import List from typing import List
from core.decorators import instance from core.decorators import instance
from core.dict_object import DictObject
from core.logger import Logger from core.logger import Logger
@@ -100,14 +101,17 @@ class AccessService:
for access_level in self.access_levels: for access_level in self.access_levels:
if access_level["level"] == level: if access_level["level"] == level:
return access_level return access_level
return False self.logger.warning(f"Access to undefined Accesslevel detected: {level} - answering with rank 'None'")
return DictObject({"label": "none", "level": 0, "handler": self.no_access})
def get_access_level_by_label(self, label) -> dict or bool: def get_access_level_by_label(self, label) -> dict or bool:
label = label.lower() label = label.lower()
for access_level in self.access_levels: for access_level in self.access_levels:
if access_level["label"] == label: if access_level["label"] == label:
return access_level return access_level
return False
self.logger.warning(f"Access to undefined Accesslevel detected: {label} - answering with rank 'None'")
return DictObject({"label": "none", "level": 0, "handler": self.no_access})
def check_access(self, char, access_level_label) -> bool: def check_access(self, char, access_level_label) -> bool:
char_id = self.character_service.resolve_char_to_id(char) char_id = self.character_service.resolve_char_to_id(char)
@@ -122,16 +122,27 @@ class AccountService:
"Is this bot used as an alliancebot") "Is this bot used as an alliancebot")
self.setting_service.register_new(self.module_name, "alt_verification", False, BooleanSettingType(), self.setting_service.register_new(self.module_name, "alt_verification", False, BooleanSettingType(),
"alts require admin verification") "alts require admin verification")
# Default preferences
self.setting_service.register_new(self.module_name, "pref_autoinvite", False, BooleanSettingType(),
"Default Value for the auto invite preference")
self.setting_service.register_new(self.module_name, "pref_raidinvite", True, BooleanSettingType(),
"Default Value for the raid invite (Massinvite) preference")
self.setting_service.register_new(self.module_name, "pref_raidspam", True, BooleanSettingType(),
"Default Value for the raid spam (Mass Message) preference")
self.setting_service.register_new(self.module_name, "pref_newsspam", True, BooleanSettingType(),
"Default Value for the news spam (News on logon) preference")
v = self.setting_service.get_value("pref_raidspam")
# Ranks
if self.setting_service.get_value("is_alliance_bot") == "1": if self.setting_service.get_value("is_alliance_bot") == "1":
self.access_service.register_access_level("officer", 80, self.check_officer) self.access_service.register_access_level("officer", 80, self.check_officer)
self.access_service.register_access_level("general", 70, self.check_general) self.access_service.register_access_level("general", 70, self.check_general)
self.access_service.register_access_level("president", 60, self.check_president) self.access_service.register_access_level("president", 60, self.check_president)
self.access_service.register_access_level("council", 40, self.check_council) self.access_service.register_access_level("council", 40, self.check_council)
self.access_service.register_access_level("moderator", 30, self.check_moderator)
self.access_service.register_access_level("member", 90, self.check_member) self.access_service.register_access_level("member", 90, self.check_member)
self.access_service.register_access_level("admin", 20, self.check_admin)
self.access_service.register_access_level("leader", 50, self.check_leader) self.access_service.register_access_level("leader", 50, self.check_leader)
self.access_service.register_access_level("moderator", 30, self.check_moderator)
self.access_service.register_access_level("admin", 20, self.check_admin)
self.access_service.register_access_level("superadmin", 10, self.check_superadmin) self.access_service.register_access_level("superadmin", 10, self.check_superadmin)
def get_main(self, char_id) -> DictObject: def get_main(self, char_id) -> DictObject:
@@ -300,19 +311,28 @@ class AccountService:
return [self.bot.public_channel_service.org_id] return [self.bot.public_channel_service.org_id]
def create_users(self, users, disable=False) -> int: def create_users(self, users, disable=False) -> int:
# Default preferences
pref_autoinvite = self.setting_service.get_value("pref_autoinvite")
pref_raidinvite = self.setting_service.get_value("pref_raidinvite")
pref_raidspam = self.setting_service.get_value("pref_raidspam")
pref_newsspam = self.setting_service.get_value("pref_newsspam")
if type(users) == list and len(users) > 0: if type(users) == list and len(users) > 0:
with self.db.pool.get_connection() as conn: with self.db.pool.get_connection() as conn:
with conn.cursor() as cur: with conn.cursor() as cur:
if disable: if disable:
cur.executemany( cur.executemany(
"INSERT IGNORE INTO account(char_id, main, member, disabled, last_updated, created) " "INSERT IGNORE INTO account(char_id, main, member, disabled, last_updated, created, "
"VALUES(?, ?, ?, 1, ?, ?) ON DUPLICATE KEY UPDATE " "auto_invite, raid_invite, raid_spam, news_spam) "
f"VALUES(?, ?, ?, 1, ?, ?, {pref_autoinvite}, {pref_raidinvite}, "
f"{pref_raidspam}, {pref_newsspam}) ON DUPLICATE KEY UPDATE "
"member=VALUE(member), last_updated=VALUE(last_updated), disabled=1", "member=VALUE(member), last_updated=VALUE(last_updated), disabled=1",
users) users)
return cur.rowcount return cur.rowcount
cur.executemany( cur.executemany(
"INSERT IGNORE INTO account(char_id, main, member, last_updated, created) " "INSERT IGNORE INTO account(char_id, main, member, last_updated, "
"VALUES(?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE " "created, auto_invite, raid_invite, raid_spam, news_spam) "
f"VALUES(?, ?, ?, ?, ?, {pref_autoinvite}, {pref_raidinvite}, "
f"{pref_raidspam}, {pref_newsspam}) ON DUPLICATE KEY UPDATE "
"member=VALUE(member), last_updated=VALUE(last_updated)", "member=VALUE(member), last_updated=VALUE(last_updated)",
users) users)
return cur.rowcount return cur.rowcount
+1 -1
View File
@@ -49,7 +49,7 @@ class SystemController:
NumberSettingType([4500, 6000, 7500, 9000, 10500, 12000]), NumberSettingType([4500, 6000, 7500, 9000, 10500, 12000]),
"Maximum size of blobs in private channel") "Maximum size of blobs in private channel")
self.setting_service.register_new("core.system", "accept_commands_from_slave_bots", False, BooleanSettingType(), self.setting_service.register_new("core.system", "accept_commands_from_slave_bots", True, BooleanSettingType(),
"Accept and respond to commands sent to slave bots (only applies if you have " "Accept and respond to commands sent to slave bots (only applies if you have "
"added slave bots in the config)") "added slave bots in the config)")
@@ -0,0 +1,95 @@
from core.command_service import CommandService
from core.decorators import instance, command
from modules.core.accounting.preference_controller import PreferenceController
from modules.core.accounting.services.account_service import AccountService
@instance(name="account_service", override=True)
class AccountServiceOnlineBot(AccountService):
registered = []
def inject(self, registry):
super().inject(registry)
self.preference_controller: PreferenceController = registry.get_instance("preference_controller")
def pre_start(self):
super().pre_start()
self.db.exec("CREATE TABLE IF NOT EXISTS registered (char_id int primary key)")
self.registered = [x.char_id for x in self.db.query("SELECT * from registered")]
self.access_service.register_access_level("unregistered", 95, self.check_unregistered)
@command(command="opt-in", params=[],
description="Register yourself in the bot",
access_level="unregistered")
def cmd_opt_in(self, request):
player = self.pork.get_character_info(request.sender.name)
if player.org_id in self.get_orgs():
if self.is_registered((main := self.get_main(request.sender.char_id)).char_id):
return "You're already registered."
self.db.exec("INSERT IGNORE INTO registered VALUES (?)", [main.char_id])
pref_autoinvite = int(self.setting_service.get_value("pref_autoinvite"))
pref_raidinvite = int(self.setting_service.get_value("pref_raidinvite"))
pref_raidspam = int(self.setting_service.get_value("pref_raidspam"))
pref_newsspam = int(self.setting_service.get_value("pref_newsspam"))
self.registered.append(main.char_id)
self.preference_controller.set_pref(main.char_id, "news", pref_newsspam)
self.preference_controller.set_pref(main.char_id, "raidspam", pref_raidspam)
self.preference_controller.set_pref(main.char_id, "autoinvite", pref_autoinvite)
# This one is of no use in Onlinebots,
# as the command taking advantage of it
# is only implemented in the raidbot modules.
# raidspam is used instead.
self.preference_controller.set_pref(main.char_id, "raidinvite", pref_raidinvite)
return "You've been registered successfully, and your preferences have been set to the defaults."
@command(command="opt-out", params=[],
description="Unregister yourself from the bot",
access_level="member")
def cmd_opt_out(self, request):
main = self.get_main(request.sender.char_id)
if self.is_registered(main.char_id):
self.db.exec("DELETE FROM registered where char_id = ?", [main.char_id])
self.registered.remove(main.char_id)
self.db.exec("UPDATE account SET disabled=1 where char_id=?", [main.char_id])
return "You've been unregistered successfully. For re-registering, " \
"you may need to contact an Administrator, " \
"as you may only register once as a spam protection. " \
"Further tells will get ignored."
else:
return "You're not registered, and thus cannot unregister yourself."
def is_registered(self, char_id):
return char_id in self.registered
def simple_checks(self, account):
main = account.get("main", -1)
if main and main in self.registered:
return super().simple_checks(account)
return False
def check_unregistered(self, char_id) -> bool:
account = self.get_account(char_id) or {}
return super().simple_checks(account)
def check_member(self, char_id) -> bool:
account = self.get_account(char_id) or {}
if self.simple_checks(account):
return True
return False
@instance(name="command_service", override=True)
class AccountServiceOnlineBot(CommandService):
def access_denied_response(self, message, sender, cmd_config, reply):
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":
if sender.access_level['label'] == "unregistered":
self.bot.send_mass_message(sender.char_id,
"You are not registered yet. To gain access to my commands, you'll need to use <highlight><symbol>opt-in</highlight>")
return
self.bot.send_mass_message(sender.char_id, self.getresp("global", "access_denied"))
+25 -24
View File
@@ -76,23 +76,23 @@ class OrgController:
orgs = orgs[0] orgs = orgs[0]
if self.db.exec("REPLACE INTO orgs(org_id) VALUES(?)", if self.db.exec("REPLACE INTO orgs(org_id) VALUES(?)",
[orgs.org_id]) == 1: [orgs.org_id]) == 1:
sender.reply("Adding the organisation <highlight>%s<end> to the roster..." % orgs.org_name) sender.reply(f"Adding the organisation <highlight>{orgs.org_name}<end> to the roster...")
org_adder = Thread(name=orgs.org_id, target=self.fetch_single, org_adder = Thread(name=orgs.org_id, target=self.fetch_single,
args=(orgs.org_id, orgs.org_name, sender)) args=(orgs.org_id, orgs.org_name, sender))
self.threads[orgs.org_id] = org_adder self.threads[orgs.org_id] = org_adder
org_adder.start() org_adder.start()
else: else:
return "The organisation <highlight>%s<end> is in the roster already." % orgs.org_name return f"The organisation <highlight>{orgs.org_name}<end> is in the roster already."
elif len(orgs) == 0: elif len(orgs) == 0:
return "No org with the name <highlight>%s<end> was found on PoRK." % search return f"No org with the name <highlight>{search}<end> was found on PoRK."
else: else:
blob = "Your search had multiple results; please pick an org:<br>" blob = "Your search had multiple results; please pick an org:<br>"
for org in orgs: for org in orgs:
blob += "[%s][%s] <highlight>%s<end> (<highlight>%s<end>) <%s>%s<end> [<highlight>%s<end> " \ blob += f'[{self.text.make_chatcmd("Add", f"/tell <myname> orgs add {org.org_id}")}]' \
"members]<br><pagebreak>" \ f'[{self.text.make_chatcmd("More", f"/tell <myname> org info {org.org_id}")}]' \
% (self.text.make_chatcmd("Add", "/tell <myname> orgs add %s" % org.org_id), f' <highlight>{org.org_name}<end> (<highlight>{org.org_id}<end>) ' \
self.text.make_chatcmd("More", "/tell <myname> org info %s" % org.org_id), f'<{org.faction.lower()}>{org.faction}<end> [<highlight>{org.member_count}<end> members]' \
org.org_name, org.org_id, org.faction.lower(), org.faction, org.member_count) f'<br><pagebreak>'
return ChatBlob("Pick an Org", blob) return ChatBlob("Pick an Org", blob)
@command(command="orgs", params=[Const("rem"), Any("Organisation")], access_level="admin", @command(command="orgs", params=[Const("rem"), Any("Organisation")], access_level="admin",
@@ -109,19 +109,19 @@ class OrgController:
org_remover = Thread(name=orgs.org_id, target=self.remove_single, args=(orgs.org_id, orgs.org_name)) org_remover = Thread(name=orgs.org_id, target=self.remove_single, args=(orgs.org_id, orgs.org_name))
self.threads[orgs.org_id] = org_remover self.threads[orgs.org_id] = org_remover
org_remover.start() org_remover.start()
return "Removed the organisation <highlight>%s<end> from the roster." % orgs.org_name return f"Removed the organisation <highlight>{orgs.org_name}<end> from the roster."
else: else:
return "The organisation <highlight>%s<end> is not on the roster list." % orgs.org_name return f"The organisation <highlight>{orgs.org_name}<end> is not on the roster list."
elif len(orgs) == 0: elif len(orgs) == 0:
return "The organisation <highlight>%s<end> is not on the roster list." % search return f"The organisation <highlight>{search}<end> is not on the roster list."
else: else:
blob = "Your search had multiple results; please pick an org:<br>" blob = "Your search had multiple results; please pick an org:<br>"
for org in orgs: for org in orgs:
blob += "[%s][%s] <highlight>%s<end> (<highlight>%s<end>) <%s>%s<end> [<highlight>%s<end> " \ blob += f'[{self.text.make_chatcmd("Remove", f"/tell <myname> orgs remove {org.org_id}")}]' \
"members]<br><pagebreak>" \ f'[{self.text.make_chatcmd("More", f"/tell <myname> org info {org.org_id}")}]' \
% (self.text.make_chatcmd("Remove", "/tell <myname> orgs remove %s" % org.org_id), f' <highlight>{org.org_name}<end> (<highlight>{org.org_id}<end>) ' \
self.text.make_chatcmd("More", "/tell <myname> org info %s" % org.org_id), f'<{org.faction.lower()}>{org.faction}<end> [<highlight>{org.member_count}<end> members]' \
org.org_name, org.org_id, org.faction.lower(), org.faction, org.member_count) f'<br><pagebreak>'
return ChatBlob("Pick an Org", blob) return ChatBlob("Pick an Org", blob)
@command(command="orgs", params=[Const("list", is_optional=True)], access_level="member", @command(command="orgs", params=[Const("list", is_optional=True)], access_level="member",
@@ -169,7 +169,7 @@ class OrgController:
continue continue
data.append((int(match[0]), match[1], int(match[2]), match[4], start)) data.append((int(match[0]), match[1], int(match[2]), match[4], start))
count += 1 count += 1
self.logger.info("Batch %s done!" % letter) self.logger.info(f"Batch {letter} done!")
with self.db.pool.get_connection() as conn: with self.db.pool.get_connection() as conn:
with conn.cursor() as cur: with conn.cursor() as cur:
@@ -183,7 +183,7 @@ class OrgController:
"last_seen=VALUE(last_seen)", "last_seen=VALUE(last_seen)",
data) data)
self.db.exec("DELETE FROM all_orgs where last_seen < ?", [time.time() - 2 * 24 * 60 * 60]) self.db.exec("DELETE FROM all_orgs where last_seen < ?", [time.time() - 2 * 24 * 60 * 60])
self.logger.info("Successfully fetched %d orgs in %d seconds." % (count, time.time() - start)) self.logger.info(f"Successfully fetched {count} orgs in {time.time() - start:.2f} seconds.")
self.threads.pop('orgdiscover', None) self.threads.pop('orgdiscover', None)
if "orgdiscover" not in self.threads.keys(): if "orgdiscover" not in self.threads.keys():
@@ -229,7 +229,7 @@ class OrgController:
"level": char_info["LEVELX"], "level": char_info["LEVELX"],
"ai_level": char_info["ALIENLEVEL"], "ai_level": char_info["ALIENLEVEL"],
"ranks": 0})) "ranks": 0}))
self.logger.info("Organisation %s has been updated." % org.org_name) self.logger.info(f"Organisation {org.org_name} has been updated.")
self.account_service.create_users(accounts) self.account_service.create_users(accounts)
if len(data) > 1: if len(data) > 1:
with self.db.lock: with self.db.lock:
@@ -286,8 +286,9 @@ class OrgController:
"ranks": count})) "ranks": count}))
self.account_service.remove_members(accounts) self.account_service.remove_members(accounts)
self.log(output, time.time() - start) self.log(output, time.time() - start)
self.logger.info("Successfully fetched %d players from %d orgs in %d seconds. - " % ( self.logger.info(
len(data), len(ours), time.time() - start)) f"Successfully fetched {len(data)} players from {len(ours)} orgs "
f"in {time.time() - start:.2f} seconds. - ")
del self.threads['roster'] del self.threads['roster']
if "roster" not in self.threads.keys(): if "roster" not in self.threads.keys():
@@ -330,11 +331,11 @@ class OrgController:
"pvp_rating, pvp_title, source, last_updated) VALUES " "pvp_rating, pvp_title, source, last_updated) VALUES "
"(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", data) "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", data)
self.account_service.create_users(accounts) self.account_service.create_users(accounts)
self.logger.info("Organisation %s added!" % org_name) self.logger.info(f"Organisation {org_name} added!")
sender.reply(f"<highlight>{org_name}</highlight> has been added to the roster. " sender.reply(f"<highlight>{org_name}</highlight> has been added to the roster. "
f"Runtime: {time.time() - start:.2f} seconds.") f"Runtime: {time.time() - start:.2f} seconds.")
self.logger.info("Successfully fetched %d players in %d seconds." % (count, time.time() - start)) self.logger.info(f"Successfully fetched {count} players in {time.time() - start} seconds.")
del self.threads[org_id] del self.threads[org_id]
def remove_single(self, org_id, org_name): def remove_single(self, org_id, org_name):
@@ -344,7 +345,7 @@ class OrgController:
self.db.exec("UPDATE account set member=-1 where char_id in" self.db.exec("UPDATE account set member=-1 where char_id in"
" (SELECT char_id from player where org_id=?)", [org_id]) " (SELECT char_id from player where org_id=?)", [org_id])
self.db.exec("DELETE FROM online where char_id in (SELECT char_id from player where org_id=?)", [org_id]) self.db.exec("DELETE FROM online where char_id in (SELECT char_id from player where org_id=?)", [org_id])
self.logger.info("Organisation %s removed!" % org_name) self.logger.info(f"Organisation {org_name} removed!")
del self.threads[org_id] del self.threads[org_id]
def log(self, blob, duration): def log(self, blob, duration):
+15 -9
View File
@@ -15,6 +15,7 @@ from core.setting_service import SettingService
from core.text import Text from core.text import Text
from core.tyrbot import Tyrbot from core.tyrbot import Tyrbot
from core.util import Util from core.util import Util
from modules.core.accounting.services.account_service import AccountService
from modules.core.ban.ban_service import BanService from modules.core.ban.ban_service import BanService
@@ -62,6 +63,7 @@ class RaidController:
self.setting_service: SettingService = registry.get_instance("setting_service") self.setting_service: SettingService = registry.get_instance("setting_service")
self.ban: BanService = registry.get_instance("ban_service") self.ban: BanService = registry.get_instance("ban_service")
self.private_channel_service: PrivateChannelService = registry.get_instance("private_channel_service") self.private_channel_service: PrivateChannelService = registry.get_instance("private_channel_service")
self.account_service: AccountService = registry.get_instance("account_service")
@command(command="raid", params=[Const("desc"), Any("&lt;description&gt;")], @command(command="raid", params=[Const("desc"), Any("&lt;description&gt;")],
description="Change the title of the Raid", access_level="leader") description="Change the title of the Raid", access_level="leader")
@@ -119,7 +121,9 @@ class RaidController:
if self.raid: if self.raid:
return "There's already a raid running." return "There's already a raid running."
self.raid = Raid(request.sender, request.sender.access_level["level"]) self.raid = Raid(request.sender, request.sender.access_level["level"])
self.raid.bot = self.bot.get_char_name() # after I saw myself sending raid invites with the wrong bot reference by accident atleast once,
# the default is being set to allianceraid again.
self.raid.bot = "allianceraid" # self.bot.get_char_name()
self.raid.last_action = time.time() self.raid.last_action = time.time()
spam = f""" spam = f"""
________________ ________________
@@ -146,7 +150,7 @@ class RaidController:
return "There's no raid running." return "There's no raid running."
def blob(label, msg): def blob(label, msg):
return "<a href=\"text://%s\">%s</a>" % (textwrap.dedent(msg), textwrap.dedent(label)) return f"<a href=\"text://{textwrap.dedent(msg)}\">{textwrap.dedent(label)}</a>"
last = time.time() last = time.time()
if self.raid.last_spam + 5 * 60 > last: if self.raid.last_spam + 5 * 60 > last:
@@ -178,7 +182,7 @@ class RaidController:
""" """
subtile = f"""<yellow>[<green>{request.sender.name}</green>]: Raid Starting: <notice>{self.raid.raid_desc}</notice> -- use <notice>/tell {self.raid.bot} join</notice> to participate or {click_here}</yellow></yellow> """ subtile = f"""<yellow>[<green>{request.sender.name}</green>]: Raid Starting: <notice>{self.raid.raid_desc}</notice> -- use <notice>/tell {self.raid.bot} join</notice> to participate or {click_here}</yellow></yellow> """
# noinspection SqlAggregates # noinspection SqlAggregates
players = self.db.query("SELECT p.*, a.subtile_spam, a.raid_invite, a.raid_spam from online o " players = self.db.query("SELECT p.*, a.subtile_spam, a.raid_invite, a.raid_spam, a.main, a.disabled, a.member from online o "
"left join player p on o.char_id = p.char_id " "left join player p on o.char_id = p.char_id "
"left join account a on a.char_id=(select main from account where char_id=o.char_id) " "left join account a on a.char_id=(select main from account where char_id=o.char_id) "
"where p.level >= ? AND ((a.raid_invite=1 or a.raid_spam = 1) " "where p.level >= ? AND ((a.raid_invite=1 or a.raid_spam = 1) "
@@ -189,18 +193,20 @@ class RaidController:
"AND o.bot=? group by o.char_id " "AND o.bot=? group by o.char_id "
"ORDER BY p.profession, p.name, p.level, p.org_rank_id;", "ORDER BY p.profession, p.name, p.level, p.org_rank_id;",
[self.raid.min_level, self.bot.get_char_id()]) [self.raid.min_level, self.bot.get_char_id()])
self.bot.send_mass_message(request.sender.char_id, f"Sending invites to {len(players)} Players...") self.bot.send_mass_message(request.sender.char_id, f"Attempting to send {len(players)} invites...")
info = "Sent invites to:" info = "Sent invites to:"
prof = "" prof = ""
count = len(players)
for i in players: for i in players:
if not self.account_service.simple_checks(i):
count -= 1
continue
if prof != i.profession: if prof != i.profession:
info += "\n\n<img src=tdb://id:GFX_GUI_FRIENDLIST_SPLITTER>" info += "\n\n<img src=tdb://id:GFX_GUI_FRIENDLIST_SPLITTER>"
info += "\n" + "<img src=rdb://" + str( info += "\n" + f"<img src=rdb://{self.profs.get(i.profession)}><tab><green>{i.profession}<end>\n"
self.profs.get(i.profession)) + "><tab><green>%s<end>\n" % i.profession
info += "<img src=tdb://id:GFX_GUI_FRIENDLIST_SPLITTER>" info += "<img src=tdb://id:GFX_GUI_FRIENDLIST_SPLITTER>"
prof = i.profession prof = i.profession
if self.ban.get_ban(i.char_id):
continue
if i.raid_spam == 1: if i.raid_spam == 1:
self.bot.send_mass_message(i.char_id, spam if i.subtile_spam == 0 else subtile) self.bot.send_mass_message(i.char_id, spam if i.subtile_spam == 0 else subtile)
# if i.raid_invite == 1: # if i.raid_invite == 1:
@@ -211,7 +217,7 @@ class RaidController:
self.raid.last_action = time.time() self.raid.last_action = time.time()
self.raid.last_spam = time.time() self.raid.last_spam = time.time()
self.bot.send_mass_message(request.sender.char_id, self.bot.send_mass_message(request.sender.char_id,
f"Successfully sent {len(players)} invites! [{self.text.format_page('More', info)}]") f"Successfully sent {count} invite{'s' if count != 1 else ''}! [{self.text.format_page('More', info)}]")
@command(command="raid", params=[Const("settings")], @command(command="raid", params=[Const("settings")],
description="Change the title of the Raid", access_level="leader") description="Change the title of the Raid", access_level="leader")
@@ -25,7 +25,7 @@ class RandomController:
self.command_alias_service.add_alias("verify", "roll verify") self.command_alias_service.add_alias("verify", "roll verify")
self.command_alias_service.add_alias("lootorder", "random") self.command_alias_service.add_alias("lootorder", "random")
@command(command="random", params=[Any("items")], access_level="all", @command(command="random", params=[Any("items")], access_level="member",
description="Randomly order a list of elements", description="Randomly order a list of elements",
extended_description="Enter a space-delimited list of items to randomize.") extended_description="Enter a space-delimited list of items to randomize.")
def random_command(self, _, items): def random_command(self, _, items):
@@ -33,19 +33,19 @@ class RandomController:
random.shuffle(items) random.shuffle(items)
return " ".join(items) return " ".join(items)
@command(command="roll", params=[Const("verify"), Int("roll_id")], access_level="all", @command(command="roll", params=[Const("verify"), Int("roll_id")], access_level="member",
description="Verify a roll that happened") description="Verify a roll that happened")
def roll_verify_command(self, _, _1, roll_id): def roll_verify_command(self, _, _1, roll_id):
row = self.db.query_single("SELECT * FROM roll WHERE id = ?", [roll_id]) row = self.db.query_single("SELECT * FROM roll WHERE id = ?", [roll_id])
if not row: if not row:
return "Could not find roll with id <highlight>%d</highlight>." % roll_id return f"Could not find roll with id <highlight>{roll_id:d}</highlight>."
else: else:
time_string = self.util.time_to_readable(int(time.time()) - row.created_at) time_string = self.util.time_to_readable(int(time.time()) - row.created_at)
name = self.character_service.resolve_char_to_name(row.char_id) name = self.character_service.resolve_char_to_name(row.char_id)
return "<highlight>%s</highlight> rolled by <highlight>%s</highlight> %s ago. Possible options: %s." % ( return f"<highlight>{row.result}</highlight> rolled by <highlight>{name}</highlight> " \
row.result, name, time_string, row.options) f"{time_string} ago. Possible options: {row.options}."
@command(command="roll", params=[Int("start_value", is_optional=True), Int("end_value")], access_level="all", @command(command="roll", params=[Int("start_value", is_optional=True), Int("end_value")], access_level="member",
description="Roll a number between 1 and a number", description="Roll a number between 1 and a number",
extended_description="The given numbers are included in the roll.") extended_description="The given numbers are included in the roll.")
def roll_number_command(self, request, start_value, end_value): def roll_number_command(self, request, start_value, end_value):
@@ -64,7 +64,7 @@ class RandomController:
f"To verify do /tell <myname> verify {self.db.last_insert_id():d}" f"To verify do /tell <myname> verify {self.db.last_insert_id():d}"
# Keep this method at the bottom of file otherwise it will precede over all other commands # Keep this method at the bottom of file otherwise it will precede over all other commands
@command(command="roll", params=[Any("items")], access_level="all", @command(command="roll", params=[Any("items")], access_level="member",
description="Roll a random value", description="Roll a random value",
extended_description="Enter a space-delimited list of values to roll") extended_description="Enter a space-delimited list of values to roll")
def roll_text_variables_command(self, request, items): def roll_text_variables_command(self, request, items):
@@ -17,7 +17,7 @@ class WhompahController:
self.db.create_view("whompah_cities") self.db.create_view("whompah_cities")
self.db.create_view("whompah_cities_rel") self.db.create_view("whompah_cities_rel")
@command(command="whompah", params=[], access_level="all", @command(command="whompah", params=[], access_level="member",
description="Show list of whompah cities") description="Show list of whompah cities")
def whompah_list_cmd(self, request): def whompah_list_cmd(self, request):
cities = self.db.query("SELECT id, city_name, zone, faction, short_name FROM whompah_cities ORDER BY city_name") cities = self.db.query("SELECT id, city_name, zone, faction, short_name FROM whompah_cities ORDER BY city_name")
@@ -29,7 +29,7 @@ class WhompahController:
return ChatBlob("Whompah Cities", blob) return ChatBlob("Whompah Cities", blob)
@command(command="whompah", params=[Any("city1"), Any("city2")], access_level="all", @command(command="whompah", params=[Any("city1"), Any("city2")], access_level="member",
description="Show whompah route between two cities") description="Show whompah route between two cities")
def whompah_travel_cmd(self, request, city_name1, city_name2): def whompah_travel_cmd(self, request, city_name1, city_name2):
city1 = self.get_whompah_city(city_name1) city1 = self.get_whompah_city(city_name1)
@@ -53,7 +53,7 @@ class WhompahController:
path = self.format_path(self.find_path(cities, city1.id, city2.id)) path = self.format_path(self.find_path(cities, city1.id, city2.id))
return " -> ".join(path) return " -> ".join(path)
@command(command="whompah", params=[Any("city")], access_level="all", @command(command="whompah", params=[Any("city")], access_level="member",
description="Show whompah destinations for a city") description="Show whompah destinations for a city")
def whompah_city_cmd(self, request, city_name): def whompah_city_cmd(self, request, city_name):
city = self.get_whompah_city(city_name) city = self.get_whompah_city(city_name)
@@ -265,7 +265,7 @@ class LootListsController:
@command(command="totwh", params=[Options( @command(command="totwh", params=[Options(
["binyacht", "guardian", "summoner", "loremaster", "nematet", "aegis", "lien", "gartua", "aztur", "khalum", ["binyacht", "guardian", "summoner", "loremaster", "nematet", "aegis", "lien", "gartua", "aztur", "khalum",
"uklesh", "gen", "armor"])], "uklesh", "gen", "armor"])],
description="Get list of items from Temple of Three Winds", access_level="all") description="Get list of items from Temple of Three Winds", access_level="member")
def totwh_loot_cmd(self, _, category_name): def totwh_loot_cmd(self, _, category_name):
category = self.get_real_category_name(category_name) category = self.get_real_category_name(category_name)
items = self.get_items("Temple of Three Winds (HL)", category) items = self.get_items("Temple of Three Winds (HL)", category)
@@ -274,7 +274,7 @@ class LootListsController:
else: else:
return "No loot registered for <highlight>%s<end>." % category_name return "No loot registered for <highlight>%s<end>." % category_name
@command(command="totwh", params=[], description="Get list of items from Temple of Three Winds", access_level="all") @command(command="totwh", params=[], description="Get list of items from Temple of Three Winds", access_level="member")
def totwh_tables_cmd(self, _): def totwh_tables_cmd(self, _):
return ChatBlob("Temple of Three Winds (HL) loot tables", return ChatBlob("Temple of Three Winds (HL) loot tables",
self.build_overview("Temple of Three Winds (HL)", "totwh")) self.build_overview("Temple of Three Winds (HL)", "totwh"))
+11 -9
View File
@@ -52,7 +52,7 @@ class MailController:
def logon_event(self, _, data): def logon_event(self, _, data):
if not self.bot.is_ready(): if not self.bot.is_ready():
return return
if data.account.disabled == 1: if not self.account_service.simple_checks(data.account):
return return
if "mail" in self.buddy_service.get_buddy(data.packet.char_id)["types"]: if "mail" in self.buddy_service.get_buddy(data.packet.char_id)["types"]:
self.job_schedule.delayed_job(self.send_mail, 16, data.packet.char_id, self.get_mails(data.packet.char_id)) self.job_schedule.delayed_job(self.send_mail, 16, data.packet.char_id, self.get_mails(data.packet.char_id))
@@ -129,8 +129,10 @@ class MailController:
recipient = self.account_service.get_account(receiver.char_id) recipient = self.account_service.get_account(receiver.char_id)
if not recipient: if not recipient:
return f"No account for <highlight>{receiver.name}</highlight> found." return f"No account for <highlight>{receiver.name}</highlight> found."
if recipient.member == -1 or recipient.disabled == 1:
return f"The Character <highlight>{recipient.name}</highlight> has " \ # if recipient.member == -1 or recipient.disabled == 1:
if not self.account_service.simple_checks(recipient):
return f"The Character <highlight>{recipient.name}</highlight> has " \
f"no active account in <highlight><myname></highlight>." f"no active account in <highlight><myname></highlight>."
self.db.exec("INSERT INTO mail(sender, recipient, text, sent_at) VALUES(?, ?, ?, ?)", self.db.exec("INSERT INTO mail(sender, recipient, text, sent_at) VALUES(?, ?, ?, ?)",
[sender.sender.char_id, recipient.main, message, time.time()]) [sender.sender.char_id, recipient.main, message, time.time()])
@@ -152,12 +154,12 @@ class MailController:
group = self.account_service.get_group_tag(recipient) group = self.account_service.get_group_tag(recipient)
users = [] users = []
if group: if group:
if group == "all": # if group == "all":
if sender.sender.access_level['level'] > 20: # if sender.sender.access_level['level'] > 20:
return "This group is unavailable." # return "This group is unavailable."
users = self.account_service.get_all_members() # users = self.account_service.get_all_members()
else: # else:
users = self.account_service.get_by_group(group) users = self.account_service.get_by_group(group)
elif not group: elif not group:
return f"Sorry, but the group <highlight>{recipient}</highlight> does not exist. " \ return f"Sorry, but the group <highlight>{recipient}</highlight> does not exist. " \
+4 -1
View File
@@ -122,7 +122,8 @@ hh:mm - DD.MM.YYYY
return return
if "member" in self.buddy_service.get_buddy(data.packet.char_id)["types"]: if "member" in self.buddy_service.get_buddy(data.packet.char_id)["types"]:
account = data.account account = data.account
if account.disabled == 1: # Apply standard checks. (User Banned, Account disabled, ...)
if not self.account_service.simple_checks(data.account):
return return
if self.db.query_single("SELECT * from org_bots where char_id=?", [data.packet.char_id]): if self.db.query_single("SELECT * from org_bots where char_id=?", [data.packet.char_id]):
return return
@@ -138,6 +139,8 @@ hh:mm - DD.MM.YYYY
self.job_schedule.delayed_job(self.send_news, 15, user, self.account_service.get_alts(account.main), self.job_schedule.delayed_job(self.send_news, 15, user, self.account_service.get_alts(account.main),
discord, discord,
self.preferences.get_pref_view_small(account)) self.preferences.get_pref_view_small(account))
# This one is kinda redudant now that the simple checks get done above, will remove it in the future.
if account.last_seen == 0 and self.setting_service.get_value('is_alliance_bot') == "1": if account.last_seen == 0 and self.setting_service.get_value('is_alliance_bot') == "1":
self.bot.send_mass_message(data.packet.char_id, self.INFO) self.bot.send_mass_message(data.packet.char_id, self.INFO)
+4 -5
View File
@@ -35,13 +35,12 @@ class OnlineDisplay:
blob, org, priv, notify = online blob, org, priv, notify = online
postfix = [] postfix = []
if org > 0: if org > 0:
postfix.append(f"Org: {org}") postfix.append(f"<notice>Org: {org}</notice>")
if priv > 0: if priv > 0:
postfix.append(f"Priv: {priv}") postfix.append(f"<highlight>Priv: {priv}</notice>")
if notify > 0: if notify > 0:
postfix.append(f"Buddylist: {notify}") postfix.append(f"<notice>Buddylist: {notify}</notice>")
blob = ChatBlob(title, blob) blob = ChatBlob(title, blob, suffix=f" ({f', '.join(postfix)})")
blob.page_postfix = f" ({f', '.join(postfix)})"
return blob return blob
def format_by_channel_main(self, query, params): def format_by_channel_main(self, query, params):
+3 -3
View File
@@ -20,7 +20,7 @@ class QuoteController:
"created_at INT NOT NULL, " "created_at INT NOT NULL, "
"content VARCHAR(4096) NOT NULL)") "content VARCHAR(4096) NOT NULL)")
@command(command="quote", params=[], access_level="all", @command(command="quote", params=[], access_level="member",
description="Show a random quote") description="Show a random quote")
def quote_command(self, request): def quote_command(self, request):
quote = self.get_quote_info() quote = self.get_quote_info()
@@ -30,7 +30,7 @@ class QuoteController:
else: else:
return "There are no quotes to display." return "There are no quotes to display."
@command(command="quote", params=[Int("quote_id")], access_level="all", @command(command="quote", params=[Int("quote_id")], access_level="member",
description="Show a specific quote") description="Show a specific quote")
def quote_view_command(self, _, quote_id): def quote_view_command(self, _, quote_id):
quote = self.get_quote_info(quote_id) quote = self.get_quote_info(quote_id)
@@ -40,7 +40,7 @@ class QuoteController:
else: else:
return f"Could not find quote with ID <highlight>{quote_id:d}</highlight>." return f"Could not find quote with ID <highlight>{quote_id:d}</highlight>."
@command(command="quote", params=[Const("add"), Any("quote")], access_level="all", @command(command="quote", params=[Const("add"), Any("quote")], access_level="member",
description="Show a specific quote") description="Show a specific quote")
def quote_add_command(self, request, _, quote): def quote_add_command(self, request, _, quote):
if len(quote) > 4096: if len(quote) > 4096:
+1 -1
View File
@@ -50,7 +50,7 @@ class RecipeController:
recipe = self.find_recipe(recipe_id, recipes) recipe = self.find_recipe(recipe_id, recipes)
if recipe: if recipe:
recipes.remove(recipe) recipes.remove(recipe)
if recipe.dt == dt: if recipe.dt >= dt:
continue continue
self.update_recipe(recipe_dir, recipe_id, file_type, dt) self.update_recipe(recipe_dir, recipe_id, file_type, dt)