async def unban(self, ctx, username, *, reason='It\'s your lucky day!'): await ctx.message.delete() log_channel = await commands.TextChannelConverter().convert(ctx, config.read('log_channel_id')) username = self.username_is_player_id(username) if not self.valid_username_format(username): await ctx.author.send(f"Invalid username format: `{username}`") raise commands.UserInputError # Check that user is banned with db_conn() as db: db.execute(f'SELECT blocked, discord_id FROM ticketServer_tickets WHERE email = \'{username}\'') row = db.fetchone() if row == None: await ctx.author.send(f'Could not find an account with the username: `{username}`') return if row[0] == 0: print(f'{ctx.author} tried to unban {username} but they\'re not already banned.') await ctx.author.send(f'`{username}` is not already banned.') return # Unban the user with db_conn() as db: db.execute(f'UPDATE ticketServer_tickets SET blocked = 0 WHERE email = \'{username}\'') print(f'{ctx.author} unbanned {username} for: {reason}') discord_user = ctx.guild.get_member(int(row[1])) # Notify the user try: embed = discord.Embed(title='You were unbanned from 2HOL', colour=discord.Colour.green()) embed.add_field(name='Reason:', value=f'{reason}', inline=True) await discord_user.send(embed=embed) except: # Message can fail if the user does not allow messages from anyone notify_user = False else: notify_user = True # Embed log embed = discord.Embed(title='Unbanned a user from the game', colour=discord.Colour.green()) embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url) embed.add_field(name='Member:', value=f'{discord_user.name}#{discord_user.discriminator}', inline=True) embed.add_field(name='Username:'******'{username}', inline=True) embed.add_field(name='Reason:', value=f'{reason}', inline=True) embed.add_field(name='Notification:', value='Successful' if notify_user else 'Failed', inline=True) embed.set_footer(text=f"Member ID: {discord_user.id}", icon_url=discord_user.avatar_url) await log_channel.send(embed=embed)
async def regenerate(self, ctx, user: discord.User): await ctx.message.delete() log_channel = await commands.TextChannelConverter().convert(ctx, config.read('log_channel_id')) key = await self.dictator.get_cog('User').create_key() with db_conn() as db: db.execute(f'UPDATE ticketServer_tickets SET login_key = \'{key}\' WHERE discord_id = \'{user.id}\'') # Notify the user try: embed = discord.Embed(title='Your key to access 2HOL has been regenerated.', colour=discord.Colour.green()) await user.send(embed=embed) except: notify_user = False else: notify_user = True # Embed log embed = discord.Embed(title='User key regenerated', colour=discord.Colour.green()) embed.add_field(name='User:'******'{user.mention}', inline=True) embed.add_field(name='Moderator:', value=f'{ctx.author.mention}', inline=True) embed.add_field(name='User notification:', value='Successful' if notify_user else 'Failed', inline=True) await log_channel.send(embed=embed)
def playtime_less_than(self, discord_id, less_than_minutes): with db_conn() as db: db.execute( f'SELECT time_played FROM ticketServer_tickets WHERE discord_id = {discord_id}' ) time_played = db.fetchone() return True if int(time_played[0]) < less_than_minutes else False
async def info(self, ctx, user: discord.User): await ctx.message.delete() with db_conn() as db: db.execute( f'SELECT time_played, blocked, email, last_activity FROM ticketServer_tickets WHERE discord_id = \'{user.id}\'' ) user_info = db.fetchone() if not user_info: embed = discord.Embed( title=f'No results for the user \'{user.mention}\'.', colour=0xffbb35) await ctx.author.send(embed=embed) return # User hasn't lived a single life yet if user_info[0] == 0: embed = discord.Embed( title= f'\'{user.name}#{user.discriminator}\' (or {user_info[2]}) has not lived any lives yet.', colour=0xffbb35) await ctx.author.send(embed=embed) return # Time formatting current_time = datetime.datetime.now(tz=datetime.timezone.utc) current_time = current_time.replace(microsecond=0) last_active = datetime.datetime(year=user_info[3].year, month=user_info[3].month, day=user_info[3].day, hour=user_info[3].hour, minute=user_info[3].minute, second=user_info[3].second, tzinfo=datetime.timezone.utc) diff = current_time - last_active diff_split = str(diff).split(':') # diff_split[0] appears as '3 days, 4' where 3 = amount of days and 4 = amount of hours. diff_formatted = f'{diff_split[0]} hours, {diff_split[1]} minutes ago' member = ctx.guild.get_member(user.id) # Form embed embed = discord.Embed( title=f'Results for the user \'{user.name}#{user.discriminator}\':', colour=0xffbb35) embed.add_field(name='Time played:', value=f'{round(user_info[0] / 60, 1)} hours') embed.add_field(name='Blocked:', value='Yes' if user_info[1] else 'No') embed.add_field(name='Joined guild:', value=member.joined_at.date() if member else 'Unknown') embed.add_field(name='Username:'******'Last activity:', value=diff_formatted) embed.set_footer(text='Data range: August 2019 - Current') await ctx.author.send(embed=embed)
async def create_bot(self, ctx, prefix, amount: int): await ctx.message.delete() # Filter prefix prefix = (re.sub('[^a-zA-Z0-9]', '', prefix)) for i in range(amount): username = f'{prefix}-{i}' key = await self.create_key() with db_conn() as db: db.execute(f'INSERT INTO ticketServer_tickets (email, login_key) VALUES (\'{username}\', \'{key}\')') await ctx.author.send(f'{username} :: {key}')
def username_from_player_id(self, player_id: int) -> str: """Takes an int as a players life ID and returns the associated username.""" with db_conn() as db: """ A player life ID can be repeated between different servers. We have made use of a single server for four years and do not intend to change this in the short term, so are largely unaffected by this. To resolve this, we assume we're only interested in the most recent player who lived with this ID. This is achieved with 'ORDER BY death_time DESC LIMIT 1' """ db.execute(f'SELECT lineageServer_users.email FROM lineageServer_lives INNER JOIN lineageServer_users ON lineageServer_lives.user_id = lineageServer_users.id WHERE player_id = {player_id} ORDER BY death_time DESC LIMIT 1') username = db.fetchone() if not username: return else: # We really only want the first result of the tuple username = username[0] return username
async def whowas(self, ctx, *, character_name): await ctx.message.delete() # Result limt, due to embed length limitations, the maxium is 8. history = 5 player_id = None # Safe characters only character_name = re.sub(('[^a-zA-Z0-9 ]'), '', character_name) if self.is_int(character_name): # character_name is a player life ID, retrieve the associated character name. player_id = character_name with db_conn() as db: """ A player life ID can be repeated between different servers. We have made use of a single server for four years and do not intend to change this in the short term, so are largely unaffected by this. To resolve this, we assume we're only interested in the most recent player who lived with this ID. This is achieved with 'ORDER BY death_time DESC LIMIT 1' """ db.execute(f'SELECT lineageServer_lives.name FROM lineageServer_lives WHERE player_id = {character_name} ORDER BY death_time DESC LIMIT 1') character_name = db.fetchone() if not character_name: embed = discord.Embed(title=f'No results for that player ID.', colour=0xffbb35) await ctx.send(embed=embed) return else: # We really only want the first result of the tuple character_name = character_name[0] with db_conn() as db: # I don't understand why I need to use %s instead of F strings. But it doesn't work otherwise. db.execute('SELECT ticketServer_tickets.discord_id, lineageServer_lives.death_time, lineageServer_users.email, lineageServer_lives.id, ticketServer_tickets.time_played FROM lineageServer_lives INNER JOIN lineageServer_users ON lineageServer_lives.user_id = lineageServer_users.id INNER JOIN ticketServer_tickets ON lineageServer_users.email = ticketServer_tickets.email WHERE name = %s ORDER BY death_time DESC LIMIT %s', (character_name, history)) users = db.fetchall() if not users: embed = discord.Embed(title=f'No results for the character \'{character_name}\'.', description=f"Found name \'{character_name}\' from Player ID \'{player_id}\'" if player_id else "", colour=0xffbb35) await ctx.send(embed=embed) return current_time = datetime.datetime.now(tz=datetime.timezone.utc) current_time = current_time.replace(microsecond=0) embed = discord.Embed(title=f"Latest {history} results for the name \'{character_name}\':", description=f"Found name \'{character_name}\' from Player ID \'{player_id}\'" if player_id else "", colour=0xffbb35) embed.set_author(name=ctx.author.name, icon_url=ctx.author.avatar_url) for u in users: try: found_user = await self.dictator.fetch_user(u[0]) except: raise commands.CommandError else: # Format death time as timezone aware death_time = datetime.datetime(year=u[1].year, month=u[1].month, day=u[1].day, hour=u[1].hour, minute=u[1].minute, second=u[1].second, tzinfo=datetime.timezone.utc) diff = current_time - death_time diff_split = str(diff).split(':') # diff_split[0] appears as '3 days, 4' where 3 = amount of days and 4 = amount of hours. I aplogise if you have to debug this. diff_formatted = f'{diff_split[0]} hours, {diff_split[1]} minutes ago' embed.add_field(name='Username:'******'{u[2]}', inline=True) embed.add_field(name='Member:', value=f'{found_user}', inline=True) embed.add_field(name='Died:', value=f'{diff_formatted}', inline=True) if len(users) < history: embed.add_field(name='\u200b', value='End of results') await ctx.send(embed=embed)
async def create_user(self, user, username=None): if username is None: username = user.name # Filter username, can't have any nasty characters # Then replaces any non whitlisted (regex) characters with empty string username = (re.sub('[^a-zA-Z0-9]', '', username)) if len(username) < 3: # Username was only made up of special chracters, prompt for one chosen_username = await self.prompt_user(user, f'Hey {user.mention}, your username doesn\'t contain enough valid characters. What should I use instead?') if chosen_username is None: await user.send('You didn\'t tell me what to use instead.') return else: await self.create_user(user, chosen_username) return # Check if user already has an account before creating one check_user = await self.search_user(user.id) if check_user is not None: # User already has an account username = check_user[0] key = check_user[1] print(f'We tried to create an account for {user} but they already had one, so we\'ll send them their login information.') await user.send(f'Hey {user.mention}, you already have an account! Here is your login information:\n**Username:** {username}\n**Key:** {key}') return # Can't be having usernames too long, database allows for up to 255 but seriously? if len(username) > 45: username = username[0:45] username += '-' + user.discriminator # Check if username is already in use check_name = await self.search_username(username) if check_name is not None: # Username is already in use, prompt for one chosen_username = await self.prompt_user(user, f'Hey {user.mention}, your username is already in use. What should I use instead?') if chosen_username is None: await user.send('You didn\'t tell me what to use instead.') return else: await self.create_user(user, chosen_username) return # Create the users accounnt, calling on create_key for a key key = str(await self.create_key()) user_id = int(user.id) username = str(username) with db_conn() as db: db.execute(f'INSERT INTO ticketServer_tickets (email, discord_id, login_key) VALUES (\'{username}\', \'{user_id}\', \'{key}\')') # Notify the user try: await user.send(f'Welcome to 2HOL {user.mention}!\nYou can read how to start playing our game at <https://twohoursonelife.com/first-time-playing>\nWhen you\'re ready, you can use the details below to log in to the game:\n**Username:** {username}\n**Key:** {key}') except: notify_user = False else: notify_user = True debug_log_channel = self.dictator.get_channel(int(config.read('debug_log_channel_id'))) # Embed log embed = discord.Embed(title='New game account created', colour=discord.Colour.green()) embed.add_field(name='Member:', value=f'{user.mention}', inline=True) embed.add_field(name='Username:'******'{username}', inline=True) embed.add_field(name='User notification:', value='Successful' if notify_user else 'Failed', inline=True) await debug_log_channel.send(embed=embed) print(f'Successfully created an account for {user.name}#{user.discriminator} using the username {username}.')
async def search_username(self, user): with db_conn() as db: db.execute(f'SELECT email FROM ticketServer_tickets WHERE email = \'{user}\'') row = db.fetchone() return row
async def search_user(self, user_id): with db_conn() as db: db.execute(f'SELECT email, login_key FROM ticketServer_tickets WHERE discord_id = \'{user_id}\'') row = db.fetchone() return row