121 lines
No EOL
3.6 KiB
JavaScript
121 lines
No EOL
3.6 KiB
JavaScript
const { Pool } = require('pg');
|
|
const jwt = require('jsonwebtoken');
|
|
|
|
const pool = new Pool({
|
|
connectionString: process.env.DATABASE_URL,
|
|
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
|
|
});
|
|
|
|
// Middleware to verify user authentication
|
|
function verifyAuth(req) {
|
|
const authHeader = req.headers.authorization;
|
|
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
throw new Error('No token provided');
|
|
}
|
|
|
|
const token = authHeader.substring(7);
|
|
const jwtSecret = process.env.JWT_SECRET || 'fallback-secret-change-in-production';
|
|
|
|
try {
|
|
const decoded = jwt.verify(token, jwtSecret);
|
|
return decoded;
|
|
} catch (error) {
|
|
throw new Error('Invalid token');
|
|
}
|
|
}
|
|
|
|
export default async function handler(req, res) {
|
|
const client = await pool.connect();
|
|
|
|
try {
|
|
// Verify authentication
|
|
const user = verifyAuth(req);
|
|
|
|
if (req.method === 'GET') {
|
|
// Get user's collections
|
|
const collectionsQuery = `
|
|
SELECT
|
|
uc.id, uc.name, uc.description, uc.is_public, uc.created_at, uc.updated_at,
|
|
COUNT(cc.id) as total_cards,
|
|
COALESCE(SUM(cc.quantity * COALESCE(c.current_price, 0)), 0) as total_value
|
|
FROM user_collections uc
|
|
LEFT JOIN collection_cards cc ON uc.id = cc.collection_id
|
|
LEFT JOIN cards c ON cc.card_id = c.id
|
|
WHERE uc.user_id = $1
|
|
GROUP BY uc.id, uc.name, uc.description, uc.is_public, uc.created_at, uc.updated_at
|
|
ORDER BY uc.created_at DESC
|
|
`;
|
|
|
|
const collections = await client.query(collectionsQuery, [user.userId]);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
collections: collections.rows.map(collection => ({
|
|
id: collection.id,
|
|
name: collection.name,
|
|
description: collection.description,
|
|
isPublic: collection.is_public,
|
|
totalCards: parseInt(collection.total_cards) || 0,
|
|
totalValue: parseFloat(collection.total_value) || 0,
|
|
createdAt: collection.created_at,
|
|
updatedAt: collection.updated_at
|
|
}))
|
|
});
|
|
|
|
} else if (req.method === 'POST') {
|
|
// Create new collection
|
|
const { name, description, isPublic = false } = req.body;
|
|
|
|
if (!name || name.trim().length === 0) {
|
|
return res.status(400).json({ error: 'Collection name is required' });
|
|
}
|
|
|
|
const insertQuery = `
|
|
INSERT INTO user_collections (user_id, name, description, is_public)
|
|
VALUES ($1, $2, $3, $4)
|
|
RETURNING id, name, description, is_public, created_at, updated_at
|
|
`;
|
|
|
|
const result = await client.query(insertQuery, [
|
|
user.userId,
|
|
name.trim(),
|
|
description?.trim() || null,
|
|
isPublic
|
|
]);
|
|
|
|
const newCollection = result.rows[0];
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
message: 'Collection created successfully',
|
|
collection: {
|
|
id: newCollection.id,
|
|
name: newCollection.name,
|
|
description: newCollection.description,
|
|
isPublic: newCollection.is_public,
|
|
totalCards: 0,
|
|
totalValue: 0,
|
|
createdAt: newCollection.created_at,
|
|
updatedAt: newCollection.updated_at
|
|
}
|
|
});
|
|
|
|
} else {
|
|
res.status(405).json({ error: 'Method not allowed' });
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Collections API error:', error);
|
|
|
|
if (error.message === 'No token provided' || error.message === 'Invalid token') {
|
|
res.status(401).json({ error: error.message });
|
|
} else {
|
|
res.status(500).json({
|
|
error: 'Internal server error',
|
|
details: error.message
|
|
});
|
|
}
|
|
} finally {
|
|
client.release();
|
|
}
|
|
}
|