@modular-rest/server 1.6.6 → 1.7.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/README.md CHANGED
@@ -6,6 +6,8 @@ a nodejs module based on KOAJS for developing Rest-APIs in a modular solution.
6
6
  this module has one method:
7
7
  - `createRest`: is the main functionality of the module.
8
8
 
9
+ **Note**: active "javascript.implicitProjectConfig.checkJs": true in your vscode settings.
10
+
9
11
  ## Install
10
12
 
11
13
  Install using [npm](https://www.npmjs.com/package/modular-rest):
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "@modular-rest/server",
3
- "version": "1.6.6",
3
+ "version": "1.7.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": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "generate:types": "tsc"
8
9
  },
10
+ "types": "./types/index.d.ts",
9
11
  "repository": {
10
12
  "type": "git",
11
13
  "url": "git+https://github.com/navidshad/modular-rest.git"
@@ -35,5 +37,8 @@
35
37
  "mongoose": "^5.10.9",
36
38
  "nested-property": "^4.0.0"
37
39
  },
38
- "devDependencies": {}
40
+ "devDependencies": {
41
+ "@types/koa": "^2.14.0",
42
+ "typescript": "^5.3.3"
43
+ }
39
44
  }
@@ -1,89 +1,53 @@
1
- let koa = require("koa");
1
+ const koa = require("koa");
2
2
  const cors = require("@koa/cors");
3
3
  const koaBody = require("koa-body");
4
4
  const koaStatic = require("koa-static-server");
5
- var path = require("path");
6
- var Combination = require("./class/combinator");
7
- let DataProvider = require("./services/data_provider/service");
8
- let UserService = require("./services/user_manager/service");
5
+ const path = require("path");
6
+ const Combination = require("./class/combinator");
7
+ const DataProvider = require("./services/data_provider/service");
8
+ const UserService = require("./services/user_manager/service");
9
9
 
10
10
  let defaultServiceRoot = __dirname + "/services";
11
11
 
12
- // staticOptions = {
13
- // /**
14
- // * directory that is to be served
15
- // */
16
- // rootDir?: string | undefined;
17
- // /**
18
- // * optional rewrite path
19
- // */
20
- // rootPath?: string | undefined;
21
- // /**
22
- // * optional default file to serve if requested static is missing
23
- // */
24
- // notFoundFile?: string | undefined;
25
- // /**
26
- // * request access log to console
27
- // */
28
- // log?: boolean | undefined;
29
- // /**
30
- // * don't execute any downstream middleware. defaults to true
31
- // */
32
- // last?: boolean | undefined;
33
- // /**
34
- // * Browser cache max-age in milliseconds. defaults to 0
35
- // */
36
- // maxage?: number | undefined;
37
- // /**
38
- // * Allow transfer of hidden files. defaults to false
39
- // */
40
- // hidden?: boolean | undefined;
41
- // /**
42
- // * Try to serve the gzipped version of a file automatically when gzip is supported by a client and if the requested
43
- // */
44
- // gzip?: boolean | undefined;
45
- // /**
46
- // * Try to serve the brotli version of a file automatically when brotli is supported by a client and in the requested
47
- // */
48
- // brotli?: boolean | undefined;
49
- // index?: string | undefined;
50
- // }
12
+ /**
13
+ * @typedef {import('koa')} Koa
14
+ */
51
15
 
52
16
  /**
53
17
  * @param {{
54
- * cors: any; // Options for @koa/cors middleware.
55
- * modulesPath: string; // Root directory of your router.js/db.js files.
56
- * static: {
57
- * rootDir: string; // Root directory of your static files.
58
- * rootPath: string; // Root path of your static files.
59
- * notFoundFile: string; // Not found file.
60
- * log: boolean; // Log requests to console.
61
- * last: boolean; // Don't execute any downstream middleware.
62
- * maxage: number; // Browser cache max-age in milliseconds.
63
- * hidden: boolean; // Allow transfer of hidden files.
64
- * gzip: boolean; // Try to serve the gzipped version of a file automatically when gzip is supported by a client and if the requested
65
- * brotli: boolean; // Try to serve the brotli version of a file automatically when brotli is supported by a client and in the requested
66
- * index: string; // Index file.
18
+ * cors?: any; // Options for @koa/cors middleware.
19
+ * modulesPath?: string; // Root directory of your router.js/db.js files.
20
+ * staticPath?: {
21
+ * rootDir?: string; // Root directory of your static files.
22
+ * rootPath?: string; // Root path of your static files.
23
+ * notFoundFile?: string; // Not found file.
24
+ * log?: boolean; // Log requests to console.
25
+ * last?: boolean; // Don't execute any downstream middleware.
26
+ * maxage?: number; // Browser cache max-age in milliseconds.
27
+ * hidden?: boolean; // Allow transfer of hidden files.
28
+ * gzip?: boolean; // Try to serve the gzipped version of a file automatically when gzip is supported by a client and if the requested file exists.
29
+ * brotli?: boolean; // Try to serve the brotli version of a file automatically when brotli is supported by a client and if the requested file exists.
30
+ * index?: string; // Index file.
67
31
  * };
68
- * onBeforeInit: (koaApp) => void; // A callback called before initializing the Koa server.
69
- * onAfterInit: (koaApp) => void; // A callback called after server initialization.
70
- * port: number; // Server port.
71
- * dontListen: boolean; // If true, the server will not run and will only return the Koa app object.
72
- * mongo: {
32
+ * onBeforeInit?: (koaApp:Koa) => void; // A callback called before initializing the Koa server.
33
+ * onAfterInit?: (koaApp:Koa) => void; // A callback called after server initialization.
34
+ * port?: number; // Server port.
35
+ * dontListen?: boolean; // If true, the server will not run and will only return the Koa app object.
36
+ * mongo?: {
73
37
  * dbPrefix: string; // A prefix for your database name.
74
38
  * mongoBaseAddress: string; // The address of your MongoDB server without any database specification.
75
- * addressMap: string; // Specific addresses for each database.
39
+ * addressMap?: string; // Specific addresses for each database.
76
40
  * };
77
- * keypair: {
41
+ * keypair?: {
78
42
  * private: string; // Private key for RSA authentication.
79
43
  * public: string; // Public key for RSA authentication.
80
44
  * };
81
- * adminUser: {
45
+ * adminUser?: {
82
46
  * email: string; // Admin user email.
83
47
  * password: string; // Admin user password.
84
48
  * };
85
49
  * verificationCodeGeneratorMethod: () => string; // A method to return a verification code when registering a new user.
86
- * collectionDefinitions: CollectionDefinition[]; // An array of additional collection definitions.
50
+ * collectionDefinitions?: CollectionDefinition[]; // An array of additional collection definitions.
87
51
  * }} options
88
52
  */
89
53
  module.exports = async function createRest(options) {
@@ -121,8 +85,8 @@ module.exports = async function createRest(options) {
121
85
  /**
122
86
  * Plug In KoaStatic
123
87
  */
124
- if (options.static) {
125
- app.use(koaStatic(options.static));
88
+ if (options.staticPath) {
89
+ app.use(koaStatic(options.staticPath));
126
90
  }
127
91
 
128
92
  /**
@@ -1,25 +1,33 @@
1
- module.exports = class CollectionDefinition {
2
- /**
3
- * This class helps to create a mongoose collection
4
- * associated with permissions and triggers .
5
- *
6
- * @param {object} option
7
- * @param {string} option.db database name
8
- * @param {string} option.collection collection name
9
- * @param {object} option.schema mongoose schema
10
- * @param {array} option.permissions a list of Permission for this collection
11
- * @param {array} option.trigger a DatabaseTrigger
12
- */
13
- constructor({ db, collection, schema, permissions, trigger }) {
14
- // string
15
- this.database = db;
16
- // string
17
- this.collection = collection;
18
- // schema object of mongoose
19
- this.schema = schema;
20
- // a list of Permission for this collection
21
- this.permissions = permissions;
1
+ /**
2
+ * @typedef {import('./security.js').Permission} Permission
3
+ * @typedef {import('./database_trigger.js')} DatabaseTrigger
4
+ */
22
5
 
23
- this.trigger = trigger;
24
- }
25
- }
6
+ class CollectionDefinition {
7
+ /**
8
+ * This class helps to create a mongoose collection
9
+ * associated with permissions and triggers.
10
+ *
11
+ * @class
12
+ * @param {Object} option
13
+ * @param {string} option.db - Database name
14
+ * @param {string} option.collection - Collection name
15
+ * @param {Object} option.schema - Mongoose schema
16
+ * @param {Array<Permission>} option.permissions - A list of permissions for this collection
17
+ * @param {Array<DatabaseTrigger>} option.trigger - A database trigger
18
+ */
19
+ constructor({ db, collection, schema, permissions, trigger }) {
20
+ // string
21
+ this.database = db;
22
+ // string
23
+ this.collection = collection;
24
+ // schema object of mongoose
25
+ this.schema = schema;
26
+ // a list of Permission for this collection
27
+ this.permissions = permissions;
28
+
29
+ this.trigger = trigger;
30
+ }
31
+ }
32
+
33
+ module.exports = CollectionDefinition;
@@ -1,90 +1,101 @@
1
- let Router = require('koa-router');
2
- let directory = require('./directory.js');
1
+ let Router = require("koa-router");
2
+ let directory = require("./directory.js");
3
3
 
4
4
  class Combinator {
5
+ async combineRoutesByFilePath(rootDirectory, app) {
6
+ // find route paths
7
+ let option = { name: "router", filter: [".js"] };
8
+ let routerPaths = await directory
9
+ .find(rootDirectory, option)
10
+ .then()
11
+ .catch((e) => {
12
+ console.log(e);
13
+ });
5
14
 
6
- async combineRoutesByFilePath(rootDirectory, app) {
7
- // find route paths
8
- let option = { name: 'router', filter: ['.js'] }
9
- let routerPaths = await directory.find(rootDirectory, option).then()
10
- .catch(e => { console.log(e) });
15
+ // create and combine routes into the app
16
+ for (let i = 0; i < routerPaths.length; i++) {
17
+ let service = require(routerPaths[i]);
18
+ let name = service.name;
11
19
 
12
- // create and combine routes into the app
13
- for (let i = 0; i < routerPaths.length; i++) {
14
- let service = require(routerPaths[i]);
15
- let name = service.name;
20
+ var serviceRouter = new Router();
21
+ serviceRouter.use(`/${name}`, service.main.routes());
16
22
 
17
-
18
- var serviceRouter = new Router();
19
- serviceRouter.use(`/${name}`, service.main.routes());
20
-
21
- app.use(serviceRouter.routes());
22
- }
23
+ app.use(serviceRouter.routes());
23
24
  }
25
+ }
24
26
 
25
- /**
26
- *
27
- * @param {object} option
28
- * @param {string} option.rootDirectory root directory of files
29
- * @param {object} option.filename an object of {name, extension}
30
- * @param {string} option.filename.name name of file
31
- * @param {string} option.filename.extension the extension of the file
32
- * @param {boolean} option.combineWithRoot combine all file content and return theme as a object
33
- * @param {boolean} option.convertToArray return file content as an array instead an object
34
- */
35
- async combineModulesByFilePath({
36
- rootDirectory, filename, combineWithRoot, convertToArray
37
- }) {
38
- // find route paths
39
- let rootObject_temp;
40
- let option = { name: filename.name, filter: [filename.extension] }
41
- let modulesPath = await directory.find(rootDirectory, option).then()
42
- .catch(e => { console.log(e) });
27
+ /**
28
+ *
29
+ * @param {object} option
30
+ * @param {string} option.rootDirectory root directory of files
31
+ * @param {object} option.filename an object of {name, extension}
32
+ * @param {string} option.filename.name name of file
33
+ * @param {string} option.filename.extension the extension of the file
34
+ * @param {boolean} option.combineWithRoot combine all file content and return theme as a object
35
+ * @param {boolean} option.convertToArray return file content as an array instead an object
36
+ */
37
+ async combineModulesByFilePath({
38
+ rootDirectory,
39
+ filename,
40
+ combineWithRoot,
41
+ convertToArray,
42
+ }) {
43
+ // find route paths
44
+ let rootObject_temp;
45
+ let option = { name: filename.name, filter: [filename.extension] };
46
+ let modulesPath = await directory
47
+ .find(rootDirectory, option)
48
+ .then()
49
+ .catch((e) => {
50
+ console.log(e);
51
+ });
43
52
 
44
- // create and combine routes into the app
45
- for (let i = 0; i < modulesPath.length; i++) {
46
- let moduleObject = require(modulesPath[i]);
53
+ // create and combine routes into the app
54
+ for (let i = 0; i < modulesPath.length; i++) {
55
+ let moduleObject = require(modulesPath[i]);
47
56
 
48
- //act by otherOption
49
- if (combineWithRoot) {
50
- if(moduleObject.name)
51
- delete moduleObject.name;
57
+ //act by otherOption
58
+ if (combineWithRoot) {
59
+ if (moduleObject.name) delete moduleObject.name;
52
60
 
53
- if(moduleObject.length) {
54
- if(!rootObject_temp) rootObject_temp = [];
55
-
56
- rootObject_temp = [...rootObject_temp, ...moduleObject];
57
- }
58
- else {
59
- rootObject_temp = this.extendObj(rootObject_temp, moduleObject);
60
- }
61
- // else if (typeof)
62
- }
63
- // default act
64
- else {
65
- let name = moduleObject.name;
66
- rootObject_temp[name] = moduleObject;
67
- }
68
- }
61
+ if (moduleObject.length) {
62
+ if (!rootObject_temp) rootObject_temp = [];
69
63
 
70
- // options
71
- // convertToArray
72
- if (convertToArray) {
73
- rootObject_temp = Object.values(rootObject_temp);
64
+ rootObject_temp = [...rootObject_temp, ...moduleObject];
65
+ } else {
66
+ rootObject_temp = this.extendObj(rootObject_temp, moduleObject);
74
67
  }
68
+ // else if (typeof)
69
+ }
70
+ // default act
71
+ else {
72
+ let name = moduleObject.name;
73
+ rootObject_temp[name] = moduleObject;
74
+ }
75
+ }
75
76
 
76
- // set result to main rootObject
77
- return rootObject_temp;
77
+ // options
78
+ // convertToArray
79
+ if (convertToArray) {
80
+ rootObject_temp = Object.values(rootObject_temp);
78
81
  }
79
82
 
80
- extendObj(obj, src) {
81
- for (var key in src) {
82
- if (src.hasOwnProperty(key))
83
- obj[key] = src[key];
84
- }
85
- return obj;
83
+ // set result to main rootObject
84
+ return rootObject_temp;
85
+ }
86
+
87
+ extendObj(obj, src) {
88
+ for (var key in src) {
89
+ if (src.hasOwnProperty(key)) obj[key] = src[key];
86
90
  }
91
+ return obj;
92
+ }
93
+
94
+ static get instance() {
95
+ return instance;
96
+ }
87
97
  }
88
98
 
89
- Combinator.instance = new Combinator();
99
+ const instance = new Combinator();
100
+
90
101
  module.exports = Combinator.instance;
@@ -1,15 +1,21 @@
1
+ /**
2
+ * `DatabaseTrigger` is a class that defines a callback to be called on a specific database transaction.
3
+ *
4
+ * @class
5
+ */
1
6
  class DatabaseTrigger {
2
- /**
3
- * Is a definition for a callback being called on
4
- * a specific database transaction.
5
- *
6
- * @param {string} operation Operation name
7
- * @param {function} callback trigger callback
8
- */
9
- constructor(operation, callback = (query, queryResult) => { }) {
10
- this.operation = operation;
11
- this.callback = callback;
12
- }
7
+ /**
8
+ * Creates a new instance of `DatabaseTrigger`.
9
+ *
10
+ * @param {string} operation - The name of the operation on which the callback should be triggered.
11
+ * @param {function} [callback=(query, queryResult) => {}] - The callback function to be triggered. It accepts two parameters:
12
+ * 1. `query` - The query that is being executed.
13
+ * 2. `queryResult` - The result of the query execution.
14
+ */
15
+ constructor(operation, callback = (query, queryResult) => {}) {
16
+ this.operation = operation;
17
+ this.callback = callback;
18
+ }
13
19
  }
14
20
 
15
- module.exports = DatabaseTrigger;
21
+ module.exports = DatabaseTrigger;
@@ -1,44 +1,118 @@
1
+ /**
2
+ * Class representing an access definition.
3
+ */
1
4
  class AccessDefinition {
2
- constructor({ database, collection, permissionList }) {
3
- this.database = database;
4
- this.collection = collection;
5
- this.permissionList = permissionList;
6
- }
5
+ /**
6
+ * Create an access definition.
7
+ * @param {Object} options - The options for the access definition.
8
+ * @param {string} options.database - The name of the database.
9
+ * @param {string} options.collection - The name of the collection.
10
+ * @param {Array.<Permission>} options.permissionList - The list of permissions.
11
+ */
12
+ constructor({ database, collection, permissionList }) {
13
+ this.database = database;
14
+ this.collection = collection;
15
+ this.permissionList = permissionList;
16
+ }
7
17
  }
8
18
 
19
+ /**
20
+ * @typedef {('god_access'|'user_access'|'delete'|'upload_file_access'|'remove_file_access'|'anonymous_access')} PermissionType
21
+ */
22
+
23
+ /**
24
+ * Class representing a permission.
25
+ */
9
26
  class Permission {
10
- constructor({ type, read = false, write = false, onlyOwnData = false }) {
11
- this.type = type;
12
- this.read = read;
13
- this.write = write;
14
- /**
15
- * If true users can perform CRUD on documents that they created already.
16
- */
17
- this.onlyOwnData = onlyOwnData;
18
- }
27
+ /**
28
+ * Create a permission.
29
+ * @param {Object} options - The options for the permission.
30
+ * @param {PermissionType} options.type - The type of the permission.
31
+ * @param {boolean} [options.read=false] - The read access of the permission.
32
+ * @param {boolean} [options.write=false] - The write access of the permission.
33
+ * @param {boolean} [options.onlyOwnData=false] - If true, users can perform CRUD on documents that they created already.
34
+ */
35
+ constructor({ type, read = false, write = false, onlyOwnData = false }) {
36
+ this.type = type;
37
+ this.read = read;
38
+ this.write = write;
39
+ this.onlyOwnData = onlyOwnData;
40
+ }
19
41
  }
20
42
 
43
+ /**
44
+ * Class representing different types of permissions.
45
+ * Each static getter returns a string that represents a specific type of permission.
46
+ */
21
47
  class PermissionTypes {
22
- constructor() {
23
- this.god_access = 'god_access';
24
- this.user_access = 'user_access';
25
- this.upload_file_access = 'upload_file_access';
26
- this.remove_file_access = 'remove_file_access';
27
- this.anonymous_access = 'anonymous_access';
28
- }
29
-
30
- static get god_access() { return 'god_access' };
31
- static get user_access() { return 'user_access' };
32
- static get upload_file_access() { return 'upload_file_access' };
33
- static get remove_file_access() { return 'remove_file_access' };
34
- static get anonymous_access() { return 'anonymous_access' };
48
+ /**
49
+ * Create permission types.
50
+ * Each property represents a specific type of permission.
51
+ */
52
+ constructor() {
53
+ this.god_access = "god_access"; // Represents god access permission type
54
+ this.user_access = "user_access"; // Represents user access permission type
55
+ this.upload_file_access = "upload_file_access"; // Represents upload file access permission type
56
+ this.remove_file_access = "remove_file_access"; // Represents remove file access permission type
57
+ this.anonymous_access = "anonymous_access"; // Represents anonymous access permission type
58
+ }
59
+
60
+ /**
61
+ * Get the string representing god access permission type.
62
+ * @return {string} The god access permission type.
63
+ */
64
+ static get god_access() {
65
+ return "god_access";
66
+ }
67
+
68
+ /**
69
+ * Get the string representing user access permission type.
70
+ * @return {string} The user access permission type.
71
+ */
72
+ static get user_access() {
73
+ return "user_access";
74
+ }
75
+
76
+ /**
77
+ * Get the string representing upload file access permission type.
78
+ * @return {string} The upload file access permission type.
79
+ */
80
+ static get upload_file_access() {
81
+ return "upload_file_access";
82
+ }
83
+
84
+ /**
85
+ * Get the string representing remove file access permission type.
86
+ * @return {string} The remove file access permission type.
87
+ */
88
+ static get remove_file_access() {
89
+ return "remove_file_access";
90
+ }
91
+
92
+ /**
93
+ * Get the string representing anonymous access permission type.
94
+ * @return {string} The anonymous access permission type.
95
+ */
96
+ static get anonymous_access() {
97
+ return "anonymous_access";
98
+ }
35
99
  }
36
100
 
101
+ /**
102
+ * Class representing access types.
103
+ */
37
104
  class AccessTypes {
38
- static get read() { return 'read' };
39
- static get write() { return 'write' };
105
+ static get read() {
106
+ return "read";
107
+ }
108
+ static get write() {
109
+ return "write";
110
+ }
40
111
  }
41
112
 
42
113
  module.exports = {
43
- AccessDefinition, Permission, PermissionTypes, AccessTypes
44
- }
114
+ AccessDefinition,
115
+ Permission,
116
+ PermissionTypes,
117
+ AccessTypes,
118
+ };
@@ -1,38 +1,42 @@
1
1
  class TriggerOperator {
2
- constructor() {
3
- this.triggers = [];
4
- }
2
+ constructor() {
3
+ this.triggers = [];
4
+ }
5
5
 
6
- /**
7
- * add a collection trigger
8
- * @param {object} trigger DatabaseTrigger object
9
- */
10
- addTrigger(trigger) {
11
- this.triggers.push(trigger);
12
- }
6
+ /**
7
+ * add a collection trigger
8
+ * @param {object} trigger DatabaseTrigger object
9
+ */
10
+ addTrigger(trigger) {
11
+ this.triggers.push(trigger);
12
+ }
13
13
 
14
- /**
15
- * Call a trigger
16
- * @param {string} operation operation name
17
- * @param {string} database database name
18
- * @param {string} collection collection name
19
- * @param {string} data
20
- */
21
- call(operation, database, collection, data) {
22
- let result;
14
+ /**
15
+ * Call a trigger
16
+ * @param {string} operation operation name
17
+ * @param {string} database database name
18
+ * @param {string} collection collection name
19
+ * @param {string} data
20
+ */
21
+ call(operation, database, collection, data) {
22
+ let result;
23
23
 
24
- this.triggers.forEach(trigger => {
25
- if (
26
- operation == trigger.operation &&
27
- database == trigger.database &&
28
- collection == trigger.collection
29
- )
30
- result = trigger.callback(data.input, data.output);
31
- });
24
+ this.triggers.forEach((trigger) => {
25
+ if (
26
+ operation == trigger.operation &&
27
+ database == trigger.database &&
28
+ collection == trigger.collection
29
+ )
30
+ result = trigger.callback(data.input, data.output);
31
+ });
32
32
 
33
- return result;
34
- }
33
+ return result;
34
+ }
35
+
36
+ static get instance() {
37
+ return instance;
38
+ }
35
39
  }
36
40
 
37
- TriggerOperator.instance = new TriggerOperator();
38
- module.exports = TriggerOperator.instance;
41
+ const instance = new TriggerOperator();
42
+ module.exports = TriggerOperator.instance;
package/src/index.js CHANGED
@@ -14,47 +14,21 @@ const CollectionDefinition = require("./class/collection_definition");
14
14
  const Schemas = require("./class/db_schemas");
15
15
  const DatabaseTrigger = require("./class/database_trigger");
16
16
  const SecurityClass = require("./class/security");
17
-
18
17
  const middleware = require("./middlewares");
19
18
  const userManager = require("./services/user_manager/service");
20
19
 
21
20
  module.exports = {
22
21
  createRest,
23
-
24
- //
25
- // Utilities
26
- //
27
22
  reply,
28
23
  TypeCasters,
29
-
30
- /**
31
- * @type {import('./class/paginator').create}
32
- */
33
24
  paginator,
34
-
35
- /**
36
- * @type {import('./class/validator')}
37
- */
38
25
  validator,
39
-
40
- /**
41
- * @type {import('./services/data_provider/service').getCollection}
42
- * @return {import('mongoose').Model} Mongoose model https://mongoosejs.com/docs/api/model.html
43
- */
44
26
  getCollection,
45
-
46
- //
47
- // Base class
48
- //
49
27
  CollectionDefinition,
50
28
  Schemas,
51
29
  Schema,
52
30
  DatabaseTrigger,
53
-
54
31
  ...SecurityClass,
55
-
56
- // Middlewares
57
32
  middleware,
58
-
59
33
  userManager: userManager.main,
60
34
  };
@@ -1,4 +1,13 @@
1
+ /**
2
+ * Validator module
3
+ * @module class/validator
4
+ */
1
5
  let validateObject = require("./class/validator");
6
+
7
+ /**
8
+ * User manager service
9
+ * @module services/user_manager/service
10
+ */
2
11
  const userManager = require("./services/user_manager/service");
3
12
 
4
13
  /**
@@ -9,7 +18,7 @@ const userManager = require("./services/user_manager/service");
9
18
  * @param {Function} next - Koa next function
10
19
  * @returns {Promise<void>}
11
20
  */
12
- module.exports.auth = async (ctx, next) => {
21
+ async function auth(ctx, next) {
13
22
  let headers = ctx.header;
14
23
  let headersValidated = validateObject(headers, "authorization");
15
24
 
@@ -27,4 +36,8 @@ module.exports.auth = async (ctx, next) => {
27
36
  console.log(err);
28
37
  ctx.throw(err.status || 412, err.message);
29
38
  });
39
+ }
40
+
41
+ module.exports = {
42
+ auth,
30
43
  };
@@ -1,196 +1,193 @@
1
- let name = 'dataProvider';
2
- const colog = require('colog');
3
- let {
4
- AccessTypes,
5
- AccessDefinition
6
- } = require('../../class/security');
1
+ let name = "dataProvider";
2
+ const colog = require("colog");
3
+ let { AccessTypes, AccessDefinition } = require("../../class/security");
7
4
 
8
- const Mongoose = require('mongoose');
9
- Mongoose.set('useCreateIndex', true);
5
+ const Mongoose = require("mongoose");
6
+ Mongoose.set("useCreateIndex", true);
10
7
 
11
8
  let connections = {};
12
9
  let collections = {};
13
10
  let permissionDefinitions = {};
14
11
 
15
- let triggers = require('../../class/trigger_operator');
16
- let TypeCasters = require('./typeCasters');
12
+ let triggers = require("../../class/trigger_operator");
13
+ let TypeCasters = require("./typeCasters");
17
14
 
18
15
  /**
19
- *
16
+ *
20
17
  * @param {string} dbName database name
21
18
  * @param {array} CollectionDefinitionList an array of CollectionDefinition instance
22
19
  * @param {object} mongoOption
23
20
  * @param {string} mongoOption.dbPrefix
24
21
  * @param {string} mongoOption.mongoBaseAddress
25
22
  */
26
- function connectToDatabaseByCollectionDefinitionList(dbName, collectionDefinitionList = [], mongoOption) {
27
-
28
- return new Promise((done, reject) => {
29
- // Create db connection
30
- //
31
- const fullDbName = (mongoOption.dbPrefix || '') + dbName
32
- const connectionString = mongoOption.mongoBaseAddress + '/' + fullDbName;
33
-
34
- colog.info(`- Connecting to database ${connectionString}`)
35
-
36
- let connection = Mongoose.createConnection(connectionString, {
37
- ...mongoOption,
38
- useUnifiedTopology: true,
39
- useNewUrlParser: true,
40
- });
41
-
42
- // Store connection
43
- connections[dbName] = connection;
44
-
45
- // add db models from schemas
46
- collectionDefinitionList.forEach(collectionDefinition => {
47
-
48
- let collection = collectionDefinition.collection;
49
- let schema = collectionDefinition.schema;
50
-
51
- if (collections[dbName] == undefined)
52
- collections[dbName] = {};
53
-
54
- if (permissionDefinitions[dbName] == undefined)
55
- permissionDefinitions[dbName] = {};
56
-
57
- // create model from schema
58
- // and store in on global collection object
59
- let model = connection.model(collection, schema);
60
- collections[dbName][collection] = model
61
-
62
- // define Access Definition from component permissions
63
- // and store it on global access definition object
64
- permissionDefinitions[dbName][collection] = new AccessDefinition({
65
- database: dbName,
66
- collection: collection,
67
- permissionList: collectionDefinition.permissions
68
- });
69
-
70
- // add trigger
71
- if (collectionDefinition.trigger != undefined) {
72
- triggers.addTrigger(collectionDefinition.trigger);
73
- }
74
-
75
- })
76
-
77
- connection.on('connected', () => {
78
- colog.success(`- ${fullDbName} database has been connected`)
79
- done()
80
- });
81
- })
23
+ function connectToDatabaseByCollectionDefinitionList(
24
+ dbName,
25
+ collectionDefinitionList = [],
26
+ mongoOption
27
+ ) {
28
+ return new Promise((done, reject) => {
29
+ // Create db connection
30
+ //
31
+ const fullDbName = (mongoOption.dbPrefix || "") + dbName;
32
+ const connectionString = mongoOption.mongoBaseAddress + "/" + fullDbName;
33
+
34
+ colog.info(`- Connecting to database ${connectionString}`);
35
+
36
+ let connection = Mongoose.createConnection(connectionString, {
37
+ ...mongoOption,
38
+ useUnifiedTopology: true,
39
+ useNewUrlParser: true,
40
+ });
41
+
42
+ // Store connection
43
+ connections[dbName] = connection;
44
+
45
+ // add db models from schemas
46
+ collectionDefinitionList.forEach((collectionDefinition) => {
47
+ let collection = collectionDefinition.collection;
48
+ let schema = collectionDefinition.schema;
49
+
50
+ if (collections[dbName] == undefined) collections[dbName] = {};
51
+
52
+ if (permissionDefinitions[dbName] == undefined)
53
+ permissionDefinitions[dbName] = {};
54
+
55
+ // create model from schema
56
+ // and store in on global collection object
57
+ let model = connection.model(collection, schema);
58
+ collections[dbName][collection] = model;
59
+
60
+ // define Access Definition from component permissions
61
+ // and store it on global access definition object
62
+ permissionDefinitions[dbName][collection] = new AccessDefinition({
63
+ database: dbName,
64
+ collection: collection,
65
+ permissionList: collectionDefinition.permissions,
66
+ });
67
+
68
+ // add trigger
69
+ if (collectionDefinition.trigger != undefined) {
70
+ triggers.addTrigger(collectionDefinition.trigger);
71
+ }
72
+ });
73
+
74
+ connection.on("connected", () => {
75
+ colog.success(`- ${fullDbName} database has been connected`);
76
+ done();
77
+ });
78
+ });
82
79
  }
83
80
 
84
81
  /**
85
- *
82
+ *
86
83
  * @param {object} option
87
84
  * @param {array} option.list an array of CollectionDefinition instance
88
85
  * @param {object} option.mongoOption
89
86
  * @param {string} option.mongoOption.dbPrefix
90
87
  * @param {string} option.mongoOption.mongoBaseAddress
91
88
  */
92
- async function addCollectionDefinitionByList({
93
- list,
94
- mongoOption
95
- }) {
96
- let clusteredByDBName = {};
97
-
98
- // cluster list by their database name.
99
- list.forEach(collectionDefinition => {
100
- let database = collectionDefinition.database;
101
- if (!clusteredByDBName[database]) clusteredByDBName[database] = [];
102
- clusteredByDBName[database].push(collectionDefinition);
103
- })
104
-
105
- // connect to databases
106
- for (const dbName in clusteredByDBName) {
107
- if (clusteredByDBName.hasOwnProperty(dbName)) {
108
- const collectionDefinitionList = clusteredByDBName[dbName];
109
- await connectToDatabaseByCollectionDefinitionList(dbName, collectionDefinitionList, mongoOption);
110
- }
89
+ async function addCollectionDefinitionByList({ list, mongoOption }) {
90
+ let clusteredByDBName = {};
91
+
92
+ // cluster list by their database name.
93
+ list.forEach((collectionDefinition) => {
94
+ let database = collectionDefinition.database;
95
+ if (!clusteredByDBName[database]) clusteredByDBName[database] = [];
96
+ clusteredByDBName[database].push(collectionDefinition);
97
+ });
98
+
99
+ // connect to databases
100
+ for (const dbName in clusteredByDBName) {
101
+ if (clusteredByDBName.hasOwnProperty(dbName)) {
102
+ const collectionDefinitionList = clusteredByDBName[dbName];
103
+ await connectToDatabaseByCollectionDefinitionList(
104
+ dbName,
105
+ collectionDefinitionList,
106
+ mongoOption
107
+ );
111
108
  }
109
+ }
112
110
  }
113
111
 
112
+ /**
113
+ * Get a collection from a database.
114
+ * @param {string} db - The database name.
115
+ * @param {string} collection - The collection name.
116
+ * @returns {import('mongoose').Model} The found collection.
117
+ */
114
118
  function getCollection(db, collection) {
115
- let fountCollection;
119
+ let fountCollection;
116
120
 
117
- if (collections.hasOwnProperty(db)) {
118
- if (collections[db].hasOwnProperty(collection))
119
- fountCollection = collections[db][collection];
120
- }
121
+ if (collections.hasOwnProperty(db)) {
122
+ if (collections[db].hasOwnProperty(collection))
123
+ fountCollection = collections[db][collection];
124
+ }
121
125
 
122
- return fountCollection;
126
+ return fountCollection;
123
127
  }
124
128
 
125
129
  function _getPermissionList(db, collection, operationType) {
126
- let permissionList = [];
127
- let permissionDefinition;
128
-
129
- if (!permissionDefinitions.hasOwnProperty(db))
130
- return permissionList;
131
-
132
- permissionDefinition = permissionDefinitions[db][collection];
133
-
134
- permissionDefinition.permissionList.forEach(permission => {
135
- if (permission.onlyOwnData == true) {
136
- permissionList.push(permission);
137
- } else if (operationType == AccessTypes.read &&
138
- permission.read == true) {
139
- permissionList.push(permission);
140
- } else if (operationType == AccessTypes.write &&
141
- permission.write == true) {
142
- permissionList.push(permission);
143
- }
144
- });
130
+ let permissionList = [];
131
+ let permissionDefinition;
132
+
133
+ if (!permissionDefinitions.hasOwnProperty(db)) return permissionList;
145
134
 
146
- return permissionList;
135
+ permissionDefinition = permissionDefinitions[db][collection];
136
+
137
+ permissionDefinition.permissionList.forEach((permission) => {
138
+ if (permission.onlyOwnData == true) {
139
+ permissionList.push(permission);
140
+ } else if (operationType == AccessTypes.read && permission.read == true) {
141
+ permissionList.push(permission);
142
+ } else if (operationType == AccessTypes.write && permission.write == true) {
143
+ permissionList.push(permission);
144
+ }
145
+ });
146
+
147
+ return permissionList;
147
148
  }
148
149
 
149
150
  function checkAccess(db, collection, operationType, queryOrDoc, user) {
150
- let key = false;
151
- let permissionList = _getPermissionList(db, collection, operationType);
152
-
153
- permissionList.forEach(permission => {
154
- let permissionType = permission.type;
155
-
156
- if (permission.onlyOwnData == true) {
157
- let owner = queryOrDoc.owner;
158
- let userId = user.id;
159
-
160
- try {
161
- if (owner.toString() == userId.toString())
162
- key = true;
163
- } catch (error) {
164
- key = false;
165
- }
166
- } else if (operationType == AccessTypes.read) {
167
- if (permission.read &&
168
- user.permission[permissionType] == true)
169
- key = true;
170
- } else if (operationType == AccessTypes.write) {
171
-
172
- if (permission.write &&
173
- user.permission[permissionType] == true)
174
- key = true;
175
- }
176
- });
151
+ let key = false;
152
+ let permissionList = _getPermissionList(db, collection, operationType);
177
153
 
178
- return key;
179
- }
154
+ permissionList.forEach((permission) => {
155
+ let permissionType = permission.type;
180
156
 
181
- function getAsID(strId) {
182
- let id;
183
- try {
184
- id = Mongoose.Types.ObjectId(strId);
185
- } catch (e) {
186
- console.log('strId did not cast objectId', e);
157
+ if (permission.onlyOwnData == true) {
158
+ let owner = queryOrDoc.owner;
159
+ let userId = user.id;
160
+
161
+ try {
162
+ if (owner.toString() == userId.toString()) key = true;
163
+ } catch (error) {
164
+ key = false;
165
+ }
166
+ } else if (operationType == AccessTypes.read) {
167
+ if (permission.read && user.permission[permissionType] == true)
168
+ key = true;
169
+ } else if (operationType == AccessTypes.write) {
170
+ if (permission.write && user.permission[permissionType] == true)
171
+ key = true;
187
172
  }
173
+ });
188
174
 
189
- return id;
175
+ return key;
176
+ }
177
+
178
+ function getAsID(strId) {
179
+ let id;
180
+ try {
181
+ id = Mongoose.Types.ObjectId(strId);
182
+ } catch (e) {
183
+ console.log("strId did not cast objectId", e);
184
+ }
185
+
186
+ return id;
190
187
  }
191
188
 
192
189
  function performPopulateToQueryObject(queryObj, popArr = []) {
193
- /*
190
+ /*
194
191
  https://mongoosejs.com/docs/populate.html
195
192
  popArr must be contains this objects
196
193
  {
@@ -198,36 +195,35 @@ function performPopulateToQueryObject(queryObj, popArr = []) {
198
195
  select: 'name -_id',
199
196
  }
200
197
  */
201
- popArr.forEach(pop => queryObj.populate(pop));
202
- return queryObj;
198
+ popArr.forEach((pop) => queryObj.populate(pop));
199
+ return queryObj;
203
200
  }
204
201
 
205
202
  function performAdditionalOptionsToQueryObject(queryObj, options) {
206
- /**
207
- * https://mongoosejs.com/docs/api/query.html#query_Query-sort
208
- *
209
- * Options must be contain a method name and an argument of above methods.
210
- * {
211
- * sort: '-_id',
212
- * limit: 10,
213
- * }
214
- */
215
- Object.keys(options).forEach(method => {
216
- queryObj = queryObj[method](options[method]);
217
- })
218
-
219
- return queryObj;
203
+ /**
204
+ * https://mongoosejs.com/docs/api/query.html#query_Query-sort
205
+ *
206
+ * Options must be contain a method name and an argument of above methods.
207
+ * {
208
+ * sort: '-_id',
209
+ * limit: 10,
210
+ * }
211
+ */
212
+ Object.keys(options).forEach((method) => {
213
+ queryObj = queryObj[method](options[method]);
214
+ });
215
+
216
+ return queryObj;
220
217
  }
221
218
 
222
-
223
219
  module.exports = {
224
- name,
225
- getCollection,
226
- addCollectionDefinitionByList,
227
- checkAccess,
228
- getAsID,
229
- performPopulateToQueryObject,
230
- performAdditionalOptionsToQueryObject,
231
- triggers,
232
- TypeCasters,
233
- }
220
+ name,
221
+ getCollection,
222
+ addCollectionDefinitionByList,
223
+ checkAccess,
224
+ getAsID,
225
+ performPopulateToQueryObject,
226
+ performAdditionalOptionsToQueryObject,
227
+ triggers,
228
+ TypeCasters,
229
+ };
@@ -373,8 +373,12 @@ class UserManager {
373
373
  let authM = DataProvider.getCollection("cms", "auth");
374
374
  return authM.updateOne(query, update).exec().then();
375
375
  }
376
+
377
+ static get instance() {
378
+ return instance;
379
+ }
376
380
  }
377
381
 
378
- UserManager.instance = new UserManager();
382
+ const instance = new UserManager();
379
383
  module.exports.name = "userManager";
380
384
  module.exports.main = UserManager.instance;
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "include": ["**/*.js"],
3
+ "compilerOptions": {
4
+ "declaration": true,
5
+ "emitDeclarationOnly": true,
6
+ "allowJs": true,
7
+ "outDir": "./types",
8
+ "checkJs": false
9
+ }
10
+ }