From bc8976590d12691954a28f58fc930b494a1964ef Mon Sep 17 00:00:00 2001 From: Vegard Berg Date: Mon, 6 Feb 2023 20:11:44 +0100 Subject: [PATCH] Deprecate resources feature for now --- database.py | 21 --- heimdallr/commands/__resources.py | 244 ++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+), 21 deletions(-) create mode 100644 heimdallr/commands/__resources.py diff --git a/database.py b/database.py index 80751e8..a6d3837 100644 --- a/database.py +++ b/database.py @@ -176,27 +176,6 @@ class BotMessages(Model): database = db -class Resources(Model): - id = AutoField() - guild_id = BigIntegerField() - title = TextField() - description = TextField() - url = TextField() - - class Meta: - table_name = "Resources" - database = db - - -class ResourceTags(Model): - resource_id = ForeignKeyField(Resources, to_field="id") - tag = TextField() - - class Meta: - primary_key = CompositeKey("resource_id", "tag") - table_name = "ResourceTags" - database = db - class BadNames(Model): id = AutoField() diff --git a/heimdallr/commands/__resources.py b/heimdallr/commands/__resources.py new file mode 100644 index 0000000..84df38e --- /dev/null +++ b/heimdallr/commands/__resources.py @@ -0,0 +1,244 @@ +"""Deprecated module + +This was intended to be the resources module. A user-submitted, curated directory of +resources for a guild. For the time being, forum channels serve as enough of an equivalent +for the needs of NLL. So this is to be considered deprecated. + +""" + +from naff import ( + slash_command, + slash_option, + Extension, + Client, + Permissions, + InteractionContext, + OptionTypes, + Embed, + Member, + EmbedField, + EmbedAuthor, + Modal, + InputText, + TextStyles, + ChannelTypes, + GuildText, +) +import logging + +from database import ( + Resources as ResourcesModel, + ResourceTags as ResourceTagsModel, + ResourceAuthors as ResourceAuthorsModel, + ResourcesUnpublished as ResourcesUnpublishedModel, + ResourceChannels as ResourceChannelsModel, + +) + + +class Resources(Extension): + def __init__(self, client: Client) -> None: + self.client = client + + @slash_command( + name="adm", + group_name="set", + group_description="Set settings for this guild", + sub_cmd_name="submitted_resources_channel", + sub_cmd_description="Set whether or not to use the name filter", + dm_permission=False, + default_member_permissions=Permissions.MANAGE_GUILD, + ) + @slash_option( + name="channel", + description="The channel in which submitted/unpublished resources should appear", + opt_type=OptionTypes.CHANNEL, + channel_types=[ChannelTypes.GUILD_TEXT], + ) + async def adm_set_submitted_resources_channel( + self, ctx: InteractionContext, channel: GuildText|None = None + ): + if channel is None: + resource_channel = ResourceChannelsModel.get_or_none(guild_id=ctx.guild.id) + + if resource_channel is not None: + resource_channel.delete_instance() + + await ctx.send(ephemeral=True, content="Submitted resource channel unset.") + return + + resource_channel: ResourceChannelsModel + resource_channel, _ = ResourceChannelsModel.get_or_create(guild_id=ctx.guild.id) + resource_channel.channel_id = channel.id + resource_channel.save() + + await ctx.send(ephemeral=True, + content=f"Submitted resource channel set to {channel.mention}." + ) + + + + + @slash_command( + name="resources", + description="Get or add resources", + default_member_permissions=Permissions.SEND_MESSAGES, + dm_permission=False, + ) + async def resources(self, ctx: InteractionContext): + ... + + @resources.subcommand( + sub_cmd_name="list", + sub_cmd_description="List resources", + ) + @slash_option( + name="page", + description="Page of resources to show", + opt_type=OptionTypes.INTEGER, + required=False, + ) + async def resources_list(self, ctx: InteractionContext, page: int = 1): + await ctx.defer(ephemeral=True) + LIMIT = 10 + resources: list[ResourcesModel] = ( + ResourcesModel.select() + .paginate(page, LIMIT) + .order_by(ResourcesModel.id.asc()) + ) + + embeds: list[Embed] = [] + + for resource in resources: + resource_authors: list[ + ResourceAuthorsModel + ] = ResourceAuthorsModel.select().where( + ResourceAuthorsModel.resource_id == resource.id + ) + + authors: list[str] = [] + + for author in resource_authors: + member = await self.client.fetch_member(author.user_id, ctx.guild_id) + if member is None: + authors.append(author.name) + else: + authors.append( + f"{member.display_name} ({member.username}#{member.discriminator})" + ) + embed = Embed(title=resource.title, description=resource.description) + embed.add_field("**Authors**", "\n".join(authors)) + + no_resources = ResourcesModel.select().count() + pages = no_resources // LIMIT + if no_resources % LIMIT != 0: + pages += 1 + + await ctx.send(ephemeral=True, content=f"Page {page} of {pages}", embeds=embeds) + + @resources.subcommand( + sub_cmd_name="submit", + sub_cmd_description="Submit a resource for approval", + ) + async def resources_submit(self, ctx: InteractionContext): + modal_wait = await ctx.send_modal( + Modal( + title="New resource", + components=[ + InputText( + label="Title", + custom_id="title", + style=TextStyles.SHORT, + placeholder="A title!", + min_length=8, + max_length=64, + ), + InputText( + label="Content", + custom_id="content", + style=TextStyles.PARAGRAPH, + placeholder="A description of the resource.", + min_length=16, + ), + InputText( + label="Tags", + custom_id="tags", + style=TextStyles.SHORT, + placeholder="Tags separated by spaces; e.g: grammar language-dialects tag", + max_length=128, + ), + ], + ) + ) + + modal_ctx = await self.client.wait_for_modal(modal_wait, author=ctx.author.id) + await modal_ctx.defer(ephemeral=True) + + title = modal_ctx.responses.get("title") + content = modal_ctx.responses.get("content") + tags = modal_ctx.responses.get("tags") + + if title is None: + await modal_ctx.send("Title cannot be empty.") + return + if content is None: + await modal_ctx.send("Content cannot be empty.") + return + + resource: ResourcesUnpublishedModel = ResourcesUnpublishedModel.create( + guild_id=modal_ctx.guild.id, + title=title, + description=content, + tags=tags, + author=modal_ctx.author.id, + ) + + await modal_ctx.send(f"Your resource *{title}* has been submitted!") + + await self.__post_to_resources_submission_channel(resource) + + async def __post_to_resources_submission_channel(self, resource: ResourcesUnpublishedModel): + res_unpublished_channel: ResourceChannelsModel | None = ResourceChannelsModel.get_or_none( + ResourceChannelsModel.guild_id == resource.guild_id + ) + + if res_unpublished_channel is None: + return # No unpublished resources channel has been set. + + channel_id = int(res_unpublished_channel.channel_id) + channel = await self.client.fetch_channel(channel_id) + + guild_id = int(resource.guild_id) + user_id = int(resource.author) + author: Member | None = await self.client.fetch_member(guild_id=guild_id, user_id=user_id) + author_text = None + author_icon_url = None + if author is None: + author_text = f"<@{int(resource.author)}>" + else: + author_icon_url = author.display_avatar.as_url() + if author.display_name != author.username: + author_text = f"{author.display_name} ({author.username}#{author.discriminator})" + else: + author_text = f"{author.username}#{author.discriminator}" + + await channel.send( + embed=Embed( + title=str(resource.title), + description=str(resource.description), + author=EmbedAuthor( + name=author_text, + icon_url=author_icon_url, + ) + + ) + ) + + +def setup(bot: Client): + ResourcesModel.create_table(safe=True) + ResourceTagsModel.create_table(safe=True) + ResourcesUnpublishedModel.create_table(safe=True) + ResourceChannelsModel.create_table(safe=True) + Resources(bot) + logging.info("Resources extension loaded")