async def fetch_filled_fields(self, db) -> typing.Dict[uuid.UUID, FilledField]: """Fetch the fields for this profile and store them in .all_filled_fields""" if self.template is None or len(self.template.all_fields) == 0: await self.fetch_template(db, fetch_fields=True) field_rows = await db("SELECT * FROM filled_field WHERE user_id=$1 AND name=$2 AND field_id=ANY($3::UUID[])", self.user_id, self.name, self.template.all_fields.keys()) self.all_filled_fields.clear() for f in field_rows: filled = FilledField(**f) filled.field = self.template.all_fields[filled.field_id] self.all_filled_fields[filled.field_id] = filled return self.all_filled_fields
async def startup(self): """Clears all the bot's caches and fills them from a DB read""" # Remove caches self.logger.debug("Clearing caches") self.guild_settings.clear() Field.all_fields.clear() Field.all_profile_fields.clear() FilledField.all_filled_fields.clear() Profile.all_guilds.clear() Profile.all_profiles.clear() UserProfile.all_profiles.clear() # Get database connection db = await self.database.get_connection() # Get stored prefixes try: guild_data = await db("SELECT * FROM guild_settings") except Exception as e: self.logger.critical(f"Error selecting from guild_settings - {e}") exit(1) for row in guild_data: self.guild_settings[row['guild_id']] = dict(row) # Fill caches fields = await db('SELECT * FROM field') filled_fields = await db('SELECT * FROM filled_field') profiles = await db('SELECT * FROM profile') user_profiles = await db('SELECT * FROM created_profile') if fields: for i in fields: Field(**i) if filled_fields: for i in filled_fields: FilledField(**i) if profiles: for i in profiles: Profile(**i) if user_profiles: for i in user_profiles: UserProfile(**i) # Wait for the bot to cache users before continuing self.logger.debug( "Waiting until ready before completing startup method.") await self.wait_until_ready() # Close database connection await db.disconnect()
async def startup(self): ''' Resets and fills the FamilyTreeMember cache with objects ''' # Remove caches LOGGER.debug("Clearing caches") Field.all_fields.clear() Field.all_profile_fields.clear() FilledField.all_filled_fields.clear() Profile.all_guilds.clear() Profile.all_profiles.clear() UserProfile.all_profiles.clear() # Fill caches async with self.database() as db: fields = await db('SELECT * FROM field') filled_fields = await db('SELECT * FROM filled_field') profiles = await db('SELECT * FROM profile') user_profiles = await db('SELECT * FROM created_profile') if fields: for i in fields: Field(**i) if filled_fields: for i in filled_fields: FilledField(**i) if profiles: for i in profiles: Profile(**i) if user_profiles: for i in user_profiles: UserProfile(**i) # Wait for the bot to cache users before continuing LOGGER.debug("Waiting until ready before completing startup method.") await self.wait_until_ready()
async def setprofilemeta(self, ctx: Context, profile: Profile, target_user: Member): """Talks a user through setting up a profile on a given server""" # Set up some variaballlales user = ctx.author target_user = target_user or user fields = profile.fields # Check if they're setting someone else's profile and they're not a mod if target_user != ctx.author and not member_is_moderator( ctx.bot, ctx.author): await ctx.send( f"You're missing the `manage_roles` permission required to do this." ) return # Check if they already have a profile set user_profile = profile.get_profile_for_member(target_user) if user_profile is not None: await ctx.send( f"{'You' if target_user == user else target_user.mention} already {'have' if target_user == user else 'has'} a profile set for `{profile.name}`." ) return # See if you we can send them the PM try: await user.send( f"Now talking you through setting up a `{profile.name}` profile{' for ' + target_user.mention if target_user != user else ''}." ) await ctx.send("Sent you a PM!") except Exception: await ctx.send( "I'm unable to send you PMs to set up the profile :/") return # Talk the user through each field filled_fields = [] for field in fields: await user.send(field.prompt) # User text input if isinstance(field.field_type, (TextField, NumberField)): check = lambda m: m.author == user and isinstance( m.channel, DMChannel) while True: try: m = await self.bot.wait_for('message', check=check, timeout=field.timeout) except AsyncTimeoutError: await user.send( f"Your input for this field has timed out. Please try running `set{profile.name}` on your server again." ) return try: field.field_type.check(m.content) field_content = m.content break except FieldCheckFailure as e: await user.send(e.message) # Image input elif isinstance(field.field_type, ImageField): check = lambda m: m.author == user and isinstance( m.channel, DMChannel) while True: try: m = await self.bot.wait_for('message', check=check, timeout=field.timeout) except AsyncTimeoutError: await user.send( f"Your input for this field has timed out. Please try running `set{profile.name}` on your server again." ) return try: if m.attachments: content = m.attachments[0].url else: content = m.content field.field_type.check(content) field_content = content break except FieldCheckFailure as e: await user.send(e.message) # Invalid field type apparently else: raise Exception( f"Field type {field.field_type} is not catered for") # Add field to list filled_fields.append( FilledField(target_user.id, field.field_id, field_content)) # Make the UserProfile object up = UserProfile(target_user.id, profile.profile_id, profile.verification_channel_id == None) # Make sure the bot can send the embed at all try: await user.send(embed=up.build_embed()) except Exception as e: await user.send( f"Your profile couldn't be sent to you - `{e}`.\nPlease try again later." ) return # Make sure the bot can send the embed to the channel if profile.verification_channel_id: try: channel = await self.bot.fetch_channel( profile.verification_channel_id) embed = up.build_embed() embed.set_footer( text=f'{profile.name.upper()} // Verification Check') v = await channel.send( f"New **{profile.name}** submission from {target_user.mention}\n{target_user.id}/{profile.profile_id}", embed=embed) await v.add_reaction(self.TICK_EMOJI) await v.add_reaction(self.CROSS_EMOJI) except Exception as e: await user.send( f"Your profile couldn't be send to the verification channel? - `{e}`." ) return # Database me up daddy async with self.bot.database() as db: try: await db( 'INSERT INTO created_profile (user_id, profile_id, verified) VALUES ($1, $2, $3)', up.user_id, up.profile.profile_id, up.verified) except UniqueViolationError: await db( 'UPDATE created_profile SET verified=$3 WHERE user_id=$1 AND profile_id=$2', up.user_id, up.profile.profile_id, up.verified) await db( 'DELETE FROM filled_field WHERE user_id=$1 AND field_id in (SELECT field_id FROM field WHERE profile_id=$2)', up.user_id, up.profile.profile_id) self.log_handler.warn( f"Deleted profile for {up.user_id} on UniqueViolationError" ) for field in filled_fields: await db( 'INSERT INTO filled_field (user_id, field_id, value) VALUES ($1, $2, $3)', field.user_id, field.field_id, field.value) # Respond to user await user.send("Your profile has been created and saved.")