Browse Source

откат

Vadim 7 months ago
parent
commit
869c8f4340
39 changed files with 2459 additions and 1623 deletions
  1. 222 2
      package-lock.json
  2. 1 0
      package.json
  3. 29 23
      src/api/auth-api.ts
  4. 33 0
      src/api/companies-management-api.ts
  5. 0 26
      src/api/company-manager-api.ts
  6. 0 241
      src/api/event-manager-api.ts
  7. 114 0
      src/api/events-management-api.ts
  8. 67 0
      src/api/locations-management-api.ts
  9. 102 0
      src/api/tasks-management-api.ts
  10. 0 36
      src/db/db-interrceptor.ts
  11. 76 0
      src/db/db-interrceptors.ts
  12. 1 2
      src/db/db-service.ts
  13. 119 54
      src/db/db-shema.ts
  14. 8 3
      src/db/db.ts
  15. 18 4
      src/main.ts
  16. 1 1
      src/middlewares/auth-middleware.ts
  17. 0 66
      src/modules/company/company-router.ts
  18. 19 0
      src/modules/entities-management/entityes-service.ts
  19. 0 859
      src/modules/event-manager/event-manager-router.ts
  20. 120 0
      src/modules/events-management/companies-router.ts
  21. 483 0
      src/modules/events-management/events-router.ts
  22. 238 0
      src/modules/locations-management/locations-router.ts
  23. 39 0
      src/modules/permissions-management/check-permissions-service.ts
  24. 74 0
      src/modules/permissions-management/permissions-types.ts
  25. 173 0
      src/modules/tasks-management/task-blocks-router.ts
  26. 248 0
      src/modules/tasks-management/tasks-router.ts
  27. 0 23
      src/modules/user/auth/services/user-auth-service.ts
  28. 89 109
      src/modules/users-management/auth/routers/auth-router.ts
  29. 2 2
      src/modules/users-management/auth/services/session-service.ts
  30. 11 5
      src/modules/users-management/auth/services/token-service.ts
  31. 31 0
      src/modules/users-management/auth/services/user-auth-service.ts
  32. 0 0
      src/modules/users-management/auth/services/user-registration-service.ts
  33. 0 0
      src/modules/users-management/auth/types/token-playload-type.ts
  34. 43 26
      src/modules/users-management/confirm-pins/confirm-pins-service.ts
  35. 40 27
      src/plugins/logger.ts
  36. 32 0
      src/plugins/logger_old.ts
  37. 2 2
      src/services/mail-service.ts
  38. 22 14
      src/utils/router-utils.ts
  39. 2 98
      src/utils/user-utils.ts

+ 222 - 2
package-lock.json

@@ -22,6 +22,7 @@
         "pg": "^8.11.3",
         "slonik": "^37.2.0",
         "uuid": "^10.0.0",
+        "winston": "^3.17.0",
         "zod": "^3.22.4"
       },
       "devDependencies": {
@@ -55,6 +56,26 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/@colors/colors": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
+      "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.1.90"
+      }
+    },
+    "node_modules/@dabh/diagnostics": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
+      "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
+      "license": "MIT",
+      "dependencies": {
+        "colorspace": "1.1.x",
+        "enabled": "2.0.x",
+        "kuler": "^2.0.0"
+      }
+    },
     "node_modules/@esbuild/aix-ppc64": {
       "version": "0.19.11",
       "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz",
@@ -912,6 +933,12 @@
         "@types/node": "*"
       }
     },
+    "node_modules/@types/triple-beam": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
+      "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==",
+      "license": "MIT"
+    },
     "node_modules/@types/uuid": {
       "version": "10.0.0",
       "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
@@ -1396,6 +1423,12 @@
         "node": ">=8"
       }
     },
+    "node_modules/async": {
+      "version": "3.2.6",
+      "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+      "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+      "license": "MIT"
+    },
     "node_modules/balanced-match": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1618,6 +1651,16 @@
         "node": ">=10"
       }
     },
+    "node_modules/color": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+      "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^1.9.3",
+        "color-string": "^1.6.0"
+      }
+    },
     "node_modules/color-convert": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -1633,8 +1676,17 @@
     "node_modules/color-name": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-      "dev": true
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/color-string": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "^1.0.0",
+        "simple-swizzle": "^0.2.2"
+      }
     },
     "node_modules/color-support": {
       "version": "1.1.3",
@@ -1644,6 +1696,31 @@
         "color-support": "bin.js"
       }
     },
+    "node_modules/color/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/color/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+      "license": "MIT"
+    },
+    "node_modules/colorspace": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
+      "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
+      "license": "MIT",
+      "dependencies": {
+        "color": "^3.1.3",
+        "text-hex": "1.0.x"
+      }
+    },
     "node_modules/concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -1909,6 +1986,12 @@
       "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
       "dev": true
     },
+    "node_modules/enabled": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
+      "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
+      "license": "MIT"
+    },
     "node_modules/encodeurl": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@@ -2278,6 +2361,12 @@
         "reusify": "^1.0.4"
       }
     },
+    "node_modules/fecha": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
+      "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
+      "license": "MIT"
+    },
     "node_modules/file-entry-cache": {
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -2389,6 +2478,12 @@
       "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz",
       "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ=="
     },
+    "node_modules/fn.name": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
+      "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
+      "license": "MIT"
+    },
     "node_modules/foreground-child": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
@@ -2890,6 +2985,12 @@
         "node": ">= 0.10"
       }
     },
+    "node_modules/is-arrayish": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+      "license": "MIT"
+    },
     "node_modules/is-binary-path": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@@ -2949,6 +3050,18 @@
         "node": ">=8"
       }
     },
+    "node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/isarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -3075,6 +3188,12 @@
         "json-buffer": "3.0.1"
       }
     },
+    "node_modules/kuler": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
+      "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
+      "license": "MIT"
+    },
     "node_modules/levn": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -3180,6 +3299,29 @@
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
     },
+    "node_modules/logform": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
+      "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@colors/colors": "1.6.0",
+        "@types/triple-beam": "^1.3.2",
+        "fecha": "^4.2.0",
+        "ms": "^2.1.1",
+        "safe-stable-stringify": "^2.3.1",
+        "triple-beam": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      }
+    },
+    "node_modules/logform/node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "license": "MIT"
+    },
     "node_modules/lru-cache": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -3543,6 +3685,15 @@
         "wrappy": "1"
       }
     },
+    "node_modules/one-time": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
+      "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
+      "license": "MIT",
+      "dependencies": {
+        "fn.name": "1.x.x"
+      }
+    },
     "node_modules/optionator": {
       "version": "0.9.3",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@@ -4244,6 +4395,15 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
+    "node_modules/simple-swizzle": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+      "license": "MIT",
+      "dependencies": {
+        "is-arrayish": "^0.3.1"
+      }
+    },
     "node_modules/simple-update-notifier": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
@@ -4359,6 +4519,15 @@
         "node": ">= 10.x"
       }
     },
+    "node_modules/stack-trace": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+      "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/stacktrace-parser": {
       "version": "0.1.10",
       "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz",
@@ -4591,6 +4760,12 @@
         "node": ">=10"
       }
     },
+    "node_modules/text-hex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
+      "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
+      "license": "MIT"
+    },
     "node_modules/text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -4634,6 +4809,15 @@
       "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
       "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
     },
+    "node_modules/triple-beam": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
+      "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14.0.0"
+      }
+    },
     "node_modules/ts-api-utils": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
@@ -4862,6 +5046,42 @@
         "node": ">=8"
       }
     },
+    "node_modules/winston": {
+      "version": "3.17.0",
+      "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz",
+      "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==",
+      "license": "MIT",
+      "dependencies": {
+        "@colors/colors": "^1.6.0",
+        "@dabh/diagnostics": "^2.0.2",
+        "async": "^3.2.3",
+        "is-stream": "^2.0.0",
+        "logform": "^2.7.0",
+        "one-time": "^1.0.0",
+        "readable-stream": "^3.4.0",
+        "safe-stable-stringify": "^2.3.1",
+        "stack-trace": "0.0.x",
+        "triple-beam": "^1.3.0",
+        "winston-transport": "^4.9.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      }
+    },
+    "node_modules/winston-transport": {
+      "version": "4.9.0",
+      "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
+      "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
+      "license": "MIT",
+      "dependencies": {
+        "logform": "^2.7.0",
+        "readable-stream": "^3.6.2",
+        "triple-beam": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 12.0.0"
+      }
+    },
     "node_modules/wrap-ansi": {
       "version": "8.1.0",
       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",

+ 1 - 0
package.json

@@ -39,6 +39,7 @@
     "pg": "^8.11.3",
     "slonik": "^37.2.0",
     "uuid": "^10.0.0",
+    "winston": "^3.17.0",
     "zod": "^3.22.4"
   },
   "devDependencies": {

+ 29 - 23
src/api/auth-api.ts

@@ -3,10 +3,11 @@ import { z } from "zod";
 class authApi {
   // /auth/registration
   public ZRegistration = {
-    req: z.object({
-      email: z.string().email(),
-      password: z.string(),
-    }),
+    req: z
+      .object({
+        email: z.string().email(),
+      })
+      .strict(),
     res: z.object({
       code: z.enum(["pinIsSent", "pinIsNotSent", "alreadyExists"]),
       transactionId: z.string().uuid().optional(),
@@ -15,33 +16,38 @@ class authApi {
 
   // /auth/confirm-registration
   public ZConfirmRegistration = {
-    req: z.object({
-      email: z.string().email(),
-      password: z.string(),
-      transactionId: z.string().uuid(),
-      confirmPin: z.number().min(1000).max(9999),
-      timezone: z.string(),
-    }),
-    res: z.object({
-      code: z.enum(["registered", "pinIsWrong", "pinIsRotten", "tooManyTries"]),
-      triesRemained: z.number().optional(),
-      userData: z
-        .object({
+    req: z
+      .object({
+        password: z.string(),
+        name: z.string(),
+        transactionId: z.string().uuid(),
+        confirmPin: z.number().min(1000).max(9999),
+      })
+      .strict(),
+    res: z.discriminatedUnion("code", [
+      z.object({
+        code: z.literal("registered"),
+        userData: z.object({
           accessToken: z.string(),
           refreshToken: z.string(),
           email: z.string().email(),
           userId: z.string(),
-        })
-        .optional(),
-    }),
+        }),
+      }),
+      z.object({ code: z.literal("pinIsWrong"), triesRemained: z.number() }),
+      z.object({ code: z.literal("pinIsRotten") }),
+      z.object({ code: z.literal("tooManyTries") }),
+    ]),
   };
 
   // /auth/login
   public ZLogin = {
-    req: z.object({
-      email: z.string().email(),
-      password: z.string(),
-    }),
+    req: z
+      .object({
+        email: z.string().email(),
+        password: z.string(),
+      })
+      .strict(),
     res: z.object({
       code: z.enum(["userNotFound", "passIsWrong", "tooManyTries", "success"]),
       triesRemained: z.number().optional(),

+ 33 - 0
src/api/companies-management-api.ts

@@ -0,0 +1,33 @@
+import { z } from "zod";
+
+class companyManagementApi {
+  // /companies-management/create-company
+  public ZCreateCompany = {
+    req: z
+      .object({
+        name: z.string(),
+        timezone: z.string(),
+      })
+      .strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+    }),
+  };
+
+  // /companies-management/get-companies
+  public ZGetUserCompanies = {
+    res: z.object({
+      code: z.enum(["success"]),
+      companies: z.array(
+        z.object({
+          company_id: z.string(),
+          name: z.string(),
+          owner_id: z.string(),
+          timezone: z.string(),
+        }),
+      ),
+    }),
+  };
+}
+
+export const CompanyManagementApi = new companyManagementApi();

+ 0 - 26
src/api/company-manager-api.ts

@@ -1,26 +0,0 @@
-import { z } from "zod";
-
-class companyManagerApi {
-  public ZAddCompany = {
-    req: z.object({
-      name: z.string(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  public ZGetUserCompanies = {
-    res: z.object({
-      code: z.enum(["success"]),
-      companies: z.array(
-        z.object({
-          company_id: z.string(),
-          name: z.string(),
-        }),
-      ),
-    }),
-  };
-}
-
-export const CompanyManagerApi = new companyManagerApi();

+ 0 - 241
src/api/event-manager-api.ts

@@ -1,241 +0,0 @@
-import { z } from "zod";
-
-class eventManagerApi {
-  // /event/create-event
-  ZCreateEvent = {
-    req: z.object({
-      name: z.string(),
-      timezone: z.string().optional(),
-      dates: z.array(z.string()),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-      event_id: z.string(),
-    }),
-  };
-
-  ZGetEventList = {
-    req: z.object({}),
-    res: z.object({
-      code: z.enum(["success"]),
-      events: z.array(
-        z.object({
-          event_id: z.string(),
-          local_name: z.string(),
-          timezone: z.string(),
-          dates: z.array(z.string()),
-        }),
-      ),
-    }),
-  };
-
-  ZGetEvent = {
-    req: z.object({ eventId: z.string() }),
-    res: z.object({
-      code: z.enum(["success"]),
-      event: z.object({
-        event_id: z.string(),
-        local_name: z.string(),
-        timezone: z.string(),
-        dates: z.array(z.string()),
-        programPoints: z.array(
-          z.object({
-            point_id: z.string(),
-            name: z.string(),
-            date_start: z.date(),
-            date_end: z.date(),
-            room_id: z.string().nullable(),
-            is_internal: z.boolean(),
-          }),
-        ),
-
-        rooms: z.array(
-          z.object({
-            room_id: z.string(),
-            name: z.string(),
-          }),
-        ),
-      }),
-    }),
-  };
-
-  // /event/get-month-events
-  // ZGetMonthEvents = {
-  //   req: z.object({
-  //     month: z.number().min(0).max(11),
-  //     year: z.number(),
-  //     timezone: z.string(),
-  //   }),
-  //   res: z.object({
-  //     code: z.enum(["success"]),
-  //     events: z.array(
-  //       z.object({
-  //         event_id: z.string(),
-  //         local_name: z.string(),
-  //         date_start: z.date(),
-  //         date_end: z.date(),
-  //         timezone: z.string(),
-  //       }),
-  //     ),
-  //   }),
-  // };
-
-  // /event/add-program-point
-  ZAddProgramPoint = {
-    req: z.object({
-      eventId: z.string(),
-      name: z.string(),
-      dateStart: z.string(),
-      dateEnd: z.string(),
-      roomId: z.string().optional(),
-      isInternal: z.boolean(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  // /event/add-user-room
-  ZAddUserRoom = {
-    req: z.object({
-      name: z.string(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  // /event/add-user-room
-  ZGetUserRooms = {
-    // req: z.object({
-    //   permission: z.enum(["creator", "editor", "viewer"]),
-    // }),
-
-    res: z.object({
-      code: z.enum(["success"]),
-      rooms: z.array(
-        z.object({
-          room_id: z.string(),
-          name: z.string(),
-          permission: z.enum(["editor", "viewer"]),
-        }),
-      ),
-    }),
-  };
-
-  ZUpdateEvent = {
-    req: z.object({
-      eventId: z.string(),
-      name: z.string(),
-      timezone: z.string(),
-      dates: z.array(z.string()),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  ZUpdateProgramPoint = {
-    req: z.object({
-      pointId: z.string(),
-      name: z.string(),
-      dateStart: z.string(),
-      dateEnd: z.string(),
-      roomId: z.string().optional(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  ZAddTaskBlock = {
-    req: z.object({
-      eventId: z.string(),
-      name: z.string(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  ZUpdateTaskBlock = {
-    req: z.object({
-      taskBlockId: z.string(),
-      name: z.string(),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  ZGetTaskBlocks = {
-    req: z.object({ eventId: z.string() }),
-    res: z.object({
-      code: z.enum(["success"]),
-      taskBlocks: z.array(
-        z.object({
-          task_block_id: z.string(),
-          name: z.string(),
-        }),
-      ),
-    }),
-  };
-
-  ZAddTask = {
-    req: z.object({
-      name: z.string(),
-      dateStart: z.string().nullable(),
-      dateEnd: z.string().nullable(),
-      ownerId: z.string(),
-      isTodo: z.boolean(),
-      taskBlockId: z.string(),
-      pointId: z.string().nullable(),
-      roomId: z.string().nullable(),
-      executors: z.array(z.string()),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  ZUpdateTask = {
-    req: z.object({
-      taskId: z.string(),
-      name: z.string(),
-      dateStart: z.string().nullable(),
-      dateEnd: z.string().nullable(),
-      ownerId: z.string(),
-      isTodo: z.boolean(),
-      taskBlockId: z.string(),
-      pointId: z.string().nullable(),
-      roomId: z.string().nullable(),
-      executors: z.array(z.string()),
-    }),
-    res: z.object({
-      code: z.enum(["success"]),
-    }),
-  };
-
-  ZGetBlockTasks = {
-    req: z.object({ taskBlockId: z.string() }),
-    res: z.object({
-      code: z.enum(["success"]),
-      tasks: z.array(
-        z.object({
-          task_id: z.string(),
-          name: z.string(),
-          date_start: z.date().nullable(),
-          date_end: z.date().nullable(),
-          owner_id: z.string(),
-          is_todo: z.boolean(),
-          task_block_id: z.string(),
-          point_id: z.string().nullable(),
-          room_id: z.string().nullable(),
-          executors: z.array(z.string()),
-        }),
-      ),
-    }),
-  };
-}
-
-export const EventManagerApi = new eventManagerApi();

+ 114 - 0
src/api/events-management-api.ts

@@ -0,0 +1,114 @@
+import { z } from "zod";
+
+class eventsManagementApi {
+  ZGetCompanyEvents = {
+    req: z
+      .object({
+        companyId: z.string(),
+      })
+      .strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+      events: z.array(
+        z.object({
+          event_id: z.string(),
+          local_name: z.string(),
+          timezone: z.string(),
+          dates: z.array(z.date()),
+        }),
+      ),
+    }),
+  };
+
+  ZCreateEvent = {
+    req: z
+      .object({
+        localName: z.string(),
+        timezone: z.string().optional(),
+        dates: z.array(z.string()),
+        companyId: z.string(),
+      })
+      .strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+      event_id: z.string(),
+    }),
+  };
+
+  ZGetEvent = {
+    req: z.object({ eventId: z.string() }).strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+      event: z.object({
+        event_id: z.string(),
+        local_name: z.string(),
+        timezone: z.string(),
+        dates: z.array(z.date()),
+        programPoints: z.array(
+          z.object({
+            program_point_id: z.string(),
+            name: z.string(),
+            start_date: z.date(),
+            end_date: z.date(),
+            room_id: z.string().nullable(),
+            is_internal: z.boolean(),
+          }),
+        ),
+
+        rooms: z.array(
+          z.object({
+            room_id: z.string(),
+            name: z.string(),
+          }),
+        ),
+      }),
+    }),
+  };
+
+  ZCreateProgramPoint = {
+    req: z
+      .object({
+        eventId: z.string(),
+        name: z.string(),
+        startDate: z.string(),
+        endDate: z.string(),
+        roomId: z.string().optional(),
+        isInternal: z.boolean(),
+      })
+      .strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+    }),
+  };
+
+  ZUpdateEvent = {
+    req: z
+      .object({
+        eventId: z.string(),
+        localName: z.string().optional(),
+        timezone: z.string().optional(),
+        dates: z.array(z.string()).optional(),
+      })
+      .strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+    }),
+  };
+
+  ZUpdateProgramPoint = {
+    req: z
+      .object({
+        programPointId: z.string(),
+        name: z.string(),
+        startDate: z.string(),
+        endDate: z.string(),
+        roomId: z.string().optional(),
+      })
+      .strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+    }),
+  };
+}
+
+export const EventsManagementApi = new eventsManagementApi();

+ 67 - 0
src/api/locations-management-api.ts

@@ -0,0 +1,67 @@
+import { z } from "zod";
+
+class locationsManagementApi {
+  ZCreateLocation = {
+    req: z
+      .object({
+        name: z.string(),
+        companyId: z.string(),
+      })
+      .strict(),
+
+    res: z.object({
+      code: z.enum(["success"]),
+    }),
+  };
+
+  ZGetCompanyLocations = {
+    req: z
+      .object({
+        companyId: z.string(),
+      })
+      .strict(),
+
+    res: z.object({
+      code: z.enum(["success"]),
+      locations: z.array(
+        z.object({
+          location_id: z.string(),
+          name: z.string(),
+        }),
+      ),
+    }),
+  };
+
+  ZCreateRoom = {
+    req: z
+      .object({
+        name: z.string(),
+        locationId: z.string(),
+      })
+      .strict(),
+
+    res: z.object({
+      code: z.enum(["success"]),
+    }),
+  };
+
+  ZGetLocationRooms = {
+    req: z
+      .object({
+        locationId: z.string(),
+      })
+      .strict(),
+
+    res: z.object({
+      code: z.enum(["success"]),
+      rooms: z.array(
+        z.object({
+          room_id: z.string(),
+          name: z.string(),
+        }),
+      ),
+    }),
+  };
+}
+
+export const LocationsManagementApi = new locationsManagementApi();

+ 102 - 0
src/api/tasks-management-api.ts

@@ -0,0 +1,102 @@
+import { z } from "zod";
+
+class tasksManagementApi {
+  ZCreateTaskBlock = {
+    req: z
+      .object({
+        eventId: z.string(),
+        name: z.string(),
+      })
+      .strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+    }),
+  };
+
+  ZUpdateTaskBlock = {
+    req: z
+      .object({
+        taskBlockId: z.string(),
+        name: z.string(),
+      })
+      .strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+    }),
+  };
+
+  ZGetEventTaskBlocks = {
+    req: z.object({ eventId: z.string() }).strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+      taskBlocks: z.array(
+        z.object({
+          task_block_id: z.string(),
+          name: z.string(),
+        }),
+      ),
+    }),
+  };
+
+  ZCreateTask = {
+    req: z
+      .object({
+        name: z.string(),
+        startDate: z.string().nullable(),
+        endDate: z.string().nullable(),
+        accountableId: z.string().nullable(),
+        isTodo: z.boolean(),
+        programPointId: z.string().nullable(),
+        roomId: z.string().nullable(),
+        taskBlockId: z.string(),
+        executors: z.array(z.string()),
+      })
+      .strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+    }),
+  };
+
+  ZUpdateTask = {
+    req: z
+      .object({
+        taskId: z.string(),
+
+        name: z.string().optional(),
+        startDate: z.string().nullable().optional(),
+        endDate: z.string().nullable().optional(),
+        accountableId: z.string().nullable().optional(),
+        isTodo: z.boolean().optional(),
+        programPointId: z.string().nullable().optional(),
+        roomId: z.string().nullable().optional(),
+        executors: z.array(z.string()).optional(),
+      })
+      .strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+    }),
+  };
+
+  ZGetBlockTasks = {
+    req: z.object({ taskBlockId: z.string() }).strict(),
+    res: z.object({
+      code: z.enum(["success"]),
+      tasks: z.array(
+        z.object({
+          task_id: z.string(),
+          name: z.string(),
+          start_date: z.date().nullable(),
+          end_date: z.date().nullable(),
+          accountable_id: z.string().nullable(),
+          is_todo: z.boolean(),
+          program_point_id: z.string().nullable(),
+          room_id: z.string().nullable(),
+          task_block_id: z.string(),
+          executors: z.array(z.string()),
+        }),
+      ),
+    }),
+  };
+}
+
+export const TasksManagementApi = new tasksManagementApi();

+ 0 - 36
src/db/db-interrceptor.ts

@@ -1,36 +0,0 @@
-import {
-  type Interceptor,
-  type QueryResultRow,
-  SchemaValidationError,
-} from "slonik";
-
-import { logger } from "../plugins/logger.js";
-
-export const createResultParserInterceptor = (): Interceptor => {
-  return {
-    // If you are not going to transform results using Zod, then you should use `afterQueryExecution` instead.
-    // Future versions of Zod will provide a more efficient parser when parsing without transformations.
-    // You can even combine the two – use `afterQueryExecution` to validate results, and (conditionally)
-    // transform results as needed in `transformRow`.
-    transformRow: (executionContext, actualQuery, row) => {
-      const { resultParser } = executionContext;
-      logger.trace("Запрос: ", { actualQuery, row });
-
-      if (!resultParser) {
-        return row;
-      }
-
-      const validationResult = resultParser.safeParse(row);
-
-      if (!validationResult.success) {
-        throw new SchemaValidationError(
-          actualQuery,
-          row,
-          validationResult.error.issues,
-        );
-      }
-
-      return validationResult.data as QueryResultRow;
-    },
-  };
-};

+ 76 - 0
src/db/db-interrceptors.ts

@@ -0,0 +1,76 @@
+import {
+  type Interceptor,
+  type QueryResultRow,
+  SchemaValidationError,
+  type QueryContext,
+  type Query,
+} from "slonik";
+
+import { logger } from "../plugins/logger.js";
+
+export const createResultParserInterceptor = (): Interceptor => {
+  return {
+    // If you are not going to transform results using Zod, then you should use `afterQueryExecution` instead.
+    // Future versions of Zod will provide a more efficient parser when parsing without transformations.
+    // You can even combine the two – use `afterQueryExecution` to validate results, and (conditionally)
+    // transform results as needed in `transformRow`.
+    // TODO заменить на afterQueryExecution
+    transformRow: (executionContext, actualQuery, row) => {
+      const { resultParser } = executionContext;
+      logger.silly("Запрос: ", { actualQuery, row });
+
+      if (!resultParser) {
+        return row;
+      }
+
+      const validationResult = resultParser.safeParse(row);
+
+      if (!validationResult.success) {
+        throw new SchemaValidationError(
+          actualQuery,
+          row,
+          validationResult.error.issues,
+        );
+      }
+
+      return validationResult.data as QueryResultRow;
+    },
+  };
+};
+
+interface ExtendedQueryContext extends QueryContext {
+  callerStack?: string;
+}
+
+export const createErrorLoggingInterceptor = (): Interceptor => {
+  return {
+    transformQuery: (executionContext: ExtendedQueryContext, query: Query) => {
+      // Сохраняем стек вызовов для отладки.
+      executionContext.callerStack =
+        new Error().stack || "No stack trace available";
+      return query;
+    },
+    queryExecutionError: (
+      executionContext: ExtendedQueryContext,
+      actualQuery: Query,
+      error: Error,
+    ) => {
+      const callerStack = executionContext.callerStack || "No stack";
+
+      // Создаем новое исключение с дополнительной информацией.
+      const enhancedError = new Error(
+        `
+        Query failed: ${actualQuery.sql}
+        Parameters: ${JSON.stringify(actualQuery.values)}
+        Caller stack: ${callerStack}
+        Original error: ${error.message}
+      `.trim(),
+      );
+
+      // Сохраняем оригинальную ошибку как причину (если поддерживается).
+      (enhancedError as Error & { cause?: Error }).cause = error;
+
+      throw enhancedError;
+    },
+  };
+};

+ 1 - 2
src/db/db-service.ts

@@ -6,7 +6,6 @@ import { ZDbShema } from "./db-shema.js";
 import { logger } from "#logger";
 
 // база данных
-
 class DbService {
   async checkDbShema() {
     const dbColumns = await db.any(sql.type(
@@ -36,7 +35,7 @@ class DbService {
             c.column_name;
         `);
 
-    logger.trace("Текущая бд: ", dbColumns, "Необходимая БД: ", ZDbShema);
+    logger.silly("Текущая бд: ", dbColumns, "Необходимая БД: ", ZDbShema);
 
     // перебор схем
     for (const shema in ZDbShema) {

+ 119 - 54
src/db/db-shema.ts

@@ -1,66 +1,49 @@
 import { z } from "zod";
 
 const ZDbShema = {
-  users: {
-    user_profiles: {
-      user_id: z.string(),
-      email: z.string().email(),
-      password: z.string(),
-      wrong_pass_tries: z.number(),
-      timezone: z.string(),
-    },
-
-    user_confirm_pins: {
-      transaction_id: z.string(),
-      email: z.string().email(),
-      confirm_pin: z.number().min(1000).max(9999),
-      create_time: z.date(),
-      wrong_pin_tries: z.number(),
-    },
-  },
-
-  event_manager: {
+  events_management: {
     events: {
       event_id: z.string(),
       local_name: z.string(),
       timezone: z.string(),
-      dates: z.array(z.string()),
+      company_id: z.string(),
+    },
+
+    companies: {
+      company_id: z.string(),
+      name: z.string(),
+      owner_id: z.string(),
+      timezone: z.string(),
     },
 
-    event_permissions: {
-      permission_id: z.number(),
+    event_dates: {
       event_id: z.string(),
-      user_id: z.string(),
-      permission: z.enum(["editor", "viewer"]),
+      date: z.date(),
     },
 
     program_points: {
-      point_id: z.string(),
+      program_point_id: z.string(),
       name: z.string().min(1),
-      date_start: z.date(),
-      date_end: z.date(),
-      room_id: z.string().nullable(),
+      start_date: z.date(),
+      end_date: z.date(),
       event_id: z.string(),
+      room_id: z.string().nullable(),
+      group: z.string(),
       is_internal: z.boolean(),
     },
-
-    rooms: {
-      room_id: z.string(),
-      name: z.string(),
-    },
   },
 
-  task_manager: {
+  tasks_management: {
     tasks: {
       task_id: z.string(),
       name: z.string(),
-      date_start: z.date().nullable(),
-      date_end: z.date().nullable(),
-      owner_id: z.string(),
+      start_date: z.date().nullable(),
+      end_date: z.date().nullable(),
+      accountable_id: z.string().nullable(),
       is_todo: z.boolean(),
-      task_block_id: z.string(),
-      point_id: z.string().nullable(),
+      program_point_id: z.string().nullable(),
       room_id: z.string().nullable(),
+      task_block_id: z.string(),
     },
 
     task_blocks: {
@@ -69,32 +52,114 @@ const ZDbShema = {
       event_id: z.string(),
     },
 
-    task_block_permissions: {
-      task_block_permission_id: z.number(),
-      task_block_id: z.string(),
-      user_id: z.string(),
-      permission: z.enum(["editor", "viewer"]),
-    },
-
     task_executors: {
-      task_executor_id: z.string(),
       task_id: z.string(),
       user_id: z.string(),
     },
   },
 
-  company_manager: {
-    companies: {
+  locations_management: {
+    locations: {
+      location_id: z.string(),
+      name: z.string(),
       company_id: z.string(),
+    },
+
+    rooms: {
+      room_id: z.string(),
       name: z.string(),
-      owner_id: z.string(),
+      location_id: z.string(),
     },
 
-    company_permissions: {
-      company_permission_id: z.string(),
-      company_id: z.string(),
+    event_locations: {
+      event_id: z.string(),
+      location_id: z.string(),
+    },
+  },
+
+  users_management: {
+    users: {
+      user_id: z.string(),
+      email: z.string().email(),
+      name: z.string(),
+      password: z.string(),
+      wrong_pass_tries: z.number(),
+    },
+
+    user_refresh_tokens: {
+      refresh_token: z.string(),
+      user_id: z.string(),
+    },
+
+    confirm_pins: {
+      transaction_id: z.string(),
+      email: z.string().email(),
+      confirm_pin: z.number().min(1000).max(9999),
+      create_time: z.date(),
+      wrong_pin_tries: z.number(),
+    },
+  },
+
+  permissions_management: {
+    user_roles: {
       user_id: z.string(),
-      permission: z.enum(["editor", "viewer"]),
+      role_id: z.string(),
+    },
+
+    role_entity_permission: {
+      role_id: z.string(),
+      entity_id: z.string(),
+      permission_id: z.string(),
+      permission_value_id: z.string(),
+      is_preset: z.boolean(),
+    },
+
+    roles: {
+      role_id: z.string(),
+      name: z.string(),
+      description: z.string(),
+      entity_id: z.string().nullable(),
+      entity_type_id: z.string(),
+      is_default: z.boolean(),
+    },
+
+    permissions: {
+      permission_id: z.string(),
+      name: z.string(),
+      entity_type_id: z.string(),
+    },
+
+    permission_values: {
+      permission_value_id: z.string(),
+      permission_id: z.string(),
+      name: z.string(),
+      is_default: z.boolean(),
+      parent_id: z.string().nullable(),
+    },
+
+    cached_user_permissions: {
+      user_id: z.string(),
+      entity_id: z.string(),
+      permission_id: z.string(),
+      permission_value_id: z.string(),
+    },
+
+    default_roles_permissions: {
+      role_id: z.string(),
+      permission_id: z.string(),
+      permission_value_id: z.string(),
+    },
+  },
+
+  entities_management: {
+    entities: {
+      entity_id: z.string(),
+      entity_type_id: z.string(),
+    },
+
+    entity_types: {
+      entity_type_id: z.string(),
+      name: z.string(),
     },
   },
 };

+ 8 - 3
src/db/db.ts

@@ -1,6 +1,8 @@
 import { createPool } from "slonik";
-
-import { createResultParserInterceptor } from "./db-interrceptor.js";
+import {
+  createErrorLoggingInterceptor,
+  createResultParserInterceptor,
+} from "./db-interrceptors.js";
 
 const host = process.env.DB_HOST;
 const port = process.env.DB_PORT;
@@ -11,7 +13,10 @@ const databaseName = process.env.DB_NAME;
 const pool = await createPool(
   `postgres://${user}:${password}@${host}:${port}/${databaseName}`,
   {
-    interceptors: [createResultParserInterceptor()],
+    interceptors: [
+      createResultParserInterceptor(),
+      createErrorLoggingInterceptor(),
+    ],
     typeParsers: [
       {
         name: "int8",

+ 18 - 4
src/main.ts

@@ -37,11 +37,25 @@ app.use((req, res, next) => {
 // роутеры
 import authMiddleware from "./middlewares/auth-middleware.js";
 
-import authRouter from "./modules/user/auth/routers/auth-router.js";
+// users-management
+import authRouter from "./modules/users-management/auth/routers/auth-router.js";
 app.use("/api/auth/", authRouter);
 
-import EventManagerRouter from "./modules/event-manager/event-manager-router.js";
-app.use("/api/event-manager/", authMiddleware(), EventManagerRouter);
+// events-management
+import CompaniesRouter from "./modules/events-management/companies-router.js";
+app.use("/api/events-management/", authMiddleware(), CompaniesRouter);
+import EventsRouter from "./modules/events-management/events-router.js";
+app.use("/api/events-management/", authMiddleware(), EventsRouter);
+
+// locations-management
+import LocationsRouter from "./modules/locations-management/locations-router.js";
+app.use("/api/locations-management/", authMiddleware(), LocationsRouter);
+
+// tasks-management
+import TasksRouter from "./modules/tasks-management/tasks-router.js";
+app.use("/api/tasks-management/", authMiddleware(), TasksRouter);
+import TaskBlocksRouter from "./modules/tasks-management/task-blocks-router.js";
+app.use("/api/tasks-management/", authMiddleware(), TaskBlocksRouter);
 
 // import sessionRouter from "./modules/user/routers/session-router.js";
 // app.use("/api/session/", sessionRouter);
@@ -60,7 +74,7 @@ const start = async () => {
 
     app.listen(PORT, () => logger.info(`Сервер запущен на порту ${PORT}`));
   } catch (e) {
-    logger.fatal(e);
+    logger.error(e);
   }
 };
 

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

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

+ 0 - 66
src/modules/company/company-router.ts

@@ -1,66 +0,0 @@
-// router
-import express from "express";
-const router = express.Router();
-export default router;
-
-// db
-import { db } from "#db";
-import { ZDbShema } from "#db-shema";
-import { sql } from "slonik";
-
-// api
-import { CompanyManagerApi } from "#api/company-manager-api.ts";
-
-// 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";
-
-dayjs.extend(utc);
-
-router.post("/add-company", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = CompanyManagerApi.ZAddCompany.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const { name } = CompanyManagerApi.ZAddCompany.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    const companyId = uuidv7();
-
-    // company
-    await db.query(
-      sql.unsafe`
-      insert into users.companies
-        (company_id, name, owner_id)
-      values
-        (${companyId}, ${name}, ${userId})`,
-    );
-
-    sendRes(200, { code: "success" });
-  } catch (e) {
-    next(e);
-  }
-});

+ 19 - 0
src/modules/entities-management/entityes-service.ts

@@ -0,0 +1,19 @@
+import { db } from "#db/db.js";
+import { sql } from "slonik";
+
+class entityesService {
+  async createEntity(
+    entityId: string,
+    entityTypeId: "company" | "event" | "task_block" | "task",
+  ) {
+    await db.query(
+      sql.unsafe`
+      insert into entity_management.entities 
+        (entity_id, entity_type_id)
+      values 
+        (${entityId}, ${entityTypeId})`,
+    );
+  }
+}
+
+export const EntityesService = new entityesService();

+ 0 - 859
src/modules/event-manager/event-manager-router.ts

@@ -1,859 +0,0 @@
-// router
-import express from "express";
-const router = express.Router();
-export default router;
-
-// db
-import { db } from "#db";
-import { ZDbShema } from "#db-shema";
-import { sql } from "slonik";
-
-// api
-import { EventManagerApi } from "#api/event-manager-api.ts";
-
-// 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";
-
-dayjs.extend(utc);
-
-router.post("/create-event", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZCreateEvent.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const { name, dates, timezone } = EventManagerApi.ZCreateEvent.req.parse(
-      req.body,
-    );
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // если тз не указана, то ставим тз пользователя
-    let tz = timezone;
-    if (!tz) {
-      const userTz = (
-        await db.one(
-          sql.type(
-            z.object({ timezone: ZDbShema.users.user_profiles.timezone }),
-          )`select timezone from users.user_profiles where user_id = ${userId}`,
-        )
-      ).timezone;
-
-      tz = userTz;
-    }
-    //
-
-    const eventId = uuidv7();
-
-    // event
-    await db.query(
-      sql.unsafe`
-      insert into event_manager.events 
-        (event_id, local_name, timezone, dates) 
-      values 
-        (${eventId}, ${name}, ${tz}, ${JSON.stringify(dates)})`,
-    );
-
-    // permission
-    await db.query(
-      sql.unsafe`
-      insert into event_manager.event_permissions 
-        (event_id, user_id, permission) 
-      values 
-        (${eventId}, ${userId}, 'creator')`,
-    );
-
-    sendRes(200, { code: "success", event_id: eventId });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/get-event-list", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZGetEventList.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-    // TODO сделать проверку на юзера
-    // const userId = UserUtils.getUserFromReq(req).userId;
-    // const userTz = (
-    //   await db.one(
-    //     sql.type(
-    //       z.object({ timezone: ZDbShema.users.user_profiles.timezone }),
-    //     )`select timezone from users.user_profiles where user_id = ${userId}`,
-    //   )
-    // ).timezone;
-
-    const nowWithUzerTz = dayjs.utc().startOf("day");
-
-    const DbEventsTypes = ZDbShema.event_manager.events;
-    const events = await db.any(
-      sql.type(
-        z.object({
-          event_id: DbEventsTypes.event_id,
-          local_name: DbEventsTypes.event_id,
-          timezone: DbEventsTypes.timezone,
-          dates: DbEventsTypes.dates,
-        }),
-      )`
-      select
-        event_id,
-        local_name,
-        timezone,
-        dates
-      from
-        event_manager.events
-      where
-        exists (
-          select
-          from
-            jsonb_array_elements_text(dates)
-          where
-            value::date >= ${nowWithUzerTz.toISOString()}
-        )
-        `,
-    );
-
-    sendRes(200, { code: "success", events: [...events] });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/get-event", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZGetEvent.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const { eventId } = EventManagerApi.ZGetEvent.req.parse(req.body);
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-    await UserUtils.checkEventPermissions(eventId, userId, "viewer");
-
-    // event
-    const DbEventsTypes = ZDbShema.event_manager.events;
-    const event = await db.maybeOne(
-      sql.type(
-        z.object({
-          event_id: DbEventsTypes.event_id,
-          local_name: DbEventsTypes.local_name,
-          timezone: DbEventsTypes.timezone,
-          dates: DbEventsTypes.dates,
-        }),
-      )`
-      select
-        event_id,
-        local_name,
-        timezone,
-        dates
-      from
-        event_manager.events
-      where 
-        event_id = ${eventId}
-        `,
-    );
-
-    if (!event) throw ApiError.BadRequest("EventNotFound", "Ивент не найден");
-
-    // points
-    const DbPointsType = ZDbShema.event_manager.program_points;
-    const programPoints = await db.any(
-      sql.type(
-        z.object({
-          point_id: DbPointsType.point_id,
-          name: DbPointsType.name,
-          date_start: DbPointsType.date_start,
-          date_end: DbPointsType.date_end,
-          room_id: DbPointsType.room_id,
-          is_internal: DbPointsType.is_internal,
-        }),
-      )`
-        select
-          point_id,
-          name,
-          date_start,
-          date_end,
-          room_id,
-          is_internal
-        from
-          event_manager.program_points pp
-        where
-          pp.event_id = ${eventId}
-        `,
-    );
-
-    //
-    const eventRoomsIds = new Set<string>();
-
-    for (const point of programPoints) {
-      if (point.room_id) eventRoomsIds.add(point.room_id);
-    }
-    //
-    // rooms
-    const eventRoomsIdsArr = Array.from(eventRoomsIds);
-    let rooms: readonly {
-      name: string;
-      room_id: string;
-    }[] = [];
-
-    // TODO ошибка в in?
-    if (eventRoomsIdsArr.length > 0) {
-      console.log(1);
-
-      rooms = await db.any(
-        sql.type(
-          z.object({
-            room_id: ZDbShema.event_manager.rooms.room_id,
-            name: ZDbShema.event_manager.rooms.name,
-          }),
-        )`
-          select
-            room_id, name
-          from
-            event_manager.rooms
-          where
-            room_id in (${sql.join(eventRoomsIdsArr, sql.fragment`, `)})
-          `,
-      );
-    }
-
-    // res
-    sendRes(200, {
-      code: "success",
-      event: {
-        ...event,
-        programPoints: [...programPoints],
-        rooms: [...rooms],
-      },
-    });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/add-program-point", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZAddProgramPoint.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const { name, dateStart, dateEnd, eventId, roomId, isInternal } =
-      EventManagerApi.ZAddProgramPoint.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-    await UserUtils.checkEventPermissions(eventId, userId, "editor");
-
-    const pointId = uuidv7();
-
-    // event
-    await db.query(
-      sql.unsafe`
-        insert into event_manager.program_points
-          (point_id, name, date_start, date_end, room_id, event_id, is_internal)
-        values
-          (${pointId}, ${name}, ${dateStart}, ${dateEnd}, ${roomId || null}, ${eventId}, ${isInternal})
-      `,
-    );
-
-    sendRes(200, { code: "success" });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/add-user-room", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZAddUserRoom.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const { name } = EventManagerApi.ZAddUserRoom.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    const roomId = uuidv7();
-
-    await db.query(
-      sql.unsafe`
-      insert into event_manager.rooms 
-        (room_id, name) 
-      values 
-        (${roomId}, ${name})`,
-    );
-
-    await db.query(
-      sql.unsafe`
-      insert into event_manager.room_user_permissions 
-        (user_id, room_id, permission) 
-      values 
-        (${userId}, ${roomId}, 'creator')`,
-    );
-
-    sendRes(200, { code: "success" });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/get-user-rooms", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZGetUserRooms.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    // const { permission } = EventManagerApi.ZGetUserRooms.req.parse(req.body);
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    const permissions = ["viewer", "editor"];
-
-    const rooms = await db.any(
-      sql.type(
-        z.object({
-          room_id: ZDbShema.event_manager.rooms.room_id,
-          name: ZDbShema.event_manager.rooms.name,
-          permission: ZDbShema.event_manager.event_permissions.permission,
-        }),
-      )`
-      select
-        r.room_id,
-        r."name",
-        rup."permission"
-      from
-        event_manager.rooms r
-      join event_manager.room_user_permissions rup on
-        r.room_id = rup.room_id
-      where
-        rup.user_id = ${userId}
-        and rup.permission in (${sql.join(permissions, sql.fragment`, `)})
-        `,
-    );
-
-    // res
-    sendRes(200, {
-      code: "success",
-      rooms: [...rooms],
-    });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/update-event", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZUpdateEvent.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const { eventId, name, dates, timezone } =
-      EventManagerApi.ZUpdateEvent.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-    await UserUtils.checkEventPermissions(eventId, userId, "editor");
-
-    // event
-    await db.query(
-      sql.unsafe`
-      update event_manager.events
-      set
-        local_name = ${name},
-        timezone = ${timezone},
-        dates = ${JSON.stringify(dates)}
-      where
-        event_id = ${eventId}`,
-    );
-
-    sendRes(200, { code: "success" });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/update-program-point", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZUpdateProgramPoint.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const { pointId, name, dateStart, dateEnd, roomId } =
-      EventManagerApi.ZUpdateProgramPoint.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    const eventId = await db.maybeOneFirst(
-      sql.type(
-        z.object({
-          event_id: ZDbShema.event_manager.events.event_id,
-        }),
-      )`
-      select
-        event_id
-      from
-        event_manager.program_points
-      where 
-        point_id = ${pointId}
-      `,
-    );
-
-    if (!eventId) {
-      throw ApiError.BadRequest("Point not found", "Point not found");
-    }
-
-    // проверка прав
-    await UserUtils.checkEventPermissions(eventId, userId, "editor");
-
-    // point
-    await db.query(
-      sql.unsafe`
-      update event_manager.program_points
-      set
-        name = ${name},
-        date_start = ${dateStart},
-        date_end = ${dateEnd},
-        room_id = ${roomId || null}
-      where
-        point_id = ${pointId}`,
-    );
-
-    sendRes(200, { code: "success" });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/add-task-block", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZAddTaskBlock.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const { name, eventId } = EventManagerApi.ZAddTaskBlock.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-    await UserUtils.checkEventPermissions(eventId, userId, "editor");
-
-    const blockId = uuidv7();
-
-    // block
-    await db.query(
-      sql.unsafe`
-      insert into task_manager.task_blocks
-        (task_block_id, name, event_id)
-      values
-        (${blockId}, ${name}, ${eventId})`,
-    );
-
-    sendRes(200, { code: "success" });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/update-task-block", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZUpdateTaskBlock.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const { taskBlockId, name } = EventManagerApi.ZUpdateTaskBlock.req.parse(
-      req.body,
-    );
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    const eventId = await db.maybeOneFirst(
-      sql.type(
-        z.object({
-          event_id: ZDbShema.event_manager.events.event_id,
-        }),
-      )`
-      select
-        event_id
-      from
-        task_manager.task_blocks
-      where 
-        task_block_id = ${taskBlockId}
-      `,
-    );
-
-    if (!eventId) {
-      throw ApiError.BadRequest("Block not found", "Block not found");
-    }
-
-    // проверка прав
-    await UserUtils.checkEventPermissions(eventId, userId, "editor");
-
-    // block
-    await db.query(
-      sql.unsafe`
-      update task_manager.task_blocks
-      set
-        name = ${name}
-      where
-        task_block_id = ${taskBlockId}`,
-    );
-
-    sendRes(200, { code: "success" });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/get-task-blocks", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZGetTaskBlocks.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const { eventId } = EventManagerApi.ZGetTaskBlocks.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-    await UserUtils.checkEventPermissions(eventId, userId, "viewer");
-
-    const taskBlocks = await db.any(
-      sql.type(
-        z.object({
-          task_block_id: ZDbShema.task_manager.task_blocks.task_block_id,
-          name: ZDbShema.task_manager.task_blocks.name,
-        }),
-      )`
-        select
-          task_block_id,
-          name
-        from
-          task_manager.task_blocks
-        where
-          event_id = ${eventId}
-        `,
-    );
-
-    // res
-    sendRes(200, {
-      code: "success",
-      taskBlocks: [...taskBlocks],
-    });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/add-task", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZAddTask.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const {
-      dateEnd,
-      dateStart,
-      isTodo,
-      name,
-      ownerId,
-      taskBlockId,
-      pointId,
-      executors,
-      roomId,
-    } = EventManagerApi.ZAddTask.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-
-    await UserUtils.checkTaskBlockPermissions(taskBlockId, userId, "editor");
-
-    const taskId = uuidv7();
-
-    // task
-    await db.query(
-      sql.unsafe`
-      insert into task_manager.tasks
-        (task_id, name, date_start, date_end, owner_id, is_todo, task_block_id, point_id, room_id)
-      values
-        (${taskId}, ${name}, ${dateStart}, ${dateEnd}, ${ownerId}, ${isTodo}, ${taskBlockId}, ${pointId}, ${roomId})`,
-    );
-
-    // executors
-    const executorsWithId = executors.map((e) => ({
-      task_executor_id: uuidv7(),
-      task_id: taskId,
-      user_id: e,
-    }));
-
-    for (const executor of executorsWithId) {
-      await db.query(
-        sql.unsafe`
-        insert into task_manager.task_executors
-          (task_executor_id, task_id, user_id)
-        values
-          (${executor.task_executor_id}, ${executor.task_id}, ${executor.user_id})`,
-      );
-    }
-
-    sendRes(200, { code: "success" });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/update-task", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZUpdateTask.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const {
-      dateEnd,
-      dateStart,
-      isTodo,
-      name,
-      pointId,
-      taskBlockId,
-      executors,
-      taskId,
-      roomId,
-    } = EventManagerApi.ZUpdateTask.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-
-    await UserUtils.checkTaskBlockPermissions(taskBlockId, userId, "editor");
-
-    // task
-    await db.query(
-      sql.unsafe`
-      update task_manager.tasks
-      set
-        name = ${name},
-        date_start = ${dateStart},
-        date_end = ${dateEnd},
-        is_todo = ${isTodo},
-        point_id = ${pointId},
-        room_id = ${roomId}
-      where
-        task_id = ${taskId}`,
-    );
-
-    // executors
-    await db.query(
-      sql.unsafe`
-      delete from task_manager.task_executors
-      where
-        task_id = ${taskId}`,
-    );
-
-    const executorsWithId = executors.map((e) => ({
-      task_executor_id: uuidv7(),
-      task_id: taskId,
-      user_id: e,
-    }));
-
-    for (const executor of executorsWithId) {
-      await db.query(
-        sql.unsafe`
-        insert into task_manager.task_executors
-          (task_executor_id, task_id, user_id)
-        values
-          (${executor.task_executor_id}, ${executor.task_id}, ${executor.user_id})`,
-      );
-    }
-
-    sendRes(200, { code: "success" });
-  } catch (e) {
-    next(e);
-  }
-});
-
-router.post("/get-block-tasks", async (req, res, next) => {
-  try {
-    // функция валидации ответа
-    const ZResType = EventManagerApi.ZGetBlockTasks.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
-    // валидация запроса
-    const { taskBlockId } = EventManagerApi.ZGetBlockTasks.req.parse(req.body);
-
-    const userId = UserUtils.getUserFromReq(req).userId;
-
-    // проверка прав
-
-    await UserUtils.checkTaskBlockPermissions(taskBlockId, userId, "viewer");
-
-    const tasks = await db.any(
-      sql.type(
-        z.object({
-          task_id: ZDbShema.task_manager.tasks.task_id,
-          name: ZDbShema.task_manager.tasks.name,
-          date_start: ZDbShema.task_manager.tasks.date_start,
-          date_end: ZDbShema.task_manager.tasks.date_end,
-          is_todo: ZDbShema.task_manager.tasks.is_todo,
-          owner_id: ZDbShema.task_manager.tasks.owner_id,
-          task_block_id: ZDbShema.task_manager.tasks.task_block_id,
-          point_id: ZDbShema.task_manager.tasks.point_id,
-          room_id: ZDbShema.task_manager.tasks.room_id,
-          executors: z.array(ZDbShema.task_manager.task_executors.user_id),
-        }),
-      )`
-        select
-          t.task_id,
-          t.name,
-          t.date_start,
-          t.date_end,
-          t.is_todo,
-          t.owner_id,
-          t.task_block_id,
-          t.point_id,
-          t.room_id,
-          array(
-          select
-            user_id
-          from
-            task_manager.task_executors e
-          where
-            e.task_id = t.task_id) as executors
-        from
-          task_manager.tasks t`,
-    );
-
-    // res
-    sendRes(200, {
-      code: "success",
-      tasks: [...tasks],
-    });
-  } catch (e) {
-    next(e);
-  }
-});

+ 120 - 0
src/modules/events-management/companies-router.ts

@@ -0,0 +1,120 @@
+// router
+import express from "express";
+const router = express.Router();
+export default router;
+
+// db
+import { db } from "#db";
+import { ZDbShema } from "#db-shema";
+import { sql } from "slonik";
+
+// api
+import { CompanyManagementApi } from "#api/companies-management-api.js";
+
+// 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 { EntityesService } from "#modules/entities-management/entityes-service.js";
+import { RouterUtils } from "#utils/router-utils.js";
+
+dayjs.extend(utc);
+
+router.post("/create-company", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { name, timezone } = CompanyManagementApi.ZCreateCompany.req.parse(
+      req.body,
+    );
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    const companyId = uuidv7();
+
+    // entity
+    await EntityesService.createEntity(companyId, "company");
+
+    // company
+    await db.query(
+      sql.unsafe`
+      insert into events_management.companies
+        (company_id, name, owner_id, timezone)
+      values
+        (${companyId}, ${name}, ${userId}, ${timezone})`,
+    );
+
+    // permissions
+    const MANAGER_ROLE_ID = process.env.COMPANY_MANAGER_ROLE_ID;
+    if (!MANAGER_ROLE_ID) {
+      throw Error("COMPANY_MANAGER_ROLE_ID is not defined");
+    }
+
+    await db.query(
+      sql.unsafe`
+      insert into permissions_management.user_roles
+        (user_id, role_id)
+      values
+        (${userId}, ${MANAGER_ROLE_ID})`,
+    );
+
+    RouterUtils.validAndSendResponse(
+      CompanyManagementApi.ZCreateCompany.res,
+      res,
+      { code: "success" },
+    );
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/get-user-companies", async (req, res, next) => {
+  try {
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    const REQUIRED_PERMISSION = "company_view_true";
+
+    const companies = await db.any(
+      sql.type(
+        z.object({
+          company_id: ZDbShema.events_management.companies.company_id,
+          name: ZDbShema.events_management.companies.name,
+          owner_id: ZDbShema.events_management.companies.owner_id,
+          timezone: ZDbShema.events_management.companies.timezone,
+        }),
+      )`
+        select
+          c.company_id,
+          c."name",
+          c.owner_id,
+          c.timezone
+        from
+          events_management.companies c
+        join permissions_management.cached_user_permissions cup on
+          c.company_id = cup.entity_id
+        where 
+          cup.user_id = ${userId}
+          and cup.permission_value_id = ${REQUIRED_PERMISSION}
+        `,
+    );
+
+    RouterUtils.validAndSendResponse(
+      CompanyManagementApi.ZGetUserCompanies.res,
+      res,
+      { code: "success", companies: [...companies] },
+    );
+  } catch (e) {
+    next(e);
+  }
+});

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

@@ -0,0 +1,483 @@
+// router
+import express from "express";
+const router = express.Router();
+export default router;
+
+// db
+import { db } from "#db";
+import { ZDbShema } from "#db-shema";
+import { sql } from "slonik";
+
+// api
+import { EventsManagementApi } from "#api/events-management-api.js";
+
+// 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 { CheckPermissionsService } from "#modules/permissions-management/check-permissions-service.js";
+import { EntityesService } from "#modules/entities-management/entityes-service.js";
+import { RouterUtils } from "#utils/router-utils.js";
+
+dayjs.extend(utc);
+
+router.post("/get-company-events", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { companyId } = EventsManagementApi.ZGetCompanyEvents.req.parse(
+      req.body,
+    );
+
+    // const nowWithUzerTz = dayjs.utc().startOf("day");
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    const DbEventsTypes = ZDbShema.events_management.events;
+    const events = await db.any(
+      sql.type(
+        z.object({
+          event_id: DbEventsTypes.event_id,
+          local_name: DbEventsTypes.event_id,
+          timezone: DbEventsTypes.timezone,
+          dates: z.array(ZDbShema.events_management.event_dates.date),
+        }),
+      )`
+        select
+          e.event_id,
+          e.local_name,
+          e.timezone,
+          e.company_id,
+          ARRAY_AGG(ed."date") as dates
+        from
+          events_management.events e
+        join 
+          permissions_management.cached_user_permissions cup 
+        on
+          e.company_id = cup.entity_id
+        left join 
+          events_management.event_dates ed 
+        on
+          e.event_id = ed.event_id
+        where
+          e.company_id = ${companyId}
+          and
+          cup.user_id = ${userId}
+          and cup.permission_value_id = 'view_event_true'
+        group by
+          e.event_id,
+          e.local_name,
+          e.timezone,
+          e.company_id;
+        `,
+    );
+
+    RouterUtils.validAndSendResponse(
+      EventsManagementApi.ZGetCompanyEvents.res,
+      res,
+      { code: "success", events: [...events] },
+    );
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/create-event", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { localName, dates, timezone, companyId } =
+      EventsManagementApi.ZCreateEvent.req.parse(req.body);
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    // проверка прав
+    await CheckPermissionsService.checkEntityPermission(
+      companyId,
+      userId,
+      "create_event_true",
+    );
+
+    // если тз не указана, то ставим тз компании
+    let tz = timezone;
+    if (!tz) {
+      const userTz = (
+        await db.one(
+          sql.type(
+            z.object({
+              timezone: ZDbShema.events_management.companies.timezone,
+            }),
+          )`
+          select 
+            timezone 
+          from 
+            events_management.companies 
+          where 
+            company_id = ${companyId}`,
+        )
+      ).timezone;
+
+      tz = userTz;
+    }
+    //
+
+    const eventId = uuidv7();
+
+    // createEntity
+    await EntityesService.createEntity(eventId, "event");
+
+    // get event
+    await db.query(
+      sql.unsafe`
+      insert into events_management.events 
+        (event_id, local_name, timezone, company_id) 
+      values 
+        (${eventId}, ${localName}, ${tz}, ${companyId})`,
+    );
+
+    // get dates
+    for (const date of dates) {
+      await db.query(
+        sql.unsafe`
+        insert into events_management.event_dates 
+          (event_id, date) 
+        values 
+          (${eventId}, ${date})`,
+      );
+    }
+
+    // add role to user
+    const MANAGER_ROLE_ID = process.env.EVENT_DEFAULT_ROLE_MANAGER_ID;
+    if (!MANAGER_ROLE_ID) {
+      throw Error("EVENT_DEFAULT_ROLE_MANAGER_ID is not defined");
+    }
+
+    await db.query(
+      sql.unsafe`
+      insert into 
+        permissions_management.user_roles
+      (user_id, role_id)
+      values
+        (${userId}, ${MANAGER_ROLE_ID})`,
+    );
+
+    RouterUtils.validAndSendResponse(
+      EventsManagementApi.ZCreateEvent.res,
+      res,
+      {
+        code: "success",
+        event_id: eventId,
+      },
+    );
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/get-event", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { eventId } = EventsManagementApi.ZGetEvent.req.parse(req.body);
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    // проверка прав
+    await CheckPermissionsService.checkEntityPermission(
+      eventId,
+      userId,
+      "view_event_true",
+    );
+
+    // event
+    const DbEventsTypes = ZDbShema.events_management.events;
+    const event = await db.maybeOne(
+      sql.type(
+        z.object({
+          event_id: DbEventsTypes.event_id,
+          local_name: DbEventsTypes.local_name,
+          timezone: DbEventsTypes.timezone,
+          dates: z.array(ZDbShema.events_management.event_dates.date),
+        }),
+      )`
+          select
+            e.event_id,
+            e.local_name,
+            e.timezone,
+            ARRAY_AGG(ed."date") as dates
+          from
+            events_management.events e
+          left join events_management.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 = ZDbShema.events_management.program_points;
+    const programPoints = await db.any(
+      sql.type(
+        z.object({
+          program_point_id: DbPointsType.program_point_id,
+          name: DbPointsType.name,
+          start_date: DbPointsType.start_date,
+          end_date: DbPointsType.end_date,
+          room_id: DbPointsType.room_id,
+          is_internal: DbPointsType.is_internal,
+        }),
+      )`
+        select
+          program_point_id,
+          name,
+          start_date,
+          end_date,
+          room_id,
+          is_internal
+        from
+          events_management.program_points
+        where
+          event_id = ${eventId}
+        `,
+    );
+
+    // уникальные комнаты ивента
+    const eventRoomsIds = new Set<string>();
+    for (const point of programPoints) {
+      if (point.room_id) eventRoomsIds.add(point.room_id);
+    }
+    const eventRoomsIdsArr = Array.from(eventRoomsIds);
+    //
+    // rooms
+    let rooms: readonly {
+      name: string;
+      room_id: string;
+    }[] = [];
+
+    // TODO ошибка в in?
+    if (eventRoomsIdsArr.length > 0) {
+      rooms = await db.any(
+        sql.type(
+          z.object({
+            room_id: ZDbShema.locations_management.rooms.room_id,
+            name: ZDbShema.locations_management.rooms.name,
+            location_id: ZDbShema.locations_management.rooms.location_id,
+          }),
+        )`
+          select
+            room_id, name, location_id
+          from
+            location_management.rooms
+          where
+            room_id in (${sql.join(eventRoomsIdsArr, sql.fragment`, `)})
+          `,
+      );
+    }
+
+    // res
+    RouterUtils.validAndSendResponse(EventsManagementApi.ZGetEvent.res, res, {
+      code: "success",
+      event: {
+        ...event,
+        programPoints: [...programPoints],
+        rooms: [...rooms],
+      },
+    });
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/create-program-point", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { name, startDate, endDate, eventId, roomId, isInternal } =
+      EventsManagementApi.ZCreateProgramPoint.req.parse(req.body);
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    // проверка прав
+    await CheckPermissionsService.checkEntityPermission(
+      eventId,
+      userId,
+      "create_program_point_true",
+    );
+
+    const programPointId = uuidv7();
+
+    // event
+    await db.query(
+      sql.unsafe`
+        insert into events_management.program_points
+          (program_point_id, name, start_date, end_date, room_id, event_id, is_internal)
+        values
+          (${programPointId}, ${name}, ${startDate}, ${endDate}, ${roomId || null}, ${eventId}, ${isInternal})
+      `,
+    );
+
+    RouterUtils.validAndSendResponse(
+      EventsManagementApi.ZCreateProgramPoint.res,
+      res,
+      { code: "success" },
+    );
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/update-event", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { eventId, localName, dates, timezone } =
+      EventsManagementApi.ZUpdateEvent.req.parse(req.body);
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    if (localName) {
+      // проверка прав
+      await CheckPermissionsService.checkEntityPermission(
+        eventId,
+        userId,
+        "edit_event_name_true",
+      );
+    }
+
+    if (timezone) {
+      // проверка прав
+      await CheckPermissionsService.checkEntityPermission(
+        eventId,
+        userId,
+        "edit_event_timezone_true",
+      );
+    }
+
+    // change localName, timezone
+    await db.query(
+      sql.unsafe`
+    update events_management.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 CheckPermissionsService.checkEntityPermission(
+        eventId,
+        userId,
+        "edit_event_dates_true",
+      );
+
+      await db.query(
+        sql.unsafe`
+        delete from events_management.event_dates
+        where
+          event_id = ${eventId}`,
+      );
+
+      for (const date of dates) {
+        await db.query(
+          sql.unsafe`
+          insert into events_management.event_dates 
+            (event_id, date) 
+          values 
+            (${eventId}, ${date})`,
+        );
+      }
+    }
+
+    RouterUtils.validAndSendResponse(
+      EventsManagementApi.ZUpdateEvent.res,
+      res,
+      {
+        code: "success",
+      },
+    );
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/update-program-point", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { programPointId, name, startDate, endDate, roomId } =
+      EventsManagementApi.ZUpdateProgramPoint.req.parse(req.body);
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    const eventId = await db.maybeOneFirst(
+      sql.type(
+        z.object({
+          event_id: ZDbShema.events_management.events.event_id,
+        }),
+      )`
+      select
+        event_id
+      from
+        events_management.program_points
+      where 
+        program_point_id = ${programPointId}
+      `,
+    );
+
+    if (!eventId) {
+      throw ApiError.BadRequest("Point not found", "Point not found");
+    }
+
+    // проверка прав
+    await CheckPermissionsService.checkEntityPermission(
+      eventId,
+      userId,
+      "edit_event_program_points_true",
+    );
+
+    // point
+    await db.query(
+      sql.unsafe`
+      update events_management.program_points
+      set
+        name = ${name},
+        start_date = ${startDate},
+        end_date = ${endDate},
+        room_id = ${roomId || null}
+      where
+        program_point_id = ${programPointId}`,
+    );
+
+    RouterUtils.validAndSendResponse(
+      EventsManagementApi.ZUpdateProgramPoint.res,
+      res,
+      {
+        code: "success",
+      },
+    );
+  } catch (e) {
+    next(e);
+  }
+});

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

@@ -0,0 +1,238 @@
+// router
+import express from "express";
+const router = express.Router();
+export default router;
+
+// db
+import { db } from "#db";
+import { ZDbShema } from "#db-shema";
+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/locations-management-api.js";
+import { CheckPermissionsService } from "#modules/permissions-management/check-permissions-service.js";
+import { RouterUtils } from "#utils/router-utils.js";
+import { ApiError } from "#exceptions/api-error.js";
+
+dayjs.extend(utc);
+
+router.post("/create-location", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { name, companyId } =
+      LocationsManagementApi.ZCreateLocation.req.parse(req.body);
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    await CheckPermissionsService.checkEntityPermission(
+      companyId,
+      userId,
+      "create_location_true",
+    );
+
+    const locationId = uuidv7();
+
+    // location
+    await db.query(
+      sql.unsafe`
+         insert into location_management.locations
+           (location_id, name, company_id)
+         values
+           (${locationId}, ${name}, ${companyId})`,
+    );
+
+    RouterUtils.validAndSendResponse(
+      LocationsManagementApi.ZCreateLocation.res,
+      res,
+      {
+        code: "success",
+      },
+    );
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/get-company-locations", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { companyId } = LocationsManagementApi.ZGetCompanyLocations.req.parse(
+      req.body,
+    );
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    const locations = await db.any(
+      sql.type(
+        z.object({
+          location_id: ZDbShema.locations_management.locations.location_id,
+          name: ZDbShema.locations_management.locations.name,
+        }),
+      )`
+              select
+                l.location_id,
+                l.name
+              from
+                locations_management.locations l
+              join permissions_management.cached_user_permissions cup on
+                l.company_id = cup.entity_id
+              where
+                cup.entity_id = ${companyId}
+                and
+                cup.user_id = ${userId}
+                and
+                cup.permission_value_id = 'locations_view_true'
+              `,
+    );
+
+    RouterUtils.validAndSendResponse(
+      LocationsManagementApi.ZGetCompanyLocations.res,
+      res,
+      {
+        code: "success",
+        locations: [...locations],
+      },
+    );
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/create-room", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { name, locationId } = LocationsManagementApi.ZCreateRoom.req.parse(
+      req.body,
+    );
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    // get location company
+    const companyId = await db.maybeOneFirst(
+      sql.type(
+        z.object({
+          company_id: ZDbShema.locations_management.locations.company_id,
+        }),
+      )`
+      select
+        company_id
+      from
+        locations_management.locations
+      where
+        location_id = ${locationId}
+      `,
+    );
+
+    if (!companyId) {
+      throw ApiError.BadRequest("Location not found", "Location not found");
+    }
+
+    // проверка прав
+    await CheckPermissionsService.checkEntityPermission(
+      companyId,
+      userId,
+      "create_room_true",
+    );
+
+    const roomId = uuidv7();
+
+    await db.query(
+      sql.unsafe`
+      insert into locations_management.rooms 
+        (room_id, name, location_id) 
+      values 
+        (${roomId}, ${name}, ${locationId})`,
+    );
+
+    RouterUtils.validAndSendResponse(
+      LocationsManagementApi.ZCreateRoom.res,
+      res,
+      {
+        code: "success",
+      },
+    );
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/get-location-rooms", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { locationId } = LocationsManagementApi.ZGetLocationRooms.req.parse(
+      req.body,
+    );
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    // get location company
+    const companyId = await db.maybeOneFirst(
+      sql.type(
+        z.object({
+          company_id: ZDbShema.locations_management.locations.company_id,
+        }),
+      )`
+          select
+            company_id
+          from
+            locations_management.locations
+          where
+            location_id = ${locationId}
+          `,
+    );
+
+    if (!companyId) {
+      throw ApiError.BadRequest("Location not found", "Location not found");
+    }
+
+    // проверка прав
+    await CheckPermissionsService.checkEntityPermission(
+      companyId,
+      userId,
+      "locations_view_true",
+    );
+
+    const rooms = await db.any(
+      sql.type(
+        z.object({
+          room_id: ZDbShema.locations_management.rooms.room_id,
+          name: ZDbShema.locations_management.rooms.name,
+        }),
+      )`
+        select
+          room_id,
+          name
+        from
+          locations_management.rooms
+        where
+          location_id = ${locationId}
+        `,
+    );
+
+    // res
+    RouterUtils.validAndSendResponse(
+      LocationsManagementApi.ZGetLocationRooms.res,
+      res,
+      {
+        code: "success",
+        rooms: [...rooms],
+      },
+    );
+  } catch (e) {
+    next(e);
+  }
+});

+ 39 - 0
src/modules/permissions-management/check-permissions-service.ts

@@ -0,0 +1,39 @@
+// types
+
+import { ApiError } from "#exceptions/api-error.js";
+import { db } from "#db";
+import { sql } from "slonik";
+import { AllPermissionsValues } from "./permissions-types.js";
+
+class checkPermissionsService {
+  async checkEntityPermission(
+    entityId: string,
+    userId: string,
+    requiredPermissionValues: AllPermissionsValues | AllPermissionsValues[],
+  ) {
+    if (typeof requiredPermissionValues === "string") {
+      requiredPermissionValues = [requiredPermissionValues];
+    }
+
+    // TODO добавить проверку родителя
+    const isFound = await db.exists(sql.unsafe`
+    select * from
+      permissions_management.cached_user_permissions
+    where
+      entity_id = ${entityId} and
+      user_id = ${userId} and
+      permission_value IN (${sql.join(
+        requiredPermissionValues.map((value) => sql.unsafe`${value}`),
+        sql.fragment`, `,
+      )})
+    `);
+
+    if (!isFound) {
+      throw ApiError.ForbiddenError();
+    }
+
+    return true;
+  }
+}
+
+export const CheckPermissionsService = new checkPermissionsService();

+ 74 - 0
src/modules/permissions-management/permissions-types.ts

@@ -0,0 +1,74 @@
+export const PERMISSIONS = {
+  view_company: {
+    entityType: "company",
+    values: ["view_company_true", "view_company_false"],
+  },
+  create_event: {
+    entityType: "company",
+    values: ["create_event_true", "create_event_false"],
+  },
+  create_location: {
+    entityType: "company",
+    values: ["create_location_true", "create_location_false"],
+  },
+  locations_view: {
+    entityType: "company",
+    values: ["locations_view_true", "locations_view_false"],
+  },
+  create_room: {
+    entityType: "location",
+    values: ["create_room_true", "create_room_false"],
+  },
+
+  // event
+  view_event: {
+    entityType: "event",
+    values: ["view_event_true", "view_event_false"],
+  },
+  create_program_point: {
+    entityType: "event",
+    values: ["create_program_point_true", "create_program_point_false"],
+  },
+  edit_event_name: {
+    entityType: "event",
+    values: ["edit_event_name_true", "edit_event_name_false"],
+  },
+  edit_event_dates: {
+    entityType: "event",
+    values: ["edit_event_dates_true", "edit_event_dates_false"],
+  },
+  edit_event_timezone: {
+    entityType: "event",
+    values: ["edit_event_timezone_true", "edit_event_timezone_false"],
+  },
+  edit_event_program_points: {
+    entityType: "event",
+    values: [
+      "edit_event_program_points_true",
+      "edit_event_program_points_false",
+    ],
+  },
+  create_task_block: {
+    entityType: "event",
+    values: ["create_task_block_true", "create_task_block_false"],
+  },
+
+  // task block
+  edit_task_block: {
+    entityType: "task_block",
+    values: ["edit_task_block_true", "edit_task_block_false"],
+  },
+  create_task: {
+    entityType: "task_block",
+    values: ["create_task_true", "create_task_false"],
+  },
+
+  // task
+  edit_task: {
+    entityType: "task",
+    values: ["edit_task_true", "edit_task_false"],
+  },
+} as const;
+
+export type AllPermissionsValues =
+  (typeof PERMISSIONS)[keyof typeof PERMISSIONS]["values"][number];

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

@@ -0,0 +1,173 @@
+// router
+import express from "express";
+const router = express.Router();
+export default router;
+
+// db
+import { db } from "#db";
+import { ZDbShema } from "#db-shema";
+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);
+
+// other
+import { z } from "zod";
+
+import { v7 as uuidv7 } from "uuid";
+// import { logger } from "#logger";
+import { UserUtils } from "#utils/user-utils.js";
+import { EntityesService } from "#modules/entities-management/entityes-service.js";
+import { RouterUtils } from "#utils/router-utils.js";
+import { TasksManagementApi } from "#api/tasks-management-api.js";
+import { CheckPermissionsService } from "#modules/permissions-management/check-permissions-service.js";
+import { ApiError } from "#exceptions/api-error.js";
+
+dayjs.extend(utc);
+
+router.post("/create-task-block", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { name, eventId } = TasksManagementApi.ZCreateTaskBlock.req.parse(
+      req.body,
+    );
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    // проверка прав
+    await CheckPermissionsService.checkEntityPermission(
+      eventId,
+      userId,
+      "create_task_block_true",
+    );
+
+    const blockId = uuidv7();
+
+    // create entity
+    await EntityesService.createEntity(blockId, "task_block");
+
+    // create block
+    await db.query(
+      sql.unsafe`
+      insert into tasks_management.task_blocks
+        (task_block_id, name, event_id)
+      values
+        (${blockId}, ${name}, ${eventId})`,
+    );
+
+    RouterUtils.validAndSendResponse(
+      TasksManagementApi.ZCreateTaskBlock.res,
+      res,
+      { code: "success" },
+    );
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/update-task-block", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { taskBlockId, name } = TasksManagementApi.ZUpdateTaskBlock.req.parse(
+      req.body,
+    );
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    const eventId = await db.maybeOneFirst(
+      sql.type(
+        z.object({
+          event_id: ZDbShema.events_management.events.event_id,
+        }),
+      )`
+      select
+        event_id
+      from
+        tasks_management.task_blocks
+      where 
+        task_block_id = ${taskBlockId}
+      `,
+    );
+
+    if (!eventId) {
+      throw ApiError.BadRequest("Task block not found", "Task block not found");
+    }
+
+    // проверка прав
+    await CheckPermissionsService.checkEntityPermission(
+      eventId,
+      userId,
+      "edit_task_block_true",
+    );
+
+    // block
+    await db.query(
+      sql.unsafe`
+      update tasks_management.task_blocks
+      set
+        name = ${name}
+      where
+        task_block_id = ${taskBlockId}`,
+    );
+
+    RouterUtils.validAndSendResponse(
+      TasksManagementApi.ZUpdateTaskBlock.res,
+      res,
+      { code: "success" },
+    );
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/get-event-task-blocks", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { eventId } = TasksManagementApi.ZGetEventTaskBlocks.req.parse(
+      req.body,
+    );
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    const REQUIRED_PERMISSION = "task_block_view_true";
+    const taskBlocks = await db.any(
+      sql.type(
+        z.object({
+          task_block_id: ZDbShema.tasks_management.task_blocks.task_block_id,
+          name: ZDbShema.tasks_management.task_blocks.name,
+        }),
+      )`
+        select
+          tb.task_block_id,
+          tb.name
+        from
+          tasks_management.task_blocks tb
+          -- permissions
+        join permissions_management.cached_user_permissions cup on
+          tb.event_id = cup.entity_id
+        where
+          tb.event_id = ${eventId} and
+          cup.user_id = ${userId} and
+          cup.permission_value_id = ${REQUIRED_PERMISSION}
+        `,
+    );
+
+    // res
+    RouterUtils.validAndSendResponse(
+      TasksManagementApi.ZGetEventTaskBlocks.res,
+      res,
+      { code: "success", taskBlocks: [...taskBlocks] },
+    );
+  } catch (e) {
+    next(e);
+  }
+});

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

@@ -0,0 +1,248 @@
+// router
+import express from "express";
+const router = express.Router();
+export default router;
+
+// db
+import { db } from "#db";
+import { ZDbShema } from "#db-shema";
+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);
+
+// other
+import { z } from "zod";
+
+import { v7 as uuidv7 } from "uuid";
+// import { logger } from "#logger";
+import { UserUtils } from "#utils/user-utils.js";
+import { EntityesService } from "#modules/entities-management/entityes-service.js";
+import { RouterUtils } from "#utils/router-utils.js";
+import { TasksManagementApi } from "#api/tasks-management-api.js";
+import { CheckPermissionsService } from "#modules/permissions-management/check-permissions-service.js";
+
+dayjs.extend(utc);
+
+router.post("/create-task", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const {
+      name,
+      startDate,
+      endDate,
+      isTodo,
+      taskBlockId,
+      programPointId,
+      executors,
+      roomId,
+      accountableId,
+    } = TasksManagementApi.ZCreateTask.req.parse(req.body);
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    // проверка прав
+    await CheckPermissionsService.checkEntityPermission(
+      taskBlockId,
+      userId,
+      "create_task_true",
+    );
+
+    const taskId = uuidv7();
+
+    // create entity
+    await EntityesService.createEntity(taskId, "task");
+
+    // create task
+    await db.query(
+      sql.unsafe`
+      insert into tasks_management.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 db.query(
+        sql.unsafe`
+        insert into tasks_management.task_executors
+          (task_id, user_id)
+        values
+          (${taskId}, ${executorId})`,
+      );
+    }
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/update-task", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const {
+      taskId,
+
+      endDate,
+      startDate,
+      isTodo,
+      name,
+      programPointId,
+      executors,
+      roomId,
+      accountableId,
+    } = TasksManagementApi.ZUpdateTask.req.parse(req.body);
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    // проверка прав
+    await CheckPermissionsService.checkEntityPermission(
+      taskId,
+      userId,
+      "edit_task_true",
+    );
+
+    // edit task
+    await db.query(
+      sql.unsafe`
+      update tasks_management.tasks
+      set
+        ${sql.join(
+          [
+            name !== undefined ? `name = ${name}` : "name = name",
+            startDate !== undefined
+              ? `start_date = ${startDate}`
+              : "start_date = start_date",
+            endDate !== undefined
+              ? `end_date = ${endDate}`
+              : "end_date = end_date",
+            isTodo !== undefined ? `is_todo = ${isTodo}` : "is_todo = is_todo",
+            programPointId !== undefined
+              ? `program_point_id = ${programPointId}`
+              : "program_point_id = program_point_id",
+            roomId !== undefined ? `room_id = ${roomId}` : "room_id = room_id",
+            accountableId !== undefined
+              ? `accountable_id = ${accountableId}`
+              : "accountable_id = accountable_id",
+          ],
+          sql.fragment`, `,
+        )}
+      where
+        task_id = ${taskId}`,
+    );
+
+    if (executors) {
+      // del executors
+      await db.query(
+        sql.unsafe`
+      delete from task_management.task_executors
+      where
+        task_id = ${taskId}`,
+      );
+
+      // add executors
+      for (const executorId of executors) {
+        await db.query(
+          sql.unsafe`
+        insert into tasks_management.task_executors
+          (task_id, user_id)
+        values
+          (${taskId}, ${executorId})`,
+        );
+      }
+    }
+
+    RouterUtils.validAndSendResponse(TasksManagementApi.ZUpdateTask.res, res, {
+      code: "success",
+    });
+  } catch (e) {
+    next(e);
+  }
+});
+
+router.post("/get-block-tasks", async (req, res, next) => {
+  try {
+    // валидация запроса
+    const { taskBlockId } = TasksManagementApi.ZGetBlockTasks.req.parse(
+      req.body,
+    );
+
+    const userId = UserUtils.getUserFromReq(req).userId;
+
+    const REQUIRED_PERMISSION = "task_view_true";
+    const ZDbTasks = ZDbShema.tasks_management.tasks;
+    const tasks = await db.any(
+      sql.type(
+        z.object({
+          task_id: ZDbTasks.task_id,
+          name: ZDbTasks.name,
+          start_date: ZDbTasks.start_date,
+          end_date: ZDbTasks.end_date,
+          is_todo: ZDbTasks.is_todo,
+          accountable_id: ZDbTasks.accountable_id,
+          task_block_id: ZDbTasks.task_block_id,
+          program_point_id: ZDbTasks.program_point_id,
+          room_id: ZDbTasks.room_id,
+          executors: z.array(ZDbShema.tasks_management.task_executors.user_id),
+        }),
+      )`
+          select
+            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,
+            ARRAY_AGG(te.user_id) as executors
+          from
+            tasks_management.tasks t
+            --	executors
+          left join tasks_management.task_executors te on
+            t.task_id = te.task_id
+            --	permissions
+          join permissions_management.cached_user_permissions cup on
+            t.task_id = cup.entity_id
+          where
+            --	perm
+            cup.user_id = ${userId}
+            and
+          cup.permission_value_id = ${REQUIRED_PERMISSION}
+            and
+            --
+          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.ZGetBlockTasks.res,
+      res,
+      { code: "success", tasks: [...tasks] },
+    );
+  } catch (e) {
+    next(e);
+  }
+});

+ 0 - 23
src/modules/user/auth/services/user-auth-service.ts

@@ -1,23 +0,0 @@
-import { logger } from "#logger";
-import bcript from "bcrypt";
-import { DayjsUtils } from "#dayjsUtils";
-
-// db
-import { db } from "#db";
-import { sql } from "slonik";
-
-class userAuthService {
-  async authTriesIncrement(userId: string) {
-    await db.any(
-      sql.unsafe`update users.user_profiles set wrong_pass_tries = wrong_pass_tries + 1 where user_id = ${userId}`,
-    );
-  }
-
-  async resetAuthTries(userId: string) {
-    await db.any(
-      sql.unsafe`update users.user_profiles set wrong_pass_tries = 0 where user_id = ${userId}`,
-    );
-  }
-}
-
-export const UserAuthService = new userAuthService();

+ 89 - 109
src/modules/user/auth/routers/auth-router.ts → src/modules/users-management/auth/routers/auth-router.ts

@@ -20,41 +20,36 @@ import utc from "dayjs/plugin/utc.js";
 dayjs.extend(utc);
 
 // other
-import { ZodTypeAny, z } from "zod";
+import { z } from "zod";
 import bcript from "bcrypt";
 import { v7 as uuidv7 } from "uuid";
 
-import { logger } from "#logger";
 import tokenService from "../services/token-service.js";
 import { UserAuthService } from "../services/user-auth-service.js";
-import { ConfirmPinsService } from "#modules/user/confirm-pins/confirm-pins-service.js";
+import { ConfirmPinsService } from "#modules/users-management/confirm-pins/confirm-pins-service.js";
+import { RouterUtils } from "#utils/router-utils.js";
 
 dayjs.extend(utc);
 
 router.post("/registration", async (req, res, next) => {
   try {
-    // функция валидации ответа
-    const ZResType = AuthApi.ZRegistration.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
     // валидация запроса
-    const { email, password } = AuthApi.ZRegistration.req.parse(req.body);
+    const { email } = AuthApi.ZRegistration.req.parse(req.body);
 
     // проверка на существование пользователя
     const isUserExist = await db.exists(
-      sql.unsafe`select email from users.user_profiles where email = ${email}`,
+      sql.unsafe`select email from users_management.users where email = ${email}`,
     );
 
     // если пользователь уже зарегистрирован
     if (isUserExist) {
-      sendRes(400, { code: "alreadyExists" });
+      RouterUtils.validAndSendResponse(
+        AuthApi.ZRegistration.res,
+        res,
+        { code: "alreadyExists" },
+        400,
+      );
+
       return;
     }
 
@@ -63,74 +58,84 @@ router.post("/registration", async (req, res, next) => {
     try {
       await ConfirmPinsService.sendConfirmPin(transactionId, email);
     } catch {
-      sendRes(400, { code: "pinIsNotSent", transactionId });
+      RouterUtils.validAndSendResponse(
+        AuthApi.ZRegistration.res,
+        res,
+        { code: "pinIsNotSent", transactionId },
+        400,
+      );
       return;
     }
 
-    sendRes(200, { code: "pinIsSent", transactionId });
+    RouterUtils.validAndSendResponse(AuthApi.ZRegistration.res, res, {
+      code: "pinIsSent",
+      transactionId: transactionId,
+    });
   } catch (e) {
     next(e);
   }
 });
 
+// TODO добавить компанию
 router.post("/confirm-registration", async (req, res, next) => {
   try {
-    // функция валидации ответа
-    const ZResType = AuthApi.ZConfirmRegistration.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
     // валидация запроса
-    const { email, password, transactionId, confirmPin, timezone } =
+    const { password, name, transactionId, confirmPin } =
       AuthApi.ZConfirmRegistration.req.parse(req.body);
 
     // проверка пина
-    const pinStatus = await ConfirmPinsService.checkConfirmPin(
+    const pinInfo = await ConfirmPinsService.checkConfirmPin(
       transactionId,
-      email,
       confirmPin,
     );
 
     // если пин протухший
-    if (pinStatus === "rotten") {
-      sendRes(400, { code: "pinIsRotten" });
+    if (pinInfo.status === "rotten") {
+      RouterUtils.validAndSendResponse(
+        AuthApi.ZConfirmRegistration.res,
+        res,
+        { code: "pinIsRotten" },
+        400,
+      );
       return;
     }
 
     // слишком много попыток
-    if (pinStatus === "tooManyTries") {
-      sendRes(400, { code: "tooManyTries" });
+    if (pinInfo.status === "tooManyTries") {
+      RouterUtils.validAndSendResponse(
+        AuthApi.ZConfirmRegistration.res,
+        res,
+        { code: "tooManyTries" },
+        400,
+      );
       return;
     }
 
     // неправильный
-    if (pinStatus !== "correct" && pinStatus.status === "wrong") {
-      sendRes(400, {
-        code: "pinIsWrong",
-        triesRemained: pinStatus.triesRemained,
-      });
+    if (pinInfo.status === "wrong") {
+      RouterUtils.validAndSendResponse(
+        AuthApi.ZConfirmRegistration.res,
+        res,
+        {
+          code: "pinIsWrong",
+          triesRemained: pinInfo.triesRemained,
+        },
+        400,
+      );
       return;
     }
 
     // пин правильный
+    const email = pinInfo.email;
     // регистрация
     const hashPassword = await bcript.hash(password, 3);
-    const userId = await db.oneFirst(
-      sql.type(
-        z.object({
-          user_id: ZDbShema.users.user_profiles.user_id,
-        }),
-      )`
-      insert into users.user_profiles 
-        (user_id, email, password, timezone) 
+    const userId = uuidv7();
+    await db.query(
+      sql.unsafe`
+      insert into users_management.users 
+        (user_id, email, name, password) 
       values 
-        (${uuidv7()}, ${email}, ${hashPassword}, ${timezone}) 
-      returning user_id`,
+        (${userId}, ${email}, ${name}, ${hashPassword})`,
     );
 
     // токены
@@ -139,13 +144,14 @@ router.post("/confirm-registration", async (req, res, next) => {
       userId,
     });
     await tokenService.insertRefreshToken(userId, refreshToken);
+
     res.cookie("refreshToken", refreshToken, {
       maxAge: 30 * 24 * 60 * 60 * 1000, //30d
       httpOnly: true, //запрет на изменение пользователем
       // secure: true, //после включения https
     });
 
-    sendRes(200, {
+    RouterUtils.validAndSendResponse(AuthApi.ZConfirmRegistration.res, res, {
       code: "registered",
       userData: {
         accessToken,
@@ -154,7 +160,6 @@ router.post("/confirm-registration", async (req, res, next) => {
         userId,
       },
     });
-    return;
   } catch (e) {
     next(e);
   }
@@ -162,16 +167,6 @@ router.post("/confirm-registration", async (req, res, next) => {
 
 router.post("/login", async (req, res, next) => {
   try {
-    // функция валидации ответа
-    const ZResType = AuthApi.ZLogin.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
     // валидация запроса
     const { email, password } = AuthApi.ZLogin.req.parse(req.body);
 
@@ -179,20 +174,30 @@ router.post("/login", async (req, res, next) => {
     const user = await db.maybeOne(
       sql.type(
         z.object({
-          user_id: ZDbShema.users.user_profiles.user_id,
-          password: ZDbShema.users.user_profiles.password,
-          wrong_pass_tries: ZDbShema.users.user_profiles.wrong_pass_tries,
+          user_id: ZDbShema.users_management.users.user_id,
+          password: ZDbShema.users_management.users.password,
+          wrong_pass_tries: ZDbShema.users_management.users.wrong_pass_tries,
         }),
-      )`select user_id, password, wrong_pass_tries from users.user_profiles where email = ${email}`,
+      )`
+      select 
+        user_id, password, wrong_pass_tries 
+      from 
+        users_management.users 
+      where 
+        email = ${email}`,
     );
     if (!user) {
-      sendRes(400, { code: "userNotFound" });
+      RouterUtils.validAndSendResponse(AuthApi.ZLogin.res, res, {
+        code: "userNotFound",
+      });
       return;
     }
 
     // если количество попыток превышено
     if (user.wrong_pass_tries > Number(process.env.PASSWORD_MAX_TRIES) - 1) {
-      sendRes(400, { code: "tooManyTries" });
+      RouterUtils.validAndSendResponse(AuthApi.ZLogin.res, res, {
+        code: "tooManyTries",
+      });
       return;
     }
 
@@ -202,7 +207,11 @@ router.post("/login", async (req, res, next) => {
       await UserAuthService.authTriesIncrement(user.user_id);
       const triesRemained =
         Number(process.env.PASSWORD_MAX_TRIES) - 1 - user.wrong_pass_tries;
-      sendRes(400, { code: "passIsWrong", triesRemained });
+
+      RouterUtils.validAndSendResponse(AuthApi.ZLogin.res, res, {
+        code: "passIsWrong",
+        triesRemained,
+      });
       return;
     }
 
@@ -221,7 +230,7 @@ router.post("/login", async (req, res, next) => {
       // secure: true, //после включения https
     });
 
-    sendRes(200, {
+    RouterUtils.validAndSendResponse(AuthApi.ZLogin.res, res, {
       code: "success",
       userData: { email, accessToken, refreshToken, userId: user.user_id },
     });
@@ -231,17 +240,6 @@ router.post("/login", async (req, res, next) => {
 });
 router.post("/logout", async (req, res, next) => {
   try {
-    // функция валидации ответа
-    const ZResType = AuthApi.ZLogout.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
     const { refreshToken } = req.cookies;
 
     const userData = tokenService.validateRefreshToken(refreshToken);
@@ -249,7 +247,9 @@ router.post("/logout", async (req, res, next) => {
     await tokenService.removeToken(userData.userId, refreshToken);
     res.clearCookie("refreshToken");
 
-    sendRes(200, { code: "success" });
+    RouterUtils.validAndSendResponse(AuthApi.ZLogout.res, res, {
+      code: "success",
+    });
   } catch (e) {
     next(e);
   }
@@ -257,17 +257,6 @@ router.post("/logout", async (req, res, next) => {
 
 router.post("/logoutAllDevices", async (req, res, next) => {
   try {
-    // функция валидации ответа
-    const ZResType = AuthApi.ZLogoutAllDevices.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
     const { refreshToken } = req.cookies;
 
     const userData = tokenService.validateRefreshToken(refreshToken);
@@ -275,7 +264,9 @@ router.post("/logoutAllDevices", async (req, res, next) => {
     await tokenService.removeAllUserTokens(userData.userId);
     res.clearCookie("refreshToken");
 
-    sendRes(200, { code: "success" });
+    RouterUtils.validAndSendResponse(AuthApi.ZLogoutAllDevices.res, res, {
+      code: "success",
+    });
   } catch (e) {
     next(e);
   }
@@ -283,17 +274,6 @@ router.post("/logoutAllDevices", async (req, res, next) => {
 
 router.get("/refresh", async (req, res, next) => {
   try {
-    // функция валидации ответа
-    const ZResType = AuthApi.ZRefresh.res; //change
-    const sendRes = (
-      status: 200 | 400 | 500,
-      resData: z.infer<typeof ZResType>,
-    ) => {
-      const response = ZResType.parse(resData);
-      res.status(status).json(response);
-    };
-    //
-
     const { refreshToken } = req.cookies;
 
     if (!refreshToken) throw ApiError.UnauthorizedError();
@@ -311,9 +291,9 @@ router.get("/refresh", async (req, res, next) => {
     const newUserData = await db.maybeOne(
       sql.type(
         z.object({
-          email: ZDbShema.users.user_profiles.email,
+          email: ZDbShema.users_management.users.email,
         }),
-      )`select email from users.user_profiles where user_id = ${userData.userId}`,
+      )`select email from users_management.users where user_id = ${userData.userId}`,
     );
     if (!newUserData) {
       throw ApiError.UnauthorizedError();
@@ -334,7 +314,7 @@ router.get("/refresh", async (req, res, next) => {
       // secure: true, //после включения https
     });
 
-    sendRes(200, {
+    RouterUtils.validAndSendResponse(AuthApi.ZRefresh.res, res, {
       code: "success",
       userData: {
         email: newUserData.email,

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

@@ -1,6 +1,6 @@
 // база данных
 
-import ApiError from "../../../exceptions/api-error.js";
+import { ApiError } from "#exceptions/api-error.js";
 
 // база данных
 
@@ -13,7 +13,7 @@ class SessionService {
   }) {
     const userData = cookies.userData;
     if (!userData) {
-      throw ApiError.UnauthorizedErrors();
+      throw ApiError.UnauthorizedError();
     }
     return userData;
   }

+ 11 - 5
src/modules/user/auth/services/token-service.ts → src/modules/users-management/auth/services/token-service.ts

@@ -32,7 +32,7 @@ class TokenService {
   async insertRefreshToken(userId: string, refreshToken: string) {
     await db.query(
       sql.unsafe`
-      insert into users.user_refresh_tokens
+      insert into users_management.user_refresh_tokens
         (user_id, refresh_token)
       values
         (${userId}, ${refreshToken})
@@ -44,7 +44,7 @@ class TokenService {
     await db.query(
       sql.unsafe`
       update
-        users.user_refresh_tokens
+        users_management.user_refresh_tokens
       set
         refresh_token = ${newRefreshToken}
       where
@@ -56,7 +56,7 @@ class TokenService {
   async removeToken(userId: string, refreshToken: string) {
     await db.query(sql.unsafe`
       delete from
-        users.user_refresh_tokens
+        users_management.user_refresh_tokens
       where
         user_id = ${userId} and refresh_token = ${refreshToken}
     `);
@@ -65,7 +65,7 @@ class TokenService {
   async removeAllUserTokens(userId: string) {
     await db.query(sql.unsafe`
     delete from
-      users.user_refresh_tokens
+      users_management.user_refresh_tokens
     where
       user_id = ${userId}
     `);
@@ -85,7 +85,13 @@ class TokenService {
 
   async findToken(userId: string, refreshToken: string): Promise<boolean> {
     const tokenIsExist = await db.exists(
-      sql.unsafe`select user_id from users.user_refresh_tokens where user_id = ${userId} and refresh_token = ${refreshToken}`,
+      sql.unsafe`
+      select 
+        user_id 
+      from 
+        users_management.user_refresh_tokens 
+      where 
+        user_id = ${userId} and refresh_token = ${refreshToken}`,
     );
     return tokenIsExist;
   }

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

@@ -0,0 +1,31 @@
+// db
+import { db } from "#db";
+import { sql } from "slonik";
+
+class userAuthService {
+  async authTriesIncrement(userId: string) {
+    await db.any(
+      sql.unsafe`
+      update 
+        users_management.users 
+      set 
+        wrong_pass_tries = wrong_pass_tries + 1 
+      where 
+        user_id = ${userId}`,
+    );
+  }
+
+  async resetAuthTries(userId: string) {
+    await db.any(
+      sql.unsafe`
+      update 
+        users_management.users 
+      set 
+        wrong_pass_tries = 0 
+      where 
+        user_id = ${userId}`,
+    );
+  }
+}
+
+export const UserAuthService = new userAuthService();

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


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


+ 43 - 26
src/modules/user/confirm-pins/confirm-pins-service.ts → src/modules/users-management/confirm-pins/confirm-pins-service.ts

@@ -15,15 +15,25 @@ class confirmPinsService {
     return Math.floor(1000 + Math.random() * 9000);
   }
 
-  private async deleteConfirmPin(transactionId: string, email: string) {
+  private async deleteConfirmPin(transactionId: string) {
     await db.any(
-      sql.unsafe`delete from users.user_confirm_pins where transaction_id = ${transactionId} and email = ${email}`,
+      sql.unsafe`
+      delete from 
+        users_management.confirm_pins 
+      where 
+        transaction_id = ${transactionId}`,
     );
   }
 
-  private async pinTriesIncrement(transactionId: string, email: string) {
+  private async pinTriesIncrement(transactionId: string) {
     await db.any(
-      sql.unsafe`update users.user_confirm_pins set wrong_pin_tries = wrong_pin_tries + 1 where transaction_id = ${transactionId} and email = ${email}`,
+      sql.unsafe`
+      update 
+        users_management.confirm_pins 
+      set 
+        wrong_pin_tries = wrong_pin_tries + 1 
+      where 
+        transaction_id = ${transactionId}`,
     );
   }
   //
@@ -31,10 +41,10 @@ class confirmPinsService {
   //
   async sendConfirmPin(transactionId: string, email: string) {
     const confirmPin = this.genRandom4DigitNumber();
-
+    logger.debug(1);
     // удаляем если пин уже есть
-    await this.deleteConfirmPin(transactionId, email);
-
+    await this.deleteConfirmPin(transactionId);
+    logger.debug(2);
     // отправка
     const mailBody = `
     <div>
@@ -43,11 +53,11 @@ class confirmPinsService {
     </div>
 `;
     await MailService.sendMail(email, "Ваш код для EVENT", mailBody);
-
+    logger.debug(3);
     // бд
     await db.any(
       sql.unsafe`
-      insert into users.user_confirm_pins (
+      insert into users_management.confirm_pins (
         transaction_id,
         email,
         confirm_pin,
@@ -58,7 +68,7 @@ class confirmPinsService {
         ${confirmPin}, 
         ${DayjsUtils.createDayjsUtcWithoutOffset().toISOString()})`,
     );
-
+    logger.debug(4);
     logger.info("Отправлен временный код: ", {
       email,
       confirmPin,
@@ -67,30 +77,37 @@ class confirmPinsService {
 
   async checkConfirmPin(
     transactionId: string,
-    email: string,
     confirmPin: number,
   ): Promise<
-    | "correct"
-    | "rotten"
-    | "tooManyTries"
+    | { status: "correct"; email: string }
+    | { status: "rotten" }
+    | { status: "tooManyTries" }
     | {
         status: "wrong";
-        triesRemained?: number;
+        triesRemained: number;
       }
   > {
     const pinInfo = await db.maybeOne(
       sql.type(
         z.object({
-          confirm_pin: ZDbShema.users.user_confirm_pins.confirm_pin,
-          create_time: ZDbShema.users.user_confirm_pins.create_time,
-          wrong_pin_tries: ZDbShema.users.user_confirm_pins.wrong_pin_tries,
+          confirm_pin: ZDbShema.users_management.confirm_pins.confirm_pin,
+          email: ZDbShema.users_management.confirm_pins.email,
+          create_time: ZDbShema.users_management.confirm_pins.create_time,
+          wrong_pin_tries:
+            ZDbShema.users_management.confirm_pins.wrong_pin_tries,
         }),
-      )`select confirm_pin, create_time, wrong_pin_tries from users.user_confirm_pins where transaction_id = ${transactionId} and email = ${email}`,
+      )`
+      select 
+        confirm_pin, email, create_time, wrong_pin_tries
+      from 
+        users_management.confirm_pins 
+      where 
+        transaction_id = ${transactionId}`,
     );
 
     // не существует
     if (!pinInfo) {
-      return "rotten";
+      return { status: "rotten" };
     }
 
     // много попыток
@@ -98,7 +115,7 @@ class confirmPinsService {
       pinInfo.wrong_pin_tries >
       Number(process.env.CONFIRM_PIN_MAX_TRIES) - 1
     ) {
-      return "tooManyTries";
+      return { status: "tooManyTries" };
     }
 
     // просрочка
@@ -109,13 +126,13 @@ class confirmPinsService {
           .add(Number(process.env.CONFIRM_PIN_LIFETIME_MINS), "minutes"),
       )
     ) {
-      await this.deleteConfirmPin(transactionId, email);
-      return "rotten";
+      await this.deleteConfirmPin(transactionId);
+      return { status: "rotten" };
     }
 
     // неправильный
     if (pinInfo.confirm_pin !== confirmPin) {
-      await this.pinTriesIncrement(transactionId, email);
+      await this.pinTriesIncrement(transactionId);
 
       const triesRemained =
         Number(process.env.CONFIRM_PIN_MAX_TRIES) - 1 - pinInfo.wrong_pin_tries;
@@ -127,8 +144,8 @@ class confirmPinsService {
     }
 
     // правильный
-    await this.deleteConfirmPin(transactionId, email);
-    return "correct";
+    await this.deleteConfirmPin(transactionId);
+    return { status: "correct", email: pinInfo.email };
   }
 }
 

+ 40 - 27
src/plugins/logger.ts

@@ -1,32 +1,45 @@
-import log4js from "log4js";
+import { createLogger, format, transports } from "winston";
 
-log4js.configure({
-  appenders: {
-    console: {
-      type: "console",
-    },
+import path from "path";
 
-    allFile: {
-      type: "file",
-      filename: "logs/all-logs.log",
-      maxLogSize: 10485760,
-      backups: 30,
-    },
+const __dirname = path.resolve();
 
-    emergenciesFile: { type: "file", filename: "logs/panic-logs.log" },
+// Форматирование логов
+const customFormat = format.combine(
+  format.timestamp({ format: "DD.MM.YYYY HH:mm:ss" }), // Добавление временной метки
+  format.errors({ stack: true }), // Автоматическое добавление стека для ошибок
+  format.printf((info) => {
+    const { timestamp, level, message, stack, ...rest } = info;
 
-    "just-errors": {
-      type: "logLevelFilter",
-      appender: "emergenciesFile",
-      level: "error",
-    },
-  },
-  categories: {
-    default: {
-      appenders: ["console", "allFile", "just-errors"],
-      level: process.env.LOGS_LEVEL || "all",
-    },
-  },
-});
+    // Приведение stack к строке или undefined
+    const stackString = typeof stack === "string" ? stack : undefined;
+
+    // Форматирование вложенных объектов
+    const additionalData = Object.keys(rest).length
+      ? `\nAdditional Info: ${JSON.stringify(rest, null, 2)}`
+      : "";
 
-export const logger = log4js.getLogger();
+    // Извлечение информации о файле и строке из стека
+    const stackInfo = stackString ? stackString.split("\n")[1]?.trim() : "";
+    return `[${timestamp}] [${level}]: ${message} ${additionalData} ${stackInfo} `;
+  }),
+);
+// Логгер Winston
+export const logger = createLogger({
+  level: process.env.LOGS_LEVEL || "error", // Уровень логирования
+  format: customFormat, // Формат логов
+  transports: [
+    new transports.Console({
+      // Логирование в консоль
+      format: format.combine(
+        format.colorize({ all: true }), // Цветные логи для консоли
+        customFormat,
+      ),
+    }),
+    new transports.File({
+      // Логирование в файл
+      filename: path.join(__dirname, "logs", "app.log"), // Путь к файлу логов
+      level: "error", // Логировать только ошибки
+    }),
+  ],
+});

+ 32 - 0
src/plugins/logger_old.ts

@@ -0,0 +1,32 @@
+import log4js from "log4js";
+
+log4js.configure({
+  appenders: {
+    console: {
+      type: "console",
+    },
+
+    allFile: {
+      type: "file",
+      filename: "logs/all-logs.log",
+      maxLogSize: 10485760,
+      backups: 30,
+    },
+
+    emergenciesFile: { type: "file", filename: "logs/panic-logs.log" },
+
+    "just-errors": {
+      type: "logLevelFilter",
+      appender: "emergenciesFile",
+      level: "error",
+    },
+  },
+  categories: {
+    default: {
+      appenders: ["console", "allFile", "just-errors"],
+      level: process.env.LOGS_LEVEL || "all",
+    },
+  },
+});
+
+export const logger = log4js.getLogger();

+ 2 - 2
src/services/mail-service.ts

@@ -17,7 +17,7 @@ class mailService {
   }
 
   public async sendMail(to: string, title: string, html: string) {
-    logger.trace("Попытка отправки письма: ", {
+    logger.silly("Попытка отправки письма: ", {
       host: process.env.SMTP_HOST,
       port: Number(process.env.SMTP_PORT),
       user: process.env.SMTP_USER,
@@ -34,7 +34,7 @@ class mailService {
       html: html,
     });
 
-    logger.trace("Письмо отправлено: ", {
+    logger.silly("Письмо отправлено: ", {
       host: process.env.SMTP_HOST,
       port: Number(process.env.SMTP_PORT),
       user: process.env.SMTP_USER,

+ 22 - 14
src/utils/router-utils.ts

@@ -1,16 +1,24 @@
-// import { ZodTypeAny } from "zod";
-// import { Response } from "express";
+import { Response } from "express";
+import { z } from "zod";
 
-// class routerUtils {
-//   validAndSendResponse<T>(
-//     zodType: ZodTypeAny,
-//     res: Response,
-//     status: 200 | 400 | 500,
-//     resData: T,
-//   ) {
-//     const response = zodType.parse(resData);
-//     res.status(status).json(response);
-//   }
-// }
+class routerUtils {
+  /**
+   * Функция для валидации и отправки ответа
+   *
+   * @param ZResType - тип ответа
+   * @param Response - объект Response
+   * @param resData - данные ответа
+   * @param status - статус ответа, по умолчанию 200
+   */
+  validAndSendResponse<T extends z.ZodTypeAny>(
+    ZResType: T,
+    Response: Response,
+    resData: T["_output"],
+    status: 200 | 400 | 500 = 200,
+  ) {
+    const response = ZResType.parse(resData);
+    Response.status(status).json(response);
+  }
+}
 
-// export const RouterUtils = new routerUtils();
+export const RouterUtils = new routerUtils();

+ 2 - 98
src/utils/user-utils.ts

@@ -1,11 +1,8 @@
 import type { Request } from "express";
 // types
-import { ZTokenPayload } from "#modules/user/auth/types/token-playload-type.js";
-import { z } from "zod";
+import { ZTokenPayload } from "#modules/users-management/auth/types/token-playload-type.js";
+
 import { ApiError } from "#exceptions/api-error.js";
-import { db } from "#db";
-import { sql } from "slonik";
-import { ZDbShema } from "../db/db-shema.js";
 
 class userUtils {
   public getUserFromReq(req: Request) {
@@ -16,99 +13,6 @@ class userUtils {
     }
     return userData.data;
   }
-
-  async checkEventPermissions(
-    eventId: string,
-    userId: string,
-    requiredPermission: "editor" | "viewer",
-  ) {
-    // проверка прав
-    const userEventPermission = await db.maybeOneFirst(
-      sql.type(
-        z.object({
-          permission: ZDbShema.event_manager.event_permissions.permission,
-        }),
-      )`
-          select 
-            permission 
-          from 
-            event_manager.event_permissions 
-          where 
-            event_id = ${eventId} and user_id = ${userId}`,
-    );
-    if (!userEventPermission) throw ApiError.ForbiddenError();
-
-    const permissionList = {
-      creator: ["editor", "viewer"],
-      editor: ["editor", "viewer"],
-      viewer: ["viewer"],
-    };
-
-    if (!permissionList[userEventPermission].includes(requiredPermission))
-      throw ApiError.ForbiddenError();
-
-    return userEventPermission;
-  }
-
-  async checkTaskBlockPermissions(
-    taskBlockId: string,
-    userId: string,
-    requiredPermission: "editor" | "viewer",
-  ) {
-    // проверка прав
-    const userTaskBlockPermission = await db.maybeOneFirst(
-      sql.type(
-        z.object({
-          permission: ZDbShema.task_manager.task_block_permissions.permission,
-        }),
-      )`
-          select 
-            permission 
-          from 
-            task_manager.task_block_permissions 
-          where 
-            task_block_id = ${taskBlockId} and user_id = ${userId}`,
-    );
-    if (userTaskBlockPermission) {
-      // проверка прав на блок задач
-      const permissionList = {
-        editor: ["editor", "viewer"],
-        viewer: ["viewer"],
-      };
-
-      if (
-        requiredPermission &&
-        !permissionList[userTaskBlockPermission].includes(requiredPermission)
-      )
-        throw ApiError.ForbiddenError();
-
-      return userTaskBlockPermission;
-    } else {
-      // проверка прав на ивент, так как владелец ивента владеет и всеми блоками задач
-      const eventId = await db.oneFirst(
-        sql.type(
-          z.object({
-            event_id: ZDbShema.event_manager.events.event_id,
-          }),
-        )`
-              select
-                event_id
-              from
-              event_manager.task_blocks
-              where 
-                task_block_id = ${taskBlockId}
-              `,
-      );
-
-      const eventPermission = await this.checkEventPermissions(
-        eventId,
-        userId,
-        requiredPermission,
-      );
-
-      return eventPermission;
-    }
-  }
 }
 
 export const UserUtils = new userUtils();