async def set_forty_role(self, ctx, role_id): role_id = utils.sanitize_name(role_id) try: role_id = int(role_id) role = discord.utils.get(ctx.guild.roles, id=role_id) except: role = discord.utils.get(ctx.guild.roles, name=role_id) if role is None: try: role = await ctx.guild.create_role(name=role_id, hoist=False, mentionable=True) except discord.errors.HTTPException: pass if role is None: await ctx.message.add_reaction(self.bot.failed_react) return await ctx.send(embed=discord.Embed( colour=discord.Colour.red(), description= f"Unable to find or create role with name or id: **{role_id}**." ), delete_after=10) await ctx.send(embed=discord.Embed( colour=discord.Colour.from_rgb(255, 255, 0), description=f"Created new role: **{role.name}**"), delete_after=10) quick_badge_dict = self.bot.guild_dict[ctx.guild.id]['configure_dict']\ .get('quick_badge', self.quick_badge_dict_default) quick_badge_dict['40_role'] = role.id self.bot.guild_dict[ ctx.guild.id]['configure_dict']['quick_badge'] = quick_badge_dict await ctx.channel.send( f'Level 40 auto-assign role set to **{role.name}**.', delete_after=10) return await ctx.message.add_reaction(self.bot.success_react)
async def update_raid_location(Kyogre, ctx, guild_dict, message, report_channel, raid_channel, gym): guild = message.guild raid_dict = guild_dict[guild.id]['raidchannel_dict'][raid_channel.id] oldraidmsg = await raid_channel.fetch_message(raid_dict['raidmessage']) oldreportmsg = await report_channel.fetch_message(raid_dict['raidreport']) report_embed, raid_embed = await embed_utils.build_raid_embeds( Kyogre, ctx, raid_dict, True) regions = [gym.region] otw_list = [] trainer_dict = copy.deepcopy(raid_dict['trainer_dict']) for trainer in trainer_dict.keys(): if trainer_dict[trainer]['status']['coming']: user = guild.get_member(trainer) otw_list.append(user.mention) await raid_channel.send( content=f"Someone has suggested a different location for the raid! " f"Trainers {', '.join(otw_list)}: make sure you are headed to the right place!" ) channel_name = raid_channel.name channel_prefix = channel_name.split("_")[0] new_channel_name = utils.sanitize_name(channel_prefix + "_" + gym.name)[:32] await raid_channel.edit(name=new_channel_name) try: message_content = get_raidtext(Kyogre, guild, raid_dict, raid_channel, False) await oldraidmsg.edit(new_content=message_content, embed=raid_embed, content=message_content) except: Kyogre.logger.info( f"Failed to update raid channel embed for raid at {gym.name}") try: content = build_raid_report_message(Kyogre, raid_channel, raid_dict) message_content = get_raidtext(Kyogre, guild, raid_dict, raid_channel, True) await oldreportmsg.edit(new_content=content, embed=report_embed, content=content) if raid_dict['raidcityreport'] is not None: report_city_channel = Kyogre.get_channel(raid_dict['reportcity']) report_city_msg = await report_city_channel.fetch_message( raid_dict['raidcityreport']) await report_city_msg.edit(new_content=message_content, embed=report_embed, content=message_content) except: Kyogre.logger.info( f"Failed to update report channel embed for raid at {gym.name}") raid_dict['raidmessage'] = oldraidmsg.id raid_dict['raidreport'] = oldreportmsg.id raid_dict['gym'] = gym.id raid_dict['address'] = gym.name raid_dict['regions'] = regions guild_dict[guild.id]['raidchannel_dict'][raid_channel.id] = raid_dict list_cog = Kyogre.cogs.get('ListManagement') await list_cog.update_listing_channels(guild, "raid", edit=True) return
async def _set_hatch(self, ctx, *, new_datestr): new_date = parse(new_datestr) date_key = new_date.strftime("%b_%d").lower() start_time = new_date.strftime("%H:%M") hatch, expire = self._calculate_ex_start_time(date_key, start_time, ctx.guild.id) channel = ctx.channel ex_raid = self.bot.guild_dict[channel.guild.id]['exchannel_dict'][ channel.category_id]['channels'][channel.id] ex_raid['hatch'] = hatch ex_raid['expire'] = expire embed = await self._build_ex_embed(ctx, ex_raid) channel_message_id = ex_raid['channel_message'] channel_message = await ctx.channel.fetch_message(channel_message_id) location_matching_cog = self.bot.cogs.get('LocationMatching') gym_id = ex_raid['gym'] gym = location_matching_cog.get_gym_by_id(ctx.guild.id, gym_id) name = utils.sanitize_name( f"{start_time.lower().replace(':', '')} {gym.name}")[:36] await ctx.channel.edit(name=name) await channel_message.edit(embed=embed) offset = self.bot.guild_dict[ ctx.guild.id]['configure_dict']['settings']['offset'] offset *= (60 * 60) hatch = datetime.datetime.fromtimestamp(hatch + offset) new_hatch_str = datetime.datetime.fromtimestamp( hatch.timestamp()).strftime('%a %b %d %I:%M %p') await ctx.channel.send( f"The start time for this EX raid has been changed to **{new_hatch_str}**!" )
async def _validate_or_create_role(self, ctx, role_id, eventname='', checkin=False): try: role_id = int(role_id) role = discord.utils.get(ctx.guild.roles, id=role_id) except: role = discord.utils.get(ctx.guild.roles, name=role_id) if role is None: try: if role_id.isdigit(): role_id = utils.sanitize_name(eventname) else: role_id = utils.sanitize_name(role_id) role = await ctx.guild.create_role(name=role_id, hoist=False, mentionable=True) except discord.errors.HTTPException: pass if role is None: await ctx.message.add_reaction(self.failed_react) if checkin: await ctx.send(embed=discord.Embed( colour=discord.Colour.red(), description= f"Checkin failed, no role found with name: **{role_id}** and failed to create role." ), delete_after=10) else: await ctx.send(embed=discord.Embed( colour=discord.Colour.red(), description= f"No valid role found with name or id: **{role_id}**. Failed to create role with that name." ), delete_after=10) return None await ctx.invoke(self.bot.get_command('event updaterole'), info=f"{eventname}, {role.name}") await ctx.send(embed=discord.Embed( colour=discord.Colour.from_rgb(255, 255, 0), description=f"Created new role: **{role.name}**"), delete_after=10) return role
async def _short_output(self, ctx, *, info): guild = ctx.guild info = re.split(r',*\s+', info) if len(info) < 2: await ctx.message.add_reaction(self.bot.failed_react) return await ctx.send( "Please provide both a region name and a channel name or id.", delete_after=15) region = info[0].lower() channel_info = ' '.join(info[1:]).lower() region_names = self.bot.guild_dict[guild.id]['configure_dict'].get( 'regions', {}).get('info', None) if not region_names: await ctx.message.add_reaction(self.bot.failed_react) return await ctx.send( "No regions have been configured for this server.", delete_after=15) if region not in region_names.keys(): await ctx.message.add_reaction(self.bot.failed_react) return await ctx.send( f"No region with name: **{region}** found in this server's configuration.", delete_after=15) if channel_info == "none": self.bot.guild_dict[guild.id]['configure_dict']['raid'].setdefault( 'short_output', {})[region] = None msg = f"Short output channel removed for **{region}**." else: channel = None name = utils.sanitize_name(channel_info) # If a channel mention is passed, it won't be recognized as an int but this for get will succeed try: channel = discord.utils.get(guild.text_channels, id=int(name)) except ValueError: pass if not channel: channel = discord.utils.get(guild.text_channels, name=name) if not channel: await ctx.message.add_reaction(self.bot.failed_react) return await ctx.send( f"No channel with name or id: **{channel_info}** " f"found in this server's channel list.", delete_after=15) self.bot.guild_dict[guild.id]['configure_dict']['raid'].setdefault( 'short_output', {})[region] = channel.id msg = f"Short output channel for **{region}** set to **{channel.mention}**" await ctx.message.add_reaction(self.bot.success_react) return await ctx.send(msg, delete_after=15)
async def get_channel_by_name_or_id(ctx, name): channel = None # If a channel mention is passed, it won't be recognized as an int but this get will succeed name = utils.sanitize_name(name) try: channel = discord.utils.get(ctx.guild.text_channels, id=int(name)) except ValueError: pass if not channel: channel = discord.utils.get(ctx.guild.text_channels, name=name) if channel: guild_channel_list = [] for textchannel in ctx.guild.text_channels: guild_channel_list.append(textchannel.id) diff = set([channel.id]) - set(guild_channel_list) else: diff = True if diff: return None return channel
async def _send_pvp_notification_async(self, ctx): message = ctx.message channel = message.channel guild = message.guild trainer = guild.get_member(message.author.id) trainer_info_dict = self.bot.guild_dict[ guild.id]['trainers'].setdefault('info', {}) friends = trainer_info_dict.setdefault(message.author.id, {}).setdefault('friends', []) outbound_dict = {} tag_msg = f'**{trainer.display_name}** wants to battle! Who will challenge them?!' for friend in friends: friend = guild.get_member(friend) outbound_dict[friend.id] = { 'discord_obj': friend, 'message': tag_msg } role_name = utils.sanitize_name(f"pvp {trainer.name}") subscriptions_cog = self.bot.cogs.get('Subscriptions') if not subscriptions_cog: return None return await subscriptions_cog.generate_role_notification_async( role_name, channel, outbound_dict)
async def _create_ex_channel(self, ctx, gym, start_time, cat): channel_overwrite_dict = ctx.channel.overwrites kyogre_overwrite = { self.bot.user: discord.PermissionOverwrite(send_messages=True, read_messages=True, manage_roles=True, manage_channels=True, manage_messages=True, add_reactions=True, external_emojis=True, read_message_history=True, embed_links=True, mention_everyone=True, attach_files=True) } channel_overwrite_dict.update(kyogre_overwrite) name = start_time.lower().replace(':', '').replace('am', '').replace('pm', '') name = utils.sanitize_name(f"{name} {gym.name}")[:36] return await ctx.guild.create_text_channel( name, overwrites=channel_overwrite_dict, category=cat)
async def update_raid_location(Kyogre, guild_dict, message, report_channel, raid_channel, gym): guild = message.guild raid_dict = guild_dict[guild.id]['raidchannel_dict'][raid_channel.id] oldraidmsg = await raid_channel.fetch_message(raid_dict['raidmessage']) oldreportmsg = await report_channel.fetch_message(raid_dict['raidreport']) oldembed = oldraidmsg.embeds[0] newloc = gym.maps_url regions = [gym.region] new_embed = discord.Embed(title=oldembed.title, url=newloc, colour=guild.me.colour) for field in oldembed.fields: t = 'team' s = 'status' if (t not in field.name.lower()) and (s not in field.name.lower()): new_embed.add_field(name=field.name, value=field.value, inline=field.inline) weather = raid_dict.get('weather', None) utils_cog = Kyogre.cogs.get('Utilities') enabled = utils_cog.raid_channels_enabled(guild, raid_channel) if enabled: embed_indices = await embed_utils.get_embed_field_indices(new_embed) gym_embed = new_embed.fields[embed_indices['gym']] gym_info = "**Name:** {0}\n**Notes:** {1}".format( gym.name, "_EX Eligible Gym_" if gym.ex_eligible else "N/A") if weather is not None: gym_info += "\n**Weather**: " + weather new_embed.set_field_at(embed_indices['gym'], name=gym_embed.name, value=gym_info, inline=True) new_embed.set_footer(text=oldembed.footer.text, icon_url=oldembed.footer.icon_url) new_embed.set_thumbnail(url=oldembed.thumbnail.url) otw_list = [] trainer_dict = copy.deepcopy(raid_dict['trainer_dict']) for trainer in trainer_dict.keys(): if trainer_dict[trainer]['status']['coming']: user = guild.get_member(trainer) otw_list.append(user.mention) await raid_channel.send( content= 'Someone has suggested a different location for the raid! Trainers {trainer_list}: make sure you are headed to the right place!' .format(trainer_list=', '.join(otw_list))) channel_name = raid_channel.name channel_prefix = channel_name.split("_")[0] new_channel_name = utils.sanitize_name(channel_prefix + "_" + gym.name)[:32] await raid_channel.edit(name=new_channel_name) try: message_content = get_raidtext(Kyogre, guild, guild_dict, raid_dict, gym, report_channel, raid_channel, False) await oldraidmsg.edit(new_content=message_content, embed=new_embed, content=message_content) except: pass try: if enabled: embed_indices = await embed_utils.get_embed_field_indices(new_embed ) new_embed = await embed_utils.filter_fields_for_report_embed( new_embed, embed_indices, enabled) message_content = get_raidtext(Kyogre, guild, guild_dict, raid_dict, gym, report_channel, raid_channel, True) await oldreportmsg.edit(new_content=message_content, embed=new_embed, content=message_content) if raid_dict['raidcityreport'] is not None: report_city_channel = Kyogre.get_channel( raid_dict['reportcity']) report_city_msg = await report_city_channel.fetch_message( raid_dict['raidcityreport']) await report_city_msg.edit(new_content=message_content, embed=new_embed, content=message_content) except: pass raid_dict['raidmessage'] = oldraidmsg.id raid_dict['raidreport'] = oldreportmsg.id raid_dict['gym'] = gym.id raid_dict['address'] = gym.name raid_dict['regions'] = regions guild_dict[guild.id]['raidchannel_dict'][raid_channel.id] = raid_dict list_cog = Kyogre.cogs.get('ListManagement') await list_cog.update_listing_channels(guild, "raid", edit=True) return
async def send_notifications_async(self, notification_type, details, new_channel, exclusions=[]): valid_types = [ 'raid', 'research', 'wild', 'nest', 'gym', 'shiny', 'item', 'lure', 'hideout' ] if notification_type not in valid_types: return guild = new_channel.guild # get trainers try: results = (SubscriptionTable.select( SubscriptionTable.trainer, SubscriptionTable.target, SubscriptionTable.specific).join( TrainerTable, on=(SubscriptionTable.trainer == TrainerTable.snowflake )).where((SubscriptionTable.type == notification_type) | (SubscriptionTable.type == 'pokemon') | (SubscriptionTable.type == 'gym')). where(TrainerTable.guild == guild.id).where( SubscriptionTable.guild_id == guild.id)).execute() except: return # group targets by trainer trainers = set([s.trainer for s in results]) target_dict = { t: {s.target: s.specific for s in results if s.trainer == t} for t in trainers } regions = set(details.get('regions', [])) ex_eligible = details.get('ex-eligible', None) tier = details.get('tier', None) perfect = details.get('perfect', None) pokemon_list = details.get('pokemon', []) gym = details.get('location', None) item = details.get('item', None) lure_type = details.get('lure_type', None) if not isinstance(pokemon_list, list): pokemon_list = [pokemon_list] location = details.get('location', None) multi = details.get('multi', False) region_dict = self.bot.guild_dict[guild.id]['configure_dict'].get( 'regions', None) outbound_dict = {} # build final dict for trainer in target_dict: user = guild.get_member(trainer) if trainer in exclusions or not user: continue if region_dict and region_dict.get('enabled', False): matched_regions = [ n for n, o in region_dict.get('info', {}).items() if o['role'] in [r.name for r in user.roles] ] if regions and regions.isdisjoint(matched_regions): continue targets = target_dict[trainer] descriptors = [] target_matched = False if 'ex-eligible' in targets and ex_eligible: target_matched = True descriptors.append('ex-eligible') if tier and str(tier) in targets: tier = str(tier) if targets[tier]: try: current_gym_ids = targets[tier].strip('[').strip(']') split_id_string = current_gym_ids.split(', ') split_ids = [] for s in split_id_string: try: split_ids.append(int(s)) except ValueError: pass target_gyms = (GymTable.select( LocationTable.id, LocationTable.name, LocationTable.latitude, LocationTable.longitude, RegionTable.name.alias('region'), GymTable.ex_eligible, LocationNoteTable.note).join(LocationTable).join( LocationRegionRelation).join(RegionTable).join( LocationNoteTable, JOIN.LEFT_OUTER, on=(LocationNoteTable.location_id == LocationTable.id) ).where((LocationTable.guild == guild.id) & ( LocationTable.guild == RegionTable.guild) & (LocationTable.id << split_ids))) target_gyms = target_gyms.objects(Gym) found_gym_names = [r.name for r in target_gyms] if gym in found_gym_names: target_matched = True except: pass else: target_matched = True descriptors.append( 'level {level}'.format(level=details['tier'])) pkmn_adj = '' if perfect and 'perfect' in targets: target_matched = True pkmn_adj = 'perfect ' for pokemon in pokemon_list: if pokemon.name in targets: target_matched = True full_name = pkmn_adj + pokemon.name descriptors.append(full_name) if gym in targets: target_matched = True if item and item.lower() in targets: target_matched = True if 'shiny' in targets: target_matched = True if 'takeover' in targets or (lure_type and lure_type in targets): trainer_info = self.bot.guild_dict[ guild.id]['trainers'].setdefault('info', {}).setdefault( trainer, {}) t_location = trainer_info.setdefault('location', None) distance = trainer_info.setdefault('distance', None) stop = details['location'] if t_location is not None and distance is not None: if self.close_enough( (float(stop.latitude), float(stop.longitude)), (t_location[0], t_location[1]), distance): target_matched = True else: target_matched = False else: target_matched = True if not target_matched: continue description = ', '.join(descriptors) start = 'An' if re.match(r'^[aeiou]', description, re.I) else 'A' if notification_type == 'item': start = 'An' if re.match(r'^[aeiou]', item, re.I) else 'A' if multi: location = 'multiple locations' message = f'{start} **{item} research task** has been reported at **{location}**!' elif notification_type == 'lure': message = f'A **{lure_type.capitalize()}** lure has been dropped at {location.name}!' elif notification_type == 'hideout': message = f'A **Team Rocket Hideout** has been spotted at {location.name}!' elif notification_type == 'wild': message = f'A **wild {description} spawn** has been reported at **{location}**!' elif notification_type == 'research': if multi: location = 'multiple locations' message = f'{start} **{description} research task** has been reported at **{location}**!' elif 'hatching' in details and details['hatching']: message = f"The egg at **{location}** has hatched into {start.lower()} **{description}** raid!" else: message = f'{start} {description} {notification_type} at {location} has been reported!' outbound_dict[trainer] = {'discord_obj': user, 'message': message} pokemon_names = ' '.join([p.name for p in pokemon_list]) if notification_type == 'item': role_name = utils.sanitize_name(f"{item} {location}".title()) elif notification_type == 'lure': role_name = utils.sanitize_name( f'{lure_type} {location.name}'.title()) elif notification_type == 'hideout': role_name = utils.sanitize_name( f'Rocket Hideout {location.name}'.title()) else: role_name = utils.sanitize_name( f"{notification_type} {pokemon_names} {location}".title()) # starting to hit rate limit for role creation so explicitly mentioning all trainers in the meantime await self.notify_all_async(new_channel, outbound_dict) faves_cog = self.bot.cogs.get('Faves') return faves_cog.get_report_points(guild.id, pokemon_list, notification_type)