deckhearth/api/collections/add-card.js

174 lines
No EOL
4.8 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) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const client = await pool.connect();
try {
// Verify authentication
const user = verifyAuth(req);
const {
collectionId,
cardId,
quantity = 1,
condition = 'near-mint',
notes = null,
purchasePrice = null
} = req.body;
// Validate required fields
if (!collectionId || !cardId) {
return res.status(400).json({
error: 'Collection ID and Card ID are required'
});
}
// Verify collection ownership
const collectionCheck = await client.query(
'SELECT id, name FROM user_collections WHERE id = $1 AND user_id = $2',
[collectionId, user.userId]
);
if (collectionCheck.rows.length === 0) {
return res.status(404).json({
error: 'Collection not found or access denied'
});
}
// Verify card exists
const cardCheck = await client.query(
'SELECT id, name, game, rarity, current_price FROM cards WHERE id = $1',
[cardId]
);
if (cardCheck.rows.length === 0) {
return res.status(404).json({
error: 'Card not found'
});
}
const card = cardCheck.rows[0];
const collection = collectionCheck.rows[0];
// Check if card already exists in collection with same condition
const existingCard = await client.query(`
SELECT id, quantity
FROM collection_cards
WHERE collection_id = $1 AND card_id = $2 AND condition = $3
`, [collectionId, cardId, condition]);
let result;
if (existingCard.rows.length > 0) {
// Update existing entry - increase quantity
const newQuantity = existingCard.rows[0].quantity + quantity;
await client.query(`
UPDATE collection_cards
SET quantity = $1, updated_at = CURRENT_TIMESTAMP
WHERE id = $2
`, [newQuantity, existingCard.rows[0].id]);
result = {
action: 'updated',
previousQuantity: existingCard.rows[0].quantity,
newQuantity: newQuantity
};
} else {
// Create new collection card entry
const insertResult = await client.query(`
INSERT INTO collection_cards (
collection_id, card_id, quantity, condition, notes, purchase_price
) VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, added_at
`, [collectionId, cardId, quantity, condition, notes, purchasePrice]);
result = {
action: 'added',
collectionCardId: insertResult.rows[0].id,
addedAt: insertResult.rows[0].added_at
};
}
// Get updated collection stats
const statsQuery = await client.query(`
SELECT
COUNT(cc.id) as total_entries,
COALESCE(SUM(cc.quantity), 0) as total_cards,
COALESCE(SUM(cc.quantity * COALESCE(c.current_price, 0)), 0) as total_value
FROM collection_cards cc
LEFT JOIN cards c ON cc.card_id = c.id
WHERE cc.collection_id = $1
`, [collectionId]);
const stats = statsQuery.rows[0];
res.status(200).json({
success: true,
message: `Card ${result.action} successfully`,
result: {
...result,
card: {
id: card.id,
name: card.name,
game: card.game,
rarity: card.rarity,
currentPrice: card.current_price
},
collection: {
id: collection.id,
name: collection.name
},
quantity: quantity,
condition: condition,
collectionStats: {
totalEntries: parseInt(stats.total_entries),
totalCards: parseInt(stats.total_cards),
totalValue: parseFloat(stats.total_value)
}
}
});
} catch (error) {
console.error('Add card to collection 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();
}
}