feat: add player handler with all endpoints
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
import { route, HandlerContext, HttpError } from '@/lib/router';
|
||||
import { getDb } from '@/lib/db';
|
||||
|
||||
// POST /player — Create player profile
|
||||
route('player', ['POST'], (ctx: HandlerContext) => {
|
||||
const { steam_id, player_name } = ctx.body as any;
|
||||
if (!steam_id) throw new HttpError(400, 'steam_id is required');
|
||||
const db = getDb();
|
||||
const existing = db.prepare('SELECT * FROM players WHERE steam_id = ?').get(steam_id) as any;
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
db.prepare('INSERT INTO players (steam_id, player_name) VALUES (?, ?)').run(steam_id, player_name || '');
|
||||
try {
|
||||
db.prepare('INSERT OR IGNORE INTO battle_passes (steam_id) VALUES (?)').run(steam_id);
|
||||
} catch {}
|
||||
const player = db.prepare('SELECT * FROM players WHERE steam_id = ?').get(steam_id);
|
||||
return player;
|
||||
});
|
||||
|
||||
// GET /player/:steamId — Get player profile
|
||||
// Returns the player row plus recentGames array and stats object
|
||||
route('player/:steamId', ['GET'], (ctx: HandlerContext) => {
|
||||
const db = getDb();
|
||||
const player = db.prepare('SELECT * FROM players WHERE steam_id = ?').get(ctx.params.steamId) as any;
|
||||
if (!player) throw new HttpError(404, 'Player not found');
|
||||
return {
|
||||
...player,
|
||||
recentGames: [],
|
||||
stats: {
|
||||
total_games: 0,
|
||||
total_wins: 0,
|
||||
rating: 0,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// GET /player/:steamId/history — Match history with limit/offset
|
||||
route('player/:steamId/history', ['GET'], (ctx: HandlerContext) => {
|
||||
const limit = parseInt(ctx.searchParams.get('limit') || '10');
|
||||
const offset = parseInt(ctx.searchParams.get('offset') || '0');
|
||||
const db = getDb();
|
||||
const games = db.prepare(
|
||||
'SELECT * FROM game_history WHERE steam_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?'
|
||||
).all(ctx.params.steamId, limit, offset);
|
||||
return games;
|
||||
});
|
||||
|
||||
// GET /player/:steamId/currency — Get currency balances
|
||||
route('player/:steamId/currency', ['GET'], (ctx: HandlerContext) => {
|
||||
const db = getDb();
|
||||
const player = db.prepare('SELECT free_currency, donate_currency, dust_currency FROM players WHERE steam_id = ?').get(ctx.params.steamId) as any;
|
||||
if (!player) throw new HttpError(404, 'Player not found');
|
||||
return player;
|
||||
});
|
||||
|
||||
// PUT /player/:steamId/currency — Save currency balances
|
||||
route('player/:steamId/currency', ['PUT'], (ctx: HandlerContext) => {
|
||||
const { free_currency, donate_currency, dust_currency } = ctx.body as any;
|
||||
const db = getDb();
|
||||
const player = db.prepare('SELECT * FROM players WHERE steam_id = ?').get(ctx.params.steamId) as any;
|
||||
if (!player) throw new HttpError(404, 'Player not found');
|
||||
db.prepare(`
|
||||
UPDATE players SET free_currency = ?, donate_currency = ?, dust_currency = ?, updated_at = datetime('now')
|
||||
WHERE steam_id = ?
|
||||
`).run(
|
||||
free_currency ?? player.free_currency,
|
||||
donate_currency ?? player.donate_currency,
|
||||
dust_currency ?? player.dust_currency,
|
||||
ctx.params.steamId
|
||||
);
|
||||
return { success: true };
|
||||
});
|
||||
|
||||
// POST /player/:steamId/currency/give — Grant currency (used by BP rewards)
|
||||
route('player/:steamId/currency/give', ['POST'], (ctx: HandlerContext) => {
|
||||
const body = ctx.body as any;
|
||||
const free_amount = body.free_amount ?? body.freeAmount ?? 0;
|
||||
const donate_amount = body.donate_amount ?? body.donateAmount ?? 0;
|
||||
const dust_amount = body.dust_amount ?? body.dustAmount ?? 0;
|
||||
const db = getDb();
|
||||
const player = db.prepare('SELECT * FROM players WHERE steam_id = ?').get(ctx.params.steamId) as any;
|
||||
if (!player) throw new HttpError(404, 'Player not found');
|
||||
db.prepare(`
|
||||
UPDATE players SET free_currency = free_currency + ?, donate_currency = donate_currency + ?,
|
||||
dust_currency = dust_currency + ?, updated_at = datetime('now') WHERE steam_id = ?
|
||||
`).run(
|
||||
free_amount,
|
||||
donate_amount,
|
||||
dust_amount,
|
||||
ctx.params.steamId
|
||||
);
|
||||
return { success: true };
|
||||
});
|
||||
|
||||
// POST /player/:steamId/purchases — Record a store purchase
|
||||
route('player/:steamId/purchases', ['POST'], (ctx: HandlerContext) => {
|
||||
const { item_id, item_category, card_id, price_free, price_donate, price_dust } = ctx.body as any;
|
||||
const db = getDb();
|
||||
db.prepare(`
|
||||
INSERT INTO purchases (steam_id, item_id, item_category, card_id, price_free, price_donate, price_dust)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(ctx.params.steamId, item_id, item_category || 'items', card_id || null, price_free || 0, price_donate || 0, price_dust || 0);
|
||||
return { success: true };
|
||||
});
|
||||
|
||||
// POST /player/:steamId/promo/redeem — Redeem a promo code
|
||||
route('player/:steamId/promo/redeem', ['POST'], (ctx: HandlerContext) => {
|
||||
const { code } = ctx.body as any;
|
||||
if (!code) throw new HttpError(400, 'Code is required');
|
||||
const normalizedCode = String(code).toUpperCase();
|
||||
const db = getDb();
|
||||
const promo = db.prepare('SELECT * FROM promo_codes WHERE code = ?').get(normalizedCode) as any;
|
||||
if (!promo) throw new HttpError(404, 'Promo code not found');
|
||||
if (promo.expires_at && new Date(promo.expires_at) < new Date()) throw new HttpError(400, 'Code expired');
|
||||
if (promo.current_uses >= promo.max_uses) throw new HttpError(400, 'Code fully redeemed');
|
||||
|
||||
const existing = db.prepare('SELECT * FROM promo_redemptions WHERE steam_id = ? AND code = ?').get(ctx.params.steamId, normalizedCode);
|
||||
if (existing) throw new HttpError(400, 'Code already redeemed');
|
||||
|
||||
db.prepare(`
|
||||
UPDATE players SET free_currency = free_currency + ?, donate_currency = donate_currency + ?,
|
||||
dust_currency = dust_currency + ?, updated_at = datetime('now') WHERE steam_id = ?
|
||||
`).run(promo.free_currency, promo.donate_currency, promo.dust_currency, ctx.params.steamId);
|
||||
|
||||
db.prepare('UPDATE promo_codes SET current_uses = current_uses + 1 WHERE code = ?').run(normalizedCode);
|
||||
db.prepare('INSERT INTO promo_redemptions (steam_id, code) VALUES (?, ?)').run(ctx.params.steamId, normalizedCode);
|
||||
|
||||
const player = db.prepare('SELECT free_currency, donate_currency, dust_currency FROM players WHERE steam_id = ?').get(ctx.params.steamId);
|
||||
return { success: true, rewards: { free_currency: promo.free_currency, donate_currency: promo.donate_currency, dust_currency: promo.dust_currency }, currency: player };
|
||||
});
|
||||
|
||||
// GET /player/:steamId/sounds_wheel — Get sounds wheel
|
||||
route('player/:steamId/sounds_wheel', ['GET'], (ctx: HandlerContext) => {
|
||||
const db = getDb();
|
||||
const player = db.prepare('SELECT sounds_wheel FROM players WHERE steam_id = ?').get(ctx.params.steamId) as any;
|
||||
if (!player) throw new HttpError(404, 'Player not found');
|
||||
return { sounds_wheel: JSON.parse(player.sounds_wheel || '{}') };
|
||||
});
|
||||
|
||||
// PUT /player/:steamId/sounds_wheel — Save sounds wheel
|
||||
route('player/:steamId/sounds_wheel', ['PUT'], (ctx: HandlerContext) => {
|
||||
const { sounds_wheel } = ctx.body as any;
|
||||
const db = getDb();
|
||||
db.prepare("UPDATE players SET sounds_wheel = ?, updated_at = datetime('now') WHERE steam_id = ?")
|
||||
.run(JSON.stringify(sounds_wheel || {}), ctx.params.steamId);
|
||||
return { success: true };
|
||||
});
|
||||
|
||||
// POST /player/:steamId/deal-purchase — Buy a deal/offer
|
||||
route('player/:steamId/deal-purchase', ['POST'], (ctx: HandlerContext) => {
|
||||
const { deal_key } = ctx.body as any;
|
||||
return { success: true, ok: true, item_id: 'deal_' + deal_key, item_category: 'items' };
|
||||
});
|
||||
|
||||
// GET /player/:steamId/active_effects — Get active cosmetic effects
|
||||
route('player/:steamId/active_effects', ['GET'], (ctx: HandlerContext) => {
|
||||
const db = getDb();
|
||||
const row = db.prepare('SELECT effects FROM active_effects WHERE steam_id = ?').get(ctx.params.steamId) as any;
|
||||
return { active_effects: row ? JSON.parse(row.effects) : {} };
|
||||
});
|
||||
|
||||
// PUT /player/:steamId/active_effects — Save active effects
|
||||
route('player/:steamId/active_effects', ['PUT'], (ctx: HandlerContext) => {
|
||||
const { active_effects } = ctx.body as any;
|
||||
const db = getDb();
|
||||
db.prepare(`
|
||||
INSERT INTO active_effects (steam_id, effects, updated_at) VALUES (?, ?, datetime('now'))
|
||||
ON CONFLICT(steam_id) DO UPDATE SET effects = ?, updated_at = datetime('now')
|
||||
`).run(ctx.params.steamId, JSON.stringify(active_effects || {}), JSON.stringify(active_effects || {}));
|
||||
return { success: true };
|
||||
});
|
||||
Reference in New Issue
Block a user