feat: Multi-feature CRM update
- Add team_leader role with appropriate permissions - Add lastSeen timestamp for chat online indicator - Add needsFollowup flag to ucastnici table - Add getTodayCalendarCount endpoint for calendar badge - Add company reminders to calendar data - Enhance company search to include phone and contacts - Update routes to allow team_leader access to kurzy, services, timesheets Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@ import express from 'express';
|
||||
import path from 'path';
|
||||
import * as aiKurzyController from '../controllers/ai-kurzy.controller.js';
|
||||
import { authenticate } from '../middlewares/auth/authMiddleware.js';
|
||||
import { requireAdmin } from '../middlewares/auth/roleMiddleware.js';
|
||||
import { requireTeamLeaderOrAdmin } from '../middlewares/auth/roleMiddleware.js';
|
||||
import { validateBody, validateParams, validateQuery } from '../middlewares/security/validateInput.js';
|
||||
import { createUpload, ALLOWED_FILE_TYPES } from '../config/upload.js';
|
||||
import {
|
||||
@@ -29,9 +29,9 @@ const upload = createUpload({
|
||||
diskPath: path.join(process.cwd(), 'uploads', 'ai-kurzy'),
|
||||
});
|
||||
|
||||
// All routes require authentication and admin role
|
||||
// All routes require authentication and admin or team_leader role
|
||||
router.use(authenticate);
|
||||
router.use(requireAdmin);
|
||||
router.use(requireTeamLeaderOrAdmin);
|
||||
|
||||
// ==================== STATISTICS ====================
|
||||
|
||||
|
||||
@@ -19,6 +19,11 @@ const eventIdSchema = z.object({
|
||||
// Všetky routes vyžadujú autentifikáciu
|
||||
router.use(authenticate);
|
||||
|
||||
/**
|
||||
* GET /api/events/today-count - Získať počet eventov a todos pre dnešok (pre badge v sidebar)
|
||||
*/
|
||||
router.get('/today-count', eventController.getTodayCount);
|
||||
|
||||
/**
|
||||
* GET /api/events - Získať eventy a todos podľa mesiaca (filtrované podľa assigned users)
|
||||
*/
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as serviceController from '../controllers/service.controller.js';
|
||||
import * as serviceFolderController from '../controllers/service-folder.controller.js';
|
||||
import * as serviceDocumentController from '../controllers/service-document.controller.js';
|
||||
import { authenticate } from '../middlewares/auth/authMiddleware.js';
|
||||
import { requireAdmin } from '../middlewares/auth/roleMiddleware.js';
|
||||
import { requireAdmin, requireTeamLeaderOrAdmin } from '../middlewares/auth/roleMiddleware.js';
|
||||
import { validateBody, validateParams } from '../middlewares/security/validateInput.js';
|
||||
import { createServiceSchema, updateServiceSchema } from '../validators/crm.validators.js';
|
||||
import { createUpload } from '../config/upload.js';
|
||||
@@ -30,11 +30,11 @@ router.use(authenticate);
|
||||
router.get('/folders', serviceFolderController.getAllFolders);
|
||||
|
||||
/**
|
||||
* POST /api/services/folders - Create new folder (admin only)
|
||||
* POST /api/services/folders - Create new folder (admin/team_leader)
|
||||
*/
|
||||
router.post(
|
||||
'/folders',
|
||||
requireAdmin,
|
||||
requireTeamLeaderOrAdmin,
|
||||
validateBody(createFolderSchema),
|
||||
serviceFolderController.createFolder
|
||||
);
|
||||
@@ -49,22 +49,22 @@ router.get(
|
||||
);
|
||||
|
||||
/**
|
||||
* PUT /api/services/folders/:folderId - Update folder (admin only)
|
||||
* PUT /api/services/folders/:folderId - Update folder (admin/team_leader)
|
||||
*/
|
||||
router.put(
|
||||
'/folders/:folderId',
|
||||
requireAdmin,
|
||||
requireTeamLeaderOrAdmin,
|
||||
validateParams(folderIdSchema),
|
||||
validateBody(updateFolderSchema),
|
||||
serviceFolderController.updateFolder
|
||||
);
|
||||
|
||||
/**
|
||||
* DELETE /api/services/folders/:folderId - Delete folder (admin only)
|
||||
* DELETE /api/services/folders/:folderId - Delete folder (admin/team_leader)
|
||||
*/
|
||||
router.delete(
|
||||
'/folders/:folderId',
|
||||
requireAdmin,
|
||||
requireTeamLeaderOrAdmin,
|
||||
validateParams(folderIdSchema),
|
||||
serviceFolderController.deleteFolder
|
||||
);
|
||||
@@ -100,11 +100,11 @@ router.get(
|
||||
);
|
||||
|
||||
/**
|
||||
* DELETE /api/services/folders/:folderId/documents/:documentId - Delete document (admin only)
|
||||
* DELETE /api/services/folders/:folderId/documents/:documentId - Delete document (admin/team_leader)
|
||||
*/
|
||||
router.delete(
|
||||
'/folders/:folderId/documents/:documentId',
|
||||
requireAdmin,
|
||||
requireTeamLeaderOrAdmin,
|
||||
validateParams(folderDocumentIdSchema),
|
||||
serviceDocumentController.deleteDocument
|
||||
);
|
||||
@@ -117,11 +117,11 @@ router.delete(
|
||||
router.get('/', serviceController.getAllServices);
|
||||
|
||||
/**
|
||||
* POST /api/services - Create new service (admin only)
|
||||
* POST /api/services - Create new service (admin/team_leader)
|
||||
*/
|
||||
router.post(
|
||||
'/',
|
||||
requireAdmin,
|
||||
requireTeamLeaderOrAdmin,
|
||||
validateBody(createServiceSchema),
|
||||
serviceController.createService
|
||||
);
|
||||
@@ -136,22 +136,22 @@ router.get(
|
||||
);
|
||||
|
||||
/**
|
||||
* PUT /api/services/:serviceId - Update service (admin only)
|
||||
* PUT /api/services/:serviceId - Update service (admin/team_leader)
|
||||
*/
|
||||
router.put(
|
||||
'/:serviceId',
|
||||
requireAdmin,
|
||||
requireTeamLeaderOrAdmin,
|
||||
validateParams(serviceIdSchema),
|
||||
validateBody(updateServiceSchema),
|
||||
serviceController.updateService
|
||||
);
|
||||
|
||||
/**
|
||||
* DELETE /api/services/:serviceId - Delete service (admin only)
|
||||
* DELETE /api/services/:serviceId - Delete service (admin/team_leader)
|
||||
*/
|
||||
router.delete(
|
||||
'/:serviceId',
|
||||
requireAdmin,
|
||||
requireTeamLeaderOrAdmin,
|
||||
validateParams(serviceIdSchema),
|
||||
serviceController.deleteService
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import express from 'express';
|
||||
import * as timeTrackingController from '../controllers/time-tracking.controller.js';
|
||||
import { authenticate } from '../middlewares/auth/authMiddleware.js';
|
||||
import { requireAdmin } from '../middlewares/auth/roleMiddleware.js';
|
||||
import { requireTeamLeaderOrAdmin } from '../middlewares/auth/roleMiddleware.js';
|
||||
import { validateBody, validateParams } from '../middlewares/security/validateInput.js';
|
||||
import {
|
||||
startTimeEntrySchema,
|
||||
@@ -47,8 +47,8 @@ router.post(
|
||||
// Get running time entry
|
||||
router.get('/running', timeTrackingController.getRunningTimeEntry);
|
||||
|
||||
// Get all running time entries (for dashboard) - admin only
|
||||
router.get('/running-all', requireAdmin, timeTrackingController.getAllRunningTimeEntries);
|
||||
// Get all running time entries (for dashboard) - admin/team_leader
|
||||
router.get('/running-all', requireTeamLeaderOrAdmin, timeTrackingController.getAllRunningTimeEntries);
|
||||
|
||||
// Get all time entries with filters
|
||||
router.get('/', timeTrackingController.getAllTimeEntries);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import express from 'express';
|
||||
import * as timesheetController from '../controllers/timesheet.controller.js';
|
||||
import { authenticate } from '../middlewares/auth/authMiddleware.js';
|
||||
import { requireAdmin } from '../middlewares/auth/roleMiddleware.js';
|
||||
import { requireTeamLeaderOrAdmin } from '../middlewares/auth/roleMiddleware.js';
|
||||
import { validateBody, validateParams } from '../middlewares/security/validateInput.js';
|
||||
import { z } from 'zod';
|
||||
import { createUpload } from '../config/upload.js';
|
||||
@@ -48,7 +48,7 @@ router.get('/my', timesheetController.getMyTimesheets);
|
||||
* Get all timesheets (admin only)
|
||||
* GET /api/timesheets/all
|
||||
*/
|
||||
router.get('/all', requireAdmin, timesheetController.getAllTimesheets);
|
||||
router.get('/all', requireTeamLeaderOrAdmin, timesheetController.getAllTimesheets);
|
||||
|
||||
/**
|
||||
* Download timesheet
|
||||
|
||||
@@ -2,6 +2,7 @@ import express from 'express';
|
||||
import { authenticate } from '../middlewares/auth/authMiddleware.js';
|
||||
import { db } from '../config/database.js';
|
||||
import { users } from '../db/schema.js';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -21,6 +22,7 @@ router.get('/', async (req, res, next) => {
|
||||
firstName: users.firstName,
|
||||
lastName: users.lastName,
|
||||
role: users.role,
|
||||
lastSeen: users.lastSeen,
|
||||
})
|
||||
.from(users)
|
||||
.orderBy(users.username);
|
||||
@@ -31,4 +33,23 @@ router.get('/', async (req, res, next) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Update user's lastSeen timestamp (heartbeat)
|
||||
* POST /api/users/heartbeat
|
||||
*/
|
||||
router.post('/heartbeat', async (req, res, next) => {
|
||||
try {
|
||||
const userId = req.userId;
|
||||
|
||||
await db
|
||||
.update(users)
|
||||
.set({ lastSeen: new Date() })
|
||||
.where(eq(users.id, userId));
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user