237 lines
6.9 KiB
JavaScript
237 lines
6.9 KiB
JavaScript
const express = require('express');
|
|
const path = require('path');
|
|
const axios = require('axios');
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 3000;
|
|
const API_URL = process.env.API_URL || 'http://localhost:5001';
|
|
|
|
app.use(express.json());
|
|
|
|
// Serve admin page (before static middleware)
|
|
app.get('/admin.html', (req, res) => {
|
|
res.sendFile(path.join(__dirname, 'public', 'admin.html'));
|
|
});
|
|
|
|
app.get('/admin', (req, res) => {
|
|
res.sendFile(path.join(__dirname, 'public', 'admin.html'));
|
|
});
|
|
|
|
// Serve preferences page
|
|
app.get('/preferences.html', (req, res) => {
|
|
res.sendFile(path.join(__dirname, 'public', 'preferences.html'));
|
|
});
|
|
|
|
app.get('/preferences', (req, res) => {
|
|
res.sendFile(path.join(__dirname, 'public', 'preferences.html'));
|
|
});
|
|
|
|
// Serve static files
|
|
app.use(express.static('public'));
|
|
|
|
// API proxy
|
|
app.get('/api/news', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/news`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(500).json({ error: 'Failed to fetch news' });
|
|
}
|
|
});
|
|
|
|
app.get('/api/stats', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/stats`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(500).json({ error: 'Failed to fetch stats' });
|
|
}
|
|
});
|
|
|
|
app.post('/api/subscribe', async (req, res) => {
|
|
try {
|
|
const response = await axios.post(`${API_URL}/api/subscribe`, req.body);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(error.response?.status || 500).json(
|
|
error.response?.data || { error: 'Failed to subscribe' }
|
|
);
|
|
}
|
|
});
|
|
|
|
app.post('/api/unsubscribe', async (req, res) => {
|
|
try {
|
|
const response = await axios.post(`${API_URL}/api/unsubscribe`, req.body);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(error.response?.status || 500).json(
|
|
error.response?.data || { error: 'Failed to unsubscribe' }
|
|
);
|
|
}
|
|
});
|
|
|
|
app.get('/api/subscribers', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/subscribers`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(error.response?.status || 500).json(
|
|
error.response?.data || { error: 'Failed to get subscribers' }
|
|
);
|
|
}
|
|
});
|
|
|
|
app.get('/api/subscribers/:email', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/subscribers/${req.params.email}`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(error.response?.status || 500).json(
|
|
error.response?.data || { error: 'Failed to get subscriber' }
|
|
);
|
|
}
|
|
});
|
|
|
|
app.get('/api/categories', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/categories`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(error.response?.status || 500).json(
|
|
error.response?.data || { error: 'Failed to get categories' }
|
|
);
|
|
}
|
|
});
|
|
|
|
app.delete('/api/admin/subscribers/delete-all', async (req, res) => {
|
|
try {
|
|
const response = await axios.delete(`${API_URL}/api/admin/subscribers/delete-all`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(error.response?.status || 500).json(
|
|
error.response?.data || { error: 'Failed to delete subscribers' }
|
|
);
|
|
}
|
|
});
|
|
|
|
app.get('/api/rss-feeds', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/rss-feeds`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(error.response?.status || 500).json(
|
|
error.response?.data || { error: 'Failed to get RSS feeds' }
|
|
);
|
|
}
|
|
});
|
|
|
|
app.get('/api/rss-feeds/export', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/rss-feeds/export`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(error.response?.status || 500).json(
|
|
error.response?.data || { error: 'Failed to export RSS feeds' }
|
|
);
|
|
}
|
|
});
|
|
|
|
app.post('/api/rss-feeds/import', async (req, res) => {
|
|
try {
|
|
const response = await axios.post(`${API_URL}/api/rss-feeds/import`, req.body);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(error.response?.status || 500).json(
|
|
error.response?.data || { error: 'Failed to import RSS feeds' }
|
|
);
|
|
}
|
|
});
|
|
|
|
app.get('/api/admin/recent-articles', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/admin/recent-articles`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(error.response?.status || 500).json(
|
|
error.response?.data || { error: 'Failed to get recent articles' }
|
|
);
|
|
}
|
|
});
|
|
|
|
// Ollama API proxy endpoints for admin dashboard
|
|
app.get('/api/ollama/ping', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/ollama/ping`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(500).json({ error: 'Failed to ping Ollama' });
|
|
}
|
|
});
|
|
|
|
app.get('/api/ollama/gpu-status', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/ollama/gpu-status`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(500).json({ error: 'Failed to get GPU status' });
|
|
}
|
|
});
|
|
|
|
app.get('/api/ollama/test', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/ollama/test`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(500).json({ error: 'Failed to test Ollama' });
|
|
}
|
|
});
|
|
|
|
app.get('/api/ollama/models', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/ollama/models`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(500).json({ error: 'Failed to get models' });
|
|
}
|
|
});
|
|
|
|
app.get('/api/ollama/config', async (req, res) => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/api/ollama/config`);
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
res.status(500).json({ error: 'Failed to get config' });
|
|
}
|
|
});
|
|
|
|
app.get('/api/search', async (req, res) => {
|
|
try {
|
|
const { q, limit, category } = req.query;
|
|
const response = await axios.get(`${API_URL}/api/search`, {
|
|
params: { q, limit, category }
|
|
});
|
|
res.json(response.data);
|
|
} catch (error) {
|
|
if (error.response) {
|
|
// The request was made and the server responded with a status code
|
|
// that falls out of the range of 2xx
|
|
console.error('Search API Error:', error.response.status, error.response.data);
|
|
res.status(error.response.status).json(error.response.data);
|
|
} else if (error.request) {
|
|
// The request was made but no response was received
|
|
console.error('Search API No Response:', error.request);
|
|
res.status(502).json({ error: 'Search service unavailable (timeout/connection)' });
|
|
} else {
|
|
// Something happened in setting up the request that triggered an Error
|
|
console.error('Search API Request Error:', error.message);
|
|
res.status(500).json({ error: 'Internal proxy error' });
|
|
}
|
|
}
|
|
});
|
|
|
|
app.listen(PORT, () => {
|
|
console.log(`Frontend server running on http://localhost:${PORT}`);
|
|
console.log(`Admin dashboard: http://localhost:${PORT}/admin.html`);
|
|
});
|
|
|