Spaces:
Running
Running
Update server.js
Browse files
server.js
CHANGED
@@ -9,6 +9,7 @@ import jwt from 'jsonwebtoken';
|
|
9 |
import FormData from 'form-data';
|
10 |
import pg from 'pg';
|
11 |
import fetch from 'node-fetch';
|
|
|
12 |
|
13 |
dotenv.config();
|
14 |
|
@@ -99,6 +100,9 @@ const pool = new Pool({
|
|
99 |
}
|
100 |
});
|
101 |
|
|
|
|
|
|
|
102 |
// Create tables if they don't exist
|
103 |
const initializeDatabase = async () => {
|
104 |
try {
|
@@ -132,6 +136,11 @@ const initializeDatabase = async () => {
|
|
132 |
`);
|
133 |
// Add censored column if it doesn't exist
|
134 |
await pool.query(`ALTER TABLE images ADD COLUMN IF NOT EXISTS censored BOOLEAN DEFAULT false;`);
|
|
|
|
|
|
|
|
|
|
|
135 |
console.log('Database initialized successfully');
|
136 |
} catch (error) {
|
137 |
console.error('Error initializing database:', error);
|
@@ -322,14 +331,25 @@ app.post('/api/upload-image', authenticateToken, async (req, res) => {
|
|
322 |
}
|
323 |
});
|
324 |
|
|
|
325 |
app.get('/api/community-images', async (req, res) => {
|
326 |
try {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
327 |
const result = await pool.query(`
|
328 |
SELECT i.id, i.image_url, i.uploaded_url, i.prompt, i.created_at, i.censored, u.username
|
329 |
FROM images i
|
330 |
JOIN users u ON i.user_id = u.id
|
331 |
ORDER BY i.created_at DESC
|
332 |
-
|
|
|
|
|
333 |
res.json(result.rows);
|
334 |
} catch (error) {
|
335 |
console.error('Error fetching community images:', error);
|
@@ -796,18 +816,22 @@ app.post('/api/add-community-image', authenticateToken, async (req, res) => {
|
|
796 |
}
|
797 |
});
|
798 |
|
799 |
-
// Auth status endpoint
|
800 |
app.get('/api/auth/status', authenticateToken, async (req, res) => {
|
801 |
try {
|
|
|
|
|
|
|
|
|
|
|
802 |
const result = await pool.query(
|
803 |
'SELECT id, username, email FROM users WHERE id = $1',
|
804 |
[req.user.id]
|
805 |
);
|
806 |
-
|
807 |
if (result.rows.length === 0) {
|
808 |
return res.status(401).json({ error: 'User not found' });
|
809 |
}
|
810 |
-
|
811 |
res.json({ user: result.rows[0] });
|
812 |
} catch (error) {
|
813 |
console.error('Auth status error:', error);
|
@@ -817,21 +841,27 @@ app.get('/api/auth/status', authenticateToken, async (req, res) => {
|
|
817 |
|
818 |
// Admin endpoints (no authentication required for admin functions)
|
819 |
|
820 |
-
// Get image statistics
|
821 |
app.get('/api/admin/stats', async (req, res) => {
|
822 |
try {
|
|
|
|
|
|
|
|
|
|
|
823 |
const totalImages = await pool.query('SELECT COUNT(*) as count FROM images');
|
824 |
const uniqueUsers = await pool.query('SELECT COUNT(DISTINCT user_id) as count FROM images');
|
825 |
const last24Hours = await pool.query(`
|
826 |
SELECT COUNT(*) as count FROM images
|
827 |
WHERE created_at >= NOW() - INTERVAL '24 hours'
|
828 |
`);
|
829 |
-
|
830 |
-
res.json({
|
831 |
totalImages: parseInt(totalImages.rows[0].count),
|
832 |
uniqueUsers: parseInt(uniqueUsers.rows[0].count),
|
833 |
last24Hours: parseInt(last24Hours.rows[0].count)
|
834 |
-
}
|
|
|
|
|
835 |
} catch (error) {
|
836 |
console.error('Error getting admin stats:', error);
|
837 |
res.status(500).json({ error: 'Error getting statistics' });
|
|
|
9 |
import FormData from 'form-data';
|
10 |
import pg from 'pg';
|
11 |
import fetch from 'node-fetch';
|
12 |
+
import NodeCache from 'node-cache';
|
13 |
|
14 |
dotenv.config();
|
15 |
|
|
|
100 |
}
|
101 |
});
|
102 |
|
103 |
+
// Initialize cache (default TTL: 60 seconds)
|
104 |
+
const cache = new NodeCache({ stdTTL: 60, checkperiod: 120 });
|
105 |
+
|
106 |
// Create tables if they don't exist
|
107 |
const initializeDatabase = async () => {
|
108 |
try {
|
|
|
136 |
`);
|
137 |
// Add censored column if it doesn't exist
|
138 |
await pool.query(`ALTER TABLE images ADD COLUMN IF NOT EXISTS censored BOOLEAN DEFAULT false;`);
|
139 |
+
// Add indexes for performance
|
140 |
+
await pool.query(`CREATE INDEX IF NOT EXISTS idx_images_user_id ON images(user_id);`);
|
141 |
+
await pool.query(`CREATE INDEX IF NOT EXISTS idx_images_created_at ON images(created_at);`);
|
142 |
+
await pool.query(`CREATE INDEX IF NOT EXISTS idx_user_generations_user_id ON user_generations(user_id);`);
|
143 |
+
await pool.query(`CREATE INDEX IF NOT EXISTS idx_user_generations_created_at ON user_generations(created_at);`);
|
144 |
console.log('Database initialized successfully');
|
145 |
} catch (error) {
|
146 |
console.error('Error initializing database:', error);
|
|
|
331 |
}
|
332 |
});
|
333 |
|
334 |
+
// Community images with cache and pagination
|
335 |
app.get('/api/community-images', async (req, res) => {
|
336 |
try {
|
337 |
+
const page = parseInt(req.query.page) || 1;
|
338 |
+
const limit = parseInt(req.query.limit) || 50;
|
339 |
+
const offset = (page - 1) * limit;
|
340 |
+
const cacheKey = `community-images:${page}:${limit}`;
|
341 |
+
const cached = cache.get(cacheKey);
|
342 |
+
if (cached) {
|
343 |
+
return res.json(cached);
|
344 |
+
}
|
345 |
const result = await pool.query(`
|
346 |
SELECT i.id, i.image_url, i.uploaded_url, i.prompt, i.created_at, i.censored, u.username
|
347 |
FROM images i
|
348 |
JOIN users u ON i.user_id = u.id
|
349 |
ORDER BY i.created_at DESC
|
350 |
+
LIMIT $1 OFFSET $2
|
351 |
+
`, [limit, offset]);
|
352 |
+
cache.set(cacheKey, result.rows);
|
353 |
res.json(result.rows);
|
354 |
} catch (error) {
|
355 |
console.error('Error fetching community images:', error);
|
|
|
816 |
}
|
817 |
});
|
818 |
|
819 |
+
// Auth status endpoint with cache
|
820 |
app.get('/api/auth/status', authenticateToken, async (req, res) => {
|
821 |
try {
|
822 |
+
const cacheKey = `auth-status:${req.user.id}`;
|
823 |
+
const cached = cache.get(cacheKey);
|
824 |
+
if (cached) {
|
825 |
+
return res.json({ user: cached });
|
826 |
+
}
|
827 |
const result = await pool.query(
|
828 |
'SELECT id, username, email FROM users WHERE id = $1',
|
829 |
[req.user.id]
|
830 |
);
|
|
|
831 |
if (result.rows.length === 0) {
|
832 |
return res.status(401).json({ error: 'User not found' });
|
833 |
}
|
834 |
+
cache.set(cacheKey, result.rows[0]);
|
835 |
res.json({ user: result.rows[0] });
|
836 |
} catch (error) {
|
837 |
console.error('Auth status error:', error);
|
|
|
841 |
|
842 |
// Admin endpoints (no authentication required for admin functions)
|
843 |
|
844 |
+
// Get image statistics with cache
|
845 |
app.get('/api/admin/stats', async (req, res) => {
|
846 |
try {
|
847 |
+
const cacheKey = 'admin-stats';
|
848 |
+
const cached = cache.get(cacheKey);
|
849 |
+
if (cached) {
|
850 |
+
return res.json(cached);
|
851 |
+
}
|
852 |
const totalImages = await pool.query('SELECT COUNT(*) as count FROM images');
|
853 |
const uniqueUsers = await pool.query('SELECT COUNT(DISTINCT user_id) as count FROM images');
|
854 |
const last24Hours = await pool.query(`
|
855 |
SELECT COUNT(*) as count FROM images
|
856 |
WHERE created_at >= NOW() - INTERVAL '24 hours'
|
857 |
`);
|
858 |
+
const stats = {
|
|
|
859 |
totalImages: parseInt(totalImages.rows[0].count),
|
860 |
uniqueUsers: parseInt(uniqueUsers.rows[0].count),
|
861 |
last24Hours: parseInt(last24Hours.rows[0].count)
|
862 |
+
};
|
863 |
+
cache.set(cacheKey, stats);
|
864 |
+
res.json(stats);
|
865 |
} catch (error) {
|
866 |
console.error('Error getting admin stats:', error);
|
867 |
res.status(500).json({ error: 'Error getting statistics' });
|