diff --git a/src/events/interactionCreate/button/approveSubmission.ts b/src/events/interactionCreate/button/approveSubmission.ts index 57bca51..0417a3d 100644 --- a/src/events/interactionCreate/button/approveSubmission.ts +++ b/src/events/interactionCreate/button/approveSubmission.ts @@ -14,7 +14,7 @@ export const customId = 'submissionApproveButton'; export class ApproveSubmissionButton implements PermanentButtonInteraction { public customId = customId; public async execute(interaction: ButtonInteraction) { - if (!interaction.inGuild() || !interaction.channel) return; + if (!interaction.inGuild() || !interaction.channel?.isThread()) return; const permissions = interaction.member.permissions as PermissionsBitField; @@ -50,16 +50,22 @@ export class ApproveSubmissionButton implements PermanentButtonInteraction { return; } + await interaction.reply('Başvuru onaylandı.'); + try { await submitter.roles.add(configuration.submission.role); } catch { - await interaction.reply({ - content: 'Başvuru sahibine rol verilemedi.', - ephemeral: true, - }); + await interaction.editReply('Başvuru sahibine rol verilemedi.'); return; } + try { + await interaction.channel.setLocked(true); + await interaction.channel.setArchived(true); + } catch { + await interaction.followUp('Alt başlık arşivlenemedi.'); + } + logger.info( `Approved submission of [${submitter.user.tag}](${submitter.user.id}) by [${interaction.user.tag}](${interaction.user.id})` ); @@ -67,16 +73,7 @@ export class ApproveSubmissionButton implements PermanentButtonInteraction { logger.channel( 'submission', interaction.client, - `${submitter.user} hesabının başvurusu ${interaction.user} tarafından onaylandı.` + `${submitter.user} hesabının başvurusu ${interaction.user} tarafından onaylandı: ${interaction.channel}` ); - - try { - await interaction.channel.delete(); - } catch { - await interaction.reply({ - content: 'Başvuru onaylandı fakat alt başlık silinemedi.', - ephemeral: true, - }); - } } } diff --git a/src/events/interactionCreate/button/createSubmission.ts b/src/events/interactionCreate/button/createSubmission.ts index bdb19dd..67021be 100644 --- a/src/events/interactionCreate/button/createSubmission.ts +++ b/src/events/interactionCreate/button/createSubmission.ts @@ -3,7 +3,7 @@ import { type ButtonInteraction, type ModalActionRowComponentBuilder as ModalActionRow, ModalBuilder, - type TextChannel, + TextChannel, TextInputBuilder, TextInputStyle, } from 'discord.js'; @@ -17,13 +17,12 @@ export const customId = 'submissionCreateButton'; export class CreateSubmissionButton implements PermanentButtonInteraction { public customId = customId; public async execute(interaction: ButtonInteraction) { - if (!interaction.channel || !interaction.channel.isTextBased()) return; + if (!(interaction.channel instanceof TextChannel)) return; - const channel = interaction.channel as TextChannel; - const channelThreads = await channel.threads.fetch(); + const threadManager = await interaction.channel.threads.fetch(); - const thread = channelThreads.threads.find((thread) => - thread.name.endsWith(interaction.user.id) + const thread = threadManager.threads.find( + (thread) => thread.name.endsWith(interaction.user.id) && !thread.locked ); if (thread) { @@ -52,10 +51,6 @@ export class CreateSubmissionButton implements PermanentButtonInteraction { return; } - // note: there is a limit of max threads per guild (1000), it'ld better to - // check if it's reached but it's quite impossible to reach that limit - // so i'll ignore it for now. - const modal = new ModalBuilder() .setCustomId(modalId) .setTitle('Başvuru Formu'); diff --git a/src/events/interactionCreate/button/denySubmission.ts b/src/events/interactionCreate/button/denySubmission.ts index 31be503..1de1250 100644 --- a/src/events/interactionCreate/button/denySubmission.ts +++ b/src/events/interactionCreate/button/denySubmission.ts @@ -13,7 +13,7 @@ export const customId = 'submissionDenyButton'; export class DenySubmissionButton implements PermanentButtonInteraction { public customId = customId; public async execute(interaction: ButtonInteraction) { - if (!interaction.inGuild() || !interaction.channel) return; + if (!interaction.inGuild() || !interaction.channel?.isThread()) return; const permissions = interaction.member.permissions as PermissionsBitField; @@ -26,12 +26,19 @@ export class DenySubmissionButton implements PermanentButtonInteraction { messageContent.indexOf('>') ); - let submitter: User | null; + let submitter: User | null = null; try { submitter = await interaction.client.users.fetch(submitterId); + } catch {} + + await interaction.reply('Başvuru reddedildi.'); + + try { + await interaction.channel.setLocked(true); + await interaction.channel.setArchived(true); } catch { - submitter = null; + await interaction.followUp('Alt başlık arşivlenemedi.'); } logger.info( @@ -41,16 +48,7 @@ export class DenySubmissionButton implements PermanentButtonInteraction { logger.channel( 'submission', interaction.client, - `<@${submitterId}> hesabının başvurusu ${interaction.user} tarafından reddedildi.` + `<@${submitterId}> hesabının başvurusu ${interaction.user} tarafından reddedildi: ${interaction.channel}` ); - - try { - await interaction.channel.delete(); - } catch { - await interaction.reply({ - content: 'Başvuru reddedildi fakat alt başlık silinemedi.', - ephemeral: true, - }); - } } } diff --git a/src/events/interactionCreate/modal/createSubmission.ts b/src/events/interactionCreate/modal/createSubmission.ts index 09004c1..8cc0f5d 100644 --- a/src/events/interactionCreate/modal/createSubmission.ts +++ b/src/events/interactionCreate/modal/createSubmission.ts @@ -5,7 +5,7 @@ import { ChannelType, type MessageActionRowComponentBuilder as MessageActionRow, type ModalSubmitInteraction, - type TextChannel, + TextChannel, ThreadAutoArchiveDuration, } from 'discord.js'; @@ -20,11 +20,9 @@ export const customId = 'createSubmissionModal'; export class CreateSubmissionModal implements ModalInteraction { public customId = customId; public async execute(interaction: ModalSubmitInteraction) { - if (!interaction.channel || !interaction.channel.isTextBased()) return; + if (!(interaction.channel instanceof TextChannel)) return; - const channel = interaction.channel as TextChannel; - - const thread = await channel.threads.create({ + const thread = await interaction.channel.threads.create({ name: `${interaction.user.username} #${interaction.user.id}`, autoArchiveDuration: ThreadAutoArchiveDuration.OneWeek, type: ChannelType.PrivateThread, diff --git a/src/logger.ts b/src/logger.ts index b33c6b5..a3ac3b2 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,4 +1,4 @@ -import type { Client } from 'discord.js'; +import type { Client, MessageCreateOptions } from 'discord.js'; import { once } from 'events'; import pino from 'pino'; import pretty from 'pino-pretty'; @@ -8,7 +8,12 @@ import { name } from '@/package'; type Channel = 'verify' | 'submission'; type ExtendedLogger = pino.Logger & { - channel: (channel: Channel, client: Client, message: string) => Promise; + channel: ( + channel: Channel, + client: Client, + message: string, + options?: MessageCreateOptions + ) => Promise; }; const channels: Record = { @@ -36,7 +41,8 @@ async function createLogger() { logger.channel = async ( channel: Channel, client: Client, - message: string + message: string, + options?: MessageCreateOptions ) => { try { const textChannel = await client.channels.fetch(channels[channel]); @@ -52,6 +58,7 @@ async function createLogger() { await textChannel.send({ content: message, allowedMentions: { parse: [] }, + ...options, }); } catch (error) { logger.error( diff --git a/src/utils/time.ts b/src/utils/time.ts index 4938df8..9097375 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -18,3 +18,14 @@ export function timestamp(date: Date, format?: Format): string { format ? ':' + format : '' }>`; } + +export function ISO8601(date: Date): string { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; +}