async def removetagalias(self, ctx, *, alias: OwnedTag): """Remove an alias from a tag""" flow = Flow(self.bot, ctx) if alias.invoked_with == alias.name: return await ctx.send( f":x: That is not an alias, but the tag's name. " f"Try {config.BOT_PREFIX}tag delete {alias.invoked_with} instead!" ) are_you_sure = await ctx.send( f":information_source: Are you sure that you want to remove the alias " f"`{config.BOT_PREFIX}{alias.invoked_with}` " f"from `{config.BOT_PREFIX}{alias.name}`?") reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200) if reaction is None: return if not reaction: return await ctx.send("Aborted.") elif reaction: async with self.bot.db.acquire() as con: async with con.transaction(): await con.execute( "DELETE FROM guild_tags_alias WHERE alias = $1 AND tag_id = $2", alias.invoked_with, alias.id) await ctx.send( f":white_check_mark: Successfully removed the alias " f"`{config.BOT_PREFIX}{alias.invoked_with}` from " f"`{config.BOT_PREFIX}{alias.name}`.")
async def removetag(self, ctx, *, tag: OwnedTag): """Remove a tag""" flow = Flow(self.bot, ctx) are_you_sure = await ctx.send( f":information_source: Are you sure that you want to remove the tag " f"`{config.BOT_PREFIX}{tag.name}`?") reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200) if reaction is None: return if not reaction: return await ctx.send("Aborted.") elif reaction: async with self.bot.db.acquire() as con: async with con.transaction(): await con.execute( "DELETE FROM guild_tags_alias WHERE tag_id = $1", tag.id) await con.execute( "DELETE FROM guild_tags WHERE name = $1 AND guild_id = $2", tag.name, ctx.guild.id) await ctx.send( f":white_check_mark: `{config.BOT_PREFIX}{tag.name}` was removed." )
async def addrole(self, ctx): """Add a role to this server's `-roles` list""" await ctx.send(":information_source: Reply with the name of the role you want to create.") flow = Flow(self.bot, ctx) role_name = await flow.get_new_role(240) if isinstance(role_name, str): await ctx.send( f":white_check_mark: I will **create a new role** on this server named `{role_name}` for this.") try: discord_role = await ctx.guild.create_role(name=role_name) except discord.Forbidden: raise exceptions.ForbiddenError(exceptions.ForbiddenTask.CREATE_ROLE, role_name) else: discord_role = role_name await ctx.send( f":white_check_mark: I'll use the **pre-existing role** named `{discord_role.name}` for this.") await ctx.send(":information_source: Reply with a short message the user should see when they get the role.") role_join_message = await flow.get_text_input(300) if not role_join_message: return await self.bot.db.execute("INSERT INTO roles (guild_id, role_id, join_message) VALUES ($1, $2, $3) " "ON CONFLICT (guild_id, role_id) DO UPDATE set join_message = $3", ctx.guild.id, discord_role.id, role_join_message) await ctx.send(f':white_check_mark: `{discord_role.name}` was added as a selfrole or its join message was ' f'updated in case the selfrole already existed.')
async def edittag(self, ctx, *, tag: OwnedTag): """Edit one of your tags""" flow = Flow(self.bot, ctx) embed_q = await ctx.send( ":information_source: Should the tag be sent as an embed?") embed_bool = await flow.get_yes_no_reaction_confirm(embed_q, 300) if embed_bool is None: return if embed_bool: is_embedded = True else: is_embedded = False await ctx.send( ":information_source: Reply with the updated **title** of this tag." ) new_title = await flow.get_text_input(300) if new_title is None: return if len(new_title) > 256: return await ctx.send( ":x: The title cannot be longer than 256 characters.") await ctx.send( ":information_source: Reply with the updated **content** of this tag." ) new_content = await flow.get_tag_content(300) if new_content is None: return if len(new_content) > 2048: return await ctx.send( ":x: The content cannot be longer than 2048 characters.") are_you_sure = await ctx.send( f":information_source: Are you sure that you want to edit your " f"`{config.BOT_PREFIX}{tag.name}` tag?") reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200) if reaction is None: return if not reaction: return await ctx.send("Aborted.") else: await self.bot.db.execute( "UPDATE guild_tags SET content = $1, title = $3, is_embedded = $4 WHERE id = $2", new_content, tag.id, new_title, is_embedded) await ctx.send(":white_check_mark: Your tag was edited.")
async def tagcreation(self, ctx): """Allow everyone to make tags on this server, or just Administrators""" is_allowed = await self.bot.checks.is_tag_creation_allowed(ctx.guild.id ) pretty_is_allowed = "Only Administrators" if not is_allowed else "Everyone" embed = self.bot.embeds.embed_builder( title=f":pencil: Tag Creation on {ctx.guild.name}", description=f"React with the {config.GUILD_SETTINGS_GEAR} emoji" f" to change this setting.", has_footer=False) embed.add_field(name="Allowed Tag Creators", value=pretty_is_allowed) info_embed = await ctx.send(embed=embed) flow = Flow(self.bot, ctx) if await flow.gear_reaction_confirm(info_embed, 300): everyone = "\U0001f468\U0000200d\U0001f468\U0000200d\U0001f467\U0000200d\U0001f467" only_admins = "\U0001f46e" status_question = await ctx.send( f":information_source: Who should be able to create new tags " f"on this server with `-tag add`, " f"**everyone** or **just the Administrators** of this server?\n\n" f"React with {everyone} for everyone, or with {only_admins} for just " f"Administrators.") reaction, user = await flow.get_emoji_choice( everyone, only_admins, status_question, 240) if reaction is None: return if str(reaction) == everyone: await self.bot.db.execute( "UPDATE guilds SET tag_creation_allowed = true WHERE id = $1", ctx.guild.id) await ctx.send( ":white_check_mark: Everyone can now make tags with `-tag add` on this server." ) elif str(reaction) == only_admins: await self.bot.db.execute( "UPDATE guilds SET tag_creation_allowed = false WHERE id = $1", ctx.guild.id) await ctx.send( ":white_check_mark: Only Administrators can now make" " tags with `tag -add` on this server.") await self.bot.cache.update_guild_config_cache()
async def veto(self, ctx, bill_ids: Greedy[Bill]): """Veto one or multiple bills **Example:** `-ministry veto 12` will veto Bill #12 `-ministry veto 45 46 49 51 52` will veto all those bills""" if not bill_ids: return await ctx.send_help(ctx.command) bills = bill_ids flow = Flow(self.bot, ctx) error_messages = [] for _bill in bills: error = await self.verify_bill(_bill) if error: error_messages.append((_bill, error)) if error_messages: # Remove bills that did not pass verify_bill from bills list bills[:] = [b for b in bills if b not in list(map(list, zip(*error_messages)))[0]] error_messages = '\n'.join( [f"- **{_bill.name}** (#{_bill.id}): _{reason}_" for _bill, reason in error_messages]) await ctx.send(f":warning: The following bills can not be vetoed.\n{error_messages}") # If all bills failed verify_bills, return if not bills: return pretty_bills = '\n'.join([f"- **{_bill.name}** (#{_bill.id})" for _bill in bills]) are_you_sure = await ctx.send(f":information_source: Are you sure that you want to veto the following bills?" f"\n{pretty_bills}") reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200) if reaction is None: return if not reaction: return await ctx.send("Aborted.") elif reaction: async with ctx.typing(): for _bill in bills: await _bill.veto() self.veto_scheduler.add(_bill) await ctx.send(":white_check_mark: All bills were vetoed.")
async def pass_bill(self, ctx, bill_ids: Greedy[Bill]): """Pass one or multiple bills into law **Example:** `-ministry pass 12` will pass Bill #12 into law `-ministry pass 45 46 49 51 52` will pass all those bills into law""" bills = bill_ids flow = Flow(self.bot, ctx) error_messages = [] for bill in bills: error = await self.verify_bill(bill) if error: error_messages.append((bill, error)) if error_messages: # Remove bills that did not pass verify_bill from bills list bills = [b for b in bills if b not in list(map(list, zip(*error_messages)))[0]] error_messages = '\n'.join( [f"- **{_bill.name}** (#{_bill.id}): _{reason}_" for _bill, reason in error_messages]) await ctx.send(f":warning: The following bills can not be passed into law.\n{error_messages}") # If all bills failed verify_bills, return if not bills: return pretty_bills = '\n'.join([f"- **{_bill.name}** (#{_bill.id})" for _bill in bills]) are_you_sure = await ctx.send(f":information_source: Are you sure that you want " f"to pass the following bills into law?" f"\n{pretty_bills}") reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200) if reaction is None: return if not reaction: return await ctx.send("Aborted.") elif reaction: async with ctx.typing(): for bill in bills: await bill.pass_into_law() self.pass_scheduler.add(bill) await ctx.send(":white_check_mark: All bills were passed into law.")
async def addtagalias(self, ctx, *, tag: OwnedTag): """Add a new alias to a tag""" flow = Flow(self.bot, ctx) await ctx.send( f":information_source: Reply with the new alias for `{config.BOT_PREFIX}{tag.name}`." ) alias = await flow.get_text_input(240) if not alias: return if not await self.validate_tag_name(ctx, alias.lower()): return are_you_sure = await ctx.send( f":information_source: Are you sure that you want to add the " f"`{config.BOT_PREFIX}{alias}` alias to `{config.BOT_PREFIX}{tag.name}`?" ) reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200) if reaction is None: return if not reaction: return await ctx.send("Aborted.") elif reaction: async with self.bot.db.acquire() as con: async with con.transaction(): status = await con.execute( "INSERT INTO guild_tags_alias (alias, tag_id, guild_id, global)" " VALUES ($1, $2, $3, $4)", alias.lower(), tag.id, ctx.guild.id, tag.is_global) if status == "INSERT 0 1": await ctx.send( f':white_check_mark: The `{config.BOT_PREFIX}{alias}` alias was added to ' f'`{config.BOT_PREFIX}{tag.name}`.')
async def updatelink(self, ctx, law_id: Law, new_link: str): """Update the link to a law Useful for applying amendments to laws if the current Speaker does not own the law's Google Doc. **Example**: `-law updatelink 16 https://docs.google.com/1/d/ajgh3egfdjfnjdf` """ if not self.bot.laws.is_google_doc_link(new_link): return await ctx.send( f":x: This does not look like a Google Docs link: `{new_link}`" ) law = law_id # At this point, law_id is already a Law object, so calling it law_id makes no sense are_you_sure = await ctx.send( f":information_source: Are you sure that you want to change the link to " f"`{law.bill.name}` (#{law.id})?") flow = Flow(self.bot, ctx) reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200) if reaction is None: return if not reaction: return await ctx.send("Aborted.") elif reaction: try: await law.amend(new_link) except DemocracivBotException as e: return await ctx.send(e.message) law = await Law.convert(ctx, law.id) self.amend_scheduler.add(law) await ctx.send( f":white_check_mark: The link to `{law.bill.name}` was changed." )
async def addalias(self, ctx, *, party: PoliticalParty): """Add a new alias to a political party""" flow = Flow(self.bot, ctx) await ctx.send( f":information_source: Reply with the new alias for `{party.role.name}`." ) alias = await flow.get_text_input(240) if not alias: return async with self.bot.db.acquire() as connection: async with connection.transaction(): status = await connection.execute( "INSERT INTO party_alias (alias, party_id) VALUES ($1, $2)", alias.lower(), party.role.id) if status == "INSERT 0 1": await ctx.send(f':white_check_mark: Alias `{alias}` for party ' f'`{party.role.name}` was added.')
async def removelaw(self, ctx, law_ids: Greedy[Law]): """Repeal one or multiple laws **Example:** `-law repeal 24` will repeal law #24 `-law repeal 56 57 58 12 13` will repeal all those laws""" if not law_ids: return await ctx.send_help(ctx.command) laws = law_ids # At this point, law_id is already a Law object, so calling it law_id makes no sense pretty_laws = '\n'.join( [f"- **{_law.bill.name}** (#{_law.id})" for _law in laws]) are_you_sure = await ctx.send( f":information_source: Are you sure that you want repeal the following laws?" f"\n{pretty_laws}") flow = Flow(self.bot, ctx) reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200) if reaction is None: return if not reaction: return await ctx.send("Aborted.") elif reaction: for law in laws: await law.repeal() self.repeal_scheduler.add(law) return await ctx.send(f":white_check_mark: All laws were repealed." )
async def addtag(self, ctx): """Add a tag for this server""" flow = Flow(self.bot, ctx) await ctx.send( ":information_source: Reply with the **name** of the tag. This will be used to access the" " tag via the bot's prefix.") name = await flow.get_text_input(300) if name is None: return if not await self.validate_tag_name(ctx, name.lower()): return embed_q = await ctx.send( ":information_source: Should the tag be sent as an embed?") embed_bool = await flow.get_yes_no_reaction_confirm(embed_q, 300) if embed_bool is None: return if embed_bool: is_embedded = True else: is_embedded = False await ctx.send( ":information_source: Reply with the **title** of the tag.") title = await flow.get_text_input(300) if title is None: return if len(title) > 256: return await ctx.send( ":x: The title cannot be longer than 256 characters.") await ctx.send( ":information_source: Reply with the **content** of the tag.") content = await flow.get_tag_content(300) if content is None: return if len(content) > 2048: return await ctx.send( ":x: The content cannot be longer than 2048 characters.") is_global = False if ctx.author.guild_permissions.administrator and ctx.guild.id == self.bot.democraciv_guild_object.id: is_global_msg = await ctx.send( ":information_source: Should this tag be global?") reaction = await flow.get_yes_no_reaction_confirm( is_global_msg, 300) if reaction is None: return if reaction: is_global = True elif not reaction: is_global = False are_you_sure = await ctx.send( f":information_source: Are you sure that you want to add the tag " f"`{config.BOT_PREFIX}{name}`?") reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200) if reaction is None: return if not reaction: return await ctx.send("Aborted.") elif reaction: async with self.bot.db.acquire() as con: async with con.transaction(): _id = await con.fetchval( "INSERT INTO guild_tags (guild_id, name, content, title," " global, author, is_embedded) VALUES " "($1, $2, $3, $4, $5, $6, $7) RETURNING id", ctx.guild.id, name.lower(), content, title, is_global, ctx.author.id, is_embedded) await con.execute( "INSERT INTO guild_tags_alias (tag_id, alias, guild_id, global)" " VALUES ($1, $2, $3, $4)", _id, name.lower(), ctx.guild.id, is_global) await ctx.send( f":white_check_mark: The `{config.BOT_PREFIX}{name}` tag was added." )
async def exportlaws(self, ctx): """Generate a Legal Code as a Google Docs document from the list of active laws""" flow = Flow(self.bot, ctx) query = """SELECT legislature_laws.law_id, legislature_bills.bill_name, legislature_bills.link FROM legislature_laws JOIN legislature_bills ON legislature_laws.bill_id = legislature_bills.id ORDER BY legislature_laws.law_id; """ await ctx.send( ":information_source: Reply with an **edit** link to a Google Docs " "document you created. I will then fill that document to make it an up-to-date Legal Code.\n" ":warning: Note that I will replace the entire content of your Google Docs document if it " "isn't empty.") doc_url = await flow.get_private_text_input(120) if not doc_url: ctx.command.reset_cooldown(ctx) return if not self.bot.laws.is_google_doc_link(doc_url): ctx.command.reset_cooldown(ctx) return await ctx.send( ":x: That doesn't look like a Google Docs URL.") await ctx.send( f":white_check_mark: I will generate an up-to-date Legal Code." f"\n:arrows_counterclockwise: This may take a few minutes...") async with ctx.typing(): all_laws = await self.bot.db.fetch(query) ugly_laws = [] for record in all_laws: ugly_laws.append({ 'id': record['law_id'], 'name': record['bill_name'], 'link': record['link'] }) date = datetime.datetime.utcnow().strftime("%B %d, %Y at %H:%M") result = await self.bot.google_api.run_apps_script( script_id="MMV-pGVACMhaf_DjTn8jfEGqnXKElby-M", function="generate_legal_code", parameters=[ doc_url, { 'name': self.bot.mk.NATION_FULL_NAME, 'date': date }, ugly_laws ]) if result is None or not result['done']: ctx.command.reset_cooldown(ctx) return await ctx.send( ":x: There was an error while generating the document. Are you sure that you " "gave me an edit link?") if 'error' in result: ctx.command.reset_cooldown(ctx) error_msg = ("Exception: No item with the given ID could be found," " or you do not have permission to access it.", "Action not allowed") if result['error']['details'][0]['errorMessage'] in error_msg: return await ctx.send( ":x: I cannot access that Google Docs document. Are you sure that you " "gave me an edit link?") else: return await ctx.send( ":x: There was an error while generating the document. Are you sure that you " "gave me an edit link?") embed = self.bot.embeds.embed_builder( title=f"Generated Legal Code", description="This Legal Code is not guaranteed to be correct. Its " f"content is based entirely on the list of Laws " f"in `{config.BOT_PREFIX}laws`." "\n\nRemember to change the edit link you " "gave me earlier to not be public.") embed.add_field(name="Link to the Legal Code", value=result['response']['result']['view'], inline=False) await ctx.send(embed=embed)
async def welcome(self, ctx): """Add a welcome message that every new member will see once they join this server""" is_welcome_enabled = await self.bot.checks.is_welcome_message_enabled( ctx.guild.id) current_welcome_channel = await utils.get_welcome_channel( self.bot, ctx.guild) current_welcome_message = await self.bot.db.fetchval( "SELECT welcome_message FROM guilds WHERE id = $1", ctx.guild.id) if current_welcome_channel is None: current_welcome_channel = "-" else: current_welcome_channel = current_welcome_channel.mention if not current_welcome_message: current_welcome_message = "-" elif len(current_welcome_message) > 1024: current_welcome_message = "*The welcome message is too long to fit in here.*" embed = self.bot.embeds.embed_builder( title=f":wave: Welcome Messages on {ctx.guild.name}", description= f"React with the {config.GUILD_SETTINGS_GEAR} emoji to change" f" these settings.", has_footer=False) embed.add_field(name="Enabled", value=self.emojiy_settings(is_welcome_enabled)) embed.add_field(name="Welcome Channel", value=current_welcome_channel) embed.add_field(name="Welcome Message", value=current_welcome_message, inline=False) info_embed = await ctx.send(embed=embed) flow = Flow(self.bot, ctx) if await flow.gear_reaction_confirm(info_embed, 300): status_question = await ctx.send( "React with :white_check_mark: to enable welcome messages," " or with :x: to disable welcome messages.") reaction = await flow.get_yes_no_reaction_confirm( status_question, 240) if reaction is None: return if reaction: await self.bot.db.execute( "UPDATE guilds SET welcome = true WHERE id = $1", ctx.guild.id) await ctx.send(":white_check_mark: Enabled welcome messages.") # Get new welcome channel await ctx.send( ":information_source: Reply with the name of the welcome channel." ) channel_object = await flow.get_new_channel(240) if isinstance(channel_object, str): raise exceptions.ChannelNotFoundError(channel_object) status = await self.bot.db.execute( "UPDATE guilds SET welcome_channel = $2 WHERE id = $1", ctx.guild.id, channel_object.id) if status == "UPDATE 1": await ctx.send( f":white_check_mark: Set the welcome channel to {channel_object.mention}." ) # Get new welcome message await ctx.send( f":information_source: Reply with the message that should be sent to {channel_object.mention} " f"every time a new member joins.\n\nWrite `{{member}}` " f"to make the Bot mention the user.") welcome_message = await flow.get_text_input(300) if welcome_message: status = await self.bot.db.execute( "UPDATE guilds SET welcome_message = $2 WHERE id = $1", ctx.guild.id, welcome_message) if status == "UPDATE 1": await ctx.send( f":white_check_mark: Welcome message was set.") elif not reaction: await self.bot.db.execute( "UPDATE guilds SET welcome = false WHERE id = $1", ctx.guild.id) await ctx.send( ":white_check_mark: Welcome messages were disabled.") await self.bot.cache.update_guild_config_cache()
async def report(self, ctx): """Report something to the Democraciv Moderation This command only works in DMs with me.""" flow = Flow(self.bot, ctx) anon_question = await ctx.send( "You can report something directly to the mods with this command. Abuse " "(i.e. spamming joke reports) will be punished.\n\n\n:information_source: " "Do you want this report to be anonymous?") is_anon = True reaction = await flow.get_yes_no_reaction_confirm(anon_question, 150) if reaction is None: return if reaction: is_anon = True elif not reaction: is_anon = False await ctx.send( ":information_source: Reply with the details of your report. This will abort after" " 10 minutes of no reply.") content = await flow.get_text_input(600) if not content: return if len(content) > 2048: return await ctx.send( ":x: Text cannot be more than 2048 characters.") pretty_anon = "be anonymous" if is_anon else "not be anonymous" are_you_sure = await ctx.send( f":information_source: Are you sure that you want to send this report? " f"The report will **{pretty_anon}**.") reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 150) if reaction is None: return if reaction: embed = self.bot.embeds.embed_builder( title=":exclamation: New Report", description=content) if is_anon: from_value = "*Anonymous Report*" else: from_value = str(ctx.author) embed.add_field(name="From", value=from_value) await mk.get_democraciv_channel( self.bot, mk.DemocracivChannel.MODERATION_NOTIFICATIONS_CHANNEL).send( content=mk.get_democraciv_role( self.bot, mk.DemocracivRole.MODERATION_ROLE).mention, embed=embed) await ctx.send(":white_check_mark: Report was sent.") elif not reaction: return await ctx.send("Aborted.")
async def defaultrole(self, ctx): """Give every new member a specific role once they join this server""" is_default_role_enabled = await self.bot.checks.is_default_role_enabled( ctx.guild.id) current_default_role = await self.bot.db.fetchval( "SELECT defaultrole_role FROM guilds WHERE id = $1", ctx.guild.id) current_default_role = ctx.guild.get_role(current_default_role) if current_default_role is None: current_default_role = "-" else: current_default_role = current_default_role.mention embed = self.bot.embeds.embed_builder( title=f":partying_face: Default Role on {ctx.guild.name}", description=f"React with the {config.GUILD_SETTINGS_GEAR} emoji to" f" change these settings.", has_footer=False) embed.add_field(name="Enabled", value=self.emojiy_settings(is_default_role_enabled)) embed.add_field(name="Default Role", value=current_default_role) info_embed = await ctx.send(embed=embed) flow = Flow(self.bot, ctx) if await flow.gear_reaction_confirm(info_embed, 300): status_question = await ctx.send( "React with :white_check_mark: to enable the default role, or with :x: to disable the default role." ) reaction = await flow.get_yes_no_reaction_confirm( status_question, 240) if reaction is None: return if reaction: await self.bot.db.execute( "UPDATE guilds SET defaultrole = true WHERE id = $1", ctx.guild.id) await ctx.send(":white_check_mark: Enabled the default role.") await ctx.send( ":information_source: Reply with the name of the role that every " "new member should get once they join.") new_default_role = await flow.get_new_role(240) if isinstance(new_default_role, str): await ctx.send( f":white_check_mark: I will **create a new role** on this server named `{new_default_role}`" f" for the default role.") try: new_default_role_object = await ctx.guild.create_role( name=new_default_role) except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.CREATE_ROLE, new_default_role) else: new_default_role_object = new_default_role await ctx.send( f":white_check_mark: I'll use the **pre-existing role** named " f"`{new_default_role_object.name}` for the default role." ) status = await self.bot.db.execute( "UPDATE guilds SET defaultrole_role = $2 WHERE id = $1", ctx.guild.id, new_default_role_object.id) if status == "UPDATE 1": await ctx.send( f":white_check_mark: Set the default role to `{new_default_role_object.name}`." ) elif not reaction: await self.bot.db.execute( "UPDATE guilds SET defaultrole = false WHERE id = $1", ctx.guild.id) await ctx.send(":white_check_mark: Disabled the default role.") await self.bot.cache.update_guild_config_cache()
async def logs(self, ctx): """Log important events like message edits & deletions and more to a specific channel""" is_logging_enabled = await self.bot.checks.is_logging_enabled( ctx.guild.id) current_logging_channel = await utils.get_logging_channel( self.bot, ctx.guild) if current_logging_channel is None: current_logging_channel = "-" else: current_logging_channel = current_logging_channel.mention embed = self.bot.embeds.embed_builder( title=f":spy: Event Logging on {ctx.guild.name}", description=f"React with the {config.GUILD_SETTINGS_GEAR} emoji " f"to change these settings.", has_footer=False) embed.add_field(name="Enabled", value=self.emojiy_settings(is_logging_enabled)) embed.add_field(name="Log Channel", value=current_logging_channel) info_embed = await ctx.send(embed=embed) flow = Flow(self.bot, ctx) if await flow.gear_reaction_confirm(info_embed, 300): status_question = await ctx.send( "React with :white_check_mark: to enable logging, " "or with :x: to disable logging.") reaction = await flow.get_yes_no_reaction_confirm( status_question, 240) if reaction is None: return if reaction: await self.bot.db.execute( "UPDATE guilds SET logging = true WHERE id = $1", ctx.guild.id) await ctx.send(":white_check_mark: Event logging was enabled.") await ctx.send( ":information_source: Reply with the name of the channel" " that I should use to log all events to.") channel_object = await flow.get_new_channel(240) if isinstance(channel_object, str): raise exceptions.ChannelNotFoundError(channel_object) status = await self.bot.db.execute( "UPDATE guilds SET logging_channel = $2 WHERE id = $1", ctx.guild.id, channel_object.id) if status == "UPDATE 1": await ctx.send( f":white_check_mark: Set the logging channel to {channel_object.mention}." ) elif not reaction: await self.bot.db.execute( "UPDATE guilds SET logging = false WHERE id = $1", ctx.guild.id) await ctx.send(":white_check_mark: Event logging was disabled." ) await self.bot.cache.update_guild_config_cache()
async def archiveoldgov(self, ctx): """Move all channels in the Government category and #propaganda into the Archives and set the right permissions """ flow = Flow(self.bot, ctx) are_you_sure = await ctx.send( f":information_source: Are you sure that you want archive every government channel?" ) reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 200) if reaction is None: return if not reaction: return await ctx.send("Aborted.") elif reaction: async with ctx.typing(): government_category: discord.CategoryChannel = discord.utils.get( self.bot.democraciv_guild_object.categories, name="Government") if government_category is None: return await ctx.send( ":x: There is no category named `Government` for me to archive." ) def predicate(c): return c.name.lower() == f"mk{self.bot.mk.MARK}-archive" archive_category = discord.utils.find( predicate, self.bot.democraciv_guild_object.categories) if archive_category is None: return await ctx.send( f":x: There is no category named `MK{self.bot.mk.MARK}-Archive` for me to use." ) everyone_perms = discord.PermissionOverwrite( read_message_history=False, send_messages=False, read_messages=False) everyone_role = self.bot.democraciv_guild_object.default_role archive_perms = discord.PermissionOverwrite( read_message_history=True, send_messages=False, read_messages=True) archives_role = discord.utils.get( self.bot.democraciv_guild_object.roles, name="Archives") if archives_role is None: return await ctx.send( ":x: There is no role named `Archives` for me to use.") for channel in government_category.text_channels: await channel.send( f":tada: Thanks for playing Democraciv MK{self.bot.mk.MARK}!" ) await channel.edit( name=f"mk{self.bot.mk.MARK}-{channel.name}", overwrites={ everyone_role: everyone_perms, archives_role: archive_perms }, category=archive_category) propaganda_channel = discord.utils.get( self.bot.democraciv_guild_object.text_channels, name="propaganda") if propaganda_channel is not None: await propaganda_channel.edit( name=f"mk{self.bot.mk.MARK}-propaganda", category=archive_category, overwrites={ everyone_role: everyone_perms, archives_role: archive_perms }) press_channel = discord.utils.get( self.bot.democraciv_guild_object.text_channels, name="press") if press_channel is not None: await press_channel.edit( name=f"mk{self.bot.mk.MARK}-press", category=archive_category, overwrites={ everyone_role: everyone_perms, archives_role: archive_perms }) await ctx.send(":white_check_mark: Done.")
async def create_new_party(self, ctx) -> typing.Optional[PoliticalParty]: await ctx.send( ":information_source: Reply with the name of the new party you want to create." ) flow = Flow(self.bot, ctx) role_name = await flow.get_new_role(240) if isinstance(role_name, str): is_updated = False await ctx.send( f":white_check_mark: I will **create a new role** on this server named `{role_name}`" f" for the new party.") try: discord_role = await ctx.guild.create_role(name=role_name) except discord.Forbidden: raise exceptions.ForbiddenError( exceptions.ForbiddenTask.CREATE_ROLE, role_name) else: is_updated = True discord_role = role_name await ctx.send( f":white_check_mark: I'll use the **pre-existing role**" f" `{discord_role.name}` for the new party.") await ctx.send( ":information_source: Reply with the name of the party's leader or representative." ) leader = await flow.get_text_input(240) if not leader: return try: leader_member = await commands.MemberConverter().convert( ctx, leader) except commands.BadArgument: raise exceptions.MemberNotFoundError(leader) await ctx.send( ":information_source: Reply with the invite link to the party's Discord server. " "If they don't have one, just reply with gibberish.") party_invite = await flow.get_text_input(300) if not party_invite: return None discord_invite_pattern = re.compile( r"(?:https?://)?discord(?:app\.com/invite|\.gg)/?[a-zA-Z0-9]+/?") if not discord_invite_pattern.fullmatch(party_invite): party_invite = None is_private = False private_question = await ctx.send( "Should this new party be **public**, i.e. join-able by everyone? " "React with :white_check_mark: if yes, or with :x: if not.") reaction = await flow.get_yes_no_reaction_confirm( private_question, 240) if reaction is None: return None if reaction: is_private = False elif not reaction: is_private = True async with self.bot.db.acquire() as connection: async with connection.transaction(): await connection.execute( "INSERT INTO parties (id, discord_invite, is_private, leader) VALUES ($1, $2, $3, $4)" "ON CONFLICT (id) DO UPDATE SET discord_invite = $2, is_private = $3," " leader = $4 WHERE parties.id = $1", discord_role.id, party_invite, is_private, leader_member.id) await connection.execute( "INSERT INTO party_alias (alias, party_id) VALUES ($1, $2)" " ON CONFLICT DO NOTHING ", discord_role.name.lower(), discord_role.id) if not is_updated: await ctx.send( f':white_check_mark: `{discord_role.name}` was added as a new party.' ) else: await ctx.send( f':white_check_mark: `{discord_role.name}` was added as a new party or its ' f'properties were updated if it already existed.') return await PoliticalParty.convert(ctx, discord_role.id)
async def mergeparties(self, ctx, amount_of_parties: int): """Merge one or multiple parties into a single, new party""" flow = Flow(self.bot, ctx) to_be_merged = [] for i in range(1, amount_of_parties + 1): await ctx.send( f":information_source: What's the name or alias for political party #{i}?" ) name = await flow.get_text_input(120) if not name: return try: party = await PoliticalParty.convert(ctx, name) except exceptions.PartyNotFoundError: return await ctx.send( f":x: There is no party that matches `{name}`. Aborted.") to_be_merged.append(party) members_to_merge = { member for party in to_be_merged for member in party.role.members } pretty_parties = [f"`{party.role.name}`" for party in to_be_merged] are_you_sure = await ctx.send( f":information_source: Are you sure that you want to merge" f" {', '.join(pretty_parties)} into one, new party?") reaction = await flow.get_yes_no_reaction_confirm(are_you_sure, 120) if reaction is None: return if not reaction: return await ctx.send("Aborted.") try: new_party = await self.create_new_party(ctx) except exceptions.DemocracivBotException as e: return await ctx.send( f"{e.message}\n:x: Party creation failed, old parties were not deleted." ) if new_party is None or new_party.role is None: return await ctx.send( ":x: Party creation failed, old parties were not deleted.") async with ctx.typing(): for member in members_to_merge: await member.add_roles(new_party.role) for party in to_be_merged: # In case the merger keeps the name and thus role of an old party if party.role.id == new_party.role.id: continue async with self.bot.db.acquire() as connection: async with connection.transaction(): await connection.execute( "DELETE FROM party_alias WHERE party_id = $1", party.role.id) await connection.execute( "DELETE FROM parties WHERE id = $1", party.role.id) await party.role.delete() await ctx.send(":white_check_mark: The old parties were deleted and" " all their members have now the role of the new party." )