Loading cog/actions.py +55 −2 Original line number Diff line number Diff line Loading @@ -1970,7 +1970,7 @@ def get_scanner(name): raise cog.exc.InvalidCommandArgs("The scanners are not ready. Please try again in 15 seconds.") from exc async def monitor_carrier_events(client, *, next_summary, last_timestamp=None, delay=60): async def monitor_carrier_events(client, *, next_summary, last_timestamp=None, delay=60): # pragma: no cover """ Simple async task that just checks for new events every delay. Loading Loading @@ -2016,7 +2016,7 @@ async def monitor_carrier_events(client, *, next_summary, last_timestamp=None, d ) async def monitor_ocr_sheet(client, *, delay=1800, repeat=True): async def monitor_ocr_sheet(client, *, delay=1800, repeat=True): # pragma: no cover """ Simple async task that just checks for changes to the OCR sheet. This task will schedule itself infinitely on a delay. Loading Loading @@ -2056,6 +2056,58 @@ async def monitor_ocr_sheet(client, *, delay=1800, repeat=True): ) async def monitor_snipe_merits(client, *, repeat=True): # pragma: no cover """ Schedule self to check snipe merits at the following times. This task will sleep until required. - 12 hours before tick, remind everyone with @here ping to redeem. - 30 minutes before tick, ping unredeemed users directly. Kwargs: repeat: If true, will schedule itself infinitely. """ guild = [x for x in client.guilds if x.name == FUC_GUILD] if guild: guild = guild[0] chan_id = cog.util.get_config('snipe_channel', default=None) if not guild or not chan_id: # Don't bother if not set return snipe_chan = client.get_channel(chan_id) next_cycle = cog.util.next_weekly_tick(datetime.datetime.utcnow()) # 12 hours to tick, ping here next_date = next_cycle - datetime.timedelta(hours=12) now = datetime.datetime.utcnow() if now < next_date: diff_dates = next_date - now delay_seconds = diff_dates.seconds + diff_dates.days * 24 * 60 * 60 await asyncio.sleep(delay_seconds) # Notify here client.send_message(snipe_chan, "@here Snipe members it is tick day and there are 12 hours remaining.") # 30 mins to tick ping remaining in message next_date = next_cycle - datetime.timedelta(minutes=30) now = datetime.datetime.utcnow() if now < next_date: diff_dates = next_date - now delay_seconds = diff_dates.seconds + diff_dates.days * 24 * 60 * 60 await asyncio.sleep(delay_seconds) # Notify members holding with cogdb.session_scope(cogdb.Session) as session: to_contact = cogdb.query.get_snipe_members_holding(session, client) msg = """__Final Snipe Reminder__ There are less than **30 minutes left**. The following members are still holding. """ client.send_message(snipe_chan, msg + to_contact) if repeat: asyncio.ensure_future( monitor_snipe_merits(client, repeat=repeat) ) async def report_to_leadership(client, msgs): # pragma: no cover """ Send messages to the channel configured to receive reports. Loading Loading @@ -2156,3 +2208,4 @@ UM_NPC_TABLE = [ ['Archon Delaine', 'Kumo Crew Watch', 'Kumo Crew Transport', 'Kumo Crew Strike Ships'] ] TRACK_LIMIT = 20 FUC_GUILD = "Federal United Command" cog/bot.py +1 −0 Original line number Diff line number Diff line Loading @@ -203,6 +203,7 @@ class CogBot(discord.Client): simple_heartbeat(), cog.actions.monitor_carrier_events(self, next_summary=next_summary, delay=60), cog.actions.monitor_ocr_sheet(self), cog.actions.monitor_snipe_merits(self), cogdb.eddb.monitor_eddb_caches(), cogdb.monitor_pools(), )) Loading cogdb/query.py +38 −3 Original line number Diff line number Diff line Loading @@ -15,7 +15,8 @@ import cog.sheets import cogdb.eddb from cog.util import substr_match, get_config from cogdb.schema import (DiscordUser, FortSystem, FortPrep, FortDrop, FortUser, FortOrder, UMSystem, UMUser, UMHold, EUMSheet, KOS, AdminPerm, ChannelPerm, RolePerm, UMSystem, UMUser, UMHold, EUMSheet, KOS, AdminPerm, ChannelPerm, RolePerm, TrackSystem, TrackSystemCached, TrackByID, OCRTracker, OCRTrigger, OCRPrep, Global, Vote) from cogdb.scanners import FortScanner Loading Loading @@ -114,7 +115,7 @@ def users_with_all_merits(session): """ return session.query(DiscordUser, (sqla.func.ifnull(FortUser.dropped, 0) + sqla.func.ifnull(UMUser.combo, 0)).label('total')).\ outerjoin(FortUser, DiscordUser.pref_name == FortUser.name).\ outerjoin(UMUser, DiscordUser.pref_name == UMUser.name).\ outerjoin(UMUser, DiscordUser.pref_name == UMUser.name,).\ order_by(sqla.desc("total")).\ all() Loading Loading @@ -147,6 +148,7 @@ def users_with_um_merits(session): """ return session.query(DiscordUser, UMUser.combo).\ join(UMUser, UMUser.name == DiscordUser.pref_name).\ filter(UMUser.sheet_src == EUMSheet.main).\ order_by(UMUser.combo.desc()).\ all() Loading Loading @@ -597,7 +599,10 @@ def um_all_held_merits(session, *, sheet_src=EUMSheet.main): except KeyError: c_dict[merit.user.name] = {merit.system.name: merit} systems = session.query(UMSystem).order_by(UMSystem.id).all() systems = session.query(UMSystem).\ filter(UMSystem.sheet_src == EUMSheet.main).\ order_by(UMSystem.id).\ all() system_names = [sys.name for sys in systems] rows = [] for cmdr in c_dict: Loading Loading @@ -1295,3 +1300,33 @@ def get_vote(session, discord_id, vote_type): session.add(the_vote) return the_vote def get_snipe_members_holding(session, guild): """ Find the members who are holding merits on the snipe sheet. For each found member, attempt to resolve them with the guild to mention them. If we cannot resolve their name with guild, just write the name. Format one large message reminding the users and return it. Args: session: A session onto the db. guild: The guild of the server in question. Returns: A string formatted mentioning or naming all users with snipe merits. """ snipe_holds = session.query(UMHold).\ filter(UMHold.sheet_src == EUMSheet.snipe, UMHold.held > 0).\ all() template_msg = "{} is holding {} merits in {}\n" reply = "" for hold in snipe_holds: duser = hold.user.discord_user found = guild.get_member_named(duser.pref_name) mention = found.mention if found else duser.pref_name reply += template_msg.format(mention, hold.held, hold.system.name) return reply cogdb/schema.py +11 −4 Original line number Diff line number Diff line Loading @@ -534,7 +534,8 @@ class UMUser(Base): def held(self): """ Total merits held by this cmdr. """ return sqla.select([sqla.func.sum(UMHold.held)]).\ where(UMHold.user_id == self.id).\ where(sqla.and_(UMHold.user_id == self.id, UMHold.sheet_src != EUMSheet.snipe)).\ label('held') @hybrid_property Loading @@ -550,7 +551,8 @@ class UMUser(Base): def redeemed(self): """ Total merits redeemed by this cmdr. """ return sqla.select([sqla.func.sum(UMHold.redeemed)]).\ where(UMHold.user_id == self.id).\ where(sqla.and_(UMHold.user_id == self.id, UMHold.sheet_src != EUMSheet.snipe)).\ label('redeemed') @hybrid_property Loading @@ -570,6 +572,7 @@ class UMUser(Base): def __repr__(self): keys = ['id', 'name', 'row', 'cry'] kwargs = ['{}={!r}'.format(key, getattr(self, key)) for key in keys] kwargs.insert(1, "sheet_src={}".format("EUMSheet.main" if self.sheet_src == EUMSheet.main else "EUMSheet.snipe")) return "{}({})".format(self.__class__.__name__, ', '.join(kwargs)) Loading Loading @@ -639,6 +642,7 @@ class UMSystem(Base): keys = ['id', 'name', 'sheet_col', 'goal', 'security', 'notes', 'progress_us', 'progress_them', 'close_control', 'priority', 'map_offset'] kwargs = ['{}={!r}'.format(key, getattr(self, key)) for key in keys] kwargs.insert(1, "sheet_src={}".format("EUMSheet.main" if self.sheet_src == EUMSheet.main else "EUMSheet.snipe")) return "{}({})".format(self.__class__.__name__, ', '.join(kwargs)) Loading Loading @@ -805,6 +809,7 @@ class UMHold(Base): def __repr__(self): keys = ['id', 'system_id', 'user_id', 'held', 'redeemed'] kwargs = ['{}={!r}'.format(key, getattr(self, key)) for key in keys] kwargs.insert(1, "sheet_src={}".format("EUMSheet.main" if self.sheet_src == EUMSheet.main else "EUMSheet.snipe")) return "{}({})".format(self.__class__.__name__, ', '.join(kwargs)) Loading Loading @@ -1667,6 +1672,8 @@ def run_schema_queries(session): # pragma: no cover trigger=6000, undermine=0, notes="S/M Priority, Skip"), FortSystem(name='Rana', sheet_col='J', sheet_order=5, fort_status=0, trigger=6000, undermine=1.2, notes="Attacked"), FortPrep(name='Rhea', sheet_col='L', sheet_order=6, fort_status=0, trigger=8000, notes="To prep"), ) session.add_all(systems) session.flush() Loading Loading @@ -1734,7 +1741,7 @@ def run_schema_queries(session): # pragma: no cover OCRTracker(system="Frey", updated_at=date), OCRTracker(system="Adeo"), OCRTracker(system="Sol"), OCRPrep(system="Othime"), OCRPrep(system="Rhea"), OCRTrigger(system="Frey") ) session.add_all(ocrs_systems) Loading @@ -1750,7 +1757,7 @@ def run_schema_queries(session): # pragma: no cover print(sys.ocr_tracker) print(sys.ocr_trigger) sys = session.query(FortSystem).filter(FortSystem.name == "Othime").one() sys = session.query(FortPrep).one() print(sys.ocr_prep) Loading tests/cogdb/test_query.py +12 −0 Original line number Diff line number Diff line Loading @@ -846,3 +846,15 @@ def test_vote_get(session, f_dusers, f_vote_testbed): the_vote = cogdb.query.get_vote(session, f_dusers[2].id, VoteType.prep) assert the_vote.id == f_dusers[2].id assert the_vote.vote == VoteType.prep def test_get_snipe_members_holding(session, f_bot, f_dusers, f_um_testbed): expected = 'User3 is holding 5000 merits in ToSnipe\n' results = cogdb.query.get_snipe_members_holding(session, f_bot.guilds[0]) assert results == expected def test_get_snipe_members_holding(session, f_bot, f_dusers, f_um_testbed): expected = 'User3 is holding 5000 merits in ToSnipe\n' results = cogdb.query.get_snipe_members_holding(session, f_bot.guilds[0]) assert results == expected Loading
cog/actions.py +55 −2 Original line number Diff line number Diff line Loading @@ -1970,7 +1970,7 @@ def get_scanner(name): raise cog.exc.InvalidCommandArgs("The scanners are not ready. Please try again in 15 seconds.") from exc async def monitor_carrier_events(client, *, next_summary, last_timestamp=None, delay=60): async def monitor_carrier_events(client, *, next_summary, last_timestamp=None, delay=60): # pragma: no cover """ Simple async task that just checks for new events every delay. Loading Loading @@ -2016,7 +2016,7 @@ async def monitor_carrier_events(client, *, next_summary, last_timestamp=None, d ) async def monitor_ocr_sheet(client, *, delay=1800, repeat=True): async def monitor_ocr_sheet(client, *, delay=1800, repeat=True): # pragma: no cover """ Simple async task that just checks for changes to the OCR sheet. This task will schedule itself infinitely on a delay. Loading Loading @@ -2056,6 +2056,58 @@ async def monitor_ocr_sheet(client, *, delay=1800, repeat=True): ) async def monitor_snipe_merits(client, *, repeat=True): # pragma: no cover """ Schedule self to check snipe merits at the following times. This task will sleep until required. - 12 hours before tick, remind everyone with @here ping to redeem. - 30 minutes before tick, ping unredeemed users directly. Kwargs: repeat: If true, will schedule itself infinitely. """ guild = [x for x in client.guilds if x.name == FUC_GUILD] if guild: guild = guild[0] chan_id = cog.util.get_config('snipe_channel', default=None) if not guild or not chan_id: # Don't bother if not set return snipe_chan = client.get_channel(chan_id) next_cycle = cog.util.next_weekly_tick(datetime.datetime.utcnow()) # 12 hours to tick, ping here next_date = next_cycle - datetime.timedelta(hours=12) now = datetime.datetime.utcnow() if now < next_date: diff_dates = next_date - now delay_seconds = diff_dates.seconds + diff_dates.days * 24 * 60 * 60 await asyncio.sleep(delay_seconds) # Notify here client.send_message(snipe_chan, "@here Snipe members it is tick day and there are 12 hours remaining.") # 30 mins to tick ping remaining in message next_date = next_cycle - datetime.timedelta(minutes=30) now = datetime.datetime.utcnow() if now < next_date: diff_dates = next_date - now delay_seconds = diff_dates.seconds + diff_dates.days * 24 * 60 * 60 await asyncio.sleep(delay_seconds) # Notify members holding with cogdb.session_scope(cogdb.Session) as session: to_contact = cogdb.query.get_snipe_members_holding(session, client) msg = """__Final Snipe Reminder__ There are less than **30 minutes left**. The following members are still holding. """ client.send_message(snipe_chan, msg + to_contact) if repeat: asyncio.ensure_future( monitor_snipe_merits(client, repeat=repeat) ) async def report_to_leadership(client, msgs): # pragma: no cover """ Send messages to the channel configured to receive reports. Loading Loading @@ -2156,3 +2208,4 @@ UM_NPC_TABLE = [ ['Archon Delaine', 'Kumo Crew Watch', 'Kumo Crew Transport', 'Kumo Crew Strike Ships'] ] TRACK_LIMIT = 20 FUC_GUILD = "Federal United Command"
cog/bot.py +1 −0 Original line number Diff line number Diff line Loading @@ -203,6 +203,7 @@ class CogBot(discord.Client): simple_heartbeat(), cog.actions.monitor_carrier_events(self, next_summary=next_summary, delay=60), cog.actions.monitor_ocr_sheet(self), cog.actions.monitor_snipe_merits(self), cogdb.eddb.monitor_eddb_caches(), cogdb.monitor_pools(), )) Loading
cogdb/query.py +38 −3 Original line number Diff line number Diff line Loading @@ -15,7 +15,8 @@ import cog.sheets import cogdb.eddb from cog.util import substr_match, get_config from cogdb.schema import (DiscordUser, FortSystem, FortPrep, FortDrop, FortUser, FortOrder, UMSystem, UMUser, UMHold, EUMSheet, KOS, AdminPerm, ChannelPerm, RolePerm, UMSystem, UMUser, UMHold, EUMSheet, KOS, AdminPerm, ChannelPerm, RolePerm, TrackSystem, TrackSystemCached, TrackByID, OCRTracker, OCRTrigger, OCRPrep, Global, Vote) from cogdb.scanners import FortScanner Loading Loading @@ -114,7 +115,7 @@ def users_with_all_merits(session): """ return session.query(DiscordUser, (sqla.func.ifnull(FortUser.dropped, 0) + sqla.func.ifnull(UMUser.combo, 0)).label('total')).\ outerjoin(FortUser, DiscordUser.pref_name == FortUser.name).\ outerjoin(UMUser, DiscordUser.pref_name == UMUser.name).\ outerjoin(UMUser, DiscordUser.pref_name == UMUser.name,).\ order_by(sqla.desc("total")).\ all() Loading Loading @@ -147,6 +148,7 @@ def users_with_um_merits(session): """ return session.query(DiscordUser, UMUser.combo).\ join(UMUser, UMUser.name == DiscordUser.pref_name).\ filter(UMUser.sheet_src == EUMSheet.main).\ order_by(UMUser.combo.desc()).\ all() Loading Loading @@ -597,7 +599,10 @@ def um_all_held_merits(session, *, sheet_src=EUMSheet.main): except KeyError: c_dict[merit.user.name] = {merit.system.name: merit} systems = session.query(UMSystem).order_by(UMSystem.id).all() systems = session.query(UMSystem).\ filter(UMSystem.sheet_src == EUMSheet.main).\ order_by(UMSystem.id).\ all() system_names = [sys.name for sys in systems] rows = [] for cmdr in c_dict: Loading Loading @@ -1295,3 +1300,33 @@ def get_vote(session, discord_id, vote_type): session.add(the_vote) return the_vote def get_snipe_members_holding(session, guild): """ Find the members who are holding merits on the snipe sheet. For each found member, attempt to resolve them with the guild to mention them. If we cannot resolve their name with guild, just write the name. Format one large message reminding the users and return it. Args: session: A session onto the db. guild: The guild of the server in question. Returns: A string formatted mentioning or naming all users with snipe merits. """ snipe_holds = session.query(UMHold).\ filter(UMHold.sheet_src == EUMSheet.snipe, UMHold.held > 0).\ all() template_msg = "{} is holding {} merits in {}\n" reply = "" for hold in snipe_holds: duser = hold.user.discord_user found = guild.get_member_named(duser.pref_name) mention = found.mention if found else duser.pref_name reply += template_msg.format(mention, hold.held, hold.system.name) return reply
cogdb/schema.py +11 −4 Original line number Diff line number Diff line Loading @@ -534,7 +534,8 @@ class UMUser(Base): def held(self): """ Total merits held by this cmdr. """ return sqla.select([sqla.func.sum(UMHold.held)]).\ where(UMHold.user_id == self.id).\ where(sqla.and_(UMHold.user_id == self.id, UMHold.sheet_src != EUMSheet.snipe)).\ label('held') @hybrid_property Loading @@ -550,7 +551,8 @@ class UMUser(Base): def redeemed(self): """ Total merits redeemed by this cmdr. """ return sqla.select([sqla.func.sum(UMHold.redeemed)]).\ where(UMHold.user_id == self.id).\ where(sqla.and_(UMHold.user_id == self.id, UMHold.sheet_src != EUMSheet.snipe)).\ label('redeemed') @hybrid_property Loading @@ -570,6 +572,7 @@ class UMUser(Base): def __repr__(self): keys = ['id', 'name', 'row', 'cry'] kwargs = ['{}={!r}'.format(key, getattr(self, key)) for key in keys] kwargs.insert(1, "sheet_src={}".format("EUMSheet.main" if self.sheet_src == EUMSheet.main else "EUMSheet.snipe")) return "{}({})".format(self.__class__.__name__, ', '.join(kwargs)) Loading Loading @@ -639,6 +642,7 @@ class UMSystem(Base): keys = ['id', 'name', 'sheet_col', 'goal', 'security', 'notes', 'progress_us', 'progress_them', 'close_control', 'priority', 'map_offset'] kwargs = ['{}={!r}'.format(key, getattr(self, key)) for key in keys] kwargs.insert(1, "sheet_src={}".format("EUMSheet.main" if self.sheet_src == EUMSheet.main else "EUMSheet.snipe")) return "{}({})".format(self.__class__.__name__, ', '.join(kwargs)) Loading Loading @@ -805,6 +809,7 @@ class UMHold(Base): def __repr__(self): keys = ['id', 'system_id', 'user_id', 'held', 'redeemed'] kwargs = ['{}={!r}'.format(key, getattr(self, key)) for key in keys] kwargs.insert(1, "sheet_src={}".format("EUMSheet.main" if self.sheet_src == EUMSheet.main else "EUMSheet.snipe")) return "{}({})".format(self.__class__.__name__, ', '.join(kwargs)) Loading Loading @@ -1667,6 +1672,8 @@ def run_schema_queries(session): # pragma: no cover trigger=6000, undermine=0, notes="S/M Priority, Skip"), FortSystem(name='Rana', sheet_col='J', sheet_order=5, fort_status=0, trigger=6000, undermine=1.2, notes="Attacked"), FortPrep(name='Rhea', sheet_col='L', sheet_order=6, fort_status=0, trigger=8000, notes="To prep"), ) session.add_all(systems) session.flush() Loading Loading @@ -1734,7 +1741,7 @@ def run_schema_queries(session): # pragma: no cover OCRTracker(system="Frey", updated_at=date), OCRTracker(system="Adeo"), OCRTracker(system="Sol"), OCRPrep(system="Othime"), OCRPrep(system="Rhea"), OCRTrigger(system="Frey") ) session.add_all(ocrs_systems) Loading @@ -1750,7 +1757,7 @@ def run_schema_queries(session): # pragma: no cover print(sys.ocr_tracker) print(sys.ocr_trigger) sys = session.query(FortSystem).filter(FortSystem.name == "Othime").one() sys = session.query(FortPrep).one() print(sys.ocr_prep) Loading
tests/cogdb/test_query.py +12 −0 Original line number Diff line number Diff line Loading @@ -846,3 +846,15 @@ def test_vote_get(session, f_dusers, f_vote_testbed): the_vote = cogdb.query.get_vote(session, f_dusers[2].id, VoteType.prep) assert the_vote.id == f_dusers[2].id assert the_vote.vote == VoteType.prep def test_get_snipe_members_holding(session, f_bot, f_dusers, f_um_testbed): expected = 'User3 is holding 5000 merits in ToSnipe\n' results = cogdb.query.get_snipe_members_holding(session, f_bot.guilds[0]) assert results == expected def test_get_snipe_members_holding(session, f_bot, f_dusers, f_um_testbed): expected = 'User3 is holding 5000 merits in ToSnipe\n' results = cogdb.query.get_snipe_members_holding(session, f_bot.guilds[0]) assert results == expected