feat: объединение страниц профиля — /profile рендерит карточку пользователя
- /profile теперь обёртка MyProfilePage над UserProfilePage (один экран для своего и чужого профиля) - self-вкладки из ProfileSettings перенесены: Уведомления, Offline, Интерфейс, Безопасность (components/profile/*) - ProfileSettings.tsx удалён - админ видит вкладки Уведомления и Offline на чужой карточке с данными целевого пользователя (userId-параметр в GET/POST /api/subscriptions, PATCH/DELETE по владельцу, GET /api/sync/config?userId=; проверка canManageUser) - Роль/Активен/Статус disabled для не-админа (сервер их и раньше игнорировал) - пункт меню «Настройки профиля» переименован в «Мой профиль»
This commit is contained in:
@@ -5,6 +5,7 @@ import { tenantIsolation } from "../middleware/tenant.middleware";
|
||||
import { validateRequest } from "../middleware/validation.middleware";
|
||||
import { createSubscriptionSchema, updateSubscriptionSchema } from "@shared/schema";
|
||||
import { notificationService } from "../services/notification.service";
|
||||
import { canManageUser } from "../utils/user-access";
|
||||
|
||||
export function registerChatNotificationRoutes(router: Router): void {
|
||||
// Get user notifications
|
||||
@@ -97,13 +98,27 @@ export function registerChatNotificationRoutes(router: Router): void {
|
||||
);
|
||||
|
||||
// Get user subscriptions
|
||||
// ?userId=N — подписки другого пользователя (только при canManageUser: админ/руководитель)
|
||||
router.get('/api/subscriptions',
|
||||
authenticateToken,
|
||||
tenantIsolation,
|
||||
async (req: AuthenticatedRequest, res) => {
|
||||
try {
|
||||
let targetUserId = req.user!.id;
|
||||
if (req.query.userId !== undefined) {
|
||||
const queryUserId = parseInt(String(req.query.userId));
|
||||
if (isNaN(queryUserId)) {
|
||||
return res.status(400).json({ success: false, error: 'Некорректный ID пользователя' });
|
||||
}
|
||||
if (queryUserId !== req.user!.id) {
|
||||
if (!(await canManageUser(req.user, queryUserId, req.organizationId!))) {
|
||||
return res.status(403).json({ success: false, error: 'Нет прав на просмотр подписок этого пользователя' });
|
||||
}
|
||||
targetUserId = queryUserId;
|
||||
}
|
||||
}
|
||||
const subscriptions = await notificationService.getUserSubscriptions(
|
||||
req.user!.id, req.organizationId!
|
||||
targetUserId, req.organizationId!
|
||||
);
|
||||
res.json({ success: true, subscriptions });
|
||||
} catch (error) {
|
||||
@@ -114,14 +129,22 @@ export function registerChatNotificationRoutes(router: Router): void {
|
||||
);
|
||||
|
||||
// Create subscription
|
||||
// body.userId — создать подписку другому пользователю (только при canManageUser)
|
||||
router.post('/api/subscriptions',
|
||||
authenticateToken,
|
||||
tenantIsolation,
|
||||
validateRequest(createSubscriptionSchema),
|
||||
async (req: AuthenticatedRequest, res) => {
|
||||
try {
|
||||
let targetUserId = req.user!.id;
|
||||
if (req.body.userId !== undefined && req.body.userId !== req.user!.id) {
|
||||
if (!(await canManageUser(req.user, req.body.userId, req.organizationId!))) {
|
||||
return res.status(403).json({ success: false, error: 'Нет прав на управление подписками этого пользователя' });
|
||||
}
|
||||
targetUserId = req.body.userId;
|
||||
}
|
||||
const subscription = await notificationService.createSubscription({
|
||||
userId: req.user!.id,
|
||||
userId: targetUserId,
|
||||
organizationId: req.organizationId!,
|
||||
eventTypeCode: req.body.eventTypeCode,
|
||||
targetType: req.body.targetType,
|
||||
@@ -147,8 +170,17 @@ export function registerChatNotificationRoutes(router: Router): void {
|
||||
if (isNaN(subscriptionId)) {
|
||||
return res.status(400).json({ success: false, error: 'Некорректный ID подписки' });
|
||||
}
|
||||
const existing = await notificationService.getSubscriptionById(subscriptionId, req.organizationId!);
|
||||
if (!existing) {
|
||||
return res.status(404).json({ success: false, error: 'Подписка не найдена' });
|
||||
}
|
||||
// Владелец подписки или canManageUser над владельцем (админ/руководитель)
|
||||
if (existing.userId !== req.user!.id &&
|
||||
!(await canManageUser(req.user, existing.userId, req.organizationId!))) {
|
||||
return res.status(403).json({ success: false, error: 'Нет прав на изменение этой подписки' });
|
||||
}
|
||||
const subscription = await notificationService.updateSubscription(
|
||||
subscriptionId, req.user!.id, req.organizationId!, req.body
|
||||
subscriptionId, existing.userId, req.organizationId!, req.body
|
||||
);
|
||||
if (!subscription) {
|
||||
return res.status(404).json({ success: false, error: 'Подписка не найдена' });
|
||||
@@ -171,7 +203,16 @@ export function registerChatNotificationRoutes(router: Router): void {
|
||||
if (isNaN(subscriptionId)) {
|
||||
return res.status(400).json({ success: false, error: 'Некорректный ID подписки' });
|
||||
}
|
||||
await notificationService.deleteSubscription(subscriptionId, req.user!.id, req.organizationId!);
|
||||
const existing = await notificationService.getSubscriptionById(subscriptionId, req.organizationId!);
|
||||
if (!existing) {
|
||||
return res.status(404).json({ success: false, error: 'Подписка не найдена' });
|
||||
}
|
||||
// Владелец подписки или canManageUser над владельцем (админ/руководитель)
|
||||
if (existing.userId !== req.user!.id &&
|
||||
!(await canManageUser(req.user, existing.userId, req.organizationId!))) {
|
||||
return res.status(403).json({ success: false, error: 'Нет прав на удаление этой подписки' });
|
||||
}
|
||||
await notificationService.deleteSubscription(subscriptionId, existing.userId, req.organizationId!);
|
||||
res.json({ success: true, message: 'Подписка удалена' });
|
||||
} catch (error) {
|
||||
console.error('Delete subscription error:', error);
|
||||
|
||||
Reference in New Issue
Block a user