202 lines
11 KiB
JavaScript
202 lines
11 KiB
JavaScript
import fs from 'fs';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import { DatabaseSync } from 'node:sqlite';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const strapiDbPath = path.join(__dirname, '..', 'strapi-cms', '.tmp', 'data.db');
|
|
const strapiUploadsDir = path.join(__dirname, '..', 'strapi-cms', 'public', 'uploads');
|
|
const targetPublicUploads = path.join(__dirname, '..', 'public', 'uploads');
|
|
const targetServerUploads = path.join(__dirname, '..', 'server', 'uploads');
|
|
|
|
function syncUploads() {
|
|
try {
|
|
if (!fs.existsSync(strapiUploadsDir)) return;
|
|
if (!fs.existsSync(targetPublicUploads)) fs.mkdirSync(targetPublicUploads, { recursive: true });
|
|
if (!fs.existsSync(targetServerUploads)) fs.mkdirSync(targetServerUploads, { recursive: true });
|
|
|
|
const files = fs.readdirSync(strapiUploadsDir);
|
|
files.forEach((f) => {
|
|
if (f === '.gitkeep') return;
|
|
const srcFile = path.join(strapiUploadsDir, f);
|
|
const destPublic = path.join(targetPublicUploads, f);
|
|
const destServer = path.join(targetServerUploads, f);
|
|
if (!fs.existsSync(destPublic)) fs.copyFileSync(srcFile, destPublic);
|
|
if (!fs.existsSync(destServer)) fs.copyFileSync(srcFile, destServer);
|
|
});
|
|
} catch (e) {
|
|
console.warn('Note: Upload sync warning:', e.message);
|
|
}
|
|
}
|
|
|
|
export async function getStrapiBlogs() {
|
|
syncUploads();
|
|
|
|
// 1. Primary: Fetch live blogs directly from Strapi REST API (PostgreSQL / Live Strapi DB)
|
|
try {
|
|
const strapiBaseUrl = process.env.STRAPI_URL || 'http://127.0.0.1:1337';
|
|
const response = await fetch(`${strapiBaseUrl}/api/blogs?populate=*`, {
|
|
headers: { 'Accept': 'application/json' },
|
|
signal: AbortSignal.timeout(3000)
|
|
});
|
|
|
|
if (response.ok) {
|
|
const json = await response.json();
|
|
const items = json.data || [];
|
|
|
|
if (Array.isArray(items) && items.length > 0) {
|
|
const blogs = items.map((b) => {
|
|
let coverUrl = b.coverImage?.url || b.ogImage?.url || null;
|
|
if (!coverUrl) {
|
|
const cat = (b.category || '').toLowerCase();
|
|
if (b.title?.includes('LLM')) coverUrl = '/assets/arvindh_llm_financial.jpg';
|
|
else if (b.title?.includes('Supply Chain')) coverUrl = '/assets/arvindh_supply_chain.jpg';
|
|
else if (b.title?.includes('PRODMAX')) coverUrl = '/assets/prodmax_dashboard.png';
|
|
else if (b.title?.includes('Incidents') || b.title?.includes('VR')) coverUrl = '/assets/whyus_vr_man.jpg';
|
|
else if (b.title?.includes('SCADA') || b.title?.includes('IT/OT')) coverUrl = '/assets/whyus_arab_meeting.jpg';
|
|
else if (b.title?.includes('Cleanroom')) coverUrl = 'https://images.unsplash.com/photo-1592478411213-6153e4ebc07d?auto=format&fit=crop&w=800&q=80';
|
|
else if (b.title?.includes('Spatial') || b.title?.includes('Maintenance')) coverUrl = '/assets/whyus_hologram.jpg';
|
|
else if (b.title?.includes('Energy')) coverUrl = '/assets/whyus_teamwork.png';
|
|
else if (b.title?.includes('Telemetry') || b.title?.includes('Sensor')) coverUrl = 'https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?auto=format&fit=crop&w=800&q=80';
|
|
else if (b.title?.includes('Monoliths') || b.title?.includes('Micro-Frontends')) coverUrl = 'https://images.unsplash.com/photo-1519389950473-47ba0277781c?auto=format&fit=crop&w=800&q=80';
|
|
else if (b.title?.includes('Zero-Trust')) coverUrl = 'https://images.unsplash.com/photo-1563986768494-4dee2763ff3f?auto=format&fit=crop&w=800&q=80';
|
|
else if (b.title?.includes('Multi-Cloud')) coverUrl = 'https://images.unsplash.com/photo-1544197150-b99a580bb7a8?auto=format&fit=crop&w=800&q=80';
|
|
else if (cat.includes('ai')) coverUrl = '/assets/arvindh_agentic_ai.jpg';
|
|
else coverUrl = 'https://images.unsplash.com/photo-1519389950473-47ba0277781c?auto=format&fit=crop&w=800&q=80';
|
|
}
|
|
|
|
const rawDate = b.publishDate || b.publishedAt || b.createdAt;
|
|
const dateStr = rawDate
|
|
? new Date(rawDate).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' })
|
|
: new Date().toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' });
|
|
|
|
return {
|
|
id: b.id || b.documentId,
|
|
documentId: b.documentId,
|
|
category: b.category || 'Technology',
|
|
title: b.title,
|
|
excerpt: b.excerpt || '',
|
|
content: b.content || '',
|
|
readTime: b.readTime || '5 min read',
|
|
date: dateStr,
|
|
image: coverUrl,
|
|
slug: b.slug,
|
|
author: (() => {
|
|
if (typeof b.authorName === 'string' && b.authorName.trim()) return b.authorName.trim();
|
|
if (typeof b.author === 'string' && b.author.trim()) return b.author.trim();
|
|
const authorObj = b.author || b.createdBy;
|
|
if (authorObj && typeof authorObj === 'object') {
|
|
const full = `${authorObj.firstname || authorObj.firstName || ''} ${authorObj.lastname || authorObj.lastName || ''}`.trim();
|
|
if (full) return full;
|
|
if (authorObj.username) return authorObj.username;
|
|
}
|
|
const titleLower = (b.title || '').toLowerCase();
|
|
const catLower = (b.category || '').toLowerCase();
|
|
if (titleLower.includes('llm') || titleLower.includes('autonomous') || catLower.includes('ai')) return 'Dr. Arvindh Ramachandran';
|
|
if (titleLower.includes('scada') || titleLower.includes('zero-trust') || catLower.includes('operation')) return 'Vikramaditya Sharma';
|
|
if (titleLower.includes('supply chain') || titleLower.includes('predictive')) return 'Siddharth Varma';
|
|
if (titleLower.includes('speed vs') || titleLower.includes('workplace') || titleLower.includes('retention') || titleLower.includes('training')) return 'Purushothaman Gopalan';
|
|
if (catLower.includes('vr') || catLower.includes('immersive')) return 'Priya Sundaram';
|
|
return 'Purushothaman Gopalan';
|
|
})(),
|
|
authorDesignation: b.authorDesignation || 'Chief AI Architect & Head of Data Engineering',
|
|
editor: (typeof b.editorName === 'string' && b.editorName.trim())
|
|
? b.editorName.trim()
|
|
: (typeof b.editor === 'string' && b.editor.trim()
|
|
? b.editor.trim()
|
|
: (b.editor?.firstname ? `${b.editor.firstname} ${b.editor.lastname || ''}`.trim() : (b.editor?.username || null))),
|
|
editorDesignation: b.editorDesignation || null,
|
|
tags: b.tags || [],
|
|
metaTitle: b.metaTitle || null,
|
|
metaDescription: b.metaDescription || null,
|
|
keywords: b.keywords || null,
|
|
canonicalURL: b.canonicalURL || null
|
|
};
|
|
});
|
|
|
|
if (blogs.length > 0) return blogs;
|
|
}
|
|
}
|
|
} catch (apiErr) {
|
|
console.warn('Note: Live Strapi REST API fetch bypassed/failed, trying SQLite fallback:', apiErr.message);
|
|
}
|
|
|
|
// 2. Fallback: SQLite `.tmp/data.db` if Strapi API is offline
|
|
try {
|
|
if (!fs.existsSync(strapiDbPath)) return null;
|
|
const db = new DatabaseSync(strapiDbPath);
|
|
const rows = db.prepare('SELECT * FROM blogs WHERE published_at IS NOT NULL ORDER BY id ASC').all();
|
|
const mediaLinks = db.prepare("SELECT * FROM files_related_mph WHERE related_type = 'api::blog.blog'").all();
|
|
const files = db.prepare('SELECT * FROM files').all();
|
|
const adminUsers = db.prepare('SELECT id, firstname, lastname FROM admin_users').all();
|
|
|
|
const userMap = {};
|
|
adminUsers.forEach((u) => {
|
|
userMap[u.id] = `${u.firstname || ''} ${u.lastname || ''}`.trim();
|
|
});
|
|
|
|
const seenSlugs = new Set();
|
|
const blogs = [];
|
|
|
|
rows.forEach((b) => {
|
|
if (!b.title || b.title.toLowerCase().startsWith('test 3')) return;
|
|
if (seenSlugs.has(b.slug)) return;
|
|
seenSlugs.add(b.slug);
|
|
|
|
const link = mediaLinks.find((l) => l.related_id === b.id);
|
|
const file = link ? files.find((f) => f.id === link.file_id) : null;
|
|
let image = file ? file.url : null;
|
|
|
|
if (!image) {
|
|
const cat = (b.category || '').toLowerCase();
|
|
if (b.title.includes('LLM')) image = '/assets/arvindh_llm_financial.jpg';
|
|
else if (b.title.includes('Supply Chain')) image = '/assets/arvindh_supply_chain.jpg';
|
|
else if (b.title.includes('PRODMAX')) image = '/assets/prodmax_dashboard.png';
|
|
else if (b.title.includes('Incidents') || b.title.includes('VR')) image = '/assets/whyus_vr_man.jpg';
|
|
else if (b.title.includes('SCADA') || b.title.includes('IT/OT')) image = '/assets/whyus_arab_meeting.jpg';
|
|
else if (b.title.includes('Cleanroom')) image = 'https://images.unsplash.com/photo-1592478411213-6153e4ebc07d?auto=format&fit=crop&w=800&q=80';
|
|
else if (b.title.includes('Spatial') || b.title.includes('Maintenance')) image = '/assets/whyus_hologram.jpg';
|
|
else if (b.title.includes('Energy')) image = '/assets/whyus_teamwork.png';
|
|
else if (b.title.includes('Telemetry') || b.title.includes('Sensor')) image = 'https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?auto=format&fit=crop&w=800&q=80';
|
|
else if (b.title.includes('Monoliths') || b.title.includes('Micro-Frontends')) image = 'https://images.unsplash.com/photo-1519389950473-47ba0277781c?auto=format&fit=crop&w=800&q=80';
|
|
else if (b.title.includes('Zero-Trust')) image = 'https://images.unsplash.com/photo-1563986768494-4dee2763ff3f?auto=format&fit=crop&w=800&q=80';
|
|
else if (b.title.includes('Multi-Cloud')) image = 'https://images.unsplash.com/photo-1544197150-b99a580bb7a8?auto=format&fit=crop&w=800&q=80';
|
|
else if (cat.includes('ai')) image = '/assets/arvindh_agentic_ai.jpg';
|
|
else image = 'https://images.unsplash.com/photo-1519389950473-47ba0277781c?auto=format&fit=crop&w=800&q=80';
|
|
}
|
|
|
|
const dateStr = b.published_at
|
|
? new Date(Number(b.published_at)).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' })
|
|
: new Date(Number(b.created_at || Date.now())).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' });
|
|
|
|
const author = userMap[b.created_by_id] || 'Dr. Arvindh Ramachandran';
|
|
const authorRole = b.author_designation || 'Chief AI Architect & Head of Data Engineering';
|
|
const hasEditor = Boolean(b.editor_designation || (b.updated_by_id && b.updated_by_id !== b.created_by_id));
|
|
const editor = hasEditor ? (userMap[b.updated_by_id] && userMap[b.updated_by_id] !== author ? userMap[b.updated_by_id] : 'Cavin Editorial Board') : null;
|
|
const editorRole = b.editor_designation || (hasEditor ? 'Senior Technical Reviewer' : null);
|
|
|
|
blogs.push({
|
|
id: b.id,
|
|
category: b.category || 'Technology',
|
|
title: b.title,
|
|
excerpt: b.excerpt || '',
|
|
content: b.content || '',
|
|
readTime: b.read_time || '5 min read',
|
|
date: dateStr,
|
|
image,
|
|
slug: b.slug,
|
|
author,
|
|
authorDesignation: authorRole,
|
|
editor,
|
|
editorDesignation: editorRole,
|
|
tags: b.tags ? JSON.parse(b.tags) : []
|
|
});
|
|
});
|
|
|
|
return blogs.length > 0 ? blogs : null;
|
|
} catch (err) {
|
|
console.warn('Note: Strapi SQLite DB sync check bypassed:', err.message);
|
|
return null;
|
|
}
|
|
}
|