def create_parser(msg): """ Factory to create msg parsers. Raises: KeyError: When the class or part of msg is not supported. Returns: A parser ready to parse the message. """ key = "{} {}".format(msg['header']['softwareName'], msg["$schemaRef"]) logging.getLogger(__name__).info("Schema Key: %s", key) cls_name = SCHEMA_MAP[key] cls = getattr(sys.modules[__name__], cls_name) with cogdb.session_scope(cogdb.Session) as session, \ cogdb.session_scope(cogdb.EDDBSession, autoflush=False) as eddb_session: return cls(session, eddb_session, msg)
def test_get_current_global(session, f_global_testbed): session.query(Global).delete() current = cogdb.query.get_current_global(session) assert current.consolidation == 0 current.consolidation = 77 session.commit() with cogdb.session_scope(cogdb.Session): latest = cogdb.query.get_current_global(session) latest == current latest.consolidation == 77
async def vote_cycle(request, cycle): """Provide vote consolidation data for a given cycle. Args: request: The request object for flask. cycle: The cycle to get voting data for. """ start = cog.util.cycle_to_start(cycle) end = start + datetime.timedelta(weeks=1) with cogdb.session_scope(cogdb.Session) as session: return sanic.response.json(get_vote_data(session, start, end))
async def vote_range(request, start, end): """Provide voting information after a given datetime. Args: request: The request object for flask. start: The timestamp (UTC) to get data after. end: The timestamp (UTC) to get data before. """ start = datetime.datetime.utcfromtimestamp(start) end = datetime.datetime.utcfromtimestamp(end) with cogdb.session_scope(cogdb.Session) as session: return sanic.response.json(get_vote_data(session, start, end))
async def vote(request): """ The route to provide vote information via charts. """ cur_cycle = cog.util.current_cycle() start = cog.util.cycle_to_start(cur_cycle) end = start + datetime.timedelta(weeks=1) with cogdb.session_scope(cogdb.Session) as session: data = get_vote_data(session, start, end) return sanic.response.html(TEMPLATES['vote'].render(request=request, data=data, cycle=cur_cycle))
def monitor_factions(session, faction_names=None): """ Get all information on the provided factions. By default use set list. Returns: A list of messages to send. """ current = sqla_orm.aliased(FactionState) pending = sqla_orm.aliased(FactionState) sys = sqla_orm.aliased(System) sys_control = sqla_orm.aliased(System) if not faction_names: faction_names = WATCH_FACTIONS with cogdb.session_scope(cogdb.EDDBSession) as eddb_session: faction_ids = [ x[0] for x in eddb_session.query(edb.Faction.id).filter( edb.Faction.name.in_(faction_names)).all() ] control_state_id = session.query(PowerState.id).\ filter(PowerState.text == "Control").\ scalar_subquery() matches = session.query(Influence.influence, sys.name, Faction.name, Government.text, current.text, pending.text, sqla.func.ifnull(sys_control.name, 'N/A')).\ filter(Influence.faction_id.in_(faction_ids)).\ join(sys, Influence.system_id == sys.id).\ join(Faction, Influence.faction_id == Faction.id).\ join(Government, Faction.government_id == Government.id).\ join(current, Influence.state_id == current.id).\ join(pending, Influence.pending_state_id == pending.id).\ outerjoin(sys_control, sqla.and_( sys_control.power_state_id == control_state_id, sys_control.dist_to(sys) < 15 )).\ limit(1000).\ all() lines = [[ "Control", "System", "Faction", "Gov", "Inf", "State", "Pending State" ]] for match in matches: lines += [[ match[-1], match[1][:16], match[2][:16], match[3][:3], "{:5.2f}".format(round(match[0], 2)), match[-3], match[-2] ]] return cog.tbl.format_table(lines, header=True, prefix="\n\n**Monitored Factions**\n")
async def search_inara_and_kos(self, looking_for_cmdr, msg): """ Top level wrapper to search for a cmdr. Search both Inara and local KOS db, respond with appropriate information. Respond to user with information from both depending on what was found. Args: looking_for_cmdr: The cmdr's name to look on inara. msg: The message the user sent, tracks the channel/author to respond to. Returns: kos_info: The information on if a report for kos addition should be made to moderation. """ try: cmdr_info = await self.search_with_api(looking_for_cmdr, msg, ignore_multiple_match=False) return await cog.inara.api.reply_with_api_result( cmdr_info["req_id"], cmdr_info["event_data"], msg) except InaraNoResult as exc: futs = [] response = f"__Inara__ Could not find CMDR **{looking_for_cmdr}**" # Even if not on inara.cz, lookup in kos with cogdb.session_scope(cogdb.Session) as session: kos_embeds = kos_lookup_cmdr_embeds(session, looking_for_cmdr) if kos_embeds: futs += [ cog.util.BOT.send_message(msg.channel, embed=embed) for embed in kos_embeds ] futs += [self.delete_waiting_message(exc.req_id)] else: response += f"\n\n__KOS__ Could not find CMDR **{looking_for_cmdr}**" for fut in [cog.util.BOT.send_message(msg.channel, response) ] + futs: await fut # Not found in KOS, will ask if should be added. if not kos_embeds: return await self.should_cmdr_be_on_kos( exc.req_id, looking_for_cmdr, msg)
def expand_to_candidates(session, system_name): """ Considering system_name, determine all controlling nearby factions that could expand to it. Returns: [[system_name, distance, influence, state, faction_name], ...] """ with cogdb.session_scope(cogdb.EDDBSession) as eddb_session: centre = cogdb.eddb.get_systems(eddb_session, [system_name])[0] blacklist = session.query(Faction.id).\ join(Influence, Influence.faction_id == Faction.id).\ join(System, Influence.system_id == System.id).\ filter(System.name == system_name, Influence.system_id == System.id, Faction.id == Influence.faction_id).\ scalar_subquery() matches = session.query(System.name, System.dist_to(centre), System.population, Influence, Faction, FactionState.text, Government.text).\ join(Influence, Influence.system_id == System.id).\ join(Faction, Influence.faction_id == Faction.id).\ join(FactionState, Faction.state_id == FactionState.id).\ join(Government, Faction.government_id == Government.id).\ filter(System.dist_to(centre) <= 20, System.name != centre.name, Influence.is_controlling_faction == 1, Faction.id.notin_(blacklist)).\ order_by(System.dist_to(centre)).\ all() lines = [["System", "Dist", "Pop", "Inf", "Gov", "State", "Faction"]] for sys_name, sys_dist, sys_pop, inf, fact, fact_state, gov in matches: lines += [[ sys_name[:16], "{:5.2f}".format(sys_dist), "{:3.1f}".format(math.log(sys_pop, 10)), "{:5.2f}".format(inf.influence), gov[:4], fact_state, fact.name ]] return lines
def check_interaction_response(orig_author, sent, inter): """ Check if a user is the original requesting author or if the responding user to interaction is an admin. Use functools.partial to leave only inter arg. Args: orig_author: The original author who made request. sent: The message sent with options/buttons. inter: The interaction argument to check. Returns: True ONLY if responding to same message and user allowed. """ user_allowed = inter.user == orig_author if not user_allowed: with cogdb.session_scope(cogdb.Session) as session: try: cogdb.query.get_admin(session, inter.user) user_allowed = True except cog.exc.NoMatch: pass return inter.message == sent and user_allowed
def eddb_session(): with cogdb.session_scope(cogdb.EDDBSession) as session: yield session
def side_session(): with cogdb.session_scope(cogdb.SideSession) as session: yield session
def session(): with cogdb.session_scope(cogdb.Session) as session: yield session
except KeyboardInterrupt: msg = """Terminating ZMQ connection.""" print(msg) # Any time code run, need these dirs to write to try: shutil.rmtree(ALL_MSGS) except OSError: pass try: shutil.rmtree(JOURNAL_MSGS) except OSError: pass try: shutil.rmtree(JOURNAL_CARS) except OSError: pass os.mkdir(ALL_MSGS) os.mkdir(JOURNAL_MSGS) os.mkdir(JOURNAL_CARS) try: with cogdb.session_scope(cogdb.EDDBSession) as init_session: MAPS = create_id_maps(init_session) except (sqla_orm.exc.NoResultFound, sqla.exc.ProgrammingError): MAPS = None if __name__ == "__main__": main()
async def reply_with_api_result(self, req_id, event_data, msg): """ Reply using event_data from Inara API getCommanderProfile. Send information to user based on Inara and KOS lookup. Args: req_id: The id of the request to search. event_data: The event_data returned by Inara. msg: The original message from a user requesting search. Returns: kos_info: A KOS info object explaining if searched cmdr should be added. See should_cmdr_be_on_kos method. """ # cmdr prototype, only name guaranteed. Others will display if not found. # keeping original prototype from regex method. # balance and assets are not given from api. cmdr = { 'name': 'ERROR', 'profile_picture': 'https://inara.cz/images/userportraitback.png', 'role': EMPTY_INARA, 'allegiance': EMPTY_INARA, 'rank': EMPTY_INARA, 'power': EMPTY_INARA, 'squad': EMPTY_INARA, 'squad_rank': EMPTY_INARA, 'squad_count': EMPTY_INARA, } map_event = [ ["name", "userName"], ["name", "commanderName" ], # commanderName not always set, fallback to userName ["profile_picture", "avatarImageURL"], ["role", "preferredGameRole"], ["allegiance", "preferredAllegianceName"], ["power", "preferredPowerName"], ] for slot, data_name in map_event: received = event_data.get(data_name, cmdr[slot]) if received: cmdr[slot] = received # rank, ranks are a List of Dictionaries. try to get combat rank if "commanderRanksPilot" in event_data: match = next((rank for rank in event_data["commanderRanksPilot"] if rank["rankName"] == "combat"), None) if match: try: cmdr["rank"] = COMBAT_RANKS[int(match["rankValue"])] except (ValueError, KeyError): cmdr["rank"] = 'Unknown Rank' embeds = [] try: cmdr["squad"] = event_data["commanderSquadron"].get( "squadronName", cmdr["squad"]) embeds += [await squad_details_embed(event_data, cmdr)] except KeyError: pass cmdr_embed = discord.Embed.from_dict({ 'color': PP_COLORS.get(cmdr["allegiance"], PP_COLORS['default']), 'author': { 'name': cmdr["name"], 'icon_url': cmdr["profile_picture"], }, 'provider': { 'name': 'Inara', 'url': SITE, }, 'thumbnail': { 'url': cmdr['profile_picture'] }, 'title': "Commander Profile", 'url': event_data["inaraURL"], "fields": [ { 'name': 'Allegiance', 'value': cmdr["allegiance"], 'inline': True }, { 'name': 'Role', 'value': cmdr["role"], 'inline': True }, { 'name': 'Combat Rank', 'value': cmdr["rank"], 'inline': True }, { 'name': 'Squadron', 'value': cmdr["squad"], 'inline': True }, ], }) embeds = [cmdr_embed] + embeds with cogdb.session_scope(cogdb.Session) as session: kos_embeds = kos_lookup_cmdr_embeds(session, cmdr['name'], cmdr['profile_picture']) embeds += kos_embeds futs = [ cog.util.BOT.send_message(msg.channel, embed=embed) for embed in embeds ] futs += [self.delete_waiting_message(req_id)] for fut in futs: await fut if not kos_embeds: # Not found in KOS db, ask if should be added kos_info = await self.should_cmdr_be_on_kos( req_id, cmdr['name'], msg) kos_info['squad'] = cmdr.get('squad', EMPTY_INARA) return kos_info
def main(): with cogdb.session_scope(cogdb.SideSession) as side_session: feudal_finder(side_session)
async def on_message(self, message): """ Intercepts every message sent to guild! Notes: message.author - Returns member object roles -> List of Role objects. First always @everyone. roles[0].name -> String name of role. message.channel - Channel object. name -> Name of channel guild -> guild of channel members -> Iterable of all members channels -> Iterable of all channels get_member_by_name -> Search for user by nick message.content - The text """ content = message.content author = message.author channel = message.channel # TODO: Better filtering, use a loop and filter funcs. if await self.ignore_message(message): return if not message.content.startswith(self.prefix): await self.message_hooks(message) return log = logging.getLogger(__name__) log.info("guild: '%s' Channel: '%s' User: '******' | %s", channel.guild, channel.name, author.name, content) try: edit_time = message.edited_at content = re.sub(r'<[#@]\S+>', '', content).strip() # Strip mentions from text with cogdb.session_scope(cogdb.Session) as session: # Check permissions before full parsing cmd = content[len(self.prefix):content.find(' ')] cogdb.query.check_perms(session, message, cmd) args = self.parser.parse_args(re.split(r'\s+', content)) await self.dispatch_command(args=args, bot=self, msg=message, session=session) except cog.exc.ArgumentParseError as exc: log.exception("Failed to parse command. '%s' | %s", author.name, content) exc.write_log(log, content=content, author=author, channel=channel) if 'invalid choice' not in exc.message: try: self.parser.parse_args( content.split(' ')[0:1] + ['--help']) except cog.exc.ArgumentHelpError as exc2: exc.message = 'Invalid command use. Check the command help.' exc.message += '\n{}\n{}'.format( len(exc.message) * '-', exc2.message) await self.send_ttl_message(channel, str(exc)) try: if edit_time == message.edited_at: await message.delete() except discord.DiscordException: pass except cog.exc.CogException as exc: exc.write_log(log, content=content, author=author, channel=channel) if isinstance(exc, cog.exc.UserException): await self.send_ttl_message(channel, str(exc)) try: if edit_time == message.edited_at: await message.delete() except discord.DiscordException: pass else: await self.send_message(channel, str(exc)) except discord.DiscordException as exc: if exc.args[0].startswith("BAD REQUEST (status code: 400"): resp = "Response would be > 2000 chars, I cannot transmit it to Discord." resp += "\n\nIf this useage is valid see Gears." await self.send_ttl_message(channel, resp) try: if edit_time == message.edited_at: await message.delete() except discord.DiscordException: pass else: gears = self.get_member_by_substr("gearsand").mention await self.send_message( channel, "A critical discord error! {}.".format(gears)) line = "Discord.py Library raised an exception" line += cog.exc.log_format(content=content, author=author, channel=channel) log.exception(line) except apiclient.errors.Error as exc: line = "Google Sheets API raised an exception" line += "\n" + str(exc) + "\n\n" line += cog.exc.log_format(content=content, author=author, channel=channel) log.exception(line)