Browse Source

Новое новое начало

Vadim 4 months ago
parent
commit
f1c1455333

+ 1 - 0
.example.env

@@ -24,6 +24,7 @@ JWT_REFRESH_SECRET= ""
 PASSWORD_MAX_TRIES = "10"
 ACCESS_TOKEN_LIFETIME_MINS= "15"
 REFRESH_TOKEN_LIFETIME_DAYS= "90"
+BCRYPT_SALT_ROUNDS = "12"
 
 # CONFIRM PINS
 CONFIRM_PIN_LIFETIME_MINS = "60"

+ 16 - 275
src/api/api.ts

@@ -2,7 +2,7 @@ import { z } from "zod";
 
 class authApi {
   // /auth/registration
-  public POST_Registration = {
+  POST_Registration = {
     req: z.object({
       email: z.string().email(),
     }),
@@ -21,7 +21,7 @@ class authApi {
   };
 
   // /auth/confirm-registration
-  public POST_ConfirmRegistration = {
+  POST_ConfirmRegistration = {
     req: z.object({
       password: z.string(),
       name: z.string(),
@@ -32,7 +32,6 @@ class authApi {
       z.object({
         code: z.literal("registered"),
         accessToken: z.string(),
-        refreshToken: z.string(),
         userData: z.object({
           email: z.string().email(),
           userId: z.string().uuid(),
@@ -45,7 +44,7 @@ class authApi {
   };
 
   // /auth/login
-  public POST_Login = {
+  POST_Login = {
     req: z.object({
       email: z.string().email(),
       password: z.string(),
@@ -55,7 +54,6 @@ class authApi {
         code: z.enum(["success"]),
 
         accessToken: z.string(),
-        refreshToken: z.string(),
         userData: z.object({
           email: z.string(),
           userId: z.string().uuid(),
@@ -78,95 +76,48 @@ class authApi {
   };
 
   // /auth/logout
-  public POST_Logout = {
+  POST_Logout = {
     res: z.object({
       code: z.enum(["success"]),
     }),
   };
 
   // /auth/logout-all-devices
-  public POST_LogoutAllDevices = {
+  POST_LogoutAllDevices = {
     res: z.object({
       code: z.enum(["success"]),
     }),
   };
 
   // /auth/refresh
-  public POST_Refresh = {
+  POST_Refresh = {
     res: z.object({
       code: z.enum(["success"]),
 
       accessToken: z.string(),
-      refreshToken: z.string(),
       userData: z.object({
         email: z.string().email(),
         userId: z.string().uuid(),
       }),
     }),
   };
-}
-export const AuthApi = new authApi();
 
-class companiesApi {
-  POST_Company = {
-    req: z.object({
-      name: z.string(),
-      timezone: z.string(),
-    }),
+  GET_Permissions = {
     res: z.object({
       code: z.enum(["success"]),
-    }),
-  };
 
-  GET_UserCompanies = {
-    res: z.object({
-      code: z.enum(["success"]),
-      companies: z.array(
-        z.object({
-          companyId: z.string().uuid(),
-          name: z.string(),
-          timezone: z.string(),
-        }),
-      ),
-    }),
-  };
-
-  GET_Company = {
-    req: z.object({
-      companyId: z.string().uuid(),
-    }),
-
-    res: z.object({
-      code: z.enum(["success"]),
-
-      company: z.object({
-        companyId: z.string().uuid(),
-        name: z.string(),
-        ownerId: z.string().uuid(),
-        timezone: z.string(),
-
-        events: z.array(
-          z.object({
-            eventId: z.string().uuid(),
-            localName: z.string(),
-            timezone: z.string(),
-            companyId: z.string().uuid(),
-            dates: z.array(z.string().datetime()),
-          }),
-        ),
-      }),
+      permissions: z.array(z.string()),
     }),
   };
 }
-export const CompaniesApi = new companiesApi();
+export const AuthApi = new authApi();
 
-class eventsManagementApi {
+class eventManagementApi {
   POST_Event = {
     req: z.object({
       localName: z.string(),
-      timezone: z.string().optional(),
+      timezone: z.string(),
       dates: z.array(z.string()),
-      companyId: z.string().uuid(),
     }),
     res: z.object({
       code: z.enum(["success"]),
@@ -183,230 +134,20 @@ class eventsManagementApi {
         localName: z.string(),
         timezone: z.string(),
         dates: z.array(z.string().datetime()),
-        programPoints: z.array(
-          z.object({
-            programPointId: z.string().uuid(),
-            name: z.string(),
-            startDate: z.string().datetime(),
-            endDate: z.string().datetime(),
-            roomId: z.string().uuid().nullable(),
-            isInternal: z.boolean(),
-          }),
-        ),
-
-        rooms: z.array(
-          z.object({
-            roomId: z.string().uuid(),
-            name: z.string(),
-          }),
-        ),
-
-        taskBlocks: z.array(
-          z.object({
-            taskBlockId: z.string().uuid(),
-            name: z.string(),
-          }),
-        ),
-
-        managers: z.array(
-          z.object({
-            userId: z.string().uuid(),
-            name: z.string(),
-            email: z.string().email(),
-          }),
-        ),
-
-        roles: z.array(
-          z.object({
-            roleId: z.string().uuid(),
-            name: z.string(),
-          }),
-        ),
       }),
     }),
   };
 
-  POST_ProgramPoint = {
-    req: z.object({
-      eventId: z.string().uuid(),
-
-      name: z.string(),
-      startDate: z.string(),
-      endDate: z.string(),
-      roomId: z.string().uuid().nullable(),
-      isInternal: z.boolean(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-      programPointId: z.string().uuid(),
-    }),
-  };
-
-  PATCH_Event = {
-    req: z.object({
-      eventId: z.string().uuid(),
-
-      localName: z.string().optional(),
-      timezone: z.string().optional(),
-      dates: z.array(z.string()).optional(),
-
-      programPoint: z
-        .object({
-          programPointId: z.string().uuid(),
-          name: z.string(),
-          startDate: z.string(),
-          endDate: z.string(),
-          roomId: z.string().uuid().nullable(),
-        })
-        .optional(),
-
-      role: z
-        .object({
-          roleId: z.string().uuid(),
-          name: z.string(),
-        })
-        .optional(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  POST_Role = {
-    req: z.object({
-      eventId: z.string().uuid(),
-      name: z.string(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-      roleId: z.string().uuid(),
-    }),
-  };
-}
-
-export const EventsManagementApi = new eventsManagementApi();
-
-class locationsManagementApi {
-  POST_Location = {
+  // activity
+  POST_Activity = {
     req: z.object({
-      name: z.string(),
       eventId: z.string().uuid(),
-      rooms: z.array(
-        z.object({
-          name: z.string(),
-          parentId: z.string().uuid().nullable(),
-        }),
-      ),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-      locationId: z.string().uuid(),
-    }),
-  };
-
-  GET_EventLocations = {
-    req: z.object({
-      eventId: z.string().uuid(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-      locations: z.array(
-        z.object({
-          locationId: z.string().uuid(),
-          name: z.string(),
-          rooms: z.array(
-            z.object({
-              roomId: z.string().uuid(),
-              name: z.string(),
-              parentId: z.string().uuid().nullable(),
-            }),
-          ),
-        }),
-      ),
-    }),
-  };
-}
-
-export const LocationsManagementApi = new locationsManagementApi();
-
-class tasksManagementApi {
-  POST_TaskBlock = {
-    req: z.object({
-      eventId: z.string().uuid(),
-      name: z.string(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  PATCH_TaskBlock = {
-    req: z.object({
-      taskBlockId: z.string().uuid(),
-      name: z.string(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  POST_Task = {
-    req: z.object({
-      name: z.string(),
-      startDate: z.string().nullable(),
-      endDate: z.string().nullable(),
-      accountableId: z.string().uuid().nullable(),
-      isTodo: z.boolean(),
-      programPointId: z.string().uuid().nullable(),
-      roomId: z.string().uuid().nullable(),
-      taskBlockId: z.string().uuid(),
-      executors: z.array(z.string()),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  PATCH_Task = {
-    req: z.object({
-      taskId: z.string().uuid(),
-
-      name: z.string().optional(),
-      startDate: z.string().nullable().optional(),
-      endDate: z.string().nullable().optional(),
-      accountableId: z.string().uuid().nullable().optional(),
-      isTodo: z.boolean().optional(),
-      programPointId: z.string().uuid().nullable().optional(),
-      roomId: z.string().uuid().nullable().optional(),
-      executors: z.array(z.string()).optional(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
+      localName: z.string(),
     }),
-  };
-
-  GET_TaskBlock = {
-    req: z.object({ taskBlockId: z.string().uuid() }).strict(),
     res: z.object({
       code: z.enum(["success"]),
-      taskBlockId: z.string().uuid(),
-      name: z.string(),
-      tasks: z.array(
-        z.object({
-          taskId: z.string().uuid(),
-          name: z.string(),
-          startDate: z.string().datetime().nullable(),
-          endDate: z.string().datetime().nullable(),
-          accountableId: z.string().uuid().nullable(),
-          isTodo: z.boolean(),
-          programPointId: z.string().uuid().nullable(),
-          roomId: z.string().uuid().nullable(),
-          taskBlockId: z.string().uuid(),
-          executors: z.array(z.string()),
-        }),
-      ),
+      activityId: z.string().uuid(),
     }),
   };
 }
-
-export const TasksManagementApi = new tasksManagementApi();
+export const EventsManagementApi = new eventManagementApi();

+ 1 - 0
src/config/config.ts

@@ -76,6 +76,7 @@ const ConfigSchema = z.object({
   PASSWORD_MAX_TRIES: requiredNumber("PASSWORD_MAX_TRIES", 5),
   ACCESS_TOKEN_LIFETIME_MINS: requiredNumber("ACCESS_TOKEN_LIFETIME_MINS", 15),
   REFRESH_TOKEN_LIFETIME_DAYS: requiredNumber("REFRESH_TOKEN_LIFETIME_DAYS", 7),
+  BCRYPT_SALT_ROUNDS: requiredNumber("BCRYPT_SALT_ROUNDS", 12),
 
   // CONFIRM PINS
   CONFIRM_PIN_LIFETIME_MINS: requiredNumber("CONFIRM_PIN_LIFETIME_MINS", 10),

+ 120 - 74
src/db/db-schema.ts

@@ -2,6 +2,17 @@ import { z } from "zod";
 
 const DbSchema = {
   ev: {
+    events: {
+      eventId: z.string().uuid(),
+      localName: z.string(),
+      timezone: z.string(),
+      companyId: z.string().uuid(),
+      eventTypeId: z.string(),
+    },
+    eventTypes: {
+      eventTypeId: z.string(),
+      name: z.string(),
+    },
     eventDates: {
       eventId: z.string().uuid(),
       date: z.string().datetime(),
@@ -10,25 +21,16 @@ const DbSchema = {
       eventId: z.string().uuid(),
       locationId: z.string().uuid(),
     },
-    eventManagers: {
-      eventId: z.string().uuid(),
-      userId: z.string().uuid(),
-    },
-    events: {
-      eventId: z.string().uuid(),
-      localName: z.string(),
-      timezone: z.string(),
-      companyId: z.string().uuid(),
-    },
     locations: {
       locationId: z.string().uuid(),
       name: z.string(),
       eventId: z.string().uuid(),
     },
-    perms: {
-      permId: z.string(),
+    areas: {
+      areaId: z.string().uuid(),
       name: z.string(),
-      defaultValue: z.boolean(),
+      locationId: z.string().uuid(),
+      parentId: z.string().uuid().nullable(),
     },
     programPoints: {
       programPointId: z.string().uuid(),
@@ -36,91 +38,135 @@ const DbSchema = {
       startDate: z.string().datetime(),
       endDate: z.string().datetime(),
       eventId: z.string().uuid(),
-      roomId: z.string().uuid().nullable(),
-      group: z.string(),
+      areaId: z.string().uuid().nullable(),
+      blockId: z.string(),
       isInternal: z.boolean(),
     },
-    roleTokens: {
-      token: z.string().uuid(),
-      roleId: z.string().uuid(),
-      capacity: z.number(),
+  },
+
+  usr: {
+    confirmPins: {
+      transactionId: z.string().uuid(),
+      email: z.string().email(),
+      confirmPin: z.number().min(1000).max(9999),
+      createTime: z.string().datetime(),
+      wrongPinTries: z.number(),
     },
-    roleTokenConnections: {
-      connectionId: z.string().uuid(),
-      token: z.string().uuid(),
-      username: z.string(),
+
+    userRefreshTokens: {
+      tokenId: z.string().uuid(),
+      refreshToken: z.string(),
+      userId: z.string().uuid(),
+    },
+    users: {
+      userId: z.string().uuid(),
+      email: z.string().email(),
+      name: z.string(),
+      password: z.string(),
+      wrongPassTries: z.number(),
     },
+
+    // roles
     roles: {
       roleId: z.string().uuid(),
-      eventId: z.string().uuid(),
       name: z.string(),
+      eventId: z.string().uuid(),
+      eventType: z.string(),
+      isSystem: z.boolean(),
     },
-    rolesOverrides: {
+    userRoles: {
       roleId: z.string().uuid(),
-      permId: z.string(),
-      newValue: z.boolean(),
+      userId: z.string().uuid(),
     },
-    rooms: {
-      roomId: z.string().uuid(),
-      name: z.string(),
-      locationId: z.string().uuid(),
-      parentId: z.string().uuid().nullable(),
+    roleGroups: {
+      roleId: z.string().uuid(),
+      groupId: z.string().uuid(),
     },
-    taskBlocks: {
-      taskBlockId: z.string().uuid(),
+    groups: {
+      groupId: z.string().uuid(),
       name: z.string(),
-      eventId: z.string().uuid(),
     },
-    taskExecutors: {
-      taskId: z.string().uuid(),
-      roleId: z.string().uuid(),
+    groupPerms: {
+      groupId: z.string().uuid(),
+      permId: z.string().uuid(),
     },
-    tasks: {
-      taskId: z.string().uuid(),
+    perms: {
+      permId: z.string().uuid(),
+      name: z.string(),
+      objId: z.string().uuid(),
+    },
+    objects: {
+      objId: z.string().uuid(),
       name: z.string(),
-      startDate: z.string().datetime().nullable(),
-      endDate: z.string().datetime().nullable(),
-      accountableId: z.string().uuid().nullable(),
-      isTodo: z.boolean(),
-      programPointId: z.string().uuid().nullable(),
-      roomId: z.string().uuid().nullable(),
-      taskBlockId: z.string().uuid(),
-      checklist: z.array(
-        z.object({
-          checklistItemId: z.string().uuid(),
-          name: z.string(),
-          isDone: z.boolean(),
-        }),
-      ),
     },
   },
 
-  usr: {
-    companies: {
-      companyId: z.string().uuid(),
+  act: {
+    activities: {
+      activityId: z.string().uuid(),
       name: z.string(),
-      ownerId: z.string().uuid(),
-      timezone: z.string(),
+      eventId: z.string().uuid(),
     },
-
-    confirmPins: {
-      transactionId: z.string().uuid(),
-      email: z.string().email(),
-      confirmPin: z.number().min(1000).max(9999),
-      createTime: z.string().datetime(),
-      wrongPinTries: z.number(),
+    activityRegs: {
+      activityRegId: z.string().uuid(),
+      activityId: z.string().uuid(),
+      peId: z.string().uuid(),
     },
-
-    userRefreshTokens: {
-      refreshToken: z.string(),
-      userId: z.string().uuid(),
+    peTypes: {
+      peTypeId: z.string().uuid(),
+      name: z.string(),
     },
-    users: {
+    activityPeTypes: {
+      activityId: z.string().uuid(),
+      peTypeId: z.string().uuid(),
+    },
+    partEntities: {
+      peId: z.string().uuid(),
+      peTypeId: z.string().uuid(),
+      eventId: z.string().uuid(),
+      ownerId: z.string().uuid(),
+    },
+    peMembers: {
+      peMemberId: z.string().uuid(),
+      peId: z.string().uuid(),
       userId: z.string().uuid(),
-      email: z.string().email(),
+    },
+    // fields
+    fieldValidators: {
+      validatorId: z.string(),
       name: z.string(),
-      password: z.string(),
-      wrongPassTries: z.number(),
+      fieldTypeId: z.string(),
+    },
+    fieldTypes: {
+      fieldTypeId: z.string(),
+      name: z.string(),
+    },
+    customFieldDefinitions: {
+      fieldId: z.string().uuid(),
+      name: z.string(),
+      fieldTypeId: z.string(),
+      validatorId: z.string().nullable(),
+      validatorValue: z.string().nullable(),
+      options: z.string().nullable(),
+      isRequired: z.boolean(),
+    },
+    activityRegFormFields: {
+      activityId: z.string().uuid(),
+      fieldId: z.string().uuid(),
+    },
+    arFieldValues: {
+      activityRegId: z.string().uuid(),
+      fieldId: z.string().uuid(),
+      value: z.string(),
+    },
+    pe_form_fields: {
+      peTypeId: z.string().uuid(),
+      fieldId: z.string().uuid(),
+    },
+    peFieldValues: {
+      peId: z.string().uuid(),
+      fieldId: z.string().uuid(),
+      value: z.string(),
     },
   },
 };

+ 1 - 1
src/main.ts

@@ -40,7 +40,7 @@ logger.info("Импорт роутеров...");
 import authMiddleware from "./middlewares/auth-middleware.js";
 
 // users-management
-import authRouter from "./modules/users-management/auth/routers/auth-router.js";
+import authRouter from "./modules/users/auth/routers/auth-router.js";
 app.use("/api/auth/", authRouter);
 
 // events-management

+ 1 - 1
src/middlewares/auth-middleware.ts

@@ -1,5 +1,5 @@
 import { ApiError } from "../exceptions/api-error.js";
-import tokenService from "#modules/users-management/auth/services/token-service.js";
+import tokenService from "#modules/users/auth/services/token-service.js";
 import type { NextFunction, Request, Response } from "express";
 import { logger } from "#plugins/logger.js";
 

+ 0 - 119
src/modules/companies-management/companies-router.ts

@@ -1,119 +0,0 @@
-// router
-import express from "express";
-const router = express.Router();
-export default router;
-
-// db
-import { selPool, updPool } from "#db";
-import { DbSchema } from "#db-schema";
-import { sql } from "slonik";
-
-// api
-import { CompaniesApi } from "#api";
-
-// error
-// import { ApiError } from "#exceptions/api-error.ts";
-
-// dayjs
-import dayjs from "dayjs";
-import utc from "dayjs/plugin/utc.js";
-dayjs.extend(utc);
-import timezone from "dayjs/plugin/timezone.js";
-dayjs.extend(timezone);
-
-// other
-import { z } from "zod";
-
-import { v7 as uuidv7 } from "uuid";
-// import { logger } from "#logger";
-import { UserUtils } from "#utils/user-utils.js";
-import { RouterUtils } from "#utils/router-utils.js";
-import { ApiError } from "#exceptions/api-error.js";
-import { CompaniesService } from "./companies-service.js";
-
-dayjs.extend(utc);
-
-// TODO: транзакции
-router.post("/company", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { name, timezone } = CompaniesApi.POST_Company.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    const companyId = uuidv7();
-
-    // company
-    await updPool.query(
-      sql.unsafe`
-      insert into usr.companies
-        (company_id, name, owner_id, timezone)
-      values
-        (${companyId}, ${name}, ${userId}, ${timezone})`,
-    );
-
-    RouterUtils.validAndSendResponse(CompaniesApi.POST_Company.res, res, {
-      code: "success",
-    });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.get("/user-companies", async (req, res, next) => {
-  try {
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    const companies = await selPool.any(
-      sql.type(
-        z.object({
-          companyId: DbSchema.usr.companies.companyId,
-          name: DbSchema.usr.companies.name,
-          timezone: DbSchema.usr.companies.timezone,
-        }),
-      )`
-        select
-          c.company_id as "companyId",
-          c."name",
-          c.timezone
-        from
-          usr.companies c
-        where
-          c.owner_id = ${userId}
-        `,
-    );
-
-    RouterUtils.validAndSendResponse(CompaniesApi.GET_UserCompanies.res, res, {
-      code: "success",
-      companies: [...companies],
-    });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.get("/company/:companyId", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { companyId } = CompaniesApi.GET_Company.req.parse(req.params);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    await CompaniesService.checkCompanyAccess(userId, companyId);
-
-    const company = await CompaniesService.getCompanyById(companyId);
-
-    if (!company) {
-      throw ApiError.BadRequest("Company not found", "Компания не найдена");
-    }
-
-    const events = await CompaniesService.getCompanyEvents(companyId);
-
-    RouterUtils.validAndSendResponse(CompaniesApi.GET_Company.res, res, {
-      code: "success",
-      company: { ...company, events: [...events] },
-    });
-  } catch (e) {
-    next(e);
-  }
-});

+ 0 - 104
src/modules/companies-management/companies-service.ts

@@ -1,104 +0,0 @@
-// types
-
-import { selPool } from "#db";
-import { sql } from "slonik";
-import { z } from "zod";
-import { DbSchema } from "#db/db-schema.js";
-import { ApiError } from "#exceptions/api-error.js";
-
-class companiesService {
-  async checkCompanyAccess(userId: string, companyId: string) {
-    const companyData = await selPool.maybeOne(
-      sql.type(
-        z.object({
-          name: DbSchema.usr.companies.name,
-          timezone: DbSchema.usr.companies.timezone,
-        }),
-      )`
-    select 
-      name,
-      timezone
-    from 
-      usr.companies
-    where
-      company_id = ${companyId} and
-      owner_id = ${userId}
-    limit 1
-      `,
-    );
-
-    if (!companyData) {
-      throw ApiError.ForbiddenError();
-    }
-
-    return {
-      comapnyId: companyId,
-      ownerId: userId,
-      name: companyData.name,
-      timezone: companyData.timezone,
-    };
-  }
-
-  async getCompanyEvents(companyId: string) {
-    const events = await selPool.any(
-      sql.type(
-        z.object({
-          eventId: DbSchema.ev.events.eventId,
-          localName: DbSchema.ev.events.localName,
-          timezone: DbSchema.ev.events.timezone,
-          companyId: DbSchema.ev.events.companyId,
-          dates: z.array(DbSchema.ev.eventDates.date),
-        }),
-      )`
-        SELECT
-          e.event_id as "eventId",
-          e.local_name as "localName",
-          e.timezone,
-          e.company_id as "companyId",
-          COALESCE(ARRAY_REMOVE(ARRAY_AGG(ed."date"), NULL), '{}') AS dates
-        FROM
-          ev.events e
-        LEFT JOIN
-          ev.event_dates ed
-        ON
-          e.event_id = ed.event_id
-        WHERE
-          e.company_id = ${companyId}
-        GROUP BY
-          e.event_id,
-          e.local_name,
-          e.timezone,
-          e.company_id;
-            `,
-    );
-
-    return events;
-  }
-
-  async getCompanyById(companyId: string) {
-    const company = await selPool.maybeOne(
-      sql.type(
-        z.object({
-          companyId: DbSchema.usr.companies.companyId,
-          name: DbSchema.usr.companies.name,
-          ownerId: DbSchema.usr.companies.ownerId,
-          timezone: DbSchema.usr.companies.timezone,
-        }),
-      )`
-        select
-          c.company_id as "companyId",
-          c."name",
-          c.owner_id as "ownerId",
-          c.timezone
-        from
-          usr.companies c
-        where
-          c.company_id = ${companyId}
-        `,
-    );
-
-    return company;
-  }
-}
-
-export const CompaniesService = new companiesService();

+ 0 - 403
src/modules/events-management/events-router.ts

@@ -1,403 +0,0 @@
-// router
-import express from "express";
-const router = express.Router();
-export default router;
-
-// db
-import { selPool, updPool } from "#db";
-import { DbSchema } from "#db-schema";
-import { sql } from "slonik";
-
-// api
-import { EventsManagementApi } from "#api";
-
-// error
-import { ApiError } from "#exceptions/api-error.ts";
-
-// dayjs
-import dayjs from "dayjs";
-import utc from "dayjs/plugin/utc.js";
-dayjs.extend(utc);
-import timezone from "dayjs/plugin/timezone.js";
-dayjs.extend(timezone);
-
-// other
-import { z } from "zod";
-
-import { v7 as uuidv7 } from "uuid";
-// import { logger } from "#logger";
-import { UserUtils } from "#utils/user-utils.js";
-import { RouterUtils } from "#utils/router-utils.js";
-import { CompaniesService } from "#modules/companies-management/companies-service.js";
-import { EventsService } from "./events-service.js";
-
-dayjs.extend(utc);
-
-router.post("/event", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { localName, dates, timezone, companyId } =
-      EventsManagementApi.POST_Event.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    const company = await CompaniesService.checkCompanyAccess(
-      userId,
-      companyId,
-    );
-
-    // если тз не указана, то ставим тз компании
-    let tz = timezone;
-    if (!tz) {
-      tz = company.timezone;
-    }
-    //
-
-    const eventId = uuidv7();
-
-    // создаём ивент
-    await updPool.query(
-      sql.unsafe`
-      insert into ev.events 
-        (event_id, local_name, timezone, company_id) 
-      values 
-        (${eventId}, ${localName}, ${tz}, ${companyId})`,
-    );
-
-    // вставляем даты ивента
-    for (const date of dates) {
-      await updPool.query(
-        sql.unsafe`
-        insert into ev.event_dates 
-          (event_id, date) 
-        values 
-          (${eventId}, ${date})`,
-      );
-    }
-
-    // менеджер
-    await updPool.query(
-      sql.unsafe`
-      insert into ev.event_managers 
-        (event_id, user_id) 
-      values 
-        (${eventId}, ${userId})`,
-    );
-
-    RouterUtils.validAndSendResponse(EventsManagementApi.POST_Event.res, res, {
-      code: "success",
-      eventId: eventId,
-    });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.get("/event/:eventId", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { eventId } = EventsManagementApi.GET_Event.req.parse(req.params);
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    await EventsService.checkEventAccess(userId, eventId);
-
-    // event
-    const event = await selPool.maybeOne(
-      sql.type(
-        z.object({
-          eventId: DbSchema.ev.events.eventId,
-          localName: DbSchema.ev.events.localName,
-          timezone: DbSchema.ev.events.timezone,
-          dates: z.array(DbSchema.ev.eventDates.date),
-        }),
-      )`
-          select
-            e.event_id as "eventId",
-            e.local_name as "localName",
-            e.timezone,
-            COALESCE(ARRAY_REMOVE(ARRAY_AGG(ed."date"), NULL), '{}') AS dates
-          from
-            ev.events e
-          left join ev.event_dates ed on
-            e.event_id = ed.event_id
-          where
-            e.event_id = ${eventId}
-          group by
-            e.event_id,
-            e.local_name,
-            e.timezone;
-        `,
-    );
-    if (!event) throw ApiError.BadRequest("EventNotFound", "Ивент не найден");
-
-    // points
-    const DbPointsType = DbSchema.ev.programPoints;
-    const programPoints = await selPool.any(
-      sql.type(
-        z.object({
-          programPointId: DbPointsType.programPointId,
-          name: DbPointsType.name,
-          startDate: DbPointsType.startDate,
-          endDate: DbPointsType.endDate,
-          roomId: DbPointsType.roomId,
-          isInternal: DbPointsType.isInternal,
-        }),
-      )`
-        select
-          program_point_id as "programPointId",
-          name,
-          start_date as "startDate",
-          end_date as "endDate",
-          room_id as "roomId",
-          is_internal as "isInternal"
-        from
-          ev.program_points
-        where
-          event_id = ${eventId}
-        `,
-    );
-
-    // rooms
-    const rooms = await selPool.any(
-      sql.type(
-        z.object({
-          roomId: DbSchema.ev.rooms.roomId,
-          name: DbSchema.ev.rooms.name,
-          locationId: DbSchema.ev.rooms.locationId,
-        }),
-      )`
-          select
-            r.room_id as "roomId", 
-            r.name, 
-            r.location_id as "locationId"
-          from
-            ev.rooms r
-          join ev.locations l on
-            l.location_id = r.location_id
-          where
-            l.event_id = ${eventId}
-          `,
-    );
-
-    // task-blocks
-    // TODO: вынести
-    const taskBlocks = await selPool.any(
-      sql.type(
-        z.object({
-          taskBlockId: DbSchema.ev.taskBlocks.taskBlockId,
-          name: DbSchema.ev.taskBlocks.name,
-        }),
-      )`
-        select
-          tb.task_block_id as "taskBlockId",
-          tb.name
-        from
-          ev.task_blocks tb
-        where
-          tb.event_id = ${eventId}
-        `,
-    );
-
-    const managers = await selPool.any(
-      sql.type(
-        z.object({
-          userId: DbSchema.ev.eventManagers.userId,
-          name: DbSchema.usr.users.name,
-          email: DbSchema.usr.users.email,
-        }),
-      )`
-        select
-          em.user_id as "userId",
-          u.name,
-          u.email
-        from 
-          ev.event_managers em
-        join
-          usr.users u on
-          em.user_id = u.user_id
-        where
-          em.event_id = ${eventId}
-        `,
-    );
-
-    const roles = await selPool.any(
-      sql.type(
-        z.object({
-          roleId: DbSchema.ev.roles.roleId,
-          name: DbSchema.ev.roles.name,
-        }),
-      )`
-        select
-          r.role_id as "roleId",
-          r.name
-        from
-          ev.roles r
-        where
-          r.event_id = ${eventId}
-        `,
-    );
-
-    // res
-    RouterUtils.validAndSendResponse(EventsManagementApi.GET_Event.res, res, {
-      code: "success",
-      event: {
-        ...event,
-        programPoints: [...programPoints],
-        rooms: [...rooms],
-        taskBlocks: [...taskBlocks],
-        managers: [...managers],
-        roles: [...roles],
-      },
-    });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/program-point", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { name, startDate, endDate, eventId, roomId, isInternal } =
-      EventsManagementApi.POST_ProgramPoint.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-    await EventsService.checkEventAccess(userId, eventId);
-
-    const programPointId = uuidv7();
-
-    await updPool.query(
-      sql.unsafe`
-        insert into ev.program_points
-          (program_point_id, name, start_date, end_date, room_id, event_id, is_internal)
-        values
-          (${programPointId}, ${name}, ${startDate}, ${endDate}, ${roomId}, ${eventId}, ${isInternal})
-      `,
-    );
-
-    RouterUtils.validAndSendResponse(
-      EventsManagementApi.POST_ProgramPoint.res,
-      res,
-      { code: "success", programPointId },
-    );
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.patch("/event", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { eventId, localName, dates, timezone, programPoint, role } =
-      EventsManagementApi.PATCH_Event.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-    await EventsService.checkEventAccess(userId, eventId);
-
-    // change localName, timezone
-    await updPool.query(
-      sql.unsafe`
-    update ev.events
-    set
-      ${sql.join(
-        [
-          localName
-            ? sql.unsafe`local_name = ${localName}`
-            : sql.unsafe`local_name = local_name`,
-
-          timezone
-            ? sql.unsafe`timezone = ${timezone}`
-            : sql.unsafe`timezone = timezone`,
-        ],
-        sql.fragment`, `,
-      )}
-    where
-      event_id = ${eventId}`,
-    );
-
-    // change dates
-    if (dates) {
-      await updPool.query(
-        sql.unsafe`
-        delete from ev.event_dates
-        where
-          event_id = ${eventId}`,
-      );
-
-      for (const date of dates) {
-        await updPool.query(
-          sql.unsafe`
-          insert into ev.event_dates 
-            (event_id, date) 
-          values 
-            (${eventId}, ${date})`,
-        );
-      }
-    }
-
-    // TODO: преверить безопасность pp и roles
-    if (programPoint) {
-      await updPool.query(
-        sql.unsafe`
-        update ev.program_points
-        set
-          name = ${programPoint.name},
-          start_date = ${programPoint.startDate},
-          end_date = ${programPoint.endDate},
-          room_id = ${programPoint.roomId}
-        where
-          program_point_id = ${programPoint.programPointId}`,
-      );
-    }
-
-    if (role) {
-      await updPool.query(
-        sql.unsafe`
-        update ev.roles
-        set
-          name = ${role.name}
-        where
-          role_id = ${role.roleId}`,
-      );
-    }
-
-    RouterUtils.validAndSendResponse(EventsManagementApi.PATCH_Event.res, res, {
-      code: "success",
-    });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/role", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { name, eventId } = EventsManagementApi.POST_Role.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-    await EventsService.checkEventAccess(userId, eventId);
-
-    const roleId = uuidv7();
-
-    // create role
-    await updPool.query(
-      sql.unsafe`
-      insert into ev.roles
-        (role_id, name, event_id)
-      values
-        (${roleId}, ${name}, ${eventId})`,
-    );
-
-    RouterUtils.validAndSendResponse(EventsManagementApi.POST_Role.res, res, {
-      code: "success",
-      roleId,
-    });
-  } catch (e) {
-    next(e);
-  }
-});

+ 0 - 86
src/modules/events-management/events-service.ts

@@ -1,86 +0,0 @@
-// types
-
-import { selPool } from "#db";
-import { sql } from "slonik";
-import { ApiError } from "#exceptions/api-error.js";
-import { DbSchema } from "#db/db-schema.js";
-import { z } from "zod";
-
-class eventsService {
-  async checkEventAccess(userId: string, eventId: string) {
-    const isExist = await selPool.exists(
-      sql.unsafe`
-      select 
-        1 
-      from 
-        ev.event_managers 
-      where
-        event_id = ${eventId} and
-        user_id = ${userId}
-        `,
-    );
-
-    if (!isExist) {
-      throw ApiError.ForbiddenError();
-    }
-
-    return true;
-  }
-
-  async getEventIdByOther({
-    taskBlockId,
-    taskId,
-  }: {
-    taskBlockId?: string;
-    taskId?: string;
-  }): Promise<string> {
-    if (taskBlockId) {
-      const eventId = await selPool.maybeOneFirst(
-        sql.type(z.object({ eventId: DbSchema.ev.taskBlocks.eventId }))`
-        select
-          event_id as "eventId"
-        from
-          ev.task_blocks
-        where
-          task_block_id = ${taskBlockId}
-        `,
-      );
-
-      if (!eventId) {
-        throw ApiError.BadRequest("TaskBlockNotFound", "TaskBlockNotFound");
-      }
-
-      return eventId;
-    }
-
-    if (taskId) {
-      const taskBlockId = await selPool.maybeOneFirst(
-        sql.type(z.object({ taskBlockId: DbSchema.ev.taskBlocks.taskBlockId }))`
-        select
-          task_block_id as "taskBlockId"
-        from
-          ev.tasks
-        where
-          task_id = ${taskId}
-        limit 1
-        `,
-      );
-
-      if (!taskBlockId)
-        throw ApiError.BadRequest("TaskNotFound", "TaskNotFound");
-
-      const eventId = this.getEventIdByOther({ taskBlockId });
-
-      if (!eventId) throw ApiError.BadRequest("TaskNotFound", "TaskNotFound");
-
-      return eventId;
-    }
-
-    throw ApiError.BadRequest(
-      "getEventIdByOther IncorrectParams",
-      "getEventIdByOther IncorrectParams",
-    );
-  }
-}
-
-export const EventsService = new eventsService();

+ 0 - 136
src/modules/locations-management/locations-router.ts

@@ -1,136 +0,0 @@
-// router
-import express from "express";
-const router = express.Router();
-export default router;
-
-// db
-import { selPool, updPool } from "#db";
-import { DbSchema } from "#db-schema";
-import { sql } from "slonik";
-
-// error
-// import { ApiError } from "#exceptions/api-error.ts";
-
-// dayjs
-import dayjs from "dayjs";
-import utc from "dayjs/plugin/utc.js";
-dayjs.extend(utc);
-import timezone from "dayjs/plugin/timezone.js";
-dayjs.extend(timezone);
-
-// other
-import { z } from "zod";
-
-import { v7 as uuidv7 } from "uuid";
-// import { logger } from "#logger";
-import { UserUtils } from "#utils/user-utils.js";
-import { LocationsManagementApi } from "#api";
-import { RouterUtils } from "#utils/router-utils.js";
-import { EventsService } from "#modules/events-management/events-service.js";
-
-dayjs.extend(utc);
-
-router.post("/location", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { name, eventId, rooms } =
-      LocationsManagementApi.POST_Location.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    await EventsService.checkEventAccess(userId, eventId);
-
-    const locationId = uuidv7();
-
-    // location
-    await updPool.query(
-      sql.unsafe`
-         insert into ev.locations
-           (location_id, name, event_id)
-         values
-           (${locationId}, ${name}, ${eventId})`,
-    );
-
-    // rooms
-    for (const room of rooms) {
-      const roomId = uuidv7();
-      await updPool.query(
-        sql.unsafe`
-          insert into ev.rooms
-            (room_id, location_id, name, parent_id)
-          values
-            (${roomId}, ${locationId}, ${room.name}, ${room.parentId})
-        `,
-      );
-    }
-
-    RouterUtils.validAndSendResponse(
-      LocationsManagementApi.POST_Location.res,
-      res,
-      {
-        code: "success",
-        locationId,
-      },
-    );
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.get("/event-locations/:eventId", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { eventId } = LocationsManagementApi.GET_EventLocations.req.parse(
-      req.params,
-    );
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    await EventsService.checkEventAccess(userId, eventId);
-
-    const locations = await selPool.any(
-      sql.type(
-        z.object({
-          locationId: DbSchema.ev.locations.locationId,
-          name: DbSchema.ev.locations.name,
-          rooms: z.array(
-            z.object({
-              roomId: DbSchema.ev.rooms.roomId,
-              name: DbSchema.ev.rooms.name,
-              parentId: DbSchema.ev.rooms.parentId,
-            }),
-          ),
-        }),
-      )` 
-        SELECT
-            l.location_id as "locationId",
-            l.name,
-            COALESCE(
-                json_agg(
-                    jsonb_build_object(
-                        'roomId', r.room_id,
-                        'name', r.name,
-                        'parentId', r.parent_id
-                    )
-                ) FILTER (WHERE r.room_id IS NOT NULL),
-                '[]'::json
-            ) AS rooms
-        FROM ev.locations l
-        LEFT JOIN ev.rooms r ON l.location_id = r.location_id
-        WHERE l.event_id = ${eventId}
-        GROUP BY l.location_id, l.name;
-              `,
-    );
-
-    RouterUtils.validAndSendResponse(
-      LocationsManagementApi.GET_EventLocations.res,
-      res,
-      {
-        code: "success",
-        locations: [...locations],
-      },
-    );
-  } catch (e) {
-    next(e);
-  }
-});

+ 142 - 0
src/modules/management/event/event-controller.ts

@@ -0,0 +1,142 @@
+// db
+import { selPool, updPool } from "#db";
+import { DbSchema } from "#db-schema";
+import { sql } from "slonik";
+
+// api
+import { EventsManagementApi } from "#api";
+
+// error
+import { ApiError } from "#exceptions/api-error.js";
+
+// // dayjs
+// import dayjs from "dayjs";
+// import utc from "dayjs/plugin/utc.js";
+// dayjs.extend(utc);
+// import timezone from "dayjs/plugin/timezone.js";
+// dayjs.extend(timezone);
+
+// other
+import { z } from "zod";
+import { Request, Response } from "express";
+
+import { v7 as uuidv7 } from "uuid";
+// import { logger } from "#logger";
+import { UserUtils } from "#utils/user-utils.js";
+import { RouterUtils } from "#utils/router-utils.js";
+import { PermService } from "#modules/users/auth/services/perms-service.js";
+
+class eventController {
+  async createEvent(req: Request, res: Response) {
+    // валидация запроса
+    const { localName, dates, timezone } =
+      EventsManagementApi.POST_Event.req.parse(req.body);
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    await PermService.checkObjPerm(userId, "", "event", "CREATE"); // TODO: Решить что делать с ивентом
+
+    const eventId = uuidv7();
+
+    // создаём ивент
+    await updPool.query(
+      sql.unsafe`
+      insert into ev.events 
+        (event_id, local_name, timezone) 
+      values 
+        (${eventId}, ${localName}, ${timezone})`,
+    );
+
+    // вставляем даты ивента
+    for (const date of dates) {
+      await updPool.query(
+        sql.unsafe`
+        insert into ev.event_dates 
+          (event_id, date) 
+        values 
+          (${eventId}, ${date})`,
+      );
+    }
+
+    RouterUtils.validAndSendResponse(EventsManagementApi.POST_Event.res, res, {
+      code: "success",
+      eventId: eventId,
+    });
+  }
+  async getEvent(req: Request, res: Response) {
+    // валидация запроса
+    const { eventId } = EventsManagementApi.GET_Event.req.parse(req.params);
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    await PermService.checkObjPerm(userId, eventId, "event", "READ");
+
+    const event = await selPool.maybeOne(
+      sql.type(
+        z.object({
+          eventId: DbSchema.ev.events.eventId,
+          localName: DbSchema.ev.events.localName,
+          timezone: DbSchema.ev.events.timezone,
+          dates: z.array(DbSchema.ev.eventDates.date),
+        }),
+      )`
+            select
+              e.event_id as "eventId",
+              e.local_name as "localName",
+              e.timezone,
+              COALESCE(ARRAY_REMOVE(ARRAY_AGG(ed."date"), NULL), '{}') AS dates
+            from
+              ev.events e
+            left join ev.event_dates ed on
+              e.event_id = ed.event_id
+            where
+              e.event_id = ${eventId}
+            group by
+              e.event_id,
+              e.local_name,
+              e.timezone;
+          `,
+    );
+    if (!event) throw ApiError.BadRequest("EventNotFound", "Ивент не найден");
+
+    RouterUtils.validAndSendResponse(EventsManagementApi.GET_Event.res, res, {
+      code: "success",
+      event: event,
+    });
+  }
+  async updateEvent(req: Request, res: Response) {}
+  async deleteEvent(req: Request, res: Response) {}
+  async createActivity(req: Request, res: Response) {
+    // валидация запроса
+    const { eventId, localName } = EventsManagementApi.POST_Activity.req.parse(
+      req.body,
+    );
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    await PermService.checkObjPerm(userId, eventId, "activity", "CREATE");
+
+    const activityId = uuidv7();
+
+    // создаём активность
+    await updPool.query(
+      sql.unsafe`
+      insert into ev.activities 
+        (activity_id, event_id, local_name) 
+      values 
+        (${activityId}, ${eventId}, ${localName})`,
+    );
+
+    RouterUtils.validAndSendResponse(
+      EventsManagementApi.POST_Activity.res,
+      res,
+      {
+        code: "success",
+        activityId: activityId,
+      },
+    );
+  }
+  async getActivity(req: Request, res: Response) {}
+  async updateActivity(req: Request, res: Response) {}
+  async deleteActivity(req: Request, res: Response) {}
+}
+export const EventController = new eventController();

+ 34 - 0
src/modules/management/event/event-router.ts

@@ -0,0 +1,34 @@
+import { RouterUtils } from "#utils/router-utils.js";
+
+import express from "express";
+import { EventController } from "./event-controller.js";
+const router = express.Router();
+export default router;
+
+router.post("/event", RouterUtils.asyncHandler(EventController.createEvent));
+
+router.get(
+  "/event/:eventId",
+  RouterUtils.asyncHandler(EventController.getEvent),
+);
+
+router.patch(
+  "/event/:eventId",
+  RouterUtils.asyncHandler(EventController.updateEvent),
+);
+
+router.delete(
+  "/event/:eventId",
+  RouterUtils.asyncHandler(EventController.deleteEvent),
+);
+
+router.post(
+  "/activity",
+  RouterUtils.asyncHandler(EventController.createActivity),
+);
+
+router.get("/activity/:activityId", RouterUtils.asyncHandler());
+
+router.patch("/activity/:activityId", RouterUtils.asyncHandler());
+
+router.delete("/activity/:activityId", RouterUtils.asyncHandler());

+ 0 - 195
src/modules/tasks-management/task-blocks-router.ts

@@ -1,195 +0,0 @@
-// router
-import express from "express";
-const router = express.Router();
-export default router;
-
-// db
-import { selPool, updPool } from "#db";
-import { sql } from "slonik";
-
-// api
-
-// error
-// import { ApiError } from "#exceptions/api-error.ts";
-
-// dayjs
-import dayjs from "dayjs";
-import utc from "dayjs/plugin/utc.js";
-dayjs.extend(utc);
-import timezone from "dayjs/plugin/timezone.js";
-dayjs.extend(timezone);
-
-import { v7 as uuidv7 } from "uuid";
-// import { logger } from "#logger";
-import { UserUtils } from "#utils/user-utils.js";
-import { RouterUtils } from "#utils/router-utils.js";
-import { TasksManagementApi } from "#api";
-import { EventsService } from "#modules/events-management/events-service.js";
-import { z } from "zod";
-import { DbSchema } from "#db/db-schema.js";
-import { ApiError } from "#exceptions/api-error.js";
-
-dayjs.extend(utc);
-
-router.post("/task-block", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { name, eventId } = TasksManagementApi.POST_TaskBlock.req.parse(
-      req.body,
-    );
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-    await EventsService.checkEventAccess(userId, eventId);
-
-    const blockId = uuidv7();
-
-    // create block
-    await updPool.query(
-      sql.unsafe`
-      insert into ev.task_blocks
-        (task_block_id, name, event_id)
-      values
-        (${blockId}, ${name}, ${eventId})`,
-    );
-
-    RouterUtils.validAndSendResponse(
-      TasksManagementApi.POST_TaskBlock.res,
-      res,
-      { code: "success" },
-    );
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.patch("/task-block", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { taskBlockId, name } = TasksManagementApi.PATCH_TaskBlock.req.parse(
-      req.body,
-    );
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    const eventId = await EventsService.getEventIdByOther({ taskBlockId });
-
-    await EventsService.checkEventAccess(userId, eventId);
-
-    await updPool.query(
-      sql.unsafe`
-      update ev.task_blocks
-      set
-        name = ${name}
-      where
-        task_block_id = ${taskBlockId}`,
-    );
-
-    RouterUtils.validAndSendResponse(
-      TasksManagementApi.PATCH_TaskBlock.res,
-      res,
-      { code: "success" },
-    );
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.get("/task-block/:taskBlockId", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const { taskBlockId } = TasksManagementApi.GET_TaskBlock.req.parse(
-      req.params,
-    );
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    const eventId = await EventsService.getEventIdByOther({ taskBlockId });
-
-    await EventsService.checkEventAccess(userId, eventId);
-
-    const taskBlock = await selPool.maybeOne(
-      sql.type(
-        z.object({
-          taskBlockId: DbSchema.ev.taskBlocks.taskBlockId,
-          name: DbSchema.ev.taskBlocks.name,
-        }),
-      )`
-    select
-      task_block_id as "taskBlockId",
-      name
-      from ev.task_blocks
-      where task_block_id = ${taskBlockId}
-    `,
-    );
-
-    if (!taskBlock) {
-      throw ApiError.BadRequest("Task block not found", "Task block not found");
-    }
-
-    const ZDbTasks = DbSchema.ev.tasks;
-    const tasks = await selPool.any(
-      sql.type(
-        z.object({
-          taskId: ZDbTasks.taskId,
-          name: ZDbTasks.name,
-          startDate: ZDbTasks.startDate,
-          endDate: ZDbTasks.endDate,
-          isTodo: ZDbTasks.isTodo,
-          accountableId: ZDbTasks.accountableId,
-          taskBlockId: ZDbTasks.taskBlockId,
-          programPointId: ZDbTasks.programPointId,
-          roomId: ZDbTasks.roomId,
-          executors: z.array(DbSchema.ev.taskExecutors.roleId),
-        }),
-      )`
-          select
-            t.task_id as "taskId",
-            t.name,
-            t.start_date as "startDate",
-            t.end_date as "endDate",
-            t.is_todo as "isTodo",
-            t.accountable_id as "accountableId",
-            t.task_block_id as "taskBlockId",
-            t.program_point_id as "programPointId",
-            t.room_id as "roomId",
-            coalesce(ARRAY_REMOVE(ARRAY_AGG(te.role_id),
-            null),
-            '{}') as executors
-          from
-            ev.tasks t
-            --	executors
-          left join ev.task_executors te on
-            t.task_id = te.task_id
-          where
-            t.task_block_id = ${taskBlockId}
-            -- для executors
-          group by
-            t.task_id,
-            t.name,
-            t.start_date,
-            t.end_date,
-            t.is_todo,
-            t.accountable_id,
-            t.task_block_id,
-            t.program_point_id,
-            t.room_id
-  `,
-    );
-
-    // res
-    RouterUtils.validAndSendResponse(
-      TasksManagementApi.GET_TaskBlock.res,
-      res,
-      {
-        code: "success",
-        taskBlockId: taskBlock.taskBlockId,
-        name: taskBlock.name,
-        tasks: [...tasks],
-      },
-    );
-  } catch (e) {
-    next(e);
-  }
-});

+ 0 - 167
src/modules/tasks-management/tasks-router.ts

@@ -1,167 +0,0 @@
-// router
-import express from "express";
-const router = express.Router();
-export default router;
-
-// db
-import { updPool } from "#db";
-import { sql } from "slonik";
-
-// api
-
-// error
-// import { ApiError } from "#exceptions/api-error.ts";
-
-// dayjs
-import dayjs from "dayjs";
-import utc from "dayjs/plugin/utc.js";
-dayjs.extend(utc);
-import timezone from "dayjs/plugin/timezone.js";
-dayjs.extend(timezone);
-
-import { v7 as uuidv7 } from "uuid";
-import { UserUtils } from "#utils/user-utils.js";
-import { RouterUtils } from "#utils/router-utils.js";
-import { TasksManagementApi } from "#api";
-import { EventsService } from "#modules/events-management/events-service.js";
-
-dayjs.extend(utc);
-
-router.post("/task", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const {
-      name,
-      startDate,
-      endDate,
-      isTodo,
-      taskBlockId,
-      programPointId,
-      executors,
-      roomId,
-      accountableId,
-    } = TasksManagementApi.POST_Task.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-    //
-
-    // проверка прав
-    const eventId = await EventsService.getEventIdByOther({ taskBlockId });
-    await EventsService.checkEventAccess(userId, eventId);
-    //
-
-    const taskId = uuidv7();
-
-    // create task
-    await updPool.query(
-      sql.unsafe`
-      insert into ev.tasks
-        (task_id, name, start_date, end_date, accountable_id, is_todo, task_block_id, program_point_id, room_id)
-      values
-        (${taskId}, ${name}, ${startDate}, ${endDate}, ${accountableId}, ${isTodo}, ${taskBlockId}, ${programPointId}, ${roomId})`,
-    );
-
-    // add executors
-    for (const executorId of executors) {
-      await updPool.query(
-        sql.unsafe`
-        insert into ev.task_executors
-          (task_id, role)
-        values
-          (${taskId}, ${executorId})`,
-      );
-    }
-
-    RouterUtils.validAndSendResponse(TasksManagementApi.POST_Task.res, res, {
-      code: "success",
-    });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.patch("/task", async (req, res, next) => {
-  try {
-    // валидация запроса
-    const {
-      taskId,
-      endDate,
-      startDate,
-      isTodo,
-      name,
-      programPointId,
-      executors,
-      roomId,
-      accountableId,
-    } = TasksManagementApi.PATCH_Task.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-    const eventId = await EventsService.getEventIdByOther({ taskId });
-    await EventsService.checkEventAccess(userId, eventId);
-
-    // edit task
-    await updPool.query(
-      sql.unsafe`
-      UPDATE ev.tasks
-      SET
-        ${sql.join(
-          [
-            name !== undefined
-              ? sql.fragment`name = ${name}`
-              : sql.fragment`name = name`,
-            startDate !== undefined
-              ? sql.fragment`start_date = ${startDate}`
-              : sql.fragment`start_date = start_date`,
-            endDate !== undefined
-              ? sql.fragment`end_date = ${endDate}`
-              : sql.fragment`end_date = end_date`,
-            isTodo !== undefined
-              ? sql.fragment`is_todo = ${isTodo}`
-              : sql.fragment`is_todo = is_todo`,
-            programPointId !== undefined
-              ? sql.fragment`program_point_id = ${programPointId}`
-              : sql.fragment`program_point_id = program_point_id`,
-            roomId !== undefined
-              ? sql.fragment`room_id = ${roomId}`
-              : sql.fragment`room_id = room_id`,
-            accountableId !== undefined
-              ? sql.fragment`accountable_id = ${accountableId}`
-              : sql.fragment`accountable_id = accountable_id`,
-          ],
-          sql.fragment`, `,
-        )}
-      WHERE task_id = ${taskId}
-      `,
-    );
-
-    if (executors && executors.length) {
-      // del executors
-      await updPool.query(
-        sql.unsafe`
-      delete from ev.task_executors
-      where
-        task_id = ${taskId}`,
-      );
-
-      // add executors
-      // TODO: вынести и слить с event-block
-      for (const executorId of executors) {
-        await updPool.query(
-          sql.unsafe`
-        insert into ev.task_executors
-          (task_id, role_id)
-        values
-          (${taskId}, ${executorId})`,
-        );
-      }
-    }
-
-    RouterUtils.validAndSendResponse(TasksManagementApi.PATCH_Task.res, res, {
-      code: "success",
-    });
-  } catch (e) {
-    next(e);
-  }
-});

+ 66 - 108
src/modules/users-management/auth/routers/auth-router.ts → src/modules/users/auth/routers/auth-controller.ts

@@ -1,8 +1,3 @@
-// router
-import express from "express";
-const router = express.Router();
-export default router;
-
 // db
 import { selPool, updPool } from "#db";
 import { DbSchema } from "#db-schema";
@@ -14,11 +9,6 @@ import { AuthApi } from "#api";
 // error
 import { ApiError } from "#exceptions/api-error.js";
 
-// dayjs
-import dayjs from "dayjs";
-import utc from "dayjs/plugin/utc.js";
-dayjs.extend(utc);
-
 // other
 import { z } from "zod";
 import bcript from "bcrypt";
@@ -26,21 +16,22 @@ import { v7 as uuidv7 } from "uuid";
 
 import tokenService from "../services/token-service.js";
 import { UserAuthService } from "../services/user-auth-service.js";
-import { ConfirmPinsService } from "#modules/users-management/confirm-pins/confirm-pins-service.js";
+import { ConfirmPinsService } from "#modules/users/confirm-pins/confirm-pins-service.js";
 import { RouterUtils } from "#utils/router-utils.js";
 import { config } from "#config";
-
-dayjs.extend(utc);
-
-router.post("/registration", async (req, res, next) => {
-  try {
+import { Request, Response } from "express";
+
+class authController {
+  // --- Регистрация ---
+  async register(
+    req: Request,
+    res: Response,
+    // next: NextFunction
+  ) {
     // валидация запроса
     const { email } = AuthApi.POST_Registration.req.parse(req.body);
 
-    // проверка на существование пользователя
-    const isUserExist = await selPool.exists(
-      sql.unsafe`select email from usr.users where email = ${email}`,
-    );
+    const isUserExist = await UserAuthService.checkUserExistByEmail(email);
 
     // если пользователь уже зарегистрирован
     if (isUserExist) {
@@ -72,14 +63,9 @@ router.post("/registration", async (req, res, next) => {
       code: "pinIsSent",
       transactionId: transactionId,
     });
-  } catch (e) {
-    next(e);
   }
-});
 
-// TODO добавить компанию
-router.post("/confirm-registration", async (req, res, next) => {
-  try {
+  async confirmRegistration(req: Request, res: Response) {
     // валидация запроса
     const { password, name, transactionId, confirmPin } =
       AuthApi.POST_ConfirmRegistration.req.parse(req.body);
@@ -90,40 +76,37 @@ router.post("/confirm-registration", async (req, res, next) => {
       confirmPin,
     );
 
-    // если пин протухший
-    if (pinInfo.status === "rotten") {
-      RouterUtils.validAndSendResponse(
-        AuthApi.POST_ConfirmRegistration.res,
-        res,
-        { code: "pinIsRotten" },
-        400,
-      );
-      return;
-    }
-
-    // слишком много попыток
-    if (pinInfo.status === "tooManyTries") {
-      RouterUtils.validAndSendResponse(
-        AuthApi.POST_ConfirmRegistration.res,
-        res,
-        { code: "tooManyTries" },
-        400,
-      );
-      return;
-    }
-
-    // неправильный
-    if (pinInfo.status === "wrong") {
-      RouterUtils.validAndSendResponse(
-        AuthApi.POST_ConfirmRegistration.res,
-        res,
-        {
-          code: "pinIsWrong",
-          triesRemained: pinInfo.triesRemained,
-        },
-        400,
-      );
-      return;
+    switch (pinInfo.status) {
+      case "rotten": {
+        RouterUtils.validAndSendResponse(
+          AuthApi.POST_ConfirmRegistration.res,
+          res,
+          { code: "pinIsRotten" },
+          400,
+        );
+        return;
+      }
+      case "tooManyTries": {
+        RouterUtils.validAndSendResponse(
+          AuthApi.POST_ConfirmRegistration.res,
+          res,
+          { code: "tooManyTries" },
+          400,
+        );
+        return;
+      }
+      case "wrong": {
+        RouterUtils.validAndSendResponse(
+          AuthApi.POST_ConfirmRegistration.res,
+          res,
+          {
+            code: "pinIsWrong",
+            triesRemained: pinInfo.triesRemained,
+          },
+          400,
+        );
+        return;
+      }
     }
 
     // пин правильный
@@ -133,10 +116,10 @@ router.post("/confirm-registration", async (req, res, next) => {
     const userId = uuidv7();
     await updPool.query(
       sql.unsafe`
-      insert into usr.users 
-        (user_id, email, name, password) 
-      values 
-        (${userId}, ${email}, ${name}, ${hashPassword})`,
+          insert into usr.users 
+            (user_id, email, name, password) 
+          values 
+            (${userId}, ${email}, ${name}, ${hashPassword})`,
     );
 
     // токены
@@ -146,11 +129,7 @@ router.post("/confirm-registration", async (req, res, next) => {
     });
     await tokenService.insertRefreshToken(userId, refreshToken);
 
-    res.cookie("refreshToken", refreshToken, {
-      maxAge: 30 * 24 * 60 * 60 * 1000, //30d
-      httpOnly: true, //запрет на изменение пользователем
-      // secure: true, //после включения https
-    });
+    tokenService.setRefreshTokenInCookie(res, refreshToken);
 
     RouterUtils.validAndSendResponse(
       AuthApi.POST_ConfirmRegistration.res,
@@ -158,20 +137,15 @@ router.post("/confirm-registration", async (req, res, next) => {
       {
         code: "registered",
         accessToken,
-        refreshToken,
         userData: {
           email,
           userId,
         },
       },
     );
-  } catch (e) {
-    next(e);
   }
-});
 
-router.post("/login", async (req, res, next) => {
-  try {
+  async login(req: Request, res: Response) {
     // валидация запроса
     const { email, password } = AuthApi.POST_Login.req.parse(req.body);
 
@@ -184,14 +158,14 @@ router.post("/login", async (req, res, next) => {
           wrongPassTries: DbSchema.usr.users.wrongPassTries,
         }),
       )`
-      select 
-        user_id as "userId", 
-        password, 
-        wrong_pass_tries as "wrongPassTries"
-      from 
-        usr.users 
-      where 
-        email = ${email}`,
+     select 
+       user_id as "userId", 
+       password, 
+       wrong_pass_tries as "wrongPassTries"
+     from 
+       usr.users 
+     where 
+       email = ${email}`,
     );
     if (!user) {
       RouterUtils.validAndSendResponse(
@@ -247,11 +221,8 @@ router.post("/login", async (req, res, next) => {
       userId: user.userId,
     });
     await tokenService.insertRefreshToken(user.userId, refreshToken);
-    res.cookie("refreshToken", refreshToken, {
-      maxAge: 30 * 24 * 60 * 60 * 1000, //30d
-      httpOnly: true, //запрет на изменение пользователем
-      // secure: true, //после включения https
-    });
+
+    tokenService.setRefreshTokenInCookie(res, refreshToken);
 
     RouterUtils.validAndSendResponse(
       AuthApi.POST_Login.res,
@@ -259,17 +230,13 @@ router.post("/login", async (req, res, next) => {
       {
         code: "success",
         accessToken,
-        refreshToken,
         userData: { email, userId: user.userId },
       },
       200,
     );
-  } catch (e) {
-    next(e);
   }
-});
-router.post("/logout", async (req, res, next) => {
-  try {
+
+  async logout(req: Request, res: Response) {
     const { refreshToken } = req.cookies;
 
     const userData = tokenService.validateRefreshToken(refreshToken);
@@ -280,13 +247,9 @@ router.post("/logout", async (req, res, next) => {
     RouterUtils.validAndSendResponse(AuthApi.POST_Logout.res, res, {
       code: "success",
     });
-  } catch (e) {
-    next(e);
   }
-});
 
-router.post("/logoutAllDevices", async (req, res, next) => {
-  try {
+  async logoutAllDevices(req: Request, res: Response) {
     const { refreshToken } = req.cookies;
 
     const userData = tokenService.validateRefreshToken(refreshToken);
@@ -297,13 +260,9 @@ router.post("/logoutAllDevices", async (req, res, next) => {
     RouterUtils.validAndSendResponse(AuthApi.POST_LogoutAllDevices.res, res, {
       code: "success",
     });
-  } catch (e) {
-    next(e);
   }
-});
 
-router.get("/refresh", async (req, res, next) => {
-  try {
+  async refresh(req: Request, res: Response) {
     const { refreshToken } = req.cookies;
 
     if (!refreshToken) throw ApiError.UnauthorizedError();
@@ -346,13 +305,12 @@ router.get("/refresh", async (req, res, next) => {
       code: "success",
 
       accessToken: newTokens.accessToken,
-      refreshToken: newTokens.refreshToken,
       userData: {
         email: newUserData.email,
         userId: userData.userId,
       },
     });
-  } catch (e) {
-    next(e);
   }
-});
+}
+
+export const AuthController = new authController();

+ 23 - 0
src/modules/users/auth/routers/auth-router.ts

@@ -0,0 +1,23 @@
+import { RouterUtils } from "#utils/router-utils.js";
+import { AuthController } from "./auth-controller.js";
+
+import express from "express";
+const router = express.Router();
+export default router;
+
+router.post("/registration", RouterUtils.asyncHandler(AuthController.register));
+
+router.post(
+  "/confirm-registration",
+  RouterUtils.asyncHandler(AuthController.confirmRegistration),
+);
+
+router.post("/login", RouterUtils.asyncHandler(AuthController.login));
+router.post("/logout", RouterUtils.asyncHandler(AuthController.logout));
+
+router.post(
+  "/logoutAllDevices",
+  RouterUtils.asyncHandler(AuthController.logoutAllDevices),
+);
+
+router.get("/refresh", RouterUtils.asyncHandler(AuthController.refresh));

+ 42 - 0
src/modules/users/auth/services/perms-service.ts

@@ -0,0 +1,42 @@
+// types
+
+import { ApiError } from "#exceptions/api-error.js";
+import { selPool } from "#db";
+import { sql } from "slonik";
+import { z } from "zod";
+
+class permService {
+  private cachedUserPerms = new Set<string>();
+
+  async cacheUsersPerms() {
+    const perms = await selPool.anyFirst(
+      sql.type(
+        z.object({
+          user_perms: z.string(),
+        }),
+      )`select user_perms from usr.get_user_perms()`,
+    );
+
+    this.cachedUserPerms = new Set(perms);
+  }
+
+  async checkObjPerm(
+    userId: string,
+    eventId: string,
+    objectName: string,
+    permission: "READ" | "CREATE" | "CHANGE",
+  ) {
+    const permString =
+      `${userId}|${eventId}|${objectName}|${permission}`.toLowerCase();
+
+    const isFound = this.cachedUserPerms.has(permString);
+
+    if (!isFound) {
+      throw ApiError.ForbiddenError();
+    }
+
+    return true;
+  }
+}
+
+export const PermService = new permService();

+ 0 - 0
src/modules/users-management/auth/services/session-service.ts → src/modules/users/auth/services/session-service.ts


+ 2 - 1
src/modules/users-management/auth/services/token-service.ts → src/modules/users/auth/services/token-service.ts

@@ -158,9 +158,10 @@ class TokenService {
    */
   setRefreshTokenInCookie(res: Response, token: string) {
     res.cookie("refreshToken", token, {
-      maxAge: config.REFRESH_TOKEN_LIFETIME_DAYS * 24 * 60 * 60 * 1000, //в миллисекундах
+      maxAge: config.REFRESH_TOKEN_LIFETIME_DAYS * 24 * 60 * 60 * 1000,
       httpOnly: true, //запрет на изменение пользователем
       // secure: true, //после включения https
+      sameSite: "lax", // TODO: Разбраться
     });
   }
 }

+ 7 - 1
src/modules/users-management/auth/services/user-auth-service.ts → src/modules/users/auth/services/user-auth-service.ts

@@ -1,8 +1,14 @@
 // db
-import { updPool } from "#db/db.js";
+import { selPool, updPool } from "#db/db.js";
 import { sql } from "slonik";
 
 class userAuthService {
+  async checkUserExistByEmail(email: string) {
+    return await selPool.exists(
+      sql.unsafe`select email from usr.users where email = ${email}`,
+    );
+  }
+
   async authTriesIncrement(userId: string) {
     await updPool.query(
       sql.unsafe`

+ 0 - 0
src/modules/users-management/auth/services/user-registration-service.ts → src/modules/users/auth/services/user-registration-service.ts


+ 0 - 0
src/modules/users-management/auth/types/token-playload-type.ts → src/modules/users/auth/types/token-playload-type.ts


+ 0 - 0
src/modules/users-management/confirm-pins/confirm-pins-service.ts → src/modules/users/confirm-pins/confirm-pins-service.ts


+ 8 - 1
src/utils/router-utils.ts

@@ -1,4 +1,4 @@
-import { Response } from "express";
+import { NextFunction, RequestHandler, Response, Request } from "express";
 import { z } from "zod";
 
 class routerUtils {
@@ -19,6 +19,13 @@ class routerUtils {
     const response = ZResType.parse(resData);
     Response.status(status).json(response);
   }
+
+  // Вспомогательная функция для обработки async маршрутов
+  asyncHandler(fn: RequestHandler) {
+    return (req: Request, res: Response, next: NextFunction) => {
+      Promise.resolve(fn(req, res, next)).catch(next);
+    };
+  }
 }
 
 export const RouterUtils = new routerUtils();

+ 1 - 1
src/utils/user-utils.ts

@@ -1,6 +1,6 @@
 import type { Request } from "express";
 // types
-import { TokenPayload } from "#modules/users-management/auth/types/token-playload-type.js";
+import { TokenPayload } from "#modules/users/auth/types/token-playload-type.js";
 
 import { ApiError } from "#exceptions/api-error.js";