@ruiapp/rapid-core 0.9.2 → 0.9.4

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.
@@ -1,4 +1,4 @@
1
- import { CreateEntityOptions, RpdApplicationConfig, RpdDataModel, UpdateEntityByIdOptions } from "../types";
1
+ import { CreateEntityOptions, RpdApplicationConfig, RpdDataModel, RpdRouteActionConfig, UpdateEntityByIdOptions } from "../types";
2
2
  import { IRpdServer, RapidPlugin } from "./server";
3
3
  import { RouteContext } from "./routeContext";
4
4
  import { ActionHandlerContext } from "./actionHandler";
@@ -38,6 +38,8 @@ declare class PluginManager {
38
38
  onPrepareRouteContext(routeContext: RouteContext): Promise<void>;
39
39
  /** 在接收到HTTP请求,执行 actions 前调用。 */
40
40
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
41
+ /** 在执行 action hanlder 前调用。 */
42
+ beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
41
43
  /** 在创建实体前调用。 */
42
44
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
43
45
  /** 在更新实体前调用。 */
@@ -2,7 +2,7 @@ import { RapidRequest } from "./request";
2
2
  import { RapidResponse } from "./response";
3
3
  import { HttpStatus } from "./http-types";
4
4
  import { IRpdServer } from "./server";
5
- import { IDatabaseAccessor, IDatabaseClient } from "../types";
5
+ import { IDatabaseAccessor, IDatabaseClient, RpdRoute } from "../types";
6
6
  export type Next = () => Promise<void>;
7
7
  export type TransactionState = "uninited" | "inited" | "started";
8
8
  export declare class RouteContext {
@@ -14,7 +14,7 @@ export declare class RouteContext {
14
14
  method: string;
15
15
  path: string;
16
16
  params: Record<string, string>;
17
- routeConfig: any;
17
+ routeConfig: RpdRoute;
18
18
  static newSystemOperationContext(server: IRpdServer): RouteContext;
19
19
  constructor(server: IRpdServer, request?: RapidRequest);
20
20
  clone(): RouteContext;
@@ -1,4 +1,4 @@
1
- import { CreateEntityOptions, EmitServerEventOptions, EntityWatcherType, GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseClient, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RapidServerConfig, RpdApplicationConfig, RpdDataModel, RpdDataModelProperty, RpdServerEventTypes, UpdateEntityByIdOptions } from "../types";
1
+ import { CreateEntityOptions, EmitServerEventOptions, EntityWatcherType, GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseClient, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RapidServerConfig, RpdApplicationConfig, RpdDataModel, RpdDataModelProperty, RpdRouteActionConfig, RpdServerEventTypes, UpdateEntityByIdOptions } from "../types";
2
2
  import { IPluginActionHandler, ActionHandler, ActionHandlerContext } from "./actionHandler";
3
3
  import { Next, RouteContext } from "./routeContext";
4
4
  import EntityManager from "../dataAccess/entityManager";
@@ -32,6 +32,7 @@ export interface IRpdServer {
32
32
  emitEvent<TEventName extends keyof RpdServerEventTypes>(event: EmitServerEventOptions<TEventName>): void;
33
33
  handleRequest(request: RapidRequest, next: Next): Promise<Response>;
34
34
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
35
+ beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
35
36
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
36
37
  beforeUpdateEntity(model: RpdDataModel, options: UpdateEntityByIdOptions, currentEntity: any): Promise<void>;
37
38
  registerCronJob(job: CronJobConfiguration): void;
@@ -108,6 +109,8 @@ export interface RapidPlugin {
108
109
  onPrepareRouteContext?: (server: IRpdServer, routeContext: RouteContext) => Promise<any>;
109
110
  /** 在接收到HTTP请求,执行 actions 前调用。 */
110
111
  beforeRunRouteActions?: (server: IRpdServer, handlerContext: ActionHandlerContext) => Promise<any>;
112
+ /** 在执行 action hanlder 前调用。 */
113
+ beforeRunActionHandler?: (server: IRpdServer, handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig) => Promise<any>;
111
114
  /** 在创建实体前调用。 */
112
115
  beforeCreateEntity?: (server: IRpdServer, model: RpdDataModel, options: CreateEntityOptions) => Promise<any>;
113
116
  /** 在更新实体前调用。 */
package/dist/index.d.ts CHANGED
@@ -15,8 +15,12 @@ export * from "./utilities/accessControlUtility";
15
15
  export * from "./utilities/entityUtility";
16
16
  export * from "./utilities/jwtUtility";
17
17
  export * from "./utilities/timeUtility";
18
- export * from "./helpers/entityHelpers";
18
+ export * from "./utilities/passwordUtility";
19
+ export * from "./helpers/entityHelper";
19
20
  export * from "./helpers/licenseHelper";
21
+ export * as entityHelper from "./helpers/entityHelper";
22
+ export * as licenseHelper from "./helpers/licenseHelper";
23
+ export * as metaHelper from "./helpers/metaHelper";
20
24
  export * from "./deno-std/http/cookie";
21
25
  export { mapDbRowToEntity } from "./dataAccess/entityMapper";
22
26
  export * as bootstrapApplicationConfig from "./bootstrapApplicationConfig";
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ var qs = require('qs');
9
9
  var dayjs = require('dayjs');
10
10
  var jsonwebtoken = require('jsonwebtoken');
11
11
  var crypto = require('crypto');
12
- var bcrypt = require('bcrypt');
12
+ var bcrypt = require('bcryptjs');
13
13
  var path = require('path');
14
14
  var fs = require('fs');
15
15
  var uuid = require('uuid');
@@ -928,6 +928,14 @@ class PluginManager {
928
928
  }
929
929
  }
930
930
  }
931
+ /** 在执行 action hanlder 前调用。 */
932
+ async beforeRunActionHandler(handlerContext, actionConfig) {
933
+ for (const plugin of this.#plugins) {
934
+ if (plugin.beforeRunActionHandler) {
935
+ await plugin.beforeRunActionHandler(this.#server, handlerContext, actionConfig);
936
+ }
937
+ }
938
+ }
931
939
  /** 在创建实体前调用。 */
932
940
  async beforeCreateEntity(model, options) {
933
941
  for (const plugin of this.#plugins) {
@@ -1030,6 +1038,7 @@ async function buildRoutes(server, applicationConfig) {
1030
1038
  if (!handler) {
1031
1039
  throw new Error("Unknown handler: " + actionCode);
1032
1040
  }
1041
+ await server.beforeRunActionHandler(handlerContext, actionConfig);
1033
1042
  const result = handler(handlerContext, actionConfig.config);
1034
1043
  if (result instanceof Promise) {
1035
1044
  await result;
@@ -2079,6 +2088,20 @@ function getEntityPropertyByFieldName(server, model, fieldName) {
2079
2088
  return property;
2080
2089
  }
2081
2090
 
2091
+ var metaHelper = /*#__PURE__*/Object.freeze({
2092
+ __proto__: null,
2093
+ isRelationProperty: isRelationProperty,
2094
+ isOneRelationProperty: isOneRelationProperty,
2095
+ isManyRelationProperty: isManyRelationProperty,
2096
+ getEntityProperties: getEntityProperties,
2097
+ getEntityPropertiesIncludingBase: getEntityPropertiesIncludingBase,
2098
+ getEntityPropertyByCode: getEntityPropertyByCode,
2099
+ getEntityProperty: getEntityProperty,
2100
+ getEntityOwnPropertyByCode: getEntityOwnPropertyByCode,
2101
+ getEntityOwnProperty: getEntityOwnProperty,
2102
+ getEntityPropertyByFieldName: getEntityPropertyByFieldName
2103
+ });
2104
+
2082
2105
  function getNowString() {
2083
2106
  return dayjs__default["default"]().format("YYYY-MM-DD HH:mm:ss.SSS");
2084
2107
  }
@@ -2279,6 +2302,11 @@ function detectChangedFieldsOfEntity(server, model, before, after) {
2279
2302
  return null;
2280
2303
  }
2281
2304
 
2305
+ var entityHelper = /*#__PURE__*/Object.freeze({
2306
+ __proto__: null,
2307
+ detectChangedFieldsOfEntity: detectChangedFieldsOfEntity
2308
+ });
2309
+
2282
2310
  async function validateEntity(server, model, entity) {
2283
2311
  for (const propCode in entity) {
2284
2312
  let prop = getEntityPropertyByCode(server, model, propCode);
@@ -4301,6 +4329,9 @@ class RapidServer {
4301
4329
  async beforeRunRouteActions(handlerContext) {
4302
4330
  await this.#pluginManager.beforeRunRouteActions(handlerContext);
4303
4331
  }
4332
+ async beforeRunActionHandler(handlerContext, actionConfig) {
4333
+ await this.#pluginManager.beforeRunActionHandler(handlerContext, actionConfig);
4334
+ }
4304
4335
  async beforeCreateEntity(model, options) {
4305
4336
  await this.#pluginManager.beforeCreateEntity(model, options);
4306
4337
  }
@@ -5015,6 +5046,30 @@ async function generateJwtSecretKey() {
5015
5046
  return encode(exportedKey);
5016
5047
  }
5017
5048
 
5049
+ /**
5050
+ * Generates password hash.
5051
+ * @param password
5052
+ * @param salt
5053
+ * @returns
5054
+ */
5055
+ async function generatePasswordHash(password, salt) {
5056
+ if (!salt) {
5057
+ salt = 10;
5058
+ }
5059
+ const passwordHash = await bcrypt__default["default"].hash(password, salt);
5060
+ return passwordHash;
5061
+ }
5062
+ /**
5063
+ * Validates the password against the hash.
5064
+ * @param password
5065
+ * @param passwordHash
5066
+ * @returns
5067
+ */
5068
+ async function validatePassword(password, passwordHash) {
5069
+ const isMatch = await bcrypt__default["default"].compare(password, passwordHash);
5070
+ return isMatch;
5071
+ }
5072
+
5018
5073
  function validateLicense(server) {
5019
5074
  const licenseService = server.getService("licenseService");
5020
5075
  const license = licenseService.getLicense();
@@ -5039,6 +5094,12 @@ function tryValidateLicense(logger, server) {
5039
5094
  return false;
5040
5095
  }
5041
5096
 
5097
+ var licenseHelper = /*#__PURE__*/Object.freeze({
5098
+ __proto__: null,
5099
+ validateLicense: validateLicense,
5100
+ tryValidateLicense: tryValidateLicense
5101
+ });
5102
+
5042
5103
  const values = new Map();
5043
5104
  async function set(key, value, options) {
5044
5105
  let expireAt = -1;
@@ -6010,66 +6071,66 @@ var queryDatabase = /*#__PURE__*/Object.freeze({
6010
6071
  * This plugin provide:
6011
6072
  * - routes for manage data in database.
6012
6073
  */
6013
- const routeConfigs = [
6074
+ const entityOperationConfigs = [
6014
6075
  {
6015
- code: "createBatch",
6016
- method: "POST",
6017
- endpoint: "/operations/create_batch",
6018
- handlerCode: "createCollectionEntitiesBatch",
6076
+ operationCode: "createBatch",
6077
+ httpMethod: "POST",
6078
+ requestEndpoint: "/operations/create_batch",
6079
+ actionHandlerCode: "createCollectionEntitiesBatch",
6019
6080
  },
6020
6081
  {
6021
- code: "find",
6022
- method: "POST",
6023
- endpoint: "/operations/find",
6024
- handlerCode: "findCollectionEntities",
6082
+ operationCode: "find",
6083
+ httpMethod: "POST",
6084
+ requestEndpoint: "/operations/find",
6085
+ actionHandlerCode: "findCollectionEntities",
6025
6086
  },
6026
6087
  {
6027
- code: "count",
6028
- method: "POST",
6029
- endpoint: "/operations/count",
6030
- handlerCode: "countCollectionEntities",
6088
+ operationCode: "count",
6089
+ httpMethod: "POST",
6090
+ requestEndpoint: "/operations/count",
6091
+ actionHandlerCode: "countCollectionEntities",
6031
6092
  },
6032
6093
  {
6033
- code: "delete",
6034
- method: "POST",
6035
- endpoint: "/operations/delete",
6036
- handlerCode: "deleteCollectionEntities",
6094
+ operationCode: "delete",
6095
+ httpMethod: "POST",
6096
+ requestEndpoint: "/operations/delete",
6097
+ actionHandlerCode: "deleteCollectionEntities",
6037
6098
  },
6038
6099
  {
6039
- code: "addRelations",
6040
- method: "POST",
6041
- endpoint: "/operations/add_relations",
6042
- handlerCode: "addEntityRelations",
6100
+ operationCode: "addRelations",
6101
+ httpMethod: "POST",
6102
+ requestEndpoint: "/operations/add_relations",
6103
+ actionHandlerCode: "addEntityRelations",
6043
6104
  },
6044
6105
  {
6045
- code: "removeRelations",
6046
- method: "POST",
6047
- endpoint: "/operations/remove_relations",
6048
- handlerCode: "removeEntityRelations",
6106
+ operationCode: "removeRelations",
6107
+ httpMethod: "POST",
6108
+ requestEndpoint: "/operations/remove_relations",
6109
+ actionHandlerCode: "removeEntityRelations",
6049
6110
  },
6050
6111
  {
6051
- code: "getById",
6052
- method: "GET",
6053
- endpoint: "/:id",
6054
- handlerCode: "findCollectionEntityById",
6112
+ operationCode: "getById",
6113
+ httpMethod: "GET",
6114
+ requestEndpoint: "/:id",
6115
+ actionHandlerCode: "findCollectionEntityById",
6055
6116
  },
6056
6117
  {
6057
- code: "create",
6058
- method: "POST",
6059
- endpoint: "",
6060
- handlerCode: "createCollectionEntity",
6118
+ operationCode: "create",
6119
+ httpMethod: "POST",
6120
+ requestEndpoint: "",
6121
+ actionHandlerCode: "createCollectionEntity",
6061
6122
  },
6062
6123
  {
6063
- code: "updateById",
6064
- method: "PATCH",
6065
- endpoint: "/:id",
6066
- handlerCode: "updateCollectionEntityById",
6124
+ operationCode: "updateById",
6125
+ httpMethod: "PATCH",
6126
+ requestEndpoint: "/:id",
6127
+ actionHandlerCode: "updateCollectionEntityById",
6067
6128
  },
6068
6129
  {
6069
- code: "deleteById",
6070
- method: "DELETE",
6071
- endpoint: "/:id",
6072
- handlerCode: "deleteCollectionEntityById",
6130
+ operationCode: "deleteById",
6131
+ httpMethod: "DELETE",
6132
+ requestEndpoint: "/:id",
6133
+ actionHandlerCode: "deleteCollectionEntityById",
6073
6134
  },
6074
6135
  ];
6075
6136
  class DataManager {
@@ -6106,17 +6167,17 @@ class DataManager {
6106
6167
  const routes = [];
6107
6168
  models.forEach((model) => {
6108
6169
  const { namespace, singularCode, pluralCode } = model;
6109
- routeConfigs.forEach((routeConfig) => {
6170
+ entityOperationConfigs.forEach((entityOperationConfig) => {
6110
6171
  routes.push({
6111
6172
  namespace,
6112
- name: `${namespace}.${singularCode}.${routeConfig.code}`,
6113
- code: `${namespace}.${singularCode}.${routeConfig.code}`,
6173
+ name: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
6174
+ code: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
6114
6175
  type: "RESTful",
6115
- method: routeConfig.method,
6116
- endpoint: `/${namespace}/${pluralCode}${routeConfig.endpoint}`,
6176
+ method: entityOperationConfig.httpMethod,
6177
+ endpoint: `/${namespace}/${pluralCode}${entityOperationConfig.requestEndpoint}`,
6117
6178
  actions: [
6118
6179
  {
6119
- code: routeConfig.handlerCode,
6180
+ code: entityOperationConfig.actionHandlerCode,
6120
6181
  config: {
6121
6182
  namespace,
6122
6183
  singularCode,
@@ -6892,12 +6953,11 @@ async function handler$e(plugin, ctx, options) {
6892
6953
  if (!user) {
6893
6954
  throw new Error("User not found.");
6894
6955
  }
6895
- const isMatch = await bcrypt__default["default"].compare(oldPassword, user.password);
6956
+ const isMatch = await validatePassword(oldPassword, user.password);
6896
6957
  if (!isMatch) {
6897
6958
  throw new Error("旧密码错误。");
6898
6959
  }
6899
- const saltRounds = 10;
6900
- const passwordHash = await bcrypt__default["default"].hash(newPassword, saltRounds);
6960
+ const passwordHash = await generatePasswordHash(newPassword);
6901
6961
  await userDataAccessor.updateById(user.id, {
6902
6962
  password: passwordHash,
6903
6963
  }, routeContext?.getDbTransactionClient());
@@ -6939,7 +6999,7 @@ async function handler$d(plugin, ctx, options) {
6939
6999
  if (user.state !== "enabled") {
6940
7000
  throw new Error("用户已被禁用,不允许登录。");
6941
7001
  }
6942
- const isMatch = await bcrypt__default["default"].compare(password, user.password);
7002
+ const isMatch = await validatePassword(password, user.password);
6943
7003
  if (!isMatch) {
6944
7004
  throw new Error("用户名或密码错误。");
6945
7005
  }
@@ -7040,8 +7100,7 @@ async function handler$a(plugin, ctx, options) {
7040
7100
  if (!user) {
7041
7101
  throw new Error("User not found.");
7042
7102
  }
7043
- const saltRounds = 10;
7044
- const passwordHash = await bcrypt__default["default"].hash(password, saltRounds);
7103
+ const passwordHash = await generatePasswordHash(password);
7045
7104
  await userDataAccessor.updateById(user.id, {
7046
7105
  password: passwordHash,
7047
7106
  }, routeContext?.getDbTransactionClient());
@@ -9568,8 +9627,10 @@ exports.createJwt = createJwt;
9568
9627
  exports.decodeJwt = decodeJwt;
9569
9628
  exports.deleteCookie = deleteCookie;
9570
9629
  exports.detectChangedFieldsOfEntity = detectChangedFieldsOfEntity;
9630
+ exports.entityHelper = entityHelper;
9571
9631
  exports.formatDateTimeWithTimezone = formatDateTimeWithTimezone;
9572
9632
  exports.generateJwtSecretKey = generateJwtSecretKey;
9633
+ exports.generatePasswordHash = generatePasswordHash;
9573
9634
  exports.getCookies = getCookies;
9574
9635
  exports.getDateString = getDateString;
9575
9636
  exports.getEntityRelationTargetId = getEntityRelationTargetId;
@@ -9577,8 +9638,11 @@ exports.getNowString = getNowString;
9577
9638
  exports.getNowStringWithTimezone = getNowStringWithTimezone;
9578
9639
  exports.getSetCookies = getSetCookies;
9579
9640
  exports.isAccessAllowed = isAccessAllowed;
9641
+ exports.licenseHelper = licenseHelper;
9580
9642
  exports.mapDbRowToEntity = mapDbRowToEntity;
9643
+ exports.metaHelper = metaHelper;
9581
9644
  exports.setCookie = setCookie;
9582
9645
  exports.tryValidateLicense = tryValidateLicense;
9583
9646
  exports.validateLicense = validateLicense;
9647
+ exports.validatePassword = validatePassword;
9584
9648
  exports.verifyJwt = verifyJwt;
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RpdApplicationConfig, RpdDataModel, RpdServerEventTypes, RapidServerConfig, RpdDataModelProperty, CreateEntityOptions, UpdateEntityByIdOptions, EntityWatcherType, EmitServerEventOptions, IDatabaseClient } from "./types";
1
+ import { GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RpdApplicationConfig, RpdDataModel, RpdServerEventTypes, RapidServerConfig, RpdDataModelProperty, CreateEntityOptions, UpdateEntityByIdOptions, EntityWatcherType, EmitServerEventOptions, IDatabaseClient, RpdRouteActionConfig } from "./types";
2
2
  import { ActionHandler, ActionHandlerContext, IPluginActionHandler } from "./core/actionHandler";
3
3
  import { IRpdServer, RapidPlugin } from "./core/server";
4
4
  import { Next } from "./core/routeContext";
@@ -58,6 +58,7 @@ export declare class RapidServer implements IRpdServer {
58
58
  get middlewares(): any[];
59
59
  handleRequest(rapidRequest: RapidRequest, next: Next): Promise<Response>;
60
60
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
61
+ beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
61
62
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
62
63
  beforeUpdateEntity(model: RpdDataModel, options: UpdateEntityByIdOptions, currentEntity: any): Promise<void>;
63
64
  }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Generates password hash.
3
+ * @param password
4
+ * @param salt
5
+ * @returns
6
+ */
7
+ export declare function generatePasswordHash(password: string, salt?: number | string): Promise<string>;
8
+ /**
9
+ * Validates the password against the hash.
10
+ * @param password
11
+ * @param passwordHash
12
+ * @returns
13
+ */
14
+ export declare function validatePassword(password: string, passwordHash: string): Promise<boolean>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruiapp/rapid-core",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,7 +19,7 @@
19
19
  "typescript": "^4.8.4"
20
20
  },
21
21
  "dependencies": {
22
- "bcrypt": "^5.1.1",
22
+ "bcryptjs": "^3.0.2",
23
23
  "cron": "^3.1.7",
24
24
  "dayjs": "^1.11.7",
25
25
  "jsonwebtoken": "^9.0.2",
@@ -1,4 +1,4 @@
1
- import { CreateEntityOptions, RpdApplicationConfig, RpdDataModel, UpdateEntityByIdOptions } from "~/types";
1
+ import { CreateEntityOptions, RpdApplicationConfig, RpdDataModel, RpdRouteActionConfig, UpdateEntityByIdOptions } from "~/types";
2
2
  import { IRpdServer, RapidPlugin } from "./server";
3
3
  import { RouteContext } from "./routeContext";
4
4
  import { ActionHandlerContext } from "./actionHandler";
@@ -162,6 +162,15 @@ class PluginManager {
162
162
  }
163
163
  }
164
164
 
165
+ /** 在执行 action hanlder 前调用。 */
166
+ async beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig) {
167
+ for (const plugin of this.#plugins) {
168
+ if (plugin.beforeRunActionHandler) {
169
+ await plugin.beforeRunActionHandler(this.#server, handlerContext, actionConfig);
170
+ }
171
+ }
172
+ }
173
+
165
174
  /** 在创建实体前调用。 */
166
175
  async beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions) {
167
176
  for (const plugin of this.#plugins) {
@@ -2,7 +2,7 @@ import { RapidRequest } from "./request";
2
2
  import { RapidResponse } from "./response";
3
3
  import { HttpStatus } from "./http-types";
4
4
  import { IRpdServer } from "./server";
5
- import { IDatabaseAccessor, IDatabaseClient } from "~/types";
5
+ import { IDatabaseAccessor, IDatabaseClient, RpdRoute } from "~/types";
6
6
 
7
7
  export type Next = () => Promise<void>;
8
8
 
@@ -18,7 +18,7 @@ export class RouteContext {
18
18
  method: string;
19
19
  path: string;
20
20
  params: Record<string, string>;
21
- routeConfig: any;
21
+ routeConfig: RpdRoute;
22
22
  #server: IRpdServer;
23
23
  #dbTransactionClient: IDatabaseClient | undefined;
24
24
  #dbTransactionState: TransactionState;
@@ -74,6 +74,8 @@ export async function buildRoutes(server: IRpdServer, applicationConfig: RpdAppl
74
74
  throw new Error("Unknown handler: " + actionCode);
75
75
  }
76
76
 
77
+ await server.beforeRunActionHandler(handlerContext, actionConfig);
78
+
77
79
  const result = handler(handlerContext, actionConfig.config);
78
80
  if (result instanceof Promise) {
79
81
  await result;
@@ -13,6 +13,7 @@ import {
13
13
  RpdApplicationConfig,
14
14
  RpdDataModel,
15
15
  RpdDataModelProperty,
16
+ RpdRouteActionConfig,
16
17
  RpdServerEventTypes,
17
18
  UpdateEntityByIdOptions,
18
19
  } from "~/types";
@@ -53,6 +54,7 @@ export interface IRpdServer {
53
54
  emitEvent<TEventName extends keyof RpdServerEventTypes>(event: EmitServerEventOptions<TEventName>): void;
54
55
  handleRequest(request: RapidRequest, next: Next): Promise<Response>;
55
56
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
57
+ beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
56
58
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
57
59
  beforeUpdateEntity(model: RpdDataModel, options: UpdateEntityByIdOptions, currentEntity: any): Promise<void>;
58
60
 
@@ -145,6 +147,8 @@ export interface RapidPlugin {
145
147
  onPrepareRouteContext?: (server: IRpdServer, routeContext: RouteContext) => Promise<any>;
146
148
  /** 在接收到HTTP请求,执行 actions 前调用。 */
147
149
  beforeRunRouteActions?: (server: IRpdServer, handlerContext: ActionHandlerContext) => Promise<any>;
150
+ /** 在执行 action hanlder 前调用。 */
151
+ beforeRunActionHandler?: (server: IRpdServer, handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig) => Promise<any>;
148
152
  /** 在创建实体前调用。 */
149
153
  beforeCreateEntity?: (server: IRpdServer, model: RpdDataModel, options: CreateEntityOptions) => Promise<any>;
150
154
  /** 在更新实体前调用。 */
@@ -23,7 +23,7 @@ import { isNullOrUndefined } from "~/utilities/typeUtility";
23
23
  import { mapDbRowToEntity, mapEntityToDbRow } from "./entityMapper";
24
24
  import { mapPropertyNameToColumnName } from "./propertyMapper";
25
25
  import { IRpdServer, RapidPlugin } from "~/core/server";
26
- import { detectChangedFieldsOfEntity } from "~/helpers/entityHelpers";
26
+ import { detectChangedFieldsOfEntity } from "~/helpers/entityHelper";
27
27
  import {
28
28
  cloneDeep,
29
29
  concat,
package/src/index.ts CHANGED
@@ -22,9 +22,13 @@ export * from "./utilities/accessControlUtility";
22
22
  export * from "./utilities/entityUtility";
23
23
  export * from "./utilities/jwtUtility";
24
24
  export * from "./utilities/timeUtility";
25
+ export * from "./utilities/passwordUtility";
25
26
 
26
- export * from "./helpers/entityHelpers";
27
+ export * from "./helpers/entityHelper";
27
28
  export * from "./helpers/licenseHelper";
29
+ export * as entityHelper from "./helpers/entityHelper";
30
+ export * as licenseHelper from "./helpers/licenseHelper";
31
+ export * as metaHelper from "./helpers/metaHelper";
28
32
 
29
33
  export * from "./deno-std/http/cookie";
30
34
 
@@ -1,7 +1,6 @@
1
- import bcrypt from "bcrypt";
2
1
  import { ActionHandlerContext } from "~/core/actionHandler";
3
- import { RapidPlugin } from "~/core/server";
4
2
  import AuthPlugin from "../AuthPlugin";
3
+ import { generatePasswordHash, validatePassword } from "~/utilities/passwordUtility";
5
4
 
6
5
  export const code = "changePassword";
7
6
 
@@ -43,13 +42,12 @@ export async function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, opt
43
42
  throw new Error("User not found.");
44
43
  }
45
44
 
46
- const isMatch = await bcrypt.compare(oldPassword, user.password);
45
+ const isMatch = await validatePassword(oldPassword, user.password);
47
46
  if (!isMatch) {
48
47
  throw new Error("旧密码错误。");
49
48
  }
50
49
 
51
- const saltRounds = 10;
52
- const passwordHash = await bcrypt.hash(newPassword, saltRounds);
50
+ const passwordHash = await generatePasswordHash(newPassword);
53
51
 
54
52
  await userDataAccessor.updateById(
55
53
  user.id,
@@ -1,10 +1,9 @@
1
- import bcrypt from "bcrypt";
2
1
  import { setCookie } from "~/deno-std/http/cookie";
3
2
  import { ActionHandlerContext } from "~/core/actionHandler";
4
- import { RapidPlugin } from "~/core/server";
5
3
  import AuthService from "../services/AuthService";
6
4
  import { validateLicense } from "~/helpers/licenseHelper";
7
5
  import AuthPlugin from "../AuthPlugin";
6
+ import { validatePassword } from "~/utilities/passwordUtility";
8
7
 
9
8
  export const code = "createSession";
10
9
 
@@ -45,7 +44,7 @@ export async function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, opt
45
44
  throw new Error("用户已被禁用,不允许登录。");
46
45
  }
47
46
 
48
- const isMatch = await bcrypt.compare(password, user.password);
47
+ const isMatch = await validatePassword(password, user.password);
49
48
  if (!isMatch) {
50
49
  throw new Error("用户名或密码错误。");
51
50
  }
@@ -1,7 +1,6 @@
1
- import bcrypt from "bcrypt";
2
1
  import { ActionHandlerContext } from "~/core/actionHandler";
3
- import { RapidPlugin } from "~/core/server";
4
2
  import AuthPlugin from "../AuthPlugin";
3
+ import { generatePasswordHash } from "~/utilities/passwordUtility";
5
4
 
6
5
  export const code = "resetPassword";
7
6
 
@@ -32,8 +31,7 @@ export async function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, opt
32
31
  throw new Error("User not found.");
33
32
  }
34
33
 
35
- const saltRounds = 10;
36
- const passwordHash = await bcrypt.hash(password, saltRounds);
34
+ const passwordHash = await generatePasswordHash(password);
37
35
 
38
36
  await userDataAccessor.updateById(
39
37
  user.id,
@@ -25,71 +25,71 @@ import {
25
25
  RapidPlugin,
26
26
  } from "~/core/server";
27
27
 
28
- const routeConfigs: {
29
- code: string;
30
- method: RpdHttpMethod;
31
- endpoint: string;
32
- handlerCode: string;
28
+ const entityOperationConfigs: {
29
+ operationCode: string;
30
+ httpMethod: RpdHttpMethod;
31
+ requestEndpoint: string;
32
+ actionHandlerCode: string;
33
33
  }[] = [
34
34
  {
35
- code: "createBatch",
36
- method: "POST",
37
- endpoint: "/operations/create_batch",
38
- handlerCode: "createCollectionEntitiesBatch",
35
+ operationCode: "createBatch",
36
+ httpMethod: "POST",
37
+ requestEndpoint: "/operations/create_batch",
38
+ actionHandlerCode: "createCollectionEntitiesBatch",
39
39
  },
40
40
  {
41
- code: "find",
42
- method: "POST",
43
- endpoint: "/operations/find",
44
- handlerCode: "findCollectionEntities",
41
+ operationCode: "find",
42
+ httpMethod: "POST",
43
+ requestEndpoint: "/operations/find",
44
+ actionHandlerCode: "findCollectionEntities",
45
45
  },
46
46
  {
47
- code: "count",
48
- method: "POST",
49
- endpoint: "/operations/count",
50
- handlerCode: "countCollectionEntities",
47
+ operationCode: "count",
48
+ httpMethod: "POST",
49
+ requestEndpoint: "/operations/count",
50
+ actionHandlerCode: "countCollectionEntities",
51
51
  },
52
52
  {
53
- code: "delete",
54
- method: "POST",
55
- endpoint: "/operations/delete",
56
- handlerCode: "deleteCollectionEntities",
53
+ operationCode: "delete",
54
+ httpMethod: "POST",
55
+ requestEndpoint: "/operations/delete",
56
+ actionHandlerCode: "deleteCollectionEntities",
57
57
  },
58
58
  {
59
- code: "addRelations",
60
- method: "POST",
61
- endpoint: "/operations/add_relations",
62
- handlerCode: "addEntityRelations",
59
+ operationCode: "addRelations",
60
+ httpMethod: "POST",
61
+ requestEndpoint: "/operations/add_relations",
62
+ actionHandlerCode: "addEntityRelations",
63
63
  },
64
64
  {
65
- code: "removeRelations",
66
- method: "POST",
67
- endpoint: "/operations/remove_relations",
68
- handlerCode: "removeEntityRelations",
65
+ operationCode: "removeRelations",
66
+ httpMethod: "POST",
67
+ requestEndpoint: "/operations/remove_relations",
68
+ actionHandlerCode: "removeEntityRelations",
69
69
  },
70
70
  {
71
- code: "getById",
72
- method: "GET",
73
- endpoint: "/:id",
74
- handlerCode: "findCollectionEntityById",
71
+ operationCode: "getById",
72
+ httpMethod: "GET",
73
+ requestEndpoint: "/:id",
74
+ actionHandlerCode: "findCollectionEntityById",
75
75
  },
76
76
  {
77
- code: "create",
78
- method: "POST",
79
- endpoint: "",
80
- handlerCode: "createCollectionEntity",
77
+ operationCode: "create",
78
+ httpMethod: "POST",
79
+ requestEndpoint: "",
80
+ actionHandlerCode: "createCollectionEntity",
81
81
  },
82
82
  {
83
- code: "updateById",
84
- method: "PATCH",
85
- endpoint: "/:id",
86
- handlerCode: "updateCollectionEntityById",
83
+ operationCode: "updateById",
84
+ httpMethod: "PATCH",
85
+ requestEndpoint: "/:id",
86
+ actionHandlerCode: "updateCollectionEntityById",
87
87
  },
88
88
  {
89
- code: "deleteById",
90
- method: "DELETE",
91
- endpoint: "/:id",
92
- handlerCode: "deleteCollectionEntityById",
89
+ operationCode: "deleteById",
90
+ httpMethod: "DELETE",
91
+ requestEndpoint: "/:id",
92
+ actionHandlerCode: "deleteCollectionEntityById",
93
93
  },
94
94
  ];
95
95
 
@@ -135,17 +135,17 @@ class DataManager implements RapidPlugin {
135
135
  models.forEach((model) => {
136
136
  const { namespace, singularCode, pluralCode } = model;
137
137
 
138
- routeConfigs.forEach((routeConfig) => {
138
+ entityOperationConfigs.forEach((entityOperationConfig) => {
139
139
  routes.push({
140
140
  namespace,
141
- name: `${namespace}.${singularCode}.${routeConfig.code}`,
142
- code: `${namespace}.${singularCode}.${routeConfig.code}`,
141
+ name: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
142
+ code: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
143
143
  type: "RESTful",
144
- method: routeConfig.method,
145
- endpoint: `/${namespace}/${pluralCode}${routeConfig.endpoint}`,
144
+ method: entityOperationConfig.httpMethod,
145
+ endpoint: `/${namespace}/${pluralCode}${entityOperationConfig.requestEndpoint}`,
146
146
  actions: [
147
147
  {
148
- code: routeConfig.handlerCode,
148
+ code: entityOperationConfig.actionHandlerCode,
149
149
  config: {
150
150
  namespace,
151
151
  singularCode,
package/src/server.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  RpdEntityCreateEventPayload,
19
19
  EmitServerEventOptions,
20
20
  IDatabaseClient,
21
+ RpdRouteActionConfig,
21
22
  } from "./types";
22
23
 
23
24
  import QueryBuilder from "./queryBuilder/queryBuilder";
@@ -475,6 +476,10 @@ export class RapidServer implements IRpdServer {
475
476
  await this.#pluginManager.beforeRunRouteActions(handlerContext);
476
477
  }
477
478
 
479
+ async beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig) {
480
+ await this.#pluginManager.beforeRunActionHandler(handlerContext, actionConfig);
481
+ }
482
+
478
483
  async beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions) {
479
484
  await this.#pluginManager.beforeCreateEntity(model, options);
480
485
  }
@@ -0,0 +1,26 @@
1
+ import bcrypt from "bcryptjs";
2
+
3
+ /**
4
+ * Generates password hash.
5
+ * @param password
6
+ * @param salt
7
+ * @returns
8
+ */
9
+ export async function generatePasswordHash(password: string, salt?: number | string): Promise<string> {
10
+ if (!salt) {
11
+ salt = 10;
12
+ }
13
+ const passwordHash = await bcrypt.hash(password, salt);
14
+ return passwordHash;
15
+ }
16
+
17
+ /**
18
+ * Validates the password against the hash.
19
+ * @param password
20
+ * @param passwordHash
21
+ * @returns
22
+ */
23
+ export async function validatePassword(password: string, passwordHash: string): Promise<boolean> {
24
+ const isMatch = await bcrypt.compare(password, passwordHash);
25
+ return isMatch;
26
+ }