async def followslist(self, ctx, channel: discord.TextChannel = None): """List all followed accounts on server or channel""" data = await self.bot.db.execute( """ SELECT twitter_user.username, channel_id, added_on FROM follow LEFT JOIN twitter_user ON twitter_user.user_id = follow.twitter_user_id WHERE follow.guild_id = %s """ + (f" AND channel_id = {channel.id}" if channel is not None else "") + " ORDER BY channel_id, added_on DESC", ctx.guild.id, ) content = discord.Embed(title="Followed twitter users", color=self.bot.twitter_blue) rows = [] for username, channel_id, added_on in data: rows.append( (f"<#{channel_id}> < " if channel is None else "") + f"**@{username}** (since {added_on} UTC)" ) if not rows: rows.append("Nothing yet :(") pages = menus.Menu(source=menus.ListMenu(rows, embed=content), clear_reactions_after=True) await pages.start(ctx)
async def guilds(self, ctx: commands.Context): """Show all connected guilds.""" content = discord.Embed( title=f"Active in {len(self.bot.guilds)} guilds", color=self.bot.twitter_blue, ) rows = [] for i, guild in enumerate(sorted(self.bot.guilds, key=lambda x: x.member_count, reverse=True), start=1): rows.append( f"`#{i:2}`[`{guild.id}`] **{guild.member_count}** members : **{guild.name}**" ) pages = menus.Menu(source=menus.ListMenu(rows, embed=content), clear_reactions_after=True) await pages.start(ctx)
async def remove(self, ctx, channel: discord.TextChannel, *usernames): """Remove users from the follow list.""" if not usernames: raise exceptions.Info("You must give at least one twitter user to remove!") rows = [] current_users = await self.bot.db.execute( "SELECT twitter_user_id FROM follow WHERE channel_id = %s", channel.id ) successes = 0 for username in usernames: status = None try: user_id = (await self.api.get_user(username=username)).data.id except Exception as e: # user not found, maybe changed username # try finding username from cache user_id = await self.bot.db.execute( "SELECT user_id FROM twitter_user WHERE username = %s", username ) if user_id: user_id = user_id[0][0] else: status = f":x: Error {e.args[0][0]['code']}: {e.args[0][0]['message']}" if status is None: if (user_id,) not in current_users: status = ":x: User is not being followed on this channel" else: await self.unfollow(channel.id, user_id) status = ":white_check_mark: Success" successes += 1 rows.append(f"**@{username}** {status}") content = discord.Embed( title=f":notepad_spiral: Removed {successes}/{len(usernames)} users from {channel.name}", color=self.bot.twitter_blue, ) content.set_footer(text="Changes will take effect within a minute") pages = menus.Menu(source=menus.ListMenu(rows, embed=content), clear_reactions_after=True) await pages.start(ctx)
async def add(self, ctx, channel: discord.TextChannel, *usernames): """Add users to the follow list.""" if not usernames: raise exceptions.Info("You must give at least one twitter user to follow!") rows = [] time_now = arrow.now().datetime current_users = await self.bot.db.execute( "SELECT twitter_user_id FROM follow WHERE channel_id = %s", channel.id ) guild_follow_current, guild_follow_limit = await queries.get_follow_limit( self.bot.db, channel.guild.id ) successes = 0 for username in usernames: status = None try: user = (await self.api.get_user(username=username)).data except Exception as e: status = f":x: Error {e}" else: if (user.id,) in current_users: status = ":x: User already being followed on this channel" else: if guild_follow_current >= guild_follow_limit: status = f":lock: Guild follow count limit reached ({guild_follow_limit})" else: await self.follow(channel, user.id, user.username, time_now) status = ":white_check_mark: Success" successes += 1 guild_follow_current += 1 rows.append(f"**@{user.username}** {status}") content = discord.Embed( title=f":notepad_spiral: Added {successes}/{len(usernames)} users to {channel.name}", color=self.bot.twitter_blue, ) content.set_footer(text="Changes will take effect within a minute") pages = menus.Menu(source=menus.ListMenu(rows, embed=content), clear_reactions_after=True) await pages.start(ctx)
async def purge(self, ctx: commands.Context): """Remove all follows from unavailable guilds and channels.""" data = await self.bot.db.execute( """ SELECT channel_id, guild_id, twitter_user_id, username FROM follow JOIN twitter_user ON twitter_user_id=user_id """ ) actions = [] guilds_to_delete = [] channels_to_delete = [] users_to_delete = [] twitter_usernames = {} usernames_to_change = [] for channel_id, guild_id, twitter_uid, username in data: if self.bot.get_guild(guild_id) is None: actions.append(f"Could not find guild with id: [{guild_id}]") guilds_to_delete.append(guild_id) elif self.bot.get_channel(channel_id) is None: actions.append(f"Could not find channel with id: [{channel_id}]") channels_to_delete.append(channel_id) else: twitter_usernames[twitter_uid] = username uids = list(twitter_usernames.keys()) for uids_chunk in [uids[i : i + 100] for i in range(0, len(uids), 100)]: userdata = await self.api.get_users(ids=uids_chunk) if userdata.errors: for error in userdata.errors: actions.append(error["detail"]) users_to_delete.append(int(error["value"])) if userdata.data: for user in userdata.data: if twitter_usernames[user.id] != user.username: actions.append( f"User has changed username from @{twitter_usernames[user.id]} to @{user.username}" ) usernames_to_change.append((user.id, user.username)) if not actions: return await ctx.send("There is nothing to do.") content = discord.Embed( title="Purge results", color=self.bot.twitter_blue, ) pages = menus.Menu( source=menus.ListMenu(actions, embed=content), clear_reactions_after=True, ) await pages.start(ctx) confirm = await menus.Confirm("Run actions?").prompt(ctx) if confirm: await ctx.send("Running purge...") if guilds_to_delete: await self.bot.db.execute( "DELETE FROM follow WHERE guild_id IN %s", guilds_to_delete ) if channels_to_delete: await self.bot.db.execute( "DELETE FROM follow WHERE channel_id IN %s", channels_to_delete ) if users_to_delete: await self.bot.db.execute( "DELETE FROM twitter_user WHERE user_id IN %s", users_to_delete ) for uid, new_name in usernames_to_change: await self.bot.db.execute( "UPDATE twitter_user SET username = %s WHERE user_id = %s", new_name, uid ) await ctx.send("Purge complete!")