@intlayer/backend 5.8.0-canary.0 → 5.8.1-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/cjs/controllers/organization.controller.cjs +12 -12
  2. package/dist/cjs/controllers/organization.controller.cjs.map +1 -1
  3. package/dist/cjs/controllers/project.controller.cjs +1 -1
  4. package/dist/cjs/controllers/project.controller.cjs.map +1 -1
  5. package/dist/cjs/schemas/organization.schema.cjs.map +1 -1
  6. package/dist/cjs/schemas/session.schema.cjs.map +1 -1
  7. package/dist/cjs/services/organization.service.cjs.map +1 -1
  8. package/dist/cjs/services/tag.service.cjs.map +1 -1
  9. package/dist/cjs/utils/AI/askDocQuestion/embeddings.json +46114 -28672
  10. package/dist/cjs/utils/errors/ErrorHandler.cjs +3 -3
  11. package/dist/cjs/utils/errors/ErrorHandler.cjs.map +1 -1
  12. package/dist/cjs/utils/filtersAndPagination/getFiltersAndPaginationFromBody.cjs +1 -1
  13. package/dist/cjs/utils/filtersAndPagination/getFiltersAndPaginationFromBody.cjs.map +1 -1
  14. package/dist/cjs/utils/plan.cjs +3 -3
  15. package/dist/cjs/utils/plan.cjs.map +1 -1
  16. package/dist/cjs/utils/validation/validateOrganization.cjs +5 -1
  17. package/dist/cjs/utils/validation/validateOrganization.cjs.map +1 -1
  18. package/dist/esm/controllers/organization.controller.mjs +13 -13
  19. package/dist/esm/controllers/organization.controller.mjs.map +1 -1
  20. package/dist/esm/controllers/project.controller.mjs +2 -2
  21. package/dist/esm/controllers/project.controller.mjs.map +1 -1
  22. package/dist/esm/schemas/organization.schema.mjs.map +1 -1
  23. package/dist/esm/schemas/session.schema.mjs.map +1 -1
  24. package/dist/esm/services/organization.service.mjs.map +1 -1
  25. package/dist/esm/services/tag.service.mjs.map +1 -1
  26. package/dist/esm/utils/AI/askDocQuestion/embeddings.json +46114 -28672
  27. package/dist/esm/utils/errors/ErrorHandler.mjs +1 -1
  28. package/dist/esm/utils/errors/ErrorHandler.mjs.map +1 -1
  29. package/dist/esm/utils/filtersAndPagination/getFiltersAndPaginationFromBody.mjs +1 -1
  30. package/dist/esm/utils/filtersAndPagination/getFiltersAndPaginationFromBody.mjs.map +1 -1
  31. package/dist/esm/utils/plan.mjs +2 -2
  32. package/dist/esm/utils/plan.mjs.map +1 -1
  33. package/dist/esm/utils/validation/validateOrganization.mjs +5 -1
  34. package/dist/esm/utils/validation/validateOrganization.mjs.map +1 -1
  35. package/dist/types/controllers/organization.controller.d.ts.map +1 -1
  36. package/dist/types/schemas/organization.schema.d.ts +2 -2
  37. package/dist/types/schemas/organization.schema.d.ts.map +1 -1
  38. package/dist/types/schemas/session.schema.d.ts +2 -2
  39. package/dist/types/schemas/session.schema.d.ts.map +1 -1
  40. package/dist/types/services/organization.service.d.ts +2 -2
  41. package/dist/types/services/organization.service.d.ts.map +1 -1
  42. package/dist/types/services/tag.service.d.ts +1 -1
  43. package/dist/types/services/tag.service.d.ts.map +1 -1
  44. package/dist/types/utils/errors/ErrorHandler.d.ts +1 -1
  45. package/dist/types/utils/errors/ErrorHandler.d.ts.map +1 -1
  46. package/dist/types/utils/plan.d.ts +1 -1
  47. package/dist/types/utils/validation/validateOrganization.d.ts +2 -2
  48. package/dist/types/utils/validation/validateOrganization.d.ts.map +1 -1
  49. package/package.json +8 -8
@@ -21,10 +21,10 @@ __export(ErrorHandler_exports, {
21
21
  ErrorHandler: () => ErrorHandler
22
22
  });
23
23
  module.exports = __toCommonJS(ErrorHandler_exports);
24
+ var import_httpStatusCodes = require('./../../utils/httpStatusCodes.cjs');
24
25
  var import_config = require("@intlayer/config");
25
26
  var import_logger = require('./../../logger/index.cjs');
26
27
  var import_responseData = require('./../../utils/responseData.cjs');
27
- var import_export = require('./../../export.cjs');
28
28
  var import_express_intlayer = require("express-intlayer");
29
29
  var import_errorCodes = require('./errorCodes.cjs');
30
30
  class ErrorHandler {
@@ -63,7 +63,7 @@ class ErrorHandler {
63
63
  "Error",
64
64
  error.message ?? JSON.stringify(error),
65
65
  void 0,
66
- error.httpStatusCode ?? import_export.HttpStatusCodes.INTERNAL_SERVER_ERROR_500,
66
+ error.httpStatusCode ?? import_httpStatusCodes.HttpStatusCodes.INTERNAL_SERVER_ERROR_500,
67
67
  isPaginatedResponse
68
68
  );
69
69
  }
@@ -91,7 +91,7 @@ class ErrorHandler {
91
91
  const errorTitle = (0, import_express_intlayer.t)(title, import_config.Locales.ENGLISH);
92
92
  const errorMessage = (0, import_express_intlayer.t)(message, import_config.Locales.ENGLISH);
93
93
  import_logger.logger.error(errorMessage, messageDetails);
94
- const status = statusCode ?? import_export.HttpStatusCodes.INTERNAL_SERVER_ERROR_500;
94
+ const status = statusCode ?? import_httpStatusCodes.HttpStatusCodes.INTERNAL_SERVER_ERROR_500;
95
95
  if (isPaginatedResponse) {
96
96
  const responseData2 = (0, import_responseData.formatPaginatedResponse)({
97
97
  error: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/utils/errors/ErrorHandler.ts"],"sourcesContent":["// Import required modules and types from their respective locations.\nimport { Locales } from '@intlayer/config';\nimport { logger } from '@logger';\nimport { formatPaginatedResponse, formatResponse } from '@utils/responseData';\nimport type { Response } from 'express';\n// @ts-ignore express-intlayer not build yet\nimport { type UserAPI, HttpStatusCodes } from '@/export';\nimport type { LanguageContent } from 'express-intlayer';\nimport { t } from 'express-intlayer';\nimport { type ErrorCodes, errorData } from './errorCodes';\nimport type { AppError } from './ErrorsClass';\n\n// Define a class named 'ErrorHandler' to encapsulate error handling logic.\nexport class ErrorHandler {\n /**\n * Handles generic error responses by formatting and sending a JSON response.\n * @param res - The response object provided by Express.js.\n * @param errorKey - A key representing the specific error.\n * @param statusCode - (Optional) A specific HTTP status code to use for the response.\n * @param isPaginatedResponse - Flag to determine if the response should be paginated.\n */\n static handleGenericErrorResponse(\n res: Response,\n errorKey: ErrorCodes,\n errorDetails?: object,\n statusCode?: HttpStatusCodes,\n isPaginatedResponse: boolean = false\n ) {\n const error = errorData[errorKey];\n const status = statusCode ?? error.statusCode; // Use the provided status code or default to the one in errorData.\n\n // Delegate to a more customizable error response handler.\n this.handleCustomErrorResponse(\n res,\n errorKey,\n error.title,\n error.message,\n errorDetails,\n status,\n isPaginatedResponse\n );\n }\n\n /**\n * Handles application-specific error responses by formatting and sending a JSON response.\n * @param res - The response object provided by Express.js.\n * @param error - The error object.\n * @param messageDetails - (Optional) Additional message details to include in the response.\n * @param isPaginatedResponse - (Optional) Flag to determine if the response should be paginated.\n */\n static handleAppErrorResponse(\n res: Response,\n error: AppError,\n messageDetails?: object,\n isPaginatedResponse: boolean = false\n ) {\n if (!error.isAppError) {\n this.handleCustomErrorResponse(\n res,\n error.errorKey ?? 'UNKNOWN_ERROR',\n 'Error',\n error.message ?? JSON.stringify(error),\n undefined,\n error.httpStatusCode ?? HttpStatusCodes.INTERNAL_SERVER_ERROR_500,\n isPaginatedResponse\n );\n }\n\n const isMultilingual = error.isMultilingual ?? false;\n // Delegate to a more customizable error response handler.\n this.handleCustomErrorResponse(\n res,\n error.errorKey,\n isMultilingual ? error.multilingualTitle : error.title,\n isMultilingual ? error.multilingualMessage : error.message,\n error.messageDetails ?? messageDetails,\n error.httpStatusCode,\n isPaginatedResponse\n );\n }\n\n /**\n * Handles more customizable error responses with detailed error messages and codes.\n * @param res - The response object.\n * @param errorKey - Error code key used to fetch the corresponding message and default status.\n * @param message - The localized error message object.\n * @param messageDetails - (Optional) Additional message details to include in the response.\n * @param statusCode - (Optional) HTTP status code, defaults to 500 if not specified.\n * @param isPaginatedResponse - Determines if the error should be part of a paginated response.\n */\n static handleCustomErrorResponse<T>(\n res: Response,\n errorKey: ErrorCodes | string,\n title: LanguageContent<string> | string,\n message: LanguageContent<string> | string,\n messageDetails?: object,\n statusCode?: HttpStatusCodes,\n isPaginatedResponse: boolean = false\n ) {\n const errorTitle = t(title as LanguageContent<string>, Locales.ENGLISH);\n const errorMessage = t(message as LanguageContent<string>, Locales.ENGLISH);\n logger.error(errorMessage, messageDetails); // Log the English version of the error message.\n const status = statusCode ?? HttpStatusCodes.INTERNAL_SERVER_ERROR_500; // Default to 500 if no status code is provided.\n\n if (isPaginatedResponse) {\n // Format the response as a paginated error response if requested.\n const responseData = formatPaginatedResponse<T>({\n error: {\n code: errorKey,\n title: errorTitle,\n message: errorMessage,\n },\n status,\n });\n res.status(status).json(responseData);\n return;\n }\n\n // Format the response as a standard non-paginated error response.\n const responseData = formatResponse<UserAPI>({\n error: {\n code: errorKey,\n title: errorTitle,\n message: errorMessage,\n ...messageDetails,\n },\n status,\n });\n\n res.status(status).json(responseData);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,oBAAwB;AACxB,oBAAuB;AACvB,0BAAwD;AAGxD,oBAA8C;AAE9C,8BAAkB;AAClB,wBAA2C;AAIpC,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQxB,OAAO,2BACL,KACA,UACA,cACA,YACA,sBAA+B,OAC/B;AACA,UAAM,QAAQ,4BAAU,QAAQ;AAChC,UAAM,SAAS,cAAc,MAAM;AAGnC,SAAK;AAAA,MACH;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,uBACL,KACA,OACA,gBACA,sBAA+B,OAC/B;AACA,QAAI,CAAC,MAAM,YAAY;AACrB,WAAK;AAAA,QACH;AAAA,QACA,MAAM,YAAY;AAAA,QAClB;AAAA,QACA,MAAM,WAAW,KAAK,UAAU,KAAK;AAAA,QACrC;AAAA,QACA,MAAM,kBAAkB,8BAAgB;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,iBAAiB,MAAM,kBAAkB;AAE/C,SAAK;AAAA,MACH;AAAA,MACA,MAAM;AAAA,MACN,iBAAiB,MAAM,oBAAoB,MAAM;AAAA,MACjD,iBAAiB,MAAM,sBAAsB,MAAM;AAAA,MACnD,MAAM,kBAAkB;AAAA,MACxB,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,0BACL,KACA,UACA,OACA,SACA,gBACA,YACA,sBAA+B,OAC/B;AACA,UAAM,iBAAa,2BAAE,OAAkC,sBAAQ,OAAO;AACtE,UAAM,mBAAe,2BAAE,SAAoC,sBAAQ,OAAO;AAC1E,yBAAO,MAAM,cAAc,cAAc;AACzC,UAAM,SAAS,cAAc,8BAAgB;AAE7C,QAAI,qBAAqB;AAEvB,YAAMA,oBAAe,6CAA2B;AAAA,QAC9C,OAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO;AAAA,UACP,SAAS;AAAA,QACX;AAAA,QACA;AAAA,MACF,CAAC;AACD,UAAI,OAAO,MAAM,EAAE,KAAKA,aAAY;AACpC;AAAA,IACF;AAGA,UAAM,mBAAe,oCAAwB;AAAA,MAC3C,OAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO;AAAA,QACP,SAAS;AAAA,QACT,GAAG;AAAA,MACL;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,OAAO,MAAM,EAAE,KAAK,YAAY;AAAA,EACtC;AACF;","names":["responseData"]}
1
+ {"version":3,"sources":["../../../../src/utils/errors/ErrorHandler.ts"],"sourcesContent":["// Import required modules and types from their respective locations.\nimport type { UserAPI } from '@/types/user.types';\nimport { HttpStatusCodes } from '@/utils/httpStatusCodes';\nimport { Locales } from '@intlayer/config';\nimport { logger } from '@logger';\nimport { formatPaginatedResponse, formatResponse } from '@utils/responseData';\nimport type { Response } from 'express';\n// @ts-ignore express-intlayer not build yet\nimport type { LanguageContent } from 'express-intlayer';\nimport { t } from 'express-intlayer';\nimport { type ErrorCodes, errorData } from './errorCodes';\nimport type { AppError } from './ErrorsClass';\n\n// Define a class named 'ErrorHandler' to encapsulate error handling logic.\nexport class ErrorHandler {\n /**\n * Handles generic error responses by formatting and sending a JSON response.\n * @param res - The response object provided by Express.js.\n * @param errorKey - A key representing the specific error.\n * @param statusCode - (Optional) A specific HTTP status code to use for the response.\n * @param isPaginatedResponse - Flag to determine if the response should be paginated.\n */\n static handleGenericErrorResponse(\n res: Response,\n errorKey: ErrorCodes,\n errorDetails?: object,\n statusCode?: HttpStatusCodes,\n isPaginatedResponse: boolean = false\n ) {\n const error = errorData[errorKey];\n const status = statusCode ?? error.statusCode; // Use the provided status code or default to the one in errorData.\n\n // Delegate to a more customizable error response handler.\n this.handleCustomErrorResponse(\n res,\n errorKey,\n error.title,\n error.message,\n errorDetails,\n status,\n isPaginatedResponse\n );\n }\n\n /**\n * Handles application-specific error responses by formatting and sending a JSON response.\n * @param res - The response object provided by Express.js.\n * @param error - The error object.\n * @param messageDetails - (Optional) Additional message details to include in the response.\n * @param isPaginatedResponse - (Optional) Flag to determine if the response should be paginated.\n */\n static handleAppErrorResponse(\n res: Response,\n error: AppError,\n messageDetails?: object,\n isPaginatedResponse: boolean = false\n ) {\n if (!error.isAppError) {\n this.handleCustomErrorResponse(\n res,\n error.errorKey ?? 'UNKNOWN_ERROR',\n 'Error',\n error.message ?? JSON.stringify(error),\n undefined,\n error.httpStatusCode ?? HttpStatusCodes.INTERNAL_SERVER_ERROR_500,\n isPaginatedResponse\n );\n }\n\n const isMultilingual = error.isMultilingual ?? false;\n // Delegate to a more customizable error response handler.\n this.handleCustomErrorResponse(\n res,\n error.errorKey,\n isMultilingual ? error.multilingualTitle : error.title,\n isMultilingual ? error.multilingualMessage : error.message,\n error.messageDetails ?? messageDetails,\n error.httpStatusCode,\n isPaginatedResponse\n );\n }\n\n /**\n * Handles more customizable error responses with detailed error messages and codes.\n * @param res - The response object.\n * @param errorKey - Error code key used to fetch the corresponding message and default status.\n * @param message - The localized error message object.\n * @param messageDetails - (Optional) Additional message details to include in the response.\n * @param statusCode - (Optional) HTTP status code, defaults to 500 if not specified.\n * @param isPaginatedResponse - Determines if the error should be part of a paginated response.\n */\n static handleCustomErrorResponse<T>(\n res: Response,\n errorKey: ErrorCodes | string,\n title: LanguageContent<string> | string,\n message: LanguageContent<string> | string,\n messageDetails?: object,\n statusCode?: HttpStatusCodes,\n isPaginatedResponse: boolean = false\n ) {\n const errorTitle = t(title as LanguageContent<string>, Locales.ENGLISH);\n const errorMessage = t(message as LanguageContent<string>, Locales.ENGLISH);\n logger.error(errorMessage, messageDetails); // Log the English version of the error message.\n const status = statusCode ?? HttpStatusCodes.INTERNAL_SERVER_ERROR_500; // Default to 500 if no status code is provided.\n\n if (isPaginatedResponse) {\n // Format the response as a paginated error response if requested.\n const responseData = formatPaginatedResponse<T>({\n error: {\n code: errorKey,\n title: errorTitle,\n message: errorMessage,\n },\n status,\n });\n res.status(status).json(responseData);\n return;\n }\n\n // Format the response as a standard non-paginated error response.\n const responseData = formatResponse<UserAPI>({\n error: {\n code: errorKey,\n title: errorTitle,\n message: errorMessage,\n ...messageDetails,\n },\n status,\n });\n\n res.status(status).json(responseData);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,6BAAgC;AAChC,oBAAwB;AACxB,oBAAuB;AACvB,0BAAwD;AAIxD,8BAAkB;AAClB,wBAA2C;AAIpC,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQxB,OAAO,2BACL,KACA,UACA,cACA,YACA,sBAA+B,OAC/B;AACA,UAAM,QAAQ,4BAAU,QAAQ;AAChC,UAAM,SAAS,cAAc,MAAM;AAGnC,SAAK;AAAA,MACH;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,uBACL,KACA,OACA,gBACA,sBAA+B,OAC/B;AACA,QAAI,CAAC,MAAM,YAAY;AACrB,WAAK;AAAA,QACH;AAAA,QACA,MAAM,YAAY;AAAA,QAClB;AAAA,QACA,MAAM,WAAW,KAAK,UAAU,KAAK;AAAA,QACrC;AAAA,QACA,MAAM,kBAAkB,uCAAgB;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAEA,UAAM,iBAAiB,MAAM,kBAAkB;AAE/C,SAAK;AAAA,MACH;AAAA,MACA,MAAM;AAAA,MACN,iBAAiB,MAAM,oBAAoB,MAAM;AAAA,MACjD,iBAAiB,MAAM,sBAAsB,MAAM;AAAA,MACnD,MAAM,kBAAkB;AAAA,MACxB,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,0BACL,KACA,UACA,OACA,SACA,gBACA,YACA,sBAA+B,OAC/B;AACA,UAAM,iBAAa,2BAAE,OAAkC,sBAAQ,OAAO;AACtE,UAAM,mBAAe,2BAAE,SAAoC,sBAAQ,OAAO;AAC1E,yBAAO,MAAM,cAAc,cAAc;AACzC,UAAM,SAAS,cAAc,uCAAgB;AAE7C,QAAI,qBAAqB;AAEvB,YAAMA,oBAAe,6CAA2B;AAAA,QAC9C,OAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO;AAAA,UACP,SAAS;AAAA,QACX;AAAA,QACA;AAAA,MACF,CAAC;AACD,UAAI,OAAO,MAAM,EAAE,KAAKA,aAAY;AACpC;AAAA,IACF;AAGA,UAAM,mBAAe,oCAAwB;AAAA,MAC3C,OAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO;AAAA,QACP,SAAS;AAAA,QACT,GAAG;AAAA,MACL;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,OAAO,MAAM,EAAE,KAAK,YAAY;AAAA,EACtC;AACF;","names":["responseData"]}
@@ -21,7 +21,7 @@ __export(getFiltersAndPaginationFromBody_exports, {
21
21
  getFiltersAndPaginationFromBody: () => getFiltersAndPaginationFromBody
22
22
  });
23
23
  module.exports = __toCommonJS(getFiltersAndPaginationFromBody_exports);
24
- const DEFAULT_PAGE_SIZE = 100;
24
+ const DEFAULT_PAGE_SIZE = 1e3;
25
25
  const DEFAULT_PAGE = 1;
26
26
  const getFiltersAndPaginationFromBody = (req) => {
27
27
  let filters = {};
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/utils/filtersAndPagination/getFiltersAndPaginationFromBody.ts"],"sourcesContent":["import type { Request } from 'express';\nimport type { ObjectId } from 'mongoose';\n\nconst DEFAULT_PAGE_SIZE = 100;\nconst DEFAULT_PAGE = 1;\n\ntype Filters = Record<string, string | string[] | ObjectId | ObjectId[]>;\n\nexport type FiltersAndPagination<T extends Filters> =\n | ({\n page?: string;\n pageSize?: string;\n } & T)\n | undefined;\n\nexport type FiltersAndPaginationResult<T extends Filters> = {\n filters: T;\n page: number;\n skip: number;\n pageSize: number;\n getNumberOfPages: (totalItems: number) => number;\n};\n\n/**\n * Extracts filters and pagination information from the request body.\n * @param req - Express request object.\n * @returns Object containing filters, page, pageSize, and getNumberOfPages functions.\n */\nexport const getFiltersAndPaginationFromBody = <T extends Filters>(\n req: Request<FiltersAndPagination<T>>\n): FiltersAndPaginationResult<T> => {\n let filters = {} as T;\n let pageSize = DEFAULT_PAGE_SIZE;\n let page = DEFAULT_PAGE;\n\n const query = req.query as unknown as FiltersAndPagination<T>;\n\n if (typeof query === 'object') {\n const {\n pageSize: pageSizeRequest,\n page: pageRequest,\n ...filtersRequest\n } = query;\n\n if (typeof pageSizeRequest === 'string') {\n pageSize = parseInt(pageSizeRequest);\n } else if (typeof pageSizeRequest === 'number') {\n pageSize = pageSizeRequest;\n }\n\n if (typeof pageRequest === 'string') {\n page = parseInt(pageRequest);\n } else if (typeof pageRequest === 'number') {\n page = pageRequest;\n }\n\n if (filtersRequest && Object.keys(filtersRequest).length > 0) {\n filters = filtersRequest as T;\n }\n }\n\n const skip = (page - 1) * pageSize;\n\n const getNumberOfPages = (totalItems: number) =>\n Math.ceil(totalItems / pageSize);\n\n return {\n filters,\n skip,\n page,\n pageSize,\n getNumberOfPages,\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,MAAM,oBAAoB;AAC1B,MAAM,eAAe;AAwBd,MAAM,kCAAkC,CAC7C,QACkC;AAClC,MAAI,UAAU,CAAC;AACf,MAAI,WAAW;AACf,MAAI,OAAO;AAEX,QAAM,QAAQ,IAAI;AAElB,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM;AAAA,MACJ,UAAU;AAAA,MACV,MAAM;AAAA,MACN,GAAG;AAAA,IACL,IAAI;AAEJ,QAAI,OAAO,oBAAoB,UAAU;AACvC,iBAAW,SAAS,eAAe;AAAA,IACrC,WAAW,OAAO,oBAAoB,UAAU;AAC9C,iBAAW;AAAA,IACb;AAEA,QAAI,OAAO,gBAAgB,UAAU;AACnC,aAAO,SAAS,WAAW;AAAA,IAC7B,WAAW,OAAO,gBAAgB,UAAU;AAC1C,aAAO;AAAA,IACT;AAEA,QAAI,kBAAkB,OAAO,KAAK,cAAc,EAAE,SAAS,GAAG;AAC5D,gBAAU;AAAA,IACZ;AAAA,EACF;AAEA,QAAM,QAAQ,OAAO,KAAK;AAE1B,QAAM,mBAAmB,CAAC,eACxB,KAAK,KAAK,aAAa,QAAQ;AAEjC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../src/utils/filtersAndPagination/getFiltersAndPaginationFromBody.ts"],"sourcesContent":["import type { Request } from 'express';\nimport type { ObjectId } from 'mongoose';\n\nconst DEFAULT_PAGE_SIZE = 1000;\nconst DEFAULT_PAGE = 1;\n\ntype Filters = Record<string, string | string[] | ObjectId | ObjectId[]>;\n\nexport type FiltersAndPagination<T extends Filters> =\n | ({\n page?: string;\n pageSize?: string;\n } & T)\n | undefined;\n\nexport type FiltersAndPaginationResult<T extends Filters> = {\n filters: T;\n page: number;\n skip: number;\n pageSize: number;\n getNumberOfPages: (totalItems: number) => number;\n};\n\n/**\n * Extracts filters and pagination information from the request body.\n * @param req - Express request object.\n * @returns Object containing filters, page, pageSize, and getNumberOfPages functions.\n */\nexport const getFiltersAndPaginationFromBody = <T extends Filters>(\n req: Request<FiltersAndPagination<T>>\n): FiltersAndPaginationResult<T> => {\n let filters = {} as T;\n let pageSize = DEFAULT_PAGE_SIZE;\n let page = DEFAULT_PAGE;\n\n const query = req.query as unknown as FiltersAndPagination<T>;\n\n if (typeof query === 'object') {\n const {\n pageSize: pageSizeRequest,\n page: pageRequest,\n ...filtersRequest\n } = query;\n\n if (typeof pageSizeRequest === 'string') {\n pageSize = parseInt(pageSizeRequest);\n } else if (typeof pageSizeRequest === 'number') {\n pageSize = pageSizeRequest;\n }\n\n if (typeof pageRequest === 'string') {\n page = parseInt(pageRequest);\n } else if (typeof pageRequest === 'number') {\n page = pageRequest;\n }\n\n if (filtersRequest && Object.keys(filtersRequest).length > 0) {\n filters = filtersRequest as T;\n }\n }\n\n const skip = (page - 1) * pageSize;\n\n const getNumberOfPages = (totalItems: number) =>\n Math.ceil(totalItems / pageSize);\n\n return {\n filters,\n skip,\n page,\n pageSize,\n getNumberOfPages,\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,MAAM,oBAAoB;AAC1B,MAAM,eAAe;AAwBd,MAAM,kCAAkC,CAC7C,QACkC;AAClC,MAAI,UAAU,CAAC;AACf,MAAI,WAAW;AACf,MAAI,OAAO;AAEX,QAAM,QAAQ,IAAI;AAElB,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM;AAAA,MACJ,UAAU;AAAA,MACV,MAAM;AAAA,MACN,GAAG;AAAA,IACL,IAAI;AAEJ,QAAI,OAAO,oBAAoB,UAAU;AACvC,iBAAW,SAAS,eAAe;AAAA,IACrC,WAAW,OAAO,oBAAoB,UAAU;AAC9C,iBAAW;AAAA,IACb;AAEA,QAAI,OAAO,gBAAgB,UAAU;AACnC,aAAO,SAAS,WAAW;AAAA,IAC7B,WAAW,OAAO,gBAAgB,UAAU;AAC1C,aAAO;AAAA,IACT;AAEA,QAAI,kBAAkB,OAAO,KAAK,cAAc,EAAE,SAAS,GAAG;AAC5D,gBAAU;AAAA,IACZ;AAAA,EACF;AAEA,QAAM,QAAQ,OAAO,KAAK;AAE1B,QAAM,mBAAmB,CAAC,eACxB,KAAK,KAAK,aAAa,QAAQ;AAEjC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -18,7 +18,7 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var plan_exports = {};
20
20
  __export(plan_exports, {
21
- getPLanDetails: () => getPLanDetails,
21
+ getPlanDetails: () => getPlanDetails,
22
22
  retrievePlanInformation: () => retrievePlanInformation
23
23
  });
24
24
  module.exports = __toCommonJS(plan_exports);
@@ -61,7 +61,7 @@ const planDetails = {
61
61
  contentAI: true
62
62
  }
63
63
  };
64
- const getPLanDetails = (plan) => {
64
+ const getPlanDetails = (plan) => {
65
65
  if (plan?.status !== "active") {
66
66
  return planDetails["FREE"];
67
67
  }
@@ -69,7 +69,7 @@ const getPLanDetails = (plan) => {
69
69
  };
70
70
  // Annotate the CommonJS export names for ESM import in node:
71
71
  0 && (module.exports = {
72
- getPLanDetails,
72
+ getPlanDetails,
73
73
  retrievePlanInformation
74
74
  });
75
75
  //# sourceMappingURL=plan.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/plan.ts"],"sourcesContent":["import type { Plan } from '@/types/plan.types';\n\n/**\n * Retrieves the plan type based on the price ID.\n * @param priceId - The price ID to retrieve the plan type from.\n * @returns The plan type and period.\n */\nexport const retrievePlanInformation = (\n priceId: string\n): Pick<Plan, 'period' | 'type'> => {\n switch (priceId) {\n case process.env.STRIPE_PREMIUM_YEARLY_PRICE_ID!:\n return { period: 'YEARLY', type: 'PREMIUM' };\n case process.env.STRIPE_PREMIUM_MONTHLY_PRICE_ID!:\n return { period: 'MONTHLY', type: 'PREMIUM' };\n case process.env.STRIPE_ENTERPRISE_YEARLY_PRICE_ID!:\n return { period: 'YEARLY', type: 'ENTERPRISE' };\n case process.env.STRIPE_ENTERPRISE_MONTHLY_PRICE_ID!:\n return { period: 'MONTHLY', type: 'ENTERPRISE' };\n default:\n return { period: undefined, type: 'FREE' };\n }\n};\n\ntype PlanDetails = {\n numberOfOrganizationUsers?: number;\n numberOfProjects?: number;\n totalStorage?: number;\n SeoAI: boolean;\n contentAI: boolean;\n};\n\nconst planDetails: Record<Plan['type'], PlanDetails> = {\n ['FREE']: {\n numberOfOrganizationUsers: 1,\n numberOfProjects: 1,\n totalStorage: 100, // 100 MB\n SeoAI: false,\n contentAI: false,\n },\n ['PREMIUM']: {\n numberOfOrganizationUsers: 20,\n numberOfProjects: 10,\n totalStorage: 500, // 500 MB\n SeoAI: false,\n contentAI: true,\n },\n ['ENTERPRISE']: {\n numberOfOrganizationUsers: undefined,\n numberOfProjects: undefined,\n totalStorage: undefined,\n SeoAI: true,\n contentAI: true,\n },\n};\n\nexport const getPLanDetails = (plan?: Plan): PlanDetails => {\n if (plan?.status !== 'active') {\n return planDetails['FREE'];\n }\n\n return planDetails[plan.type];\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,MAAM,0BAA0B,CACrC,YACkC;AAClC,UAAQ,SAAS;AAAA,IACf,KAAK,QAAQ,IAAI;AACf,aAAO,EAAE,QAAQ,UAAU,MAAM,UAAU;AAAA,IAC7C,KAAK,QAAQ,IAAI;AACf,aAAO,EAAE,QAAQ,WAAW,MAAM,UAAU;AAAA,IAC9C,KAAK,QAAQ,IAAI;AACf,aAAO,EAAE,QAAQ,UAAU,MAAM,aAAa;AAAA,IAChD,KAAK,QAAQ,IAAI;AACf,aAAO,EAAE,QAAQ,WAAW,MAAM,aAAa;AAAA,IACjD;AACE,aAAO,EAAE,QAAQ,QAAW,MAAM,OAAO;AAAA,EAC7C;AACF;AAUA,MAAM,cAAiD;AAAA,EACrD,CAAC,MAAM,GAAG;AAAA,IACR,2BAA2B;AAAA,IAC3B,kBAAkB;AAAA,IAClB,cAAc;AAAA;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,EACb;AAAA,EACA,CAAC,SAAS,GAAG;AAAA,IACX,2BAA2B;AAAA,IAC3B,kBAAkB;AAAA,IAClB,cAAc;AAAA;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,EACb;AAAA,EACA,CAAC,YAAY,GAAG;AAAA,IACd,2BAA2B;AAAA,IAC3B,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,EACb;AACF;AAEO,MAAM,iBAAiB,CAAC,SAA6B;AAC1D,MAAI,MAAM,WAAW,UAAU;AAC7B,WAAO,YAAY,MAAM;AAAA,EAC3B;AAEA,SAAO,YAAY,KAAK,IAAI;AAC9B;","names":[]}
1
+ {"version":3,"sources":["../../../src/utils/plan.ts"],"sourcesContent":["import type { Plan } from '@/types/plan.types';\n\n/**\n * Retrieves the plan type based on the price ID.\n * @param priceId - The price ID to retrieve the plan type from.\n * @returns The plan type and period.\n */\nexport const retrievePlanInformation = (\n priceId: string\n): Pick<Plan, 'period' | 'type'> => {\n switch (priceId) {\n case process.env.STRIPE_PREMIUM_YEARLY_PRICE_ID!:\n return { period: 'YEARLY', type: 'PREMIUM' };\n case process.env.STRIPE_PREMIUM_MONTHLY_PRICE_ID!:\n return { period: 'MONTHLY', type: 'PREMIUM' };\n case process.env.STRIPE_ENTERPRISE_YEARLY_PRICE_ID!:\n return { period: 'YEARLY', type: 'ENTERPRISE' };\n case process.env.STRIPE_ENTERPRISE_MONTHLY_PRICE_ID!:\n return { period: 'MONTHLY', type: 'ENTERPRISE' };\n default:\n return { period: undefined, type: 'FREE' };\n }\n};\n\ntype PlanDetails = {\n numberOfOrganizationUsers?: number;\n numberOfProjects?: number;\n totalStorage?: number;\n SeoAI: boolean;\n contentAI: boolean;\n};\n\nconst planDetails: Record<Plan['type'], PlanDetails> = {\n ['FREE']: {\n numberOfOrganizationUsers: 1,\n numberOfProjects: 1,\n totalStorage: 100, // 100 MB\n SeoAI: false,\n contentAI: false,\n },\n ['PREMIUM']: {\n numberOfOrganizationUsers: 20,\n numberOfProjects: 10,\n totalStorage: 500, // 500 MB\n SeoAI: false,\n contentAI: true,\n },\n ['ENTERPRISE']: {\n numberOfOrganizationUsers: undefined,\n numberOfProjects: undefined,\n totalStorage: undefined,\n SeoAI: true,\n contentAI: true,\n },\n};\n\nexport const getPlanDetails = (plan?: Plan): PlanDetails => {\n if (plan?.status !== 'active') {\n return planDetails['FREE'];\n }\n\n return planDetails[plan.type];\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,MAAM,0BAA0B,CACrC,YACkC;AAClC,UAAQ,SAAS;AAAA,IACf,KAAK,QAAQ,IAAI;AACf,aAAO,EAAE,QAAQ,UAAU,MAAM,UAAU;AAAA,IAC7C,KAAK,QAAQ,IAAI;AACf,aAAO,EAAE,QAAQ,WAAW,MAAM,UAAU;AAAA,IAC9C,KAAK,QAAQ,IAAI;AACf,aAAO,EAAE,QAAQ,UAAU,MAAM,aAAa;AAAA,IAChD,KAAK,QAAQ,IAAI;AACf,aAAO,EAAE,QAAQ,WAAW,MAAM,aAAa;AAAA,IACjD;AACE,aAAO,EAAE,QAAQ,QAAW,MAAM,OAAO;AAAA,EAC7C;AACF;AAUA,MAAM,cAAiD;AAAA,EACrD,CAAC,MAAM,GAAG;AAAA,IACR,2BAA2B;AAAA,IAC3B,kBAAkB;AAAA,IAClB,cAAc;AAAA;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,EACb;AAAA,EACA,CAAC,SAAS,GAAG;AAAA,IACX,2BAA2B;AAAA,IAC3B,kBAAkB;AAAA,IAClB,cAAc;AAAA;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,EACb;AAAA,EACA,CAAC,YAAY,GAAG;AAAA,IACd,2BAA2B;AAAA,IAC3B,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,OAAO;AAAA,IACP,WAAW;AAAA,EACb;AACF;AAEO,MAAM,iBAAiB,CAAC,SAA6B;AAC1D,MAAI,MAAM,WAAW,UAAU;AAC7B,WAAO,YAAY,MAAM;AAAA,EAC3B;AAEA,SAAO,YAAY,KAAK,IAAI;AAC9B;","names":[]}
@@ -36,9 +36,10 @@ const NAME_MAX_LENGTH = 100;
36
36
  const MEMBERS_MIN_LENGTH = 1;
37
37
  const validateOrganization = (organization, fieldsToCheck = defaultFieldsToCheck) => {
38
38
  const errors = {};
39
+ const organizationObject = JSON.parse(JSON.stringify(organization));
39
40
  const fieldsToValidate = new Set(fieldsToCheck);
40
41
  for (const field of fieldsToValidate) {
41
- const value = organization[field];
42
+ const value = organizationObject[field];
42
43
  errors[field] = [];
43
44
  if (field === "name") {
44
45
  const nameErrors = (0, import_validateString.validateString)(
@@ -52,6 +53,9 @@ const validateOrganization = (organization, fieldsToCheck = defaultFieldsToCheck
52
53
  }
53
54
  }
54
55
  if (field === "membersIds" || field === "adminsIds") {
56
+ console.log("field", field);
57
+ console.log("value", value);
58
+ console.log("typeof value", typeof value);
55
59
  const membersErrors = (0, import_validateArray.validateArray)(
56
60
  value,
57
61
  "Members",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/utils/validation/validateOrganization.ts"],"sourcesContent":["import { validateArray } from './validateArray';\nimport { validateString } from './validateString';\nimport type { Organization } from '@/types/organization.types';\n\nexport type OrganizationFields = (keyof Organization)[];\n\nconst defaultFieldsToCheck: OrganizationFields = [\n 'name',\n 'membersIds',\n 'adminsIds',\n];\n\ntype FieldsToCheck = (typeof defaultFieldsToCheck)[number];\ntype ValidationErrors = Partial<\n Record<(typeof defaultFieldsToCheck)[number], string[]>\n>;\n\nexport const NAME_MIN_LENGTH = 4;\nexport const NAME_MAX_LENGTH = 100;\n\nexport const MEMBERS_MIN_LENGTH = 1;\n\n/**\n * Validates an organization object.\n * @param organization The organization object to validate.\n * @returns An object containing the validation errors for each field.\n */\nexport const validateOrganization = (\n organization: Partial<Organization>,\n fieldsToCheck = defaultFieldsToCheck\n): ValidationErrors => {\n const errors: ValidationErrors = {};\n\n // Define the fields to validate\n const fieldsToValidate = new Set<FieldsToCheck>(fieldsToCheck);\n\n // Validate each field\n for (const field of fieldsToValidate) {\n const value = organization[field];\n\n // Initialize error array for the field\n errors[field] = [];\n\n // Check for name validity\n if (field === 'name') {\n const nameErrors = validateString(\n value,\n 'Name',\n NAME_MIN_LENGTH,\n NAME_MAX_LENGTH\n );\n\n if (nameErrors.length > 0) {\n errors[field] = nameErrors;\n }\n }\n\n if (field === 'membersIds' || field === 'adminsIds') {\n const membersErrors = validateArray<string>(\n value as unknown as string[],\n 'Members',\n 'string',\n undefined,\n MEMBERS_MIN_LENGTH\n );\n\n if (membersErrors.length > 0) {\n errors[field] = membersErrors;\n }\n }\n\n // Remove the error field if there are no errors\n if (errors[field].length === 0) {\n delete errors[field];\n }\n }\n\n return errors;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAA8B;AAC9B,4BAA+B;AAK/B,MAAM,uBAA2C;AAAA,EAC/C;AAAA,EACA;AAAA,EACA;AACF;AAOO,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AAExB,MAAM,qBAAqB;AAO3B,MAAM,uBAAuB,CAClC,cACA,gBAAgB,yBACK;AACrB,QAAM,SAA2B,CAAC;AAGlC,QAAM,mBAAmB,IAAI,IAAmB,aAAa;AAG7D,aAAW,SAAS,kBAAkB;AACpC,UAAM,QAAQ,aAAa,KAAK;AAGhC,WAAO,KAAK,IAAI,CAAC;AAGjB,QAAI,UAAU,QAAQ;AACpB,YAAM,iBAAa;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,UAAI,WAAW,SAAS,GAAG;AACzB,eAAO,KAAK,IAAI;AAAA,MAClB;AAAA,IACF;AAEA,QAAI,UAAU,gBAAgB,UAAU,aAAa;AACnD,YAAM,oBAAgB;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,UAAI,cAAc,SAAS,GAAG;AAC5B,eAAO,KAAK,IAAI;AAAA,MAClB;AAAA,IACF;AAGA,QAAI,OAAO,KAAK,EAAE,WAAW,GAAG;AAC9B,aAAO,OAAO,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../../../src/utils/validation/validateOrganization.ts"],"sourcesContent":["import type { Organization, OrganizationAPI } from '@/types/organization.types';\nimport { validateArray } from './validateArray';\nimport { validateString } from './validateString';\n\nexport type OrganizationFields = (keyof Organization)[];\n\nconst defaultFieldsToCheck: OrganizationFields = [\n 'name',\n 'membersIds',\n 'adminsIds',\n];\n\ntype FieldsToCheck = (typeof defaultFieldsToCheck)[number];\ntype ValidationErrors = Partial<\n Record<(typeof defaultFieldsToCheck)[number], string[]>\n>;\n\nexport const NAME_MIN_LENGTH = 4;\nexport const NAME_MAX_LENGTH = 100;\n\nexport const MEMBERS_MIN_LENGTH = 1;\n\n/**\n * Validates an organization object.\n * @param organization The organization object to validate.\n * @returns An object containing the validation errors for each field.\n */\nexport const validateOrganization = (\n organization: Partial<Organization | OrganizationAPI>,\n fieldsToCheck = defaultFieldsToCheck\n): ValidationErrors => {\n const errors: ValidationErrors = {};\n\n const organizationObject = JSON.parse(JSON.stringify(organization));\n\n // Define the fields to validate\n const fieldsToValidate = new Set<FieldsToCheck>(fieldsToCheck);\n\n // Validate each field\n for (const field of fieldsToValidate) {\n const value = organizationObject[field];\n\n // Initialize error array for the field\n errors[field] = [];\n\n // Check for name validity\n if (field === 'name') {\n const nameErrors = validateString(\n value,\n 'Name',\n NAME_MIN_LENGTH,\n NAME_MAX_LENGTH\n );\n\n if (nameErrors.length > 0) {\n errors[field] = nameErrors;\n }\n }\n\n if (field === 'membersIds' || field === 'adminsIds') {\n console.log('field', field);\n console.log('value', value);\n console.log('typeof value', typeof value);\n\n const membersErrors = validateArray<string>(\n value as unknown as string[],\n 'Members',\n 'string',\n undefined,\n MEMBERS_MIN_LENGTH\n );\n\n if (membersErrors.length > 0) {\n errors[field] = membersErrors;\n }\n }\n\n // Remove the error field if there are no errors\n if (errors[field].length === 0) {\n delete errors[field];\n }\n }\n\n return errors;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,2BAA8B;AAC9B,4BAA+B;AAI/B,MAAM,uBAA2C;AAAA,EAC/C;AAAA,EACA;AAAA,EACA;AACF;AAOO,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AAExB,MAAM,qBAAqB;AAO3B,MAAM,uBAAuB,CAClC,cACA,gBAAgB,yBACK;AACrB,QAAM,SAA2B,CAAC;AAElC,QAAM,qBAAqB,KAAK,MAAM,KAAK,UAAU,YAAY,CAAC;AAGlE,QAAM,mBAAmB,IAAI,IAAmB,aAAa;AAG7D,aAAW,SAAS,kBAAkB;AACpC,UAAM,QAAQ,mBAAmB,KAAK;AAGtC,WAAO,KAAK,IAAI,CAAC;AAGjB,QAAI,UAAU,QAAQ;AACpB,YAAM,iBAAa;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,UAAI,WAAW,SAAS,GAAG;AACzB,eAAO,KAAK,IAAI;AAAA,MAClB;AAAA,IACF;AAEA,QAAI,UAAU,gBAAgB,UAAU,aAAa;AACnD,cAAQ,IAAI,SAAS,KAAK;AAC1B,cAAQ,IAAI,SAAS,KAAK;AAC1B,cAAQ,IAAI,gBAAgB,OAAO,KAAK;AAExC,YAAM,oBAAgB;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,UAAI,cAAc,SAAS,GAAG;AAC5B,eAAO,KAAK,IAAI;AAAA,MAClB;AAAA,IACF;AAGA,QAAI,OAAO,KAAK,EAAE,WAAW,GAAG;AAC9B,aAAO,OAAO,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
@@ -13,7 +13,7 @@ import {
13
13
  mapOrganizationsToAPI
14
14
  } from "./../utils/mapper/organization.mjs";
15
15
  import { hasPermission } from "./../utils/permissions.mjs";
16
- import { getPLanDetails } from "./../utils/plan.mjs";
16
+ import { getPlanDetails } from "./../utils/plan.mjs";
17
17
  import {
18
18
  formatPaginatedResponse,
19
19
  formatResponse
@@ -194,7 +194,7 @@ const addOrganizationMember = async (req, res, _next) => {
194
194
  ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
195
195
  return;
196
196
  }
197
- const planType = getPLanDetails(organization.plan);
197
+ const planType = getPlanDetails(organization.plan);
198
198
  if (planType.numberOfOrganizationUsers && organization.membersIds.length >= planType.numberOfOrganizationUsers) {
199
199
  ErrorHandler.handleGenericErrorResponse(res, "PLAN_USER_LIMIT_REACHED", {
200
200
  organizationId: organization.id
@@ -213,17 +213,6 @@ const addOrganizationMember = async (req, res, _next) => {
213
213
  }
214
214
  newMember = newUser;
215
215
  }
216
- await sendEmail({
217
- type: "invite",
218
- to: userEmail,
219
- username: newMember.email.slice(0, newMember.email.indexOf("@")),
220
- invitedByUsername: user.name,
221
- invitedByEmail: user.email,
222
- organizationName: organization.name,
223
- inviteLink: `${process.env.CLIENT_URL}/auth/login?email=${newMember.email}`,
224
- inviteFromIp: req.ip ?? "",
225
- inviteFromLocation: req.hostname
226
- });
227
216
  const updatedOrganization = await organizationService.updateOrganizationById(organization.id, {
228
217
  ...organization,
229
218
  membersIds: [...organization.membersIds, newMember.id]
@@ -242,6 +231,17 @@ const addOrganizationMember = async (req, res, _next) => {
242
231
  data: mapOrganizationToAPI(updatedOrganization)
243
232
  });
244
233
  res.json(responseData);
234
+ await sendEmail({
235
+ type: "invite",
236
+ to: userEmail,
237
+ username: newMember.email.slice(0, newMember.email.indexOf("@")),
238
+ invitedByUsername: user.name,
239
+ invitedByEmail: user.email,
240
+ organizationName: organization.name,
241
+ inviteLink: `${process.env.CLIENT_URL}/auth/login?email=${newMember.email}`,
242
+ inviteFromIp: req.ip ?? "",
243
+ inviteFromLocation: req.hostname
244
+ });
245
245
  return;
246
246
  } catch (error) {
247
247
  ErrorHandler.handleAppErrorResponse(res, error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/controllers/organization.controller.ts"],"sourcesContent":["import type {\n Organization,\n OrganizationAPI,\n OrganizationCreationData,\n} from '@/types/organization.types';\nimport type { User, UserAPI } from '@/types/user.types';\nimport { logger } from '@logger';\nimport type { ResponseWithSession } from '@middlewares/sessionAuth.middleware';\nimport { SessionModel } from '@models/session.model';\nimport { sendEmail } from '@services/email.service';\nimport * as organizationService from '@services/organization.service';\nimport * as projectService from '@services/project.service';\nimport * as userService from '@services/user.service';\nimport { ErrorHandler, type AppError } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getOrganizationFiltersAndPagination,\n type OrganizationFilters,\n type OrganizationFiltersParams,\n} from '@utils/filtersAndPagination/getOrganizationFiltersAndPagination';\nimport {\n mapOrganizationToAPI,\n mapOrganizationsToAPI,\n} from '@utils/mapper/organization';\nimport { hasPermission } from '@utils/permissions';\nimport { getPLanDetails } from '@utils/plan';\nimport {\n formatPaginatedResponse,\n formatResponse,\n type PaginatedResponse,\n type ResponseData,\n} from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport { Types } from 'mongoose';\nimport { Stripe } from 'stripe';\n\nexport type GetOrganizationsParams =\n FiltersAndPagination<OrganizationFiltersParams>;\nexport type GetOrganizationsResult = PaginatedResponse<OrganizationAPI>;\n\n/**\n * Retrieves a list of organizations based on filters and pagination.\n */\nexport const getOrganizations = async (\n req: Request<GetOrganizationsParams>,\n res: ResponseWithSession<GetOrganizationsResult>,\n _next: NextFunction\n) => {\n const { user, roles } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getOrganizationFiltersAndPagination(req);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n const restrictedFilter: OrganizationFilters = {\n ...filters,\n membersIds: { $in: [...(filters?.membersIds ?? []), String(user.id)] },\n };\n\n try {\n const organizations = await organizationService.findOrganizations(\n restrictedFilter,\n skip,\n pageSize\n );\n\n if (\n !hasPermission(\n roles,\n 'organization:read'\n )({\n ...res.locals,\n targetOrganizations: organizations,\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const totalItems = await organizationService.countOrganizations(filters);\n\n const responseData = formatPaginatedResponse<OrganizationAPI>({\n data: mapOrganizationsToAPI(organizations),\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.status(200).json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetOrganizationParam = { organizationId: string };\nexport type GetOrganizationResult = ResponseData<OrganizationAPI>;\n\n/**\n * Retrieves an organization by its ID.\n */\nexport const getOrganization = async (\n req: Request<GetOrganizationParam, any, any>,\n res: ResponseWithSession<GetOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { roles } = res.locals;\n const { organizationId } = req.params as Partial<GetOrganizationParam>;\n\n if (!organizationId) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_ID_NOT_FOUND');\n return;\n }\n\n try {\n const organization =\n await organizationService.getOrganizationById(organizationId);\n\n if (\n !hasPermission(\n roles,\n 'organization:read'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const responseData = formatResponse<OrganizationAPI>({\n data: mapOrganizationToAPI(organization),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddOrganizationBody = OrganizationCreationData;\nexport type AddOrganizationResult = ResponseData<OrganizationAPI>;\n\n/**\n * Adds a new organization to the database.\n */\nexport const addOrganization = async (\n req: Request<any, any, AddOrganizationBody>,\n res: ResponseWithSession<AddOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, roles } = res.locals;\n const organization = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_DATA_NOT_FOUND');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n try {\n const newOrganization = await organizationService.createOrganization(\n organization,\n user.id\n );\n\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization created successfully',\n fr: 'Organisation créée avec succès',\n es: 'Organización creada con éxito',\n }),\n description: t({\n en: 'Your organization has been created successfully',\n fr: 'Votre organisation a été créée avec succès',\n es: 'Su organización ha sido creada con éxito',\n }),\n data: mapOrganizationToAPI(newOrganization),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateOrganizationBody = Partial<Organization>;\nexport type UpdateOrganizationResult = ResponseData<OrganizationAPI>;\n\n/**\n * Updates an existing organization in the database.\n */\nexport const updateOrganization = async (\n req: Request<undefined, undefined, UpdateOrganizationBody>,\n res: ResponseWithSession<UpdateOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, roles } = res.locals;\n const organizationFields = req.body;\n\n if (!organizationFields) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_DATA_NOT_FOUND');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'organization:write'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const updatedOrganization =\n await organizationService.updateOrganizationById(\n organization.id,\n organizationFields\n );\n\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: mapOrganizationToAPI(updatedOrganization),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddOrganizationMemberBody = {\n userEmail: string;\n};\nexport type AddOrganizationMemberResult = ResponseData<OrganizationAPI>;\n\n/**\n * Add member to the organization in the database.\n */\nexport const addOrganizationMember = async (\n req: Request<any, any, AddOrganizationMemberBody>,\n res: ResponseWithSession<AddOrganizationMemberResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, user, roles } = res.locals;\n const { userEmail } = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'organization:admin'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const planType = getPLanDetails(organization.plan);\n\n if (\n planType.numberOfOrganizationUsers &&\n organization.membersIds.length >= planType.numberOfOrganizationUsers\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PLAN_USER_LIMIT_REACHED', {\n organizationId: organization.id,\n });\n return;\n }\n\n try {\n let newMember = await userService.getUserByEmail(userEmail);\n\n if (!newMember) {\n // Create user if not found\n const newUser = await userService.createUser({ email: userEmail });\n if (!newUser) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_CREATION_FAILED', {\n email: userEmail,\n });\n return;\n }\n\n newMember = newUser;\n }\n\n await sendEmail({\n type: 'invite',\n to: userEmail,\n username: newMember.email.slice(0, newMember.email.indexOf('@')),\n invitedByUsername: user.name,\n invitedByEmail: user.email,\n organizationName: organization.name,\n inviteLink: `${process.env.CLIENT_URL}/auth/login?email=${newMember.email}`,\n inviteFromIp: req.ip ?? '',\n inviteFromLocation: req.hostname,\n });\n\n const updatedOrganization =\n await organizationService.updateOrganizationById(organization.id, {\n ...organization,\n membersIds: [...organization.membersIds, newMember.id],\n });\n\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: mapOrganizationToAPI(updatedOrganization),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateOrganizationMembersBody = Partial<{\n membersIds: (User | UserAPI)['id'][];\n adminsIds: (User | UserAPI)['id'][];\n}>;\nexport type UpdateOrganizationMembersResult = ResponseData<OrganizationAPI>;\n\n/**\n * Update members to the organization in the database.\n */\nexport const updateOrganizationMembers = async (\n req: Request<any, any, UpdateOrganizationMembersBody>,\n res: ResponseWithSession<UpdateOrganizationMembersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, roles } = res.locals;\n const { membersIds, adminsIds } = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'organization:admin'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n if (!membersIds) {\n ErrorHandler.handleGenericErrorResponse(res, 'INVALID_REQUEST_BODY');\n return;\n }\n\n if (membersIds?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_MUST_HAVE_MEMBER'\n );\n return;\n }\n\n if (adminsIds?.filter((id) => membersIds?.includes(id)).length === 0) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_MUST_HAVE_ADMIN'\n );\n return;\n }\n\n try {\n const existingUsers = await userService.getUsersByIds(membersIds);\n\n if (!existingUsers) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n const existingAdmins = await userService.getUsersByIds(adminsIds!);\n\n if (!existingAdmins) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n const updatedOrganization =\n await organizationService.updateOrganizationById(organization.id, {\n ...organization,\n membersIds: existingUsers.map((user) => user.id),\n adminsIds: existingAdmins.map((user) => user.id),\n });\n\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: mapOrganizationToAPI(updatedOrganization),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteOrganizationResult = ResponseData<OrganizationAPI>;\n\n/**\n * Deletes an organization from the database by its ID.\n */\nexport const deleteOrganization = async (\n _req: Request,\n res: ResponseWithSession,\n _next: NextFunction\n): Promise<void> => {\n const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);\n const { organization, roles } = res.locals;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n const projects = await projectService.findProjects({\n organizationId: organization.id,\n });\n\n if (projects.length > 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECTS_EXIST', {\n organizationId: organization.id,\n });\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'organization:admin'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n // Cancel the subscription on Stripe if it exists\n if (organization.plan?.subscriptionId) {\n await stripe.subscriptions.cancel(organization.plan.subscriptionId);\n }\n\n const deletedOrganization =\n await organizationService.deleteOrganizationById(organization.id);\n\n if (!deletedOrganization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_FOUND', {\n organizationId: organization.id,\n });\n return;\n }\n\n logger.info(`Organization deleted: ${String(deletedOrganization.id)}`);\n\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization deleted successfully',\n fr: 'Organisation supprimée avec succès',\n es: 'Organización eliminada con éxito',\n }),\n description: t({\n en: 'Your organization has been deleted successfully',\n fr: 'Votre organisation a été supprimée avec succès',\n es: 'Su organización ha sido eliminada con éxito',\n }),\n data: mapOrganizationToAPI(deletedOrganization),\n });\n\n // No need to update session here, as it's a delete operation\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type SelectOrganizationParam = {\n organizationId: string | Types.ObjectId;\n};\nexport type SelectOrganizationResult = ResponseData<OrganizationAPI>;\n\n/**\n * Select an organization.\n */\nexport const selectOrganization = async (\n req: Request<SelectOrganizationParam>,\n res: ResponseWithSession<SelectOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organizationId } = req.params as Partial<SelectOrganizationParam>;\n const { session } = res.locals;\n\n if (!organizationId) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_ID_NOT_FOUND');\n return;\n }\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\n }\n\n try {\n const organization =\n await organizationService.getOrganizationById(organizationId);\n\n // Update session to set activeOrganizationId\n await SessionModel.updateOne(\n { _id: session.id },\n {\n $set: {\n activeOrganizationId: String(organization.id),\n activeProjectId: null,\n },\n }\n );\n\n // No need to update session here, as it's a select operation\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization retrieved successfully',\n fr: 'Organisation récupérée avec succès',\n es: 'Organización recuperada con éxito',\n }),\n description: t({\n en: 'Your organization has been retrieved successfully',\n fr: 'Votre organisation a été récupérée avec succès',\n es: 'Su organización ha sido recuperada con éxito',\n }),\n data: mapOrganizationToAPI(organization),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UnselectOrganizationResult = ResponseData<null>;\n\n/**\n * Unselect an organization.\n */\nexport const unselectOrganization = async (\n _req: Request,\n res: ResponseWithSession<UnselectOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { session } = res.locals;\n try {\n // Update session to clear activeOrganizationId and activeProjectId\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\n }\n\n await SessionModel.updateOne(\n { _id: session.id },\n {\n $set: {\n activeOrganizationId: null,\n activeProjectId: null,\n },\n }\n );\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Organization unselected successfully',\n fr: 'Organisation désélectionnée avec succès',\n es: 'Organización deseleccionada con éxito',\n }),\n description: t({\n en: 'Your organization has been unselected successfully',\n fr: 'Votre organisation a été désélectionnée avec succès',\n es: 'Su organización ha sido deseleccionada con éxito',\n }),\n data: null,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"AAMA,SAAS,cAAc;AAEvB,SAAS,oBAAoB;AAC7B,SAAS,iBAAiB;AAC1B,YAAY,yBAAyB;AACrC,YAAY,oBAAoB;AAChC,YAAY,iBAAiB;AAC7B,SAAS,oBAAmC;AAE5C;AAAA,EACE;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAEP,SAAS,SAAS;AAElB,SAAS,cAAc;AAShB,MAAM,mBAAmB,OAC9B,KACA,KACA,UACG;AACH,QAAM,EAAE,MAAM,MAAM,IAAI,IAAI;AAC5B,QAAM,EAAE,SAAS,UAAU,MAAM,MAAM,iBAAiB,IACtD,oCAAoC,GAAG;AAEzC,MAAI,CAAC,MAAM;AACT,iBAAa,2BAA2B,KAAK,kBAAkB;AAC/D;AAAA,EACF;AAEA,QAAM,mBAAwC;AAAA,IAC5C,GAAG;AAAA,IACH,YAAY,EAAE,KAAK,CAAC,GAAI,SAAS,cAAc,CAAC,GAAI,OAAO,KAAK,EAAE,CAAC,EAAE;AAAA,EACvE;AAEA,MAAI;AACF,UAAM,gBAAgB,MAAM,oBAAoB;AAAA,MAC9C;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QACE,CAAC;AAAA,MACC;AAAA,MACA;AAAA,IACF,EAAE;AAAA,MACA,GAAG,IAAI;AAAA,MACP,qBAAqB;AAAA,IACvB,CAAC,GACD;AACA,mBAAa,2BAA2B,KAAK,mBAAmB;AAChE;AAAA,IACF;AAEA,UAAM,aAAa,MAAM,oBAAoB,mBAAmB,OAAO;AAEvE,UAAM,eAAe,wBAAyC;AAAA,MAC5D,MAAM,sBAAsB,aAAa;AAAA,MACzC;AAAA,MACA;AAAA,MACA,YAAY,iBAAiB,UAAU;AAAA,MACvC;AAAA,IACF,CAAC;AAED,QAAI,OAAO,GAAG,EAAE,KAAK,YAAY;AACjC;AAAA,EACF,SAAS,OAAO;AACd,iBAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;AAQO,MAAM,kBAAkB,OAC7B,KACA,KACA,UACkB;AAClB,QAAM,EAAE,MAAM,IAAI,IAAI;AACtB,QAAM,EAAE,eAAe,IAAI,IAAI;AAE/B,MAAI,CAAC,gBAAgB;AACnB,iBAAa,2BAA2B,KAAK,2BAA2B;AACxE;AAAA,EACF;AAEA,MAAI;AACF,UAAM,eACJ,MAAM,oBAAoB,oBAAoB,cAAc;AAE9D,QACE,CAAC;AAAA,MACC;AAAA,MACA;AAAA,IACF,EAAE;AAAA,MACA,GAAG,IAAI;AAAA,MACP,qBAAqB,CAAC,YAAY;AAAA,IACpC,CAAC,GACD;AACA,mBAAa,2BAA2B,KAAK,mBAAmB;AAChE;AAAA,IACF;AAEA,UAAM,eAAe,eAAgC;AAAA,MACnD,MAAM,qBAAqB,YAAY;AAAA,IACzC,CAAC;AAED,QAAI,KAAK,YAAY;AACrB;AAAA,EACF,SAAS,OAAO;AACd,iBAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;AAQO,MAAM,kBAAkB,OAC7B,KACA,KACA,UACkB;AAClB,QAAM,EAAE,MAAM,MAAM,IAAI,IAAI;AAC5B,QAAM,eAAe,IAAI;AAEzB,MAAI,CAAC,cAAc;AACjB,iBAAa,2BAA2B,KAAK,6BAA6B;AAC1E;AAAA,EACF;AAEA,MAAI,CAAC,MAAM;AACT,iBAAa,2BAA2B,KAAK,kBAAkB;AAC/D;AAAA,EACF;AAEA,MAAI;AACF,UAAM,kBAAkB,MAAM,oBAAoB;AAAA,MAChD;AAAA,MACA,KAAK;AAAA,IACP;AAEA,UAAM,eAAe,eAAgC;AAAA,MACnD,SAAS,EAAE;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,aAAa,EAAE;AAAA,QACb,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,MAAM,qBAAqB,eAAe;AAAA,IAC5C,CAAC;AAED,QAAI,KAAK,YAAY;AACrB;AAAA,EACF,SAAS,OAAO;AACd,iBAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;AAQO,MAAM,qBAAqB,OAChC,KACA,KACA,UACkB;AAClB,QAAM,EAAE,cAAc,MAAM,IAAI,IAAI;AACpC,QAAM,qBAAqB,IAAI;AAE/B,MAAI,CAAC,oBAAoB;AACvB,iBAAa,2BAA2B,KAAK,6BAA6B;AAC1E;AAAA,EACF;AAEA,MAAI,CAAC,cAAc;AACjB,iBAAa,2BAA2B,KAAK,0BAA0B;AACvE;AAAA,EACF;AAEA,MACE,CAAC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EAAE;AAAA,IACA,GAAG,IAAI;AAAA,IACP,qBAAqB,CAAC,YAAY;AAAA,EACpC,CAAC,GACD;AACA,iBAAa,2BAA2B,KAAK,mBAAmB;AAChE;AAAA,EACF;AAEA,MAAI;AACF,UAAM,sBACJ,MAAM,oBAAoB;AAAA,MACxB,aAAa;AAAA,MACb;AAAA,IACF;AAEF,UAAM,eAAe,eAAgC;AAAA,MACnD,SAAS,EAAE;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,aAAa,EAAE;AAAA,QACb,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,MAAM,qBAAqB,mBAAmB;AAAA,IAChD,CAAC;AAED,QAAI,KAAK,YAAY;AACrB;AAAA,EACF,SAAS,OAAO;AACd,iBAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;AAUO,MAAM,wBAAwB,OACnC,KACA,KACA,UACkB;AAClB,QAAM,EAAE,cAAc,MAAM,MAAM,IAAI,IAAI;AAC1C,QAAM,EAAE,UAAU,IAAI,IAAI;AAE1B,MAAI,CAAC,cAAc;AACjB,iBAAa,2BAA2B,KAAK,0BAA0B;AACvE;AAAA,EACF;AAEA,MAAI,CAAC,MAAM;AACT,iBAAa,2BAA2B,KAAK,kBAAkB;AAC/D;AAAA,EACF;AAEA,MACE,CAAC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EAAE;AAAA,IACA,GAAG,IAAI;AAAA,IACP,qBAAqB,CAAC,YAAY;AAAA,EACpC,CAAC,GACD;AACA,iBAAa,2BAA2B,KAAK,mBAAmB;AAChE;AAAA,EACF;AAEA,QAAM,WAAW,eAAe,aAAa,IAAI;AAEjD,MACE,SAAS,6BACT,aAAa,WAAW,UAAU,SAAS,2BAC3C;AACA,iBAAa,2BAA2B,KAAK,2BAA2B;AAAA,MACtE,gBAAgB,aAAa;AAAA,IAC/B,CAAC;AACD;AAAA,EACF;AAEA,MAAI;AACF,QAAI,YAAY,MAAM,YAAY,eAAe,SAAS;AAE1D,QAAI,CAAC,WAAW;AAEd,YAAM,UAAU,MAAM,YAAY,WAAW,EAAE,OAAO,UAAU,CAAC;AACjE,UAAI,CAAC,SAAS;AACZ,qBAAa,2BAA2B,KAAK,wBAAwB;AAAA,UACnE,OAAO;AAAA,QACT,CAAC;AACD;AAAA,MACF;AAEA,kBAAY;AAAA,IACd;AAEA,UAAM,UAAU;AAAA,MACd,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,UAAU,UAAU,MAAM,MAAM,GAAG,UAAU,MAAM,QAAQ,GAAG,CAAC;AAAA,MAC/D,mBAAmB,KAAK;AAAA,MACxB,gBAAgB,KAAK;AAAA,MACrB,kBAAkB,aAAa;AAAA,MAC/B,YAAY,GAAG,QAAQ,IAAI,UAAU,qBAAqB,UAAU,KAAK;AAAA,MACzE,cAAc,IAAI,MAAM;AAAA,MACxB,oBAAoB,IAAI;AAAA,IAC1B,CAAC;AAED,UAAM,sBACJ,MAAM,oBAAoB,uBAAuB,aAAa,IAAI;AAAA,MAChE,GAAG;AAAA,MACH,YAAY,CAAC,GAAG,aAAa,YAAY,UAAU,EAAE;AAAA,IACvD,CAAC;AAEH,UAAM,eAAe,eAAgC;AAAA,MACnD,SAAS,EAAE;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,aAAa,EAAE;AAAA,QACb,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,MAAM,qBAAqB,mBAAmB;AAAA,IAChD,CAAC;AAED,QAAI,KAAK,YAAY;AACrB;AAAA,EACF,SAAS,OAAO;AACd,iBAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;AAWO,MAAM,4BAA4B,OACvC,KACA,KACA,UACkB;AAClB,QAAM,EAAE,cAAc,MAAM,IAAI,IAAI;AACpC,QAAM,EAAE,YAAY,UAAU,IAAI,IAAI;AAEtC,MAAI,CAAC,cAAc;AACjB,iBAAa,2BAA2B,KAAK,0BAA0B;AACvE;AAAA,EACF;AAEA,MACE,CAAC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EAAE;AAAA,IACA,GAAG,IAAI;AAAA,IACP,qBAAqB,CAAC,YAAY;AAAA,EACpC,CAAC,GACD;AACA,iBAAa,2BAA2B,KAAK,mBAAmB;AAChE;AAAA,EACF;AAEA,MAAI,CAAC,YAAY;AACf,iBAAa,2BAA2B,KAAK,sBAAsB;AACnE;AAAA,EACF;AAEA,MAAI,YAAY,WAAW,GAAG;AAC5B,iBAAa;AAAA,MACX;AAAA,MACA;AAAA,IACF;AACA;AAAA,EACF;AAEA,MAAI,WAAW,OAAO,CAAC,OAAO,YAAY,SAAS,EAAE,CAAC,EAAE,WAAW,GAAG;AACpE,iBAAa;AAAA,MACX;AAAA,MACA;AAAA,IACF;AACA;AAAA,EACF;AAEA,MAAI;AACF,UAAM,gBAAgB,MAAM,YAAY,cAAc,UAAU;AAEhE,QAAI,CAAC,eAAe;AAClB,mBAAa,2BAA2B,KAAK,gBAAgB;AAC7D;AAAA,IACF;AAEA,UAAM,iBAAiB,MAAM,YAAY,cAAc,SAAU;AAEjE,QAAI,CAAC,gBAAgB;AACnB,mBAAa,2BAA2B,KAAK,gBAAgB;AAC7D;AAAA,IACF;AAEA,UAAM,sBACJ,MAAM,oBAAoB,uBAAuB,aAAa,IAAI;AAAA,MAChE,GAAG;AAAA,MACH,YAAY,cAAc,IAAI,CAAC,SAAS,KAAK,EAAE;AAAA,MAC/C,WAAW,eAAe,IAAI,CAAC,SAAS,KAAK,EAAE;AAAA,IACjD,CAAC;AAEH,UAAM,eAAe,eAAgC;AAAA,MACnD,SAAS,EAAE;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,aAAa,EAAE;AAAA,QACb,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,MAAM,qBAAqB,mBAAmB;AAAA,IAChD,CAAC;AAED,QAAI,KAAK,YAAY;AACrB;AAAA,EACF,SAAS,OAAO;AACd,iBAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;AAOO,MAAM,qBAAqB,OAChC,MACA,KACA,UACkB;AAClB,QAAM,SAAS,IAAI,OAAO,QAAQ,IAAI,iBAAkB;AACxD,QAAM,EAAE,cAAc,MAAM,IAAI,IAAI;AAEpC,MAAI,CAAC,cAAc;AACjB,iBAAa,2BAA2B,KAAK,0BAA0B;AACvE;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,eAAe,aAAa;AAAA,IACjD,gBAAgB,aAAa;AAAA,EAC/B,CAAC;AAED,MAAI,SAAS,SAAS,GAAG;AACvB,iBAAa,2BAA2B,KAAK,kBAAkB;AAAA,MAC7D,gBAAgB,aAAa;AAAA,IAC/B,CAAC;AACD;AAAA,EACF;AAEA,MACE,CAAC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EAAE;AAAA,IACA,GAAG,IAAI;AAAA,IACP,qBAAqB,CAAC,YAAY;AAAA,EACpC,CAAC,GACD;AACA,iBAAa,2BAA2B,KAAK,mBAAmB;AAChE;AAAA,EACF;AAEA,MAAI;AAEF,QAAI,aAAa,MAAM,gBAAgB;AACrC,YAAM,OAAO,cAAc,OAAO,aAAa,KAAK,cAAc;AAAA,IACpE;AAEA,UAAM,sBACJ,MAAM,oBAAoB,uBAAuB,aAAa,EAAE;AAElE,QAAI,CAAC,qBAAqB;AACxB,mBAAa,2BAA2B,KAAK,0BAA0B;AAAA,QACrE,gBAAgB,aAAa;AAAA,MAC/B,CAAC;AACD;AAAA,IACF;AAEA,WAAO,KAAK,yBAAyB,OAAO,oBAAoB,EAAE,CAAC,EAAE;AAErE,UAAM,eAAe,eAAgC;AAAA,MACnD,SAAS,EAAE;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,aAAa,EAAE;AAAA,QACb,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,MAAM,qBAAqB,mBAAmB;AAAA,IAChD,CAAC;AAGD,QAAI,KAAK,YAAY;AACrB;AAAA,EACF,SAAS,OAAO;AACd,iBAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;AAUO,MAAM,qBAAqB,OAChC,KACA,KACA,UACkB;AAClB,QAAM,EAAE,eAAe,IAAI,IAAI;AAC/B,QAAM,EAAE,QAAQ,IAAI,IAAI;AAExB,MAAI,CAAC,gBAAgB;AACnB,iBAAa,2BAA2B,KAAK,2BAA2B;AACxE;AAAA,EACF;AAEA,MAAI,OAAO,YAAY,aAAa;AAClC,iBAAa,2BAA2B,KAAK,qBAAqB;AAClE;AAAA,EACF;AAEA,MAAI;AACF,UAAM,eACJ,MAAM,oBAAoB,oBAAoB,cAAc;AAG9D,UAAM,aAAa;AAAA,MACjB,EAAE,KAAK,QAAQ,GAAG;AAAA,MAClB;AAAA,QACE,MAAM;AAAA,UACJ,sBAAsB,OAAO,aAAa,EAAE;AAAA,UAC5C,iBAAiB;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAGA,UAAM,eAAe,eAAgC;AAAA,MACnD,SAAS,EAAE;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,aAAa,EAAE;AAAA,QACb,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,MAAM,qBAAqB,YAAY;AAAA,IACzC,CAAC;AAED,QAAI,KAAK,YAAY;AACrB;AAAA,EACF,SAAS,OAAO;AACd,iBAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;AAOO,MAAM,uBAAuB,OAClC,MACA,KACA,UACkB;AAClB,QAAM,EAAE,QAAQ,IAAI,IAAI;AACxB,MAAI;AAGF,QAAI,OAAO,YAAY,aAAa;AAClC,mBAAa,2BAA2B,KAAK,qBAAqB;AAClE;AAAA,IACF;AAEA,UAAM,aAAa;AAAA,MACjB,EAAE,KAAK,QAAQ,GAAG;AAAA,MAClB;AAAA,QACE,MAAM;AAAA,UACJ,sBAAsB;AAAA,UACtB,iBAAiB;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAEA,UAAM,eAAe,eAAqB;AAAA,MACxC,SAAS,EAAE;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,aAAa,EAAE;AAAA,QACb,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN,CAAC;AAAA,MACD,MAAM;AAAA,IACR,CAAC;AAED,QAAI,KAAK,YAAY;AACrB;AAAA,EACF,SAAS,OAAO;AACd,iBAAa,uBAAuB,KAAK,KAAiB;AAC1D;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/controllers/organization.controller.ts"],"sourcesContent":["import type {\n Organization,\n OrganizationAPI,\n OrganizationCreationData,\n} from '@/types/organization.types';\nimport type { User, UserAPI } from '@/types/user.types';\nimport { logger } from '@logger';\nimport type { ResponseWithSession } from '@middlewares/sessionAuth.middleware';\nimport { SessionModel } from '@models/session.model';\nimport { sendEmail } from '@services/email.service';\nimport * as organizationService from '@services/organization.service';\nimport * as projectService from '@services/project.service';\nimport * as userService from '@services/user.service';\nimport { ErrorHandler, type AppError } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getOrganizationFiltersAndPagination,\n type OrganizationFilters,\n type OrganizationFiltersParams,\n} from '@utils/filtersAndPagination/getOrganizationFiltersAndPagination';\nimport {\n mapOrganizationToAPI,\n mapOrganizationsToAPI,\n} from '@utils/mapper/organization';\nimport { hasPermission } from '@utils/permissions';\nimport { getPlanDetails } from '@utils/plan';\nimport {\n formatPaginatedResponse,\n formatResponse,\n type PaginatedResponse,\n type ResponseData,\n} from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport { Types } from 'mongoose';\nimport { Stripe } from 'stripe';\n\nexport type GetOrganizationsParams =\n FiltersAndPagination<OrganizationFiltersParams>;\nexport type GetOrganizationsResult = PaginatedResponse<OrganizationAPI>;\n\n/**\n * Retrieves a list of organizations based on filters and pagination.\n */\nexport const getOrganizations = async (\n req: Request<GetOrganizationsParams>,\n res: ResponseWithSession<GetOrganizationsResult>,\n _next: NextFunction\n) => {\n const { user, roles } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getOrganizationFiltersAndPagination(req);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n const restrictedFilter: OrganizationFilters = {\n ...filters,\n membersIds: { $in: [...(filters?.membersIds ?? []), String(user.id)] },\n };\n\n try {\n const organizations = await organizationService.findOrganizations(\n restrictedFilter,\n skip,\n pageSize\n );\n\n if (\n !hasPermission(\n roles,\n 'organization:read'\n )({\n ...res.locals,\n targetOrganizations: organizations,\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const totalItems = await organizationService.countOrganizations(filters);\n\n const responseData = formatPaginatedResponse<OrganizationAPI>({\n data: mapOrganizationsToAPI(organizations),\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.status(200).json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type GetOrganizationParam = { organizationId: string };\nexport type GetOrganizationResult = ResponseData<OrganizationAPI>;\n\n/**\n * Retrieves an organization by its ID.\n */\nexport const getOrganization = async (\n req: Request<GetOrganizationParam, any, any>,\n res: ResponseWithSession<GetOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { roles } = res.locals;\n const { organizationId } = req.params as Partial<GetOrganizationParam>;\n\n if (!organizationId) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_ID_NOT_FOUND');\n return;\n }\n\n try {\n const organization =\n await organizationService.getOrganizationById(organizationId);\n\n if (\n !hasPermission(\n roles,\n 'organization:read'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const responseData = formatResponse<OrganizationAPI>({\n data: mapOrganizationToAPI(organization),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddOrganizationBody = OrganizationCreationData;\nexport type AddOrganizationResult = ResponseData<OrganizationAPI>;\n\n/**\n * Adds a new organization to the database.\n */\nexport const addOrganization = async (\n req: Request<any, any, AddOrganizationBody>,\n res: ResponseWithSession<AddOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, roles } = res.locals;\n const organization = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_DATA_NOT_FOUND');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n try {\n const newOrganization = await organizationService.createOrganization(\n organization,\n user.id\n );\n\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization created successfully',\n fr: 'Organisation créée avec succès',\n es: 'Organización creada con éxito',\n }),\n description: t({\n en: 'Your organization has been created successfully',\n fr: 'Votre organisation a été créée avec succès',\n es: 'Su organización ha sido creada con éxito',\n }),\n data: mapOrganizationToAPI(newOrganization),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateOrganizationBody = Partial<Organization>;\nexport type UpdateOrganizationResult = ResponseData<OrganizationAPI>;\n\n/**\n * Updates an existing organization in the database.\n */\nexport const updateOrganization = async (\n req: Request<undefined, undefined, UpdateOrganizationBody>,\n res: ResponseWithSession<UpdateOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, roles } = res.locals;\n const organizationFields = req.body;\n\n if (!organizationFields) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_DATA_NOT_FOUND');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'organization:write'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const updatedOrganization =\n await organizationService.updateOrganizationById(\n organization.id,\n organizationFields\n );\n\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: mapOrganizationToAPI(updatedOrganization),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddOrganizationMemberBody = {\n userEmail: string;\n};\nexport type AddOrganizationMemberResult = ResponseData<OrganizationAPI>;\n\n/**\n * Add member to the organization in the database.\n */\nexport const addOrganizationMember = async (\n req: Request<any, any, AddOrganizationMemberBody>,\n res: ResponseWithSession<AddOrganizationMemberResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, user, roles } = res.locals;\n const { userEmail } = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'organization:admin'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const planType = getPlanDetails(organization.plan);\n\n if (\n planType.numberOfOrganizationUsers &&\n organization.membersIds.length >= planType.numberOfOrganizationUsers\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PLAN_USER_LIMIT_REACHED', {\n organizationId: organization.id,\n });\n return;\n }\n\n try {\n let newMember = await userService.getUserByEmail(userEmail);\n\n if (!newMember) {\n // Create user if not found\n const newUser = await userService.createUser({ email: userEmail });\n if (!newUser) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_CREATION_FAILED', {\n email: userEmail,\n });\n return;\n }\n\n newMember = newUser;\n }\n\n const updatedOrganization =\n await organizationService.updateOrganizationById(organization.id, {\n ...organization,\n membersIds: [...organization.membersIds, newMember.id],\n });\n\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: mapOrganizationToAPI(updatedOrganization),\n });\n\n res.json(responseData);\n\n await sendEmail({\n type: 'invite',\n to: userEmail,\n username: newMember.email.slice(0, newMember.email.indexOf('@')),\n invitedByUsername: user.name,\n invitedByEmail: user.email,\n organizationName: organization.name,\n inviteLink: `${process.env.CLIENT_URL}/auth/login?email=${newMember.email}`,\n inviteFromIp: req.ip ?? '',\n inviteFromLocation: req.hostname,\n });\n\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateOrganizationMembersBody = Partial<{\n membersIds: (User | UserAPI)['id'][];\n adminsIds: (User | UserAPI)['id'][];\n}>;\nexport type UpdateOrganizationMembersResult = ResponseData<OrganizationAPI>;\n\n/**\n * Update members to the organization in the database.\n */\nexport const updateOrganizationMembers = async (\n req: Request<any, any, UpdateOrganizationMembersBody>,\n res: ResponseWithSession<UpdateOrganizationMembersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, roles } = res.locals;\n const { membersIds, adminsIds } = req.body;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'organization:admin'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n if (!membersIds) {\n ErrorHandler.handleGenericErrorResponse(res, 'INVALID_REQUEST_BODY');\n return;\n }\n\n if (membersIds?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_MUST_HAVE_MEMBER'\n );\n return;\n }\n\n if (adminsIds?.filter((id) => membersIds?.includes(id)).length === 0) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'ORGANIZATION_MUST_HAVE_ADMIN'\n );\n return;\n }\n\n try {\n const existingUsers = await userService.getUsersByIds(membersIds);\n\n if (!existingUsers) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n const existingAdmins = await userService.getUsersByIds(adminsIds!);\n\n if (!existingAdmins) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_FOUND');\n return;\n }\n\n const updatedOrganization =\n await organizationService.updateOrganizationById(organization.id, {\n ...organization,\n membersIds: existingUsers.map((user) => user.id),\n adminsIds: existingAdmins.map((user) => user.id),\n });\n\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization updated successfully',\n fr: 'Organisation mise à jour avec succès',\n es: 'Organización actualizada con éxito',\n }),\n description: t({\n en: 'Your organization has been updated successfully',\n fr: 'Votre organisation a été mise à jour avec succès',\n es: 'Su organización ha sido actualizada con éxito',\n }),\n data: mapOrganizationToAPI(updatedOrganization),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteOrganizationResult = ResponseData<OrganizationAPI>;\n\n/**\n * Deletes an organization from the database by its ID.\n */\nexport const deleteOrganization = async (\n _req: Request,\n res: ResponseWithSession,\n _next: NextFunction\n): Promise<void> => {\n const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);\n const { organization, roles } = res.locals;\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n const projects = await projectService.findProjects({\n organizationId: organization.id,\n });\n\n if (projects.length > 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECTS_EXIST', {\n organizationId: organization.id,\n });\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'organization:admin'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n // Cancel the subscription on Stripe if it exists\n if (organization.plan?.subscriptionId) {\n await stripe.subscriptions.cancel(organization.plan.subscriptionId);\n }\n\n const deletedOrganization =\n await organizationService.deleteOrganizationById(organization.id);\n\n if (!deletedOrganization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_FOUND', {\n organizationId: organization.id,\n });\n return;\n }\n\n logger.info(`Organization deleted: ${String(deletedOrganization.id)}`);\n\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization deleted successfully',\n fr: 'Organisation supprimée avec succès',\n es: 'Organización eliminada con éxito',\n }),\n description: t({\n en: 'Your organization has been deleted successfully',\n fr: 'Votre organisation a été supprimée avec succès',\n es: 'Su organización ha sido eliminada con éxito',\n }),\n data: mapOrganizationToAPI(deletedOrganization),\n });\n\n // No need to update session here, as it's a delete operation\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type SelectOrganizationParam = {\n organizationId: string | Types.ObjectId;\n};\nexport type SelectOrganizationResult = ResponseData<OrganizationAPI>;\n\n/**\n * Select an organization.\n */\nexport const selectOrganization = async (\n req: Request<SelectOrganizationParam>,\n res: ResponseWithSession<SelectOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organizationId } = req.params as Partial<SelectOrganizationParam>;\n const { session } = res.locals;\n\n if (!organizationId) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_ID_NOT_FOUND');\n return;\n }\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\n }\n\n try {\n const organization =\n await organizationService.getOrganizationById(organizationId);\n\n // Update session to set activeOrganizationId\n await SessionModel.updateOne(\n { _id: session.id },\n {\n $set: {\n activeOrganizationId: String(organization.id),\n activeProjectId: null,\n },\n }\n );\n\n // No need to update session here, as it's a select operation\n const responseData = formatResponse<OrganizationAPI>({\n message: t({\n en: 'Organization retrieved successfully',\n fr: 'Organisation récupérée avec succès',\n es: 'Organización recuperada con éxito',\n }),\n description: t({\n en: 'Your organization has been retrieved successfully',\n fr: 'Votre organisation a été récupérée avec succès',\n es: 'Su organización ha sido recuperada con éxito',\n }),\n data: mapOrganizationToAPI(organization),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UnselectOrganizationResult = ResponseData<null>;\n\n/**\n * Unselect an organization.\n */\nexport const unselectOrganization = async (\n _req: Request,\n res: ResponseWithSession<UnselectOrganizationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { session } = res.locals;\n try {\n // Update session to clear activeOrganizationId and activeProjectId\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\n }\n\n await SessionModel.updateOne(\n { _id: session.id },\n {\n $set: {\n activeOrganizationId: null,\n activeProjectId: null,\n },\n }\n );\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Organization unselected successfully',\n fr: 'Organisation désélectionnée avec succès',\n es: 'Organización deseleccionada con éxito',\n }),\n description: t({\n en: 'Your organization has been unselected successfully',\n fr: 'Votre organisation a été désélectionnée avec succès',\n es: 'Su organización ha sido deseleccionada con éxito',\n }),\n data: null,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":[]}
@@ -8,7 +8,7 @@ import {
8
8
  } from "./../utils/filtersAndPagination/getProjectFiltersAndPagination.mjs";
9
9
  import { mapProjectsToAPI, mapProjectToAPI } from "./../utils/mapper/project.mjs";
10
10
  import { hasPermission } from "./../utils/permissions.mjs";
11
- import { getPLanDetails } from "./../utils/plan.mjs";
11
+ import { getPlanDetails } from "./../utils/plan.mjs";
12
12
  import {
13
13
  formatPaginatedResponse,
14
14
  formatResponse
@@ -87,7 +87,7 @@ const addProject = async (req, res, _next) => {
87
87
  return;
88
88
  }
89
89
  const { plan } = organization;
90
- const planType = getPLanDetails(plan);
90
+ const planType = getPlanDetails(plan);
91
91
  if (planType.numberOfProjects) {
92
92
  const projectCount = await projectService.countProjects({
93
93
  organizationId: organization.id
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/controllers/project.controller.ts"],"sourcesContent":["import type {\n Project,\n ProjectAPI,\n ProjectConfiguration,\n ProjectCreationData,\n ProjectData,\n} from '@/types/project.types';\nimport type { User } from '@/types/user.types';\nimport { logger } from '@logger';\nimport type { ResponseWithSession } from '@middlewares/sessionAuth.middleware';\nimport { SessionModel } from '@models/session.model';\nimport * as projectService from '@services/project.service';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getProjectFiltersAndPagination,\n type ProjectFilters,\n type ProjectFiltersParams,\n} from '@utils/filtersAndPagination/getProjectFiltersAndPagination';\nimport { mapProjectsToAPI, mapProjectToAPI } from '@utils/mapper/project';\nimport { hasPermission } from '@utils/permissions';\nimport { getPLanDetails } from '@utils/plan';\nimport {\n formatPaginatedResponse,\n formatResponse,\n type PaginatedResponse,\n type ResponseData,\n} from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport { Types } from 'mongoose';\n\nexport type GetProjectsParams = FiltersAndPagination<ProjectFiltersParams>;\nexport type GetProjectsResult = PaginatedResponse<ProjectAPI>;\n\n/**\n * Retrieves a list of projects based on filters and pagination.\n */\nexport const getProjects = async (\n req: Request<GetProjectsParams>,\n res: ResponseWithSession<GetProjectsResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, roles } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getProjectFiltersAndPagination(req);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n const restrictedFilter: ProjectFilters = {\n ...filters,\n membersIds: { $in: [...(filters.membersIds ?? []), String(user.id)] },\n organizationId: String(organization.id),\n };\n\n try {\n const projects = await projectService.findProjects(\n restrictedFilter,\n skip,\n pageSize\n );\n\n if (\n !hasPermission(\n roles,\n 'project:read'\n )({\n ...res.locals,\n targetProjects: projects,\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const totalItems = await projectService.countProjects(filters);\n\n const formattedProjects = mapProjectsToAPI(projects);\n\n const responseData = formatPaginatedResponse<ProjectAPI>({\n data: formattedProjects,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddProjectBody = ProjectCreationData;\nexport type AddProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Adds a new project to the database.\n */\nexport const addProject = async (\n req: Request<any, any, AddProjectBody>,\n res: ResponseWithSession<AddProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, user, roles } = res.locals;\n const projectData = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!projectData) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n }\n\n if (\n !hasPermission(\n roles,\n 'organization:admin'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const { plan } = organization;\n\n const planType = getPLanDetails(plan);\n\n if (planType.numberOfProjects) {\n const projectCount = await projectService.countProjects({\n organizationId: organization.id,\n });\n\n if (projectCount >= planType.numberOfProjects) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'PLAN_PROJECT_LIMIT_REACHED',\n {\n organizationId: organization.id,\n }\n );\n return;\n }\n }\n\n const project: ProjectData = {\n membersIds: [user.id],\n adminsIds: [user.id],\n creatorId: user.id,\n organizationId: organization.id,\n ...projectData,\n };\n\n try {\n const newProject = await projectService.createProject(project);\n\n const formattedProject = mapProjectToAPI(newProject);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project created successfully',\n fr: 'Projet créé avec succès',\n es: 'Proyecto creado con éxito',\n }),\n description: t({\n en: 'Your project has been created successfully',\n fr: 'Votre projet a été créé avec succès',\n es: 'Su proyecto ha sido creado con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateProjectBody = Partial<Project>;\nexport type UpdateProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Updates an existing project in the database.\n */\nexport const updateProject = async (\n req: Request<any, any, UpdateProjectBody>,\n res: ResponseWithSession<UpdateProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, project, user, roles } = res.locals;\n const projectData = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (String(project.organizationId) !== String(organization.id)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_IN_ORGANIZATION');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:write'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const updatedProject = await projectService.updateProjectById(\n project.id,\n projectData\n );\n\n const formattedProject = mapProjectToAPI(updatedProject);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project updated successfully',\n fr: 'Projet mis à jour avec succès',\n es: 'Proyecto actualizado con éxito',\n }),\n description: t({\n en: 'Your project has been updated successfully',\n fr: 'Votre projet a été mis à jour avec succès',\n es: 'Su proyecto ha sido actualizado con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\ntype UserAndAdmin = { user: User; isAdmin: boolean };\nexport type ProjectMemberByIdOption = {\n userId: string | Types.ObjectId;\n isAdmin?: boolean;\n};\n\nexport type UpdateProjectMembersBody = Partial<{\n membersIds: ProjectMemberByIdOption[];\n}>;\nexport type UpdateProjectMembersResult = ResponseData<ProjectAPI>;\n\n/**\n * Update members to the dictionary in the database.\n */\nexport const updateProjectMembers = async (\n req: Request<any, any, UpdateProjectMembersBody>,\n res: ResponseWithSession<UpdateProjectMembersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, organization, roles } = res.locals;\n const { membersIds } = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (membersIds?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_MUST_HAVE_MEMBER');\n return;\n }\n\n if (membersIds?.map((el) => el.isAdmin)?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_MUST_HAVE_ADMIN');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:write'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const existingUsers: UserAndAdmin[] = [];\n\n if (membersIds) {\n const userIdList = membersIds\n ?.filter(\n (member) =>\n // Remove members that are not in the organization\n !organization?.membersIds.includes(member.userId as Types.ObjectId)\n )\n .map((member) => member.userId);\n\n const users = await userService.getUsersByIds(userIdList);\n\n if (users) {\n const userMap: UserAndAdmin[] = users.map((user) => ({\n user,\n isAdmin:\n membersIds.find(\n (member) => String(member.userId) === String(user.id)\n )?.isAdmin ?? false,\n }));\n\n existingUsers.push(...userMap);\n }\n }\n\n const formattedMembers: Types.ObjectId[] = existingUsers.map(\n (user) => user.user.id\n );\n const formattedAdmin: Types.ObjectId[] = existingUsers\n .filter((el) => el.isAdmin)\n .map((user) => user.user.id);\n\n const updatedOrganization = await projectService.updateProjectById(\n project.id,\n {\n ...project,\n membersIds: formattedMembers,\n adminsIds: formattedAdmin,\n }\n );\n\n const formattedProject = mapProjectToAPI(updatedOrganization);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project members updated successfully',\n fr: 'Membres du projet mis à jour avec succès',\n es: 'Miembros del proyecto actualizados con éxito',\n }),\n description: t({\n en: 'Your project members have been updated successfully',\n fr: 'Les membres de votre projet ont été mis à jour avec succès',\n es: 'Los miembros de su proyecto han sido actualizados con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type PushProjectConfigurationBody = ProjectConfiguration;\nexport type PushProjectConfigurationResult = ResponseData<ProjectConfiguration>;\n\n/**\n * Pushes a project configuration to the database.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response confirming the deletion.\n */\nexport const pushProjectConfiguration = async (\n req: Request<any, any, PushProjectConfigurationBody>,\n res: ResponseWithSession<PushProjectConfigurationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, roles } = res.locals;\n const projectConfiguration = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:write'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const projectObject = await projectService.getProjectById(project.id);\n projectObject.configuration = projectConfiguration;\n\n projectObject.save();\n\n if (!projectObject.configuration) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_UPDATE_FAILED', {\n projectId: project.id,\n });\n return;\n }\n\n const responseData = formatResponse<ProjectConfiguration>({\n message: t({\n en: 'Project configuration updated successfully',\n fr: 'Configuration du projet mise à jour avec succès',\n es: 'Configuración del proyecto actualizada con éxito',\n }),\n description: t({\n en: 'Your project configuration has been updated successfully',\n fr: 'La configuration du projet a été mise à jour avec succès',\n es: 'Su configuración del proyecto ha sido actualizada con éxito',\n }),\n data: projectObject.configuration,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Deletes a project from the database by its ID.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response confirming the deletion.\n */\nexport const deleteProject = async (\n _req: Request,\n res: ResponseWithSession<DeleteProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, project, session, roles } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:admin'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const projectToDelete = await projectService.getProjectById(project.id);\n\n if (String(projectToDelete.organizationId) !== String(organization.id)) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'PROJECT_NOT_IN_ORGANIZATION'\n );\n return;\n }\n\n const deletedProject = await projectService.deleteProjectById(project.id);\n\n if (!deletedProject) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED', {\n projectId: project.id,\n });\n\n return;\n }\n\n logger.info(`Project deleted: ${String(deletedProject.id)}`);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project deleted successfully',\n fr: 'Projet supprimé avec succès',\n es: 'Proyecto eliminado con éxito',\n }),\n description: t({\n en: 'Your project has been deleted successfully',\n fr: 'Votre projet a été supprimé avec succès',\n es: 'Su proyecto ha sido eliminado con éxito',\n }),\n data: mapProjectToAPI(deletedProject),\n });\n\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: null } }\n );\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type SelectProjectParam = { projectId: string | Types.ObjectId };\nexport type SelectProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Select a project.\n */\nexport const selectProject = async (\n req: Request<SelectProjectParam>,\n res: ResponseWithSession<SelectProjectResult>,\n _next: NextFunction\n) => {\n const { projectId } = req.params;\n const { session, roles } = res.locals;\n\n if (!projectId) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_ID_NOT_FOUND');\n return;\n }\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\n }\n\n try {\n const project = await projectService.getProjectById(projectId);\n\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: String(projectId) } }\n );\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project selected successfully',\n fr: 'Projet sélectionné avec succès',\n es: 'Proyecto seleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been selected successfully',\n fr: 'Votre projet a été sélectionné avec succès',\n es: 'Su proyecto ha sido seleccionado con éxito',\n }),\n data: mapProjectToAPI(project),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UnselectProjectResult = ResponseData<null>;\n\n/**\n * Unselect a project.\n */\nexport const unselectProject = async (\n _req: Request,\n res: ResponseWithSession<UnselectProjectResult>,\n _next: NextFunction\n) => {\n const { session } = res.locals;\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\n }\n\n try {\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: null } }\n );\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Project unselected successfully',\n fr: 'Projet désélectionné avec succès',\n es: 'Proyecto deseleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been unselected successfully',\n fr: 'Votre projet a été désélectionné avec succès',\n es: 'Su proyecto ha sido deseleccionado con éxito',\n }),\n data: null,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":["user"]}
1
+ {"version":3,"sources":["../../../src/controllers/project.controller.ts"],"sourcesContent":["import type {\n Project,\n ProjectAPI,\n ProjectConfiguration,\n ProjectCreationData,\n ProjectData,\n} from '@/types/project.types';\nimport type { User } from '@/types/user.types';\nimport { logger } from '@logger';\nimport type { ResponseWithSession } from '@middlewares/sessionAuth.middleware';\nimport { SessionModel } from '@models/session.model';\nimport * as projectService from '@services/project.service';\nimport * as userService from '@services/user.service';\nimport { type AppError, ErrorHandler } from '@utils/errors';\nimport type { FiltersAndPagination } from '@utils/filtersAndPagination/getFiltersAndPaginationFromBody';\nimport {\n getProjectFiltersAndPagination,\n type ProjectFilters,\n type ProjectFiltersParams,\n} from '@utils/filtersAndPagination/getProjectFiltersAndPagination';\nimport { mapProjectsToAPI, mapProjectToAPI } from '@utils/mapper/project';\nimport { hasPermission } from '@utils/permissions';\nimport { getPlanDetails } from '@utils/plan';\nimport {\n formatPaginatedResponse,\n formatResponse,\n type PaginatedResponse,\n type ResponseData,\n} from '@utils/responseData';\nimport type { NextFunction, Request } from 'express';\nimport { t } from 'express-intlayer';\nimport { Types } from 'mongoose';\n\nexport type GetProjectsParams = FiltersAndPagination<ProjectFiltersParams>;\nexport type GetProjectsResult = PaginatedResponse<ProjectAPI>;\n\n/**\n * Retrieves a list of projects based on filters and pagination.\n */\nexport const getProjects = async (\n req: Request<GetProjectsParams>,\n res: ResponseWithSession<GetProjectsResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, roles } = res.locals;\n const { filters, pageSize, skip, page, getNumberOfPages } =\n getProjectFiltersAndPagination(req);\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n const restrictedFilter: ProjectFilters = {\n ...filters,\n membersIds: { $in: [...(filters.membersIds ?? []), String(user.id)] },\n organizationId: String(organization.id),\n };\n\n try {\n const projects = await projectService.findProjects(\n restrictedFilter,\n skip,\n pageSize\n );\n\n if (\n !hasPermission(\n roles,\n 'project:read'\n )({\n ...res.locals,\n targetProjects: projects,\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const totalItems = await projectService.countProjects(filters);\n\n const formattedProjects = mapProjectsToAPI(projects);\n\n const responseData = formatPaginatedResponse<ProjectAPI>({\n data: formattedProjects,\n page,\n pageSize,\n totalPages: getNumberOfPages(totalItems),\n totalItems,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type AddProjectBody = ProjectCreationData;\nexport type AddProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Adds a new project to the database.\n */\nexport const addProject = async (\n req: Request<any, any, AddProjectBody>,\n res: ResponseWithSession<AddProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, user, roles } = res.locals;\n const projectData = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!projectData) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n }\n\n if (\n !hasPermission(\n roles,\n 'organization:admin'\n )({\n ...res.locals,\n targetOrganizations: [organization],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n const { plan } = organization;\n\n const planType = getPlanDetails(plan);\n\n if (planType.numberOfProjects) {\n const projectCount = await projectService.countProjects({\n organizationId: organization.id,\n });\n\n if (projectCount >= planType.numberOfProjects) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'PLAN_PROJECT_LIMIT_REACHED',\n {\n organizationId: organization.id,\n }\n );\n return;\n }\n }\n\n const project: ProjectData = {\n membersIds: [user.id],\n adminsIds: [user.id],\n creatorId: user.id,\n organizationId: organization.id,\n ...projectData,\n };\n\n try {\n const newProject = await projectService.createProject(project);\n\n const formattedProject = mapProjectToAPI(newProject);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project created successfully',\n fr: 'Projet créé avec succès',\n es: 'Proyecto creado con éxito',\n }),\n description: t({\n en: 'Your project has been created successfully',\n fr: 'Votre projet a été créé avec succès',\n es: 'Su proyecto ha sido creado con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UpdateProjectBody = Partial<Project>;\nexport type UpdateProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Updates an existing project in the database.\n */\nexport const updateProject = async (\n req: Request<any, any, UpdateProjectBody>,\n res: ResponseWithSession<UpdateProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { organization, project, user, roles } = res.locals;\n const projectData = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_DATA_NOT_FOUND');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (String(project.organizationId) !== String(organization.id)) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_IN_ORGANIZATION');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:write'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const updatedProject = await projectService.updateProjectById(\n project.id,\n projectData\n );\n\n const formattedProject = mapProjectToAPI(updatedProject);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project updated successfully',\n fr: 'Projet mis à jour avec succès',\n es: 'Proyecto actualizado con éxito',\n }),\n description: t({\n en: 'Your project has been updated successfully',\n fr: 'Votre projet a été mis à jour avec succès',\n es: 'Su proyecto ha sido actualizado con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\ntype UserAndAdmin = { user: User; isAdmin: boolean };\nexport type ProjectMemberByIdOption = {\n userId: string | Types.ObjectId;\n isAdmin?: boolean;\n};\n\nexport type UpdateProjectMembersBody = Partial<{\n membersIds: ProjectMemberByIdOption[];\n}>;\nexport type UpdateProjectMembersResult = ResponseData<ProjectAPI>;\n\n/**\n * Update members to the dictionary in the database.\n */\nexport const updateProjectMembers = async (\n req: Request<any, any, UpdateProjectMembersBody>,\n res: ResponseWithSession<UpdateProjectMembersResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, organization, roles } = res.locals;\n const { membersIds } = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (membersIds?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_MUST_HAVE_MEMBER');\n return;\n }\n\n if (membersIds?.map((el) => el.isAdmin)?.length === 0) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_MUST_HAVE_ADMIN');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:write'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const existingUsers: UserAndAdmin[] = [];\n\n if (membersIds) {\n const userIdList = membersIds\n ?.filter(\n (member) =>\n // Remove members that are not in the organization\n !organization?.membersIds.includes(member.userId as Types.ObjectId)\n )\n .map((member) => member.userId);\n\n const users = await userService.getUsersByIds(userIdList);\n\n if (users) {\n const userMap: UserAndAdmin[] = users.map((user) => ({\n user,\n isAdmin:\n membersIds.find(\n (member) => String(member.userId) === String(user.id)\n )?.isAdmin ?? false,\n }));\n\n existingUsers.push(...userMap);\n }\n }\n\n const formattedMembers: Types.ObjectId[] = existingUsers.map(\n (user) => user.user.id\n );\n const formattedAdmin: Types.ObjectId[] = existingUsers\n .filter((el) => el.isAdmin)\n .map((user) => user.user.id);\n\n const updatedOrganization = await projectService.updateProjectById(\n project.id,\n {\n ...project,\n membersIds: formattedMembers,\n adminsIds: formattedAdmin,\n }\n );\n\n const formattedProject = mapProjectToAPI(updatedOrganization);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project members updated successfully',\n fr: 'Membres du projet mis à jour avec succès',\n es: 'Miembros del proyecto actualizados con éxito',\n }),\n description: t({\n en: 'Your project members have been updated successfully',\n fr: 'Les membres de votre projet ont été mis à jour avec succès',\n es: 'Los miembros de su proyecto han sido actualizados con éxito',\n }),\n data: formattedProject,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type PushProjectConfigurationBody = ProjectConfiguration;\nexport type PushProjectConfigurationResult = ResponseData<ProjectConfiguration>;\n\n/**\n * Pushes a project configuration to the database.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response confirming the deletion.\n */\nexport const pushProjectConfiguration = async (\n req: Request<any, any, PushProjectConfigurationBody>,\n res: ResponseWithSession<PushProjectConfigurationResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, project, roles } = res.locals;\n const projectConfiguration = req.body;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:write'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const projectObject = await projectService.getProjectById(project.id);\n projectObject.configuration = projectConfiguration;\n\n projectObject.save();\n\n if (!projectObject.configuration) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_UPDATE_FAILED', {\n projectId: project.id,\n });\n return;\n }\n\n const responseData = formatResponse<ProjectConfiguration>({\n message: t({\n en: 'Project configuration updated successfully',\n fr: 'Configuration du projet mise à jour avec succès',\n es: 'Configuración del proyecto actualizada con éxito',\n }),\n description: t({\n en: 'Your project configuration has been updated successfully',\n fr: 'La configuration du projet a été mise à jour avec succès',\n es: 'Su configuración del proyecto ha sido actualizada con éxito',\n }),\n data: projectObject.configuration,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type DeleteProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Deletes a project from the database by its ID.\n * @param req - Express request object.\n * @param res - Express response object.\n * @returns Response confirming the deletion.\n */\nexport const deleteProject = async (\n _req: Request,\n res: ResponseWithSession<DeleteProjectResult>,\n _next: NextFunction\n): Promise<void> => {\n const { user, organization, project, session, roles } = res.locals;\n\n if (!user) {\n ErrorHandler.handleGenericErrorResponse(res, 'USER_NOT_DEFINED');\n return;\n }\n\n if (!organization) {\n ErrorHandler.handleGenericErrorResponse(res, 'ORGANIZATION_NOT_DEFINED');\n return;\n }\n\n if (!project) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED');\n return;\n }\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\n }\n\n if (\n !hasPermission(\n roles,\n 'project:admin'\n )({\n ...res.locals,\n targetProjectIds: [String(project.id)],\n })\n ) {\n ErrorHandler.handleGenericErrorResponse(res, 'PERMISSION_DENIED');\n return;\n }\n\n try {\n const projectToDelete = await projectService.getProjectById(project.id);\n\n if (String(projectToDelete.organizationId) !== String(organization.id)) {\n ErrorHandler.handleGenericErrorResponse(\n res,\n 'PROJECT_NOT_IN_ORGANIZATION'\n );\n return;\n }\n\n const deletedProject = await projectService.deleteProjectById(project.id);\n\n if (!deletedProject) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_NOT_DEFINED', {\n projectId: project.id,\n });\n\n return;\n }\n\n logger.info(`Project deleted: ${String(deletedProject.id)}`);\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project deleted successfully',\n fr: 'Projet supprimé avec succès',\n es: 'Proyecto eliminado con éxito',\n }),\n description: t({\n en: 'Your project has been deleted successfully',\n fr: 'Votre projet a été supprimé avec succès',\n es: 'Su proyecto ha sido eliminado con éxito',\n }),\n data: mapProjectToAPI(deletedProject),\n });\n\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: null } }\n );\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type SelectProjectParam = { projectId: string | Types.ObjectId };\nexport type SelectProjectResult = ResponseData<ProjectAPI>;\n\n/**\n * Select a project.\n */\nexport const selectProject = async (\n req: Request<SelectProjectParam>,\n res: ResponseWithSession<SelectProjectResult>,\n _next: NextFunction\n) => {\n const { projectId } = req.params;\n const { session, roles } = res.locals;\n\n if (!projectId) {\n ErrorHandler.handleGenericErrorResponse(res, 'PROJECT_ID_NOT_FOUND');\n return;\n }\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\n }\n\n try {\n const project = await projectService.getProjectById(projectId);\n\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: String(projectId) } }\n );\n\n const responseData = formatResponse<ProjectAPI>({\n message: t({\n en: 'Project selected successfully',\n fr: 'Projet sélectionné avec succès',\n es: 'Proyecto seleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been selected successfully',\n fr: 'Votre projet a été sélectionné avec succès',\n es: 'Su proyecto ha sido seleccionado con éxito',\n }),\n data: mapProjectToAPI(project),\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n\nexport type UnselectProjectResult = ResponseData<null>;\n\n/**\n * Unselect a project.\n */\nexport const unselectProject = async (\n _req: Request,\n res: ResponseWithSession<UnselectProjectResult>,\n _next: NextFunction\n) => {\n const { session } = res.locals;\n\n if (typeof session === 'undefined') {\n ErrorHandler.handleGenericErrorResponse(res, 'SESSION_NOT_DEFINED');\n return;\n }\n\n try {\n await SessionModel.updateOne(\n { _id: session.id },\n { $set: { activeProjectId: null } }\n );\n\n const responseData = formatResponse<null>({\n message: t({\n en: 'Project unselected successfully',\n fr: 'Projet désélectionné avec succès',\n es: 'Proyecto deseleccionado con éxito',\n }),\n description: t({\n en: 'Your project has been unselected successfully',\n fr: 'Votre projet a été désélectionné avec succès',\n es: 'Su proyecto ha sido deseleccionado con éxito',\n }),\n data: null,\n });\n\n res.json(responseData);\n return;\n } catch (error) {\n ErrorHandler.handleAppErrorResponse(res, error as AppError);\n return;\n }\n};\n"],"mappings":"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","names":["user"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/schemas/organization.schema.ts"],"sourcesContent":["import { OrganizationSchema } from '@/export';\nimport {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateOrganization';\nimport { Schema } from 'mongoose';\nimport { planSchema } from './plans.schema';\n\nexport const organizationSchema = new Schema<OrganizationSchema>(\n {\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n plan: {\n type: planSchema,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(doc, ret: any) {\n ret.id = ret._id.toString(); // convert _id to id\n delete ret._id; // remove _id\n },\n },\n toObject: {\n virtuals: true,\n transform(doc, ret: any) {\n ret.id = ret._id; // convert _id to id\n delete ret._id; // remove _id\n },\n },\n }\n);\n\n// Add virtual field for id\norganizationSchema.virtual('id').get(function () {\n return this._id.toString();\n});\n"],"mappings":"AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAEpB,MAAM,qBAAqB,IAAI;AAAA,EACpC;AAAA,IACE,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,UAAU;AAAA,MACV,WAAW;AAAA,MACX,WAAW;AAAA,IACb;AAAA,IACA,YAAY;AAAA,MACV,MAAM,CAAC,OAAO,MAAM,QAAQ;AAAA,MAC5B,KAAK;AAAA,MACL,UAAU;AAAA,MACV,WAAW;AAAA,IACb;AAAA,IACA,WAAW;AAAA,MACT,MAAM,CAAC,OAAO,MAAM,QAAQ;AAAA,MAC5B,KAAK;AAAA,MACL,UAAU;AAAA,MACV,WAAW;AAAA,IACb;AAAA,IACA,WAAW;AAAA,MACT,MAAM,OAAO,MAAM;AAAA,MACnB,KAAK;AAAA,MACL,UAAU;AAAA,IACZ;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA;AAAA,IACE,YAAY;AAAA,IAEZ,QAAQ;AAAA,MACN,UAAU;AAAA;AAAA,MACV,YAAY;AAAA;AAAA,MACZ,UAAU,KAAK,KAAU;AACvB,YAAI,KAAK,IAAI,IAAI,SAAS;AAC1B,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,UAAU;AAAA,MACV,UAAU,KAAK,KAAU;AACvB,YAAI,KAAK,IAAI;AACb,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;AAGA,mBAAmB,QAAQ,IAAI,EAAE,IAAI,WAAY;AAC/C,SAAO,KAAK,IAAI,SAAS;AAC3B,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/schemas/organization.schema.ts"],"sourcesContent":["import { OrganizationSchema } from '@/types/organization.types';\nimport {\n MEMBERS_MIN_LENGTH,\n NAME_MAX_LENGTH,\n NAME_MIN_LENGTH,\n} from '@utils/validation/validateOrganization';\nimport { Schema } from 'mongoose';\nimport { planSchema } from './plans.schema';\n\nexport const organizationSchema = new Schema<OrganizationSchema>(\n {\n name: {\n type: String,\n required: true,\n minlength: NAME_MIN_LENGTH,\n maxlength: NAME_MAX_LENGTH,\n },\n membersIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n adminsIds: {\n type: [Schema.Types.ObjectId],\n ref: 'User',\n required: true,\n minlength: MEMBERS_MIN_LENGTH,\n },\n creatorId: {\n type: Schema.Types.ObjectId,\n ref: 'User',\n required: true,\n },\n plan: {\n type: planSchema,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(doc, ret: any) {\n ret.id = ret._id.toString(); // convert _id to id\n delete ret._id; // remove _id\n },\n },\n toObject: {\n virtuals: true,\n transform(doc, ret: any) {\n ret.id = ret._id; // convert _id to id\n delete ret._id; // remove _id\n },\n },\n }\n);\n\n// Add virtual field for id\norganizationSchema.virtual('id').get(function () {\n return this._id.toString();\n});\n"],"mappings":"AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAEpB,MAAM,qBAAqB,IAAI;AAAA,EACpC;AAAA,IACE,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,UAAU;AAAA,MACV,WAAW;AAAA,MACX,WAAW;AAAA,IACb;AAAA,IACA,YAAY;AAAA,MACV,MAAM,CAAC,OAAO,MAAM,QAAQ;AAAA,MAC5B,KAAK;AAAA,MACL,UAAU;AAAA,MACV,WAAW;AAAA,IACb;AAAA,IACA,WAAW;AAAA,MACT,MAAM,CAAC,OAAO,MAAM,QAAQ;AAAA,MAC5B,KAAK;AAAA,MACL,UAAU;AAAA,MACV,WAAW;AAAA,IACb;AAAA,IACA,WAAW;AAAA,MACT,MAAM,OAAO,MAAM;AAAA,MACnB,KAAK;AAAA,MACL,UAAU;AAAA,IACZ;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA;AAAA,IACE,YAAY;AAAA,IAEZ,QAAQ;AAAA,MACN,UAAU;AAAA;AAAA,MACV,YAAY;AAAA;AAAA,MACZ,UAAU,KAAK,KAAU;AACvB,YAAI,KAAK,IAAI,IAAI,SAAS;AAC1B,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,UAAU;AAAA,MACV,UAAU,KAAK,KAAU;AACvB,YAAI,KAAK,IAAI;AACb,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;AAGA,mBAAmB,QAAQ,IAAI,EAAE,IAAI,WAAY;AAC/C,SAAO,KAAK,IAAI,SAAS;AAC3B,CAAC;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/schemas/session.schema.ts"],"sourcesContent":["import { SessionSchema } from '@/export';\nimport { Schema } from 'mongoose';\n\nexport const sessionSchema = new Schema<SessionSchema>(\n {\n activeOrganizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: false,\n },\n activeProjectId: {\n type: Schema.Types.ObjectId,\n ref: 'Project',\n required: false,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(doc, ret: any) {\n ret.id = ret._id.toString(); // convert _id to id\n delete ret._id; // remove _id\n },\n },\n toObject: {\n virtuals: true,\n transform(doc, ret: any) {\n ret.id = ret._id; // convert _id to id\n delete ret._id; // remove _id\n },\n },\n }\n);\n"],"mappings":"AACA,SAAS,cAAc;AAEhB,MAAM,gBAAgB,IAAI;AAAA,EAC/B;AAAA,IACE,sBAAsB;AAAA,MACpB,MAAM,OAAO,MAAM;AAAA,MACnB,KAAK;AAAA,MACL,UAAU;AAAA,IACZ;AAAA,IACA,iBAAiB;AAAA,MACf,MAAM,OAAO,MAAM;AAAA,MACnB,KAAK;AAAA,MACL,UAAU;AAAA,IACZ;AAAA,EACF;AAAA,EACA;AAAA,IACE,YAAY;AAAA,IAEZ,QAAQ;AAAA,MACN,UAAU;AAAA;AAAA,MACV,YAAY;AAAA;AAAA,MACZ,UAAU,KAAK,KAAU;AACvB,YAAI,KAAK,IAAI,IAAI,SAAS;AAC1B,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,UAAU;AAAA,MACV,UAAU,KAAK,KAAU;AACvB,YAAI,KAAK,IAAI;AACb,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/schemas/session.schema.ts"],"sourcesContent":["import { SessionSchema } from '@/types/session.types';\nimport { Schema } from 'mongoose';\n\nexport const sessionSchema = new Schema<SessionSchema>(\n {\n activeOrganizationId: {\n type: Schema.Types.ObjectId,\n ref: 'Organization',\n required: false,\n },\n activeProjectId: {\n type: Schema.Types.ObjectId,\n ref: 'Project',\n required: false,\n },\n },\n {\n timestamps: true,\n\n toJSON: {\n virtuals: true, // keep the automatic `id` getter\n versionKey: false, // drop __v\n transform(doc, ret: any) {\n ret.id = ret._id.toString(); // convert _id to id\n delete ret._id; // remove _id\n },\n },\n toObject: {\n virtuals: true,\n transform(doc, ret: any) {\n ret.id = ret._id; // convert _id to id\n delete ret._id; // remove _id\n },\n },\n }\n);\n"],"mappings":"AACA,SAAS,cAAc;AAEhB,MAAM,gBAAgB,IAAI;AAAA,EAC/B;AAAA,IACE,sBAAsB;AAAA,MACpB,MAAM,OAAO,MAAM;AAAA,MACnB,KAAK;AAAA,MACL,UAAU;AAAA,IACZ;AAAA,IACA,iBAAiB;AAAA,MACf,MAAM,OAAO,MAAM;AAAA,MACnB,KAAK;AAAA,MACL,UAAU;AAAA,IACZ;AAAA,EACF;AAAA,EACA;AAAA,IACE,YAAY;AAAA,IAEZ,QAAQ;AAAA,MACN,UAAU;AAAA;AAAA,MACV,YAAY;AAAA;AAAA,MACZ,UAAU,KAAK,KAAU;AACvB,YAAI,KAAK,IAAI,IAAI,SAAS;AAC1B,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,UAAU;AAAA,MACV,UAAU,KAAK,KAAU;AACvB,YAAI,KAAK,IAAI;AACb,eAAO,IAAI;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/services/organization.service.ts"],"sourcesContent":["import type {\n Organization,\n OrganizationCreationData,\n OrganizationDocument,\n} from '@/types/organization.types';\nimport type { Plan, PlanDocument } from '@/types/plan.types';\nimport { OrganizationModel } from '@models/organization.model';\nimport { GenericError } from '@utils/errors';\nimport type { OrganizationFilters } from '@utils/filtersAndPagination/getOrganizationFiltersAndPagination';\nimport {\n type OrganizationFields,\n validateOrganization,\n} from '@utils/validation/validateOrganization';\nimport type { Types } from 'mongoose';\n\n/**\n * Finds organizations based on filters and pagination options.\n * @param filters - MongoDB filter query.\n * @param skip - Number of documents to skip.\n * @param limit - Number of documents to limit.\n * @returns List of organizations matching the filters.\n */\nexport const findOrganizations = async (\n filters: OrganizationFilters,\n skip: number,\n limit: number\n): Promise<OrganizationDocument[]> =>\n await OrganizationModel.find(filters).skip(skip).limit(limit);\n\n/**\n * Finds an organization by its ID.\n * @param organizationId - The ID of the organization to find.\n * @returns The organization matching the ID.\n */\nexport const getOrganizationById = async (\n organizationId: string | Types.ObjectId\n): Promise<OrganizationDocument> => {\n const organization = await OrganizationModel.findById(organizationId);\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND', { organizationId });\n }\n\n return organization;\n};\n\n/**\n * Counts the total number of organizations that match the filters.\n * @param filters - MongoDB filter query.\n * @returns Total number of organizations.\n */\nexport const countOrganizations = async (\n filters: OrganizationFilters\n): Promise<number> => {\n const result = await OrganizationModel.countDocuments(filters);\n\n if (typeof result === 'undefined') {\n throw new GenericError('ORGANIZATION_COUNT_FAILED', { filters });\n }\n\n return result;\n};\n\n/**\n * Creates a new organization in the database.\n * @param organization - The organization data to create.\n * @returns The created organization.\n */\nexport const createOrganization = async (\n organization: OrganizationCreationData,\n userId: string | Types.ObjectId\n): Promise<OrganizationDocument> => {\n const errors = validateOrganization(organization, ['name']);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('ORGANIZATION_INVALID_FIELDS', { errors });\n }\n\n try {\n const result = await OrganizationModel.create({\n creatorId: userId,\n membersIds: [userId],\n adminsIds: [userId],\n ...organization,\n });\n\n return result;\n } catch (error) {\n throw new GenericError('ORGANIZATION_CREATION_FAILED', {\n error: (error as Error).message,\n });\n }\n};\n\n/**\n * Updates an existing organization in the database by its ID.\n * @param organizationId - The ID of the organization to update.\n * @param organization - The updated organization data.\n * @returns The updated organization.\n */\nexport const updateOrganizationById = async (\n organizationId: string | Types.ObjectId,\n organization: Partial<Organization>\n): Promise<OrganizationDocument> => {\n const updatedKeys = Object.keys(organization) as OrganizationFields;\n const errors = validateOrganization(organization, updatedKeys);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('ORGANIZATION_INVALID_FIELDS', {\n organizationId,\n errors,\n });\n }\n\n const result = await OrganizationModel.updateOne(\n { _id: organizationId },\n organization\n );\n\n if (result.matchedCount === 0) {\n throw new GenericError('ORGANIZATION_UPDATE_FAILED', { organizationId });\n }\n\n return await getOrganizationById(organizationId);\n};\n\n/**\n * Deletes an organization from the database by its ID.\n * @param organizationId - The ID of the organization to delete.\n * @returns The result of the deletion operation.\n */\nexport const deleteOrganizationById = async (\n organizationId: string | Types.ObjectId\n): Promise<OrganizationDocument> => {\n const organization =\n await OrganizationModel.findByIdAndDelete(organizationId);\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND', { organizationId });\n }\n\n return organization;\n};\n\n/**\n * Updates an existing plan in the database by its ID.\n * @param planId - The ID of the plan to update.\n * @param plan - The updated plan data.\n * @returns The updated plan.\n */\nexport const updatePlan = async (\n organization: Organization | OrganizationDocument,\n plan: Partial<Plan>\n): Promise<OrganizationDocument | null> => {\n let prevPlan = organization.plan ?? {};\n\n if (typeof (prevPlan as PlanDocument)?.toObject === 'function') {\n prevPlan = (prevPlan as PlanDocument).toObject();\n }\n\n const updateOrganizationResult = await OrganizationModel.updateOne(\n { _id: organization.id },\n { $set: { plan: { ...prevPlan, ...plan } } }\n );\n\n if (updateOrganizationResult.matchedCount === 0) {\n throw new GenericError('ORGANIZATION_UPDATE_FAILED', {\n organizationId: organization.id,\n });\n }\n\n const updatedOrganization = await getOrganizationById(organization.id);\n\n return updatedOrganization;\n};\n"],"mappings":"AAMA,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;AAE7B;AAAA,EAEE;AAAA,OACK;AAUA,MAAM,oBAAoB,OAC/B,SACA,MACA,UAEA,MAAM,kBAAkB,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,KAAK;AAOvD,MAAM,sBAAsB,OACjC,mBACkC;AAClC,QAAM,eAAe,MAAM,kBAAkB,SAAS,cAAc;AAEpE,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,aAAa,0BAA0B,EAAE,eAAe,CAAC;AAAA,EACrE;AAEA,SAAO;AACT;AAOO,MAAM,qBAAqB,OAChC,YACoB;AACpB,QAAM,SAAS,MAAM,kBAAkB,eAAe,OAAO;AAE7D,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI,aAAa,6BAA6B,EAAE,QAAQ,CAAC;AAAA,EACjE;AAEA,SAAO;AACT;AAOO,MAAM,qBAAqB,OAChC,cACA,WACkC;AAClC,QAAM,SAAS,qBAAqB,cAAc,CAAC,MAAM,CAAC;AAE1D,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,UAAM,IAAI,aAAa,+BAA+B,EAAE,OAAO,CAAC;AAAA,EAClE;AAEA,MAAI;AACF,UAAM,SAAS,MAAM,kBAAkB,OAAO;AAAA,MAC5C,WAAW;AAAA,MACX,YAAY,CAAC,MAAM;AAAA,MACnB,WAAW,CAAC,MAAM;AAAA,MAClB,GAAG;AAAA,IACL,CAAC;AAED,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,IAAI,aAAa,gCAAgC;AAAA,MACrD,OAAQ,MAAgB;AAAA,IAC1B,CAAC;AAAA,EACH;AACF;AAQO,MAAM,yBAAyB,OACpC,gBACA,iBACkC;AAClC,QAAM,cAAc,OAAO,KAAK,YAAY;AAC5C,QAAM,SAAS,qBAAqB,cAAc,WAAW;AAE7D,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,UAAM,IAAI,aAAa,+BAA+B;AAAA,MACpD;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,MAAM,kBAAkB;AAAA,IACrC,EAAE,KAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,OAAO,iBAAiB,GAAG;AAC7B,UAAM,IAAI,aAAa,8BAA8B,EAAE,eAAe,CAAC;AAAA,EACzE;AAEA,SAAO,MAAM,oBAAoB,cAAc;AACjD;AAOO,MAAM,yBAAyB,OACpC,mBACkC;AAClC,QAAM,eACJ,MAAM,kBAAkB,kBAAkB,cAAc;AAE1D,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,aAAa,0BAA0B,EAAE,eAAe,CAAC;AAAA,EACrE;AAEA,SAAO;AACT;AAQO,MAAM,aAAa,OACxB,cACA,SACyC;AACzC,MAAI,WAAW,aAAa,QAAQ,CAAC;AAErC,MAAI,OAAQ,UAA2B,aAAa,YAAY;AAC9D,eAAY,SAA0B,SAAS;AAAA,EACjD;AAEA,QAAM,2BAA2B,MAAM,kBAAkB;AAAA,IACvD,EAAE,KAAK,aAAa,GAAG;AAAA,IACvB,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,GAAG,KAAK,EAAE,EAAE;AAAA,EAC7C;AAEA,MAAI,yBAAyB,iBAAiB,GAAG;AAC/C,UAAM,IAAI,aAAa,8BAA8B;AAAA,MACnD,gBAAgB,aAAa;AAAA,IAC/B,CAAC;AAAA,EACH;AAEA,QAAM,sBAAsB,MAAM,oBAAoB,aAAa,EAAE;AAErE,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../../src/services/organization.service.ts"],"sourcesContent":["import type {\n Organization,\n OrganizationAPI,\n OrganizationCreationData,\n OrganizationDocument,\n} from '@/types/organization.types';\nimport type { Plan, PlanDocument } from '@/types/plan.types';\nimport { OrganizationModel } from '@models/organization.model';\nimport { GenericError } from '@utils/errors';\nimport type { OrganizationFilters } from '@utils/filtersAndPagination/getOrganizationFiltersAndPagination';\nimport {\n type OrganizationFields,\n validateOrganization,\n} from '@utils/validation/validateOrganization';\nimport type { Types } from 'mongoose';\n\n/**\n * Finds organizations based on filters and pagination options.\n * @param filters - MongoDB filter query.\n * @param skip - Number of documents to skip.\n * @param limit - Number of documents to limit.\n * @returns List of organizations matching the filters.\n */\nexport const findOrganizations = async (\n filters: OrganizationFilters,\n skip: number,\n limit: number\n): Promise<OrganizationDocument[]> =>\n await OrganizationModel.find(filters).skip(skip).limit(limit);\n\n/**\n * Finds an organization by its ID.\n * @param organizationId - The ID of the organization to find.\n * @returns The organization matching the ID.\n */\nexport const getOrganizationById = async (\n organizationId: string | Types.ObjectId\n): Promise<OrganizationDocument> => {\n const organization = await OrganizationModel.findById(organizationId);\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND', { organizationId });\n }\n\n return organization;\n};\n\n/**\n * Counts the total number of organizations that match the filters.\n * @param filters - MongoDB filter query.\n * @returns Total number of organizations.\n */\nexport const countOrganizations = async (\n filters: OrganizationFilters\n): Promise<number> => {\n const result = await OrganizationModel.countDocuments(filters);\n\n if (typeof result === 'undefined') {\n throw new GenericError('ORGANIZATION_COUNT_FAILED', { filters });\n }\n\n return result;\n};\n\n/**\n * Creates a new organization in the database.\n * @param organization - The organization data to create.\n * @returns The created organization.\n */\nexport const createOrganization = async (\n organization: OrganizationCreationData,\n userId: string | Types.ObjectId\n): Promise<OrganizationDocument> => {\n const errors = validateOrganization(organization, ['name']);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('ORGANIZATION_INVALID_FIELDS', { errors });\n }\n\n try {\n const result = await OrganizationModel.create({\n creatorId: userId,\n membersIds: [userId],\n adminsIds: [userId],\n ...organization,\n });\n\n return result;\n } catch (error) {\n throw new GenericError('ORGANIZATION_CREATION_FAILED', {\n error: (error as Error).message,\n });\n }\n};\n\n/**\n * Updates an existing organization in the database by its ID.\n * @param organizationId - The ID of the organization to update.\n * @param organization - The updated organization data.\n * @returns The updated organization.\n */\nexport const updateOrganizationById = async (\n organizationId: string | Types.ObjectId,\n organization: Partial<Organization | OrganizationAPI>\n): Promise<OrganizationDocument> => {\n const updatedKeys = Object.keys(organization) as OrganizationFields;\n const errors = validateOrganization(organization, updatedKeys);\n\n if (Object.keys(errors).length > 0) {\n throw new GenericError('ORGANIZATION_INVALID_FIELDS', {\n organizationId,\n errors,\n });\n }\n\n const result = await OrganizationModel.updateOne(\n { _id: organizationId },\n organization\n );\n\n if (result.matchedCount === 0) {\n throw new GenericError('ORGANIZATION_UPDATE_FAILED', { organizationId });\n }\n\n return await getOrganizationById(organizationId);\n};\n\n/**\n * Deletes an organization from the database by its ID.\n * @param organizationId - The ID of the organization to delete.\n * @returns The result of the deletion operation.\n */\nexport const deleteOrganizationById = async (\n organizationId: string | Types.ObjectId\n): Promise<OrganizationDocument> => {\n const organization =\n await OrganizationModel.findByIdAndDelete(organizationId);\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND', { organizationId });\n }\n\n return organization;\n};\n\n/**\n * Updates an existing plan in the database by its ID.\n * @param planId - The ID of the plan to update.\n * @param plan - The updated plan data.\n * @returns The updated plan.\n */\nexport const updatePlan = async (\n organization: Organization | OrganizationDocument,\n plan: Partial<Plan>\n): Promise<OrganizationDocument | null> => {\n let prevPlan = organization.plan ?? {};\n\n if (typeof (prevPlan as PlanDocument)?.toObject === 'function') {\n prevPlan = (prevPlan as PlanDocument).toObject();\n }\n\n const updateOrganizationResult = await OrganizationModel.updateOne(\n { _id: organization.id },\n { $set: { plan: { ...prevPlan, ...plan } } }\n );\n\n if (updateOrganizationResult.matchedCount === 0) {\n throw new GenericError('ORGANIZATION_UPDATE_FAILED', {\n organizationId: organization.id,\n });\n }\n\n const updatedOrganization = await getOrganizationById(organization.id);\n\n return updatedOrganization;\n};\n"],"mappings":"AAOA,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;AAE7B;AAAA,EAEE;AAAA,OACK;AAUA,MAAM,oBAAoB,OAC/B,SACA,MACA,UAEA,MAAM,kBAAkB,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,KAAK;AAOvD,MAAM,sBAAsB,OACjC,mBACkC;AAClC,QAAM,eAAe,MAAM,kBAAkB,SAAS,cAAc;AAEpE,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,aAAa,0BAA0B,EAAE,eAAe,CAAC;AAAA,EACrE;AAEA,SAAO;AACT;AAOO,MAAM,qBAAqB,OAChC,YACoB;AACpB,QAAM,SAAS,MAAM,kBAAkB,eAAe,OAAO;AAE7D,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI,aAAa,6BAA6B,EAAE,QAAQ,CAAC;AAAA,EACjE;AAEA,SAAO;AACT;AAOO,MAAM,qBAAqB,OAChC,cACA,WACkC;AAClC,QAAM,SAAS,qBAAqB,cAAc,CAAC,MAAM,CAAC;AAE1D,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,UAAM,IAAI,aAAa,+BAA+B,EAAE,OAAO,CAAC;AAAA,EAClE;AAEA,MAAI;AACF,UAAM,SAAS,MAAM,kBAAkB,OAAO;AAAA,MAC5C,WAAW;AAAA,MACX,YAAY,CAAC,MAAM;AAAA,MACnB,WAAW,CAAC,MAAM;AAAA,MAClB,GAAG;AAAA,IACL,CAAC;AAED,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,IAAI,aAAa,gCAAgC;AAAA,MACrD,OAAQ,MAAgB;AAAA,IAC1B,CAAC;AAAA,EACH;AACF;AAQO,MAAM,yBAAyB,OACpC,gBACA,iBACkC;AAClC,QAAM,cAAc,OAAO,KAAK,YAAY;AAC5C,QAAM,SAAS,qBAAqB,cAAc,WAAW;AAE7D,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,UAAM,IAAI,aAAa,+BAA+B;AAAA,MACpD;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,SAAS,MAAM,kBAAkB;AAAA,IACrC,EAAE,KAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,OAAO,iBAAiB,GAAG;AAC7B,UAAM,IAAI,aAAa,8BAA8B,EAAE,eAAe,CAAC;AAAA,EACzE;AAEA,SAAO,MAAM,oBAAoB,cAAc;AACjD;AAOO,MAAM,yBAAyB,OACpC,mBACkC;AAClC,QAAM,eACJ,MAAM,kBAAkB,kBAAkB,cAAc;AAE1D,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,aAAa,0BAA0B,EAAE,eAAe,CAAC;AAAA,EACrE;AAEA,SAAO;AACT;AAQO,MAAM,aAAa,OACxB,cACA,SACyC;AACzC,MAAI,WAAW,aAAa,QAAQ,CAAC;AAErC,MAAI,OAAQ,UAA2B,aAAa,YAAY;AAC9D,eAAY,SAA0B,SAAS;AAAA,EACjD;AAEA,QAAM,2BAA2B,MAAM,kBAAkB;AAAA,IACvD,EAAE,KAAK,aAAa,GAAG;AAAA,IACvB,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,GAAG,KAAK,EAAE,EAAE;AAAA,EAC7C;AAEA,MAAI,yBAAyB,iBAAiB,GAAG;AAC/C,UAAM,IAAI,aAAa,8BAA8B;AAAA,MACnD,gBAAgB,aAAa;AAAA,IAC/B,CAAC;AAAA,EACH;AAEA,QAAM,sBAAsB,MAAM,oBAAoB,aAAa,EAAE;AAErE,SAAO;AACT;","names":[]}