132 lines
3.8 KiB
TypeScript
132 lines
3.8 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import { Pool } from 'pg';
|
|
|
|
// PostgreSQL connection configuration
|
|
const pool = new Pool({
|
|
host: '172.16.0.104',
|
|
port: 5432,
|
|
database: 'rivacube',
|
|
user: 'alma',
|
|
password: 'rivacube',
|
|
connectionTimeoutMillis: 5000,
|
|
query_timeout: 5000
|
|
});
|
|
|
|
// Helper function to clean HTML content
|
|
function cleanHtmlContent(content: string): string {
|
|
if (!content) return '';
|
|
return content
|
|
.replace(/<[^>]*>/g, '')
|
|
.replace(/ /g, ' ')
|
|
.replace(/&/g, '&')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, "'")
|
|
.trim();
|
|
}
|
|
|
|
// Helper function to format time
|
|
function formatDateTime(dateStr: string): { displayDate: string, timestamp: string } {
|
|
try {
|
|
const date = new Date(dateStr);
|
|
const day = date.getDate();
|
|
const month = date.toLocaleString('fr-FR', { month: 'short' }).toLowerCase();
|
|
|
|
return {
|
|
displayDate: `${day} ${month}.`, // Added dot for better styling
|
|
timestamp: date.toLocaleString('fr-FR', {
|
|
day: '2-digit',
|
|
month: 'short',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hour12: false
|
|
}).replace(',', ' à') // Format: "14 avr. à 15:30"
|
|
};
|
|
} catch (error) {
|
|
return { displayDate: 'N/A', timestamp: 'N/A' };
|
|
}
|
|
}
|
|
|
|
// Helper function to truncate text
|
|
function truncateText(text: string, maxLength: number): string {
|
|
if (!text || text.length <= maxLength) return text;
|
|
// Find the last space before maxLength to avoid cutting words
|
|
const lastSpace = text.lastIndexOf(' ', maxLength);
|
|
const truncated = text.substring(0, lastSpace > 0 ? lastSpace : maxLength).trim();
|
|
return truncated.replace(/[.,!?]$/, '') + '...';
|
|
}
|
|
|
|
// Helper function to format category
|
|
function formatCategory(category: string): string {
|
|
if (!category) return 'GENERAL';
|
|
// Make category names shorter and more readable
|
|
const categoryMap: { [key: string]: string } = {
|
|
'GLOBAL ISSUES - WORLD AFFAIRS': 'WORLD',
|
|
'UN NEWS - GLOBAL NEWS': 'UN NEWS',
|
|
'GLOBAL NEWS': 'WORLD',
|
|
};
|
|
|
|
const normalizedCategory = category.toUpperCase();
|
|
return categoryMap[normalizedCategory] || normalizedCategory;
|
|
}
|
|
|
|
// Helper function to format source
|
|
function formatSource(source: string): string {
|
|
if (!source) return '';
|
|
// Extract domain name without TLD and clean it up
|
|
const sourceName = source
|
|
.replace(/^(https?:\/\/)?(www\.)?/i, '')
|
|
.split('.')[0]
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]/g, ' ')
|
|
.trim();
|
|
return sourceName.charAt(0).toUpperCase() + sourceName.slice(1);
|
|
}
|
|
|
|
export async function GET() {
|
|
let client;
|
|
try {
|
|
client = await pool.connect();
|
|
console.log('Connected to PostgreSQL database');
|
|
|
|
const result = await client.query(
|
|
'SELECT * FROM news ORDER BY date DESC LIMIT 3'
|
|
);
|
|
|
|
const formattedNews = result.rows.map(article => {
|
|
const { displayDate, timestamp } = formatDateTime(article.date);
|
|
return {
|
|
id: article.id,
|
|
title: truncateText(article.title, 55),
|
|
description: truncateText(article.description, 85),
|
|
displayDate,
|
|
timestamp,
|
|
source: formatSource(article.source),
|
|
category: formatCategory(article.category),
|
|
url: article.url || '#',
|
|
};
|
|
});
|
|
|
|
console.log(`Successfully fetched ${formattedNews.length} news articles`);
|
|
return NextResponse.json(formattedNews);
|
|
|
|
} catch (error) {
|
|
console.error('Error in news API:', {
|
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
stack: error instanceof Error ? error.stack : undefined,
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
|
|
return NextResponse.json(
|
|
{
|
|
error: 'Failed to fetch news',
|
|
details: error instanceof Error ? error.message : 'Unknown error',
|
|
timestamp: new Date().toISOString(),
|
|
},
|
|
{ status: 500 }
|
|
);
|
|
} finally {
|
|
if (client) {
|
|
client.release();
|
|
}
|
|
}
|
|
}
|