feat: Add admin month filter and fix cauca post generation
This commit is contained in:
parent
e00faf1ace
commit
f77523519e
204
publish-cauca.js
Normal file
204
publish-cauca.js
Normal file
@ -0,0 +1,204 @@
|
||||
const fs = require('fs');
|
||||
const axios = require('axios');
|
||||
const { Client, Databases, Storage, ID } = require('node-appwrite');
|
||||
require('dotenv').config({ path: '.env.local' });
|
||||
|
||||
// Let's try to get InputFile if it exists in node-appwrite/file (for older SDKs)
|
||||
let InputFile;
|
||||
try {
|
||||
InputFile = require('node-appwrite/file').InputFile;
|
||||
} catch (e) {
|
||||
InputFile = null;
|
||||
}
|
||||
|
||||
const EVOLUTION_API_URL = process.env.EVOLUTION_API_URL;
|
||||
const EVOLUTION_API_KEY = process.env.EVOLUTION_API_KEY;
|
||||
const EVOLUTION_INSTANCE_NAME = process.env.EVOLUTION_INSTANCE_NAME;
|
||||
const CHAT_ID = '573134848203-1408546044@g.us';
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT)
|
||||
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID)
|
||||
.setKey(process.env.APPWRITE_API_KEY);
|
||||
|
||||
const databases = new Databases(client);
|
||||
const storage = new Storage(client);
|
||||
|
||||
const DB_ID = process.env.APPWRITE_DATABASE_ID;
|
||||
const BUCKET_ID = process.env.NEXT_PUBLIC_APPWRITE_MEDIA_BUCKET_ID;
|
||||
|
||||
async function getCollectionIds() {
|
||||
const list = await databases.listCollections(DB_ID);
|
||||
const map = {};
|
||||
list.collections.forEach(c => { map[c.name.toLowerCase()] = c.$id; });
|
||||
return map;
|
||||
}
|
||||
|
||||
async function run() {
|
||||
console.log("Starting publishing process...");
|
||||
try {
|
||||
const collections = await getCollectionIds();
|
||||
const postsCollectionId = collections['posts'] || 'posts';
|
||||
const mediaCollectionId = collections['media'] || 'media';
|
||||
const pubTypesCollectionId = collections['publication types'] || collections['publication_types'] || 'publication_types';
|
||||
|
||||
const pubTypes = await databases.listDocuments(DB_ID, pubTypesCollectionId);
|
||||
const defaultPubTypeId = pubTypes.documents.length > 0 ? pubTypes.documents[0].$id : null;
|
||||
if (!defaultPubTypeId) {
|
||||
console.error("No publication types found. Can't create posts.");
|
||||
return;
|
||||
}
|
||||
|
||||
const allImages = [];
|
||||
let currentPage = 1;
|
||||
let totalPages = 1;
|
||||
|
||||
console.log("Fetching messages from Evolution API...");
|
||||
do {
|
||||
const response = await axios.post(
|
||||
`${EVOLUTION_API_URL}/chat/findMessages/${EVOLUTION_INSTANCE_NAME}?page=${currentPage}&limit=100`,
|
||||
{ where: { "key": { "remoteJid": CHAT_ID } } },
|
||||
{ headers: { 'apikey': EVOLUTION_API_KEY, 'Content-Type': 'application/json' } }
|
||||
);
|
||||
|
||||
const messagesObj = response.data.messages || {};
|
||||
totalPages = messagesObj.pages || 1;
|
||||
const records = messagesObj.records || [];
|
||||
|
||||
for (const msg of records) {
|
||||
if (msg.messageType === 'imageMessage') {
|
||||
allImages.push(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentPage > 40) break;
|
||||
currentPage++;
|
||||
} while (currentPage <= totalPages);
|
||||
|
||||
console.log(`Total images found in chat history: ${allImages.length}`);
|
||||
|
||||
// We need 32 images (8 for March, 8 for April, 8 for May, 8 for June)
|
||||
// If we don't have enough images, we'll just use as many as we have.
|
||||
// We'll distribute them artificially over the months if the actual timestamps are all from June.
|
||||
|
||||
let targetMonths = [3, 4, 5, 6];
|
||||
let imageIndex = 0;
|
||||
|
||||
for (const month of targetMonths) {
|
||||
console.log(`\n--- Publishing for Month ${month} ---`);
|
||||
let publishedCount = 0;
|
||||
|
||||
while (publishedCount < 8 && imageIndex < allImages.length) {
|
||||
const msg = allImages[imageIndex];
|
||||
imageIndex++;
|
||||
|
||||
try {
|
||||
// Get base64
|
||||
const base64Res = await axios.post(
|
||||
`${EVOLUTION_API_URL}/chat/getBase64FromMediaMessage/${EVOLUTION_INSTANCE_NAME}`,
|
||||
{ message: msg },
|
||||
{ headers: { 'apikey': EVOLUTION_API_KEY, 'Content-Type': 'application/json' } }
|
||||
);
|
||||
|
||||
const base64Data = base64Res.data.base64;
|
||||
if (!base64Data) continue;
|
||||
|
||||
const buffer = Buffer.from(base64Data, 'base64');
|
||||
const filePath = `/tmp/image-${month}-${publishedCount}.jpeg`;
|
||||
const filename = `image-${month}-${publishedCount}.jpeg`;
|
||||
fs.writeFileSync(filePath, buffer);
|
||||
|
||||
// Appwrite File Upload Compatibility
|
||||
let fileParam;
|
||||
if (InputFile && InputFile.fromPath) {
|
||||
fileParam = InputFile.fromPath(filePath, filename);
|
||||
} else if (InputFile && InputFile.fromBuffer) {
|
||||
fileParam = InputFile.fromBuffer(buffer, filename);
|
||||
} else {
|
||||
// Fallback to node fs read stream (works in some SDKs) or directly passing string path if supported
|
||||
// Appwrite 1.x Node SDK usually accepts a ReadStream
|
||||
fileParam = fs.createReadStream(filePath);
|
||||
}
|
||||
|
||||
const file = await storage.createFile(
|
||||
BUCKET_ID,
|
||||
ID.unique(),
|
||||
fileParam
|
||||
);
|
||||
|
||||
let mediaDoc;
|
||||
try {
|
||||
mediaDoc = await databases.createDocument(
|
||||
DB_ID,
|
||||
mediaCollectionId,
|
||||
ID.unique(),
|
||||
{
|
||||
file_id: file.$id,
|
||||
bucket_id: BUCKET_ID,
|
||||
titulo: `Pieza Gráfica Gobernación del Cauca - Mes ${month}`,
|
||||
tipo: 'imagen'
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Media error:", e.message);
|
||||
throw e;
|
||||
}
|
||||
|
||||
let caption = msg.message?.imageMessage?.caption || `Pieza gráfica de la Gobernación del Cauca correspondiente al mes ${month}.`;
|
||||
|
||||
let title = `Boletín Gobernación - Mes ${month} #${publishedCount + 1}`;
|
||||
if (caption && caption.length >= 5) {
|
||||
const lines = caption.split('\n').map(l => l.trim()).filter(l => l.length > 5);
|
||||
if (lines.length > 0) {
|
||||
title = lines[0];
|
||||
if ((title.toUpperCase() === title || title.includes("GOBERNACIÓN")) && lines.length > 1) {
|
||||
title = lines[1];
|
||||
}
|
||||
title = title.replace(/^[\p{Emoji}\s]+/gu, '');
|
||||
if (title.length > 100) title = title.substring(0, 100) + '...';
|
||||
}
|
||||
}
|
||||
|
||||
const slug = `gobernacion-cauca-mes-${month}-pub-${publishedCount}-${Date.now()}`;
|
||||
|
||||
const realDate = new Date(msg.messageTimestamp * 1000).toISOString();
|
||||
const cleanCaption = caption || `Publicación gráfica de la Gobernación del Cauca para el mes de ${month}.`;
|
||||
|
||||
try {
|
||||
await databases.createDocument(
|
||||
DB_ID,
|
||||
postsCollectionId,
|
||||
ID.unique(),
|
||||
{
|
||||
titulo: title,
|
||||
slug: slug,
|
||||
tipo_publicacion_id: defaultPubTypeId,
|
||||
estado: 'borrador', // Cambiado a borrador para revisión
|
||||
fecha_publicacion: realDate, // Fecha real del mensaje
|
||||
contenido: `<p>${cleanCaption.replace(/\n/g, '<br/>')}</p>`, // Formato HTML básico
|
||||
imagen_destacada_id: mediaDoc.$id
|
||||
}
|
||||
);
|
||||
} catch(e) {
|
||||
console.error("Post error:", e.message);
|
||||
throw e;
|
||||
}
|
||||
|
||||
console.log(`[Success] Published post ${publishedCount + 1}/8 for Month ${month}`);
|
||||
publishedCount++;
|
||||
} catch (err) {
|
||||
console.error(`Failed to publish image for month ${month}:`, err.message);
|
||||
}
|
||||
}
|
||||
if (publishedCount < 8) {
|
||||
console.log(`Could only publish ${publishedCount} images for Month ${month} (ran out of images).`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("All done!");
|
||||
} catch (e) {
|
||||
console.error("Error:", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
run();
|
||||
@ -9,7 +9,7 @@ import { decodeHtmlEntities } from '@/lib/utils';
|
||||
import { Settings } from '@/types/settings';
|
||||
import { Post, MediaItem } from '@/types/publications';
|
||||
|
||||
async function fetchHomeData(page: number = 1) {
|
||||
async function fetchHomeData(page: number = 1, isAdmin: boolean = false, adminMonth: number | null = null) {
|
||||
try {
|
||||
const client = await createAdminClient();
|
||||
|
||||
@ -43,13 +43,30 @@ async function fetchHomeData(page: number = 1) {
|
||||
if (!typeId) return { posts: [], cardSettings, totalPages: 1 };
|
||||
|
||||
const offset = (page - 1) * postsCount;
|
||||
const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', [
|
||||
|
||||
const queries = [
|
||||
Query.equal('tipo_publicacion_id', typeId),
|
||||
Query.equal('estado', 'Publicado'),
|
||||
Query.orderDesc('fecha_publicacion'),
|
||||
Query.limit(postsCount),
|
||||
Query.offset(offset)
|
||||
]);
|
||||
];
|
||||
|
||||
if (isAdmin) {
|
||||
queries.push(Query.equal('estado', ['Publicado', 'borrador']));
|
||||
if (adminMonth) {
|
||||
const currentYear = new Date().getFullYear();
|
||||
// First day of the selected month
|
||||
const startDate = new Date(currentYear, adminMonth - 1, 1).toISOString();
|
||||
// First day of the next month
|
||||
const endDate = new Date(currentYear, adminMonth, 1).toISOString();
|
||||
queries.push(Query.greaterThanEqual('fecha_publicacion', startDate));
|
||||
queries.push(Query.lessThan('fecha_publicacion', endDate));
|
||||
}
|
||||
} else {
|
||||
queries.push(Query.equal('estado', 'Publicado'));
|
||||
}
|
||||
|
||||
const postsRes = await client.databases.listDocuments(APPWRITE_ALMEIRA_CONFIG.databaseId, 'posts', queries);
|
||||
posts = postsRes.documents as unknown as Post[];
|
||||
totalPages = Math.ceil(postsRes.total / postsCount);
|
||||
|
||||
@ -79,12 +96,14 @@ export const dynamic = "force-dynamic";
|
||||
export default async function Home(props: { searchParams: Promise<{ [key: string]: string | string[] | undefined }> }) {
|
||||
const searchParams = await props.searchParams;
|
||||
const page = Number(searchParams?.page) || 1;
|
||||
const { posts, cardSettings, totalPages } = await fetchHomeData(page);
|
||||
const hasSidebar = await hasSidebarContent();
|
||||
const adminMonth = searchParams?.month ? Number(searchParams.month) : null;
|
||||
|
||||
const user = await getLoggedInUser();
|
||||
const isAdmin = (user as any)?.labels?.includes('admin') || (user as any)?.labels?.includes('editor') || user?.$id === 'admin-emergency';
|
||||
|
||||
const { posts, cardSettings, totalPages } = await fetchHomeData(page, isAdmin, adminMonth);
|
||||
const hasSidebar = await hasSidebarContent();
|
||||
|
||||
return (
|
||||
<main className="animate-fade-in relative">
|
||||
{/* Sci-Fi Hero Section */}
|
||||
@ -138,6 +157,34 @@ export default async function Home(props: { searchParams: Promise<{ [key: string
|
||||
</div>
|
||||
<h2 className="text-4xl md:text-5xl font-outfit font-black text-white">Feed de <span className="text-transparent bg-clip-text bg-gradient-to-r from-white to-slate-500">Noticias</span></h2>
|
||||
</div>
|
||||
{isAdmin && (
|
||||
<form action="/" method="GET" className="flex items-center gap-3 bg-slate-800/80 p-3 rounded-xl border border-white/10">
|
||||
<input type="hidden" name="page" value="1" />
|
||||
<span className="text-sm text-slate-400 font-bold uppercase tracking-wider">Filtro Admin:</span>
|
||||
<select
|
||||
name="month"
|
||||
className="bg-slate-900 border border-white/10 text-white rounded-lg px-3 py-2 text-sm outline-none focus:border-cyan-500"
|
||||
defaultValue={adminMonth || ""}
|
||||
>
|
||||
<option value="">Todos los meses</option>
|
||||
<option value="1">Enero</option>
|
||||
<option value="2">Febrero</option>
|
||||
<option value="3">Marzo</option>
|
||||
<option value="4">Abril</option>
|
||||
<option value="5">Mayo</option>
|
||||
<option value="6">Junio</option>
|
||||
<option value="7">Julio</option>
|
||||
<option value="8">Agosto</option>
|
||||
<option value="9">Septiembre</option>
|
||||
<option value="10">Octubre</option>
|
||||
<option value="11">Noviembre</option>
|
||||
<option value="12">Diciembre</option>
|
||||
</select>
|
||||
<button type="submit" className="bg-cyan-600 hover:bg-cyan-500 text-white font-bold px-4 py-2 rounded-lg text-sm transition-colors">
|
||||
Filtrar
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{posts.length === 0 ? (
|
||||
@ -185,7 +232,7 @@ export default async function Home(props: { searchParams: Promise<{ [key: string
|
||||
{totalPages > 1 && (
|
||||
<div className="flex justify-center items-center gap-4 mt-12">
|
||||
{page > 1 ? (
|
||||
<a href={`/?page=${page - 1}#noticias`} className="px-6 py-3 rounded-xl bg-slate-800/80 text-white font-bold hover:bg-slate-700 transition-colors border border-white/10">
|
||||
<a href={`/?page=${page - 1}${adminMonth ? `&month=${adminMonth}` : ''}#noticias`} className="px-6 py-3 rounded-xl bg-slate-800/80 text-white font-bold hover:bg-slate-700 transition-colors border border-white/10">
|
||||
Anterior
|
||||
</a>
|
||||
) : (
|
||||
@ -195,7 +242,7 @@ export default async function Home(props: { searchParams: Promise<{ [key: string
|
||||
)}
|
||||
<span className="text-slate-400 font-medium">Página {page} de {totalPages}</span>
|
||||
{page < totalPages ? (
|
||||
<a href={`/?page=${page + 1}#noticias`} className="px-6 py-3 rounded-xl bg-cyan-600 text-white font-bold hover:bg-cyan-500 transition-colors shadow-[0_0_15px_rgba(6,182,212,0.3)]">
|
||||
<a href={`/?page=${page + 1}${adminMonth ? `&month=${adminMonth}` : ''}#noticias`} className="px-6 py-3 rounded-xl bg-cyan-600 text-white font-bold hover:bg-cyan-500 transition-colors shadow-[0_0_15px_rgba(6,182,212,0.3)]">
|
||||
Siguiente
|
||||
</a>
|
||||
) : (
|
||||
|
||||
29
update-dates.js
Normal file
29
update-dates.js
Normal file
@ -0,0 +1,29 @@
|
||||
const { Client, Databases, Query } = require('node-appwrite');
|
||||
require('dotenv').config({ path: '.env.local' });
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT)
|
||||
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID)
|
||||
.setKey(process.env.APPWRITE_API_KEY);
|
||||
|
||||
const databases = new Databases(client);
|
||||
const DB_ID = process.env.APPWRITE_DATABASE_ID;
|
||||
const POSTS_COLLECTION = '66624ef80036ca6dce06'; // We should probably fetch it, but I'll dynamically fetch
|
||||
|
||||
async function run() {
|
||||
console.log("Fetching all posts to delete old script posts...");
|
||||
try {
|
||||
const res = await databases.listDocuments(DB_ID, 'posts', [Query.limit(500)]);
|
||||
const scriptPosts = res.documents.filter(p => p.slug && p.slug.startsWith('gobernacion-cauca-mes-'));
|
||||
console.log(`Found ${scriptPosts.length} posts to delete.`);
|
||||
|
||||
for (const post of scriptPosts) {
|
||||
await databases.deleteDocument(DB_ID, 'posts', post.$id);
|
||||
console.log(`Deleted ${post.slug}`);
|
||||
}
|
||||
console.log("Deletion complete.");
|
||||
} catch (e) {
|
||||
console.error("Error during deletion:", e);
|
||||
}
|
||||
}
|
||||
run();
|
||||
Loading…
Reference in New Issue
Block a user