2
0

JobContext.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import { Types } from "mongoose";
  2. import BaseModule from "./BaseModule";
  3. import Job from "./Job";
  4. import JobQueue from "./JobQueue";
  5. import { Log } from "./LogBook";
  6. import { SessionSchema } from "./models/schemas/session";
  7. import { JobOptions } from "./types/JobOptions";
  8. import { Jobs, Modules } from "./types/Modules";
  9. import { UserSchema } from "./models/schemas/user";
  10. import { Models } from "./types/Models";
  11. export default class JobContext {
  12. public readonly job: Job;
  13. public readonly jobQueue: JobQueue;
  14. private _session?: SessionSchema;
  15. private readonly _socketId?: string;
  16. private _user?: UserSchema;
  17. private _permissions?: Record<string, boolean>;
  18. private _modelPermissions: Record<string, Record<string, boolean>>;
  19. public constructor(
  20. job: Job,
  21. options?: { session?: SessionSchema; socketId?: string }
  22. ) {
  23. this.job = job;
  24. this.jobQueue = JobQueue.getPrimaryInstance();
  25. this._session = options?.session;
  26. this._socketId = options?.socketId;
  27. this._modelPermissions = {};
  28. }
  29. /**
  30. * Log a message in the context of the current job, which automatically sets the category and data
  31. *
  32. * @param log - Log message or object
  33. */
  34. public log(log: string | Omit<Log, "timestamp" | "category">) {
  35. return this.job.log(log);
  36. }
  37. public getSession() {
  38. return this._session;
  39. }
  40. public setSession(session?: SessionSchema) {
  41. this._session = session;
  42. }
  43. public getSocketId() {
  44. return this._socketId;
  45. }
  46. /**
  47. * executeJob - Execute a job
  48. *
  49. * @param moduleName - Module name
  50. * @param jobName - Job name
  51. * @param params - Params
  52. */
  53. public async executeJob<
  54. ModuleNameType extends keyof Jobs & keyof Modules,
  55. JobNameType extends keyof Jobs[ModuleNameType] &
  56. keyof Omit<Modules[ModuleNameType], keyof BaseModule>,
  57. PayloadType extends "payload" extends keyof Jobs[ModuleNameType][JobNameType]
  58. ? Jobs[ModuleNameType][JobNameType]["payload"] extends undefined
  59. ? Record<string, never>
  60. : Jobs[ModuleNameType][JobNameType]["payload"]
  61. : Record<string, never>,
  62. ReturnType = "returns" extends keyof Jobs[ModuleNameType][JobNameType]
  63. ? Jobs[ModuleNameType][JobNameType]["returns"]
  64. : never
  65. >(
  66. moduleName: ModuleNameType,
  67. jobName: JobNameType,
  68. payload: PayloadType,
  69. options?: JobOptions
  70. ): Promise<ReturnType> {
  71. return new Job(jobName.toString(), moduleName, payload, {
  72. session: this._session,
  73. socketId: this._socketId,
  74. ...(options ?? {})
  75. }).execute();
  76. }
  77. public async getModel(model: keyof Models) {
  78. return this.executeJob("data", "getModel", model);
  79. }
  80. public async getUser(refresh = false) {
  81. if (!this._session?.userId)
  82. throw new Error("No user found for session");
  83. if (this._user && !refresh) return this._user;
  84. const User = await this.getModel("users");
  85. this._user = await User.findById(this._session.userId);
  86. if (!this._user) throw new Error("No user found for session");
  87. return this._user;
  88. }
  89. public async assertLoggedIn() {
  90. if (!this._session?.userId)
  91. throw new Error("No user found for session");
  92. }
  93. public async getUserPermissions(refresh = false) {
  94. if (this._permissions && !refresh) return this._permissions;
  95. this._permissions = await this.executeJob(
  96. "api",
  97. "getUserPermissions",
  98. {}
  99. );
  100. return this._permissions;
  101. }
  102. public async getUserModelPermissions(
  103. {
  104. modelName,
  105. modelId
  106. }: {
  107. modelName: keyof Models;
  108. modelId?: Types.ObjectId;
  109. },
  110. refresh = false
  111. ) {
  112. if (this._modelPermissions[modelName] && !refresh)
  113. return this._modelPermissions[modelName];
  114. this._modelPermissions[modelName] = await this.executeJob(
  115. "api",
  116. "getUserModelPermissions",
  117. { modelName, modelId }
  118. );
  119. return this._modelPermissions[modelName];
  120. }
  121. public async assertPermission(permission: string) {
  122. let permissions = await this.getUserPermissions();
  123. if (permission.startsWith("data")) {
  124. const [, modelName, modelId] =
  125. /^data\.([a-z]+)\.[A-z]+\.?([A-z0-9]+)?$/.exec(permission);
  126. permissions = {
  127. ...permissions,
  128. ...(await this.getUserModelPermissions({
  129. modelName,
  130. modelId
  131. }))
  132. };
  133. return;
  134. }
  135. if (!permissions[permission])
  136. throw new Error("Insufficient permissions");
  137. }
  138. }