Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ The required scopes are:
And the required permissions:
- Embed Links
- Manage Messages
- Manage Webhooks
- Read Message History
- Send Messages
- Send Messages in Threads
Expand Down
78 changes: 74 additions & 4 deletions cogs/link_fix.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,17 @@ async def fix_embeds(
or (isinstance(channel, discore.Thread) and (channel.locked or channel.archived))):
return

async with Typing(channel):
async def render_and_send() -> tuple[list[tuple[str, list[WebsiteLink]]], dict[discore.Message, list[WebsiteLink]]]:
rendered_links = [link for link in links if await link.render()]
if not rendered_links:
return
not_sent, messages = await send_fixed_links(rendered_links, guild, original_message)
return [], {}
return await send_fixed_links(rendered_links, guild, original_message)

if guild.reply_as_original_author_replica:
not_sent, messages = await render_and_send()
else:
async with Typing(channel):
not_sent, messages = await render_and_send()

to_delete = []
if messages:
Expand Down Expand Up @@ -200,9 +206,13 @@ async def send_fixed_links(
links_failed: list[tuple[str, list[WebsiteLink]]] = []

grouped = group_items(rendered_links, 2000)
use_original_author_replica = guild.reply_as_original_author_replica
webhook = await get_or_create_webhook(original_message.channel) if use_original_author_replica else None

for i, (message_content, links_in_group) in enumerate(grouped):
if i == 0 and guild.reply_to_message:
if webhook is not None:
coro = webhook_send(webhook, original_message, message_content, guild.reply_silently)
elif i == 0 and guild.reply_to_message:
coro = discore.fallback_reply(original_message, message_content, silent=guild.reply_silently)
else:
coro = original_message.channel.send(message_content, silent=guild.reply_silently)
Expand All @@ -216,6 +226,66 @@ async def send_fixed_links(
return links_failed, messages_sent


async def get_or_create_webhook(channel: GuildMessageableChannel) -> discore.Webhook | None:
"""
Get or create the webhook used to send messages as the original author.

:param channel: the channel to send the fixed links to
:return: the webhook to use, if available
"""

webhook_channel = channel.parent if isinstance(channel, discore.Thread) else channel
if webhook_channel is None:
return None

if not hasattr(webhook_channel, 'webhooks') or not hasattr(webhook_channel, 'create_webhook'):
return None

if not webhook_channel.permissions_for(channel.guild.me).manage_webhooks:
return None

sent, webhooks = await safe_send_coro(webhook_channel.webhooks(), forbidden=True)
Comment thread
Kyrela marked this conversation as resolved.
Outdated
if not sent:
return None
webhook_name = channel.guild.me.display_name
Comment thread
Kyrela marked this conversation as resolved.
Outdated
webhook = next((
w for w in webhooks
if w.name == webhook_name and getattr(w.user, 'id', None) == channel.guild.me.id
Comment thread
Kyrela marked this conversation as resolved.
Outdated
), None)
if webhook is not None:
return webhook
sent, webhook = await safe_send_coro(webhook_channel.create_webhook(name=webhook_name), forbidden=True)
return webhook if sent else None


async def webhook_send(
webhook: discore.Webhook,
original_message: discore.Message,
content: str,
silent: bool
) -> discore.Message:
"""
Send a fixed link using the original author's display name and avatar.

:param webhook: the webhook to use
:param original_message: the message associated with the context to reply to
:param content: the content to send
:param silent: whether to send the message silently
:return: the message created by the webhook
"""

kwargs = {
'content': content,
'username': original_message.author.display_name,
'avatar_url': original_message.author.display_avatar.url,
'silent': silent,
'wait': True
}
if isinstance(original_message.channel, discore.Thread):
kwargs['thread'] = original_message.channel
return await webhook.send(**kwargs)


async def wait_for_embed(message: discore.Message) -> bool:
"""
Wait for the message to have embeds.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""AddOriginalAuthorReplicaReplies Migration."""

from masoniteorm.migrations import Migration


class AddOriginalAuthorReplicaReplies(Migration):
def up(self):
"""
Run the migrations.
"""
with self.schema.table("guilds") as table:
table.boolean("reply_as_original_author_replica").default(False)
Comment thread
Kyrela marked this conversation as resolved.
Outdated

def down(self):
"""
Revert the migrations.
"""
with self.schema.table("guilds") as table:
table.drop_column("reply_as_original_author_replica")
1 change: 1 addition & 0 deletions database/models/Guild.py
Comment thread
Kyrela marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class Guild(DiscordRepresentation):
'roles_use_any_rule': bool,
'reply_to_message': bool,
'reply_silently': bool,
'reply_as_original_author_replica': bool,
'webhooks': bool,
'original_message': OriginalMessage,
'twitter_view': FxEmbedView,
Expand Down
12 changes: 11 additions & 1 deletion locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ settings:
read_message_history:
"true": "🟢 `Read message history` permission"
"false": "🔴 Missing `read message history` permission"
manage_webhooks:
"true": "🟢 `Manage webhooks` permission"
"false": "🔴 Missing `manage webhooks` permission"
filters:
button:
toggle:
Expand Down Expand Up @@ -148,7 +151,7 @@ settings:
reply_method:
name: "Reply method"
description: "Change the behavior on the reply"
content: "**Change what to do on the reply**\n- %{state}\n- %{silent}%{perms}"
content: "**Change what to do on the reply**\n- %{state}\n- %{silent}\n- %{replica}%{perms}"
reply:
button:
"true": "Replying"
Expand All @@ -163,6 +166,13 @@ settings:
state:
"true": "🔕 Send silently"
"false": "🔔 Send with a notification"
original_author_replica:
button:
"true": "Send as Original Author Replica"
Comment thread
Kyrela marked this conversation as resolved.
Outdated
"false": "Send as %{bot}"
state:
"true": "🪪 Send as Original Author Replica"
"false": "🤖 Send as %{bot}"
webhooks:
name: "Webhooks"
description: "Enable/Disable for webhooks"
Expand Down
12 changes: 11 additions & 1 deletion locales/ko.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ settings:
read_message_history:
"true": "🟢 `메시지 기록 보기` 권한"
"false": "🔴 `메시지 기록 보기` 권한 없음"
manage_webhooks:
"true": "🟢 `웹후크 관리하기` 권한"
"false": "🔴 `웹후크 관리하기` 권한 없음"
filters:
button:
toggle:
Expand Down Expand Up @@ -145,7 +148,7 @@ settings:
reply_method:
name: "답장 방법"
description: "답장할 때의 동작 변경하기"
content: "**답장할 때 수행할 작업 변경하기**\n- %{state}\n- %{silent}%{perms}"
content: "**답장할 때 수행할 작업 변경하기**\n- %{state}\n- %{silent}\n- %{replica}%{perms}"
reply:
button:
"true": "답장"
Expand All @@ -160,6 +163,13 @@ settings:
state:
"true": "🔕 조용히 보내기"
"false": "🔔 알림과 함께 보내기"
original_author_replica:
button:
"true": "원본 작성자 복제본으로 보내기"
"false": "%{bot}(으)로 보내기"
state:
"true": "🪪 원본 작성자 복제본으로 보내기"
"false": "🤖 %{bot}(으)로 보내기"
webhooks:
name: "웹후크"
description: "웹후크 활성화/비활성화하기"
Expand Down
42 changes: 38 additions & 4 deletions src/settings.py
Comment thread
Kyrela marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ async def embed(self) -> discore.Embed:
perms.append('manage_messages')
if self.ctx.guild.reply_to_message:
perms.append('read_message_history')
if self.ctx.guild.reply_as_original_author_replica:
perms.append('manage_webhooks')
embed.add_field(
name=t('settings.troubleshooting.permissions', channel=self.ctx.channel.mention),
value=format_perms(perms, self.ctx.channel.discord_object, include_label=False, include_valid=True),
Expand Down Expand Up @@ -1123,7 +1125,8 @@ class ReplyMethodSetting(BaseSetting):

def __init__(self, interaction: discore.Interaction, view: SettingsView, ctx: DataElements):
super().__init__(interaction, view, ctx)
self.reply_to_message = bool(ctx.guild.reply_to_message)
self.reply_as_original_author_replica = bool(ctx.guild.reply_as_original_author_replica)
self.reply_to_message = bool(ctx.guild.reply_to_message and not self.reply_as_original_author_replica)
self.reply_silently = bool(ctx.guild.reply_silently)

@property
Expand All @@ -1137,21 +1140,31 @@ async def embed(self) -> discore.Embed:
perms.append('send_messages_in_threads')
if self.reply_to_message:
perms.append('read_message_history')
if self.reply_as_original_author_replica:
perms.append('manage_webhooks')
embed = discore.Embed(
title=f"{self.emoji} {t(self.name)}",
description=t(
'settings.reply_method.content',
state=t(f'settings.reply_method.reply.state.{l(self.reply_to_message)}', emoji=self.emoji),
silent=t(f'settings.reply_method.silent.state.{l(self.reply_silently)}'),
replica=t(
f'settings.reply_method.original_author_replica.state.{l(self.reply_as_original_author_replica)}',
bot=self.ctx.guild.discord_object.me.display_name),
Comment thread
Kyrela marked this conversation as resolved.
Outdated
perms=format_perms(perms, self.ctx.channel.discord_object))
)
discore.set_embed_footer(self.bot, embed)
return embed

@property
async def option(self) -> discore.SelectOption:
has_missing_perms = (
(self.reply_to_message and is_missing_perm(['read_message_history'], self.ctx.channel.discord_object))
or (self.reply_as_original_author_replica
and is_missing_perm(['manage_webhooks'], self.ctx.channel.discord_object))
)
return discore.SelectOption(
label=('⚠️ ' if self.reply_to_message and is_missing_perm(['read_message_history'], self.ctx.channel.discord_object) else '')
label=('⚠️ ' if has_missing_perms else '')
+ t(self.name),
value=self.id,
description=t(self.description),
Expand All @@ -1163,7 +1176,8 @@ async def items(self) -> List[discore.ui.Item]:
reply_to_message_button = discore.ui.Button(
style=discore.ButtonStyle.primary if self.reply_to_message else discore.ButtonStyle.secondary,
label=t(f'settings.reply_method.reply.button.{l(self.reply_to_message)}'),
custom_id=self.id
custom_id=self.id,
disabled=self.reply_as_original_author_replica
)
edit_callback(reply_to_message_button, self.view, self.toggle_reply_to_message)
reply_silently_button = discore.ui.Button(
Expand All @@ -1172,9 +1186,19 @@ async def items(self) -> List[discore.ui.Item]:
custom_id='reply_silently'
)
edit_callback(reply_silently_button, self.view, self.toggle_reply_silently)
return [reply_to_message_button, reply_silently_button]
original_author_replica_button = discore.ui.Button(
style=discore.ButtonStyle.primary if self.reply_as_original_author_replica else discore.ButtonStyle.secondary,
label=t(
f'settings.reply_method.original_author_replica.button.{l(self.reply_as_original_author_replica)}',
bot=self.ctx.guild.discord_object.me.display_name),
Comment thread
Kyrela marked this conversation as resolved.
Outdated
custom_id='reply_as_original_author_replica'
)
edit_callback(original_author_replica_button, self.view, self.toggle_reply_as_original_author_replica)
return [reply_to_message_button, reply_silently_button, original_author_replica_button]

async def toggle_reply_to_message(self, view: SettingsView, interaction: discore.Interaction, _) -> None:
if self.reply_as_original_author_replica:
return
self.reply_to_message = not self.reply_to_message
self.ctx.guild.update({'reply_to_message': self.reply_to_message})
await view.refresh(interaction)
Expand All @@ -1184,6 +1208,16 @@ async def toggle_reply_silently(self, view: SettingsView, interaction: discore.I
self.ctx.guild.update({'reply_silently': self.reply_silently})
await view.refresh(interaction)

async def toggle_reply_as_original_author_replica(self, view: SettingsView, interaction: discore.Interaction, _) -> None:
self.reply_as_original_author_replica = not self.reply_as_original_author_replica
if self.reply_as_original_author_replica:
self.reply_to_message = False
self.ctx.guild.update({
'reply_as_original_author_replica': self.reply_as_original_author_replica,
'reply_to_message': self.reply_to_message
})
await view.refresh(interaction)


class WebhooksSetting(BaseSetting):
"""Represents the webhooks setting (respond to webhooks or not)"""
Expand Down
Loading