feat: add reminders schema management for Appwrite integration
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
const sdk: any = require('node-appwrite');
|
const sdk: any = require('node-appwrite');
|
||||||
import type Amayo from '../client';
|
import type Amayo from '../client';
|
||||||
import { getDatabases, isAppwriteConfigured, APPWRITE_COLLECTION_REMINDERS_ID, APPWRITE_DATABASE_ID } from './appwrite';
|
import { getDatabases, isAppwriteConfigured, APPWRITE_COLLECTION_REMINDERS_ID, APPWRITE_DATABASE_ID } from './appwrite';
|
||||||
|
import { ensureRemindersSchema } from './remindersSchema';
|
||||||
|
|
||||||
export type ReminderDoc = {
|
export type ReminderDoc = {
|
||||||
$id?: string;
|
$id?: string;
|
||||||
@@ -23,9 +24,20 @@ export type ReminderRow = ReminderDoc & {
|
|||||||
$databaseId?: string;
|
$databaseId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let schemaEnsured = false;
|
||||||
|
async function ensureSchemaOnce() {
|
||||||
|
if (schemaEnsured) return;
|
||||||
|
try {
|
||||||
|
await ensureRemindersSchema();
|
||||||
|
} finally {
|
||||||
|
schemaEnsured = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function scheduleReminder(doc: ReminderDoc): Promise<string> {
|
export async function scheduleReminder(doc: ReminderDoc): Promise<string> {
|
||||||
const db = getDatabases();
|
const db = getDatabases();
|
||||||
if (!db || !isAppwriteConfigured()) throw new Error('Appwrite no está configurado');
|
if (!db || !isAppwriteConfigured()) throw new Error('Appwrite no está configurado');
|
||||||
|
await ensureSchemaOnce();
|
||||||
const data = {
|
const data = {
|
||||||
userId: doc.userId,
|
userId: doc.userId,
|
||||||
guildId: doc.guildId ?? null,
|
guildId: doc.guildId ?? null,
|
||||||
@@ -41,6 +53,7 @@ export async function scheduleReminder(doc: ReminderDoc): Promise<string> {
|
|||||||
async function fetchDueReminders(limit = 25): Promise<ReminderRow[]> {
|
async function fetchDueReminders(limit = 25): Promise<ReminderRow[]> {
|
||||||
const db = getDatabases();
|
const db = getDatabases();
|
||||||
if (!db || !isAppwriteConfigured()) return [];
|
if (!db || !isAppwriteConfigured()) return [];
|
||||||
|
try { await ensureSchemaOnce(); } catch {}
|
||||||
const nowIso = new Date().toISOString();
|
const nowIso = new Date().toISOString();
|
||||||
try {
|
try {
|
||||||
const list = await db.listDocuments(APPWRITE_DATABASE_ID, APPWRITE_COLLECTION_REMINDERS_ID, [
|
const list = await db.listDocuments(APPWRITE_DATABASE_ID, APPWRITE_COLLECTION_REMINDERS_ID, [
|
||||||
|
|||||||
56
src/core/api/remindersSchema.ts
Normal file
56
src/core/api/remindersSchema.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const sdk: any = require('node-appwrite');
|
||||||
|
import { getDatabases, isAppwriteConfigured, APPWRITE_COLLECTION_REMINDERS_ID, APPWRITE_DATABASE_ID } from './appwrite';
|
||||||
|
|
||||||
|
export async function ensureRemindersSchema() {
|
||||||
|
if (!isAppwriteConfigured()) return;
|
||||||
|
const db = getDatabases();
|
||||||
|
if (!db) return;
|
||||||
|
|
||||||
|
const databaseId = APPWRITE_DATABASE_ID;
|
||||||
|
const collectionId = APPWRITE_COLLECTION_REMINDERS_ID;
|
||||||
|
|
||||||
|
// 1) Asegurar colección
|
||||||
|
try {
|
||||||
|
await db.getCollection(databaseId, collectionId);
|
||||||
|
} catch {
|
||||||
|
try {
|
||||||
|
await db.createCollection(databaseId, collectionId, collectionId, [
|
||||||
|
// Permisos por defecto: accesible solo por server via API Key
|
||||||
|
]);
|
||||||
|
// Nota: No añadimos permisos de lectura pública para evitar fuga de datos
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('No se pudo crear la colección de recordatorios (puede existir ya):', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Asegurar atributos requeridos
|
||||||
|
const createIfMissing = async (fn: () => Promise<any>) => {
|
||||||
|
try { await fn(); } catch (e: any) {
|
||||||
|
const msg = String(e?.message || e);
|
||||||
|
if (!/already exists|attribute_already_exists/i.test(msg)) {
|
||||||
|
// Otros errores se muestran
|
||||||
|
console.warn('No se pudo crear atributo:', msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await createIfMissing(() => db.createStringAttribute(databaseId, collectionId, 'userId', 64, true));
|
||||||
|
await createIfMissing(() => db.createStringAttribute(databaseId, collectionId, 'guildId', 64, false));
|
||||||
|
await createIfMissing(() => db.createStringAttribute(databaseId, collectionId, 'channelId', 64, false));
|
||||||
|
await createIfMissing(() => db.createStringAttribute(databaseId, collectionId, 'message', 2048, true));
|
||||||
|
await createIfMissing(() => db.createDatetimeAttribute(databaseId, collectionId, 'executeAt', true));
|
||||||
|
await createIfMissing(() => db.createDatetimeAttribute(databaseId, collectionId, 'createdAt', true));
|
||||||
|
|
||||||
|
// 3) Índice por executeAt para consultas por vencimiento
|
||||||
|
try {
|
||||||
|
//@ts-ignore
|
||||||
|
await db.createIndex(databaseId, collectionId, 'idx_executeAt_asc', 'key', ['executeAt'], ['ASC']);
|
||||||
|
} catch (e: any) {
|
||||||
|
const msg = String(e?.message || e);
|
||||||
|
if (!/already exists|index_already_exists/i.test(msg)) {
|
||||||
|
console.warn('No se pudo crear índice executeAt:', msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -7,6 +7,7 @@ import {loadComponents} from "./core/lib/components";
|
|||||||
import { startMemoryMonitor } from "./core/memory/memoryMonitor";
|
import { startMemoryMonitor } from "./core/memory/memoryMonitor";
|
||||||
import {memoryOptimizer} from "./core/memory/memoryOptimizer";
|
import {memoryOptimizer} from "./core/memory/memoryOptimizer";
|
||||||
import { startReminderPoller } from "./core/api/reminders";
|
import { startReminderPoller } from "./core/api/reminders";
|
||||||
|
import { ensureRemindersSchema } from "./core/api/remindersSchema";
|
||||||
|
|
||||||
// Activar monitor de memoria si se define la variable
|
// Activar monitor de memoria si se define la variable
|
||||||
const __memInt = parseInt(process.env.MEMORY_LOG_INTERVAL_SECONDS || '0', 10);
|
const __memInt = parseInt(process.env.MEMORY_LOG_INTERVAL_SECONDS || '0', 10);
|
||||||
@@ -179,6 +180,9 @@ async function bootstrap() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Asegurar esquema de Appwrite para recordatorios (colección + atributos + índice)
|
||||||
|
try { await ensureRemindersSchema(); } catch (e) { console.warn('No se pudo asegurar el esquema de recordatorios:', e); }
|
||||||
|
|
||||||
// Iniciar poller de recordatorios si Appwrite está configurado
|
// Iniciar poller de recordatorios si Appwrite está configurado
|
||||||
startReminderPoller(bot);
|
startReminderPoller(bot);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user