@ruiapp/rapid-core 0.9.1 → 0.9.3
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.
- package/dist/core/pluginManager.d.ts +3 -1
- package/dist/core/routeContext.d.ts +2 -2
- package/dist/core/server.d.ts +4 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +107 -59
- package/dist/plugins/auth/AuthPlugin.d.ts +3 -0
- package/dist/plugins/auth/AuthPluginTypes.d.ts +10 -0
- package/dist/plugins/auth/actionHandlers/changePassword.d.ts +2 -2
- package/dist/plugins/auth/actionHandlers/createSession.d.ts +2 -2
- package/dist/plugins/auth/actionHandlers/getMyProfile.d.ts +2 -2
- package/dist/plugins/auth/actionHandlers/resetPassword.d.ts +2 -2
- package/dist/server.d.ts +2 -1
- package/dist/utilities/passwordUtility.d.ts +14 -0
- package/package.json +2 -2
- package/src/core/pluginManager.ts +10 -1
- package/src/core/routeContext.ts +2 -2
- package/src/core/routesBuilder.ts +2 -0
- package/src/core/server.ts +4 -0
- package/src/index.ts +2 -0
- package/src/plugins/auth/AuthPlugin.ts +10 -0
- package/src/plugins/auth/AuthPluginTypes.ts +11 -0
- package/src/plugins/auth/actionHandlers/changePassword.ts +7 -7
- package/src/plugins/auth/actionHandlers/createSession.ts +6 -5
- package/src/plugins/auth/actionHandlers/getMyProfile.ts +6 -3
- package/src/plugins/auth/actionHandlers/resetPassword.ts +6 -6
- package/src/plugins/dataManage/DataManagePlugin.ts +51 -51
- package/src/server.ts +5 -0
- package/src/utilities/passwordUtility.ts +26 -0
|
@@ -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:
|
|
17
|
+
routeConfig: RpdRoute;
|
|
18
18
|
static newSystemOperationContext(server: IRpdServer): RouteContext;
|
|
19
19
|
constructor(server: IRpdServer, request?: RapidRequest);
|
|
20
20
|
clone(): RouteContext;
|
package/dist/core/server.d.ts
CHANGED
|
@@ -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,6 +15,7 @@ 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 "./utilities/passwordUtility";
|
|
18
19
|
export * from "./helpers/entityHelpers";
|
|
19
20
|
export * from "./helpers/licenseHelper";
|
|
20
21
|
export * from "./deno-std/http/cookie";
|
|
@@ -29,6 +30,7 @@ export { default as SequencePlugin } from "./plugins/sequence/SequencePlugin";
|
|
|
29
30
|
export * from "./plugins/sequence/SequencePluginTypes";
|
|
30
31
|
export { default as WebhooksPlugin } from "./plugins/webhooks/WebhooksPlugin";
|
|
31
32
|
export { default as AuthPlugin } from "./plugins/auth/AuthPlugin";
|
|
33
|
+
export * from "./plugins/auth/AuthPluginTypes";
|
|
32
34
|
export { default as FileManagePlugin } from "./plugins/fileManage/FileManagePlugin";
|
|
33
35
|
export { default as LicensePlugin } from "./plugins/license/LicensePlugin";
|
|
34
36
|
export * from "./plugins/license/LicensePluginTypes";
|
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('
|
|
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;
|
|
@@ -4301,6 +4310,9 @@ class RapidServer {
|
|
|
4301
4310
|
async beforeRunRouteActions(handlerContext) {
|
|
4302
4311
|
await this.#pluginManager.beforeRunRouteActions(handlerContext);
|
|
4303
4312
|
}
|
|
4313
|
+
async beforeRunActionHandler(handlerContext, actionConfig) {
|
|
4314
|
+
await this.#pluginManager.beforeRunActionHandler(handlerContext, actionConfig);
|
|
4315
|
+
}
|
|
4304
4316
|
async beforeCreateEntity(model, options) {
|
|
4305
4317
|
await this.#pluginManager.beforeCreateEntity(model, options);
|
|
4306
4318
|
}
|
|
@@ -5015,6 +5027,30 @@ async function generateJwtSecretKey() {
|
|
|
5015
5027
|
return encode(exportedKey);
|
|
5016
5028
|
}
|
|
5017
5029
|
|
|
5030
|
+
/**
|
|
5031
|
+
* Generates password hash.
|
|
5032
|
+
* @param password
|
|
5033
|
+
* @param salt
|
|
5034
|
+
* @returns
|
|
5035
|
+
*/
|
|
5036
|
+
async function generatePasswordHash(password, salt) {
|
|
5037
|
+
if (!salt) {
|
|
5038
|
+
salt = 10;
|
|
5039
|
+
}
|
|
5040
|
+
const passwordHash = await bcrypt__default["default"].hash(password, salt);
|
|
5041
|
+
return passwordHash;
|
|
5042
|
+
}
|
|
5043
|
+
/**
|
|
5044
|
+
* Validates the password against the hash.
|
|
5045
|
+
* @param password
|
|
5046
|
+
* @param passwordHash
|
|
5047
|
+
* @returns
|
|
5048
|
+
*/
|
|
5049
|
+
async function validatePassword(password, passwordHash) {
|
|
5050
|
+
const isMatch = await bcrypt__default["default"].compare(password, passwordHash);
|
|
5051
|
+
return isMatch;
|
|
5052
|
+
}
|
|
5053
|
+
|
|
5018
5054
|
function validateLicense(server) {
|
|
5019
5055
|
const licenseService = server.getService("licenseService");
|
|
5020
5056
|
const license = licenseService.getLicense();
|
|
@@ -6010,66 +6046,66 @@ var queryDatabase = /*#__PURE__*/Object.freeze({
|
|
|
6010
6046
|
* This plugin provide:
|
|
6011
6047
|
* - routes for manage data in database.
|
|
6012
6048
|
*/
|
|
6013
|
-
const
|
|
6049
|
+
const entityOperationConfigs = [
|
|
6014
6050
|
{
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6051
|
+
operationCode: "createBatch",
|
|
6052
|
+
httpMethod: "POST",
|
|
6053
|
+
requestEndpoint: "/operations/create_batch",
|
|
6054
|
+
actionHandlerCode: "createCollectionEntitiesBatch",
|
|
6019
6055
|
},
|
|
6020
6056
|
{
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6057
|
+
operationCode: "find",
|
|
6058
|
+
httpMethod: "POST",
|
|
6059
|
+
requestEndpoint: "/operations/find",
|
|
6060
|
+
actionHandlerCode: "findCollectionEntities",
|
|
6025
6061
|
},
|
|
6026
6062
|
{
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6063
|
+
operationCode: "count",
|
|
6064
|
+
httpMethod: "POST",
|
|
6065
|
+
requestEndpoint: "/operations/count",
|
|
6066
|
+
actionHandlerCode: "countCollectionEntities",
|
|
6031
6067
|
},
|
|
6032
6068
|
{
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6069
|
+
operationCode: "delete",
|
|
6070
|
+
httpMethod: "POST",
|
|
6071
|
+
requestEndpoint: "/operations/delete",
|
|
6072
|
+
actionHandlerCode: "deleteCollectionEntities",
|
|
6037
6073
|
},
|
|
6038
6074
|
{
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6075
|
+
operationCode: "addRelations",
|
|
6076
|
+
httpMethod: "POST",
|
|
6077
|
+
requestEndpoint: "/operations/add_relations",
|
|
6078
|
+
actionHandlerCode: "addEntityRelations",
|
|
6043
6079
|
},
|
|
6044
6080
|
{
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6081
|
+
operationCode: "removeRelations",
|
|
6082
|
+
httpMethod: "POST",
|
|
6083
|
+
requestEndpoint: "/operations/remove_relations",
|
|
6084
|
+
actionHandlerCode: "removeEntityRelations",
|
|
6049
6085
|
},
|
|
6050
6086
|
{
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6087
|
+
operationCode: "getById",
|
|
6088
|
+
httpMethod: "GET",
|
|
6089
|
+
requestEndpoint: "/:id",
|
|
6090
|
+
actionHandlerCode: "findCollectionEntityById",
|
|
6055
6091
|
},
|
|
6056
6092
|
{
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6093
|
+
operationCode: "create",
|
|
6094
|
+
httpMethod: "POST",
|
|
6095
|
+
requestEndpoint: "",
|
|
6096
|
+
actionHandlerCode: "createCollectionEntity",
|
|
6061
6097
|
},
|
|
6062
6098
|
{
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6099
|
+
operationCode: "updateById",
|
|
6100
|
+
httpMethod: "PATCH",
|
|
6101
|
+
requestEndpoint: "/:id",
|
|
6102
|
+
actionHandlerCode: "updateCollectionEntityById",
|
|
6067
6103
|
},
|
|
6068
6104
|
{
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6105
|
+
operationCode: "deleteById",
|
|
6106
|
+
httpMethod: "DELETE",
|
|
6107
|
+
requestEndpoint: "/:id",
|
|
6108
|
+
actionHandlerCode: "deleteCollectionEntityById",
|
|
6073
6109
|
},
|
|
6074
6110
|
];
|
|
6075
6111
|
class DataManager {
|
|
@@ -6106,17 +6142,17 @@ class DataManager {
|
|
|
6106
6142
|
const routes = [];
|
|
6107
6143
|
models.forEach((model) => {
|
|
6108
6144
|
const { namespace, singularCode, pluralCode } = model;
|
|
6109
|
-
|
|
6145
|
+
entityOperationConfigs.forEach((entityOperationConfig) => {
|
|
6110
6146
|
routes.push({
|
|
6111
6147
|
namespace,
|
|
6112
|
-
name: `${namespace}.${singularCode}.${
|
|
6113
|
-
code: `${namespace}.${singularCode}.${
|
|
6148
|
+
name: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
|
|
6149
|
+
code: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
|
|
6114
6150
|
type: "RESTful",
|
|
6115
|
-
method:
|
|
6116
|
-
endpoint: `/${namespace}/${pluralCode}${
|
|
6151
|
+
method: entityOperationConfig.httpMethod,
|
|
6152
|
+
endpoint: `/${namespace}/${pluralCode}${entityOperationConfig.requestEndpoint}`,
|
|
6117
6153
|
actions: [
|
|
6118
6154
|
{
|
|
6119
|
-
code:
|
|
6155
|
+
code: entityOperationConfig.actionHandlerCode,
|
|
6120
6156
|
config: {
|
|
6121
6157
|
namespace,
|
|
6122
6158
|
singularCode,
|
|
@@ -6876,8 +6912,9 @@ async function handler$e(plugin, ctx, options) {
|
|
|
6876
6912
|
};
|
|
6877
6913
|
return;
|
|
6878
6914
|
}
|
|
6915
|
+
const userEntitySingularCode = plugin.options?.userEntitySingularCode || "oc_user";
|
|
6879
6916
|
const userDataAccessor = server.getDataAccessor({
|
|
6880
|
-
singularCode:
|
|
6917
|
+
singularCode: userEntitySingularCode,
|
|
6881
6918
|
});
|
|
6882
6919
|
const user = await userDataAccessor.findOne({
|
|
6883
6920
|
filters: [
|
|
@@ -6891,12 +6928,11 @@ async function handler$e(plugin, ctx, options) {
|
|
|
6891
6928
|
if (!user) {
|
|
6892
6929
|
throw new Error("User not found.");
|
|
6893
6930
|
}
|
|
6894
|
-
const isMatch = await
|
|
6931
|
+
const isMatch = await validatePassword(oldPassword, user.password);
|
|
6895
6932
|
if (!isMatch) {
|
|
6896
6933
|
throw new Error("旧密码错误。");
|
|
6897
6934
|
}
|
|
6898
|
-
const
|
|
6899
|
-
const passwordHash = await bcrypt__default["default"].hash(newPassword, saltRounds);
|
|
6935
|
+
const passwordHash = await generatePasswordHash(newPassword);
|
|
6900
6936
|
await userDataAccessor.updateById(user.id, {
|
|
6901
6937
|
password: passwordHash,
|
|
6902
6938
|
}, routeContext?.getDbTransactionClient());
|
|
@@ -6915,8 +6951,9 @@ async function handler$d(plugin, ctx, options) {
|
|
|
6915
6951
|
const { response } = routeContext;
|
|
6916
6952
|
const { account, password } = input;
|
|
6917
6953
|
validateLicense(server);
|
|
6954
|
+
const userEntitySingularCode = plugin.options?.userEntitySingularCode || "oc_user";
|
|
6918
6955
|
const userDataAccessor = server.getDataAccessor({
|
|
6919
|
-
singularCode:
|
|
6956
|
+
singularCode: userEntitySingularCode,
|
|
6920
6957
|
});
|
|
6921
6958
|
const user = await userDataAccessor.findOne({
|
|
6922
6959
|
filters: [
|
|
@@ -6937,7 +6974,7 @@ async function handler$d(plugin, ctx, options) {
|
|
|
6937
6974
|
if (user.state !== "enabled") {
|
|
6938
6975
|
throw new Error("用户已被禁用,不允许登录。");
|
|
6939
6976
|
}
|
|
6940
|
-
const isMatch = await
|
|
6977
|
+
const isMatch = await validatePassword(password, user.password);
|
|
6941
6978
|
if (!isMatch) {
|
|
6942
6979
|
throw new Error("用户名或密码错误。");
|
|
6943
6980
|
}
|
|
@@ -6994,7 +7031,9 @@ async function handler$b(plugin, ctx, options) {
|
|
|
6994
7031
|
};
|
|
6995
7032
|
return;
|
|
6996
7033
|
}
|
|
6997
|
-
const
|
|
7034
|
+
const userEntitySingularCode = plugin.options?.userEntitySingularCode || "oc_user";
|
|
7035
|
+
const profilePropertyCodes = plugin.options?.profilePropertyCodes || ["id", "name", "login", "email", "department", "roles", "state", "createdAt"];
|
|
7036
|
+
const entityManager = server.getEntityManager(userEntitySingularCode);
|
|
6998
7037
|
const user = await entityManager.findEntity({
|
|
6999
7038
|
filters: [
|
|
7000
7039
|
{
|
|
@@ -7003,7 +7042,7 @@ async function handler$b(plugin, ctx, options) {
|
|
|
7003
7042
|
value: userId,
|
|
7004
7043
|
},
|
|
7005
7044
|
],
|
|
7006
|
-
properties:
|
|
7045
|
+
properties: profilePropertyCodes,
|
|
7007
7046
|
});
|
|
7008
7047
|
ctx.output = {
|
|
7009
7048
|
user,
|
|
@@ -7020,8 +7059,9 @@ const code$a = "resetPassword";
|
|
|
7020
7059
|
async function handler$a(plugin, ctx, options) {
|
|
7021
7060
|
const { server, input, routerContext: routeContext } = ctx;
|
|
7022
7061
|
const { userId, password } = input;
|
|
7062
|
+
const userEntitySingularCode = plugin.options?.userEntitySingularCode || "oc_user";
|
|
7023
7063
|
const userDataAccessor = server.getDataAccessor({
|
|
7024
|
-
singularCode:
|
|
7064
|
+
singularCode: userEntitySingularCode,
|
|
7025
7065
|
});
|
|
7026
7066
|
const user = await userDataAccessor.findOne({
|
|
7027
7067
|
filters: [
|
|
@@ -7035,8 +7075,7 @@ async function handler$a(plugin, ctx, options) {
|
|
|
7035
7075
|
if (!user) {
|
|
7036
7076
|
throw new Error("User not found.");
|
|
7037
7077
|
}
|
|
7038
|
-
const
|
|
7039
|
-
const passwordHash = await bcrypt__default["default"].hash(password, saltRounds);
|
|
7078
|
+
const passwordHash = await generatePasswordHash(password);
|
|
7040
7079
|
await userDataAccessor.updateById(user.id, {
|
|
7041
7080
|
password: passwordHash,
|
|
7042
7081
|
}, routeContext?.getDbTransactionClient());
|
|
@@ -7204,7 +7243,14 @@ class AuthService {
|
|
|
7204
7243
|
* Auth manager plugin
|
|
7205
7244
|
*/
|
|
7206
7245
|
class AuthPlugin {
|
|
7246
|
+
#options;
|
|
7207
7247
|
#authService;
|
|
7248
|
+
constructor(options) {
|
|
7249
|
+
this.#options = Object.freeze(options);
|
|
7250
|
+
}
|
|
7251
|
+
get options() {
|
|
7252
|
+
return this.#options;
|
|
7253
|
+
}
|
|
7208
7254
|
get code() {
|
|
7209
7255
|
return "authManager";
|
|
7210
7256
|
}
|
|
@@ -9558,6 +9604,7 @@ exports.deleteCookie = deleteCookie;
|
|
|
9558
9604
|
exports.detectChangedFieldsOfEntity = detectChangedFieldsOfEntity;
|
|
9559
9605
|
exports.formatDateTimeWithTimezone = formatDateTimeWithTimezone;
|
|
9560
9606
|
exports.generateJwtSecretKey = generateJwtSecretKey;
|
|
9607
|
+
exports.generatePasswordHash = generatePasswordHash;
|
|
9561
9608
|
exports.getCookies = getCookies;
|
|
9562
9609
|
exports.getDateString = getDateString;
|
|
9563
9610
|
exports.getEntityRelationTargetId = getEntityRelationTargetId;
|
|
@@ -9569,4 +9616,5 @@ exports.mapDbRowToEntity = mapDbRowToEntity;
|
|
|
9569
9616
|
exports.setCookie = setCookie;
|
|
9570
9617
|
exports.tryValidateLicense = tryValidateLicense;
|
|
9571
9618
|
exports.validateLicense = validateLicense;
|
|
9619
|
+
exports.validatePassword = validatePassword;
|
|
9572
9620
|
exports.verifyJwt = verifyJwt;
|
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
import { RpdApplicationConfig } from "../../types";
|
|
5
5
|
import { IRpdServer, RapidPlugin, RpdConfigurationItemOptions, RpdServerPluginConfigurableTargetOptions, RpdServerPluginExtendingAbilities } from "../../core/server";
|
|
6
6
|
import { RouteContext } from "../../core/routeContext";
|
|
7
|
+
import { AuthPluginInitOptions } from "./AuthPluginTypes";
|
|
7
8
|
declare class AuthPlugin implements RapidPlugin {
|
|
8
9
|
#private;
|
|
10
|
+
constructor(options: AuthPluginInitOptions);
|
|
11
|
+
get options(): AuthPluginInitOptions;
|
|
9
12
|
get code(): string;
|
|
10
13
|
get description(): string;
|
|
11
14
|
get extendingAbilities(): RpdServerPluginExtendingAbilities[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ActionHandlerContext } from "../../../core/actionHandler";
|
|
2
|
-
import
|
|
2
|
+
import AuthPlugin from "../AuthPlugin";
|
|
3
3
|
export declare const code = "changePassword";
|
|
4
|
-
export declare function handler(plugin:
|
|
4
|
+
export declare function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, options: any): Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ActionHandlerContext } from "../../../core/actionHandler";
|
|
2
|
-
import
|
|
2
|
+
import AuthPlugin from "../AuthPlugin";
|
|
3
3
|
export declare const code = "createSession";
|
|
4
|
-
export declare function handler(plugin:
|
|
4
|
+
export declare function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, options: any): Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ActionHandlerContext } from "../../../core/actionHandler";
|
|
2
|
-
import
|
|
2
|
+
import AuthPlugin from "../AuthPlugin";
|
|
3
3
|
export declare const code = "getMyProfile";
|
|
4
|
-
export declare function handler(plugin:
|
|
4
|
+
export declare function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, options: any): Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ActionHandlerContext } from "../../../core/actionHandler";
|
|
2
|
-
import
|
|
2
|
+
import AuthPlugin from "../AuthPlugin";
|
|
3
3
|
export declare const code = "resetPassword";
|
|
4
|
-
export declare function handler(plugin:
|
|
4
|
+
export declare function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, options: any): Promise<void>;
|
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.
|
|
3
|
+
"version": "0.9.3",
|
|
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
|
-
"
|
|
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) {
|
package/src/core/routeContext.ts
CHANGED
|
@@ -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:
|
|
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;
|
package/src/core/server.ts
CHANGED
|
@@ -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
|
/** 在更新实体前调用。 */
|
package/src/index.ts
CHANGED
|
@@ -22,6 +22,7 @@ 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
27
|
export * from "./helpers/entityHelpers";
|
|
27
28
|
export * from "./helpers/licenseHelper";
|
|
@@ -47,6 +48,7 @@ export * from "./plugins/sequence/SequencePluginTypes";
|
|
|
47
48
|
export { default as WebhooksPlugin } from "./plugins/webhooks/WebhooksPlugin";
|
|
48
49
|
|
|
49
50
|
export { default as AuthPlugin } from "./plugins/auth/AuthPlugin";
|
|
51
|
+
export * from "./plugins/auth/AuthPluginTypes";
|
|
50
52
|
|
|
51
53
|
export { default as FileManagePlugin } from "./plugins/fileManage/FileManagePlugin";
|
|
52
54
|
|
|
@@ -17,10 +17,20 @@ import pluginRoutes from "./routes";
|
|
|
17
17
|
import { RouteContext } from "~/core/routeContext";
|
|
18
18
|
import { verifyJwt } from "~/utilities/jwtUtility";
|
|
19
19
|
import AuthService from "./services/AuthService";
|
|
20
|
+
import { AuthPluginInitOptions } from "./AuthPluginTypes";
|
|
20
21
|
|
|
21
22
|
class AuthPlugin implements RapidPlugin {
|
|
23
|
+
#options: AuthPluginInitOptions;
|
|
22
24
|
#authService!: AuthService;
|
|
23
25
|
|
|
26
|
+
constructor(options: AuthPluginInitOptions) {
|
|
27
|
+
this.#options = Object.freeze(options);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get options(): AuthPluginInitOptions {
|
|
31
|
+
return this.#options;
|
|
32
|
+
}
|
|
33
|
+
|
|
24
34
|
get code(): string {
|
|
25
35
|
return "authManager";
|
|
26
36
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import bcrypt from "bcrypt";
|
|
2
1
|
import { ActionHandlerContext } from "~/core/actionHandler";
|
|
3
|
-
import
|
|
2
|
+
import AuthPlugin from "../AuthPlugin";
|
|
3
|
+
import { generatePasswordHash, validatePassword } from "~/utilities/passwordUtility";
|
|
4
4
|
|
|
5
5
|
export const code = "changePassword";
|
|
6
6
|
|
|
7
|
-
export async function handler(plugin:
|
|
7
|
+
export async function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, options: any) {
|
|
8
8
|
const { server, input, routerContext: routeContext } = ctx;
|
|
9
9
|
const { response } = routeContext;
|
|
10
10
|
const { id, oldPassword, newPassword } = input;
|
|
@@ -20,8 +20,9 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
|
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
const userEntitySingularCode = plugin.options?.userEntitySingularCode || "oc_user";
|
|
23
24
|
const userDataAccessor = server.getDataAccessor({
|
|
24
|
-
singularCode:
|
|
25
|
+
singularCode: userEntitySingularCode,
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
const user = await userDataAccessor.findOne(
|
|
@@ -41,13 +42,12 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
|
|
|
41
42
|
throw new Error("User not found.");
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
const isMatch = await
|
|
45
|
+
const isMatch = await validatePassword(oldPassword, user.password);
|
|
45
46
|
if (!isMatch) {
|
|
46
47
|
throw new Error("旧密码错误。");
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
const
|
|
50
|
-
const passwordHash = await bcrypt.hash(newPassword, saltRounds);
|
|
50
|
+
const passwordHash = await generatePasswordHash(newPassword);
|
|
51
51
|
|
|
52
52
|
await userDataAccessor.updateById(
|
|
53
53
|
user.id,
|
|
@@ -1,21 +1,22 @@
|
|
|
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";
|
|
5
|
+
import AuthPlugin from "../AuthPlugin";
|
|
6
|
+
import { validatePassword } from "~/utilities/passwordUtility";
|
|
7
7
|
|
|
8
8
|
export const code = "createSession";
|
|
9
9
|
|
|
10
|
-
export async function handler(plugin:
|
|
10
|
+
export async function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, options: any) {
|
|
11
11
|
const { server, input, routerContext: routeContext, logger } = ctx;
|
|
12
12
|
const { response } = routeContext;
|
|
13
13
|
const { account, password } = input;
|
|
14
14
|
|
|
15
15
|
validateLicense(server);
|
|
16
16
|
|
|
17
|
+
const userEntitySingularCode = plugin.options?.userEntitySingularCode || "oc_user";
|
|
17
18
|
const userDataAccessor = server.getDataAccessor({
|
|
18
|
-
singularCode:
|
|
19
|
+
singularCode: userEntitySingularCode,
|
|
19
20
|
});
|
|
20
21
|
|
|
21
22
|
const user = await userDataAccessor.findOne(
|
|
@@ -43,7 +44,7 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
|
|
|
43
44
|
throw new Error("用户已被禁用,不允许登录。");
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
const isMatch = await
|
|
47
|
+
const isMatch = await validatePassword(password, user.password);
|
|
47
48
|
if (!isMatch) {
|
|
48
49
|
throw new Error("用户名或密码错误。");
|
|
49
50
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { ActionHandlerContext } from "~/core/actionHandler";
|
|
2
2
|
import { RapidPlugin } from "~/core/server";
|
|
3
|
+
import AuthPlugin from "../AuthPlugin";
|
|
3
4
|
|
|
4
5
|
export const code = "getMyProfile";
|
|
5
6
|
|
|
6
|
-
export async function handler(plugin:
|
|
7
|
+
export async function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, options: any) {
|
|
7
8
|
const { server, input, routerContext } = ctx;
|
|
8
9
|
|
|
9
10
|
const userId = routerContext.state.userId;
|
|
@@ -17,7 +18,9 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
|
|
|
17
18
|
return;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
const
|
|
21
|
+
const userEntitySingularCode = plugin.options?.userEntitySingularCode || "oc_user";
|
|
22
|
+
const profilePropertyCodes = plugin.options?.profilePropertyCodes || ["id", "name", "login", "email", "department", "roles", "state", "createdAt"];
|
|
23
|
+
const entityManager = server.getEntityManager(userEntitySingularCode);
|
|
21
24
|
const user = await entityManager.findEntity({
|
|
22
25
|
filters: [
|
|
23
26
|
{
|
|
@@ -26,7 +29,7 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
|
|
|
26
29
|
value: userId,
|
|
27
30
|
},
|
|
28
31
|
],
|
|
29
|
-
properties:
|
|
32
|
+
properties: profilePropertyCodes,
|
|
30
33
|
});
|
|
31
34
|
|
|
32
35
|
ctx.output = {
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import bcrypt from "bcrypt";
|
|
2
1
|
import { ActionHandlerContext } from "~/core/actionHandler";
|
|
3
|
-
import
|
|
2
|
+
import AuthPlugin from "../AuthPlugin";
|
|
3
|
+
import { generatePasswordHash } from "~/utilities/passwordUtility";
|
|
4
4
|
|
|
5
5
|
export const code = "resetPassword";
|
|
6
6
|
|
|
7
|
-
export async function handler(plugin:
|
|
7
|
+
export async function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, options: any) {
|
|
8
8
|
const { server, input, routerContext: routeContext } = ctx;
|
|
9
9
|
const { response } = routeContext;
|
|
10
10
|
const { userId, password } = input;
|
|
11
11
|
|
|
12
|
+
const userEntitySingularCode = plugin.options?.userEntitySingularCode || "oc_user";
|
|
12
13
|
const userDataAccessor = server.getDataAccessor({
|
|
13
|
-
singularCode:
|
|
14
|
+
singularCode: userEntitySingularCode,
|
|
14
15
|
});
|
|
15
16
|
|
|
16
17
|
const user = await userDataAccessor.findOne(
|
|
@@ -30,8 +31,7 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
|
|
|
30
31
|
throw new Error("User not found.");
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
const
|
|
34
|
-
const passwordHash = await bcrypt.hash(password, saltRounds);
|
|
34
|
+
const passwordHash = await generatePasswordHash(password);
|
|
35
35
|
|
|
36
36
|
await userDataAccessor.updateById(
|
|
37
37
|
user.id,
|
|
@@ -25,71 +25,71 @@ import {
|
|
|
25
25
|
RapidPlugin,
|
|
26
26
|
} from "~/core/server";
|
|
27
27
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
const entityOperationConfigs: {
|
|
29
|
+
operationCode: string;
|
|
30
|
+
httpMethod: RpdHttpMethod;
|
|
31
|
+
requestEndpoint: string;
|
|
32
|
+
actionHandlerCode: string;
|
|
33
33
|
}[] = [
|
|
34
34
|
{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
operationCode: "createBatch",
|
|
36
|
+
httpMethod: "POST",
|
|
37
|
+
requestEndpoint: "/operations/create_batch",
|
|
38
|
+
actionHandlerCode: "createCollectionEntitiesBatch",
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
operationCode: "find",
|
|
42
|
+
httpMethod: "POST",
|
|
43
|
+
requestEndpoint: "/operations/find",
|
|
44
|
+
actionHandlerCode: "findCollectionEntities",
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
operationCode: "count",
|
|
48
|
+
httpMethod: "POST",
|
|
49
|
+
requestEndpoint: "/operations/count",
|
|
50
|
+
actionHandlerCode: "countCollectionEntities",
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
operationCode: "delete",
|
|
54
|
+
httpMethod: "POST",
|
|
55
|
+
requestEndpoint: "/operations/delete",
|
|
56
|
+
actionHandlerCode: "deleteCollectionEntities",
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
operationCode: "addRelations",
|
|
60
|
+
httpMethod: "POST",
|
|
61
|
+
requestEndpoint: "/operations/add_relations",
|
|
62
|
+
actionHandlerCode: "addEntityRelations",
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
operationCode: "removeRelations",
|
|
66
|
+
httpMethod: "POST",
|
|
67
|
+
requestEndpoint: "/operations/remove_relations",
|
|
68
|
+
actionHandlerCode: "removeEntityRelations",
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
operationCode: "getById",
|
|
72
|
+
httpMethod: "GET",
|
|
73
|
+
requestEndpoint: "/:id",
|
|
74
|
+
actionHandlerCode: "findCollectionEntityById",
|
|
75
75
|
},
|
|
76
76
|
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
operationCode: "create",
|
|
78
|
+
httpMethod: "POST",
|
|
79
|
+
requestEndpoint: "",
|
|
80
|
+
actionHandlerCode: "createCollectionEntity",
|
|
81
81
|
},
|
|
82
82
|
{
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
operationCode: "updateById",
|
|
84
|
+
httpMethod: "PATCH",
|
|
85
|
+
requestEndpoint: "/:id",
|
|
86
|
+
actionHandlerCode: "updateCollectionEntityById",
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
138
|
+
entityOperationConfigs.forEach((entityOperationConfig) => {
|
|
139
139
|
routes.push({
|
|
140
140
|
namespace,
|
|
141
|
-
name: `${namespace}.${singularCode}.${
|
|
142
|
-
code: `${namespace}.${singularCode}.${
|
|
141
|
+
name: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
|
|
142
|
+
code: `${namespace}.${singularCode}.${entityOperationConfig.operationCode}`,
|
|
143
143
|
type: "RESTful",
|
|
144
|
-
method:
|
|
145
|
-
endpoint: `/${namespace}/${pluralCode}${
|
|
144
|
+
method: entityOperationConfig.httpMethod,
|
|
145
|
+
endpoint: `/${namespace}/${pluralCode}${entityOperationConfig.requestEndpoint}`,
|
|
146
146
|
actions: [
|
|
147
147
|
{
|
|
148
|
-
code:
|
|
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
|
+
}
|