import { Router } from "express"; import { z } from 'zod'; import { storage } from "../storage"; import { authenticateToken, type AuthenticatedRequest } from "../middleware/auth.middleware"; import { tenantIsolation } from "../middleware/tenant.middleware"; import { validateRequest } from "../middleware/validation.middleware"; import { insertBookmarkFolderSchema, createBookmarkFolderSchema } from "@shared/schema"; export function registerBookmarkFolderRoutes(router: Router): void { // Get all bookmark folders for organization router.get('/api/bookmark-folders', authenticateToken, tenantIsolation, async (req: AuthenticatedRequest, res) => { try { const folders = await storage.getBookmarkFoldersByOrganization(req.organizationId!, req.user!.id); res.json({ success: true, folders }); } catch (error) { console.error('Get bookmark folders error:', error); res.status(500).json({ success: false, error: 'Ошибка при загрузке папок' }); } } ); // Get bookmark folders by parent router.get('/api/bookmark-folders/by-parent/:parentId', authenticateToken, tenantIsolation, async (req: AuthenticatedRequest, res) => { try { const parentId = req.params.parentId === 'null' ? null : parseInt(req.params.parentId); if (parentId !== null && isNaN(parentId)) { return res.status(400).json({ success: false, error: 'Некорректный ID родительской папки' }); } const folders = await storage.getBookmarkFoldersByParent(parentId, req.organizationId!, req.user!.id); res.json({ success: true, folders }); } catch (error) { console.error('Get bookmark folders by parent error:', error); res.status(500).json({ success: false, error: 'Ошибка при загрузке дочерних папок' }); } } ); // Create bookmark folder router.post('/api/bookmark-folders', authenticateToken, tenantIsolation, validateRequest(createBookmarkFolderSchema), async (req: AuthenticatedRequest, res) => { try { if (req.body.parentId) { const parentFolder = await storage.getBookmarkFolder(req.body.parentId, req.organizationId!, req.user!.id); if (!parentFolder) { return res.status(400).json({ success: false, error: 'Родительская папка не найдена или не принадлежит вам' }); } } const rawFolderData = { ...req.body, organizationId: req.organizationId!, userId: req.user!.id, createdBy: req.user!.id, isExpanded: true }; const parsedFolder = insertBookmarkFolderSchema.safeParse(rawFolderData); if (!parsedFolder.success) { return res.status(400).json({ success: false, error: 'Некорректные данные папки', details: parsedFolder.error.flatten() }); } const createdFolder = await storage.createBookmarkFolder(parsedFolder.data); res.status(201).json({ success: true, message: 'Папка создана', folder: createdFolder }); } catch (error) { console.error('Create bookmark folder error:', error); res.status(500).json({ success: false, error: 'Ошибка при создании папки' }); } } ); // Update bookmark folder router.put('/api/bookmark-folders/:id', authenticateToken, tenantIsolation, async (req: AuthenticatedRequest, res) => { try { const folderId = parseInt(req.params.id); if (isNaN(folderId)) { return res.status(400).json({ success: false, error: 'Некорректный ID папки' }); } const existingFolder = await storage.getBookmarkFolder(folderId, req.organizationId!, req.user!.id); if (!existingFolder) { return res.status(404).json({ success: false, error: 'Папка не найдена' }); } const { userId: _uF, createdBy: _cbF, organizationId: _oF, id: _idF, ...folderUpdates } = req.body; if (folderUpdates.parentId) { const parentFolder = await storage.getBookmarkFolder(folderUpdates.parentId, req.organizationId!, req.user!.id); if (!parentFolder) { return res.status(400).json({ success: false, error: 'Родительская папка не найдена или не принадлежит вам' }); } } const updatedFolder = await storage.updateBookmarkFolder( folderId, req.organizationId!, folderUpdates, req.user!.id ); res.json({ success: true, message: 'Папка обновлена', folder: updatedFolder }); } catch (error) { console.error('Update bookmark folder error:', error); res.status(500).json({ success: false, error: 'Ошибка при обновлении папки' }); } } ); // Delete bookmark folder router.delete('/api/bookmark-folders/:id', authenticateToken, tenantIsolation, async (req: AuthenticatedRequest, res) => { try { const folderId = parseInt(req.params.id); if (isNaN(folderId)) { return res.status(400).json({ success: false, error: 'Некорректный ID папки' }); } const existingFolder = await storage.getBookmarkFolder(folderId, req.organizationId!, req.user!.id); if (!existingFolder) { return res.status(404).json({ success: false, error: 'Папка не найдена' }); } await storage.deleteBookmarkFolder(folderId, req.organizationId!, req.user!.id); res.json({ success: true, message: 'Папка удалена' }); } catch (error) { console.error('Delete bookmark folder error:', error); res.status(500).json({ success: false, error: 'Ошибка при удалении папки' }); } } ); // Normalize bookmark folder positions router.post('/api/bookmark-folders/normalize-positions', authenticateToken, tenantIsolation, async (req: AuthenticatedRequest, res) => { try { await storage.normalizeBookmarkFolderPositions(req.organizationId!, req.user!.id); res.json({ success: true, message: 'Позиции папок закладок нормализованы' }); } catch (error) { console.error('Normalize bookmark folder positions error:', error); res.status(500).json({ success: false, error: 'Ошибка при нормализации позиций папок закладок' }); } } ); // Reorder bookmark folders router.post('/api/bookmark-folders/reorder', authenticateToken, tenantIsolation, async (req: AuthenticatedRequest, res) => { try { const reorderItemSchema = z.object({ items: z.array(z.object({ id: z.number().int().positive(), position: z.number().int().min(0), })).min(1), }); const parsed = reorderItemSchema.safeParse(req.body); if (!parsed.success) { return res.status(400).json({ success: false, error: 'Некорректный формат данных' }); } await storage.batchUpdateBookmarkFolderPositions(parsed.data.items, req.organizationId!, req.user!.id); res.json({ success: true }); } catch (error) { console.error('Reorder bookmark folders error:', error); res.status(500).json({ success: false, error: 'Ошибка при изменении порядка папок' }); } } ); }