dok/routes/carddeck.js
2026-04-04 11:07:20 +01:00

329 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require("express");
const router = express.Router();
const db = require("../database/database");
/* ========================
Auth Middleware
======================== */
function requireLogin(req, res, next) {
if (!req.session.user) return res.status(401).json({ error: "Nicht eingeloggt" });
next();
}
router.use(requireLogin);
/* ════════════════════════════════════════════
GET /api/card-groups
Alle Kartengruppen
════════════════════════════════════════════ */
router.get("/card-groups", async (req, res) => {
try {
const [groups] = await db.query("SELECT * FROM card_groups ORDER BY id");
res.json(groups);
} catch (err) {
console.error(err);
res.status(500).json({ error: "DB Fehler" });
}
});
/* ════════════════════════════════════════════
GET /api/cards?group_id=X&page=Y&limit=Z
Alle Karten (Admin-/Gruppen-Ansicht, kein Besitz)
════════════════════════════════════════════ */
router.get("/cards", async (req, res) => {
const { group_id, page = 1, limit = 12 } = req.query;
const offset = (page - 1) * limit;
try {
const [cards] = await db.query(
`SELECT c.*, cg.name AS group_name, cg.color AS group_color,
c.attack, c.defends, c.cooldown
FROM cards c
LEFT JOIN card_groups cg ON cg.id = c.group_id
WHERE c.group_id = ?
LIMIT ? OFFSET ?`,
[group_id, parseInt(limit), parseInt(offset)]
);
const [[{ total }]] = await db.query(
"SELECT COUNT(*) AS total FROM cards WHERE group_id = ?",
[group_id]
);
res.json({ cards, total, page: parseInt(page), totalPages: Math.ceil(total / limit) });
} catch (err) {
console.error(err);
res.status(500).json({ error: "DB Fehler" });
}
});
/* ════════════════════════════════════════════
GET /api/user-cards?group_id=X&page=Y&limit=Z
Karten die der Spieler besitzt (mit amount)
════════════════════════════════════════════ */
router.get("/user-cards", async (req, res) => {
const userId = req.session.user.id;
const { group_id, page = 1, limit = 18 } = req.query;
const offset = (page - 1) * limit;
try {
const [cards] = await db.query(
`SELECT
uc.card_id,
uc.amount,
c.name,
c.image,
c.rarity,
cg.name AS group_name,
cg.color AS group_color,
c.attack,
c.defends,
c.cooldown
FROM user_cards uc
JOIN cards c ON c.id = uc.card_id
JOIN card_groups cg ON cg.id = c.group_id
WHERE uc.user_id = ? AND c.group_id = ?
ORDER BY c.id
LIMIT ? OFFSET ?`,
[userId, group_id, parseInt(limit), parseInt(offset)]
);
const [[{ total }]] = await db.query(
`SELECT COUNT(*) AS total
FROM user_cards uc
JOIN cards c ON c.id = uc.card_id
WHERE uc.user_id = ? AND c.group_id = ?`,
[userId, group_id]
);
res.json({ cards, total, page: parseInt(page), totalPages: Math.ceil(total / limit) });
} catch (err) {
console.error(err);
res.status(500).json({ error: "DB Fehler" });
}
});
/* ════════════════════════════════════════════
GET /api/decks
Alle Decks des Spielers
════════════════════════════════════════════ */
router.get("/decks", async (req, res) => {
const userId = req.session.user.id;
try {
const [decks] = await db.query(
`SELECT d.id, d.name,
COALESCE(SUM(dc.amount), 0) AS card_count
FROM decks d
LEFT JOIN deck_cards dc ON dc.deck_id = d.id
WHERE d.user_id = ?
GROUP BY d.id
ORDER BY d.created_at`,
[userId]
);
res.json(decks);
} catch (err) {
console.error(err);
res.status(500).json({ error: "DB Fehler" });
}
});
/* ════════════════════════════════════════════
POST /api/decks { name }
Neues Deck erstellen (max. 10 pro Spieler)
════════════════════════════════════════════ */
router.post("/decks", async (req, res) => {
const userId = req.session.user.id;
const { name } = req.body;
if (!name || !name.trim()) {
return res.status(400).json({ error: "Name darf nicht leer sein." });
}
try {
const [[{ count }]] = await db.query(
"SELECT COUNT(*) AS count FROM decks WHERE user_id = ?",
[userId]
);
if (count >= 10) {
return res.status(400).json({ error: "Maximale Anzahl von 10 Decks erreicht." });
}
const [result] = await db.query(
"INSERT INTO decks (user_id, name) VALUES (?, ?)",
[userId, name.trim()]
);
res.status(201).json({ id: result.insertId, name: name.trim(), card_count: 0 });
} catch (err) {
console.error(err);
res.status(500).json({ error: "DB Fehler" });
}
});
/* ════════════════════════════════════════════
GET /api/decks/:id/cards
Karten eines bestimmten Decks
════════════════════════════════════════════ */
router.get("/decks/:id/cards", async (req, res) => {
const userId = req.session.user.id;
const deckId = req.params.id;
try {
// Deck gehört dem Spieler?
const [[deck]] = await db.query(
"SELECT id FROM decks WHERE id = ? AND user_id = ?",
[deckId, userId]
);
if (!deck) return res.status(404).json({ error: "Deck nicht gefunden." });
const [cards] = await db.query(
`SELECT
dc.card_id,
dc.amount,
c.name,
c.image,
c.rarity,
c.attack,
c.defends,
c.cooldown
FROM deck_cards dc
JOIN cards c ON c.id = dc.card_id
WHERE dc.deck_id = ?
ORDER BY c.name`,
[deckId]
);
res.json(cards);
} catch (err) {
console.error(err);
res.status(500).json({ error: "DB Fehler" });
}
});
/* ════════════════════════════════════════════
POST /api/decks/:id/cards { card_id, level }
Karte zum Deck hinzufügen
════════════════════════════════════════════ */
router.post("/decks/:id/cards", async (req, res) => {
const userId = req.session.user.id;
const deckId = req.params.id;
const { card_id } = req.body;
if (!card_id) return res.status(400).json({ error: "card_id fehlt." });
try {
// Deck gehört dem Spieler?
const [[deck]] = await db.query(
"SELECT id FROM decks WHERE id = ? AND user_id = ?",
[deckId, userId]
);
if (!deck) return res.status(404).json({ error: "Deck nicht gefunden." });
// Besitzt der Spieler diese Karte?
const [[owned]] = await db.query(
"SELECT amount FROM user_cards WHERE user_id = ? AND card_id = ?",
[userId, card_id]
);
if (!owned) return res.status(400).json({ error: "Du besitzt diese Karte nicht." });
// Deck-Gesamtzahl prüfen (max 30)
const [[{ total }]] = await db.query(
"SELECT COALESCE(SUM(amount), 0) AS total FROM deck_cards WHERE deck_id = ?",
[deckId]
);
if (total >= 30) {
return res.status(400).json({ error: "Deck ist voll (max. 30 Karten)." });
}
// Rarity > 5: max. 1× im Deck
const [[cardInfo]] = await db.query(
"SELECT rarity FROM cards WHERE id = ?",
[card_id]
);
const [[existing]] = await db.query(
"SELECT amount FROM deck_cards WHERE deck_id = ? AND card_id = ?",
[deckId, card_id]
);
if (parseInt(cardInfo?.rarity) > 5 && existing) {
return res.status(400).json({ error: "Karten ab Rarity 6 dürfen nur einmal im Deck sein." });
}
// Nicht mehr einfügen als besessen
const currentInDeck = existing ? existing.amount : 0;
if (currentInDeck >= owned.amount) {
return res.status(400).json({ error: "Du hast keine weiteren Exemplare dieser Karte." });
}
// Einfügen oder erhöhen
if (existing) {
await db.query(
"UPDATE deck_cards SET amount = amount + 1 WHERE deck_id = ? AND card_id = ?",
[deckId, card_id]
);
} else {
await db.query(
"INSERT INTO deck_cards (deck_id, card_id, amount) VALUES (?, ?, 1)",
[deckId, card_id]
);
}
res.json({ success: true });
} catch (err) {
// DB-Trigger Fehler (45000) sauber weitergeben
if (err.sqlState === "45000") {
return res.status(400).json({ error: err.message });
}
console.error(err);
res.status(500).json({ error: "DB Fehler" });
}
});
/* ════════════════════════════════════════════
DELETE /api/decks/:id/cards { card_id, level }
Karte aus Deck entfernen (amount - 1, bei 0 löschen)
════════════════════════════════════════════ */
router.delete("/decks/:id/cards", async (req, res) => {
const userId = req.session.user.id;
const deckId = req.params.id;
const { card_id } = req.body;
if (!card_id) return res.status(400).json({ error: "card_id fehlt." });
try {
// Deck gehört dem Spieler?
const [[deck]] = await db.query(
"SELECT id FROM decks WHERE id = ? AND user_id = ?",
[deckId, userId]
);
if (!deck) return res.status(404).json({ error: "Deck nicht gefunden." });
const [[entry]] = await db.query(
"SELECT id, amount FROM deck_cards WHERE deck_id = ? AND card_id = ?",
[deckId, card_id]
);
if (!entry) return res.status(404).json({ error: "Karte nicht im Deck." });
if (entry.amount > 1) {
await db.query(
"UPDATE deck_cards SET amount = amount - 1 WHERE id = ?",
[entry.id]
);
} else {
await db.query("DELETE FROM deck_cards WHERE id = ?", [entry.id]);
}
res.json({ success: true });
} catch (err) {
console.error(err);
res.status(500).json({ error: "DB Fehler" });
}
});
module.exports = router;