@modular-rest/server 1.10.4 → 1.11.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modular-rest/server",
3
- "version": "1.10.4",
3
+ "version": "1.11.0",
4
4
  "description": "a nodejs module based on KOAJS for developing Rest-APIs in a modular solution.",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -43,4 +43,4 @@
43
43
  "@types/koa__cors": "^5.0.0",
44
44
  "typescript": "^5.3.3"
45
45
  }
46
- }
46
+ }
@@ -112,11 +112,11 @@ async function createRest(options) {
112
112
  * - Setting up default services
113
113
  */
114
114
 
115
- // Plug in default routes
115
+ // 1. Plug in default routes
116
116
  await Combination.combineRoutesByFilePath(path.join(defaultServiceRoot), app);
117
117
 
118
118
  // Collect default databaseDefinitions
119
- let defaultDatabaseDefinitionList =
119
+ const defaultDatabaseDefinitionList =
120
120
  await Combination.combineModulesByFilePath({
121
121
  rootDirectory: defaultServiceRoot,
122
122
  filename: {
@@ -126,13 +126,13 @@ async function createRest(options) {
126
126
  combineWithRoot: true,
127
127
  });
128
128
 
129
- // Plug in default databaseDefinitions
129
+ // 2. Plug in default databaseDefinitions
130
130
  await DataProvider.addCollectionDefinitionByList({
131
131
  list: defaultDatabaseDefinitionList,
132
132
  mongoOption: config.mongo,
133
133
  });
134
134
 
135
- // Setting up default services
135
+ // 3. Setting up default services
136
136
  try {
137
137
  await require("./helper/presetup_services").setup(options);
138
138
  } catch (e) {
@@ -176,6 +176,15 @@ async function createRest(options) {
176
176
  config.verificationCodeGeneratorMethod
177
177
  );
178
178
  }
179
+
180
+ // 4. plug in modular functions
181
+ await Combination.combineFunctionsByFilePath({
182
+ rootDirectory: config.modulesPath,
183
+ filename: {
184
+ name: "functions",
185
+ extension: ".js",
186
+ },
187
+ });
179
188
  }
180
189
 
181
190
  /**
@@ -1,5 +1,6 @@
1
- let Router = require("koa-router");
2
- let directory = require("./directory.js");
1
+ const Router = require("koa-router");
2
+ const directory = require("./directory.js");
3
+ const { addFunction } = require("./../services/functions/service.js");
3
4
 
4
5
  class Combinator {
5
6
  async combineRoutesByFilePath(rootDirectory, app) {
@@ -42,8 +43,8 @@ class Combinator {
42
43
  }) {
43
44
  // find route paths
44
45
  let rootObject_temp;
45
- let option = { name: filename.name, filter: [filename.extension] };
46
- let modulesPath = await directory
46
+ const option = { name: filename.name, filter: [filename.extension] };
47
+ const modulesPath = await directory
47
48
  .find(rootDirectory, option)
48
49
  .then()
49
50
  .catch((e) => {
@@ -52,9 +53,9 @@ class Combinator {
52
53
 
53
54
  // create and combine routes into the app
54
55
  for (let i = 0; i < modulesPath.length; i++) {
55
- let moduleObject = require(modulesPath[i]);
56
+ const moduleObject = require(modulesPath[i]);
56
57
 
57
- //act by otherOption
58
+ // act by otherOption
58
59
  if (combineWithRoot) {
59
60
  if (moduleObject.name) delete moduleObject.name;
60
61
 
@@ -69,7 +70,7 @@ class Combinator {
69
70
  }
70
71
  // default act
71
72
  else {
72
- let name = moduleObject.name;
73
+ const name = moduleObject.name;
73
74
  rootObject_temp[name] = moduleObject;
74
75
  }
75
76
  }
@@ -84,6 +85,37 @@ class Combinator {
84
85
  return rootObject_temp;
85
86
  }
86
87
 
88
+ async combineFunctionsByFilePath({ rootDirectory, filename }) {
89
+ // find route paths
90
+ const option = { name: filename.name, filter: [filename.extension] };
91
+ const functionsPaths = await directory
92
+ .find(rootDirectory, option)
93
+ .then()
94
+ .catch((e) => {
95
+ console.log(e);
96
+ });
97
+
98
+ // create and combine routes into the app
99
+ for (let i = 0; i < functionsPaths.length; i++) {
100
+ const modularFunctions = require(functionsPaths[i]);
101
+
102
+ if (!modularFunctions.functions) {
103
+ throw new Error(
104
+ `Module file ${functionsPaths[i]} does not have functions property.`
105
+ );
106
+ }
107
+
108
+ // if array
109
+ if (modularFunctions.functions.length) {
110
+ for (const moduleFunction of modularFunctions.functions) {
111
+ addFunction(moduleFunction);
112
+ }
113
+ } else {
114
+ addFunction(modularFunctions.functions);
115
+ }
116
+ }
117
+ }
118
+
87
119
  extendObj(obj, src) {
88
120
  for (var key in src) {
89
121
  if (src.hasOwnProperty(key)) obj[key] = src[key];
package/src/index.js CHANGED
@@ -7,6 +7,7 @@ const paginator = require("./class/paginator");
7
7
  const reply = require("./class/reply");
8
8
  const validator = require("./class/validator");
9
9
  const { getCollection } = require("./services/data_provider/service");
10
+ const { defineFunction } = require("./services/functions/service");
10
11
  const TypeCasters = require("./services/data_provider/typeCasters");
11
12
 
12
13
  // Base class
@@ -28,6 +29,7 @@ module.exports = {
28
29
 
29
30
  // Service utilities
30
31
  getCollection,
32
+ defineFunction,
31
33
 
32
34
  // Database
33
35
  CollectionDefinition,
@@ -0,0 +1,34 @@
1
+ const Router = require("koa-router");
2
+ const service = require("./service");
3
+ const middleware = require("../../middlewares");
4
+ const validateObject = require("../../class/validator");
5
+ const reply = require("../../class/reply").create;
6
+
7
+ const functionRouter = new Router();
8
+ const name = "function";
9
+
10
+ functionRouter.use("/", middleware.auth, async (ctx, next) => {
11
+ const body = ctx.request.body;
12
+ const bodyValidated = validateObject(body, "name args");
13
+
14
+ // fields validation
15
+ if (!bodyValidated.isValid) {
16
+ ctx.throw(412, JSON.stringify(reply("e", { e: bodyValidated.requires })));
17
+ }
18
+
19
+ await next();
20
+ });
21
+
22
+ functionRouter.post(`/run`, middleware.auth, async (ctx) => {
23
+ const { name, args } = ctx.request.body;
24
+
25
+ try {
26
+ const result = await service.runFunction(name, args, ctx.state.user);
27
+ ctx.body = JSON.stringify(reply("s", { data: result }));
28
+ } catch (e) {
29
+ ctx.throw(500, JSON.stringify(reply("e", { e: e.message })));
30
+ }
31
+ });
32
+
33
+ module.exports.name = name;
34
+ module.exports.main = functionRouter;
@@ -0,0 +1,69 @@
1
+ const functions = [];
2
+
3
+ /**
4
+ * @typedef {import('../../class/security.js').PermissionType} PermissionType
5
+ */
6
+
7
+ /**
8
+ * Defines a function with a given name, permission types, and callback.
9
+ *
10
+ * @param {Object} params - The parameters for the function.
11
+ * @param {string} params.name - The name of the function.
12
+ * @param {[PermissionType]} params.permissionTypes - The permission types for the function.
13
+ * @param {Function} params.callback - The callback to be executed by the function.
14
+ */
15
+ function defineFunction({ name, permissionTypes, callback }) {
16
+ // Check if the function already exists
17
+ const existingFunction = functions.find((f) => f.name === name);
18
+ if (existingFunction) {
19
+ throw new Error(`Function with name ${name} already exists`);
20
+ }
21
+
22
+ // Check if the permission types provided
23
+ if (!permissionTypes || !permissionTypes.length) {
24
+ throw new Error(`Permission types not provided for function ${name}`);
25
+ }
26
+
27
+ // Check if the callback is a function
28
+ if (typeof callback !== "function") {
29
+ throw new Error(`Callback is not a function for function ${name}`);
30
+ }
31
+
32
+ // Add the function to the list of functions
33
+ return { name, permissionTypes, callback };
34
+ }
35
+
36
+ function runFunction(name, args, user) {
37
+ return new Promise((resolve, reject) => {
38
+ const func = functions.find((f) => f.name === name);
39
+ if (!func) {
40
+ reject(new Error(`Function with name ${name} not found`));
41
+ }
42
+
43
+ const hasPermission = func.permissionTypes.some((permissionType) =>
44
+ user.hasPermission(permissionType)
45
+ );
46
+
47
+ if (!hasPermission) {
48
+ reject(
49
+ new Error(`User does not have permission to run function ${name}`)
50
+ );
51
+ }
52
+
53
+ try {
54
+ resolve(func.callback(args));
55
+ } catch (e) {
56
+ reject(e);
57
+ }
58
+ });
59
+ }
60
+
61
+ function addFunction(func) {
62
+ functions.push(func);
63
+ }
64
+
65
+ module.exports = {
66
+ defineFunction,
67
+ runFunction,
68
+ addFunction,
69
+ };