|
|
|
|
@ -26,6 +26,12 @@ export type CommandResponse = {
|
|
|
|
|
mentions?: string[]; // full JIDs to mention in the outgoing message
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export type CommandOutcome = {
|
|
|
|
|
responses: CommandResponse[];
|
|
|
|
|
ok: boolean;
|
|
|
|
|
createdTaskIds?: number[];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export class CommandService {
|
|
|
|
|
static dbInstance: Database = db;
|
|
|
|
|
|
|
|
|
|
@ -1306,12 +1312,17 @@ export class CommandService {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static async handle(context: CommandContext): Promise<CommandResponse[]> {
|
|
|
|
|
const outcome = await this.handleWithOutcome(context);
|
|
|
|
|
return outcome.responses;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static async handleWithOutcome(context: CommandContext): Promise<CommandOutcome> {
|
|
|
|
|
const msg = (context.message || '').trim();
|
|
|
|
|
if (!/^\/(tarea|t)\b/i.test(msg)) {
|
|
|
|
|
return [];
|
|
|
|
|
return { responses: [], ok: true };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Gating de grupos en modo 'enforce' (Etapa 3) cuando CommandService se invoca directamente
|
|
|
|
|
// Gating de grupos en modo 'enforce' (cuando CommandService se invoca directamente)
|
|
|
|
|
if (isGroupId(context.groupId)) {
|
|
|
|
|
try { (AllowedGroups as any).dbInstance = this.dbInstance; } catch {}
|
|
|
|
|
const mode = String(process.env.GROUP_GATING_MODE || 'off').toLowerCase();
|
|
|
|
|
@ -1319,7 +1330,7 @@ export class CommandService {
|
|
|
|
|
try {
|
|
|
|
|
if (!AllowedGroups.isAllowed(context.groupId)) {
|
|
|
|
|
try { Metrics.inc('commands_blocked_total'); } catch {}
|
|
|
|
|
return [];
|
|
|
|
|
return { responses: [], ok: true };
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// Si falla el check, ser permisivos
|
|
|
|
|
@ -1328,12 +1339,79 @@ export class CommandService {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return await this.processTareaCommand(context);
|
|
|
|
|
const responses = await this.processTareaCommand(context);
|
|
|
|
|
|
|
|
|
|
// Clasificación explícita del outcome (evita lógica en server)
|
|
|
|
|
const tokens = msg.split(/\s+/);
|
|
|
|
|
const rawAction = (tokens[1] || '').toLowerCase();
|
|
|
|
|
const ACTION_ALIASES: Record<string, string> = {
|
|
|
|
|
'n': 'nueva',
|
|
|
|
|
'nueva': 'nueva',
|
|
|
|
|
'crear': 'nueva',
|
|
|
|
|
'+': 'nueva',
|
|
|
|
|
'ver': 'ver',
|
|
|
|
|
'mostrar': 'ver',
|
|
|
|
|
'listar': 'ver',
|
|
|
|
|
'ls': 'ver',
|
|
|
|
|
'x': 'completar',
|
|
|
|
|
'hecho': 'completar',
|
|
|
|
|
'completar': 'completar',
|
|
|
|
|
'done': 'completar',
|
|
|
|
|
'tomar': 'tomar',
|
|
|
|
|
'claim': 'tomar',
|
|
|
|
|
'asumir': 'tomar',
|
|
|
|
|
'asumo': 'tomar',
|
|
|
|
|
'soltar': 'soltar',
|
|
|
|
|
'unassign': 'soltar',
|
|
|
|
|
'dejar': 'soltar',
|
|
|
|
|
'liberar': 'soltar',
|
|
|
|
|
'renunciar': 'soltar',
|
|
|
|
|
'ayuda': 'ayuda',
|
|
|
|
|
'help': 'ayuda',
|
|
|
|
|
'?': 'ayuda',
|
|
|
|
|
'config': 'configurar',
|
|
|
|
|
'configurar': 'configurar',
|
|
|
|
|
'web': 'web'
|
|
|
|
|
};
|
|
|
|
|
const action = ACTION_ALIASES[rawAction] || rawAction;
|
|
|
|
|
|
|
|
|
|
// Casos explícitos considerados éxito
|
|
|
|
|
if (!action || action === 'ayuda' || action === 'web') {
|
|
|
|
|
return { responses, ok: true };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const lowerMsgs = (responses || []).map(r => String(r?.message || '').toLowerCase());
|
|
|
|
|
|
|
|
|
|
const isOkException = (m: string) =>
|
|
|
|
|
m.includes('ya estaba completada') ||
|
|
|
|
|
m.includes('ya la tenías') ||
|
|
|
|
|
m.includes('no la tenías');
|
|
|
|
|
|
|
|
|
|
const isErrorMsg = (m: string) =>
|
|
|
|
|
m.startsWith('ℹ️ uso:'.toLowerCase()) ||
|
|
|
|
|
m.includes('uso:') ||
|
|
|
|
|
m.includes('no puedes') ||
|
|
|
|
|
m.includes('no permitido') ||
|
|
|
|
|
m.includes('no encontrada') ||
|
|
|
|
|
m.includes('comando no reconocido');
|
|
|
|
|
|
|
|
|
|
let hasError = false;
|
|
|
|
|
for (const m of lowerMsgs) {
|
|
|
|
|
if (isErrorMsg(m) && !isOkException(m)) {
|
|
|
|
|
hasError = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { responses, ok: !hasError };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return [{
|
|
|
|
|
recipient: context.sender,
|
|
|
|
|
message: 'Error processing command'
|
|
|
|
|
}];
|
|
|
|
|
return {
|
|
|
|
|
responses: [{
|
|
|
|
|
recipient: context.sender,
|
|
|
|
|
message: 'Error processing command'
|
|
|
|
|
}],
|
|
|
|
|
ok: false
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|