Initial commit
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
const express = require('express');
|
||||
const { body } = require('express-validator');
|
||||
const Games = require('../models/games');
|
||||
const { pool } = require('../models/db');
|
||||
const { authenticate } = require('../middleware/auth');
|
||||
const validate = require('../middleware/validate');
|
||||
const { generateGame, regenerateGame } = require('../utils/claude');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// Create game with AI
|
||||
router.post('/create',
|
||||
authenticate,
|
||||
validate([
|
||||
body('description')
|
||||
.trim()
|
||||
.isLength({ min: 10, max: 1000 })
|
||||
.withMessage('Game description must be 10-1000 characters'),
|
||||
body('title')
|
||||
.optional()
|
||||
.trim()
|
||||
.isLength({ min: 1, max: 100 })
|
||||
]),
|
||||
async (req, res, next) => {
|
||||
try {
|
||||
const { description, title } = req.body;
|
||||
|
||||
// Check if user is a guest
|
||||
if (req.user.is_guest) {
|
||||
return res.status(403).json({
|
||||
error: 'Guests cannot create games. Please create an account first.'
|
||||
});
|
||||
}
|
||||
|
||||
// Generate game with Claude
|
||||
const result = await generateGame(description);
|
||||
|
||||
if (!result.success) {
|
||||
return res.status(500).json({ error: 'Failed to generate game. Please try again.' });
|
||||
}
|
||||
|
||||
// Create game in database
|
||||
const gameTitle = title || `Game by ${req.user.username}`;
|
||||
const game = await Games.create({
|
||||
creatorId: req.user.id,
|
||||
title: gameTitle,
|
||||
description: description,
|
||||
gameCode: result.code,
|
||||
prompt: description
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
message: 'Game created successfully',
|
||||
game: {
|
||||
id: game.id,
|
||||
title: game.title,
|
||||
description: game.description,
|
||||
status: game.status,
|
||||
createdAt: game.created_at
|
||||
},
|
||||
previewCode: result.code,
|
||||
tokensUsed: result.tokensUsed || 0
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Get game by ID
|
||||
router.get('/:gameId',
|
||||
authenticate,
|
||||
async (req, res, next) => {
|
||||
try {
|
||||
const { gameId } = req.params;
|
||||
const game = await Games.findById(gameId);
|
||||
|
||||
if (!game) {
|
||||
return res.status(404).json({ error: 'Game not found' });
|
||||
}
|
||||
|
||||
// Only show code if owner or game is published
|
||||
const isOwner = game.creator_id === req.user.id;
|
||||
const isPublished = game.status === 'published';
|
||||
|
||||
if (!isOwner && !isPublished) {
|
||||
return res.status(403).json({ error: 'Game not available' });
|
||||
}
|
||||
|
||||
// Prevent caching of game code responses
|
||||
res.set({
|
||||
'Cache-Control': 'no-store, no-cache, must-revalidate, proxy-revalidate',
|
||||
'Pragma': 'no-cache',
|
||||
'Expires': '0'
|
||||
});
|
||||
|
||||
res.json({
|
||||
game: {
|
||||
id: game.id,
|
||||
title: game.title,
|
||||
description: game.description,
|
||||
gameCode: game.game_code,
|
||||
codeVersion: game.code_version || 1,
|
||||
prompt: game.prompt,
|
||||
creationPrompt: game.creation_prompt,
|
||||
originalPrompt: game.original_prompt,
|
||||
promptWasEdited: game.prompt_was_edited || false,
|
||||
promptEditCount: game.prompt_edit_count || 0,
|
||||
promptAnswers: game.prompt_answers,
|
||||
status: game.status,
|
||||
playCount: game.play_count,
|
||||
totalRatings: game.total_ratings,
|
||||
ratingSum: game.rating_sum,
|
||||
creatorId: game.creator_id,
|
||||
creatorUsername: game.creator_username,
|
||||
creatorDisplayName: game.creator_display_name,
|
||||
createdAt: game.created_at,
|
||||
publishedAt: game.published_at,
|
||||
creatorPlayed: game.creator_played,
|
||||
creatorPlayDuration: game.creator_play_duration || 0,
|
||||
isOwner
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Update game
|
||||
router.put('/:gameId',
|
||||
authenticate,
|
||||
validate([
|
||||
body('title').optional().trim().isLength({ min: 1, max: 100 }),
|
||||
body('description').optional().trim().isLength({ min: 10, max: 1000 }),
|
||||
body('feedback').optional().trim().isLength({ min: 5, max: 1000 })
|
||||
]),
|
||||
async (req, res, next) => {
|
||||
try {
|
||||
const { gameId } = req.params;
|
||||
const { title, description, feedback } = req.body;
|
||||
|
||||
const game = await Games.findById(gameId);
|
||||
|
||||
if (!game) {
|
||||
return res.status(404).json({ error: 'Game not found' });
|
||||
}
|
||||
|
||||
if (game.creator_id !== req.user.id) {
|
||||
return res.status(403).json({ error: 'Not authorized' });
|
||||
}
|
||||
|
||||
if (game.status === 'published') {
|
||||
return res.status(400).json({ error: 'Cannot edit published games' });
|
||||
}
|
||||
|
||||
let updatedCode = game.game_code;
|
||||
let tokensUsed = 0;
|
||||
|
||||
// If feedback provided, regenerate with Claude
|
||||
if (feedback) {
|
||||
const result = await regenerateGame(game.game_code, feedback);
|
||||
if (result.success) {
|
||||
updatedCode = result.code;
|
||||
tokensUsed = result.tokensUsed || 0;
|
||||
} else {
|
||||
return res.status(500).json({ error: 'Failed to regenerate game. Please try again.' });
|
||||
}
|
||||
}
|
||||
|
||||
const updated = await Games.update(gameId, {
|
||||
title,
|
||||
description,
|
||||
gameCode: feedback ? updatedCode : undefined
|
||||
});
|
||||
|
||||
res.json({
|
||||
message: 'Game updated',
|
||||
game: {
|
||||
id: updated.id,
|
||||
title: updated.title,
|
||||
description: updated.description,
|
||||
status: updated.status,
|
||||
gameCode: updated.game_code
|
||||
},
|
||||
tokensUsed
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Submit for review
|
||||
router.post('/:gameId/submit',
|
||||
authenticate,
|
||||
async (req, res, next) => {
|
||||
try {
|
||||
const { gameId } = req.params;
|
||||
const game = await Games.findById(gameId);
|
||||
|
||||
if (!game) {
|
||||
return res.status(404).json({ error: 'Game not found' });
|
||||
}
|
||||
|
||||
if (game.creator_id !== req.user.id) {
|
||||
return res.status(403).json({ error: 'Not authorized' });
|
||||
}
|
||||
|
||||
if (game.status !== 'draft') {
|
||||
return res.status(400).json({ error: 'Game has already been submitted' });
|
||||
}
|
||||
|
||||
const updated = await Games.submit(gameId);
|
||||
|
||||
res.json({
|
||||
message: 'Game submitted for review',
|
||||
game: { id: updated.id, status: updated.status }
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Unpublish game (creator only)
|
||||
router.post('/:gameId/unpublish',
|
||||
authenticate,
|
||||
async (req, res, next) => {
|
||||
try {
|
||||
const { gameId } = req.params;
|
||||
const game = await Games.findById(gameId);
|
||||
|
||||
if (!game) {
|
||||
return res.status(404).json({ error: 'Game not found' });
|
||||
}
|
||||
|
||||
if (game.creator_id !== req.user.id) {
|
||||
return res.status(403).json({ error: 'Not authorized' });
|
||||
}
|
||||
|
||||
if (game.status !== 'published') {
|
||||
return res.status(400).json({ error: 'Game is not published' });
|
||||
}
|
||||
|
||||
// Unpublish - set status back to testing so they can re-publish
|
||||
await pool.query(
|
||||
`UPDATE games SET status = 'testing', published_at = NULL WHERE id = $1`,
|
||||
[gameId]
|
||||
);
|
||||
|
||||
res.json({
|
||||
message: 'Game unpublished. You can edit and re-publish it.',
|
||||
game: { id: parseInt(gameId), status: 'testing' }
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Delete game
|
||||
router.delete('/:gameId',
|
||||
authenticate,
|
||||
async (req, res, next) => {
|
||||
try {
|
||||
const { gameId } = req.params;
|
||||
const game = await Games.findById(gameId);
|
||||
|
||||
if (!game) {
|
||||
return res.status(404).json({ error: 'Game not found' });
|
||||
}
|
||||
|
||||
if (game.creator_id !== req.user.id && req.user.role !== 'admin') {
|
||||
return res.status(403).json({ error: 'Not authorized' });
|
||||
}
|
||||
|
||||
await Games.delete(gameId);
|
||||
|
||||
res.json({ message: 'Game deleted' });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user