diff --git a/command/destroy/channel2.mts b/command/destroy/channel2.mts index f49bb97..12c65ed 100644 --- a/command/destroy/channel2.mts +++ b/command/destroy/channel2.mts @@ -48,7 +48,7 @@ interface Options { spinner.loading("Create client") let channelClient: ChannelClient | undefined = undefined - let discordClient: DiscordClient | null = null + let discordClient: DiscordClient | undefined = undefined try { channelClient = new ChannelClient() discordClient = await createDiscordClient(discordBotToken, discordServerId) diff --git a/command/destroy/message2.mts b/command/destroy/message2.mts new file mode 100644 index 0000000..f2fb441 --- /dev/null +++ b/command/destroy/message2.mts @@ -0,0 +1,71 @@ +import { Command } from "commander" +import dotenv from "dotenv" +import type { Guild as DiscordClient } from "discord.js" +import prompts from "prompts" +import { Spinner } from "../../libs/util/spinner.mjs" +import { createDiscordClient } from "../../libs/client.mjs" +import { MessageClient } from "../../libs/message2.mjs" + +dotenv.config({ path: "./.env" }) +const spinner = new Spinner() + +interface Options { + discordBotToken?: string + discordServerId?: string +} + +;(async () => { + const confirm = await prompts({ + type: "confirm", + name: "value", + message: "Destroy message?", + }) + if (!confirm.value) process.exit(0) + + const program = new Command() + program + .description("Destroy message command") + .requiredOption( + "-dt, --discord-bot-token [string]", + "DiscordBot OAuth Token", + process.env.DISCORD_BOT_TOKEN + ) + .requiredOption( + "-ds, --discord-server-id [string]", + "Discord Server ID", + process.env.DISCORD_SERVER_ID + ) + .parse(process.argv) + + spinner.loading("Check parameter") + const options: Options = program.opts() + const { discordBotToken, discordServerId } = options + if (discordBotToken === undefined || discordServerId === undefined) { + spinner.failed(null, "Required parameter is not found") + process.exit(1) + } + spinner.success() + + spinner.loading("Create client") + let messageClient: MessageClient | undefined = undefined + let discordClient: DiscordClient | null = null + try { + messageClient = new MessageClient() + discordClient = await createDiscordClient(discordBotToken, discordServerId) + } catch (error) { + spinner.failed(null, error) + process.exit(1) + } + spinner.success() + + spinner.loading("Destroy message") + try { + await messageClient.destroyAllMessage(discordClient) + } catch (error) { + spinner.failed(null, error) + process.exit(1) + } + spinner.success() + + process.exit(0) +})() diff --git a/command/destroy/user2.mts b/command/destroy/user2.mts index be3e6ad..343ed24 100644 --- a/command/destroy/user2.mts +++ b/command/destroy/user2.mts @@ -48,7 +48,7 @@ interface Options { spinner.loading("Create client") let userClient: UserClient | undefined = undefined - let discordClient: DiscordClient | null = null + let discordClient: DiscordClient | undefined = undefined try { userClient = new UserClient() discordClient = await createDiscordClient(discordBotToken, discordServerId) diff --git a/libs/category2.mts b/libs/category2.mts index 963086a..21dcf74 100644 --- a/libs/category2.mts +++ b/libs/category2.mts @@ -50,7 +50,7 @@ export class CategoryClient { const categories = await this.getAllCategory(true) // Destroy all discord category - await Promise.all( + const newCategories = await Promise.all( categories.map(async (category) => { try { if (!category.deployId) @@ -63,19 +63,27 @@ export class CategoryClient { throw error } } + + const newCategory = (() => category)() + newCategory.deployId + + return newCategory }) ) + // Update all category data + await this.updateManyCategory(newCategories) + // Delete all category data - await this.client.category.deleteMany({ - where: { - deployId: { - not: { - equals: null, - }, - }, - }, - }) + // await this.client.category.deleteMany({ + // where: { + // deployId: { + // not: { + // equals: null, + // }, + // }, + // }, + // }) } /** diff --git a/libs/channel2.mts b/libs/channel2.mts index 7a285d4..d57ec21 100644 --- a/libs/channel2.mts +++ b/libs/channel2.mts @@ -139,12 +139,15 @@ export class ChannelClient { /** * Destroy single channel * @param discordClient - * @param channelDeployId + * @param channel */ - async destroyChannel(discordClient: DiscordClient, channelDeployId: string) { + async destroyChannel(discordClient: DiscordClient, channel: Channel) { + // Skip undeployed channel + if (!channel.deployId) return + // Destroy discord channel try { - await discordClient.channels.delete(channelDeployId) + await discordClient.channels.delete(channel.deployId) } catch (error) { if (error instanceof DiscordAPIError && error.code == 10003) { // Do not throw error if channel to be deleted does not exist @@ -153,12 +156,17 @@ export class ChannelClient { } } + // Update channel data + const newChannel = (() => channel)() + newChannel.deployId = null + await this.updateChannel(newChannel) + // Delete channel data - await this.client.channel.delete({ - where: { - deployId: channelDeployId, - }, - }) + // await this.client.channel.delete({ + // where: { + // deployId: channelDeployId, + // }, + // }) } /** @@ -225,7 +233,7 @@ export class ChannelClient { const channels = await this.getAllChannel(true) // Destroy all channel - await Promise.all( + const newChannels = await Promise.all( channels.map(async (channel) => { try { if (channel.deployId) @@ -237,20 +245,26 @@ export class ChannelClient { throw error } } + + const newChannel = (() => channel)() + newChannel.deployId = null + return channel }) ) + await this.updateManyChannel(newChannels) + // Delete all channel data - await this.client.channel.deleteMany({ - where: { - deployId: { - not: { - equals: null, - }, - }, - type: 1, - }, - }) + // await this.client.channel.deleteMany({ + // where: { + // deployId: { + // not: { + // equals: null, + // }, + // }, + // type: 1, + // }, + // }) // Destroy all category await this.categoryClient.destroyAllCategory(discordClient) diff --git a/libs/message2.mts b/libs/message2.mts index 257daac..d1b5b0e 100644 --- a/libs/message2.mts +++ b/libs/message2.mts @@ -209,6 +209,83 @@ export class MessageClient { } } + /** + * Destroy all message + */ + async destroyAllMessage(discordClient: DiscordClient) { + // Get all channel data + const channels = await this.channelClient.getAllChannel() + + // Delete all messages + await Promise.all( + channels.map(async (channel) => { + if (!channel.deployId) + throw new Error(`Failed to deployed channel id of ${channel.name}`) + + const channelManager = discordClient.channels.cache.get( + channel.deployId + ) + if ( + channelManager === undefined || + channelManager.type !== ChannelType.GuildText + ) + throw new Error(`Failed to get channel manager of ${channel.id}`) + + // Pagination message + const take = 100 + let skip = 0 + const total = await this.client.message.count({ + where: { + channelDeployId: channel.deployId, + }, + }) + while (skip < total) { + const messages = await this.client.message.findMany({ + take: take, + skip: skip, + where: { + channelDeployId: channel.deployId, + }, + orderBy: { + timestamp: "asc", + }, + }) + + // Destroy many message + await this.destroyManyMessage(channelManager, messages) + + skip += take + } + }) + ) + } + + /** + * Destroy many message + * @param channelManager + * @param messages + */ + async destroyManyMessage(channelManager: TextChannel, messages: Message[]) { + const newMessages = await Promise.all( + messages + // Skip destroy undeployed message + .filter((message) => message.deployId) + .map(async (message) => { + // Destroy message + // FIXME: Want to avoid forced type casting + await channelManager.messages.delete(message.deployId as string) + + const newMessage = (() => message)() + newMessage.deployId = null + + return newMessage + }) + ) + + // Update deployed message + await this.updateManyMessage(newMessages) + } + /** * Get slack message file * @param messageFilePath diff --git a/libs/user2.mts b/libs/user2.mts index ddd96f6..4b376e5 100644 --- a/libs/user2.mts +++ b/libs/user2.mts @@ -278,6 +278,6 @@ export class UserClient { // TODO: Destroy all message for channel for hosting user image // Destroy channel for hosting user image - await this.channelClient.destroyChannel(discordClient, userChannel.deployId) + await this.channelClient.destroyChannel(discordClient, userChannel) } } diff --git a/package.json b/package.json index eff714e..db90480 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "deploy:message": "node --loader ts-node/esm ./command/deploy/message2.mts", "destroy": "yes | run-s destroy:*", "destroy:user": "node --loader ts-node/esm ./command/destroy/user2.mts", - "destroy:message": "node --loader ts-node/esm ./command/destroy/message.mts", + "destroy:message": "node --loader ts-node/esm ./command/destroy/message2.mts", "destroy:channel": "node --loader ts-node/esm ./command/destroy/channel2.mts", "start": "run-s build deploy", "update": "npx ncu -u && npm install",