/* eslint-disable max-len */
/* Requires */
const path = require('path');
const fs = require('fs');
const BSQLite = require('better-sqlite3');
const Indexer = require('../../index');
/* Define o local da database SQL */
const dialogsSQL = path.normalize(`${irisPath}/lib/Databases/Informations/dialogues.db`);
const extrasSQL = path.normalize(`${irisPath}/lib/Databases/Utilities/extras.db`);
/* JSON | Utilidades */
const envInfo = JSON.parse(fs.readFileSync(`${__dirname}/utils.json`));
let allLanguages = [];
const databaseSQL = path.normalize(`${irisPath}/lib/Databases/Informations/${envInfo?.parameters?.databaseName?.value || 'general.db'}`);
/**
* Cria uma nova instância da database SQLite
* @constant {BSQLite}
*/
const sqlDatabase = new BSQLite(databaseSQL);
const dialDatabase = new BSQLite(dialogsSQL);
const extrasDatabase = new BSQLite(extrasSQL);
/**
* Remove comentários e linhas vazias do código SQL
* @param {string} sql - A string SQL original
* @returns {string} - A string SQL sem comentários e linhas vazias
*/
function removeCommentsAndEmptyLines(sql) {
return (sql
.split('\n')
.filter((line) => {
const trimmedLine = line.trim();
return trimmedLine && !trimmedLine.startsWith('--');
})
.join('\n')
);
}
/**
* Executa um comando SQL de forma síncrona
* @param {string} sql - O comando SQL a ser executado
* @param {Object} params - Parâmetros para substituição no SQL
* @returns {any} - O resultado da execução do SQL
*/
function executeSQLCommand(sql) {
/* Executa em try-catch para caso dê erro no exec */
try {
/* Faz a remoção dos comentários no SQL */
const finalSQL = removeCommentsAndEmptyLines(sql);
/* Filtra as linhas de comandos */
const sqlCommands = finalSQL.split(';').filter((command) => command.trim() !== '');
/* Define o resultado ou DB */
let selectResult;
/* Executa linha a linha dos comandos */
sqlCommands.forEach((command) => {
/* Se começar com SELECT significa final */
const lastCommand = sqlCommands[sqlCommands.length - 1].toUpperCase();
if (lastCommand.includes('SELECT') && command.toUpperCase() === lastCommand) {
/* O que faz com que o resultado seja posto na let feita acima */
selectResult = sqlDatabase.prepare(command).get();
/* Caso contrário, só continua executando */
} else sqlDatabase.exec(command);
});
/* Tenta fazer um parse dentro do try-catch, pois se não for nele, dará erros */
try {
/* Resultado ? Valores : Falso (Indica não ter dados) */
return selectResult ? JSON.parse(selectResult[Object.keys(selectResult)[0]]) : false;
/* Se o parse falhar */
} catch (error) {
/* Retorna que esta sem dados também */
return false;
}
/* Caso a execução na DB falhe */
} catch (error) {
/* Retorna o erro via logging */
logging.echoError(error, envInfo, __dirname);
/* E um aviso que não tem dados */
return false;
}
}
/**
* Retorna todos os detalhes do ambiente (`envInfo`).
*
* @returns {Object} O objeto `envInfo`, que contém os detalhes do ambiente da execução.
*/
function ambientDetails() {
/* Retorna a envData */
return envInfo;
}
/**
* Localiza a pasta correta com base no nome fornecido.
* @function locateFolder
* @param {string} foldername - Nome da pasta a ser localizada.
* @returns {string} Nome da pasta encontrada ou 'NONE/EXIT' se não encontrada.
*/
function locateFolder(foldername) {
/* Lista os nomes das pastas no diretório atual */
const folders = fs.readdirSync(__dirname);
/* Busca a pasta correta do arquivo SQL, ignorando maiúsculas e minúsculas */
const foundFolder = folders.find((fd) => fd.toLowerCase() === foldername.toLowerCase()) || 'NONE/EXIT';
/* Retorna a pasta encontrada */
return foundFolder;
}
/**
* Executa um comando SQLite3 com base nos parâmetros fornecidos.
* @function executeSQLite
* @param {string} sqlfolder - Nome da pasta onde o arquivo SQL está localizado.
* @param {string} typecode - Nome do arquivo SQL (sem extensão).
* @param {string} user - Identificador do usuário.
* @param {string} chatId - Identificador do chat.
* @param {string} keyup - Chave para atualização.
* @param {string} limit - Limite para a consulta.
* @param {string} value - Valor a ser inserido ou atualizado.
* @returns {void}
*/
function executeSQLite(sqlfolder, typecode, user, chatId, keyup, limit, value) {
/* Determina se vai rodar */
if ([sqlfolder, typecode, user, chatId, keyup, limit, value].some((s) => s !== null)) {
/* Define a pasta correta */
const file = locateFolder(sqlfolder);
/* Redefine como padrão */
envInfo.results.value = envInfo.parameters.standard.value[file] || {};
envInfo.results.value.error = `This function is not available because '${typecode}.sql' is not a function of '${file}', please check if you spelled it correctly or if your function resides on another system.`;
/* Define o arquivo de SQL */
const sqlFilePath = `${__dirname}/${file}/${typecode}.sql`;
/* Verifica se o arquivo existe */
if (fs.existsSync(sqlFilePath)) {
/* Ajusta a mensagem de erro para false, pois o arquivo existe */
envInfo.results.value.error = false;
/* Obtém o código SQL do arquivo em questão */
let codeSQL = fs.readFileSync(sqlFilePath, 'utf8');
/* Faz as edições necessárias no código SQL */
codeSQL = (codeSQL.replace(/{INSERTGROUP}/gi, `${chatId ?? user}`)
.replace(/{INSERTKEY}/gi, `${keyup ?? ''}`)
.replace(/{INSERTJSON}/gi, `${value ?? ''}`)
.replace(/{INSERTMATHSYM}/gi, `${limit ?? ''}`)
.replace(/{INSERTLANG}/gi, `${region ?? 'pt'}`)
.replace(/{INSERTUSER}/gi, `${user ?? chatId}`)
.replace(/{INSERTDEFAULT}/gi, `${JSON.stringify(envInfo.parameters.standard.value[file] || {})}`)
);
/* Roda o comando que insere dados no arquivo de database */
const sqlResponse = executeSQLCommand(codeSQL);
/* Se for false significa que não tem dados */
if (sqlResponse !== false) {
/* Mas caso não, é sinal que deu certo */
envInfo.results.value = sqlResponse;
}
}
}
}
/**
* Valida e corrige um JSON.
* @function validateJSON
* @param {string|Object} [stringJSON=envInfo.functions.fixer.parameters.stringJSON.value] - JSON a ser validado.
* @returns {string|boolean} Retorna o JSON válido como string ou `false` em caso de erro.
*/
function validateJSON(
stringJSON = envInfo.functions.fixer.parameters.stringJSON.value,
) {
/* Inicia com try, caso der algum erro */
try {
/* Se for uma string, faz os ajustes necessários */
const adjustedJSON = (typeof stringJSON === 'string'
? stringJSON.trim().replace(/^[^{[]*|[^}\]]*$/g, '').replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2": ').replace(/'/g, '"')
: JSON.stringify(stringJSON)
);
/* Faz uma tentativa de parse para saber se é válido */
const parsedJSON = JSON.parse(adjustedJSON);
/* Retorna o JSON válido */
return JSON.stringify(parsedJSON);
/* Se der algum erro */
} catch (error) {
/* Retorna false em caso de erro */
return false;
}
}
/**
* Adquire um ou todos os valores de uma base de dados.
* @function getValues
* @param {string} [file=envInfo.functions.get.arguments.file.value] - Nome do arquivo SQL.
* @param {string} [user=envInfo.functions.get.arguments.chatId.value] - Identificador do usuário.
* @param {string} [chatId=envInfo.functions.get.arguments.chatId.value] - Identificador do chat.
* @returns {Object} Retorna os valores obtidos ou um objeto padrão em caso de erro.
*/
function getValues(
file = envInfo.functions.get.arguments.file.value,
user = envInfo.functions.get.arguments.chatId.value,
chatId = envInfo.functions.get.arguments.chatId.value,
) {
/* Define o valor final como o padrão */
envInfo.results.value = envInfo.parameters.standard.value[locateFolder(file)] || {};
/* Define o sucesso do SQL */
envInfo.results.value.error = false;
/* Define o sucesso */
envInfo.results.success = false;
/* Try-Catch para casos de erro */
try {
/* Verifica se os valores de string estão corretos */
const isStringValid = typeof file === 'string' && /@s.whatsapp.net|false/gi.test(user) && /@g.us|false|@s.whatsapp.net|getall/gi.test(chatId);
/* Verifica se as condições batem */
if (isStringValid) {
/* Define se é para pegar todos os valores ou apenas um */
const funUsage = chatId === 'getall' ? 'getall' : 'get';
/* Executa o comando */
executeSQLite(file, funUsage, user, chatId, false, false, false);
/* Se as condições derem algum erro */
} else {
/* Define o erro como explicação */
envInfo.results.value.error = 'The usage method is incorrect. A default object will be sent to avoid errors.';
}
/* Define o sucesso */
envInfo.results.success = true;
/* Se der algum erro */
} catch (error) {
/* Insere tudo na envInfo */
logging.echoError(error, envInfo, __dirname);
}
/* Retorna os valores; caso nada acima seja feito, retorna os padrões */
return logging.postResults(envInfo);
}
/**
* Atualiza um valor específico na base de dados.
* @function updateValues
* @param {string} [file=envInfo.functions.update.arguments.file.value] - Nome do arquivo SQL.
* @param {string} [user=envInfo.functions.update.arguments.user.value] - Identificador do usuário.
* @param {string} [chatId=envInfo.functions.update.arguments.chatId.value] - Identificador do chat.
* @param {string} [keyup=envInfo.functions.update.arguments.keyup.value] - Chave para atualização.
* @param {string|Object} [value=envInfo.functions.update.arguments.value.value] - Valor a ser atualizado.
* @returns {Object} Retorna os valores atualizados ou um objeto padrão em caso de erro.
*/
function updateValues(
file = envInfo.functions.update.arguments.file.value,
user = envInfo.functions.update.arguments.user.value,
chatId = envInfo.functions.update.arguments.chatId.value,
keyup = envInfo.functions.update.arguments.keyup.value,
value = envInfo.functions.update.arguments.value.value,
) {
/* Define o valor final como o padrão */
envInfo.results.value = envInfo.parameters.standard.value[locateFolder(file)] || {};
/* Define o sucesso do SQL */
envInfo.results.value.error = false;
/* Define o sucesso */
envInfo.results.success = false;
/* Try-Catch para casos de erro */
try {
/* Define as condições de se valores estão corretos */
const areValuesValid = (
/* Verifica se as strings estão corretas */
[file, keyup].every((check) => typeof check === 'string' || typeof check === 'boolean' || typeof check === 'object')
/* Verifica se o user contém uso correto */
&& /@s.whatsapp.net|false/gi.test(user)
/* Verifica se o chatId contém uso correto */
&& /@g.us|false|@s.whatsapp.net/gi.test(chatId)
);
/* Verifica se as condições batem */
if (areValuesValid) {
/* Define o valor de Object */
let tempJson = validateJSON(value);
/* Se a keyup for uma string */
if (typeof keyup === 'string') {
/* Define um JSON Object */
tempJson = validateJSON({
[keyup]: (value || envInfo.results.value[keyup] || 0),
});
}
/* Só continua caso o JSON seja válido */
if (tempJson !== false) {
/* Executa o comando */
executeSQLite(file, 'update', user, chatId, keyup, false, tempJson);
}
/* Se as condições não baterem */
} else {
/* Define o erro como explicação */
envInfo.results.value.error = 'The usage method is incorrect. A default Object will be sent to avoid errors.';
}
/* Define o sucesso */
envInfo.results.success = true;
/* Se der algum erro */
} catch (error) {
/* Insere tudo na envInfo */
logging.echoError(error, envInfo, __dirname);
}
/* Retorna os valores; caso nada acima seja feito, retorna os padrões */
return logging.postResults(envInfo);
}
/**
* Reseta um ou mais valores na base de dados.
* @function undoValues
* @param {string} [file=envInfo.functions.purge.arguments.file.value] - Nome do arquivo SQL.
* @param {string} [user=envInfo.functions.purge.arguments.user.value] - Identificador do usuário.
* @param {string} [chatId=envInfo.functions.purge.arguments.chatId.value] - Identificador do chat.
* @param {Array<string>} [arrayundo=envInfo.functions.purge.arguments.keyundo.value] - Array de chaves a serem resetadas.
* @returns {Object} Retorna os valores resetados ou um objeto padrão em caso de erro.
*/
function undoValues(
file = envInfo.functions.purge.arguments.file.value,
user = envInfo.functions.purge.arguments.user.value,
chatId = envInfo.functions.purge.arguments.chatId.value,
arrayundo = envInfo.functions.purge.arguments.keyundo.value,
) {
/* Define uma const para hospedar os valores, pois senão serão sobrepostos por outra função */
const ambientEnv = envInfo.results;
/* Define o valor final como o padrão */
ambientEnv.value = envInfo.parameters.standard.value[locateFolder(file)] || {};
/* Define o sucesso do SQL */
ambientEnv.value.error = false;
/* Define o sucesso */
ambientEnv.success = false;
/* Try-Catch para casos de erro */
try {
/* Define as condições de se valores estão corretos */
const areValuesValid = (
/* Verifica se as strings estão corretas */
typeof file === 'string'
/* Determina se enviou uma array */
&& Array.isArray(arrayundo)
/* Verifica se o user contém uso correto */
&& /@s.whatsapp.net|false/gi.test(user)
/* Verifica se o chatId contém uso correto */
&& /@g.us|false|@s.whatsapp.net/gi.test(chatId)
);
/* Verifica se as condições batem */
if (areValuesValid) {
/* Adquire os valores padrões baseado na array, retornando uma Object */
const tempJson = validateJSON(arrayundo.reduce((o, key) => (
{ ...o, [key]: ambientEnv.value[key] || 0 }
), {}));
/* Só continua caso o JSON seja válido */
if (tempJson !== false) {
/* Roda a função de atualizar valores */
ambientEnv.value = updateValues(file, user, chatId, false, tempJson).value;
}
/* Se as condições não baterem */
} else {
/* Define o erro como explicação */
envInfo.results.value.error = 'The usage method is incorrect. A default Object will be sent to avoid errors.';
}
/* Define o sucesso */
ambientEnv.success = true;
/* Se der algum erro */
} catch (error) {
/* Insere tudo na envInfo */
logging.echoError(error, envInfo, __dirname);
}
/* Retorna os valores, caso nada acima seja feito, retorna os padrões */
return ambientEnv;
}
/**
* Adquire o JSON de um ID específico, ordenando os valores com base em uma chave.
* @function rankingValues
* @param {string} [file=envInfo.functions.finder.arguments.file.value] - Nome do arquivo SQL.
* @param {string} [chatId=envInfo.functions.finder.arguments.chatId.value] - Identificador do chat.
* @param {string} [keysort=envInfo.functions.finder.arguments.keysort.value] - Chave para ordenação.
* @param {string} [limit=envInfo.functions.finder.arguments.limit.value] - Limite de resultados.
* @returns {Object} Retorna os valores ordenados ou um objeto padrão em caso de erro.
*/
function rankingValues(
file = envInfo.functions.finder.arguments.file.value,
chatId = envInfo.functions.finder.arguments.chatId.value,
keysort = envInfo.functions.finder.arguments.keysort.value,
limit = envInfo.functions.finder.arguments.limit.value,
) {
/* Define o valor final como o padrão */
envInfo.results.value = envInfo.parameters.standard.value[locateFolder(file)] || {};
/* Define o sucesso do SQL */
envInfo.results.value.error = false;
/* Define o sucesso */
envInfo.results.success = false;
/* Try-Catch para casos de erro */
try {
/* Define as condições de se valores estão corretos */
const areValuesValid = (
/* Verifica se os valores de string estão corretos */
[file, keysort].every((check) => typeof check === 'string')
/* Define o limite de filtro */
&& /^[0-9]+$/.test(limit)
);
/* Verifica se as condições batem */
if (areValuesValid) {
/* Define a condição WHERE */
/* eslint-disable-next-line no-nested-ternary */
const newchatId = file === 'groups' ? chatId : (chatId === 'global' || file === 'bank' ? '--' : `WHERE chat = '${chatId}'`);
/* Executa o comando */
executeSQLite(file, 'sort', null, newchatId, keysort, limit, false);
/* Se as condições não baterem */
} else {
/* Define o erro como explicação */
envInfo.results.value.error = 'The usage method is incorrect. A default Object will be sent to avoid errors.';
}
/* Define o sucesso */
envInfo.results.success = true;
/* Se der algum erro */
} catch (error) {
/* Insere tudo na envInfo */
logging.echoError(error, envInfo, __dirname);
}
/* Retorna os valores, caso nada acima seja feito, retorna os padrões */
return logging.postResults(envInfo);
}
/**
* Filtra valores específicos de usuários ou grupos na base de dados com base em uma chave e operador matemático.
* @function filterValues
* @param {string} [file=envInfo.functions.finder.arguments.file.value] - Nome do arquivo SQL.
* @param {string} [user=envInfo.functions.finder.arguments.user.value] - Identificador do usuário.
* @param {string} [chatId=envInfo.functions.finder.arguments.chatId.value] - Identificador do chat.
* @param {string} [keyfilt=envInfo.functions.finder.arguments.keysort.value] - Chave para filtragem.
* @param {string} [mathsym=envInfo.functions.finder.arguments.mathsym.value] - Operador matemático para filtragem.
* @param {string|number} [value=envInfo.functions.finder.arguments.value.value] - Valor para comparação.
* @returns {Object} Retorna os valores filtrados ou um objeto padrão em caso de erro.
*/
function filterValues(
file = envInfo.functions.finder.arguments.file.value,
user = envInfo.functions.finder.arguments.user.value,
chatId = envInfo.functions.finder.arguments.chatId.value,
keyfilt = envInfo.functions.finder.arguments.keysort.value,
mathsym = envInfo.functions.finder.arguments.mathsym.value,
value = envInfo.functions.finder.arguments.value.value,
) {
/* Define o valor final como o padrão */
envInfo.results.value = envInfo.parameters.standard.value[locateFolder(file)] || {};
/* Define o sucesso do SQL */
envInfo.results.value.error = false;
/* Define o sucesso */
envInfo.results.success = false;
/* Redefine o mathsym */
const mathsymbols = typeof mathsym === 'string' ? mathsym.toUpperCase() : envInfo.functions.finder.arguments.mathsym.value;
/* Try-Catch para casos de erro */
try {
/* Define as condições de se valores estão corretos */
const areValuesValid = (
/* Verifica se os valores de string estão corretos */
[file, keyfilt].every((check) => typeof check === 'string')
/* Caso o user contenha uso correto */
&& /@s.whatsapp.net|false/gi.test(user)
/* Caso o chatId contenha uso correto */
&& /@g.us|false|@s.whatsapp.net/gi.test(chatId)
/* Verifica os tipos de MathSym */
&& ['=', '>', '<', '>=', '<=', '!=', '<>', 'IS NULL', 'IS NOT NULL', 'BETWEEN', 'IN'].includes(mathsymbols)
);
/* Verifica se as condições batem */
if (areValuesValid) {
/* Executa o comando */
executeSQLite(file, 'find', user, chatId, keyfilt, mathsymbols, value);
/* Se as condições não baterem */
} else {
/* Define o erro como explicação */
envInfo.results.value.error = 'The usage method is incorrect. A default Object will be sent to avoid errors.';
}
/* Define o sucesso */
envInfo.results.success = true;
/* Se der algum erro */
} catch (error) {
/* Insere tudo na envInfo */
logging.echoError(error, envInfo, __dirname);
}
/* Retorna os valores, caso nada acima seja feito, retorna os padrões */
return logging.postResults(envInfo);
}
/**
* Remove um usuário ou grupo da base de dados.
* @function removeValues
* @param {string} [file=envInfo.functions.remove.arguments.file.value] - Nome do arquivo SQL.
* @param {string} [user=envInfo.functions.remove.arguments.user.value] - Identificador do usuário.
* @param {string} [chatId=envInfo.functions.remove.arguments.chatId.value] - Identificador do chat.
* @returns {Object} Retorna os valores atualizados ou um objeto padrão em caso de erro.
*/
function removeValues(
file = envInfo.functions.remove.arguments.file.value,
user = envInfo.functions.remove.arguments.user.value,
chatId = envInfo.functions.remove.arguments.chatId.value,
) {
/* Define o valor final como o padrão */
envInfo.results.value = envInfo.parameters.standard.value[locateFolder(file)] || {};
/* Define o sucesso do SQL */
envInfo.results.value.error = false;
/* Define o sucesso */
envInfo.results.success = false;
/* Try-Catch para casos de erro */
try {
/* Define as condições de se os valores estão corretos */
const areValuesValid = (
/* Verifica se o file está correto */
typeof file === 'string'
/* Verifica se o user contém uso correto */
&& /@s.whatsapp.net|false/gi.test(user)
/* Verifica se o chatId contém uso correto */
&& /@g.us|false|@s.whatsapp.net/gi.test(chatId)
);
/* Verifica se as condições batem */
if (areValuesValid) {
/* Executa o comando */
executeSQLite(file, 'remove', user, chatId, false, false, false);
/* Se as condições não forem válidas */
} else {
/* Define o erro como explicação */
envInfo.results.value.error = 'The usage method is incorrect. A default Object will be sent to avoid errors.';
}
/* Define o sucesso */
envInfo.results.success = true;
/* Se algum erro acontecer */
} catch (error) {
/* Insere tudo na envInfo */
logging.echoError(error, envInfo, __dirname);
}
/* Retorna os valores. Caso nada acima seja feito, retorna os padrões */
return logging.postResults(envInfo);
}
/**
* Executa um comando personalizado na base de dados.
* @function customCommand
* @param {string} [file=envInfo.functions.custom.arguments.file.value] - Nome do arquivo SQL.
* @param {string} [user=envInfo.functions.custom.arguments.user.value] - Identificador do usuário.
* @param {string} [chatId=envInfo.functions.custom.arguments.chatId.value] - Identificador do chat.
* @param {string} [customCode=envInfo.functions.custom.arguments.customCode.value] - Código SQL personalizado.
* @returns {Object} Retorna os resultados do comando ou um objeto padrão em caso de erro.
*/
function customCommand(
file = envInfo.functions.custom.arguments.file.value,
user = envInfo.functions.custom.arguments.user.value,
chatId = envInfo.functions.custom.arguments.chatId.value,
customCode = envInfo.functions.custom.arguments.customCode.value,
) {
/* Define o valor final como o padrão */
envInfo.results.value = envInfo.parameters.standard.value[locateFolder(file)] || {};
/* Define o sucesso do SQL */
envInfo.results.value.error = false;
/* Define o sucesso */
envInfo.results.success = false;
/* Try-Catch para casos de erro */
try {
/* Define as condições de se os valores estão corretos */
const areValuesValid = (
/* Verifica se o file está correto */
typeof file === 'string'
/* Verifica se o código personalizado também está correto */
&& typeof customCode === 'string'
);
/* Verifica se as condições batem */
if (areValuesValid) {
/* Executa o comando personalizado */
executeSQLite(file, 'custom', user, chatId, customCode, false, false);
/* Se as condições não baterem */
} else {
/* Define o erro como explicação */
envInfo.results.value.error = 'The usage method is incorrect. A default Object will be sent to avoid errors.';
}
/* Define o sucesso */
envInfo.results.success = true;
/* Se der algum erro */
} catch (error) {
/* Insere tudo na envInfo */
logging.echoError(error, envInfo, __dirname);
}
/* Retorna os valores. Caso nada acima seja feito, retorna os padrões */
return logging.postResults(envInfo);
}
/**
* Recria as tabelas da base de dados mantendo seus dados (útil para atualizações que exigem alterações na estrutura).
* @function fixDatabase
* @param {Object} [params={}] - Parâmetros adicionais para a correção da base de dados.
* @param {string} [params.first=envInfo.functions.fixdb.arguments.param1.value] - Primeiro parâmetro.
* @param {string} [params.second=envInfo.functions.fixdb.arguments.param2.value] - Segundo parâmetro.
* @param {string} [params.third=envInfo.functions.fixdb.arguments.param3.value] - Terceiro parâmetro.
* @param {string} [params.fourth=envInfo.functions.fixdb.arguments.param4.value] - Quarto parâmetro.
* @param {string} [params.fifth=envInfo.functions.fixdb.arguments.param5.value] - Quinto parâmetro.
* @param {string} [params.oldDb=envInfo.functions.fixdb.arguments.oldDb.value] - Nome da base de dados antiga.
* @param {Array<string>} [params.dbNames=envInfo.functions.fixdb.arguments.dbNames.value] - Nomes das bases de dados a serem recriadas.
* @returns {Object} Retorna os resultados da correção ou um objeto padrão em caso de erro.
*/
function fixDatabase(params = {}) {
/* Define o sucesso */
envInfo.results.success = false;
/* Define parametros, caso um dia a correção precise */
const settings = {
...params,
};
/* Ajusta os valores para caso venha null ou errado */
settings.first = settings.first ?? envInfo.functions.fixdb.arguments.param1.value;
settings.second = settings.second ?? envInfo.functions.fixdb.arguments.param2.value;
settings.third = settings.third ?? envInfo.functions.fixdb.arguments.param3.value;
settings.fourth = settings.fourth ?? envInfo.functions.fixdb.arguments.param4.value;
settings.fifth = settings.fifth ?? envInfo.functions.fixdb.arguments.param5.value;
settings.oldDb = settings.oldDb ?? envInfo.functions.fixdb.arguments.oldDb.value;
settings.dbNames = settings.dbNames ?? envInfo.functions.fixdb.arguments.dbNames.value;
/* Try-Catch para casos de erro */
try {
/* Define o nome da antiga DB */
const oldDatabase = path.normalize(`${irisPath}/lib/Databases/Informations/${settings.oldDb}`);
/* Try catch secundário para o uso do accessSync */
try {
/* Verifica se a antiga DB realmente existe */
fs.accessSync(oldDatabase, fs.constants.F_OK);
/* Renomeia o arquivo antigo para o novo DB */
fs.renameSync(oldDatabase, databaseSQL);
/* Se o arquivo não existir ou se ocorrer um erro ao acessar ou renomear */
} catch (error) {
/* Printa na tela sem limitação por ser 'grave' */
console.error(error);
console.log('\nSua database não existe, está aberta ou está com defeitos, ignorando uso de antiga database....\n');
}
/* Executa os códigos de correção da database */
settings.dbNames.forEach((db) => {
/* Um a um por meio de loop */
executeSQLite(db, 'recreate', settings.first, settings.second, settings.third, settings.fourth, settings.fifth);
});
/* Define o sucesso */
envInfo.results.success = true;
/* Se der algum erro */
} catch (error) {
/* Insere tudo na envInfo */
logging.echoError(error, envInfo, __dirname);
}
/* Retorna os valores. Caso nada acima seja feito, retorna os padrões */
return logging.postResults(envInfo);
}
/**
* Remove valores específicos de um usuário ou grupo na base de dados.
* @function purgeValues
* @param {string} [file=envInfo.functions.purge.arguments.file.value] - Nome do arquivo SQL.
* @param {string} [user=envInfo.functions.purge.arguments.user.value] - Identificador do usuário.
* @param {string} [chatId=envInfo.functions.purge.arguments.chatId.value] - Identificador do chat.
* @param {string} [initKey=envInfo.functions.purge.arguments.initKey.value] - Chave inicial para remoção.
* @param {string|boolean|Object} [finKey=envInfo.functions.purge.arguments.finKey.value] - Chave final para remoção.
* @returns {Object} Retorna os valores atualizados ou um objeto padrão em caso de erro.
*/
function purgeValues(
file = envInfo.functions.purge.arguments.file.value,
user = envInfo.functions.purge.arguments.user.value,
chatId = envInfo.functions.purge.arguments.chatId.value,
initKey = envInfo.functions.purge.arguments.initKey.value,
finKey = envInfo.functions.purge.arguments.finKey.value,
) {
/* Define o valor final como o padrão */
envInfo.results.value = envInfo.parameters.standard.value[locateFolder(file)] || {};
/* Define o sucesso do SQL */
envInfo.results.value.error = false;
/* Define o sucesso */
envInfo.results.success = false;
/* Try-Catch para casos de erro */
try {
/* Define as condições de se os valores estão corretos */
const areValuesValid = (
/* Verifica se os valores de finKey estão corretos */
['string', 'boolean', 'object'].includes(typeof finKey)
/* Verifica se o initKey contém uso correto */
&& typeof initKey === 'string'
/* Verifica se o user contém uso correto */
&& /@s.whatsapp.net|false/gi.test(user)
/* Verifica se o chatId contém uso correto */
&& /@g.us|false|@s.whatsapp.net/gi.test(chatId)
);
/* Verifica se as condições batem */
if (areValuesValid) {
/* Re-define o valor de finKey */
const finalKey = typeof finKey === 'string' && finKey !== '' ? `.${finKey}` : false;
/* Executa o comando */
executeSQLite(file, 'purge', user, chatId, initKey, false, finalKey);
/* Se as condições não baterem */
} else {
/* Define o erro como explicação */
envInfo.results.value.error = 'The usage method is incorrect. A default Object will be sent to avoid errors.';
}
/* Define o sucesso */
envInfo.results.success = true;
/* Se der algum erro */
} catch (error) {
/* Insere tudo na envInfo */
logging.echoError(error, envInfo, __dirname);
}
/* Retorna os valores. Caso nada acima seja feito, retorna os padrões */
return logging.postResults(envInfo);
}
/**
* Obtém diálogos com base em parâmetros específicos, como idioma, pasta, diálogo e substituições.
* @function dialoguePicker
* @param {string} [regionPicker=envInfo.functions.languages.arguments.regionPicker.value] - Idioma a ser utilizado. Enviar 'G.A.L' nesse paramêtro retorna uma array de sigla dos idiomas.
* @param {string} [folderPicker=envInfo.functions.languages.arguments.folderPicker.value] - Pasta onde o diálogo está localizado.
* @param {string|Error} [dialogPicker=envInfo.functions.languages.arguments.dialogPicker.value] - Nome do diálogo ou erro a ser tratado.
* @param {boolean} [randomOrder=envInfo.functions.languages.arguments.randomOrder.value] - Define se a ordem dos diálogos deve ser aleatória.
* @param {boolean} [singleText=envInfo.functions.languages.arguments.singleText.value] - Define se deve retornar apenas um diálogo.
* @param {Object} [objectReplacer=envInfo.functions.languages.arguments.objectReplacer.value] - Objeto para substituir variáveis no diálogo.
* @returns {Object} Retorna o diálogo formatado, uma array de siglas de idiomas ou um objeto padrão em caso de erro.
*/
function dialoguePicker(
regionPicker = envInfo.functions.languages.arguments.regionPicker.value,
folderPicker = envInfo.functions.languages.arguments.folderPicker.value,
dialogPicker = envInfo.functions.languages.arguments.dialogPicker.value,
randomOrder = envInfo.functions.languages.arguments.randomOrder.value,
singleText = envInfo.functions.languages.arguments.singleText.value,
objectReplacer = envInfo.functions.languages.arguments.objectReplacer.value,
) {
/* Define o sucesso do SQL */
envInfo.results.value = false;
/* Define o sucesso */
envInfo.results.success = false;
/* Try-Catch para casos de erro */
try {
/* Caso ainda não tenha a array de idiomas */
if (allLanguages.length === 0) {
/* Define no código */
const tables = dialDatabase.prepare('SELECT json_group_array(name) AS tables FROM sqlite_master WHERE type=\'table\'').get();
allLanguages = JSON.parse(tables.tables);
/* Usa um valor estático padrão dos diálogos, se falhar */
if (!allLanguages.length) {
/* Pode não conter todos os idiomas! */
allLanguages = ['pt', 'ar', 'jp', 'en', 'fr', 'es', 'id', 'ms', 'hi', 'de', 'it', 'ru', 'lat'];
}
}
/* Define o idioma, mas antes verifica se é string */
let userLang = (typeof regionPicker === 'string' ? regionPicker.toLowerCase() : 'pt');
/* Se for só obtenção dos diálogos */
if (userLang.toLowerCase() === 'g.a.l') return allLanguages;
/* Define a query base */
let query = '';
/* Define se deve ajustar os diálogos de novo */
if (!allLanguages.includes(userLang)) {
/* Define o padrão */
userLang = 'pt';
}
/* Redefine o objeto */
const replaceData = objectReplacer;
/* Define o arquivo, mas antes verifica se é string */
let taskName = (typeof folderPicker === 'string' ? folderPicker : 'Default');
/* Define o diálogo final */
let nameKey = (typeof dialogPicker === 'string' || dialogPicker instanceof Error ? dialogPicker : 'Default');
/* Se for o report de erros especial [Special Error Report] */
if (nameKey instanceof Error && taskName === 'S.E.R' && config.sendSER.value === true) {
/* Formata o local e demais informações */
const stderr = nameKey.stack ? nameKey.stack.match(/\(.*\)/gi)[0].replace(/\(|\)/gi, '').split(/:/gi) : ['Disk', './', 'Unknown', 'Unknown'];
stderr[0] = stderr[0] || 'Disk';
stderr[1] = stderr[1] || './';
stderr[2] = stderr[2] || 'Unknown';
stderr[3] = stderr[3] || 'Unknown';
/* Local */
replaceData.path = path.dirname(path.resolve(stderr[0] || './')).replace(irisPath, '').replace('\\', '');
/* Arquivo */
replaceData.file = path.basename(stderr[0]);
/* Se é na Íris */
replaceData.isMe = (stderr[0].includes('node') ? '❌' : '✔️');
/* Linha do arquivo */
[replaceData.line] = [stderr[1]];
/* Caractere */
[replaceData.character] = [stderr[2]];
/* Mensagem de erro */
replaceData.fullbo = nameKey.message;
/* Nome do erro */
replaceData.typeerror = nameKey.name;
/* Determina o tipo | RangeError */
if (nameKey.name === 'RangeError') {
/* RangeError | Númerico */
query = `SELECT data FROM ${userLang} WHERE LOWER(task) = LOWER('Errors') AND LOWER(name) = LOWER('RangeError') ORDER BY RANDOM() LIMIT 1;`;
/* ReferenceError */
} else if (nameKey.name === 'ReferenceError') {
/* Falta código */
query = `SELECT REPLACE(data, '{lostvar}', '${nameKey.message.slice(0, -15)}') FROM ${userLang} WHERE LOWER(task) = LOWER('Errors') AND LOWER(name) = LOWER('ReferenceFix') ORDER BY RANDOM() LIMIT 1;`;
/* SyntaxError */
} else if (nameKey.name === 'SyntaxError') {
/* Código mal feito */
query = `SELECT data FROM ${userLang} WHERE LOWER(task) = LOWER('Errors') AND LOWER(name) = LOWER('SyntaxFix') ORDER BY RANDOM() LIMIT 1;`;
/* TypeError */
} else if (nameKey.name === 'TypeError') {
/* Constante sendo usada como let/var */
query = `SELECT data FROM ${userLang} WHERE LOWER(task) = LOWER('Errors') AND LOWER(name) = LOWER('TypeFix') ORDER BY RANDOM() LIMIT 1;`;
/* Qualquer outro [Existe?] */
} else {
/* Diz desconhecido */
query = `SELECT data FROM ${userLang} WHERE LOWER(task) = LOWER('Errors') AND LOWER(name) = LOWER('OtherFix') ORDER BY RANDOM() LIMIT 1;`;
}
/* Obtém o diálogo de sugestão */
const suggestion = dialDatabase.prepare(query).get();
replaceData.suggestion = suggestion.data;
/* Ajusta os valores para pegar a mensagem correta */
nameKey = 'Fail';
taskName = 'Errors';
/* Se for erro, mas não tem permissão de mandar o full */
} else if (nameKey instanceof Error && taskName === 'S.E.R' && config.sendSER.value === false) {
/* Define os valores da mensagem de falha */
userLang = region;
taskName = 'Loggers';
nameKey = 'Error';
}
/* Define a query */
query = `SELECT CASE WHEN COALESCE((SELECT data FROM ${userLang} WHERE LOWER(task) = LOWER('${taskName}') AND LOWER(name) = LOWER('${nameKey}') ${randomOrder ? 'ORDER BY RANDOM()' : ''} ${singleText ? ' LIMIT 1' : ''}), '[]') = '[]' THEN (SELECT data FROM ${userLang} WHERE LOWER(name) = LOWER('Default') AND LOWER(task) = LOWER('Default') ${randomOrder ? 'ORDER BY RANDOM()' : ''} ${singleText ? ' LIMIT 1' : ''}) ELSE (SELECT data FROM ${userLang} WHERE LOWER(task) = LOWER('${taskName}') AND LOWER(name) = LOWER('${nameKey}') ${randomOrder ? 'ORDER BY RANDOM()' : ''} ${singleText ? ' LIMIT 1' : ''}) END;`;
/* Faz ajustes se preciso */
query = !singleText ? query.replace(/SELECT data/gi, 'SELECT json_group_array(data)').replace(/LIMIT 1/gi, '') : query;
/* Obtém o diálogo */
const dialogData = dialDatabase.prepare(query).get();
envInfo.results.value = dialogData[Object.keys(dialogData)[0]];
/* Ajusta as variáveis internas se for apenas 1 diálogo */
if (singleText === true) {
/* Retorna o primeiro, use aleatorização para dinamismo */
envInfo.results.value = envInfo.results.value.replace(/\{([^}]*)\}/gi, (match, key) => Indexer('others').repl(replaceData, match, key));
/* Se não faz parse */
} else envInfo.results.value = JSON.parse(envInfo.results.value);
/* Define o sucesso */
envInfo.results.success = true;
/* Faz trim do valor */
envInfo.results.value = envInfo.results.value.trim();
/* Se ainda não tiver nada */
if (envInfo.results.value === '') {
/* Executa uma query simples e ajusta ela */
const simpleDial = dialDatabase.prepare(`SELECT data FROM ${userLang} WHERE LOWER(name) = 'Default' AND task = 'Default' ORDER BY RANDOM() LIMIT 1;`).get();
envInfo.results.value = simpleDial.data;
envInfo.results.value = envInfo.results.value.trim();
}
/* Se der erro em qualquer parte acima */
} catch (error) {
/* Insere tudo na envInfo */
logging.echoError(error, envInfo, __dirname);
}
/* Retorna os dados do diálogo */
return logging.postResults(envInfo);
}
/**
* Obtém uma palavra ou dado de uma tabela específica na base de dados.
* @function getKeyword
* @param {string} [selectLang=region] - Idioma a ser utilizado.
* @param {string} [nameList=envInfo.functions.keywords.arguments.nameList.value] - Nome da lista de palavras.
* @param {string} [tableName=envInfo.functions.keywords.arguments.tableName.value] - Nome da tabela na base de dados.
* @param {boolean} [randomWord=envInfo.functions.keywords.arguments.randomWord.value] - Define se a palavra deve ser escolhida aleatoriamente.
* @param {string} [fullCommand=envInfo.functions.keywords.arguments.fullCommand.value] - Comando SQL personalizado (opcional).
* @returns {Object} Retorna a palavra ou dado obtido, com informações adicionais, ou um objeto padrão em caso de erro.
*/
function getKeyword(
selectLang = region,
nameList = envInfo.functions.keywords.arguments.nameList.value,
tableName = envInfo.functions.keywords.arguments.tableName.value,
randomWord = envInfo.functions.keywords.arguments.randomWord.value,
fullCommand = envInfo.functions.keywords.arguments.fullCommand.value,
) {
/* Define o valor final como um fail keyword */
envInfo.results.value = {
id: 999,
language: 'ALL',
type: 'entity',
word: config.botName.value,
error: true,
};
/* Define o sucesso */
envInfo.results.success = false;
/* Try-Catch para casos de erro */
try {
/* Define os valores a usar */
const getLists = {
language: typeof selectLang === 'string' ? selectLang : region,
table: typeof tableName === 'string' ? tableName : envInfo.functions.keywords.arguments.tableName.value,
random: typeof randomWord === 'boolean' ? randomWord : envInfo.functions.keywords.arguments.randomWord.value,
name: typeof nameList === 'string' ? nameList : envInfo.functions.keywords.arguments.nameList.value,
command: typeof fullCommand === 'string' ? fullCommand : envInfo.functions.keywords.arguments.fullCommand.value,
};
/* Constrói a query SQLite3 */
const query = getLists.command || `SELECT json_object('id', id, 'type', type, 'language', language, 'word', name) FROM ${getLists.table} ${getLists.language === 'any' ? '' : `WHERE language = '${getLists.language}'`} ${getLists?.name && getLists?.language !== 'any' ? `AND type = '${getLists.name}'` : ''} ${getLists.random ? 'ORDER BY RANDOM()' : ''} LIMIT 1;`;
/* Obtém a palavra */
const wordSelect = extrasDatabase.prepare(query).get();
envInfo.results.value = wordSelect ? wordSelect[Object.keys(wordSelect)[0]] : '';
/* Se não for código customizado */
if (!getLists.command && envInfo.results.value) {
/* Faz versões alternativas, como JSON, invertido, etc */
envInfo.results.value = JSON.parse(envInfo.results.value);
envInfo.results.value.mistery = envInfo.results.value.word[0] + '_'.repeat(envInfo.results.value.word.length - 1);
envInfo.results.value.encoded = Buffer.from(envInfo.results.value.word).toString('base64');
envInfo.results.value.mixed = Indexer('strings').shuffle(envInfo.results.value.word).value;
envInfo.results.value.chars = envInfo.results.value.word.split('');
envInfo.results.value.mixedchars = Indexer('array').sort(envInfo.results.value.word.split('')).value;
envInfo.results.value.reverse = envInfo.results.value.chars.reverse().join('');
envInfo.results.value.arrmistery = envInfo.results.value.mistery.split('');
}
/* Define o sucesso */
envInfo.results.success = true;
/* Se der algum erro */
} catch (error) {
/* Insere tudo na envInfo */
logging.echoError(error, envInfo, __dirname);
}
/* Retorna os valores; caso nada acima seja feito, retorna os padrões */
return logging.postResults(envInfo);
}
/* Reset profundo para evitar circular */
/**
* Restaura o ambiente e atualiza as exportações do módulo com a funcionalidade principal
* @param {Object} [changeKey={}] - Chaves personalizadas para atualizar o envInfo
* @param {Object} [envFile=envInfo] - Objeto com informações do ambiente
* @param {string} [dirname=__dirname] - Caminho do diretório atual
* @returns {Object} Exportações do módulo com todas as funções configuradas
*/
/* eslint-disable-next-line no-return-assign */
const resetLocal = (
anotherData = false,
envFile = envInfo,
dirname = __dirname,
) => module.exports = logging.resetAmbient({
functions: {
[envInfo.exports.env]: { value: ambientDetails },
[envInfo.exports.reset]: { value: resetLocal },
[envInfo.exports.update]: { value: updateValues },
[envInfo.exports.undo]: { value: undoValues },
[envInfo.exports.ranking]: { value: rankingValues },
[envInfo.exports.finder]: { value: filterValues },
[envInfo.exports.languages]: { value: dialoguePicker },
[envInfo.exports.purge]: { value: purgeValues },
[envInfo.exports.fixer]: { value: validateJSON },
[envInfo.exports.remove]: { value: removeValues },
[envInfo.exports.fixdb]: { value: fixDatabase },
[envInfo.exports.custom]: { value: customCommand },
[envInfo.exports.get]: { value: getValues },
[envInfo.exports.keywords]: { value: getKeyword },
},
parameters: {
location: { value: __filename },
},
}, envFile, anotherData, dirname);
resetLocal();