174 lines
No EOL
4.8 KiB
JavaScript
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();
|
|
}
|
|
}
|