diff --git a/README.md b/README.md index 68d6edc..fe25ad5 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,14 @@ Para rodar no ambiente de testes, utilize `npm run dev` (irá funcionar como o N - /help => Mostra os comandos disponíveis. +- ### Admin-Only + +- /advert @username => Envia uma advertência para um usuário alvo. Ao receber 3, a conta dele será bloquada + +- /block @username => Bloqueia um usário, impedindo o de usar sua conta ou recria-la. + +automaticamente. + ## Estrutura do projeto - **commands** diff --git a/src/commands/command-execute.ts b/src/commands/command-execute.ts index daf2007..33d33da 100644 --- a/src/commands/command-execute.ts +++ b/src/commands/command-execute.ts @@ -12,7 +12,8 @@ import { startCommand, pokeCommand, deleteCommand, - profileCommand + profileCommand, + blockCommand, } from './resolvers'; export const commandExecuter: CommandExecuter = { @@ -28,5 +29,6 @@ export const commandExecuter: CommandExecuter = { friends: friendsCommand, poke: pokeCommand, notify: notifyCommand, - profile: profileCommand + profile: profileCommand, + block: blockCommand, }; diff --git a/src/commands/resolvers/block.ts b/src/commands/resolvers/block.ts new file mode 100644 index 0000000..3a7ead8 --- /dev/null +++ b/src/commands/resolvers/block.ts @@ -0,0 +1,131 @@ +import { CommandStateResolver } from '../../models/commands'; +import { ApproximaClient } from '../../services/client'; +import { IUser } from '../../models/user'; + +interface IAdmin { + name: string; + telegramId: number; +} + +interface IBlockContext { + admins: IAdmin[]; + isTest: boolean; +} + +interface IChosenUserContext { + chosenUser: IUser; +} + +const handleUserToBlock = async (client: ApproximaClient, username: string | undefined) => { + + const { currentUser, context } = client.getCurrentState(); + + if (username === undefined) return 'CHOICE_USER'; + + if (!username.startsWith('@')) { + /* eslint-disable max-len */ + const reply = 'Você precisa colocar um "@" antes do username para que funcione!\n' + + 'Caso o usuário não possua um username com @ no começo, não será possível realizar essa ação.\n\n' + + 'Envie um ponto (.) caso não queira mais prosseguir com o bloqueio.'; + /* eslint-enable max-len */ + + client.sendMessage(reply); + return 'CHOICE_USER'; + } + + if (currentUser.username === username) { + client.sendMessage('Você não pode dar poke em si mesmo!'); + return 'CHOICE_USER'; + } + + const user = await client.db.user.getByUsername(username); + + if (!user) { + client.sendMessage('O usuário solicitado não existe :/\nEnvie sua resposta novamente.\n'); + client.registerAction('block_command', { + target: username, exists: false + }); + + return 'CHOICE_USER' as const; + + } + else if (user.blocked === true && user.active === false) { + client.sendMessage('Usuário ' + user.username + ' já está bloquado.\n\n'); + + return 'END'; + } + + context.chosenUser = user; + + // + const response = 'Digite a mensagem que o usuário sobre o motivo do bloqueio.\n' + + 'Para deixar em branco, envie uma virgula \',\'.\n\n' + + 'Envie um ponto (.) caso não queira mais prosseguir com o bloqueio.'; + + client.sendMessage(response); + + return 'SEND' as const; +}; + + +export const blockCommand: CommandStateResolver<'block'> = { + // arg => Nome do usuario que deseja bloquear + INITIAL: async (client, _arg, originalArg) => { + let isAdmin = false; + + const state = client.getCurrentState(); + + // Confere se o user é admin + state.context.admins = JSON.parse(process.env.ADMINS!); + + for (const admin of state.context.admins) { + if (client.userId == admin.telegramId) { + isAdmin = true; + break; + } + } + if (!isAdmin) { + const response = 'O que você está tentando fazer? Esse comando é só para admins.'; + client.sendMessage(response); + + return 'END' as const; + } + + // Se tiver um argumento o usuario ja escolheu alguem para dar poke + if (originalArg != undefined && originalArg != '') { + return handleUserToBlock(client, originalArg); + } + + const response = 'Agora, me fale o username (@algoaqui) do usuário que você quer bloquear!\n' + + 'Envie um ponto (.) caso tenha desistido.'; + client.sendMessage(response); + + return 'CHOICE_USER' as const; + }, + CHOICE_USER: async (client, arg, originalArg) => { + if (arg === '.') { + client.sendMessage('Ok! Não vou prosseguir com o bloqueio.'); + return 'END'; + } + return handleUserToBlock(client, originalArg); + }, + SEND: async (client, arg, originalArg) => { + const { currentUser, context } = client.getCurrentState(); + + if (arg === '.') { + client.sendMessage('Ok! Não vou prosseguir com o bloqueio.'); + return 'END'; + } + + // Blocking the user and turn it inactive + client.db.user.edit(context.chosenUser._id, { blocked: true, active: false }); + client.sendMessage(`${currentUser.username}: ` + originalArg, + undefined, + { chatId: context.chosenUser.chat_id }); + client.sendMessage('Bloqueio efetuado.\n'); + client.registerAction('block_command', { + target: context.chosenUser.username, exists: true + }); + return 'END' as const; + } +}; diff --git a/src/commands/resolvers/index.ts b/src/commands/resolvers/index.ts index 632c0de..2159e52 100644 --- a/src/commands/resolvers/index.ts +++ b/src/commands/resolvers/index.ts @@ -11,3 +11,4 @@ export { notifyCommand } from './notify'; export { pokeCommand } from './poke'; export { deleteCommand } from './delete'; export { profileCommand } from './profile'; +export { blockCommand } from './block'; diff --git a/src/commands/resolvers/start.ts b/src/commands/resolvers/start.ts index 976ff0d..6d37181 100644 --- a/src/commands/resolvers/start.ts +++ b/src/commands/resolvers/start.ts @@ -15,7 +15,14 @@ export const startCommand: CommandStateResolver<'start'> = { let newUser = false; if (user) { - if (user.active) { + if (user.blocked) { + const message = 'Infelizmente você não está autorizado a usar este serviço\n' + + 'Boa sorte.\n'; + + client.sendMessage(message); + return 'END'; + } + else if (user.active) { client.registerAction('start_command', { new_user: newUser }); const message = 'É muito bom ter você de volta! Bora começar a usar o Approxima :)\n' + @@ -127,6 +134,7 @@ export const startCommand: CommandStateResolver<'start'> = { pending: [], connections: [], active: true, + blocked: false, updated_at: new Date() }); diff --git a/src/data/commands-and-states.ts b/src/data/commands-and-states.ts index 9beb179..b8449d6 100644 --- a/src/data/commands-and-states.ts +++ b/src/data/commands-and-states.ts @@ -12,5 +12,6 @@ export const commandsAndStates = { friends: ['CHOOSE_PAGE'], poke: ['CHOOSE_USER', 'CHOOSE_MODE'], notify: ['SEND'], - profile: [] + profile: [], + block: ['CHOICE_USER', 'SEND'], } as const; diff --git a/src/database/controllers/user.ts b/src/database/controllers/user.ts index d14fa6e..291c834 100644 --- a/src/database/controllers/user.ts +++ b/src/database/controllers/user.ts @@ -56,9 +56,9 @@ export class UserController { } } - getByUsername = async (username: string): Promise => { + getByUsername = async (username: string, active: boolean = true): Promise => { try { - const data = await this.userRepository.getByUsername(username); + const data = await this.userRepository.getByUsername(username, active); if (!data) { throw new Error('User not found'); } diff --git a/src/database/repositories/user.ts b/src/database/repositories/user.ts index 677d815..8e881b3 100644 --- a/src/database/repositories/user.ts +++ b/src/database/repositories/user.ts @@ -74,11 +74,11 @@ export class UserRepository { } } - getByUsername = async (username: string): Promise => { + getByUsername = async (username: string, active: boolean = true): Promise => { const encryptedUsername = await encrypt(username); return this.usersCollection.findOne({ username: encryptedUsername, - active: true + active: active }).then(decryptUser); } diff --git a/src/models/stats.ts b/src/models/stats.ts index aa86836..624bc7c 100644 --- a/src/models/stats.ts +++ b/src/models/stats.ts @@ -24,6 +24,7 @@ const stateActions = [ 'delete_command', 'common_prefs', 'profile_command', + 'block_command', ] as const; export type StatsActions = typeof stateActions[number]; diff --git a/src/models/user.ts b/src/models/user.ts index 4ce882a..6dfb1b8 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -12,5 +12,7 @@ export interface IUser { connections: number[]; pokes?: number[]; active: boolean; + blocked: boolean; + updated_at: Date; }