first commit
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
import { Router } from 'express';
|
||||
import { prisma } from '../db.js';
|
||||
import { requireAuth, publicUser } from '../middleware.js';
|
||||
import { normalizeRates, pickWeighted } from '../weighted.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
function formatCase(c, includeRates = false) {
|
||||
const items = (c.items || []).map((ci) => ({
|
||||
id: ci.item.id,
|
||||
name: ci.item.name,
|
||||
imageUrl: ci.item.imageUrl,
|
||||
rarity: ci.item.rarity,
|
||||
marketValue: ci.item.marketValue,
|
||||
dropRate: ci.dropRate,
|
||||
...(includeRates ? {} : {}),
|
||||
}));
|
||||
|
||||
const withChance = normalizeRates(
|
||||
items.map((i) => ({ ...i, dropRate: i.dropRate }))
|
||||
);
|
||||
|
||||
return {
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
imageUrl: c.imageUrl,
|
||||
price: c.price,
|
||||
active: c.active,
|
||||
items: withChance.map(({ dropRate, chance, ...rest }) => ({
|
||||
...rest,
|
||||
dropRate,
|
||||
chance: Number(chance.toFixed(4)),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
router.get('/', async (_req, res) => {
|
||||
try {
|
||||
const cases = await prisma.case.findMany({
|
||||
where: { active: true },
|
||||
include: {
|
||||
items: { include: { item: true } },
|
||||
},
|
||||
orderBy: { price: 'asc' },
|
||||
});
|
||||
res.json({ cases: cases.map((c) => formatCase(c)) });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Failed to load cases' });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:id', async (req, res) => {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
const c = await prisma.case.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
items: { include: { item: true } },
|
||||
},
|
||||
});
|
||||
if (!c || !c.active) {
|
||||
return res.status(404).json({ error: 'Case not found' });
|
||||
}
|
||||
res.json({ case: formatCase(c, true) });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Failed to load case' });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/:id/open', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const caseId = Number(req.params.id);
|
||||
const userId = req.session.userId;
|
||||
|
||||
const result = await prisma.$transaction(async (tx) => {
|
||||
const c = await tx.case.findUnique({
|
||||
where: { id: caseId },
|
||||
include: {
|
||||
items: { include: { item: true } },
|
||||
},
|
||||
});
|
||||
|
||||
if (!c || !c.active) {
|
||||
const err = new Error('Case not found');
|
||||
err.status = 404;
|
||||
throw err;
|
||||
}
|
||||
if (!c.items.length) {
|
||||
const err = new Error('Case has no items');
|
||||
err.status = 400;
|
||||
throw err;
|
||||
}
|
||||
|
||||
const user = await tx.user.findUnique({ where: { id: userId } });
|
||||
if (!user) {
|
||||
const err = new Error('User not found');
|
||||
err.status = 401;
|
||||
throw err;
|
||||
}
|
||||
if (user.balance < c.price) {
|
||||
const err = new Error('Insufficient balance');
|
||||
err.status = 400;
|
||||
throw err;
|
||||
}
|
||||
|
||||
const winner = pickWeighted(
|
||||
c.items.map((ci) => ({
|
||||
caseItem: ci,
|
||||
dropRate: ci.dropRate,
|
||||
}))
|
||||
);
|
||||
|
||||
const item = winner.caseItem.item;
|
||||
|
||||
const updatedUser = await tx.user.update({
|
||||
where: { id: userId },
|
||||
data: { balance: { decrement: c.price } },
|
||||
});
|
||||
|
||||
const inventoryItem = await tx.inventoryItem.create({
|
||||
data: {
|
||||
userId,
|
||||
itemId: item.id,
|
||||
},
|
||||
include: { item: true },
|
||||
});
|
||||
|
||||
await tx.transaction.create({
|
||||
data: {
|
||||
userId,
|
||||
type: 'open_case',
|
||||
amount: -c.price,
|
||||
meta: JSON.stringify({
|
||||
caseId: c.id,
|
||||
caseName: c.name,
|
||||
itemId: item.id,
|
||||
itemName: item.name,
|
||||
inventoryItemId: inventoryItem.id,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
user: publicUser(updatedUser),
|
||||
item: {
|
||||
inventoryId: inventoryItem.id,
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
imageUrl: item.imageUrl,
|
||||
rarity: item.rarity,
|
||||
marketValue: item.marketValue,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
res.json(result);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
const status = err.status || 500;
|
||||
res.status(status).json({ error: err.message || 'Failed to open case' });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user