diff --git a/src/commands/index.ts b/src/commands/index.ts index bc4350b..6f18a6b 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,119 +1,120 @@ -import { ButtonInteraction, CommandInteraction, GuildMember, Routes } from 'discord.js' -import { Command, Context, He4rtClient } from '@/types' -import { useAnnounce } from './announce' -import { useBan } from './ban' -import { useColor } from './color' -import { useDaily } from './daily' -import { useIntroduction } from './introduction' -import { useProfileGet } from './profile/profile_get' -import { useRanking } from './ranking' -import { useUnban } from './unban' -import { useChat } from './chat' -import { useTimeout } from './timeout' -import { useSay } from './say' -import { useCode } from './code' -import { useClear } from './clear' -import { useApoiase } from './apoiase' -import { useVersion } from './version' -import { useAsk } from './ask' -import { getTargetMember } from '@/utils' -import { useProfilePut } from './profile/profile_put' -import { useBadgeRedeem } from './badge/badge_redeem' -import { useRolePost } from './role/role_post' -import { useRoleDelete } from './role/role_delete' -import { resolveJudgeCommandButtonEvents, useJudge } from './judge' -import { useForumClose } from './forum/forum_close' -import { useForumCreate } from './forum/forum_create' -import { useDynamicVoice } from './dynamic_voice/dynamic_voice_create' -import { useDynamicVoiceSize } from './dynamic_voice/dynamic_voice_size' -import { useDynamicVoiceOwner } from './dynamic_voice/dynamic_voice_owner' -import { useStageATA } from './stage/stage_ata' -import { useStageStart } from './stage/stage_start' -import { useStageFinish } from './stage/stage_finish' -import { useOnboardingVoluntary } from './onboarding/onboarding_voluntary' -import { useOnboardingRequire } from './onboarding/onboarding_require' -import { useOnboardingFinalize } from './onboarding/onboarding_finalize' -import { useOnboardingQuit } from './onboarding/onboarding_quit' -import { useOnboardingWhy } from './onboarding/onboarding_why' -import { useDynamicVoiceTitle } from './dynamic_voice/dynamic_voice_title' -import { useMedal } from './medal/medal_set' -import { useMedalAdd } from './medal/medal_add' -import { useWatch } from './watch/watch_set' -import { useWatchList } from './watch/watch_get' -import { useWatchRemove } from './watch/watch_remove' - -const registerHooks = (client: He4rtClient, commands: Command[]) => { - commands.forEach(([data, cb]) => { - client.commands.set(data, cb) - }) -} - -export const registerCommands = async ({ client, rest }: Context) => { - registerHooks(client, [ - useIntroduction(), - useAnnounce(), - useColor(), - useBan(), - useUnban(), - useRanking(), - useDaily(), - useProfileGet(), - useProfilePut(), - useChat(), - useTimeout(), - useSay(), - useCode(), - useClear(), - useApoiase(), - useVersion(), - useAsk(), - useBadgeRedeem(), - useRolePost(), - useRoleDelete(), - useJudge(), - useForumClose(), - useForumCreate(), - useDynamicVoice(), - useDynamicVoiceSize(), - useDynamicVoiceOwner(), - useDynamicVoiceTitle(), - useStageATA(), - useStageFinish(), - useStageStart(), - useOnboardingVoluntary(), - useOnboardingRequire(), - useOnboardingFinalize(), - useOnboardingQuit(), - useOnboardingWhy(), - useMedal(), - useMedalAdd(), - useWatch(), - useWatchList(), - useWatchRemove(), - // useReputation() - ]) - - await rest.put(Routes.applicationGuildCommands(process.env.DISCORD_CLIENT_ID, process.env.DISCORD_GUILD_ID), { - body: [...client.commands.keys()], - }) -} - -export const commandsListener = (client: He4rtClient, interaction: CommandInteraction) => { - for (const [key, cb] of client.commands) { - if (key.name === interaction.commandName) { - cb && cb(interaction, client) - - client.logger.emit({ - message: `${getTargetMember(interaction.member as GuildMember)} acionou **/${key.name}** no canal **${ - interaction.channel.name - }**`, - type: 'command', - color: 'info', - }) - } - } -} - -export const buttonListener = async (client: He4rtClient, interaction: ButtonInteraction) => { - await resolveJudgeCommandButtonEvents(client, interaction) -} +import { ButtonInteraction, CommandInteraction, GuildMember, Routes } from 'discord.js' +import { Command, Context, He4rtClient } from '@/types' +import { useAnnounce } from './announce' +import { useBan } from './ban' +import { useColor } from './color' +import { useDaily } from './daily' +import { useIntroduction } from './introduction' +import { useProfileGet } from './profile/profile_get' +import { useRanking } from './ranking' +import { useUnban } from './unban' +import { useChat } from './chat' +import { useTimeout } from './timeout' +import { useSay } from './say' +import { useCode } from './code' +import { useClear } from './clear' +import { useApoiase } from './apoiase' +import { useVersion } from './version' +import { useAsk } from './ask' +import { getTargetMember } from '@/utils' +import { useProfilePut } from './profile/profile_put' +import { useBadgeRedeem } from './badge/badge_redeem' +import { useRolePost } from './role/role_post' +import { useRoleDelete } from './role/role_delete' +import { resolveJudgeCommandButtonEvents, useJudge } from './judge' +import { useForumClose } from './forum/forum_close' +import { useForumCreate } from './forum/forum_create' +import { useDynamicVoice } from './dynamic_voice/dynamic_voice_create' +import { useDynamicVoiceSize } from './dynamic_voice/dynamic_voice_size' +import { useDynamicVoiceOwner } from './dynamic_voice/dynamic_voice_owner' +import { useStageATA } from './stage/stage_ata' +import { useStageStart } from './stage/stage_start' +import { useStageFinish } from './stage/stage_finish' +import { useOnboardingVoluntary } from './onboarding/onboarding_voluntary' +import { useOnboardingRequire } from './onboarding/onboarding_require' +import { useOnboardingFinalize } from './onboarding/onboarding_finalize' +import { useOnboardingQuit } from './onboarding/onboarding_quit' +import { useOnboardingWhy } from './onboarding/onboarding_why' +import { useDynamicVoiceTitle } from './dynamic_voice/dynamic_voice_title' +import { useMedal } from './medal/medal_set' +import { useMedalAdd } from './medal/medal_add' +import { useWatch } from './watch/watch_set' +import { useWatchList } from './watch/watch_get' +import { useWatchRemove } from './watch/watch_remove' +import { useQuizEvent } from './quiz_event' + +const registerHooks = (client: He4rtClient, commands: Command[]) => { + commands.forEach(([data, cb]) => { + client.commands.set(data, cb) + }) +} + +export const registerCommands = async ({ client, rest }: Context) => { + registerHooks(client, [ + useIntroduction(), + useAnnounce(), + useColor(), + useBan(), + useUnban(), + useRanking(), + useDaily(), + useProfileGet(), + useProfilePut(), + useChat(), + useTimeout(), + useSay(), + useCode(), + useClear(), + useApoiase(), + useVersion(), + useAsk(), + useBadgeRedeem(), + useRolePost(), + useRoleDelete(), + useJudge(), + useForumClose(), + useForumCreate(), + useDynamicVoice(), + useDynamicVoiceSize(), + useDynamicVoiceOwner(), + useDynamicVoiceTitle(), + useStageATA(), + useStageFinish(), + useStageStart(), + useOnboardingVoluntary(), + useOnboardingRequire(), + useOnboardingFinalize(), + useOnboardingQuit(), + useOnboardingWhy(), + useMedal(), + useMedalAdd(), + useWatch(), + useWatchList(), + useWatchRemove(), + useQuizEvent() + ]) + + await rest.put(Routes.applicationGuildCommands(process.env.DISCORD_CLIENT_ID, process.env.DISCORD_GUILD_ID), { + body: [...client.commands.keys()], + }) +} + +export const commandsListener = (client: He4rtClient, interaction: CommandInteraction) => { + for (const [commandSet, commandCallBack] of client.commands) { + if (commandSet.name === interaction.commandName) { + commandCallBack && commandCallBack(interaction, client) + + client.logger.emit({ + message: `${getTargetMember(interaction.member as GuildMember)} acionou **/${commandSet.name}** no canal **${ + interaction.channel.name + }**`, + type: 'command', + color: 'info', + }) + } + } +} + +export const buttonListener = async (client: He4rtClient, interaction: ButtonInteraction) => { + await resolveJudgeCommandButtonEvents(client, interaction) +} diff --git a/src/commands/quiz_event.ts b/src/commands/quiz_event.ts new file mode 100644 index 0000000..57c9945 --- /dev/null +++ b/src/commands/quiz_event.ts @@ -0,0 +1,177 @@ +import { CommandInteraction, DMChannel, GuildMember, HexColorString, SlashCommandBuilder } from 'discord.js' +import { Command, He4rtClient } from '@/types' +import { QUIZ_EVENT } from '@/defines/ids.json' +import QUIZ from '-/commands/quiz_event.json' +import { START_CODE_CHALLENGE } from '@/defines/commands.json' +import { TIMEOUT_ANSWER, TIMEOUT_COMMAND_STRING, COLORS } from '@/defines/values.json' +import { getChannel, reply, sendInDM } from '@/utils' +import { embedTemplate } from '@/utils' +import { checkUserEventEntry, claimEventReward, getActiveEvent, getEventQuizzesById } from '@/http/firebase' + +const HINT_COMMMAND = '!dica' + +const nextTextMessage = async (dm: DMChannel, interaction: CommandInteraction): Promise => { + try { + const result = await dm.awaitMessages({ + filter: (m) => m.author.id === interaction.user.id, + time: TIMEOUT_ANSWER, + max: 1, + }) + + return result.first()!.content + } catch { + return TIMEOUT_COMMAND_STRING + } +} + +const nextMultipleRoleSelection = async ( + roles: any[], + text: string, + dm: DMChannel, + member: GuildMember, + interaction: CommandInteraction +) => { + await dm.send(text) + await dm.send( + roles.reduce((acc, val, index) => (acc += `**${index + 1}**` + ` - ${val.emoji} ${val.name}` + '\n'), '\n') + ) + const myEmbed = embedTemplate({ + title: '', + description: QUIZ.CONTINUE, + }) + + await dm.send({ embeds: [myEmbed] }) + await nextMultipleRoleSelection(roles, text, dm, member, interaction) +} + +const nextStringsData = async (dm: DMChannel, interaction: CommandInteraction, client: He4rtClient, eventId: string): Promise => { + + const quizzes = await getEventQuizzesById(client, eventId) + + for (const quiz of quizzes) { + const embed = embedTemplate({ title: quiz.title, description: quiz.question }) + await dm.send({ embeds: [embed] }) + + const wrongResponse = createEmbedResponse(COLORS.ERROR as HexColorString, 'Excelente tentativa, mas a resposta não está correta.', 'Essa foi a resposta errada.') + const rightResponse = createEmbedResponse(COLORS.SUCCESS as HexColorString, 'Ótima resposta, aqui vai a próxima!', `Respostas: **${quiz.answer}**`) + const hintResponse = createEmbedResponse(COLORS.HINT_ANSWER as HexColorString, quiz.tip) + const finishEventResponse = createEmbedResponse(null, 'Parabéns!! você conseguiu concluir o evento🎉🎉🎉') + + + async function handleUserInput() { + const userInput = await nextTextMessage(dm, interaction) + const regex = new RegExp('\\b' + userInput.toLowerCase() + '\\b'); + + const inputResult = userInput === HINT_COMMMAND ? 'hint' + : !regex.test(quiz.answer.toLowerCase()) ? 'retry' + : quiz.has_next_question ? 'continue' : 'finished' + + const actions = { + hint: () => dm.send({embeds: [hintResponse]}), + retry: () => { + dm.send('💥') + dm.send({embeds: [wrongResponse]}) + }, + continue: () => dm.send({ embeds: [rightResponse]}), + finished: () => dm.send({ embeds: [finishEventResponse]}) + } + + const result = actions[inputResult] || actions.finished + result() + + if(inputResult === 'hint' || inputResult === 'retry') + await handleUserInput() + + } + + await handleUserInput() + } +} + +const validateAccess = async (dm: DMChannel, interaction: CommandInteraction): Promise => { + const myEmbed = embedTemplate({ + title: 'Evento de programação', + description: QUIZ.CONTINUE, + }) + await sendInDM(dm, interaction, '', myEmbed) + + if (!sendInDM) return false + + await reply(interaction).successInAccessDM() + + return true +} + + +export const useQuizEvent = (): Command => { + const data = new SlashCommandBuilder() + .setName(START_CODE_CHALLENGE.TITLE) + .setDescription(START_CODE_CHALLENGE.DESCRIPTION) + .setDMPermission(true) + + return [ + data, + async (interaction, client) => { + const author = interaction.user + const member = interaction.member as GuildMember + + const activeEventId = await getActiveEvent(client) + if (!activeEventId) { + await reply(interaction).errorEventNotFound() + return + } + + const isUserEligible = await checkUserEventEntry(client, { eventId: activeEventId, userId: interaction.user.id }) + + if (!isUserEligible) { + await reply(interaction).errorParticipantFail() + return + } + + const places = { + first: 'primeiro', + second: 'segundo', + third: 'terceiro', + } + + client.users + .createDM(author) + .then(async (dm) => { + const valid = await validateAccess(dm, interaction) + + if (!valid) return + + await nextStringsData(dm, interaction, client, activeEventId) + + const channel = getChannel({ id: QUIZ_EVENT.id, client }) + const claimedReward = await claimEventReward(client, activeEventId, interaction.user.id) + await member.roles.add(claimedReward.badge) + + let participantMessage = QUIZ.REWARD_PARTICIPANT + participantMessage = participantMessage + .replace('{user}', `${author.username}`) + .replace('{exp}', `${claimedReward.he4rt_xp} XP`) + + const participantEmbed = embedTemplate({title: participantMessage}) + + const winnerEmbed = embedTemplate({ + title: `${author.username} conseguiu responder todas as perguntas com sucesso!`, + description: `Como recompensa do ${places[claimedReward.place]} lugar ganhou **${claimedReward.he4rt_xp}** de experiência!` + }) + + claimedReward.place !== 'participant' + ? channel.send({ embeds: [winnerEmbed] }) + : dm.send({ embeds: [(participantEmbed)]}) + + }) + .catch(() => {}) + .finally(async () => {}) + }, + ] +} + +const createEmbedResponse = (color: HexColorString, title: string, description?: string) => embedTemplate({ + title, + description, + color +}) diff --git a/src/defines/commands.json b/src/defines/commands.json index 5e69bbe..0c2ffb1 100644 --- a/src/defines/commands.json +++ b/src/defines/commands.json @@ -1,178 +1,182 @@ -{ - "INTRODUCE": { - "TITLE": "apresentar", - "DESCRIPTION": "Se apresente para os membros de nossa comunidade e ganhe cargos!" - }, - "ANNOUNCE": { - "TITLE": "anunciar", - "DESCRIPTION": "ADM: Anuncie no canal de anúncios com o uso do everyone automático." - }, - "COLOR": { - "TITLE": "cor", - "DESCRIPTION": "APOIADORES: Como um apoiador, você pode ter uma tag colorida customizada!" - }, - "BAN": { - "TITLE": "banir", - "DESCRIPTION": "ADM: Escolha um usuário para ser banido do servidor." - }, - "UNBAN": { - "TITLE": "desbanir", - "DESCRIPTION": "ADM: Escolha um usuário para ser desbanido do servidor." - }, - "EXAMPLE": { - "TITLE": "exemplo", - "DESCRIPTION": "Template para a criação de outros comandos." - }, - "RANKING": { - "TITLE": "ranqueamento", - "DESCRIPTION": "Veja os usuários mais ativos do servidor!" - }, - "DAILY": { - "TITLE": "bonus", - "DESCRIPTION": "Pegue aqui sua recompensa diária por interagir no servidor!" - }, - "PROFILE": { - "TITLE": "perfil", - "DESCRIPTION": "Veja seu perfil." - }, - "PROFILE_PUT": { - "TITLE": "perfil-editar", - "DESCRIPTION": "Edite seus dados." - }, - "CHAT": { - "TITLE": "chat", - "DESCRIPTION": "(ADM|MOD): Pause ou continue um chat específico." - }, - "TIMEOUT": { - "TITLE": "silenciar", - "DESCRIPTION": "(ADM|MOD): Desabilite um usuário por um certo tempo." - }, - "SAY": { - "TITLE": "falar", - "DESCRIPTION": "Faça o bot mandar uma mensagem em um canal específico." - }, - "CODE": { - "TITLE": "codigo", - "DESCRIPTION": "Mostrará como formatar um bloco de código no discord." - }, - "CLEAR": { - "TITLE": "limpar", - "DESCRIPTION": "(ADM|MOD): Limpe as mensagens do chat em questão pelo valor dado." - }, - "APOIASE": { - "TITLE": "apoiase", - "DESCRIPTION": "Apoie nosso projeto em https://apoia.se/heartdevs e receba bônus exclusivos no servidor!" - }, - "VERSION": { - "TITLE": "versao", - "DESCRIPTION": "ADM: Verifique a versão atual do bot." - }, - "REPUTATION": { - "TITLE": "reputacao", - "DESCRIPTION": "Alguém o ajudou em algo no servidor? Envie-o um agradecimento por isso!" - }, - "ASK": { - "TITLE": "perguntar", - "DESCRIPTION": "Chame a atenção de um usuário para esclarecer suas dúvidas." - }, - "BADGE_CREATE": { - "TITLE": "distintivo-criar", - "DESCRIPTION": "ADM: Crie um distintivo único para os membros!" - }, - "BADGE_SET": { - "TITLE": "distintivo", - "DESCRIPTION": "Pegue um distintivo de um evento que você participou?" - }, - "SPECIAL": { - "TITLE": "especial", - "DESCRIPTION": "Frases características de alguns membros do servidor!" - }, - "ROLE_DELETE": { - "TITLE": "cargo-deletar", - "DESCRIPTION": "ADM: Deletar um cargo específico." - }, - "ROLE_CREATE": { - "TITLE": "cargo-criar", - "DESCRIPTION": "ADM: Criar um cargo específico." - }, - "JUDGE": { - "TITLE": "avaliar", - "DESCRIPTION": "Envie um feedback, seja negativo ou positivo, a um usuário do servidor." - }, - "FORUM_CLOSE": { - "TITLE": "forum-fechar", - "DESCRIPTION": "(ADM|MOD): Fechar um fórum em específico." - }, - "FORUM_OPEN": { - "TITLE": "forum", - "DESCRIPTION": "Abra um fórum de ajuda específico e facilite os outros membros a te ajudarem." - }, - "STAGE_START": { - "TITLE": "reuniao-iniciar", - "DESCRIPTION": "(ADM): Inicialize uma reunião semanal." - }, - "STAGE_FINISH": { - "TITLE": "reuniao-finalizar", - "DESCRIPTION": "(ADM): Finalize uma reunião semanal existente." - }, - "STAGE_ATA": { - "TITLE": "reuniao-ata", - "DESCRIPTION": "(ATA): Submeta a ATA de uma reunião que já terminou." - }, - "ONBOARDING_WHY": { - "TITLE": "onboarding", - "DESCRIPTION": "Entenda o que é o nosso sistema de onboarding." - }, - "ONBOARDING_VOLUNTARY": { - "TITLE": "onboarding-voluntariar", - "DESCRIPTION": "Voluntarie-se para ajudar novos membros no servidor." - }, - "ONBOARDING_REQUIRE": { - "TITLE": "onboarding-requisitar", - "DESCRIPTION": "Use este comando para indicar que deseja ser ajudado por um voluntário." - }, - "ONBOARDING_FINALIZE": { - "TITLE": "onboarding-finalizar", - "DESCRIPTION": "Finalize uma ajuda voluntária." - }, - "ONBOARDING_QUIT": { - "TITLE": "onboarding-desistir", - "DESCRIPTION": "Desista de ser um voluntário." - }, - "DYNAMIC_VOICE": { - "TITLE": "sala", - "DESCRIPTION": "Crie um canal de voz temporário." - }, - "DYNAMIC_VOICE_SIZE": { - "TITLE": "sala-limite", - "DESCRIPTION": "(DONO): Altere o limite de membros permitidos da sala." - }, - "DYNAMIC_VOICE_OWNER": { - "TITLE": "sala-transferir", - "DESCRIPTION": "(DONO): Transfira o dono da sala para outro membro que esteja no mesmo canal de voz." - }, - "DYNAMIC_VOICE_TITLE": { - "TITLE": "sala-titulo", - "DESCRIPTION": "(DONO): Altere o título da sala por outro." - }, - "MEDAL": { - "TITLE": "medalha", - "DESCRIPTION": "Selecione sua medalha de contribuição com a comunidade." - }, - "MEDAL_ADD": { - "TITLE": "medalha-adicionar", - "DESCRIPTION": "(ADM): Adiciona um usuário a uma medalha em específico" - }, - "WATCH": { - "TITLE": "observar", - "DESCRIPTION": "(ADM|MOD): Observe um membro em específico." - }, - "WATCH_LIST": { - "TITLE": "observar-lista", - "DESCRIPTION": "(ADM|MOD): Veja a lista de membros observados." - }, - "WATCH_REMOVE": { - "TITLE": "observar-remover", - "DESCRIPTION": "(ADM|MOD): Remova um membro que esteja sendo observado." - } -} +{ + "INTRODUCE": { + "TITLE": "apresentar", + "DESCRIPTION": "Se apresente para os membros de nossa comunidade e ganhe cargos!" + }, + "ANNOUNCE": { + "TITLE": "anunciar", + "DESCRIPTION": "ADM: Anuncie no canal de anúncios com o uso do everyone automático." + }, + "COLOR": { + "TITLE": "cor", + "DESCRIPTION": "APOIADORES: Como um apoiador, você pode ter uma tag colorida customizada!" + }, + "BAN": { + "TITLE": "banir", + "DESCRIPTION": "ADM: Escolha um usuário para ser banido do servidor." + }, + "UNBAN": { + "TITLE": "desbanir", + "DESCRIPTION": "ADM: Escolha um usuário para ser desbanido do servidor." + }, + "EXAMPLE": { + "TITLE": "exemplo", + "DESCRIPTION": "Template para a criação de outros comandos." + }, + "RANKING": { + "TITLE": "ranqueamento", + "DESCRIPTION": "Veja os usuários mais ativos do servidor!" + }, + "DAILY": { + "TITLE": "bonus", + "DESCRIPTION": "Pegue aqui sua recompensa diária por interagir no servidor!" + }, + "PROFILE": { + "TITLE": "perfil", + "DESCRIPTION": "Veja seu perfil." + }, + "PROFILE_PUT": { + "TITLE": "perfil-editar", + "DESCRIPTION": "Edite seus dados." + }, + "CHAT": { + "TITLE": "chat", + "DESCRIPTION": "(ADM|MOD): Pause ou continue um chat específico." + }, + "TIMEOUT": { + "TITLE": "silenciar", + "DESCRIPTION": "(ADM|MOD): Desabilite um usuário por um certo tempo." + }, + "SAY": { + "TITLE": "falar", + "DESCRIPTION": "Faça o bot mandar uma mensagem em um canal específico." + }, + "CODE": { + "TITLE": "codigo", + "DESCRIPTION": "Mostrará como formatar um bloco de código no discord." + }, + "CLEAR": { + "TITLE": "limpar", + "DESCRIPTION": "(ADM|MOD): Limpe as mensagens do chat em questão pelo valor dado." + }, + "APOIASE": { + "TITLE": "apoiase", + "DESCRIPTION": "Apoie nosso projeto em https://apoia.se/heartdevs e receba bônus exclusivos no servidor!" + }, + "VERSION": { + "TITLE": "versao", + "DESCRIPTION": "ADM: Verifique a versão atual do bot." + }, + "REPUTATION": { + "TITLE": "reputacao", + "DESCRIPTION": "Alguém o ajudou em algo no servidor? Envie-o um agradecimento por isso!" + }, + "ASK": { + "TITLE": "perguntar", + "DESCRIPTION": "Chame a atenção de um usuário para esclarecer suas dúvidas." + }, + "BADGE_CREATE": { + "TITLE": "distintivo-criar", + "DESCRIPTION": "ADM: Crie um distintivo único para os membros!" + }, + "BADGE_SET": { + "TITLE": "distintivo", + "DESCRIPTION": "Pegue um distintivo de um evento que você participou?" + }, + "SPECIAL": { + "TITLE": "especial", + "DESCRIPTION": "Frases características de alguns membros do servidor!" + }, + "ROLE_DELETE": { + "TITLE": "cargo-deletar", + "DESCRIPTION": "ADM: Deletar um cargo específico." + }, + "ROLE_CREATE": { + "TITLE": "cargo-criar", + "DESCRIPTION": "ADM: Criar um cargo específico." + }, + "JUDGE": { + "TITLE": "avaliar", + "DESCRIPTION": "Envie um feedback, seja negativo ou positivo, a um usuário do servidor." + }, + "FORUM_CLOSE": { + "TITLE": "forum-fechar", + "DESCRIPTION": "(ADM|MOD): Fechar um fórum em específico." + }, + "FORUM_OPEN": { + "TITLE": "forum", + "DESCRIPTION": "Abra um fórum de ajuda específico e facilite os outros membros a te ajudarem." + }, + "STAGE_START": { + "TITLE": "reuniao-iniciar", + "DESCRIPTION": "(ADM): Inicialize uma reunião semanal." + }, + "STAGE_FINISH": { + "TITLE": "reuniao-finalizar", + "DESCRIPTION": "(ADM): Finalize uma reunião semanal existente." + }, + "STAGE_ATA": { + "TITLE": "reuniao-ata", + "DESCRIPTION": "(ATA): Submeta a ATA de uma reunião que já terminou." + }, + "ONBOARDING_WHY": { + "TITLE": "onboarding", + "DESCRIPTION": "Entenda o que é o nosso sistema de onboarding." + }, + "ONBOARDING_VOLUNTARY": { + "TITLE": "onboarding-voluntariar", + "DESCRIPTION": "Voluntarie-se para ajudar novos membros no servidor." + }, + "ONBOARDING_REQUIRE": { + "TITLE": "onboarding-requisitar", + "DESCRIPTION": "Use este comando para indicar que deseja ser ajudado por um voluntário." + }, + "ONBOARDING_FINALIZE": { + "TITLE": "onboarding-finalizar", + "DESCRIPTION": "Finalize uma ajuda voluntária." + }, + "ONBOARDING_QUIT": { + "TITLE": "onboarding-desistir", + "DESCRIPTION": "Desista de ser um voluntário." + }, + "DYNAMIC_VOICE": { + "TITLE": "sala", + "DESCRIPTION": "Crie um canal de voz temporário." + }, + "DYNAMIC_VOICE_SIZE": { + "TITLE": "sala-limite", + "DESCRIPTION": "(DONO): Altere o limite de membros permitidos da sala." + }, + "DYNAMIC_VOICE_OWNER": { + "TITLE": "sala-transferir", + "DESCRIPTION": "(DONO): Transfira o dono da sala para outro membro que esteja no mesmo canal de voz." + }, + "DYNAMIC_VOICE_TITLE": { + "TITLE": "sala-titulo", + "DESCRIPTION": "(DONO): Altere o título da sala por outro." + }, + "MEDAL": { + "TITLE": "medalha", + "DESCRIPTION": "Selecione sua medalha de contribuição com a comunidade." + }, + "MEDAL_ADD": { + "TITLE": "medalha-adicionar", + "DESCRIPTION": "(ADM): Adiciona um usuário a uma medalha em específico" + }, + "WATCH": { + "TITLE": "observar", + "DESCRIPTION": "(ADM|MOD): Observe um membro em específico." + }, + "WATCH_LIST": { + "TITLE": "observar-lista", + "DESCRIPTION": "(ADM|MOD): Veja a lista de membros observados." + }, + "WATCH_REMOVE": { + "TITLE": "observar-remover", + "DESCRIPTION": "(ADM|MOD): Remova um membro que esteja sendo observado." + }, + "START_CODE_CHALLENGE": { + "TITLE": "quiz-start", + "DESCRIPTION": "Iniciar sequência de desafio de perguntas." + } +} diff --git a/src/defines/ids.json b/src/defines/ids.json index 5a1ce2b..fc93d6e 100644 --- a/src/defines/ids.json +++ b/src/defines/ids.json @@ -1,366 +1,370 @@ -{ - "BOT_ID": "546150119792443403", - "DEPOSITIONS_CHANNEL": { - "id": "958175169359265802", - "title": "depoimentos-he4rt" - }, - "DYNAMIC_CATEGORY_CHANNEL": { - "id": "1051218990174838814", - "title": "Voz Dinâmica" - }, - "FORUM_CHANNEL": { - "id": "1019651765135741018", - "title": "fórum-de-ajuda" - }, - "CALLED_CHANNEL": { - "id": "1050148460843770036", - "title": "👍│feedback" - }, - "SUGGESTION_CHANNEL": { - "id": "958174907257208862", - "title": "💡︱sugestões" - }, - "POMODORO_CHANNEL": { - "id": "854775331557998603", - "title": "🟢 Coworking" - }, - "REPORT_CHANNEL": { - "id": "1045804587195576451", - "title": "🚨 | auto-report" - }, - "MEETING_DELAS_CHANNEL": { - "id": "1011752322990354462", - "title": "✅︱reunião-das-minas" - }, - "MEETING_CHANNEL": { - "id": "548935968313442304", - "title": "✅︱reunião" - }, - "MEETING_VOICE_CHANNEL": { - "id": "853401652471398400", - "title": "✅ Reunião Semanal" - }, - "AWAY_VOICE_CHANNEL": { - "id": "452927274715447296", - "title": "😴 Ausente" - }, - "CHAT_CHANNEL": { - "id": "541443469642563585", - "title": "💬︱bate-papo" - }, - "COMMANDS_CHANNEL": { - "id": "542840741588762637", - "title": "🤖︱comandos" - }, - "ADVERTS_CHANNEL": { - "id": "755094121848242337", - "title": "📢︱anúncios" - }, - "PRESENTATIONS_CHANNEL": { - "id": "540993663468306433", - "title": "📖︱apresentações" - }, - "DONATORS_CHANNEL": { - "id": "607043756482363403", - "title": "💳︱apoiadores" - }, - "PUNISHMENTS_CHANNEL": { - "id": "549056142752481283", - "title": "📌│punishments-and-mods" - }, - "LEVELUP_CHANNEL": { - "id": "552332704381927424", - "title": "📈│levelup" - }, - "LEARNING_DIARY_CHANNEL": { - "id": "544831124908802048", - "title": "🏆|aprendizado-diário" - }, - "VOLUNTEER_CHANNEL": { - "id": "1051348602259251250", - "title": "🏆|voluntários" - }, - "VALID_PRESENTATION_DEV_ROLES": [ - { - "id": "550411669084569602", - "name": "GameDev", - "emoji": "🎮" - }, - { - "id": "540993488410378281", - "name": "JavaScript", - "emoji": "📜" - }, - { - "id": "540994118634176512", - "name": "PHP", - "emoji": "🐘" - }, - { - "id": "540994295541399552", - "name": "Python", - "emoji": "🐍" - }, - { - "id": "540995072246939648", - "name": "Perl", - "emoji": "🐪" - }, - { - "id": "540995379538165774", - "name": "Java", - "emoji": "☕" - }, - { - "id": "540995627559944207", - "name": "Ruby", - "emoji": "💎" - }, - { - "id": "1136369892736647359", - "name": "Crystal", - "emoji": "🖤" - }, - { - "id": "541021498064896000", - "name": "C, C++, C#", - "emoji": "🇨" - }, - { - "id": "546152565633449995", - "name": "UX/UI", - "emoji": "🎨" - }, - { - "id": "1043325810347606056", - "name": "Rust", - "emoji": "r" - }, - { - "id": "547606728179449895", - "name": "Designer", - "emoji": "🎨" - }, - { - "id": "958788344974831687", - "name": "Elixir", - "emoji": "💧" - } - ], - "VALID_PRESENTATION_ENG_ROLES": [ - { - "id": "546148712833875985", - "name": "Advanced English", - "emoji": "🗽" - }, - { - "id": "546148711416332298", - "name": "Intermediate English", - "emoji": "🗽" - }, - { - "id": "546148708077666315", - "name": "Basic English", - "emoji": "🗽" - } - ], - "VALID_PRESENTATION_RF": [ - { - "id": "AC", - "name": "Acre" - }, - { - "id": "AL", - "name": "Alagoas" - }, - { - "id": "AP", - "name": "Amapá" - }, - { - "id": "AM", - "name": "Amazonas" - }, - { - "id": "BA", - "name": "Bahia" - }, - { - "id": "CE", - "name": "Ceará" - }, - { - "id": "DF", - "name": "Distrito Federal" - }, - { - "id": "ES", - "name": "Espírito Santo" - }, - { - "id": "GO", - "name": "Goiás" - }, - { - "id": "MA", - "name": "Maranhão" - }, - { - "id": "MT", - "name": "Mato Grosso" - }, - { - "id": "MS", - "name": "Mato Grosso do Sul" - }, - { - "id": "MG", - "name": "Minas Gerais" - }, - { - "id": "PA", - "name": "Pará" - }, - { - "id": "PB", - "name": "Paraíba" - }, - { - "id": "PR", - "name": "Paraná" - }, - { - "id": "PE", - "name": "Pernambuco" - }, - { - "id": "PI", - "name": "Piauí" - }, - { - "id": "RJ", - "name": "Rio de Janeiro" - }, - { - "id": "RN", - "name": "Rio Grande do Norte" - }, - { - "id": "RS", - "name": "Rio Grande do Sul" - }, - { - "id": "RO", - "name": "Rondônia" - }, - { - "id": "RR", - "name": "Roraima" - }, - { - "id": "SC", - "name": "Santa Catarina" - }, - { - "id": "SP", - "name": "São Paulo" - }, - { - "id": "SE", - "name": "Sergipe" - }, - { - "id": "TO", - "name": "Tocantins" - }, - { - "id": "__", - "name": "Não moro no Brasil" - } - ], - "HE4RT_DELAS_ROLE": { - "id": "1018009963903328308", - "name": "He4rt Delas", - "emoji": "💗" - }, - "PRESENTING_ROLE": { - "id": "1042951086077657098", - "name": "Apresentando", - "emoji": "🎓" - }, - "PRESENTED_ROLE": { - "id": "546150872397119491", - "name": "Apresentou", - "emoji": "🎓" - }, - "DONATOR_ROLE": { - "id": "606996933763923998", - "name": "Apoiadores", - "emoji": "💳" - }, - "NITRO_BOOSTER_ROLE": { - "id": "593925424875307038", - "name": "Nitro Booster", - "emoji": "⚡" - }, - "BEGINNER_ROLE": { - "id": "547569615421833247", - "name": "Beginner", - "emoji": "🥉" - }, - "INTERMEDIATE_ROLE": { - "id": "547569827259088944", - "name": "Intermediate", - "emoji": "🥈" - }, - "ADVANCED_ROLE": { - "id": "547569825229307916", - "name": "Advanced", - "emoji": "🏅" - }, - "SUPREME_ROLE": { - "id": "547569826324021248", - "name": "Supreme", - "emoji": "🥇" - }, - "HE4RT_ROLE": { - "id": "512389942354378772", - "name": "He4rt", - "emoji": "💜" - }, - "HE4RTLESS_ROLE": { - "id": "547543574091268118", - "name": "He4rtless", - "emoji": "🍷" - }, - "ADMINISTRATOR_ROLE": { - "id": "547549400164073472", - "name": "Equipe de Administração", - "emoji": "💼" - }, - "MODERATION_ROLE": { - "id": "547549463942791181", - "name": "Equipe de Moderação", - "emoji": "👮" - }, - "ATA_ROLE": { - "id": "1050965085184598037", - "name": "Escrivão FODA", - "emoji": "✍️" - }, - "VOLUNTEER_ROLE": { - "id": "1051348460026204231", - "name": "Voluntário", - "emoji": "💜" - }, - "SOLVED_TAG": { - "id": "1020896504862494790", - "name": "Resolvido" - }, - "UNSOLVED_TAG": { - "id": "1021558149695680554", - "name": "Não Resolvido" - }, - "HE4RT_EMOJI_ID": "<:he4rt:1051194598891991141>", - "HE4RT_DELAS_EMOJI_ID": "<:he4rtDelas:1051983616437145610>" -} +{ + "BOT_ID": "546150119792443403", + "DEPOSITIONS_CHANNEL": { + "id": "958175169359265802", + "title": "depoimentos-he4rt" + }, + "DYNAMIC_CATEGORY_CHANNEL": { + "id": "1051218990174838814", + "title": "Voz Dinâmica" + }, + "FORUM_CHANNEL": { + "id": "1019651765135741018", + "title": "fórum-de-ajuda" + }, + "CALLED_CHANNEL": { + "id": "1050148460843770036", + "title": "👍│feedback" + }, + "SUGGESTION_CHANNEL": { + "id": "958174907257208862", + "title": "💡︱sugestões" + }, + "POMODORO_CHANNEL": { + "id": "854775331557998603", + "title": "🟢 Coworking" + }, + "REPORT_CHANNEL": { + "id": "1045804587195576451", + "title": "🚨 | auto-report" + }, + "MEETING_DELAS_CHANNEL": { + "id": "1011752322990354462", + "title": "✅︱reunião-das-minas" + }, + "MEETING_CHANNEL": { + "id": "548935968313442304", + "title": "✅︱reunião" + }, + "MEETING_VOICE_CHANNEL": { + "id": "853401652471398400", + "title": "✅ Reunião Semanal" + }, + "AWAY_VOICE_CHANNEL": { + "id": "452927274715447296", + "title": "😴 Ausente" + }, + "CHAT_CHANNEL": { + "id": "541443469642563585", + "title": "💬︱bate-papo" + }, + "COMMANDS_CHANNEL": { + "id": "542840741588762637", + "title": "🤖︱comandos" + }, + "ADVERTS_CHANNEL": { + "id": "755094121848242337", + "title": "📢︱anúncios" + }, + "PRESENTATIONS_CHANNEL": { + "id": "540993663468306433", + "title": "📖︱apresentações" + }, + "DONATORS_CHANNEL": { + "id": "607043756482363403", + "title": "💳︱apoiadores" + }, + "PUNISHMENTS_CHANNEL": { + "id": "549056142752481283", + "title": "📌│punishments-and-mods" + }, + "LEVELUP_CHANNEL": { + "id": "552332704381927424", + "title": "📈│levelup" + }, + "LEARNING_DIARY_CHANNEL": { + "id": "544831124908802048", + "title": "🏆|aprendizado-diário" + }, + "VOLUNTEER_CHANNEL": { + "id": "1051348602259251250", + "title": "🏆|voluntários" + }, + "VALID_PRESENTATION_DEV_ROLES": [ + { + "id": "550411669084569602", + "name": "GameDev", + "emoji": "🎮" + }, + { + "id": "540993488410378281", + "name": "JavaScript", + "emoji": "📜" + }, + { + "id": "540994118634176512", + "name": "PHP", + "emoji": "🐘" + }, + { + "id": "540994295541399552", + "name": "Python", + "emoji": "🐍" + }, + { + "id": "540995072246939648", + "name": "Perl", + "emoji": "🐪" + }, + { + "id": "540995379538165774", + "name": "Java", + "emoji": "☕" + }, + { + "id": "540995627559944207", + "name": "Ruby", + "emoji": "💎" + }, + { + "id": "1136369892736647359", + "name": "Crystal", + "emoji": "🖤" + }, + { + "id": "541021498064896000", + "name": "C, C++, C#", + "emoji": "🇨" + }, + { + "id": "546152565633449995", + "name": "UX/UI", + "emoji": "🎨" + }, + { + "id": "1043325810347606056", + "name": "Rust", + "emoji": "r" + }, + { + "id": "547606728179449895", + "name": "Designer", + "emoji": "🎨" + }, + { + "id": "958788344974831687", + "name": "Elixir", + "emoji": "💧" + } + ], + "VALID_PRESENTATION_ENG_ROLES": [ + { + "id": "546148712833875985", + "name": "Advanced English", + "emoji": "🗽" + }, + { + "id": "546148711416332298", + "name": "Intermediate English", + "emoji": "🗽" + }, + { + "id": "546148708077666315", + "name": "Basic English", + "emoji": "🗽" + } + ], + "VALID_PRESENTATION_RF": [ + { + "id": "AC", + "name": "Acre" + }, + { + "id": "AL", + "name": "Alagoas" + }, + { + "id": "AP", + "name": "Amapá" + }, + { + "id": "AM", + "name": "Amazonas" + }, + { + "id": "BA", + "name": "Bahia" + }, + { + "id": "CE", + "name": "Ceará" + }, + { + "id": "DF", + "name": "Distrito Federal" + }, + { + "id": "ES", + "name": "Espírito Santo" + }, + { + "id": "GO", + "name": "Goiás" + }, + { + "id": "MA", + "name": "Maranhão" + }, + { + "id": "MT", + "name": "Mato Grosso" + }, + { + "id": "MS", + "name": "Mato Grosso do Sul" + }, + { + "id": "MG", + "name": "Minas Gerais" + }, + { + "id": "PA", + "name": "Pará" + }, + { + "id": "PB", + "name": "Paraíba" + }, + { + "id": "PR", + "name": "Paraná" + }, + { + "id": "PE", + "name": "Pernambuco" + }, + { + "id": "PI", + "name": "Piauí" + }, + { + "id": "RJ", + "name": "Rio de Janeiro" + }, + { + "id": "RN", + "name": "Rio Grande do Norte" + }, + { + "id": "RS", + "name": "Rio Grande do Sul" + }, + { + "id": "RO", + "name": "Rondônia" + }, + { + "id": "RR", + "name": "Roraima" + }, + { + "id": "SC", + "name": "Santa Catarina" + }, + { + "id": "SP", + "name": "São Paulo" + }, + { + "id": "SE", + "name": "Sergipe" + }, + { + "id": "TO", + "name": "Tocantins" + }, + { + "id": "__", + "name": "Não moro no Brasil" + } + ], + "HE4RT_DELAS_ROLE": { + "id": "1018009963903328308", + "name": "He4rt Delas", + "emoji": "💗" + }, + "PRESENTING_ROLE": { + "id": "1042951086077657098", + "name": "Apresentando", + "emoji": "🎓" + }, + "PRESENTED_ROLE": { + "id": "546150872397119491", + "name": "Apresentou", + "emoji": "🎓" + }, + "DONATOR_ROLE": { + "id": "606996933763923998", + "name": "Apoiadores", + "emoji": "💳" + }, + "NITRO_BOOSTER_ROLE": { + "id": "593925424875307038", + "name": "Nitro Booster", + "emoji": "⚡" + }, + "BEGINNER_ROLE": { + "id": "547569615421833247", + "name": "Beginner", + "emoji": "🥉" + }, + "INTERMEDIATE_ROLE": { + "id": "547569827259088944", + "name": "Intermediate", + "emoji": "🥈" + }, + "ADVANCED_ROLE": { + "id": "547569825229307916", + "name": "Advanced", + "emoji": "🏅" + }, + "SUPREME_ROLE": { + "id": "547569826324021248", + "name": "Supreme", + "emoji": "🥇" + }, + "HE4RT_ROLE": { + "id": "512389942354378772", + "name": "He4rt", + "emoji": "💜" + }, + "HE4RTLESS_ROLE": { + "id": "547543574091268118", + "name": "He4rtless", + "emoji": "🍷" + }, + "ADMINISTRATOR_ROLE": { + "id": "547549400164073472", + "name": "Equipe de Administração", + "emoji": "💼" + }, + "MODERATION_ROLE": { + "id": "547549463942791181", + "name": "Equipe de Moderação", + "emoji": "👮" + }, + "ATA_ROLE": { + "id": "1050965085184598037", + "name": "Escrivão FODA", + "emoji": "✍️" + }, + "VOLUNTEER_ROLE": { + "id": "1051348460026204231", + "name": "Voluntário", + "emoji": "💜" + }, + "SOLVED_TAG": { + "id": "1020896504862494790", + "name": "Resolvido" + }, + "UNSOLVED_TAG": { + "id": "1021558149695680554", + "name": "Não Resolvido" + }, + "HE4RT_EMOJI_ID": "<:he4rt:1051194598891991141>", + "HE4RT_DELAS_EMOJI_ID": "<:he4rtDelas:1051983616437145610>", + "QUIZ_EVENT": { + "id": "1050944705610911774", + "name": "evento_q&a" + } +} diff --git a/src/defines/ids_development.json b/src/defines/ids_development.json index f931f1c..83e6fab 100644 --- a/src/defines/ids_development.json +++ b/src/defines/ids_development.json @@ -1,371 +1,375 @@ -{ - "BOT_ID": "1025630826341335122", - "DEPOSITIONS_CHANNEL": { - "id": "1042817315965763595", - "title": "depoimentos-he4rt" - }, - "DYNAMIC_CATEGORY_CHANNEL": { - "id": "1051218701338300416", - "title": "Voz Dinâmica" - }, - "FORUM_CHANNEL": { - "id": "1049889714875932702", - "title": "fórum-de-ajuda" - }, - "CALLED_CHANNEL": { - "id": "1042817315965763594", - "title": "💡| chamados" - }, - "SUGGESTION_CHANNEL": { - "id": "1042817315965763594", - "title": "💡︱sugestões" - }, - "POMODORO_CHANNEL": { - "id": "1045884603778469978", - "title": "🟢 Coworking" - }, - "REPORT_CHANNEL": { - "id": "1042817315781218333", - "title": "🚨 | auto-report" - }, - "MEETING_DELAS_CHANNEL": { - "id": "1045470251632042064", - "title": "✅︱reunião-das-minas" - }, - "MEETING_CHANNEL": { - "id": "1045470226407506071", - "title": "✅︱reunião" - }, - "MEETING_VOICE_CHANNEL": { - "id": "1049873030387601449", - "title": "✅ Reunião Semanal" - }, - "AWAY_VOICE_CHANNEL": { - "id": "1042817316334866486", - "title": "😴 Ausente" - }, - "CHAT_CHANNEL": { - "id": "1042817315965763597", - "title": "💬︱bate-papo" - }, - "COMMANDS_CHANNEL": { - "id": "1042817315965763599", - "title": "🤖︱comandos" - }, - "ADVERTS_CHANNEL": { - "id": "1042821299224985640", - "title": "📢︱anúncios" - }, - "PRESENTATIONS_CHANNEL": { - "id": "1042817316754309184", - "title": "📖︱apresentações" - }, - "DONATORS_CHANNEL": { - "id": "1042817316158718023", - "title": "💳︱apoiadores" - }, - "PUNISHMENTS_CHANNEL": { - "id": "1042817315781218330", - "title": "📌│punishments-and-mods" - }, - "LEVELUP_CHANNEL": { - "id": "1042817318981472322", - "title": "📈│levelup" - }, - "LEARNING_DIARY_CHANNEL": { - "id": "104281799981472332", - "title": "🏆|aprendizado-diário" - }, - "VOLUNTEER_CHANNEL": { - "id": "1042817315965763600", - "title": "🏆|voluntários" - }, - "VALID_PRESENTATION_DEV_ROLES": [ - { - "id": "1042817315227582488", - "name": "GameDev", - "emoji": "🎮" - }, - { - "id": "1042817315227582487", - "name": "JavaScript", - "emoji": "📜" - }, - { - "id": "1042817315227582486", - "name": "Elixir", - "emoji": "💧" - }, - { - "id": "1042817315227582485", - "name": "PHP", - "emoji": "🐘" - }, - { - "id": "1042817315227582484", - "name": "Python", - "emoji": "🐍" - }, - { - "id": "1042817315206594640", - "name": "Perl", - "emoji": "🐪" - }, - { - "id": "1042817315206594639", - "name": "Java", - "emoji": "☕" - }, - { - "id": "1042817315206594638", - "name": "Ruby", - "emoji": "💎" - }, - { - "id": "1136369892736647359", - "name": "Crystal", - "emoji": "🖤" - }, - { - "id": "1042817315206594637", - "name": "C, C++, C#", - "emoji": "🇨" - }, - { - "id": "1042817315206594636", - "name": "UX/UI", - "emoji": "🎨" - }, - { - "id": "1042824308604551188", - "name": "Rust", - "emoji": "r" - }, - { - "id": "1042824387805597757", - "name": "Designer", - "emoji": "🎨" - }, - { - "id": "1042817315227582486", - "name": "Elixir", - "emoji": "💧" - } - ], - "VALID_PRESENTATION_ENG_ROLES": [ - { - "id": "1042817315185627258", - "name": "Advanced English", - "emoji": "🗽" - }, - { - "id": "1042817315185627257", - "name": "Intermediate English", - "emoji": "🗽" - }, - { - "id": "1042817315185627256", - "name": "Basic English", - "emoji": "🗽" - } - ], - "VALID_PRESENTATION_RF": [ - { - "id": "AC", - "name": "Acre" - }, - { - "id": "AL", - "name": "Alagoas" - }, - { - "id": "AP", - "name": "Amapá" - }, - { - "id": "AM", - "name": "Amazonas" - }, - { - "id": "BA", - "name": "Bahia" - }, - { - "id": "CE", - "name": "Ceará" - }, - { - "id": "DF", - "name": "Distrito Federal" - }, - { - "id": "ES", - "name": "Espírito Santo" - }, - { - "id": "GO", - "name": "Goiás" - }, - { - "id": "MA", - "name": "Maranhão" - }, - { - "id": "MT", - "name": "Mato Grosso" - }, - { - "id": "MS", - "name": "Mato Grosso do Sul" - }, - { - "id": "MG", - "name": "Minas Gerais" - }, - { - "id": "PA", - "name": "Pará" - }, - { - "id": "PB", - "name": "Paraíba" - }, - { - "id": "PR", - "name": "Paraná" - }, - { - "id": "PE", - "name": "Pernambuco" - }, - { - "id": "PI", - "name": "Piauí" - }, - { - "id": "RJ", - "name": "Rio de Janeiro" - }, - { - "id": "RN", - "name": "Rio Grande do Norte" - }, - { - "id": "RS", - "name": "Rio Grande do Sul" - }, - { - "id": "RO", - "name": "Rondônia" - }, - { - "id": "RR", - "name": "Roraima" - }, - { - "id": "SC", - "name": "Santa Catarina" - }, - { - "id": "SP", - "name": "São Paulo" - }, - { - "id": "SE", - "name": "Sergipe" - }, - { - "id": "TO", - "name": "Tocantins" - }, - { - "id": "__", - "name": "Não moro no Brasil" - } - ], - "HE4RT_DELAS_ROLE": { - "id": "1042817315173056629", - "name": "He4rt Delas", - "emoji": "💗" - }, - "PRESENTING_ROLE": { - "id": "1042817315156262917", - "name": "Apresentando", - "emoji": "🎓" - }, - "PRESENTED_ROLE": { - "id": "1042817315173056628", - "name": "Apresentou", - "emoji": "🎓" - }, - "DONATOR_ROLE": { - "id": "1042817315248541753", - "name": "Apoiadores", - "emoji": "💳" - }, - "NITRO_BOOSTER_ROLE": { - "id": "1042817315248541752", - "name": "Nitro Booster", - "emoji": "⚡" - }, - "BEGINNER_ROLE": { - "id": "1042817315227582491", - "name": "Beginner", - "emoji": "🥉" - }, - "INTERMEDIATE_ROLE": { - "id": "1042817315227582492", - "name": "Intermediate", - "emoji": "🥈" - }, - "ADVANCED_ROLE": { - "id": "1042817315227582493", - "name": "Advanced", - "emoji": "🏅" - }, - "SUPREME_ROLE": { - "id": "1042817315248541747", - "name": "Supreme", - "emoji": "🥇" - }, - "HE4RT_ROLE": { - "id": "1042817315269509121", - "name": "He4rt", - "emoji": "💜" - }, - "HE4RTLESS_ROLE": { - "id": "1042817315290497037", - "name": "He4rtless", - "emoji": "🍷" - }, - "ADMINISTRATOR_ROLE": { - "id": "1042817315269509120", - "name": "Equipe de Administração", - "emoji": "💼" - }, - "MODERATION_ROLE": { - "id": "1042817315248541756", - "name": "Equipe de Moderação", - "emoji": "👮" - }, - "ATA_ROLE": { - "id": "1042817315173056628", - "name": "Escrivão", - "emoji": "✍️" - }, - "VOLUNTEER_ROLE": { - "id": "1042817315185627257", - "name": "Voluntário", - "emoji": "💜" - }, - "SOLVED_TAG": { - "id": "1020896504862494790", - "name": "Resolvido" - }, - "UNSOLVED_TAG": { - "id": "1021558149695680554", - "name": "Não Resolvido" - }, - "HE4RT_EMOJI_ID": "<:he4rt:1051194598891991141>", - "HE4RT_DELAS_EMOJI_ID": "<:he4rtDelas:1051983616437145610>" -} +{ + "BOT_ID": "1025630826341335122", + "DEPOSITIONS_CHANNEL": { + "id": "1042817315965763595", + "title": "depoimentos-he4rt" + }, + "DYNAMIC_CATEGORY_CHANNEL": { + "id": "1051218701338300416", + "title": "Voz Dinâmica" + }, + "FORUM_CHANNEL": { + "id": "1049889714875932702", + "title": "fórum-de-ajuda" + }, + "CALLED_CHANNEL": { + "id": "1042817315965763594", + "title": "💡| chamados" + }, + "SUGGESTION_CHANNEL": { + "id": "1042817315965763594", + "title": "💡︱sugestões" + }, + "POMODORO_CHANNEL": { + "id": "1045884603778469978", + "title": "🟢 Coworking" + }, + "REPORT_CHANNEL": { + "id": "1042817315781218333", + "title": "🚨 | auto-report" + }, + "MEETING_DELAS_CHANNEL": { + "id": "1045470251632042064", + "title": "✅︱reunião-das-minas" + }, + "MEETING_CHANNEL": { + "id": "1045470226407506071", + "title": "✅︱reunião" + }, + "MEETING_VOICE_CHANNEL": { + "id": "1049873030387601449", + "title": "✅ Reunião Semanal" + }, + "AWAY_VOICE_CHANNEL": { + "id": "1042817316334866486", + "title": "😴 Ausente" + }, + "CHAT_CHANNEL": { + "id": "1042817315965763597", + "title": "💬︱bate-papo" + }, + "COMMANDS_CHANNEL": { + "id": "1042817315965763599", + "title": "🤖︱comandos" + }, + "ADVERTS_CHANNEL": { + "id": "1042821299224985640", + "title": "📢︱anúncios" + }, + "PRESENTATIONS_CHANNEL": { + "id": "1042817316754309184", + "title": "📖︱apresentações" + }, + "DONATORS_CHANNEL": { + "id": "1042817316158718023", + "title": "💳︱apoiadores" + }, + "PUNISHMENTS_CHANNEL": { + "id": "1042817315781218330", + "title": "📌│punishments-and-mods" + }, + "LEVELUP_CHANNEL": { + "id": "1042817318981472322", + "title": "📈│levelup" + }, + "LEARNING_DIARY_CHANNEL": { + "id": "104281799981472332", + "title": "🏆|aprendizado-diário" + }, + "VOLUNTEER_CHANNEL": { + "id": "1042817315965763600", + "title": "🏆|voluntários" + }, + "VALID_PRESENTATION_DEV_ROLES": [ + { + "id": "1042817315227582488", + "name": "GameDev", + "emoji": "🎮" + }, + { + "id": "1042817315227582487", + "name": "JavaScript", + "emoji": "📜" + }, + { + "id": "1042817315227582486", + "name": "Elixir", + "emoji": "💧" + }, + { + "id": "1042817315227582485", + "name": "PHP", + "emoji": "🐘" + }, + { + "id": "1042817315227582484", + "name": "Python", + "emoji": "🐍" + }, + { + "id": "1042817315206594640", + "name": "Perl", + "emoji": "🐪" + }, + { + "id": "1042817315206594639", + "name": "Java", + "emoji": "☕" + }, + { + "id": "1042817315206594638", + "name": "Ruby", + "emoji": "💎" + }, + { + "id": "1136369892736647359", + "name": "Crystal", + "emoji": "🖤" + }, + { + "id": "1042817315206594637", + "name": "C, C++, C#", + "emoji": "🇨" + }, + { + "id": "1042817315206594636", + "name": "UX/UI", + "emoji": "🎨" + }, + { + "id": "1042824308604551188", + "name": "Rust", + "emoji": "r" + }, + { + "id": "1042824387805597757", + "name": "Designer", + "emoji": "🎨" + }, + { + "id": "1042817315227582486", + "name": "Elixir", + "emoji": "💧" + } + ], + "VALID_PRESENTATION_ENG_ROLES": [ + { + "id": "1042817315185627258", + "name": "Advanced English", + "emoji": "🗽" + }, + { + "id": "1042817315185627257", + "name": "Intermediate English", + "emoji": "🗽" + }, + { + "id": "1042817315185627256", + "name": "Basic English", + "emoji": "🗽" + } + ], + "VALID_PRESENTATION_RF": [ + { + "id": "AC", + "name": "Acre" + }, + { + "id": "AL", + "name": "Alagoas" + }, + { + "id": "AP", + "name": "Amapá" + }, + { + "id": "AM", + "name": "Amazonas" + }, + { + "id": "BA", + "name": "Bahia" + }, + { + "id": "CE", + "name": "Ceará" + }, + { + "id": "DF", + "name": "Distrito Federal" + }, + { + "id": "ES", + "name": "Espírito Santo" + }, + { + "id": "GO", + "name": "Goiás" + }, + { + "id": "MA", + "name": "Maranhão" + }, + { + "id": "MT", + "name": "Mato Grosso" + }, + { + "id": "MS", + "name": "Mato Grosso do Sul" + }, + { + "id": "MG", + "name": "Minas Gerais" + }, + { + "id": "PA", + "name": "Pará" + }, + { + "id": "PB", + "name": "Paraíba" + }, + { + "id": "PR", + "name": "Paraná" + }, + { + "id": "PE", + "name": "Pernambuco" + }, + { + "id": "PI", + "name": "Piauí" + }, + { + "id": "RJ", + "name": "Rio de Janeiro" + }, + { + "id": "RN", + "name": "Rio Grande do Norte" + }, + { + "id": "RS", + "name": "Rio Grande do Sul" + }, + { + "id": "RO", + "name": "Rondônia" + }, + { + "id": "RR", + "name": "Roraima" + }, + { + "id": "SC", + "name": "Santa Catarina" + }, + { + "id": "SP", + "name": "São Paulo" + }, + { + "id": "SE", + "name": "Sergipe" + }, + { + "id": "TO", + "name": "Tocantins" + }, + { + "id": "__", + "name": "Não moro no Brasil" + } + ], + "HE4RT_DELAS_ROLE": { + "id": "1042817315173056629", + "name": "He4rt Delas", + "emoji": "💗" + }, + "PRESENTING_ROLE": { + "id": "1042817315156262917", + "name": "Apresentando", + "emoji": "🎓" + }, + "PRESENTED_ROLE": { + "id": "1042817315173056628", + "name": "Apresentou", + "emoji": "🎓" + }, + "DONATOR_ROLE": { + "id": "1042817315248541753", + "name": "Apoiadores", + "emoji": "💳" + }, + "NITRO_BOOSTER_ROLE": { + "id": "1042817315248541752", + "name": "Nitro Booster", + "emoji": "⚡" + }, + "BEGINNER_ROLE": { + "id": "1042817315227582491", + "name": "Beginner", + "emoji": "🥉" + }, + "INTERMEDIATE_ROLE": { + "id": "1042817315227582492", + "name": "Intermediate", + "emoji": "🥈" + }, + "ADVANCED_ROLE": { + "id": "1042817315227582493", + "name": "Advanced", + "emoji": "🏅" + }, + "SUPREME_ROLE": { + "id": "1042817315248541747", + "name": "Supreme", + "emoji": "🥇" + }, + "HE4RT_ROLE": { + "id": "1042817315269509121", + "name": "He4rt", + "emoji": "💜" + }, + "HE4RTLESS_ROLE": { + "id": "1042817315290497037", + "name": "He4rtless", + "emoji": "🍷" + }, + "ADMINISTRATOR_ROLE": { + "id": "1042817315269509120", + "name": "Equipe de Administração", + "emoji": "💼" + }, + "MODERATION_ROLE": { + "id": "1042817315248541756", + "name": "Equipe de Moderação", + "emoji": "👮" + }, + "ATA_ROLE": { + "id": "1042817315173056628", + "name": "Escrivão", + "emoji": "✍️" + }, + "VOLUNTEER_ROLE": { + "id": "1042817315185627257", + "name": "Voluntário", + "emoji": "💜" + }, + "SOLVED_TAG": { + "id": "1020896504862494790", + "name": "Resolvido" + }, + "UNSOLVED_TAG": { + "id": "1021558149695680554", + "name": "Não Resolvido" + }, + "HE4RT_EMOJI_ID": "<:he4rt:1051194598891991141>", + "HE4RT_DELAS_EMOJI_ID": "<:he4rtDelas:1051983616437145610>", + "QUIZ_EVENT": { + "id": "1050944705610911774", + "name": "evento_q&a" + } +} diff --git a/src/defines/localisation/commands/quiz_event.json b/src/defines/localisation/commands/quiz_event.json new file mode 100644 index 0000000..a41852f --- /dev/null +++ b/src/defines/localisation/commands/quiz_event.json @@ -0,0 +1,6 @@ +{ + "INTRO": "Nosso bot resolveu aprender sobre desenvolvimento e está dando seus primeiros passos com algoritimos, você está afim de ajudar nosso bot a resolver algumas questões? Se sim digite `/ajudar-bot` para iniciar esses desafios, toda ajuda é bem vinda e como recompensa você ganhará he4rt coins por participar e os três primeiros iram ganhar he4rt coins + experiência.", + "CONTINUE": "Você topou o desafio!! No total temos 3 perguntas para você responder, você poderá pedir dicas digitando `!dica` caso esteja com dificuldades e aqui vai a primeira pergunta...", + "REWARD_ANNOUNCE": "Parábens!!{user} Você conseguiu responder todas as perguntas e como recompensa você ganhou **{exp}** de experiência!", + "REWARD_PARTICIPANT": "Parábens!! {user} Você conseguiu responder todas as perguntas e como recompensa você ganhou **{exp}** de experiência!" +} diff --git a/src/defines/localisation/defaults/reply.json b/src/defines/localisation/defaults/reply.json index 358d665..313fe9a 100644 --- a/src/defines/localisation/defaults/reply.json +++ b/src/defines/localisation/defaults/reply.json @@ -1,15 +1,17 @@ -{ - "SUCCESS_COMMAND_DEFAULT": "Comando executado com sucesso!", - "SUCCESS_DM_SEND": "Enviado na DM!", - "EXECUTING": "O seu comando está sendo executado, aguarde!", - "ERROR_DEFAULT": "Algum erro inesperado ocorreu. Tente novamente mais tarde!", - "ERROR_INVALID_EMAIL": "Insira um email válido!", - "ERROR_MISS_PERMISSION": "Você não tem permissão para realizar esta ação!", - "ERROR_MEMBER_IS_NOT_PRESENTED": "Você ou o alvo não se apresentou! Use o comando `/apresentar` antes de executar este comando!", - "ERROR_ACCESS_DM": "**Não foi possível enviar mensagem pelo privado!** Certifique-se que eu possa enviar mensagens para você! Clique na aba de configurações do servidor -> **Config. de privacidade** -> **Mensagens Diretas**", - "ERROR_INVALID_ARGUMENT": "Algum argumento inserido é inválido!", - "ERROR_CHANNEL_PERMISSION": "Só é permitido usar este comando no canal ", - "ERROR_CANNOT_BE_BANNED": "O usuário em questão não pode ser banido ou desbanido!", - "ERROR_PAGINATION": "Este número de página não existe.", - "ERROR_PRESENTING": "**Você já está se apresentando! Consulte sua DM.**" -} +{ + "SUCCESS_COMMAND_DEFAULT": "Comando executado com sucesso!", + "SUCCESS_DM_SEND": "Enviado na DM!", + "EXECUTING": "O seu comando está sendo executado, aguarde!", + "ERROR_DEFAULT": "Algum erro inesperado ocorreu. Tente novamente mais tarde!", + "ERROR_INVALID_EMAIL": "Insira um email válido!", + "ERROR_MISS_PERMISSION": "Você não tem permissão para realizar esta ação!", + "ERROR_MEMBER_IS_NOT_PRESENTED": "Você ou o alvo não se apresentou! Use o comando `/apresentar` antes de executar este comando!", + "ERROR_ACCESS_DM": "**Não foi possível enviar mensagem pelo privado!** Certifique-se que eu possa enviar mensagens para você! Clique na aba de configurações do servidor -> **Config. de privacidade** -> **Mensagens Diretas**", + "ERROR_INVALID_ARGUMENT": "Algum argumento inserido é inválido!", + "ERROR_CHANNEL_PERMISSION": "Só é permitido usar este comando no canal ", + "ERROR_CANNOT_BE_BANNED": "O usuário em questão não pode ser banido ou desbanido!", + "ERROR_PAGINATION": "Este número de página não existe.", + "ERROR_PRESENTING": "**Você já está se apresentando! Consulte sua DM.**", + "ERROR_PARTICIPANT_EVENT": "**Você já completou este evento.**", + "ERROR_EVENT_NOT_FOUND": "**Não há evento ativo neste momento.**" +} diff --git a/src/defines/values.json b/src/defines/values.json index 786896b..ffcf9da 100644 --- a/src/defines/values.json +++ b/src/defines/values.json @@ -2,6 +2,7 @@ "CLIENT_NAME": "He4rt Developers", "CLIENT_TIMEZONE": "America/Sao_Paulo", "TIMEOUT_COMMAND": 300000, + "TIMEOUT_ANSWER": 900000, "TIMEOUT_COMMAND_STRING": "__INVALID__RESPONSE__", "DEFINE_STRING_REPLACED": "__REPLACED__", "HE4RT_ICON_1_URL": "https://i.imgur.com/iWhfWMa.png", @@ -12,7 +13,8 @@ "SUCCESS": "#46E363", "ERROR": "#C90B04", "WARNING": "#FFD421", - "INFO": "#7291FA" + "INFO": "#7291FA", + "HINT_ANSWER": "#00FFFF" }, "RESTRICTED_CUSTOM_ROLE_COLORS": [ "#313335", diff --git a/src/defines/values_development.json b/src/defines/values_development.json index d32ae98..e914b13 100644 --- a/src/defines/values_development.json +++ b/src/defines/values_development.json @@ -1,7 +1,8 @@ { "CLIENT_NAME": "He4rt Developers", "CLIENT_TIMEZONE": "America/Sao_Paulo", - "TIMEOUT_COMMAND": 30000, + "TIMEOUT_COMMAND": 300000, + "TIMEOUT_ANSWER": 900000, "TIMEOUT_COMMAND_STRING": "__INVALID__RESPONSE__", "DEFINE_STRING_REPLACED": "__REPLACED__", "HE4RT_ICON_1_URL": "https://i.imgur.com/iWhfWMa.png", @@ -12,7 +13,8 @@ "SUCCESS": "#46E363", "ERROR": "#C90B04", "WARNING": "#FFD421", - "INFO": "#7291FA" + "INFO": "#7291FA", + "HINT_ANSWER": "#00FFFF" }, "RESTRICTED_CUSTOM_ROLE_COLORS": [ "#313335", diff --git a/src/events/cron/index.ts b/src/events/cron/index.ts index 2e6e010..6039c8f 100644 --- a/src/events/cron/index.ts +++ b/src/events/cron/index.ts @@ -1,6 +1,8 @@ import { He4rtClient } from '@/types' import { verifyApoiaseMembers } from './apoiase' +import { verifyQuizEvent } from './quiz' export const cronEvents = async (client: He4rtClient) => { await verifyApoiaseMembers(client) + await verifyQuizEvent(client) } diff --git a/src/events/cron/quiz.ts b/src/events/cron/quiz.ts new file mode 100644 index 0000000..5f04181 --- /dev/null +++ b/src/events/cron/quiz.ts @@ -0,0 +1,37 @@ +import { getEvents, updateEventStatus } from '@/http/firebase' +import { He4rtClient } from '@/types' +import { embedTemplate, getChannel } from '@/utils' +import { CronJob } from 'cron' +import { QUIZ_EVENT } from '@/defines/ids.json' + +export const verifyQuizEvent = async (client: He4rtClient) => { + + await new CronJob('0 2 * * *', async () => { + const events = await getEvents(client) + const today = new Date() + + const currentEvent = events.reduce((result, event) => { + if (today >= event.date_start.toDate() && today <= event.date_end.toDate()) { + return event + } + return result + }, null) + + + if (!currentEvent.is_active) { + updateEventStatus(client, currentEvent) + const chat = getChannel({ id: QUIZ_EVENT.id, client }) + const embed = embedTemplate({ + title: 'Novo evento de Q&A disponível 👋', + description: `@everyone ${currentEvent.description}` + }) + await chat.send({ embeds: [embed] }) + } + + events.forEach((event) => { + if (event.is_active && event.date_end.toDate() < today) { + updateEventStatus(client, event) + } + }) + }).start() +} diff --git a/src/events/discord/channel.ts b/src/events/discord/channel.ts index c93c982..fb07c14 100644 --- a/src/events/discord/channel.ts +++ b/src/events/discord/channel.ts @@ -1,125 +1,124 @@ -import { - DEPOSITIONS_CHANNEL, - SUGGESTION_CHANNEL, - CHAT_CHANNEL, - MEETING_CHANNEL, - MEETING_DELAS_CHANNEL, - LEARNING_DIARY_CHANNEL, - ADVERTS_CHANNEL, -} from '@/defines/ids.json' -import { HE4RT_EMOJI_ID } from '@/defines/ids.json' -import { isAdministrator, isImageHTTPUrl, isValidProxyContent, js } from '@/utils' -import { ChannelType, GuildMember, Message, MessageType } from 'discord.js' -import { He4rtClient, MessagePOST } from '@/types' - -export const MessageListener = (client: He4rtClient, message: Message) => { - const member = message.member as GuildMember - - if (!member?.id) return - - if (message.channel.type === ChannelType.DM || client.user?.id === message.author.id || !message.channelId) return - - client.api.he4rt - .messages() - .discord.post({ - // provider_message_parent_id: message.parentId - provider_id: member.id, - provider_message_id: message.id, - channel_id: message.channelId, - content: message.content, - sent_at: message.createdAt, - }) - .catch(() => {}) -} - -export const suppressEmbedMessagesInBusyChannels = async (message: Message) => { - const validChannels = [CHAT_CHANNEL, MEETING_CHANNEL, MEETING_DELAS_CHANNEL] - - if (validChannels.some((v) => v.id === message.channel.id)) { - if ( - message.embeds.length === 0 || - isAdministrator(message.member) || - isValidProxyContent(message.content) || - isImageHTTPUrl(message.content) - ) - return - - await message.suppressEmbeds(true).catch(() => {}) - } -} - -export const sendGoodMessagesInBusyChannels = (message: Message) => { - const validChannels = [CHAT_CHANNEL, MEETING_CHANNEL, MEETING_DELAS_CHANNEL] - - if (validChannels.some((v) => v.id === message.channel.id)) { - const isChatChannel = message.channel.id === CHAT_CHANNEL.id - const content = message.content.toLowerCase().trim() - - if (content.length > 50 && isChatChannel) return - - const date = js().getUTCDate() - - const currentHour = date.getHours() - const currentPeriod = (hour: number) => ({ - dawn: hour < 5, - morning: hour >= 5 && hour < 12, - afternoon: hour >= 12 && hour < 18, - night: hour >= 18, - }) - - if (content.match(/(bom dia)/gi) && currentPeriod(currentHour).morning) { - message.reply({ content: `dia!` }).catch(() => {}) - } else if (content.match(/(boa tarde)/gi) && currentPeriod(currentHour).afternoon) { - message.reply({ content: `tarde!` }).catch(() => {}) - } else if (content.match(/(boa noite)/gi) && currentPeriod(currentHour).night) { - message.reply({ content: `noite!` }).catch(() => {}) - } else if (content.match(/(boa madrugada)/gi) && currentPeriod(currentHour).dawn) { - message.reply({ content: `boa madrugada!` }).catch(() => {}) - } - } -} - -export const bussinOrCap = async (message: Message) => { - const validChannels = [CHAT_CHANNEL, MEETING_CHANNEL, MEETING_DELAS_CHANNEL] - - if (validChannels.some((v) => v.id === message.channel.id)) { - const content = message.content.toLowerCase().split(/\s+/) - const randomness = Math.round((Math.random() % 100) * 100) - - const containsRust = content.includes('rust') - const containsGo = content.includes('go') - - if (containsRust && containsGo && randomness === 69) { - message.reply({ content: 'no cap' }).catch(() => {}) - } else if (containsRust && randomness === 69) { - message.reply({ content: 'bussin' }).catch(() => {}) - } else if (containsGo && randomness === 69) { - message.reply({ content: 'cap' }).catch(() => {}) - } - } -} - -export const reactMessagesInSuggestionChannel = async (message: Message) => { - if (SUGGESTION_CHANNEL.id === message.channel.id && message.type === MessageType.Default) { - await message.react('✅').catch(() => {}) - await message.react('❌').catch(() => {}) - } -} - -export const reactMessagesInLearningDiaryChannel = async (message: Message) => { - if (LEARNING_DIARY_CHANNEL.id === message.channel.id && message.type === MessageType.Default) { - await message.react(HE4RT_EMOJI_ID).catch(() => {}) - } -} - -export const reactAnnouncesInAdvertsChannel = async (message: Message) => { - if (ADVERTS_CHANNEL.id === message.channel.id) { - await message.react(HE4RT_EMOJI_ID).catch(() => {}) - } -} - -export const reactMessagesInDepositionsChannel = async (message: Message) => { - if (DEPOSITIONS_CHANNEL.id === message.channel.id) { - await message.react(HE4RT_EMOJI_ID).catch(() => {}) - } -} +import { + DEPOSITIONS_CHANNEL, + SUGGESTION_CHANNEL, + CHAT_CHANNEL, + MEETING_CHANNEL, + MEETING_DELAS_CHANNEL, + LEARNING_DIARY_CHANNEL, + ADVERTS_CHANNEL +} from '@/defines/ids.json' +import { HE4RT_EMOJI_ID } from '@/defines/ids.json' +import { isAdministrator, isImageHTTPUrl, isValidProxyContent, js } from '@/utils' +import { ChannelType, GuildMember, Message, MessageType } from 'discord.js' +import { He4rtClient, MessagePOST } from '@/types' + +export const MessageListener = (client: He4rtClient, message: Message) => { + const member = message.member as GuildMember + + if (!member?.id) return + + if (message.channel.type === ChannelType.DM || client.user?.id === message.author.id || !message.channelId) return + + client.api.he4rt + .messages() + .discord.post({ + provider_id: member.id, + provider_message_id: message.id, + channel_id: message.channelId, + content: message.content, + sent_at: message.createdAt, + }) + .catch(() => {}) +} + +export const suppressEmbedMessagesInBusyChannels = async (message: Message) => { + const validChannels = [CHAT_CHANNEL, MEETING_CHANNEL, MEETING_DELAS_CHANNEL] + + if (validChannels.some((v) => v.id === message.channel.id)) { + if ( + message.embeds.length === 0 || + isAdministrator(message.member) || + isValidProxyContent(message.content) || + isImageHTTPUrl(message.content) + ) + return + + await message.suppressEmbeds(true).catch(() => {}) + } +} + +export const sendGoodMessagesInBusyChannels = (message: Message) => { + const validChannels = [CHAT_CHANNEL, MEETING_CHANNEL, MEETING_DELAS_CHANNEL] + + if (validChannels.some((v) => v.id === message.channel.id)) { + const isChatChannel = message.channel.id === CHAT_CHANNEL.id + const content = message.content.toLowerCase().trim() + + if (content.length > 50 && isChatChannel) return + + const date = js().getUTCDate() + + const currentHour = date.getHours() + const currentPeriod = (hour: number) => ({ + dawn: hour < 5, + morning: hour >= 5 && hour < 12, + afternoon: hour >= 12 && hour < 18, + night: hour >= 18, + }) + + if (content.match(/(bom dia)/gi) && currentPeriod(currentHour).morning) { + message.reply({ content: `dia!` }).catch(() => {}) + } else if (content.match(/(boa tarde)/gi) && currentPeriod(currentHour).afternoon) { + message.reply({ content: `tarde!` }).catch(() => {}) + } else if (content.match(/(boa noite)/gi) && currentPeriod(currentHour).night) { + message.reply({ content: `noite!` }).catch(() => {}) + } else if (content.match(/(boa madrugada)/gi) && currentPeriod(currentHour).dawn) { + message.reply({ content: `boa madrugada!` }).catch(() => {}) + } + } +} + +export const bussinOrCap = async (message: Message) => { + const validChannels = [CHAT_CHANNEL, MEETING_CHANNEL, MEETING_DELAS_CHANNEL] + + if (validChannels.some((v) => v.id === message.channel.id)) { + const content = message.content.toLowerCase().split(/\s+/) + const randomness = Math.round((Math.random() % 100) * 100) + + const containsRust = content.includes('rust') + const containsGo = content.includes('go') + + if (containsRust && containsGo && randomness === 69) { + message.reply({ content: 'no cap' }).catch(() => {}) + } else if (containsRust && randomness === 69) { + message.reply({ content: 'bussin' }).catch(() => {}) + } else if (containsGo && randomness === 69) { + message.reply({ content: 'cap' }).catch(() => {}) + } + } +} + +export const reactMessagesInSuggestionChannel = async (message: Message) => { + if (SUGGESTION_CHANNEL.id === message.channel.id && message.type === MessageType.Default) { + await message.react('✅').catch(() => {}) + await message.react('❌').catch(() => {}) + } +} + +export const reactMessagesInLearningDiaryChannel = async (message: Message) => { + if (LEARNING_DIARY_CHANNEL.id === message.channel.id && message.type === MessageType.Default) { + await message.react(HE4RT_EMOJI_ID).catch(() => {}) + } +} + +export const reactAnnouncesInAdvertsChannel = async (message: Message) => { + if (ADVERTS_CHANNEL.id === message.channel.id) { + await message.react(HE4RT_EMOJI_ID).catch(() => {}) + } +} + +export const reactMessagesInDepositionsChannel = async (message: Message) => { + if (DEPOSITIONS_CHANNEL.id === message.channel.id) { + await message.react(HE4RT_EMOJI_ID).catch(() => {}) + } +} diff --git a/src/http/firebase.ts b/src/http/firebase.ts index ab4f6d9..6a77d97 100644 --- a/src/http/firebase.ts +++ b/src/http/firebase.ts @@ -1,4 +1,4 @@ -import { FirestoreMedal, FirestoreMedalUser, FirestoreUser, He4rtClient } from '@/types' +import { FirestoreMedal, FirestoreMedalUser, FirestoreUser, FirestoreReward, FirestoreEvent, FirestoreQuiz, He4rtClient } from '@/types' import { defu } from 'defu' export const upsertUser = async (client: He4rtClient, fields: Partial) => { @@ -18,7 +18,7 @@ export const deleteUser = async (client: He4rtClient, fields: Pick) => { const collection = client.firestore.collection('users') - + return collection.doc(fields.id).create({ id: fields.id }) } @@ -135,3 +135,92 @@ export const addUserInMedal = async ( return userCollection.doc(fields.id).set({ id: fields.id, expires_at: fields.expires_at }) } + +const addUserEvent = async (client: He4rtClient, {user, eventId}): Promise => { + const collection = client.firestore.collection('users_event') + + await collection.add({ id: user, event: eventId}) +} + +const updateEventReward = async (client: He4rtClient, reward: FirebaseFirestore.QueryDocumentSnapshot) => { + const collection = client.firestore.collection('rewards') + const entity = defu({earned: true}, reward.data() as FirestoreReward) + + return collection.doc(reward.id).set(entity) +} + +const getReward = async (client: He4rtClient, eventId: string, place?: string) => { + const rewardsCollection = client.firestore.collection('rewards') + const query = place !== 'participant' + ? await rewardsCollection.where('fk_event', '==', eventId).where('earned', '==', false).limit(1).get() + : await rewardsCollection + .where('fk_event', '==', eventId) + .where('place', '==', 'participant') + .where('earned', '==', true) + .limit(1) + .get() + + const reward = query.docs[0] + return reward +} + +export const claimEventReward = async (client: He4rtClient, eventId: string, memberId: string) => { + const result = await getReward(client, eventId) + + const reward = result === undefined ? await getReward(client, eventId, 'participant') : result + + await addUserEvent(client, { user: memberId, eventId }) + await updateEventReward(client, reward) + return reward.data() as FirestoreReward +} + +export const checkUserEventEntry = async (client: He4rtClient, {userId, eventId}): Promise => { + const eventUserCollection = client.firestore.collection('users_event') + + const query = await eventUserCollection + .where('event', '==', eventId) + .where('id', '==', userId) + .limit(1) + .get() + + return !!query.empty +} + +export const getActiveEvent = async (client: He4rtClient) => { + const eventCollection = client.firestore.collection('events') + + const query = await eventCollection + .where('is_active', '==', true) + .limit(1) + .get() + + return !query.empty ? query.docs[0].id : '' +} + +export const getEventQuizzesById = async (client: He4rtClient, eventId) => { + const quizzesCollection = client.firestore.collection('quizzes') + + const query = await quizzesCollection + .where('fk_event', '==', eventId) + .get() + + const questions = query.docs.map((doc) => doc.data()); + return questions as FirestoreQuiz[] +} + +export const getEvents = async (client: He4rtClient) => { + const eventsCollection = client.firestore.collection('events') + + const query = await eventsCollection + .get() + + const events = query.docs.map((doc) => doc.data()); + return events as FirestoreEvent[] +} + +export const updateEventStatus = async (client: He4rtClient, event: FirestoreEvent) => { + const collection = client.firestore.collection('events') + const entity = defu({is_active: !event.is_active}, event) + + return collection.doc(event.id).set(entity) +} diff --git a/src/types.ts b/src/types.ts index b33f0a2..f4ac36c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -19,6 +19,7 @@ import type { ClientBuilder } from 'uncreate' import admin from 'firebase-admin' import { Logger } from './client/logger' import { Ticker } from './client/ticker' +import { Timestamp } from '@google-cloud/firestore' export type Maybe = T | undefined | null export type RESTJson = Record @@ -224,3 +225,29 @@ export interface FirestoreMedalUser { id: string expires_at: string } + +export interface FirestoreReward { + he4rt_xp: number + earned: boolean + badge: string + place: string + id: string + fk_event: string +} + +export interface FirestoreEvent { + date_start: Timestamp + date_end: Timestamp + description: string + is_active: boolean + id: string +} + +export interface FirestoreQuiz { + tip: string + answer: string + has_next_question: boolean + fk_event: number + title: string, + question: string +} diff --git a/src/utils.ts b/src/utils.ts index 1e0e950..f0c3ee6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,431 +1,443 @@ -import { - ButtonInteraction, - CategoryChannel, - Channel, - CommandInteraction, - CommandInteractionOption, - DMChannel, - EmbedBuilder, - ForumChannel, - Guild, - GuildMember, - HexColorString, - Message, - PartialGuildMember, - PermissionFlagsBits, - TextBasedChannel, - User, - VoiceChannel, -} from 'discord.js' -import { CLIENT_NAME, CLIENT_TIMEZONE, COLORS, HE4RT_DELAS_ICON_1_URL, HE4RT_ICON_1_URL } from '@/defines/values.json' -import { - VOLUNTEER_ROLE, - PRESENTING_ROLE, - PRESENTED_ROLE, - DONATOR_ROLE, - NITRO_BOOSTER_ROLE, - HE4RT_DELAS_ROLE, - ATA_ROLE, - VALID_PRESENTATION_DEV_ROLES, - VALID_PRESENTATION_ENG_ROLES, - FORUM_CHANNEL, - DYNAMIC_CATEGORY_CHANNEL, - HE4RTLESS_ROLE, - HE4RT_ROLE, - SUPREME_ROLE, - ADVANCED_ROLE, - INTERMEDIATE_ROLE, - BEGINNER_ROLE, -} from '@/defines/ids.json' -import { - SUCCESS_COMMAND_DEFAULT, - SUCCESS_DM_SEND, - EXECUTING, - ERROR_DEFAULT, - ERROR_INVALID_EMAIL, - ERROR_MISS_PERMISSION, - ERROR_MEMBER_IS_NOT_PRESENTED, - ERROR_ACCESS_DM, - ERROR_INVALID_ARGUMENT, - ERROR_CHANNEL_PERMISSION, - ERROR_CANNOT_BE_BANNED, - ERROR_PAGINATION, - ERROR_PRESENTING, -} from '-/defaults/reply.json' -import { NOT_FOUND, LANGUAGE_NONE } from '-/defaults/display.json' -import { TIMEOUT_COMMAND_STRING, DEFINE_STRING_REPLACED } from '@/defines/values.json' -import { CommandGetOption, EmbedTemplateOptions, GetChannelOptions, He4rtClient } from '@/types' -import { DYNAMIC_VOICE_MIN_SIZE, DYNAMIC_VOICE_MAX_SIZE } from '@/defines/values.json' -import pkg from '../package.json' - -export const validDisplayDevRoles = (member: GuildMember) => { - return ( - member?.roles?.cache - ?.filter((role) => VALID_PRESENTATION_DEV_ROLES.some((v) => v.id === role.id)) - .map((role) => `<@&${role.id}>`) - .join(' ') || LANGUAGE_NONE - ) -} - -export const validDisplayEngRoles = (member: GuildMember) => { - return ( - member?.roles?.cache - ?.filter((role) => VALID_PRESENTATION_ENG_ROLES.some((v) => v.id === role.id)) - .map((role) => `<@&${role.id}>`) - .join(' ') || LANGUAGE_NONE - ) -} - -export const validDisplaySpecialRoles = (member: GuildMember) => { - return ( - member?.roles?.cache - ?.filter((role) => - [HE4RTLESS_ROLE, HE4RT_ROLE, SUPREME_ROLE, ADVANCED_ROLE, INTERMEDIATE_ROLE, BEGINNER_ROLE].some( - (v) => v.id === role.id - ) - ) - .map((role) => `<@&${role.id}>`) - .join(' ') || LANGUAGE_NONE - ) -} - -export const isPresentedMember = (member: GuildMember) => { - return member.roles.cache.some(({ id }) => id === PRESENTED_ROLE.id) -} - -export const isPresentingMember = (member: GuildMember) => { - return member.roles.cache.some(({ id }) => id === PRESENTING_ROLE.id) -} - -export const isPrivilegedMember = (member: GuildMember) => { - return isApoiaseMember(member) || isNitroBoosterMember(member) -} - -export const isApoiaseMember = (member: GuildMember) => { - return member.roles.cache.some(({ id }) => id === DONATOR_ROLE.id) -} - -export const isNitroBoosterMember = (member: GuildMember) => { - return member.roles.cache.some(({ id }) => id === NITRO_BOOSTER_ROLE.id) -} - -export const isHe4rtDelasMember = (member: GuildMember) => { - return member.roles.cache.some(({ id }) => id === HE4RT_DELAS_ROLE.id) -} - -export const isATAMember = (member: GuildMember) => { - return member.roles.cache.some(({ id }) => id === ATA_ROLE.id) -} - -export const isVoluntaryMember = (member: GuildMember) => { - return member.roles.cache.some(({ id }) => id === VOLUNTEER_ROLE.id) -} - -export const isBot = (author: User): boolean => { - return !!author?.bot -} - -export const isAdministrator = (member: GuildMember) => { - return member.permissions.has(PermissionFlagsBits.Administrator, true) -} - -export const isValidMessage = (message: Message) => { - return ( - !isBot(message.author) && message.content && message.member && message.inGuild && message?.id && message?.author?.id - ) -} - -export const isValidId = (id: number, arr: any[]) => { - return !isNaN(id) && id <= arr.length && id > 0 -} - -export const isCustomColorRole = (name: string) => { - return /.+#\d{4}/i.test(name) -} - -export const isCancellable = (str: string) => { - return str === TIMEOUT_COMMAND_STRING -} - -export const hasRole = (member: GuildMember, target: string) => { - return member.roles.cache.some(({ id }) => id === target) -} - -export const normalizeStringData = (str: string) => { - return str !== TIMEOUT_COMMAND_STRING ? str : NOT_FOUND -} - -export const embedTemplate = (options: EmbedTemplateOptions) => { - const embed = new EmbedBuilder() - .setColor( - options.color || (options.delas ? (COLORS.HE4RT_DELAS as HexColorString) : (COLORS.HE4RT as HexColorString)) - ) - .setTitle(options.title) - - if (options.description) embed.setDescription(options.description) - if (options.target?.icon) embed.setThumbnail(getUserAvatar(options.target.user)) - if (options.url) embed.setURL(options.url) - if (options.author?.avatar) embed.setAuthor({ name: options.author.username, iconURL: getUserAvatar(options.author) }) - - options.fields?.forEach((f) => { - embed.addFields(...f) - }) - - if (options.footer === undefined || options.footer) { - embed - .setFooter({ - text: `${new Date().getFullYear()} © ${CLIENT_NAME}`, - iconURL: options.delas ? HE4RT_DELAS_ICON_1_URL : HE4RT_ICON_1_URL, - }) - .setTimestamp() - } - - return embed -} - -export const dynamicVoiceEmbedTemplate = async ( - channel: VoiceChannel | TextBasedChannel, - owner: GuildMember, - options?: { send?: boolean } -) => { - const embed = embedTemplate({ - title: `Canal de Voz Dinâmico`, - description: `Para alterar o limite de membros, use \`/sala-limite\`, sendo o limite mínimo de membros **${DYNAMIC_VOICE_MIN_SIZE}** com o máximo de **${DYNAMIC_VOICE_MAX_SIZE}**. Para transferir o dono da sala a outro membro, use \`/sala-transferir\`. Para alterar o título da sala, use \`/sala-titulo\`. **Atenção: O discord limita alterações do canal de voz em 2 vezes a cada 10 minutos!**`, - fields: [ - [ - { name: '**ID do Canal**', value: channel.id, inline: false }, - { name: '**ID do Dono**', value: owner.id, inline: false }, - ], - ], - }) - - const message = { content: `<@${owner.id}>`, embeds: [embed] } - - if (options?.send) await channel.send(message).catch(() => {}) - - return message -} - -export const getUserAvatar = (author: User) => { - return `https://cdn.discordapp.com/avatars/${author.id}/${author.avatar}.png?size=256` -} - -export const getGuild = ({ guilds }: He4rtClient): Guild => { - return guilds.cache.get(process.env.DISCORD_GUILD_ID) -} - -export function getChannel({ client, id }: GetChannelOptions): T { - return client.channels.cache.get(id) as T -} - -export const getForumChannel = (client: He4rtClient) => { - return client.channels.cache.get(FORUM_CHANNEL.id) as ForumChannel -} - -export const getDynamicVoiceCategory = (client: He4rtClient) => { - return getChannel({ client, id: DYNAMIC_CATEGORY_CHANNEL.id }) -} - -export const getOption: CommandGetOption = (interaction: CommandInteraction, target: string) => { - return interaction.options.get(target) as CommandInteractionOption -} - -export const getCustomColorRole = ({ roles }: GuildMember | PartialGuildMember) => { - return roles.cache.find((x) => isCustomColorRole(x.name)) || false -} - -export const getTaggedMembers = (ids: string[]): string => { - return ids.map((id) => getUserTemplate(id)).join(' ') || '' -} - -export const getUserTemplate = (id: string) => `<@${id}>` - -export const getTargetMember = (member: GuildMember): string => { - return `**${member.id || 0} - ${member.user?.username || 'Indefinido'}**` -} - -export const getBotVersion = (): string => { - return `v${pkg.version}` -} - -export const getOptionType = (arr: { value: number; name: string }[], type: number): string => - arr.reduce((prev, current) => ({ [current.value]: current.name, ...prev }), {})[type] - -export const replaceDefineString = (str: string, target: string) => { - return str.replaceAll(DEFINE_STRING_REPLACED, target) -} - -export const sendInDM = async (dm: DMChannel, interaction: CommandInteraction | ButtonInteraction, str: string) => { - await dm.send(str).catch(async () => { - await reply(interaction).errorInAccessDM() - - return false - }) - - return true -} - -export const openAndSendMessageInDm = ( - client: He4rtClient, - member: GuildMember, - message: string, - suppress: boolean = false -): Promise => { - return new Promise((res) => { - member - ?.createDM() - .then((dm) => { - dm.send(message) - .then(async (msg) => { - if (suppress) await msg.suppressEmbeds(true).catch(() => {}) - - res() - }) - .catch(() => { - client.logger.emit({ - message: `Não foi possível enviar uma mensagem na DM para o usuário ${getTargetMember(member)}!`, - type: 'bot', - color: 'error', - }) - - res() - }) - }) - .catch(() => { - client.logger.emit({ - message: `Não foi possível enviar uma mensagem na DM para o usuário ${getTargetMember(member)}!`, - type: 'bot', - color: 'error', - }) - - res() - }) - }) -} - -export const reply = (interaction: CommandInteraction | ButtonInteraction) => { - const success = async () => { - await interaction.reply({ content: SUCCESS_COMMAND_DEFAULT, ephemeral: true }).catch(() => {}) - } - - const successInAccessDM = async () => { - await interaction.reply({ content: SUCCESS_DM_SEND, ephemeral: true }).catch(() => {}) - } - - const executing = async () => { - await interaction.reply({ content: EXECUTING, ephemeral: true }).catch(() => {}) - } - - const error = async () => { - return await interaction - .reply({ - content: ERROR_DEFAULT, - ephemeral: true, - }) - .catch(() => {}) - } - - const errorInvalidEmail = async () => { - return await interaction.reply({ - content: ERROR_INVALID_EMAIL, - ephemeral: true, - }) - } - - const errorPermission = async () => { - return await interaction.reply({ content: ERROR_MISS_PERMISSION, ephemeral: true }) - } - - const errorMemberIsNotPresented = async () => { - return await interaction.reply({ content: ERROR_MEMBER_IS_NOT_PRESENTED, ephemeral: true }) - } - - const errorInAccessDM = async () => { - await interaction.reply({ content: ERROR_ACCESS_DM, ephemeral: true }) - } - - const errorInMissingArgument = async () => { - await interaction.reply({ content: ERROR_INVALID_ARGUMENT, ephemeral: true }) - } - - const errorUserCannotBeBaned = async () => { - await interaction.reply({ content: ERROR_CANNOT_BE_BANNED, ephemeral: true }) - } - - const errorSpecificChannel = async (str: string) => { - await interaction.reply({ content: `${ERROR_CHANNEL_PERMISSION}${str}!`, ephemeral: true }) - } - - const errorPaginationFail = async () => { - await interaction.reply({ content: ERROR_PAGINATION, ephemeral: true }) - } - - const errorPresentingFail = async () => { - await interaction.reply({ content: ERROR_PRESENTING, ephemeral: true }) - } - - return { - success, - successInAccessDM, - executing, - error, - errorInvalidEmail, - errorPermission, - errorMemberIsNotPresented, - errorInAccessDM, - errorInMissingArgument, - errorUserCannotBeBaned, - errorSpecificChannel, - errorPaginationFail, - errorPresentingFail, - } -} - -export const isImageHTTPUrl = (url: string) => { - return url.match(/^https?:\/\/.*\/.*\.(png|gif|webp|jpeg|jpg)\??.*$/gim) -} - -export const isHex = (str: string) => { - return str.match(/^#[0-9A-F]{6}$/i) -} - -export const isValidProxyContent = (str: string) => { - return ['https://tenor.com', 'https://forms.gle'].some((v) => str.trim().startsWith(v)) -} - -export const js = () => { - const sleep = (ms: number) => { - return new Promise((resolve) => setTimeout(resolve, ms)) - } - - const getUTCDate = () => { - const date = new Date() - date.toLocaleString('pt-BR', { - timeZone: CLIENT_TIMEZONE, - }) - - return date - } - - const getFullTime = (): string => { - const date = getUTCDate() - - return `${date.getFullYear()}-${date.getMonth()}-${date.getDay()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` - } - - const getTime = (): string => { - const date = getUTCDate() - - let hours = (date.getHours() < 10 ? '0' : '') + date.getHours() - - let minutes = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes() - - return `${hours}:${minutes}` - } - - const randomHex = (): HexColorString => { - return `#${Math.floor(Math.random() * 16777215).toString(16)}` - } - - return { sleep, getUTCDate, getFullTime, getTime, randomHex } -} +import { + ButtonInteraction, + CategoryChannel, + Channel, + CommandInteraction, + CommandInteractionOption, + DMChannel, + EmbedBuilder, + ForumChannel, + Guild, + GuildMember, + HexColorString, + Message, + PartialGuildMember, + PermissionFlagsBits, + TextBasedChannel, + User, + VoiceChannel, +} from 'discord.js' +import { CLIENT_NAME, CLIENT_TIMEZONE, COLORS, HE4RT_DELAS_ICON_1_URL, HE4RT_ICON_1_URL } from '@/defines/values.json' +import { + VOLUNTEER_ROLE, + PRESENTING_ROLE, + PRESENTED_ROLE, + DONATOR_ROLE, + NITRO_BOOSTER_ROLE, + HE4RT_DELAS_ROLE, + ATA_ROLE, + VALID_PRESENTATION_DEV_ROLES, + VALID_PRESENTATION_ENG_ROLES, + FORUM_CHANNEL, + DYNAMIC_CATEGORY_CHANNEL, + HE4RTLESS_ROLE, + HE4RT_ROLE, + SUPREME_ROLE, + ADVANCED_ROLE, + INTERMEDIATE_ROLE, + BEGINNER_ROLE, +} from '@/defines/ids.json' +import { + SUCCESS_COMMAND_DEFAULT, + SUCCESS_DM_SEND, + EXECUTING, + ERROR_DEFAULT, + ERROR_INVALID_EMAIL, + ERROR_MISS_PERMISSION, + ERROR_MEMBER_IS_NOT_PRESENTED, + ERROR_ACCESS_DM, + ERROR_INVALID_ARGUMENT, + ERROR_CHANNEL_PERMISSION, + ERROR_CANNOT_BE_BANNED, + ERROR_PAGINATION, + ERROR_PRESENTING, + ERROR_EVENT_NOT_FOUND, + ERROR_PARTICIPANT_EVENT +} from '-/defaults/reply.json' +import { NOT_FOUND, LANGUAGE_NONE } from '-/defaults/display.json' +import { TIMEOUT_COMMAND_STRING, DEFINE_STRING_REPLACED } from '@/defines/values.json' +import { CommandGetOption, EmbedTemplateOptions, GetChannelOptions, He4rtClient } from '@/types' +import { DYNAMIC_VOICE_MIN_SIZE, DYNAMIC_VOICE_MAX_SIZE } from '@/defines/values.json' +import pkg from '../package.json' + +export const validDisplayDevRoles = (member: GuildMember) => { + return ( + member?.roles?.cache + ?.filter((role) => VALID_PRESENTATION_DEV_ROLES.some((v) => v.id === role.id)) + .map((role) => `<@&${role.id}>`) + .join(' ') || LANGUAGE_NONE + ) +} + +export const validDisplayEngRoles = (member: GuildMember) => { + return ( + member?.roles?.cache + ?.filter((role) => VALID_PRESENTATION_ENG_ROLES.some((v) => v.id === role.id)) + .map((role) => `<@&${role.id}>`) + .join(' ') || LANGUAGE_NONE + ) +} + +export const validDisplaySpecialRoles = (member: GuildMember) => { + return ( + member?.roles?.cache + ?.filter((role) => + [HE4RTLESS_ROLE, HE4RT_ROLE, SUPREME_ROLE, ADVANCED_ROLE, INTERMEDIATE_ROLE, BEGINNER_ROLE].some( + (v) => v.id === role.id + ) + ) + .map((role) => `<@&${role.id}>`) + .join(' ') || LANGUAGE_NONE + ) +} + +export const isPresentedMember = (member: GuildMember) => { + return member.roles.cache.some(({ id }) => id === PRESENTED_ROLE.id) +} + +export const isPresentingMember = (member: GuildMember) => { + return member.roles.cache.some(({ id }) => id === PRESENTING_ROLE.id) +} + +export const isPrivilegedMember = (member: GuildMember) => { + return isApoiaseMember(member) || isNitroBoosterMember(member) +} + +export const isApoiaseMember = (member: GuildMember) => { + return member.roles.cache.some(({ id }) => id === DONATOR_ROLE.id) +} + +export const isNitroBoosterMember = (member: GuildMember) => { + return member.roles.cache.some(({ id }) => id === NITRO_BOOSTER_ROLE.id) +} + +export const isHe4rtDelasMember = (member: GuildMember) => { + return member.roles.cache.some(({ id }) => id === HE4RT_DELAS_ROLE.id) +} + +export const isATAMember = (member: GuildMember) => { + return member.roles.cache.some(({ id }) => id === ATA_ROLE.id) +} + +export const isVoluntaryMember = (member: GuildMember) => { + return member.roles.cache.some(({ id }) => id === VOLUNTEER_ROLE.id) +} + +export const isBot = (author: User): boolean => { + return !!author?.bot +} + +export const isAdministrator = (member: GuildMember) => { + return member.permissions.has(PermissionFlagsBits.Administrator, true) +} + +export const isValidMessage = (message: Message) => { + return ( + !isBot(message.author) && message.content && message.member && message.inGuild && message?.id && message?.author?.id + ) +} + +export const isValidId = (id: number, arr: any[]) => { + return !isNaN(id) && id <= arr.length && id > 0 +} + +export const isCustomColorRole = (name: string) => { + return /.+#\d{4}/i.test(name) +} + +export const isCancellable = (str: string) => { + return str === TIMEOUT_COMMAND_STRING +} + +export const hasRole = (member: GuildMember, target: string) => { + return member.roles.cache.some(({ id }) => id === target) +} + +export const normalizeStringData = (str: string) => { + return str !== TIMEOUT_COMMAND_STRING ? str : NOT_FOUND +} + +export const embedTemplate = (options: EmbedTemplateOptions) => { + const embed = new EmbedBuilder() + .setColor( + options.color || (options.delas ? (COLORS.HE4RT_DELAS as HexColorString) : (COLORS.HE4RT as HexColorString)) + ) + .setTitle(options.title) + + if (options.description) embed.setDescription(options.description) + if (options.target?.icon) embed.setThumbnail(getUserAvatar(options.target.user)) + if (options.url) embed.setURL(options.url) + if (options.author?.avatar) embed.setAuthor({ name: options.author.username, iconURL: getUserAvatar(options.author) }) + + options.fields?.forEach((f) => { + embed.addFields(...f) + }) + + if (options.footer === undefined || options.footer) { + embed + .setFooter({ + text: `${new Date().getFullYear()} © ${CLIENT_NAME}`, + iconURL: options.delas ? HE4RT_DELAS_ICON_1_URL : HE4RT_ICON_1_URL, + }) + .setTimestamp() + } + + return embed +} + +export const dynamicVoiceEmbedTemplate = async ( + channel: VoiceChannel | TextBasedChannel, + owner: GuildMember, + options?: { send?: boolean } +) => { + const embed = embedTemplate({ + title: `Canal de Voz Dinâmico`, + description: `Para alterar o limite de membros, use \`/sala-limite\`, sendo o limite mínimo de membros **${DYNAMIC_VOICE_MIN_SIZE}** com o máximo de **${DYNAMIC_VOICE_MAX_SIZE}**. Para transferir o dono da sala a outro membro, use \`/sala-transferir\`. Para alterar o título da sala, use \`/sala-titulo\`. **Atenção: O discord limita alterações do canal de voz em 2 vezes a cada 10 minutos!**`, + fields: [ + [ + { name: '**ID do Canal**', value: channel.id, inline: false }, + { name: '**ID do Dono**', value: owner.id, inline: false }, + ], + ], + }) + + const message = { content: `<@${owner.id}>`, embeds: [embed] } + + if (options?.send) await channel.send(message).catch(() => {}) + + return message +} + +export const getUserAvatar = (author: User) => { + return `https://cdn.discordapp.com/avatars/${author.id}/${author.avatar}.png?size=256` +} + +export const getGuild = ({ guilds }: He4rtClient): Guild => { + return guilds.cache.get(process.env.DISCORD_GUILD_ID) +} + +export function getChannel({ client, id }: GetChannelOptions): T { + return client.channels.cache.get(id) as T +} + +export const getForumChannel = (client: He4rtClient) => { + return client.channels.cache.get(FORUM_CHANNEL.id) as ForumChannel +} + +export const getDynamicVoiceCategory = (client: He4rtClient) => { + return getChannel({ client, id: DYNAMIC_CATEGORY_CHANNEL.id }) +} + +export const getOption: CommandGetOption = (interaction: CommandInteraction, target: string) => { + return interaction.options.get(target) as CommandInteractionOption +} + +export const getCustomColorRole = ({ roles }: GuildMember | PartialGuildMember) => { + return roles.cache.find((x) => isCustomColorRole(x.name)) || false +} + +export const getTaggedMembers = (ids: string[]): string => { + return ids.map((id) => getUserTemplate(id)).join(' ') || '' +} + +export const getUserTemplate = (id: string) => `<@${id}>` + +export const getTargetMember = (member: GuildMember): string => { + return `**${member.id || 0} - ${member.user?.username || 'Indefinido'}**` +} + +export const getBotVersion = (): string => { + return `v${pkg.version}` +} + +export const getOptionType = (arr: { value: number; name: string }[], type: number): string => + arr.reduce((prev, current) => ({ [current.value]: current.name, ...prev }), {})[type] + +export const replaceDefineString = (str: string, target: string) => { + return str.replaceAll(DEFINE_STRING_REPLACED, target) +} + +export const sendInDM = async (dm: DMChannel, interaction: CommandInteraction | ButtonInteraction, str: string, embed?: EmbedBuilder) => { + await dm.send({ content: str, embeds: [embed] }).catch(async () => { + await reply(interaction).errorInAccessDM() + + return false + }) + + return true +} + +export const openAndSendMessageInDm = ( + client: He4rtClient, + member: GuildMember, + message: string, + suppress: boolean = false +): Promise => { + return new Promise((res) => { + member + ?.createDM() + .then((dm) => { + dm.send(message) + .then(async (msg) => { + if (suppress) await msg.suppressEmbeds(true).catch(() => {}) + + res() + }) + .catch(() => { + client.logger.emit({ + message: `Não foi possível enviar uma mensagem na DM para o usuário ${getTargetMember(member)}!`, + type: 'bot', + color: 'error', + }) + + res() + }) + }) + .catch(() => { + client.logger.emit({ + message: `Não foi possível enviar uma mensagem na DM para o usuário ${getTargetMember(member)}!`, + type: 'bot', + color: 'error', + }) + + res() + }) + }) +} + +export const reply = (interaction: CommandInteraction | ButtonInteraction) => { + const success = async () => { + await interaction.reply({ content: SUCCESS_COMMAND_DEFAULT, ephemeral: true }).catch(() => {}) + } + + const successInAccessDM = async () => { + await interaction.reply({ content: SUCCESS_DM_SEND, ephemeral: true }).catch(() => {}) + } + + const executing = async () => { + await interaction.reply({ content: EXECUTING, ephemeral: true }).catch(() => {}) + } + + const error = async () => { + return await interaction + .reply({ + content: ERROR_DEFAULT, + ephemeral: true, + }) + .catch(() => {}) + } + + const errorInvalidEmail = async () => { + return await interaction.reply({ + content: ERROR_INVALID_EMAIL, + ephemeral: true, + }) + } + + const errorPermission = async () => { + return await interaction.reply({ content: ERROR_MISS_PERMISSION, ephemeral: true }) + } + + const errorMemberIsNotPresented = async () => { + return await interaction.reply({ content: ERROR_MEMBER_IS_NOT_PRESENTED, ephemeral: true }) + } + + const errorInAccessDM = async () => { + await interaction.reply({ content: ERROR_ACCESS_DM, ephemeral: true }) + } + + const errorInMissingArgument = async () => { + await interaction.reply({ content: ERROR_INVALID_ARGUMENT, ephemeral: true }) + } + + const errorUserCannotBeBaned = async () => { + await interaction.reply({ content: ERROR_CANNOT_BE_BANNED, ephemeral: true }) + } + + const errorSpecificChannel = async (str: string) => { + await interaction.reply({ content: `${ERROR_CHANNEL_PERMISSION}${str}!`, ephemeral: true }) + } + + const errorPaginationFail = async () => { + await interaction.reply({ content: ERROR_PAGINATION, ephemeral: true }) + } + + const errorPresentingFail = async () => { + await interaction.reply({ content: ERROR_PRESENTING, ephemeral: true }) + } + + const errorParticipantFail = async () => { + await interaction.reply({ content: ERROR_PARTICIPANT_EVENT, ephemeral: true }) + } + + const errorEventNotFound = async () => { + await interaction.reply({ content: ERROR_EVENT_NOT_FOUND, ephemeral: true }) + } + + return { + success, + successInAccessDM, + executing, + error, + errorInvalidEmail, + errorPermission, + errorMemberIsNotPresented, + errorInAccessDM, + errorInMissingArgument, + errorUserCannotBeBaned, + errorSpecificChannel, + errorPaginationFail, + errorPresentingFail, + errorParticipantFail, + errorEventNotFound + } +} + +export const isImageHTTPUrl = (url: string) => { + return url.match(/^https?:\/\/.*\/.*\.(png|gif|webp|jpeg|jpg)\??.*$/gim) +} + +export const isHex = (str: string) => { + return str.match(/^#[0-9A-F]{6}$/i) +} + +export const isValidProxyContent = (str: string) => { + return ['https://tenor.com', 'https://forms.gle'].some((v) => str.trim().startsWith(v)) +} + +export const js = () => { + const sleep = (ms: number) => { + return new Promise((resolve) => setTimeout(resolve, ms)) + } + + const getUTCDate = () => { + const date = new Date() + date.toLocaleString('pt-BR', { + timeZone: CLIENT_TIMEZONE, + }) + + return date + } + + const getFullTime = (): string => { + const date = getUTCDate() + + return `${date.getFullYear()}-${date.getMonth()}-${date.getDay()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}` + } + + const getTime = (): string => { + const date = getUTCDate() + + let hours = (date.getHours() < 10 ? '0' : '') + date.getHours() + + let minutes = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes() + + return `${hours}:${minutes}` + } + + const randomHex = (): HexColorString => { + return `#${Math.floor(Math.random() * 16777215).toString(16)}` + } + + return { sleep, getUTCDate, getFullTime, getTime, randomHex } +}