GetModelPermissions.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import { isObjectIdOrHexString } from "mongoose";
  2. import { forEachIn } from "@common/utils/forEachIn";
  3. import CacheModule from "@/modules/CacheModule";
  4. import DataModule from "@/modules/DataModule";
  5. import ModuleManager from "@/ModuleManager";
  6. import GetPermissions, { GetPermissionsResult } from "./GetPermissions";
  7. import DataModuleJob from "@/modules/DataModule/DataModuleJob";
  8. export type GetModelPermissionsResult = Record<string, boolean>;
  9. export default class GetModelPermissions extends DataModuleJob {
  10. protected static _modelName = "users";
  11. protected static _hasPermission = true;
  12. protected override async _validate() {
  13. if (typeof this._payload !== "object" || this._payload === null)
  14. throw new Error("Payload must be an object");
  15. if (typeof this._payload.modelName !== "string")
  16. throw new Error("Model name must be a string");
  17. if (
  18. !isObjectIdOrHexString(this._payload.modelId) &&
  19. typeof this._payload.modelId !== "undefined" &&
  20. this._payload.modelId !== null
  21. )
  22. throw new Error("Model Id must be an ObjectId or undefined");
  23. }
  24. protected override async _authorize() {}
  25. protected async _execute(): Promise<GetModelPermissionsResult> {
  26. const { modelName, modelId } = this._payload;
  27. const user = await this._context.getUser().catch(() => null);
  28. const permissions = (await this._context.executeJob(
  29. GetPermissions
  30. )) as GetPermissionsResult;
  31. let cacheKey = `model-permissions.${modelName}`;
  32. if (modelId) cacheKey += `.${modelId}`;
  33. if (user) cacheKey += `.user.${user._id}`;
  34. else cacheKey += `.guest`;
  35. const cached = await CacheModule.get(cacheKey);
  36. if (cached) return cached;
  37. const Model = await DataModule.getModel(modelName);
  38. if (!Model) throw new Error("Model not found");
  39. const model = modelId ? await Model.findById(modelId) : null;
  40. if (modelId && !model) throw new Error("Model not found");
  41. const modelPermissions = Object.fromEntries(
  42. Object.entries(permissions).filter(
  43. ([permission]) =>
  44. permission.startsWith(`data.${modelName}.`) ||
  45. permission.startsWith(`event.data.${modelName}.`)
  46. )
  47. );
  48. await forEachIn(
  49. Object.entries(
  50. ModuleManager.getModule("data")?.getJobs() ?? {}
  51. ).filter(
  52. ([jobName]) =>
  53. jobName.startsWith(modelName.toString()) &&
  54. (modelId ? true : !jobName.endsWith("ById"))
  55. ) as [string, typeof DataModuleJob][],
  56. async ([jobName, Job]) => {
  57. jobName = `data.${jobName}`;
  58. let hasPermission = permissions[jobName];
  59. if (!hasPermission && modelId)
  60. hasPermission =
  61. permissions[`${jobName}.*`] ||
  62. permissions[`${jobName}.${modelId}`];
  63. if (hasPermission) {
  64. modelPermissions[jobName] = true;
  65. return;
  66. }
  67. if (typeof Job.hasPermission === "function") {
  68. hasPermission = await Job.hasPermission(model, user);
  69. }
  70. modelPermissions[jobName] = !!hasPermission;
  71. }
  72. );
  73. await CacheModule.set(cacheKey, modelPermissions, 360);
  74. return modelPermissions;
  75. }
  76. }