deckhearth/api/collections/index.js

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();
}
}