almeira-web/src/app/actions/appwrite.ts

178 lines
6.4 KiB
TypeScript

'use server'
import { Client, Databases, Storage, ID, Query } from 'node-appwrite';
import { APPWRITE_ALMEIRA_CONFIG } from '@/lib/appwrite';
import { revalidatePath } from 'next/cache';
import { SCHEMA_MAP, collectionMap } from '@/lib/schema';
// Using local endpoint and the key we set locally
const ENDPOINT = process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT || 'http://localhost/v1';
const PROJECT_ID = process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID || '69bedced002971103d13';
const API_KEY = process.env.APPWRITE_API_KEY || 'standard_2350cc147ace39b0e3fb2c42d1447bc00effb4d5e6115cd682b0d215297a3b35b2ce82e312bd35cff1b738d5eb3462c5b28887937acf217eca6c2143aa0bf4e85ab183350db830901edc0d80d17755d1de5524b945d0c4cb11871af8d33df7f7cdbdfea4237dfc8a47e3c71ac79b3e5172834cc09d451d687a3db74e839ec7a7';
export async function createDocumentServer(collectionId: string, data: any) {
try {
const client = new Client()
.setEndpoint(ENDPOINT)
.setProject(PROJECT_ID)
.setKey(API_KEY);
const databases = new Databases(client);
for(const key in data) {
if(data[key] === 'true') data[key] = true;
if(data[key] === 'false') data[key] = false;
if(data[key] === '' && typeof data[key] === 'string') delete data[key];
}
const doc = await databases.createDocument(
APPWRITE_ALMEIRA_CONFIG.databaseId,
collectionId,
ID.unique(),
data
);
revalidatePath('/dashboard/[entity]', 'page');
return { success: true, doc };
} catch (error: any) {
console.error("Create error:", error);
return { success: false, error: error.message };
}
}
export async function updateDocumentServer(collectionId: string, documentId: string, data: any) {
try {
const client = new Client().setEndpoint(ENDPOINT).setProject(PROJECT_ID).setKey(API_KEY);
const databases = new Databases(client);
for(const key in data) {
if(data[key] === 'true') data[key] = true;
if(data[key] === 'false') data[key] = false;
if(data[key] === '' && typeof data[key] === 'string') data[key] = null; // Send null to clear optional strings
}
const doc = await databases.updateDocument(
APPWRITE_ALMEIRA_CONFIG.databaseId,
collectionId,
documentId,
data
);
revalidatePath('/dashboard/[entity]', 'page');
return { success: true, doc };
} catch (error: any) {
console.error("Update error:", error);
return { success: false, error: error.message };
}
}
export async function deleteDocumentServer(collectionId: string, documentId: string, entityAlias: string) {
try {
const client = new Client().setEndpoint(ENDPOINT).setProject(PROJECT_ID).setKey(API_KEY);
const databases = new Databases(client);
// Dynamic Relational Restriction Check
// We scan all collections in SCHEMA_MAP to see if any holds a relation to the collection we are trying to delete from
for (const [colAlias, fields] of Object.entries(SCHEMA_MAP)) {
const referencingFields = fields.filter(f => f.type === 'relation' && f.relationCollection === entityAlias);
for (const refField of referencingFields) {
const checkColId = collectionMap[colAlias];
if (!checkColId) continue;
const list = await databases.listDocuments(
APPWRITE_ALMEIRA_CONFIG.databaseId,
checkColId,
[Query.equal(refField.name, documentId), Query.limit(1)]
);
if (list.total > 0) {
return {
success: false,
error: `No se puede eliminar. Existen registros en '${colAlias.replace(/_/g, ' ')}' que dependen de este dato.`
};
}
}
}
// No relation found preventing deletion, proceed safely!
await databases.deleteDocument(
APPWRITE_ALMEIRA_CONFIG.databaseId,
collectionId,
documentId
);
revalidatePath('/dashboard/[entity]', 'page');
return { success: true };
} catch (error: any) {
console.error("Delete error:", error);
return { success: false, error: error.message };
}
}
export async function uploadMediaServer(formData: FormData) {
try {
const client = new Client().setEndpoint(ENDPOINT).setProject(PROJECT_ID).setKey(API_KEY);
const databases = new Databases(client);
const files = formData.getAll('files') as File[];
if (!files || files.length === 0) throw new Error("No hay archivos para subir");
const manualTitulo = formData.get('titulo') as string;
const manualAlt = formData.get('alt_text') as string;
const manualDesc = formData.get('descripcion_seo') as string;
for (const file of files) {
if (!file || file.size === 0) continue;
// Native Fetch REST call to upload the file bypassing node-appwrite buffer overload
const appwriteFormData = new FormData();
appwriteFormData.append('fileId', 'unique()');
appwriteFormData.append('file', file);
const uploadResponse = await fetch(`${ENDPOINT}/storage/buckets/media_bucket/files`, {
method: 'POST',
headers: {
'X-Appwrite-Project': PROJECT_ID,
'X-Appwrite-Key': API_KEY
},
body: appwriteFormData
});
if (!uploadResponse.ok) {
const errBody = await uploadResponse.text();
throw new Error(`Error subiendo al Bucket: ${errBody}`);
}
const uploadData = await uploadResponse.json();
// Limpiar el nombre del archivo
let cleanName = file.name.replace(/\.[^/.]+$/, "");
cleanName = cleanName.replace(/[-_]/g, ' ');
cleanName = cleanName.replace(/[0-9]+$/g, '');
cleanName = cleanName.replace(/\s+/g, ' ').trim();
if (!cleanName) cleanName = 'Multimedia';
await databases.createDocument(
APPWRITE_ALMEIRA_CONFIG.databaseId,
'media',
ID.unique(),
{
file_id: uploadData.$id,
bucket_id: 'media_bucket',
titulo: manualTitulo || cleanName,
alt_text: manualAlt || cleanName,
descripcion_seo: manualDesc || cleanName,
tipo: file.type.startsWith('video') ? 'video' : 'imagen'
}
);
}
revalidatePath('/dashboard/media');
return { success: true };
} catch(error: any) {
console.error("Upload Error:", error);
return { success: false, error: error.message };
}
}