first commit
This commit is contained in:
133
server/src/routes/cats.ts
Normal file
133
server/src/routes/cats.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import { Router, Response } from 'express';
|
||||
import multer from 'multer';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { queryOne, queryAll, execute } from '../db';
|
||||
import { authMiddleware, AuthRequest } from '../middleware/auth.js';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const uploadsDir = path.join(__dirname, '..', '..', 'uploads');
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
destination: (_req, _file, cb) => cb(null, uploadsDir),
|
||||
filename: (_req, file, cb) => {
|
||||
const ext = path.extname(file.originalname);
|
||||
cb(null, `${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`);
|
||||
},
|
||||
});
|
||||
|
||||
const upload = multer({
|
||||
storage,
|
||||
limits: { fileSize: 10 * 1024 * 1024 },
|
||||
fileFilter: (_req, file, cb) => {
|
||||
const allowed = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
|
||||
const ext = path.extname(file.originalname).toLowerCase();
|
||||
cb(null, allowed.includes(ext));
|
||||
},
|
||||
});
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get('/', (req: AuthRequest, res: Response) => {
|
||||
const page = Math.max(1, parseInt(req.query.page as string) || 1);
|
||||
const limit = 12;
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
const cats = queryAll(
|
||||
`SELECT c.id, c.image_url, c.caption, c.created_at, c.user_id,
|
||||
u.username, u.points AS user_points,
|
||||
(SELECT COUNT(*) FROM likes WHERE cat_id = c.id) AS likes_count
|
||||
FROM cats c
|
||||
JOIN users u ON u.id = c.user_id
|
||||
ORDER BY c.created_at DESC
|
||||
LIMIT ? OFFSET ?`,
|
||||
[limit, offset]
|
||||
);
|
||||
|
||||
const countResult = queryOne('SELECT COUNT(*) as count FROM cats');
|
||||
const total = countResult?.count || 0;
|
||||
|
||||
res.json({ cats, total, page, totalPages: Math.ceil(total / limit) });
|
||||
});
|
||||
|
||||
router.get('/user/:userId', (req: AuthRequest, res: Response) => {
|
||||
const userId = parseInt(req.params.userId);
|
||||
const cats = queryAll(
|
||||
`SELECT c.id, c.image_url, c.caption, c.created_at, c.user_id,
|
||||
u.username, u.points AS user_points,
|
||||
(SELECT COUNT(*) FROM likes WHERE cat_id = c.id) AS likes_count
|
||||
FROM cats c
|
||||
JOIN users u ON u.id = c.user_id
|
||||
WHERE c.user_id = ?
|
||||
ORDER BY c.created_at DESC`,
|
||||
[userId]
|
||||
);
|
||||
|
||||
res.json({ cats });
|
||||
});
|
||||
|
||||
router.get('/:id', (req: AuthRequest, res: Response) => {
|
||||
const cat = queryOne(
|
||||
`SELECT c.id, c.image_url, c.caption, c.created_at, c.user_id,
|
||||
u.username, u.points AS user_points,
|
||||
(SELECT COUNT(*) FROM likes WHERE cat_id = c.id) AS likes_count
|
||||
FROM cats c
|
||||
JOIN users u ON u.id = c.user_id
|
||||
WHERE c.id = ?`,
|
||||
[req.params.id]
|
||||
);
|
||||
|
||||
if (!cat) {
|
||||
res.status(404).json({ error: 'Cat not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ cat });
|
||||
});
|
||||
|
||||
router.post('/', authMiddleware, upload.single('image'), (req: AuthRequest, res: Response) => {
|
||||
if (!req.file) {
|
||||
res.status(400).json({ error: 'Image required (jpg, png, gif, webp, max 10MB)' });
|
||||
return;
|
||||
}
|
||||
|
||||
const caption = (req.body.caption || '').trim();
|
||||
const image_url = `/uploads/${req.file.filename}`;
|
||||
|
||||
execute(
|
||||
'INSERT INTO cats (user_id, image_url, caption) VALUES (?, ?, ?)',
|
||||
[req.userId, image_url, caption]
|
||||
);
|
||||
|
||||
execute('UPDATE users SET points = points + 10 WHERE id = ?', [req.userId]);
|
||||
|
||||
const cat = queryOne(
|
||||
`SELECT c.id, c.image_url, c.caption, c.created_at, c.user_id,
|
||||
u.username, u.points AS user_points,
|
||||
0 AS likes_count
|
||||
FROM cats c
|
||||
JOIN users u ON u.id = c.user_id
|
||||
WHERE c.id = (SELECT MAX(id) FROM cats WHERE user_id = ?)`,
|
||||
[req.userId]
|
||||
);
|
||||
|
||||
res.status(201).json({ cat });
|
||||
});
|
||||
|
||||
router.delete('/:id', authMiddleware, (req: AuthRequest, res: Response) => {
|
||||
const cat = queryOne('SELECT user_id FROM cats WHERE id = ?', [req.params.id]);
|
||||
if (!cat) {
|
||||
res.status(404).json({ error: 'Cat not found' });
|
||||
return;
|
||||
}
|
||||
if (cat.user_id !== req.userId) {
|
||||
res.status(403).json({ error: 'Not your cat' });
|
||||
return;
|
||||
}
|
||||
|
||||
execute('DELETE FROM likes WHERE cat_id = ?', [req.params.id]);
|
||||
execute('DELETE FROM cats WHERE id = ?', [req.params.id]);
|
||||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user