feat: роли customer/admin, админ-панель, admin@site.com
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
const express = require('express');
|
||||
const { query, formatPrice } = require('../db');
|
||||
const { requireAdmin } = require('../middleware/auth');
|
||||
const { asyncHandler } = require('../utils/asyncHandler');
|
||||
const { ROLE_LABELS } = require('../constants/roles');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.use(requireAdmin);
|
||||
|
||||
router.get(
|
||||
'/',
|
||||
asyncHandler(async (req, res) => {
|
||||
const [users, products, orders, revenue] = await Promise.all([
|
||||
query('SELECT COUNT(*)::int AS n FROM users'),
|
||||
query('SELECT COUNT(*)::int AS n FROM products'),
|
||||
query('SELECT COUNT(*)::int AS n FROM orders'),
|
||||
query(
|
||||
`SELECT COALESCE(SUM(total_cents), 0)::int AS total FROM orders WHERE status != 'cancelled'`
|
||||
),
|
||||
]);
|
||||
|
||||
const { rows: recentOrders } = await query(
|
||||
`SELECT o.id, o.status, o.total_cents, o.created_at, o.customer_name, u.email AS user_email
|
||||
FROM orders o
|
||||
JOIN users u ON u.id = o.user_id
|
||||
ORDER BY o.created_at DESC
|
||||
LIMIT 10`
|
||||
);
|
||||
|
||||
res.render('admin/dashboard', {
|
||||
title: 'Админ-панель',
|
||||
stats: {
|
||||
users: users.rows[0].n,
|
||||
products: products.rows[0].n,
|
||||
orders: orders.rows[0].n,
|
||||
revenue: revenue.rows[0].total,
|
||||
},
|
||||
recentOrders,
|
||||
formatPrice,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/users',
|
||||
asyncHandler(async (req, res) => {
|
||||
const { rows: users } = await query(
|
||||
`SELECT id, email, name, role, created_at FROM users ORDER BY created_at DESC`
|
||||
);
|
||||
res.render('admin/users', {
|
||||
title: 'Пользователи',
|
||||
users,
|
||||
roleLabels: ROLE_LABELS,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/orders',
|
||||
asyncHandler(async (req, res) => {
|
||||
const { rows: orders } = await query(
|
||||
`SELECT o.id, o.status, o.total_cents, o.created_at, o.customer_name, o.customer_email,
|
||||
u.email AS account_email
|
||||
FROM orders o
|
||||
JOIN users u ON u.id = o.user_id
|
||||
ORDER BY o.created_at DESC`
|
||||
);
|
||||
res.render('admin/orders', {
|
||||
title: 'Заказы',
|
||||
orders,
|
||||
formatPrice,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/orders/:id/status',
|
||||
asyncHandler(async (req, res) => {
|
||||
const { status } = req.body;
|
||||
const allowed = ['pending', 'paid', 'shipped', 'cancelled'];
|
||||
if (!allowed.includes(status)) {
|
||||
return res.redirect('/admin/orders');
|
||||
}
|
||||
await query('UPDATE orders SET status = $1 WHERE id = $2', [status, req.params.id]);
|
||||
res.redirect('/admin/orders');
|
||||
})
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/products',
|
||||
asyncHandler(async (req, res) => {
|
||||
const { rows: products } = await query(
|
||||
`SELECT p.*, c.name AS category_name
|
||||
FROM products p
|
||||
LEFT JOIN categories c ON c.id = p.category_id
|
||||
ORDER BY p.id`
|
||||
);
|
||||
res.render('admin/products', {
|
||||
title: 'Товары',
|
||||
products,
|
||||
formatPrice,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
module.exports = router;
|
||||
+8
-3
@@ -3,6 +3,7 @@ const bcrypt = require('bcryptjs');
|
||||
const { query, formatPrice } = require('../db');
|
||||
const { getCart, cartCount } = require('../cart');
|
||||
const { requireAuth } = require('../middleware/auth');
|
||||
const { ROLES } = require('../constants/roles');
|
||||
const { asyncHandler } = require('../utils/asyncHandler');
|
||||
|
||||
const router = express.Router();
|
||||
@@ -50,8 +51,9 @@ router.post(
|
||||
const hash = bcrypt.hashSync(password, 10);
|
||||
try {
|
||||
const { rows } = await query(
|
||||
'INSERT INTO users (email, password_hash, name) VALUES ($1, $2, $3) RETURNING id',
|
||||
[email.trim().toLowerCase(), hash, name.trim()]
|
||||
`INSERT INTO users (email, password_hash, name, role)
|
||||
VALUES ($1, $2, $3, $4) RETURNING id`,
|
||||
[email.trim().toLowerCase(), hash, name.trim(), ROLES.CUSTOMER]
|
||||
);
|
||||
req.session.userId = rows[0].id;
|
||||
res.redirect('/');
|
||||
@@ -100,6 +102,9 @@ router.post(
|
||||
}
|
||||
|
||||
req.session.userId = user.id;
|
||||
if (user.role === ROLES.ADMIN && (next === '/' || next === '/account')) {
|
||||
return res.redirect('/admin');
|
||||
}
|
||||
res.redirect(next.startsWith('/') ? next : '/');
|
||||
})
|
||||
);
|
||||
@@ -115,7 +120,7 @@ router.get(
|
||||
requireAuth,
|
||||
asyncHandler(async (req, res) => {
|
||||
const { rows } = await query(
|
||||
'SELECT id, email, name, created_at FROM users WHERE id = $1',
|
||||
'SELECT id, email, name, role, created_at FROM users WHERE id = $1',
|
||||
[req.session.userId]
|
||||
);
|
||||
const user = rows[0];
|
||||
|
||||
Reference in New Issue
Block a user