fix: include ai_queries in /reminders and add chatId security filtering

This commit is contained in:
larchanka
2026-04-04 13:31:52 +02:00
committed by Mikhail Larchanka
parent 9820566567
commit 99794fec95
2 changed files with 60 additions and 15 deletions

View File

@@ -1037,30 +1037,48 @@ export class Orchestrator {
id: string;
cronExpr: string;
taskType: string;
payload: string;
enabled: boolean;
}>;
ConsoleLogger.info("core", `Found ${schedules.length} total schedules`);
// Filter reminders for this chatId - we need to check the payload of each schedule
// Since we can't easily query by chatId, we'll need to get schedule details
// For now, filter by taskType === "reminder"
const reminderSchedules = schedules.filter((s) => s.taskType === "reminder" && s.enabled);
// Filter reminders for this chatId
const filteredSchedules = schedules.filter((s) => {
if (!s.enabled) return false;
if (s.taskType !== "reminder" && s.taskType !== "ai_query") return false;
try {
const payload = JSON.parse(s.payload);
return payload.chatId === chatId;
} catch (err) {
return false;
}
});
ConsoleLogger.info("core", `Found ${reminderSchedules.length} reminder schedules`);
ConsoleLogger.info("core", `Found ${filteredSchedules.length} filtered schedules for chatId ${chatId}`);
if (reminderSchedules.length === 0) {
if (filteredSchedules.length === 0) {
ConsoleLogger.info("core", "No reminders found, sending 'No active reminders' message");
this.sendToTelegram(chatId, "👌🏻 No active reminders.");
return;
}
// Format reminders - we'll show ID and cronExpr, but reminderMessage is in the payload
// For a better implementation, we'd need to query each schedule's payload
const formatted = reminderSchedules
.map((rem) => `ID: ${rem.id}\nTime: ${rem.cronExpr}`)
// Format reminders - include message/query and task type
const formatted = filteredSchedules
.map((s) => {
let message = "N/A";
try {
const p = JSON.parse(s.payload);
message = p.reminderMessage || p.query || "N/A";
} catch (e) {}
const typeLabel = s.taskType === "ai_query" ? "🤖 Task" : "🔔 Reminder";
return `<b>${typeLabel}</b>\nID: <code>${s.id}</code>\nTime: <code>${s.cronExpr}</code>\nMessage: ${message}`;
})
.join("\n\n---\n\n");
const message = `Active reminders:\n\n${formatted}`;
const message = `⏰ <b>Active schedules:</b>\n\n${formatted}`;
ConsoleLogger.info("core", `Sending reminder list to chatId ${chatId}: ${message.substring(0, 100)}...`);
this.sendToTelegram(chatId, message, false, "HTML");
} catch (err) {
@@ -1078,12 +1096,37 @@ export class Orchestrator {
}
try {
// Security: verify that this reminder belongs to this chatId
const listResponse = await this.sendAndWait(cronManager, "cron.schedule.list", {});
const listPayload = listResponse.payload as { result?: { schedules?: Array<{ id: string; payload: string }> } };
const schedules = listPayload.result?.schedules ?? [];
const targetSchedule = schedules.find(s => s.id === reminderId);
if (!targetSchedule) {
this.sendToTelegram(chatId, `😨 Reminder <code>${reminderId}</code> not found.`);
return;
}
try {
const payload = JSON.parse(targetSchedule.payload);
if (payload.chatId !== chatId) {
this.sendToTelegram(chatId, `❌ You are not authorized to cancel this reminder.`);
return;
}
} catch (e) {
// If payload is malformed or missing chatId, we might want to prevent deletion or allow it?
// Let's be conservative: if we can't confirm ownership, we reject.
// UNLESS we are superuser (could add later).
this.sendToTelegram(chatId, `❌ Security check failed for reminder <code>${reminderId}</code>.`);
return;
}
const response = await this.sendAndWait(cronManager, "cron.schedule.remove", { id: reminderId });
const responsePayload = response.payload as { status?: string; result?: { removed?: string } };
if (responsePayload.result?.removed === reminderId) {
this.sendToTelegram(chatId, `🟢 Reminder ${reminderId} has been canceled.`);
this.sendToTelegram(chatId, `🟢 Reminder <code>${reminderId}</code> has been canceled.`);
} else {
this.sendToTelegram(chatId, `😨 Reminder ${reminderId} not found.`);
this.sendToTelegram(chatId, `😨 Reminder <code>${reminderId}</code> not found.`);
}
} catch (err) {
const message = err instanceof Error ? err.message : String(err);

View File

@@ -148,17 +148,19 @@ export class CronManager extends BaseProcess {
return id;
}
private listSchedules(): Array<{ id: string; cronExpr: string; taskType: string; enabled: boolean }> {
const rows = this.db.prepare("SELECT id, cron_expr, task_type, enabled FROM cron_schedules").all() as Array<{
private listSchedules(): Array<{ id: string; cronExpr: string; taskType: string; payload: string; enabled: boolean }> {
const rows = this.db.prepare("SELECT id, cron_expr, task_type, payload, enabled FROM cron_schedules").all() as Array<{
id: string;
cron_expr: string;
task_type: string;
payload: string;
enabled: number;
}>;
return rows.map((r) => ({
id: r.id,
cronExpr: r.cron_expr,
taskType: r.task_type,
payload: r.payload,
enabled: r.enabled === 1,
}));
}