def __init__(self, client): self.client = client self.client_tools = ClientTools(client) self.database_tools = DatabaseTools(client) insert_channel = "INSERT INTO channels (channel_id, channel_name) VALUES (%s, %s)" update_channel = "UPDATE `gssp_logging`.`channels` SET `channel_name`=%s WHERE `channel_id`=%s;" if not bool(config['discord'].get("skip_scrape")): for guild in client.guilds: logger.info("{}: Updating channels".format(str(guild))) for channel in guild.text_channels: try: cursor.execute( insert_channel, (channel.id, emoji.demojize(channel.name))) logger.debug("Inserted {} to DB".format( emoji.demojize(channel.name))) except mysql.connector.errors.IntegrityError: cursor.execute( update_channel, (emoji.demojize(channel.name), channel.id)) logger.debug("Updated {}".format( emoji.demojize(channel.name))) logger.info("{}: Updating users".format(str(guild))) for member in tqdm(guild.members, total=len(guild.members), desc="Adding users for {}".format( str(guild))): self.database_tools.add_user(member) logger.info("{}: Finished {} users".format( str(guild), len(guild.members))) logger.info("{}: Updating roles".format(str(guild))) for role in guild.roles: if role.name != "@everyone": try: cursor.execute(insert_role, (role.id, emoji.demojize(role.name), guild.id, int(role.mentionable))) except mysql.connector.errors.IntegrityError: cursor.execute(update_role, (emoji.demojize( role.name), int(role.mentionable), role.id)) # this is designed to assist with migration, by moving old discord role members over to the new # system seamlessly member_ids = [] for member in role.members: member_ids.append(member.id) role_db = DbRole(role.id, role.name, 0, members=member_ids) role_db.save_members() logger.info("{}: Finished {} roles".format( guild, len(guild.roles))) cnx.commit() else: logger.warn( "Skipping scraping data from existing servers - data may be out of date" )
async def experiments(self, ctx): """ Opt into data analysis and experiments. """ message = ctx.message channel = message.channel author = message.author create_user = "******" try: cursor.execute(create_user, (author.id, author.name)) cnx.commit() em = discord.Embed( title=strings['data_collection']['opt_in_title'], description=opt_in_message) em.set_footer(text=strings['data_collection']['opt_in_footer']) return await channel.send(embed=em) except mysql.connector.errors.IntegrityError: get_user = "******" cursor.execute(get_user, (author.id,)) opt_in_user = "******" cursor.execute(opt_in_user, (author.id,)) await channel.send(strings['data_collection']['data_track_start'] + " for " + str(ctx.message.author)) await self.client_tools.build_data_profile([author]) await channel.send(strings['data_collection']['complete'].format(author.name))
async def pingable(self, ctx, *, role_name): """Change a role from not pingable to pingable or vice versa""" if role_name[0] == '"' and role_name[-1] == '"': role_name = role_name[1:-1] role = get_role(ctx.guild.id, role_name) if role is None: return await ctx.channel.send( embed=discord.Embed(title='Error', description='Could not find that role', color=red)) if role['is_pingable'] == 1: update_query = "UPDATE `gssp`.`roles` SET `is_pingable`='0' WHERE `role_id`=%s AND `guild_id` = %s;" text = "not pingable" else: update_query = "UPDATE `gssp`.`roles` SET `is_pingable`='1' WHERE `role_id`=%s AND `guild_id` = %s;" text = "pingable" cursor.execute(update_query, ( role['role_id'], ctx.guild.id, )) cnx.commit() await ctx.channel.send( embed=discord.Embed(title="SUCCESS", description="Set {} ({}) to {}".format( role['role_name'], role['role_id'], text), color=green))
async def rename(self, ctx, role_name=None, new_name=None): """ Changes the name of a role Params: role_name : name of the role to be changed new_name : name the role should be """ # Removes excess spaces at the beginning of a role name if role_name[0] == '"' and role_name[-1] == '"': role_name = role_name[1:-1] role_check = get_role(ctx.guild.id, role_name) em = discord.Embed(title='Success', description="Renamed {} to {}".format( role_name, new_name), color=green) if role_check is None: em = discord.Embed( title="Error", description="{} is not in the DB".format(role_name), color=red) else: query = "UPDATE `gssp`.`roles` SET `role_name` = %s WHERE (`role_name` = %s AND `guild_id` = %s);" cursor.execute(query, (new_name, role_name, ctx.guild.id)) cnx.commit() return await ctx.channel.send(embed=em)
async def joinable(self, ctx, *, role_name): """ Toggles whether a role is joinable """ if role_name[0] == '"' and role_name[-1] == '"': role_name = role_name[1:-1] role = get_role(ctx.guild.id, role_name) if role is None: em = discord.Embed( title="Error", description="Could not find role {}".format(role_name), color=red) return await ctx.channel.send(embed=em) if role['is_joinable'] == 1: update_query = "UPDATE `gssp`.`roles` SET `is_joinable`='0' WHERE `role_id`=%s;" text = "not joinable" else: update_query = "UPDATE `gssp`.`roles` SET `is_joinable`='1' WHERE `role_id`=%s;" text = "joinable" cursor.execute(update_query, (role['role_id'], )) em = discord.Embed(title="Success", description="Set {} ({} to {}".format( role['role_name'], role['role_id'], text), color=green) cnx.commit() await ctx.channel.send(embed=em)
def add_message_to_db(self, message): from ags_experiments.client_tools import ClientTools self.client_tools = ClientTools(self.client) try: is_allowed = self.client_tools.channel_allowed( message.channel.id, message.channel, message.channel.is_nsfw()) except AttributeError: is_allowed = False # in PMs, and other channels, NSFW isn't an option if is_allowed: try: while True: result = cursor.fetchone() if result is not None: logger.debug(result + " - < Unread result") else: break cursor.execute(add_message_custom, ( int(message.id), message.author.id, str( message.channel.id), message.created_at.strftime('%Y-%m-%d %H:%M:%S'), message.content,)) except mysql.connector.errors.IntegrityError: pass except mysql.connector.errors.DataError: logger.warn( "Couldn't insert {} - likely a time issue".format(message.id)) cnx.commit()
def get_roles(guild_id, limit_to_joinable=True): cnx.commit() if limit_to_joinable: query = "SELECT * FROM `gssp`.`roles` WHERE `guild_id` = %s AND `is_joinable` = 1" else: query = "SELECT * FROM `gssp`.`roles` WHERE `guild_id` = %s" query = "{query} ORDER BY role_name".format(query=query) cursor.execute(query, (guild_id, )) return cursor.fetchall()
async def optout_user(self, user): """ Opt a user out of experiments, and delete their data Returns number of messages deleted """ logger.info("Deleting data for user ID {}".format(user.id)) cursor.execute("DELETE FROM users WHERE user_id = %s", (user.id, )) result = cursor.execute( "DELETE FROM messages_detailed WHERE user_id = %s", (user.id, )) cnx.commit() logger.info("Data deleted.")
def add_user(self, member): try: cursor.execute(insert_users, (member.id,)) cnx.commit() except mysql.connector.errors.IntegrityError: pass # we pass because we just want to make sure we add any new users, so we expect some already here try: cursor.execute(insert_settings, (member.id,)) cnx.commit() except mysql.connector.errors.IntegrityError: pass # see above
def get_role(guild_id, role_name): cnx.commit() query = "SELECT * FROM `gssp`.`roles` WHERE `role_name` = %s AND `guild_id` = %s" cursor.execute(query, (role_name, guild_id)) members = [] try: a = cursor.fetchall()[0] members += json.loads(a['role_assignees']) except IndexError: return None a['members'] = members return a
async def output_toggle_public_ping(self, ctx): user_settings = get_user(ctx.author.id) if user_settings['ping_public'] == 1: query = "UPDATE `gssp`.`ping_settings` SET `ping_public`='0' WHERE `user_id`='%s';" return_msg = "You will now be pinged over DM" else: query = "UPDATE `gssp`.`ping_settings` SET `ping_public`='1' WHERE `user_id`='%s';" return_msg = "You will now be pinged publicly" cursor.execute(query, (ctx.author.id, )) cnx.commit() await ctx.channel.send(embed=discord.Embed( title="Success", description=return_msg, color=green))
async def delete(self, ctx, *, role_name): """Deletes a role - cannot be undone!""" if role_name[0]=='"' and role_name[-1] == '"': role_name=role_name[1:-1] role_check = get_role(ctx.guild.id, role_name) em = discord.Embed( title="Success", description="Deleted role {}".format(role_name), color=green) if role_check is None: em = discord.Embed( title="Error", description="{} is not in the DB".format(role_name), color=red) else: query = "DELETE FROM `gssp`.`roles` WHERE `role_name` = %s AND `guild_id` = %s" cursor.execute(query, (role_name, ctx.guild.id)) cnx.commit() return await ctx.channel.send(embed=em)
async def add(self, ctx, *, role_name): """Add a role. Note: by default, it isn't joinable""" if role_name[0]=='"' and role_name[-1] == '"': role_name=role_name[1:-1] role_check = get_role(ctx.guild.id, role_name) em = discord.Embed( title="Success", description="Created role {}".format(role_name), color=green) if role_check is not None: em = discord.Embed( title="Error", description="Role is already in the DB", color=red) else: query = "INSERT INTO `gssp`.`roles` (`role_name`, `guild_id`) VALUES (%s, %s);" cursor.execute(query, (role_name, ctx.guild.id)) cnx.commit() return await ctx.channel.send(embed=em)
def is_automated(self, user): """ Returns true if user is opted in to automation, false if not """ cnx.commit() get_user = "******" cursor.execute(get_user, (user.id,)) results = cursor.fetchall() cnx.commit() try: if results[0][0] != 1: return False except IndexError: return False return True
async def save_markov(self, model, user_id): """ Save a model to markov table user_id : user's ID we want to save for model: Markov model object """ save = "INSERT INTO `markovs` (`user`, `markov_json`) VALUES (%s, %s);" save_update = "UPDATE `markovs` SET `markov_json`=%s WHERE `user`=%s;" try: cursor.execute(save, (user_id, model.to_json())) except mysql.connector.errors.IntegrityError: cursor.execute(save_update, (model.to_json(), user_id)) cnx.commit() return
async def main(): global opted_in_users global position error_count = 0 while True: try: for x in range(position, len(opted_in_users)): server, channel = await get_channel() position = x user = opted_in_users[x] messages, channels = await database_tools.get_messages(user.id, config['limit']) cnx.commit() text_full = "" for x in range(0, len(messages)): channel_temp = client.get_channel(int(channels[x])) if channel_temp is not None: if not channel_temp.is_nsfw(): text_full = text_full + messages[x] + "\n" try: text_model = markovify.NewlineText( text_full, state_size=config['state_size']) em = discord.Embed( title=user.display_name, description=text_model.make_short_sentence(140)) em.set_thumbnail(url=user.avatar_url) name = await client_tools.get_delete_emoji() name = name[0] em.set_footer( text=strings['markov']['output']['footer'].format(name)) output = await channel.send(embed=em) time.sleep(1) async for message in channel.history(limit=1, reverse=True): message = message break await delete_option(client, message, channel, client.get_emoji(int(strings['emojis']['delete'])) or "❌") except KeyError: pass opted_in_users = await get_members(server) error_count = 0 position = 0 # this means that, we don't continue from the *end* except Exception as e: error_count += 1 print(e) if error_count > 3: sys.exit(1)
async def automated(self, ctx): """ Opt in to automated messages. Run this again to opt out. """ if not self.database_tools.opted_in(user_id=ctx.author.id): return await ctx.channel.send(embed=discord.Embed(title="Error", description=strings['tagger']['errors']['not_opted_in'], color=colours.red)) if self.database_tools.is_automated(ctx.author): output = await ctx.channel.send("Opting you out of automation.") query = "UPDATE `users` SET `automate_opted_in`=b'0' WHERE `user_id`=%s;" cursor.execute(query, (ctx.author.id,)) cnx.commit() await output.delete() return await ctx.channel.send(embed=discord.Embed(title="Success", description='You will be removed from the pool on the next refresh (IE: when the bot goes back around in a loop again)')) else: output = await ctx.channel.send("Opting you into automation") query = "UPDATE`users` SET `automate_opted_in`=b'1' WHERE `user_id`=%s;" cursor.execute(query, (ctx.author.id,)) cnx.commit() await output.delete() return await ctx.channel.send(embed=discord.Embed(title="Success", description='Opted in!', color=colours.green))
async def process_message(self, message): await self.check_flags(message) user_exp = self.database_tools.opted_in(user_id=message.author.id) if user_exp is not False: self.database_tools.add_message_to_db(message) logger.debug("Message from {}".format(user_exp)) # this records analytical data - don't adjust this without reading # Discord TOS first try: cursor.execute(add_message, (int(message.id), str(message.channel.id), message.created_at.strftime('%Y-%m-%d %H:%M:%S'))) cnx.commit() except mysql.connector.errors.IntegrityError: pass try: # if its double(or more) prefixed then it cant be a command (?word is a command, ????? is not) if message.content[len(config['discord'] ['prefix'])] == config['discord']['prefix']: return except IndexError: return
def get_user(user_id): cnx.commit() # we run this just to make sure we have nothing pending query = "SELECT * FROM gssp.ping_settings WHERE user_id = %s" cursor.execute(query, (user_id, )) return cursor.fetchone()
def save_members(self): members_j = json.dumps(self.members) cursor_dict.execute(update_query, (members_j, self.role_id)) cnx.commit()