feat: add reminders schema management for Appwrite integration

This commit is contained in:
2025-09-28 01:09:26 -05:00
parent 2863183bbd
commit 1cd11e8f9a
3 changed files with 73 additions and 0 deletions

View File

@@ -2,6 +2,7 @@
const sdk: any = require('node-appwrite');
import type Amayo from '../client';
import { getDatabases, isAppwriteConfigured, APPWRITE_COLLECTION_REMINDERS_ID, APPWRITE_DATABASE_ID } from './appwrite';
import { ensureRemindersSchema } from './remindersSchema';
export type ReminderDoc = {
$id?: string;
@@ -23,9 +24,20 @@ export type ReminderRow = ReminderDoc & {
$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> {
const db = getDatabases();
if (!db || !isAppwriteConfigured()) throw new Error('Appwrite no está configurado');
await ensureSchemaOnce();
const data = {
userId: doc.userId,
guildId: doc.guildId ?? null,
@@ -41,6 +53,7 @@ export async function scheduleReminder(doc: ReminderDoc): Promise<string> {
async function fetchDueReminders(limit = 25): Promise<ReminderRow[]> {
const db = getDatabases();
if (!db || !isAppwriteConfigured()) return [];
try { await ensureSchemaOnce(); } catch {}
const nowIso = new Date().toISOString();
try {
const list = await db.listDocuments(APPWRITE_DATABASE_ID, APPWRITE_COLLECTION_REMINDERS_ID, [

View 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);
}
}
}