Compare commits
4 Commits
a64f6c6003
...
db4e353bb0
Author | SHA1 | Date |
---|---|---|
Vegard Berg | db4e353bb0 | |
Vegard Berg | 09674aa86b | |
Vegard Berg | bc8976590d | |
Vegard Berg | f3c6aa9f85 |
21
database.py
21
database.py
|
@ -176,27 +176,6 @@ class BotMessages(Model):
|
||||||
database = db
|
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):
|
class BadNames(Model):
|
||||||
id = AutoField()
|
id = AutoField()
|
||||||
|
|
|
@ -7,6 +7,9 @@ from naff import (
|
||||||
listen,
|
listen,
|
||||||
slash_command,
|
slash_command,
|
||||||
InteractionContext,
|
InteractionContext,
|
||||||
|
AuditLogEventType,
|
||||||
|
AuditLogEntry,
|
||||||
|
RoleSelectMenu,
|
||||||
)
|
)
|
||||||
from naff.api import events
|
from naff.api import events
|
||||||
from naff.models.discord.embed import (
|
from naff.models.discord.embed import (
|
||||||
|
@ -19,13 +22,13 @@ from naff.models.discord.embed import (
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from database import GuildSettings as GuildSettingsModel, JoinLeave
|
from database import GuildSettings as GuildSettingsModel, JoinLeave
|
||||||
|
|
||||||
bot = Client(intents=Intents.ALL, debug_scope=387153131378835456)
|
class HeimdallrClient(Client):
|
||||||
|
@listen()
|
||||||
|
async def on_ready(self):
|
||||||
@listen()
|
print("------------------------------------")
|
||||||
async def on_ready():
|
|
||||||
print(f"Bot '{bot.user.username}' is ready!")
|
print(f"Bot '{bot.user.username}' is ready!")
|
||||||
print(f"This bot is owned by {bot.owner}")
|
print(f"This bot is owned by {bot.owner}")
|
||||||
|
print("------------------------------------")
|
||||||
|
|
||||||
for guild in bot.guilds:
|
for guild in bot.guilds:
|
||||||
guild_q = GuildSettingsModel.get_or_none(GuildSettingsModel.guild_id == guild.id)
|
guild_q = GuildSettingsModel.get_or_none(GuildSettingsModel.guild_id == guild.id)
|
||||||
|
@ -34,13 +37,8 @@ async def on_ready():
|
||||||
guild_q.save()
|
guild_q.save()
|
||||||
|
|
||||||
|
|
||||||
|
@listen(events.MemberAdd)
|
||||||
# @listen()
|
async def on_member_join(self, event: events.MemberAdd):
|
||||||
# async def on_message_create(event: MessageCreate):
|
|
||||||
# print(f"{event.message.author.username}: {event.message.content}")
|
|
||||||
|
|
||||||
@listen(events.MemberAdd)
|
|
||||||
async def on_member_join(event: events.MemberAdd):
|
|
||||||
joinleave_q: JoinLeave
|
joinleave_q: JoinLeave
|
||||||
joinleave_q, _ = JoinLeave.get_or_create(guild_id=event.guild.id)
|
joinleave_q, _ = JoinLeave.get_or_create(guild_id=event.guild.id)
|
||||||
|
|
||||||
|
@ -59,11 +57,29 @@ async def on_member_join(event: events.MemberAdd):
|
||||||
|
|
||||||
await channel.send(str(joinleave_q.join_message).format(member=event.member, guild=event.guild))
|
await channel.send(str(joinleave_q.join_message).format(member=event.member, guild=event.guild))
|
||||||
|
|
||||||
@listen(events.MemberRemove)
|
@listen(events.MemberRemove)
|
||||||
async def on_member_leave(event: events.MemberRemove):
|
async def on_member_leave(self, event: events.MemberRemove):
|
||||||
joinleave_q: JoinLeave
|
joinleave_q: JoinLeave
|
||||||
joinleave_q, _ = JoinLeave.get_or_create(guild_id=event.guild.id)
|
joinleave_q, _ = JoinLeave.get_or_create(guild_id=event.guild.id)
|
||||||
|
|
||||||
|
guildsettings_q: GuildSettingsModel
|
||||||
|
guildsettings_q, _ = GuildSettingsModel.get_or_create(guild_id=event.guild.id)
|
||||||
|
|
||||||
|
entry: AuditLogEntry
|
||||||
|
async for entry in event.guild.audit_log_history(
|
||||||
|
action_type=AuditLogEventType.MEMBER_KICK,
|
||||||
|
limit=10
|
||||||
|
):
|
||||||
|
if (entry.target_id != event.member.id or
|
||||||
|
guildsettings_q.admin_channel is None):
|
||||||
|
continue
|
||||||
|
|
||||||
|
channel = await bot.fetch_channel(guildsettings_q.admin_channel)
|
||||||
|
await channel.send(f"{event.member.mention} was kicked with reason: {entry.reason}")
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if joinleave_q.message_channel is None:
|
if joinleave_q.message_channel is None:
|
||||||
return
|
return
|
||||||
channel = await bot.fetch_channel(joinleave_q.message_channel)
|
channel = await bot.fetch_channel(joinleave_q.message_channel)
|
||||||
|
@ -81,14 +97,16 @@ async def on_member_leave(event: events.MemberRemove):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@slash_command(name="ping", description="Ping the bot")
|
@slash_command(name="ping", description="Ping the bot")
|
||||||
async def ping_command(ctx: InteractionContext):
|
async def ping_command(self, ctx: InteractionContext):
|
||||||
ctx.ephemeral = True
|
ctx.ephemeral = True
|
||||||
await ctx.send("Pong!")
|
await ctx.send("Pong!",
|
||||||
|
components=RoleSelectMenu(placeholder="HONK")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@slash_command(name="bot-info", description="Get info about the bot")
|
@slash_command(name="bot-info", description="Get info about the bot")
|
||||||
async def bot_info_command(ctx: InteractionContext):
|
async def bot_info_command(self, ctx: InteractionContext):
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
ephemeral=True,
|
ephemeral=True,
|
||||||
embed=Embed(
|
embed=Embed(
|
||||||
|
@ -118,6 +136,14 @@ async def bot_info_command(ctx: InteractionContext):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
bot = HeimdallrClient(intents=Intents.ALL, debug_scope=387153131378835456,
|
||||||
|
sync_interactions=True,
|
||||||
|
fetch_members=True,
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def set_loglevel(level: str):
|
def set_loglevel(level: str):
|
||||||
loglevel = logging.WARNING
|
loglevel = logging.WARNING
|
||||||
|
|
||||||
|
@ -158,6 +184,7 @@ def main():
|
||||||
bot.load_extension("heimdallr.commands.self_roles")
|
bot.load_extension("heimdallr.commands.self_roles")
|
||||||
bot.load_extension("heimdallr.commands.polls")
|
bot.load_extension("heimdallr.commands.polls")
|
||||||
bot.load_extension("heimdallr.commands.bot_messages")
|
bot.load_extension("heimdallr.commands.bot_messages")
|
||||||
|
bot.load_extension("heimdallr.commands.modmail")
|
||||||
bot.start(getenv("DISCORD_TOKEN"))
|
bot.start(getenv("DISCORD_TOKEN"))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -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")
|
|
@ -351,9 +351,9 @@ class Gatekeep(Extension):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@listen(events.Button)
|
@listen(events.ButtonPressed)
|
||||||
async def on_regenerate_button(self, button: events.Button):
|
async def on_regenerate_button(self, button: events.ButtonPressed):
|
||||||
ctx = button.context
|
ctx = button.ctx
|
||||||
member = ctx.author
|
member = ctx.author
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
import logging
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from database import GuildSettings
|
||||||
|
|
||||||
|
from naff import (
|
||||||
|
Extension,
|
||||||
|
Client,
|
||||||
|
slash_command,
|
||||||
|
slash_option,
|
||||||
|
InteractionContext,
|
||||||
|
ModalContext,
|
||||||
|
Permissions,
|
||||||
|
OptionTypes,
|
||||||
|
Button,
|
||||||
|
ButtonStyles,
|
||||||
|
listen,
|
||||||
|
events,
|
||||||
|
Modal,
|
||||||
|
InputText,
|
||||||
|
TextStyles,
|
||||||
|
Role,
|
||||||
|
Embed,
|
||||||
|
EmbedAuthor,
|
||||||
|
)
|
||||||
|
|
||||||
|
class ModMail(Extension):
|
||||||
|
def __init__(self, client: Client):
|
||||||
|
self.client: Client = client
|
||||||
|
|
||||||
|
@slash_command(
|
||||||
|
name="adm",
|
||||||
|
sub_cmd_name="create-modmail-button",
|
||||||
|
sub_cmd_description="Create a button for users to create a modmail thread.",
|
||||||
|
dm_permission=False,
|
||||||
|
default_member_permissions=Permissions.MANAGE_GUILD,
|
||||||
|
)
|
||||||
|
@slash_option(
|
||||||
|
name="button-text",
|
||||||
|
description="The text that should be displayed on the button.",
|
||||||
|
opt_type=OptionTypes.STRING,
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
@slash_option(
|
||||||
|
name="notify-role",
|
||||||
|
description="Role that should be tagged upon creation of the modmail thread.",
|
||||||
|
opt_type=OptionTypes.ROLE,
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
async def adm_create_modmail_button(self, ctx: InteractionContext, button_text: str, role: Role):
|
||||||
|
await ctx.defer(ephemeral=True)
|
||||||
|
|
||||||
|
await ctx.channel.send(
|
||||||
|
components=Button(
|
||||||
|
style=ButtonStyles.GREEN,
|
||||||
|
label=button_text,
|
||||||
|
custom_id=f"send-modmail-button:{role.id}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
await ctx.send("Button created!", ephemeral=True)
|
||||||
|
|
||||||
|
@listen(events.ButtonPressed)
|
||||||
|
async def on_button(self, button: events.ButtonPressed):
|
||||||
|
ctx = button.ctx
|
||||||
|
|
||||||
|
if not ctx.custom_id.startswith("send-modmail-button"):
|
||||||
|
return
|
||||||
|
|
||||||
|
(_, role) = ctx.custom_id.split(":")
|
||||||
|
if role is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
role = await ctx.guild.fetch_role(role)
|
||||||
|
if role is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
modmail_modal = Modal(
|
||||||
|
title="Send modmail",
|
||||||
|
custom_id=f"modmail-modal:{uuid.uuid4()}",
|
||||||
|
components=[
|
||||||
|
InputText(
|
||||||
|
label="Topic",
|
||||||
|
style=TextStyles.SHORT,
|
||||||
|
custom_id="modmail_title",
|
||||||
|
required=True,
|
||||||
|
min_length=5,
|
||||||
|
max_length=100,
|
||||||
|
placeholder="Title or topic of the modmail"
|
||||||
|
),
|
||||||
|
InputText(
|
||||||
|
label="Message",
|
||||||
|
style=TextStyles.PARAGRAPH,
|
||||||
|
custom_id="modmail_body",
|
||||||
|
required=True,
|
||||||
|
min_length=24,
|
||||||
|
max_length=2000,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
await ctx.send_modal(modmail_modal)
|
||||||
|
modal_ctx: ModalContext = await self.client.wait_for_modal(modmail_modal)
|
||||||
|
|
||||||
|
thread = await ctx.channel.create_private_thread(
|
||||||
|
name=modal_ctx.responses["modmail_title"],
|
||||||
|
invitable=True,
|
||||||
|
reason=(
|
||||||
|
f"{ctx.author.username}#{ctx.author.discriminator} "
|
||||||
|
"created a support thread."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
msg = await thread.send(
|
||||||
|
content=f"{role.mention} {ctx.author.mention}",
|
||||||
|
embed=Embed(
|
||||||
|
title=modal_ctx.responses["modmail_title"],
|
||||||
|
description=modal_ctx.responses["modmail_body"],
|
||||||
|
author=EmbedAuthor(
|
||||||
|
name=(
|
||||||
|
f"{ctx.author.nickname} "
|
||||||
|
f"({ctx.author.username}#{ctx.author.discriminator})"
|
||||||
|
),
|
||||||
|
icon_url=ctx.author.avatar.as_url()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if msg:
|
||||||
|
await modal_ctx.send(
|
||||||
|
"Message created",
|
||||||
|
ephemeral=True,
|
||||||
|
components=Button(
|
||||||
|
style=ButtonStyles.LINK,
|
||||||
|
label="Go to message",
|
||||||
|
url=msg.jump_url,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def setup(client: Client):
|
||||||
|
ModMail(client)
|
||||||
|
logging.info(f"{ModMail.__name__} extension loaded.")
|
|
@ -308,9 +308,9 @@ class Polls(Extension):
|
||||||
poll_entry.channel_id = poll_message.channel.id
|
poll_entry.channel_id = poll_message.channel.id
|
||||||
poll_entry.save()
|
poll_entry.save()
|
||||||
|
|
||||||
@listen(events.Button)
|
@listen(events.ButtonPressed)
|
||||||
async def on_button(self, button: events.Button): #pylint: disable=too-many-branches,too-many-statements
|
async def on_button(self, button: events.ButtonPressed): #pylint: disable=too-many-branches,too-many-statements
|
||||||
ctx = button.context
|
ctx = button.ctx
|
||||||
|
|
||||||
# Ensure that the pressed button is a vote button.
|
# Ensure that the pressed button is a vote button.
|
||||||
if ctx.custom_id.startswith("poll-vote:"):
|
if ctx.custom_id.startswith("poll-vote:"):
|
||||||
|
|
|
@ -12,7 +12,7 @@ from naff import (
|
||||||
Role,
|
Role,
|
||||||
Embed,
|
Embed,
|
||||||
AutocompleteContext,
|
AutocompleteContext,
|
||||||
Select,
|
StringSelectMenu,
|
||||||
SelectOption,
|
SelectOption,
|
||||||
listen,
|
listen,
|
||||||
context_menu,
|
context_menu,
|
||||||
|
@ -436,7 +436,7 @@ class SelfRoles(Extension):
|
||||||
|
|
||||||
max_vals = 1 if group_q.exclusive else len(options)
|
max_vals = 1 if group_q.exclusive else len(options)
|
||||||
|
|
||||||
select = Select(
|
select = StringSelectMenu(
|
||||||
options=options,
|
options=options,
|
||||||
placeholder=f"Select roles from the group {group}",
|
placeholder=f"Select roles from the group {group}",
|
||||||
custom_id=f"role-group-assign:{group}",
|
custom_id=f"role-group-assign:{group}",
|
||||||
|
@ -552,7 +552,7 @@ class SelfRoles(Extension):
|
||||||
or msg.embeds[0].title is None
|
or msg.embeds[0].title is None
|
||||||
or len(msg.components) < 1
|
or len(msg.components) < 1
|
||||||
or len(msg.components[0].components) < 1
|
or len(msg.components[0].components) < 1
|
||||||
or not isinstance(msg.components[0].components[0], Select)
|
or not isinstance(msg.components[0].components[0], StringSelectMenu)
|
||||||
or not msg.components[0].components[0].custom_id.startswith("role-group-assign")
|
or not msg.components[0].components[0].custom_id.startswith("role-group-assign")
|
||||||
):
|
):
|
||||||
await ctx.send("Could not identify this as a role-group message!", ephemeral=True)
|
await ctx.send("Could not identify this as a role-group message!", ephemeral=True)
|
||||||
|
@ -600,7 +600,7 @@ class SelfRoles(Extension):
|
||||||
|
|
||||||
max_vals = 1 if group_q.exclusive else len(options)
|
max_vals = 1 if group_q.exclusive else len(options)
|
||||||
|
|
||||||
select = Select(
|
select = StringSelectMenu(
|
||||||
options=options,
|
options=options,
|
||||||
placeholder=f"Select roles from the group {group}",
|
placeholder=f"Select roles from the group {group}",
|
||||||
custom_id=f"role-group-assign:{group}",
|
custom_id=f"role-group-assign:{group}",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,7 +10,7 @@ heimdallr = "heimdallr.Heimdallr:main"
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.10"
|
python = "^3.10"
|
||||||
peewee = "^3.15.1"
|
peewee = "^3.15.1"
|
||||||
naff = "^1.11.1"
|
naff = "2.1.0"
|
||||||
orjson = "^3.7.8"
|
orjson = "^3.7.8"
|
||||||
python-dotenv = "^0.20.0"
|
python-dotenv = "^0.20.0"
|
||||||
captcha = "^0.4"
|
captcha = "^0.4"
|
||||||
|
|
Loading…
Reference in New Issue