diff --git a/core/command_service.py b/core/command_service.py index eafec80..bffd764 100644 --- a/core/command_service.py +++ b/core/command_service.py @@ -134,7 +134,7 @@ class CommandService: return for channel, label in self.channels.items(): - row = self.db.query_single("SELECT access_level, module, enabled, verified " + row = self.db.query_single("SELECT access_level, module, enabled, verified, sub_command " "FROM command_config " "WHERE command = ? AND sub_command = ? AND channel = ?", [command, sub_command, channel]) @@ -147,9 +147,9 @@ class CommandService: "VALUES (?, ?, ?, ?, ?, 1, 1)", [command, sub_command, access_level, channel, module]) elif row.verified: - if row.module != module: - self.logger.warning("module different for different forms of command '%s' and sub_command '%s'" % ( - command, sub_command)) + if row.module != module and row.sub_command == sub_command: + self.logger.warning(f"module different for different forms of command '{command}' " + f"and sub_command '{sub_command}'") else: # mark command as verified self.db.exec("UPDATE command_config SET verified = 1, module = ? " diff --git a/core/igncore.py b/core/igncore.py index abf93d4..44cee60 100644 --- a/core/igncore.py +++ b/core/igncore.py @@ -43,7 +43,7 @@ class IgnCore: self.last_timer_event = 0 self.start_time = int(time.time()) self.major_version = "IGNCore v2.8" - self.minor_version = "2" + self.minor_version = "3" self.incoming_queue = FifoQueue() self.mass_message_queue = None self.conns = DictObject() diff --git a/core/lookup/org_pork_service.py b/core/lookup/org_pork_service.py index 1679e86..c010cec 100644 --- a/core/lookup/org_pork_service.py +++ b/core/lookup/org_pork_service.py @@ -185,3 +185,9 @@ class OrgPorkService: # Dont use SSL, as its rather slow compared to normal requests.... # noinspection HttpUrlsUsage return f"http://people.anarchy-online.com/org/stats/d/{dimension}/name/{org_id}/basicstats.xml?data_type=json" + + def find_org(self, search, table="all_orgs"): + if search.isdigit(): + return self.db.query("SELECT * FROM " + table + " where org_id = ?", [search]) + elif isinstance(search, str): + return self.db.query("SELECT * FROM " + table + " where org_name LIKE ?", ["%" + search + "%"]) \ No newline at end of file diff --git a/modules/core/accounting/account_log_controller.py b/modules/core/accounting/account_log_controller.py index 91e7b1f..6ea2c25 100644 --- a/modules/core/accounting/account_log_controller.py +++ b/modules/core/accounting/account_log_controller.py @@ -55,7 +55,10 @@ class AccountLogController(BaseModule): sub_command="moderate") def account_add_log(self, request: command_request, _, log_type, user, text): main = self.account_service.get_main(user.char_id).char_id + if not main: + return f"The main of {user} could not be found. Are you sure there is an account?" self.account_service.add_log(main, log_type, text, request.sender.char_id) + return f"The log entry for {self.character_service.resolve_char_to_name(main)} has been added successfully." # noinspection LongLine @command(command="account", params=[Const("log"), Const("id"), Int("id")], access_level="moderator", @@ -73,7 +76,14 @@ class AccountLogController(BaseModule): f"Message: {entry.reason}\n" f"Logging Time: {self.util.format_datetime(entry.created_at)}") else: - return f"No Logentry with ID {id} found." + return f"No Logentry with ID {log_id} found." + + @command(command="account", params=[Const("log"), Const("recent")], access_level="moderator", + description="View the 20 most recent log entries", + sub_command="moderate") + def account_view_recent(self, _, _1, _2): + entries = self.account_service.get_logs(limit=20) + return ChatBlob(f"Most Recent logentries", self.display_logs(entries)) def display_logs(self, entries) -> str: blob = "" diff --git a/modules/core/accounting/services/account_service.py b/modules/core/accounting/services/account_service.py index 4d70e90..b7cd900 100644 --- a/modules/core/accounting/services/account_service.py +++ b/modules/core/accounting/services/account_service.py @@ -532,14 +532,21 @@ class AccountService: "VALUES (?, ?, ?, ?, ?, ?)", [main, log_type, delta, leader, message, time.time()]) - def get_logs(self, user, log_type=None, limit=25) -> List[DictObject]: - if not log_type: - return self.db.query("SELECT * FROM account_log " - "where char_id=? and type != 'admin' order by log_id desc LIMIT ? ", [user, limit]) - + def get_logs(self, user=None, log_type=None, limit=25) -> List[DictObject]: + if not user: + if not log_type: + return self.db.query("SELECT * FROM account_log " + "where type != 'admin' order by log_id desc LIMIT ? ", [limit]) + else: + return self.db.query("SELECT * FROM account_log " + "where type=? order by log_id desc LIMIT ?", [log_type, limit]) else: - return self.db.query("SELECT * FROM account_log " - "where char_id=? and type=? order by log_id desc LIMIT ?", [user, log_type, limit]) + if not log_type: + return self.db.query("SELECT * FROM account_log " + "where char_id=? and type != 'admin' order by log_id desc LIMIT ? ", [user, limit]) + else: + return self.db.query("SELECT * FROM account_log " + "where char_id=? and type=? order by log_id desc LIMIT ?", [user, log_type, limit]) def get_log_by_id(self, log_id) -> DictObject: return self.db.query_single("SELECT * FROM account_log where log_id=? ", [log_id]) diff --git a/modules/onlinebot/online/bot_controller.py b/modules/onlinebot/online/bot_controller.py index c87f34f..f97a2dc 100644 --- a/modules/onlinebot/online/bot_controller.py +++ b/modules/onlinebot/online/bot_controller.py @@ -1,6 +1,3 @@ -from threading import Thread - -from core import command_request, sender_obj from core.aochat.BaseModule import BaseModule from core.buddy_service import BuddyService from core.chat_blob import ChatBlob @@ -31,6 +28,7 @@ class BotController(BaseModule): self.org_pork: PorkService = registry.get_instance("org_pork_service") self.command_alias_service: CommandAliasService = registry.get_instance("command_alias_service") self.buddy_service: BuddyService = registry.get_instance("buddy_service") + self.online = registry.get_instance("buddy_service") def pre_start(self): self.db.exec("CREATE TABLE IF NOT EXISTS org_bots(char_id int primary key not null, org_id int not null)") @@ -38,24 +36,31 @@ class BotController(BaseModule): def start(self): pass - @command(command="bots", params=[Const("add"), Character("botname")], access_level="admin", - description="Add an bot to the bot list") - def bots_add_any(self, sender, _, bot): - Thread(target=self.bots_add, args=(bot, sender)).start() - - def bots_add(self, bot: sender_obj, request: command_request): + @command(command="orgs", params=[Const("bots"), Const("add"), Character("botname")], access_level="admin", + description="Add an bot to the bot list", sub_command="bots_mng") + def cmd_orgs_bots_add(self, request, _, _1, bot): player = self.pork.request_char_info(bot.name, 5) if self.db.exec("INSERT IGNORE INTO org_bots(char_id, org_id) VALUES(?, ?)", [bot.char_id, player.org_id]) == 0: - request.reply("The bot %s is already marked as an chatbot." % bot.name) + request.reply(f"The bot {bot.name} is already marked as a chatbot.") else: - request.reply("Successfully marked %s as an chatbot." % bot.name) + self.db.exec("DELETE FROM online where char_id=?", [bot.char_id]) + request.reply(f"Successfully marked {bot.name} as a chatbot.") - @command(command="bots", - params=[], + @command(command="orgs", params=[Const("bots"), Const("rem"), Character("botname")], access_level="admin", + description="Add an bot to the bot list", sub_command="bots_mng") + def cmd_orgs_bots_rem(self, request, _, _1, bot): + + if self.db.exec("DELETE FROM org_bots WHERE char_id=?", [bot.char_id]) == 0: + request.reply(f"{bot.name} is not a chatbot.") + else: + request.reply(f"Successfully removed {bot.name} as a chatbot. The character will show up in !online again after its next login.") + + @command(command="orgs", + params=[Const("bots")], access_level="moderator", description="show all orgbots", - sub_command="show") - def bots_show_all(self, _): + sub_command="bots_show") + def cmd_orgs_bots_show(self, _, _1): def format_row(query): bud = self.buddy_service.is_online(query["char_id"]) buddy = "O" if bud == 1 else "O" if bud == 0 else "U" diff --git a/modules/onlinebot/online/org_alias_controller.py b/modules/onlinebot/online/org_alias_controller.py index 3ea9de7..0347944 100644 --- a/modules/onlinebot/online/org_alias_controller.py +++ b/modules/onlinebot/online/org_alias_controller.py @@ -1,23 +1,21 @@ from core.buddy_service import BuddyService +from core.chat_blob import ChatBlob from core.command_alias_service import CommandAliasService from core.db import DB -from core.decorators import instance +from core.decorators import instance, command from core.logger import Logger from core.lookup.pork_service import PorkService 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 core.command_param_types import Const, Any # noinspection DuplicatedCode @instance() class OrgAliasController: - org_prefix = {4736: "AP", 9632: "AP", 9622: "AC", 9831: "AC", 581633: "BST", 9707: "CoH", 9990: "CoH", 4637: "HAV", - 10197: "IMP", 6093: "LCG", 4789: "MJ", 4687: "NA", 4800: "PR", 4993: "REGS", 813067: "SOTL", - 4851: "SP", 9611: "SP", 4614: "TA", 4831: "TGNF", 6183: "TRE", 9822: "TS", 4611: "UHS", - 5571: "UOTR", 520210: "WO", 1349649: "VR", 4826: "42", 1349647: "VR", 6332: "DRA", 848: "DRA", - 4675: "VA", 1558530: "EoS"} + prefix_cache = {} def inject(self, registry): self.logger = Logger(__name__) @@ -33,6 +31,75 @@ class OrgAliasController: def start(self): self.db.exec("CREATE TABLE IF NOT EXISTS org_alias(org_id int primary key not null, org_alias VARCHAR(255))") + for entry in self.db.query("SELECT * from org_alias"): + self.prefix_cache[entry.org_id] = entry.org_alias def get_alias(self, org_id): - return self.org_prefix.get(org_id, "-UKN-") + return self.prefix_cache.get(org_id, "-UKN-") + + @command(command="orgs", params=[Const("alias"), Const("list", is_optional=True)], access_level="member", + description="View the currently registered org aliases", sub_command="alias_info") + def cmd_alias_list(self, request, _, _1): + alias_list = self.db.query("SELECT ao.org_id, ao.org_name, a.org_alias, (!ISNULL(o.org_id)) as member FROM org_alias a LEFT JOIN all_orgs ao on a.org_id = ao.org_id " + "LEFT JOIN orgs o on a.org_id = o.org_id " + "ORDER BY ISNULL(o.org_id), LOWER(ao.org_name)") + blob = [] + last = -1 + for alias in alias_list: + if last != alias.member: + if alias.member == 1: + blob.append("
Members:
") + elif alias.member == 0: + blob.append("\n
Other Aliases:
") + last = alias.member + blob.append(f" [{alias.org_alias}] - {alias.org_name} ({alias.org_id})") + return ChatBlob("Aliases currently in use", "\n".join(blob)) + + @command(command="orgs", params=[Const("alias"), Const("set"), Any("alias"), Any("org")], access_level="moderator", + description="View the currently registered org aliases", + sub_command="alias_moderate") + def cmd_alias_add(self, sender, _, _1, alias, search): + orgs = self.org_pork.find_org(search) + if len(orgs) == 1: + orgs = orgs[0] + if self.db.exec("REPLACE INTO org_alias(org_id, org_alias) VALUES (?, ?)", [orgs.org_id, alias]): + self.prefix_cache[orgs.org_id] = alias + return f"Alias for {orgs.org_name} has been set to [{alias}]." + + else: + return f"There's already an alias for {orgs.org_name}.. its [{self.get_alias(orgs.org_id)}]" + elif len(orgs) == 0: + return f"No org with the name {search} was found on PoRK." + else: + blob = "Your search had multiple results; please pick an org:
" + for org in orgs: + blob += f'[{self.text.make_chatcmd("Set Alias", f"/tell orgs alias set {alias} {org.org_id}")}]' \ + f'[{self.text.make_chatcmd("More", f"/tell orgs info {org.org_id}")}]' \ + f' {org.org_name} ({org.org_id}) ' \ + f'<{org.faction.lower()}>{org.faction} [{org.member_count} members]' \ + f'
' + return ChatBlob("Pick an Org", blob) + + @command(command="orgs", params=[Const("alias"), Const("rem"), Any("org")], access_level="moderator", + description="View the currently registered org aliases", + sub_command="alias_moderate") + def cmd_alias_del(self, sender, _, _1, search): + orgs = self.org_pork.find_org(search) + if len(orgs) == 1: + orgs = orgs[0] + if self.db.exec("DELETE FROM org_alias where org_id=?", [orgs.org_id]) == 1: + self.prefix_cache.pop(orgs.org_id) + return f"Alias for {orgs.org_name} has been removed." + else: + return f"There's no alias for {orgs.org_name}.." + elif len(orgs) == 0: + return f"No org with the name {search} was found on PoRK." + else: + blob = "Your search had multiple results; please pick an org:
" + for org in orgs: + blob += f'[{self.text.make_chatcmd("Set Alias", f"/tell orgs alias rem {org.org_id}")}]' \ + f'[{self.text.make_chatcmd("More", f"/tell orgs info {org.org_id}")}]' \ + f' {org.org_name} ({org.org_id}) ' \ + f'<{org.faction.lower()}>{org.faction} [{org.member_count} members]' \ + f'
' + return ChatBlob("Pick an Org", blob) diff --git a/modules/onlinebot/online/org_controller.py b/modules/onlinebot/online/org_controller.py index 446eb16..cae60ba 100644 --- a/modules/onlinebot/online/org_controller.py +++ b/modules/onlinebot/online/org_controller.py @@ -51,6 +51,7 @@ class OrgController: self.alias_controller: OrgAliasController = registry.get_instance("org_alias_controller") self.account_service: AccountService = registry.get_instance("account_service") self.cache: CacheService = registry.get_instance("cache_service") + self.org_alias: OrgAliasController = registry.get_instance("org_alias_controller") def start(self): self.db.exec("CREATE TABLE IF NOT EXISTS orgs(org_id int primary key not null)") @@ -65,12 +66,12 @@ class OrgController: self.buddy_service.add_buddy(player.char_id, "member") @command(command="orgs", params=[Const("add"), Any("Organisation")], access_level="admin", - description="Add an org to the online list") + description="Add an org to the online list", sub_command="moderate") def orgs_add_any(self, sender, _, org): return self.orgs_add(org, sender) def orgs_add(self, search, sender): - orgs = self.find_org(search) + orgs = self.org_pork.find_org(search) if len(orgs) == 1: orgs = orgs[0] if self.db.exec("REPLACE INTO orgs(org_id) VALUES(?)", @@ -95,12 +96,12 @@ class OrgController: return ChatBlob("Pick an Org", blob) @command(command="orgs", params=[Const("rem"), Any("Organisation")], access_level="admin", - description="Remove an org from the online list") + description="Remove an org from the online list", sub_command="moderate") def orgs_rem_any(self, _, _1, org): return self.orgs_rem(org) def orgs_rem(self, search): - orgs = self.find_org(search) + orgs = self.org_pork.find_org(search) if len(orgs) == 1: orgs = orgs[0] @@ -124,19 +125,21 @@ class OrgController: return ChatBlob("Pick an Org", blob) @command(command="orgs", params=[Const("list", is_optional=True)], access_level="member", - description="View all orgs on the online list", sub_command="list") + description="View all orgs on the online list", sub_command="online_info") def orgs_list(self, sender: CommandRequest, _): - head = "
Organisations in our Alliance" + head = "
Organisations registered as Members" blob = "" - for org in self.db.query("SELECT * from orgs o " - "left join all_orgs a on o.org_id = a.org_id order by a.org_name"): + for org in self.db.query("SELECT o.*, a.*, oa.org_alias from orgs o " + "left join all_orgs a on o.org_id = a.org_id " + "left join org_alias oa on o.org_id = oa.org_id order by a.org_name"): org = DictObject(org) - blob += "- %s%s%s (%d) with %d members\n" % ( + blob += "- %s%s%s%s (%d) with %d members\n" % ( "[" + self.text.make_chatcmd("Info", "/tell orgs info %d" % org.org_id, style="style='text-decoration:none'") + "] ", "[" + self.text.make_chatcmd("Remove", "/tell orgs rem %d" % org.org_id, style="style='text-decoration:none'") + "] " if sender.sender.access_level["level"] <= 10 else "", + f"[{self.org_alias.get_alias(org.org_id)}] ", org.org_name, org.org_id, self.db.query_single("SELECT member_count from all_orgs where org_id=?", [org.org_id]).member_count) @@ -291,12 +294,6 @@ class OrgController: self.threads["roster"] = thread thread.start() - def find_org(self, search, table="all_orgs"): - if search.isdigit(): - return self.db.query("SELECT * FROM " + table + " where org_id = ?", [search]) - elif isinstance(search, str): - return self.db.query("SELECT * FROM " + table + " where org_name LIKE ?", ["%" + search + "%"]) - def fetch_single(self, org_id, org_name, sender: object): start = time.time() data = [] diff --git a/modules/orgbot/org/org_roster_controller.py b/modules/orgbot/org/org_roster_controller.py index c710acc..4c7459a 100644 --- a/modules/orgbot/org/org_roster_controller.py +++ b/modules/orgbot/org/org_roster_controller.py @@ -36,7 +36,7 @@ class OrgRosterController: ORG_MEMBER_LOGOFF_EVENT = "org_member_logoff" ORG_MEMBER_REMOVED_EVENT = "org_member_removed" - LEFT_ORG = [508, 45978487508, 45978487] + LEFT_ORG = [508, 45978487] KICKED_FROM_ORG = [508, 37093479] INVITED_TO_ORG = [508, 173558247] KICKED_INACTIVE_FROM_ORG = [508, 20908201] diff --git a/modules/standard/tower/land_controller.py b/modules/standard/tower/land_controller.py index 8a76927..041d0b5 100644 --- a/modules/standard/tower/land_controller.py +++ b/modules/standard/tower/land_controller.py @@ -16,10 +16,10 @@ from core.setting_types import BooleanSettingType from core.text import Text from core.util import Util from modules.standard.helpbot.playfield_controller import PlayfieldController -# legacy(0), EU - friendly(1) or US - friendly(2) => timing from modules.standard.tower.tower_attack_controller import TowerAttackController from modules.standard.tower.tower_events import TowerEventController +# legacy(0), EU - friendly(1) or US - friendly(2) => timing FIXED_TIMES = {1: 4, 2: 20} @@ -219,7 +219,7 @@ class LandController: blob += towers else: if not row.enabled: - blob += "Disabled\n" + blob += "Disabled\n" else: blob += "This site is potentially unplanted\n" @@ -251,7 +251,10 @@ class LandController: def get_towers(self, pf, site=None): if site: - return self.db.query("""SELECT d.playfield_id AS pf_id,d.site_number, d.site_name, d.min_ql, d.max_ql, d.x_coord, d.y_coord, d.timing, d.enabled, a.tower_id, a.ql, a.close_time, a.penalty_until, a.planted, b.*, c.*, e.* FROM tower_sites d + return self.db.query("""SELECT d.playfield_id AS pf_id,d.site_number, d.site_name, d.min_ql, d.max_ql, + d.x_coord, d.y_coord, d.timing, d.enabled, a.tower_id, a.ql, + a.close_time, a.penalty_until, a.planted, b.*, c.*, e.* + FROM tower_sites d LEFT JOIN towers a on a.pf_id = d.playfield_id and a.site_number = d.site_number LEFT JOIN aodb b ON a.high_id = b.highid LEFT JOIN playfields c on d.playfield_id = c.id @@ -259,8 +262,11 @@ class LandController: WHERE playfield_id=? AND d.site_number=? ORDER BY close_time IS NULL, ql desc""", [pf, site]) else: - return self.db.query("""SELECT d.playfield_id AS pf_id, d.site_number, d.site_name, d.min_ql, d.max_ql, d.x_coord, d.y_coord, d.timing, d.enabled, a.tower_id, a.ql, a.close_time, a.penalty_until, a.planted, b.*, c.*, e.* FROM tower_sites d - LEFT JOIN towers a on a.pf_id = d.playfield_id and a.site_number = d.site_number + return self.db.query("""SELECT d.playfield_id AS pf_id, d.site_number, d.site_name, d.min_ql, d.max_ql, + d.x_coord, d.y_coord, d.timing, d.enabled, a.tower_id, a.ql, + a.close_time, a.penalty_until, a.planted, b.*, c.*, e.* + FROM tower_sites d + LEFT JOIN towers a on a.pf_id = d.playfield_id and a.site_number = d.site_number AND a.close_time IS NOT NULL LEFT JOIN aodb b ON a.high_id = b.highid LEFT JOIN playfields c on d.playfield_id = c.id LEFT JOIN all_orgs e on a.org_id = e.org_id @@ -270,27 +276,17 @@ class LandController: """, [pf]) def get_towers_by_org(self, org_id): - return self.db.query( - "SELECT COUNT(CASE WHEN name LIKE '%Turret%' THEN 1 WHEN name LIKE '%SAM Battery%' THEN 1 END) turrets, " - "COUNT(CASE WHEN name LIKE '%Guard%' THEN 1 END) guard, " - "a.*, b.*, c.*, d.site_name, d.min_ql, d.max_ql, d.timing, d.enabled, e.* FROM towers a " - "LEFT JOIN aodb b ON a.high_id = b.highid " - "LEFT JOIN playfields c on a.pf_id = c.id " - "LEFT JOIN tower_sites d on a.pf_id = d.playfield_id and a.site_number = d.site_number " - "LEFT JOIN all_orgs e on a.org_id = e.org_id " - "WHERE a.org_id=? GROUP BY a.pf_id, a.site_number ORDER BY ql, close_time IS NOT NULL", [org_id]) - - # For some reason the Code above broke... and apparently works again now? leaving this one here, just in case. - # return self.db.query("""SELECT * FROM (SELECT COUNT(CASE WHEN name LIKE '%Turret%' THEN 1 WHEN name LIKE '%SAM Battery%' THEN 1 END) turrets, - # COUNT(CASE WHEN name LIKE '%Guard%' THEN 1 END) guard, a.pf_id, a.org_id, e.org_name, c.*, d.* FROM towers a - # LEFT JOIN aodb b ON a.high_id = b.highid - # LEFT JOIN playfields c on a.pf_id = c.id - # LEFT JOIN tower_sites d on a.pf_id = d.playfield_id and a.site_number = d.site_number - # LEFT JOIN all_orgs e on a.org_id = e.org_id - # WHERE a.org_id=? GROUP BY a.pf_id, a.site_number ORDER BY ql, close_time IS NOT NULL) t1 - # LEFT JOIN - # (SELECT * from towers a WHERE a.org_id=? AND close_time IS NOT NULL) t2 - # ON t1.pf_id=t2.pf_id AND t1.site_number = t2.site_number""", [org_id, org_id]) + return self.db.query("""SELECT * FROM (SELECT COUNT(CASE WHEN name LIKE '%Turret%' THEN 1 WHEN name LIKE '%SAM Battery%' THEN 1 END) turrets, + COUNT(CASE WHEN name LIKE '%Guard%' THEN 1 END) guard, a.pf_id, a.org_id, e.org_name, c.*, d.* FROM towers a + LEFT JOIN aodb b ON a.high_id = b.highid + LEFT JOIN playfields c on a.pf_id = c.id + LEFT JOIN tower_sites d on a.pf_id = d.playfield_id and a.site_number = d.site_number + LEFT JOIN all_orgs e on a.org_id = e.org_id + WHERE a.org_id=? GROUP BY a.pf_id, a.site_number ORDER BY ql, close_time IS NOT NULL) t1 + LEFT JOIN + (SELECT * from towers a WHERE a.org_id=? AND close_time IS NOT NULL) t2 + ON t1.pf_id=t2.pf_id AND t1.site_number = t2.site_number + ORDER BY ql""", [org_id, org_id]) def find_orgs(self, search): return self.db.query("SELECT DISTINCT a.org_name, a.org_id FROM all_orgs a "