@modular-rest/server 1.11.5 → 1.11.7
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/.prettierrc.json +0 -0
- package/package.json +7 -6
- package/src/application.js +32 -17
- package/src/class/cms_trigger.js +20 -0
- package/src/class/db_schemas.js +1 -0
- package/src/class/paginator.js +4 -3
- package/src/class/reply.js +1 -1
- package/src/class/validator.js +3 -3
- package/src/config.js +17 -15
- package/src/index.js +34 -12
- package/src/services/data_provider/typeCasters.js +4 -3
- package/src/services/file/db.js +26 -24
- package/src/services/file/service.js +169 -79
- package/src/services/user_manager/service.js +23 -8
- package/test.js +0 -10
package/.prettierrc.json
ADDED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modular-rest/server",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.7",
|
|
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": {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"types": "./types/index.d.ts",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/
|
|
13
|
+
"url": "git+https://github.com/modular-rest/modular-rest.git"
|
|
14
14
|
},
|
|
15
15
|
"keywords": [
|
|
16
16
|
"app",
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"author": "Navid Shad <navidshad72@gmail.com> (http://navid-shad.ir)",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"bugs": {
|
|
24
|
-
"url": "https://github.com/
|
|
24
|
+
"url": "https://github.com/modular-rest/modular-rest/issues"
|
|
25
25
|
},
|
|
26
|
-
"homepage": "https://github.com/
|
|
26
|
+
"homepage": "https://github.com/modular-rest/modular-rest#readme",
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@koa/cors": "^3.1.0",
|
|
29
29
|
"colog": "^1.0.4",
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
"keypair": "^1.0.4",
|
|
33
33
|
"koa": "^2.5.3",
|
|
34
34
|
"koa-body": "^4.2.0",
|
|
35
|
+
"koa-mount": "^4.0.0",
|
|
35
36
|
"koa-router": "^7.4.0",
|
|
36
|
-
"koa-static
|
|
37
|
+
"koa-static": "^5.0.0",
|
|
37
38
|
"mongoose": "^5.10.9",
|
|
38
39
|
"nested-property": "^4.0.0"
|
|
39
40
|
},
|
|
@@ -43,4 +44,4 @@
|
|
|
43
44
|
"@types/koa__cors": "^5.0.0",
|
|
44
45
|
"typescript": "^5.3.3"
|
|
45
46
|
}
|
|
46
|
-
}
|
|
47
|
+
}
|
package/src/application.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const koa = require("koa");
|
|
2
2
|
const cors = require("@koa/cors");
|
|
3
3
|
const koaBody = require("koa-body");
|
|
4
|
-
const koaStatic = require("koa-static
|
|
4
|
+
const koaStatic = require("koa-static");
|
|
5
|
+
const mount = require("koa-mount");
|
|
5
6
|
const path = require("path");
|
|
6
7
|
const Combination = require("./class/combinator");
|
|
7
8
|
const DataProvider = require("./services/data_provider/service");
|
|
@@ -13,8 +14,8 @@ const defaultServiceRoot = __dirname + "/services";
|
|
|
13
14
|
* @typedef {import('koa')} Koa
|
|
14
15
|
* @typedef {import('http').Server} server
|
|
15
16
|
* @typedef {import('@koa/cors').Options} Cors
|
|
16
|
-
* @typedef {import('./class/security').PermissionGroup} PermissionGroup
|
|
17
|
-
* @typedef {import('./class/
|
|
17
|
+
* @typedef {import('./class/security.js').PermissionGroup} PermissionGroup
|
|
18
|
+
* @typedef {import('./class/cms_trigger.js')} CmsTrigger
|
|
18
19
|
*/
|
|
19
20
|
|
|
20
21
|
const { config, setConfig } = require("./config");
|
|
@@ -25,18 +26,19 @@ const { config, setConfig } = require("./config");
|
|
|
25
26
|
* cors?: Cors; // CORS options.
|
|
26
27
|
* modulesPath?: string; // Root directory of your router.js/db.js files.
|
|
27
28
|
* uploadDirectory?: string; // Root directory of your uploaded files.
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
29
|
+
* koaBodyOptions?: object; // Options for koa-body.
|
|
30
|
+
* staticPath?: {
|
|
31
|
+
* rootDir: string; // Root directory of your static files.
|
|
32
|
+
* rootPath: string; // Root path of your static files, defaults to '/assets'.
|
|
33
|
+
* maxage?: number; // Browser cache max-age in milliseconds. Defaults to 0.
|
|
34
|
+
* hidden?: boolean; // Allow transfer of hidden files. Defaults to false.
|
|
35
|
+
* index?: string; // Default file name. Defaults to 'index.html'.
|
|
36
|
+
* defer?: boolean; // If true, serves after return next(), allowing any downstream middleware to respond first. Defaults to false.
|
|
37
|
+
* gzip?: boolean; // Try to serve the gzipped version of a file automatically when gzip is supported by a client and if the requested file with .gz extension exists. Defaults to true.
|
|
38
|
+
* br?: boolean; // Try to serve the brotli version of a file automatically when brotli is supported by a client and if the requested file with .br extension exists. Note that brotli is only accepted over https. Defaults to false.
|
|
39
|
+
* setHeaders?: Function; // Function to set custom headers on response.
|
|
40
|
+
* extensions?: boolean|Array; // Try to match extensions from passed array to search for file when no extension is suffixed in URL. First found is served. Defaults to false.
|
|
41
|
+
* };
|
|
40
42
|
* onBeforeInit?: (koaApp:Koa) => void; // A callback called before initializing the Koa server.
|
|
41
43
|
* onAfterInit?: (koaApp:Koa) => void; // A callback called after server initialization.
|
|
42
44
|
* port?: number; // Server port.
|
|
@@ -57,7 +59,8 @@ const { config, setConfig } = require("./config");
|
|
|
57
59
|
* verificationCodeGeneratorMethod: () => string; // A method to return a verification code when registering a new user.
|
|
58
60
|
* collectionDefinitions?: CollectionDefinition[]; // An array of additional collection definitions.
|
|
59
61
|
* permissionGroups?: PermissionGroup[]; // An array of additional permission groups.
|
|
60
|
-
* authTriggers?:
|
|
62
|
+
* authTriggers?: CmsTrigger[]; // An array of additional database triggers for the auth collection.
|
|
63
|
+
* fileTriggers?: CmsTrigger[]; // An array of additional database triggers for the auth collection.
|
|
61
64
|
* }} options
|
|
62
65
|
* @returns {Promise<{app: Koa, server: Server}>}
|
|
63
66
|
*/
|
|
@@ -90,6 +93,7 @@ async function createRest(options) {
|
|
|
90
93
|
*/
|
|
91
94
|
const bodyParserOptions = {
|
|
92
95
|
multipart: true,
|
|
96
|
+
...(config.koaBodyOptions || {}),
|
|
93
97
|
};
|
|
94
98
|
app.use(koaBody(bodyParserOptions));
|
|
95
99
|
|
|
@@ -97,7 +101,18 @@ async function createRest(options) {
|
|
|
97
101
|
* Plug In KoaStatic
|
|
98
102
|
*/
|
|
99
103
|
if (config.staticPath) {
|
|
100
|
-
|
|
104
|
+
const defaultStaticPath = config.staticPath.rootDir;
|
|
105
|
+
const defaultStaticRootPath = config.staticPath.rootPath || "/assets";
|
|
106
|
+
|
|
107
|
+
delete config.staticPath.rootDir;
|
|
108
|
+
delete config.staticPath.rootPath;
|
|
109
|
+
|
|
110
|
+
app.use(
|
|
111
|
+
mount(
|
|
112
|
+
defaultStaticRootPath,
|
|
113
|
+
koaStatic(defaultStaticPath, config.staticPath)
|
|
114
|
+
)
|
|
115
|
+
);
|
|
101
116
|
}
|
|
102
117
|
|
|
103
118
|
/**
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `CmsTrigger` is a class that defines a callback to be called on a specific database transaction.
|
|
3
|
+
*
|
|
4
|
+
* @class
|
|
5
|
+
*/
|
|
6
|
+
class CmsTrigger {
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new instance of `CmsTrigger`.
|
|
9
|
+
*
|
|
10
|
+
* @param {'update-one' | 'insert-one' | 'remove-one' } operation - The operation to be triggered.
|
|
11
|
+
* @param {function({query: any, queryResult: any}): void} [callback=(context) => {}] - The callback to be called when the operation is executed. The callback function takes an object as parameter with two properties: 'query' and 'queryResult'.
|
|
12
|
+
* @constructor
|
|
13
|
+
*/
|
|
14
|
+
constructor(operation, callback = (context) => {}) {
|
|
15
|
+
this.operation = operation;
|
|
16
|
+
this.callback = callback;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = CmsTrigger;
|
package/src/class/db_schemas.js
CHANGED
package/src/class/paginator.js
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* @returns {Object} - An object containing pagination information.
|
|
7
7
|
*/
|
|
8
8
|
function create(count, perPage, page) {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const totalPages = Math.ceil(count / perPage);
|
|
10
|
+
|
|
11
|
+
if (page > totalPages) page = 1;
|
|
11
12
|
|
|
12
13
|
let from = 0;
|
|
13
14
|
if (perPage == 1) from = page - 1;
|
|
@@ -16,7 +17,7 @@ function create(count, perPage, page) {
|
|
|
16
17
|
if (page <= 1) from = 0;
|
|
17
18
|
|
|
18
19
|
let result = {
|
|
19
|
-
'pages':
|
|
20
|
+
'pages': totalPages,
|
|
20
21
|
'page': page,
|
|
21
22
|
'from': from,
|
|
22
23
|
'to': perPage
|
package/src/class/reply.js
CHANGED
package/src/class/validator.js
CHANGED
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
function validate(obj, requiredFields) {
|
|
9
9
|
/*
|
|
10
10
|
this method could validate an Object by given field's name list and return bool.
|
|
11
|
-
- requiredFields: is a string that contains keys being
|
|
11
|
+
- requiredFields: is a string that contains keys being spared by " ".
|
|
12
12
|
*/
|
|
13
13
|
let type = typeof requiredFields;
|
|
14
14
|
let result;
|
|
15
15
|
|
|
16
16
|
if (type == 'string')
|
|
17
|
-
result =
|
|
17
|
+
result = checkSimple(obj, requiredFields);
|
|
18
18
|
else if (type == 'object')
|
|
19
19
|
result = checkComplex(obj, requiredFields);
|
|
20
20
|
|
|
@@ -25,7 +25,7 @@ function validate(obj, requiredFields) {
|
|
|
25
25
|
|
|
26
26
|
module.exports = validate;
|
|
27
27
|
|
|
28
|
-
function
|
|
28
|
+
function checkSimple(obj, requiredFields = '') {
|
|
29
29
|
let isValide = false;
|
|
30
30
|
let requires = requiredFields.split(' ');
|
|
31
31
|
|
package/src/config.js
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @typedef {import('koa')} Koa
|
|
3
3
|
* @typedef {import('@koa/cors').Options} Cors
|
|
4
|
-
* @typedef {import('./class/collection_definition')} CollectionDefinition
|
|
5
|
-
* @typedef {import('./class/security').PermissionGroup} PermissionGroup
|
|
6
|
-
* @typedef {import('./class/
|
|
4
|
+
* @typedef {import('./class/collection_definition.js')} CollectionDefinition
|
|
5
|
+
* @typedef {import('./class/security.js').PermissionGroup} PermissionGroup
|
|
6
|
+
* @typedef {import('./class/cms_trigger.js')} CmsTrigger
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @typedef {{
|
|
11
11
|
* cors?: Cors; // CORS options.
|
|
12
12
|
* modulesPath?: string; // Root directory of your router.js/db.js files.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
13
|
+
* koaBodyOptions?: object; // Options for koa-body.
|
|
14
|
+
* staticPath?: {
|
|
15
|
+
* rootDir: string; // Root directory of your static files.
|
|
16
|
+
* rootPath: string; // Root path of your static files, defaults to '/assets'.
|
|
17
|
+
* maxage?: number; // Browser cache max-age in milliseconds. Defaults to 0.
|
|
18
|
+
* hidden?: boolean; // Allow transfer of hidden files. Defaults to false.
|
|
19
|
+
* index?: string; // Default file name. Defaults to 'index.html'.
|
|
20
|
+
* defer?: boolean; // If true, serves after return next(), allowing any downstream middleware to respond first. Defaults to false.
|
|
21
|
+
* gzip?: boolean; // Try to serve the gzipped version of a file automatically when gzip is supported by a client and if the requested file with .gz extension exists. Defaults to true.
|
|
22
|
+
* br?: boolean; // Try to serve the brotli version of a file automatically when brotli is supported by a client and if the requested file with .br extension exists. Note that brotli is only accepted over https. Defaults to false.
|
|
23
|
+
* setHeaders?: Function; // Function to set custom headers on response.
|
|
24
|
+
* extensions?: boolean|Array; // Try to match extensions from passed array to search for file when no extension is suffixed in URL. First found is served. Defaults to false.
|
|
25
|
+
* };
|
|
25
26
|
* onBeforeInit?: (koaApp:Koa) => void; // A callback called before initializing the Koa server.
|
|
26
27
|
* onAfterInit?: (koaApp:Koa) => void; // A callback called after server initialization.
|
|
27
28
|
* port?: number; // Server port.
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
* collectionDefinitions?: CollectionDefinition[]; // An array of additional collection definitions.
|
|
44
45
|
* permissionGroups?: PermissionGroup[]; // An array of additional permission groups.
|
|
45
46
|
* authTriggers?: DatabaseTrigger[]; // An array of additional database triggers for the auth collection.
|
|
47
|
+
* fileTriggers?: CmsTrigger[]; // An array of additional database triggers for the auth collection.
|
|
46
48
|
* }} Config
|
|
47
49
|
* @exports Config
|
|
48
50
|
*/
|
package/src/index.js
CHANGED
|
@@ -9,36 +9,58 @@ const validator = require("./class/validator");
|
|
|
9
9
|
const { getCollection } = require("./services/data_provider/service");
|
|
10
10
|
const { defineFunction } = require("./services/functions/service");
|
|
11
11
|
const TypeCasters = require("./services/data_provider/typeCasters");
|
|
12
|
+
const userManager = require("./services/user_manager/service");
|
|
13
|
+
const {
|
|
14
|
+
getFile,
|
|
15
|
+
getFileLink,
|
|
16
|
+
getFilePath,
|
|
17
|
+
removeFile,
|
|
18
|
+
storeFile,
|
|
19
|
+
} = require("./services/file/service");
|
|
12
20
|
|
|
13
21
|
// Base class
|
|
14
22
|
const CollectionDefinition = require("./class/collection_definition");
|
|
15
23
|
const Schemas = require("./class/db_schemas");
|
|
16
24
|
const DatabaseTrigger = require("./class/database_trigger");
|
|
25
|
+
const CmsTrigger = require("./class/cms_trigger");
|
|
17
26
|
const SecurityClass = require("./class/security");
|
|
18
27
|
const middleware = require("./middlewares");
|
|
19
|
-
const userManager = require("./services/user_manager/service");
|
|
20
28
|
|
|
21
29
|
module.exports = {
|
|
22
30
|
createRest,
|
|
23
31
|
|
|
24
|
-
// Route utilities
|
|
25
|
-
reply,
|
|
26
|
-
TypeCasters,
|
|
27
|
-
paginator,
|
|
28
|
-
validator,
|
|
29
|
-
|
|
30
|
-
// Service utilities
|
|
31
|
-
getCollection,
|
|
32
|
-
defineFunction,
|
|
33
|
-
|
|
34
32
|
// Database
|
|
35
33
|
CollectionDefinition,
|
|
36
34
|
Schemas,
|
|
37
35
|
Schema,
|
|
38
36
|
DatabaseTrigger,
|
|
37
|
+
CmsTrigger,
|
|
39
38
|
...SecurityClass,
|
|
40
39
|
|
|
41
|
-
//
|
|
40
|
+
// Function
|
|
41
|
+
defineFunction,
|
|
42
|
+
|
|
43
|
+
// Private utilities
|
|
44
|
+
TypeCasters,
|
|
45
|
+
validator,
|
|
46
|
+
|
|
47
|
+
// Route utilities
|
|
48
|
+
reply,
|
|
49
|
+
paginator,
|
|
50
|
+
|
|
51
|
+
// Database utilities
|
|
52
|
+
getCollection,
|
|
53
|
+
|
|
54
|
+
// File Utilities
|
|
55
|
+
getFile,
|
|
56
|
+
getFileLink,
|
|
57
|
+
getFilePath,
|
|
58
|
+
removeFile,
|
|
59
|
+
storeFile,
|
|
60
|
+
|
|
61
|
+
// Middleware utilities
|
|
42
62
|
middleware,
|
|
63
|
+
|
|
64
|
+
// User utilities
|
|
43
65
|
userManager: userManager.main,
|
|
44
66
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
const Mongoose = require('mongoose');
|
|
2
|
+
|
|
2
3
|
module.exports = {
|
|
3
4
|
'ObjectId': Mongoose.Types.ObjectId,
|
|
4
5
|
'Date': (dateValue) => {
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
const strDate = dateValue.toString();
|
|
7
|
+
const mongoDateFormateInString = new Date(strDate).toISOString().split('T')[0];
|
|
7
8
|
return new Date(mongoDateFormateInString);
|
|
8
9
|
}
|
|
9
10
|
}
|
package/src/services/file/db.js
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
|
-
var mongoose = require(
|
|
2
|
-
var Schemas = require(
|
|
1
|
+
var mongoose = require("mongoose");
|
|
2
|
+
var Schemas = require("../../class/db_schemas");
|
|
3
3
|
|
|
4
|
-
let CollectionDefinition = require(
|
|
5
|
-
let { Permission, PermissionTypes } = require(
|
|
4
|
+
let CollectionDefinition = require("../../class/collection_definition");
|
|
5
|
+
let { Permission, PermissionTypes } = require("../../class/security");
|
|
6
|
+
const { config } = require("../../config");
|
|
6
7
|
|
|
7
8
|
module.exports = [
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
9
|
+
new CollectionDefinition({
|
|
10
|
+
db: "cms",
|
|
11
|
+
collection: "file",
|
|
12
|
+
schema: Schemas.file,
|
|
13
|
+
permissions: [
|
|
14
|
+
new Permission({
|
|
15
|
+
type: PermissionTypes.upload_file_access,
|
|
16
|
+
read: true,
|
|
17
|
+
write: true,
|
|
18
|
+
onlyOwnData: false,
|
|
19
|
+
}),
|
|
20
|
+
new Permission({
|
|
21
|
+
type: PermissionTypes.remove_file_access,
|
|
22
|
+
read: true,
|
|
23
|
+
write: true,
|
|
24
|
+
onlyOwnData: false,
|
|
25
|
+
}),
|
|
26
|
+
],
|
|
27
|
+
triggers: config.fileTriggers || [],
|
|
28
|
+
}),
|
|
29
|
+
];
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const pathModule = require(
|
|
3
|
-
const DataProvider = require(
|
|
1
|
+
const fs = require("file-system");
|
|
2
|
+
const pathModule = require("path");
|
|
3
|
+
const DataProvider = require("./../data_provider/service");
|
|
4
|
+
const triggerService = require("./../../class/trigger_operator");
|
|
5
|
+
const { config } = require("./../../config");
|
|
4
6
|
|
|
5
7
|
class FileService {
|
|
6
|
-
|
|
7
8
|
constructor() {
|
|
8
9
|
this.directory = null;
|
|
9
10
|
}
|
|
@@ -13,9 +14,10 @@ class FileService {
|
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
|
-
*
|
|
17
|
-
* @param {string} fileType
|
|
18
|
-
*
|
|
17
|
+
*
|
|
18
|
+
* @param {string} fileType
|
|
19
|
+
* @param {string} tag
|
|
20
|
+
*
|
|
19
21
|
* @returns storedFile
|
|
20
22
|
* @returns storedFile.fileName
|
|
21
23
|
* @returns storedFile.directory
|
|
@@ -23,119 +25,207 @@ class FileService {
|
|
|
23
25
|
* @returns storedFile.fileFormat
|
|
24
26
|
*/
|
|
25
27
|
createStoredDetail(fileType, tag) {
|
|
28
|
+
const typeParts = fileType.split("/");
|
|
29
|
+
const fileFormat = typeParts[1] || typeParts[0] || "unknown";
|
|
30
|
+
|
|
31
|
+
const time = new Date().getTime();
|
|
32
|
+
const fileName = `${time}.${fileFormat}`;
|
|
26
33
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
const fullPath = pathModule.join(
|
|
35
|
+
FileService.instance.directory,
|
|
36
|
+
fileFormat,
|
|
37
|
+
tag,
|
|
38
|
+
fileName
|
|
39
|
+
);
|
|
31
40
|
|
|
32
41
|
return { fileName, fullPath, fileFormat };
|
|
33
42
|
}
|
|
34
43
|
|
|
35
|
-
|
|
36
44
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* @param {
|
|
40
|
-
* @param {
|
|
45
|
+
* Stores a file, removes the given temporary file, and submits file details into the database.
|
|
46
|
+
*
|
|
47
|
+
* @param {Object} options - The options for storing the file.
|
|
48
|
+
* @param {Object} options.file - The file to be stored.
|
|
49
|
+
* @param {string} options.file.path - The path of the file.
|
|
50
|
+
* @param {string} options.file.type - The type of the file.
|
|
51
|
+
* @param {string} options.file.name - The original name of the file.
|
|
52
|
+
* @param {number} options.file.size - The size of the file.
|
|
53
|
+
* @param {string} options.ownerId - The ID of the owner of the file.
|
|
54
|
+
* @param {string} options.tag - The tag associated with the file.
|
|
55
|
+
* @param {boolean} [options.removeFileAfterStore=true] - Whether to remove the file after storing it.
|
|
56
|
+
*
|
|
57
|
+
* @returns {Promise} A promise that resolves with the document of the stored file.
|
|
58
|
+
*
|
|
59
|
+
* @throws {string} If the upload directory has not been set.
|
|
41
60
|
*/
|
|
42
|
-
storeFile({ file, ownerId, tag }) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
throw 'upload directory has not been set.'
|
|
61
|
+
storeFile({ file, ownerId, tag, removeFileAfterStore = true }) {
|
|
62
|
+
if (!FileService.instance.directory)
|
|
63
|
+
throw "upload directory has not been set.";
|
|
46
64
|
|
|
47
65
|
let storedFile;
|
|
48
66
|
|
|
49
|
-
return
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
storedFile = this.createStoredDetail(file.type, tag);
|
|
67
|
+
return (
|
|
68
|
+
new Promise(async (done, reject) => /**
|
|
69
|
+
* Store file and remove temp file
|
|
70
|
+
*/ {
|
|
71
|
+
storedFile = FileService.instance.createStoredDetail(file.type, tag);
|
|
55
72
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
fs.copyFile(file.path, storedFile.fullPath, {
|
|
74
|
+
done: (err) => {
|
|
75
|
+
if (err) reject(err);
|
|
76
|
+
else done();
|
|
60
77
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
65
|
-
})
|
|
66
|
-
/**
|
|
67
|
-
* Submit file detail into database
|
|
68
|
-
*/
|
|
69
|
-
.then(() => {
|
|
70
|
-
|
|
71
|
-
// Get collection model for access to relative collection
|
|
72
|
-
let CollectionModel = DataProvider.getCollection('cms', 'file');
|
|
73
|
-
|
|
74
|
-
// Create new document
|
|
75
|
-
let doc = new CollectionModel({
|
|
76
|
-
owner: ownerId,
|
|
77
|
-
fileName: storedFile.fileName,
|
|
78
|
-
originalName: file.name,
|
|
79
|
-
format: storedFile.fileFormat,
|
|
80
|
-
tag,
|
|
78
|
+
// remove temp file
|
|
79
|
+
if (removeFileAfterStore) fs.fs.unlinkSync(file.path);
|
|
80
|
+
},
|
|
81
81
|
});
|
|
82
|
-
|
|
83
|
-
return doc.save().then(() => doc);
|
|
84
|
-
|
|
85
|
-
}).catch(err => {
|
|
86
|
-
|
|
87
|
-
// remove stored file
|
|
88
|
-
fs.fs.unlinkSync(storedFile.fullPath);
|
|
89
|
-
|
|
90
|
-
throw err;
|
|
91
82
|
})
|
|
83
|
+
/**
|
|
84
|
+
* Submit file detail into database
|
|
85
|
+
*/
|
|
86
|
+
.then(() => {
|
|
87
|
+
// Get collection model for access to relative collection
|
|
88
|
+
const CollectionModel = DataProvider.getCollection("cms", "file");
|
|
89
|
+
|
|
90
|
+
const data = {
|
|
91
|
+
owner: ownerId,
|
|
92
|
+
fileName: storedFile.fileName,
|
|
93
|
+
originalName: file.name,
|
|
94
|
+
format: storedFile.fileFormat,
|
|
95
|
+
tag,
|
|
96
|
+
size: file.size,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Create new document
|
|
100
|
+
const doc = new CollectionModel(data);
|
|
101
|
+
|
|
102
|
+
return doc.save().then((savedDoc) => {
|
|
103
|
+
triggerService.call("insert-one", "cms", "file", {
|
|
104
|
+
query: null,
|
|
105
|
+
queryResult: savedDoc,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return savedDoc;
|
|
109
|
+
});
|
|
110
|
+
})
|
|
111
|
+
.catch((err) => {
|
|
112
|
+
// remove stored file
|
|
113
|
+
fs.fs.unlinkSync(storedFile.fullPath);
|
|
114
|
+
|
|
115
|
+
throw err;
|
|
116
|
+
})
|
|
117
|
+
);
|
|
92
118
|
}
|
|
93
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Removes a file from the disk.
|
|
122
|
+
*
|
|
123
|
+
* @param {string} path - The path of the file to be removed.
|
|
124
|
+
* @returns {Promise} A promise that resolves if the file is successfully removed, and rejects if an error occurs.
|
|
125
|
+
*/
|
|
94
126
|
removeFromDisc(path) {
|
|
95
127
|
return new Promise((done, reject) => {
|
|
96
128
|
fs.fs.unlink(path, (err) => {
|
|
97
|
-
if (err) reject()
|
|
98
|
-
else done()
|
|
129
|
+
if (err) reject();
|
|
130
|
+
else done();
|
|
99
131
|
});
|
|
100
|
-
})
|
|
132
|
+
});
|
|
101
133
|
}
|
|
102
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Removes a file from the database and the disk.
|
|
137
|
+
*
|
|
138
|
+
* @param {string} fileId - The ID of the file to be removed.
|
|
139
|
+
* @returns {Promise} A promise that resolves if the file is successfully removed, and rejects if an error occurs.
|
|
140
|
+
* @throws Will throw an error if upload directory has not been set.
|
|
141
|
+
*/
|
|
103
142
|
removeFile(fileId) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
throw 'upload directory has not been set.'
|
|
143
|
+
if (!FileService.instance.directory)
|
|
144
|
+
throw "upload directory has not been set.";
|
|
107
145
|
|
|
108
146
|
return new Promise(async (done, reject) => {
|
|
109
|
-
let CollectionModel = DataProvider.getCollection(
|
|
147
|
+
let CollectionModel = DataProvider.getCollection("cms", "file");
|
|
110
148
|
let fileDoc = await CollectionModel.findOne({ _id: fileId }).exec();
|
|
111
149
|
|
|
112
150
|
if (!fileDoc) {
|
|
113
|
-
reject(
|
|
151
|
+
reject("file not found");
|
|
114
152
|
return;
|
|
115
153
|
}
|
|
116
154
|
|
|
117
|
-
await CollectionModel.deleteOne({ _id: fileId })
|
|
155
|
+
await CollectionModel.deleteOne({ _id: fileId })
|
|
156
|
+
.exec()
|
|
118
157
|
.then(() => {
|
|
119
|
-
|
|
120
158
|
// create file path
|
|
121
|
-
|
|
159
|
+
const filePath = pathModule.join(
|
|
160
|
+
FileService.instance.directory,
|
|
161
|
+
fileDoc.format,
|
|
162
|
+
fileDoc.tag,
|
|
163
|
+
fileDoc.fileName
|
|
164
|
+
);
|
|
122
165
|
|
|
123
166
|
// Remove file from disc
|
|
124
|
-
return
|
|
167
|
+
return FileService.instance
|
|
168
|
+
.removeFromDisc(filePath)
|
|
125
169
|
.catch(async (err) => {
|
|
126
|
-
|
|
127
|
-
// Recreate fileDoc if removing file operation has error
|
|
170
|
+
// Recreate fileDoc if removing file operation has error
|
|
128
171
|
await new CollectionModel(fileDoc).save();
|
|
129
172
|
|
|
130
173
|
throw err;
|
|
131
|
-
})
|
|
132
|
-
|
|
174
|
+
});
|
|
175
|
+
})
|
|
176
|
+
.then(() => {
|
|
177
|
+
triggerService.call("remove-one", "cms", "file", {
|
|
178
|
+
query: { _id: fileId },
|
|
179
|
+
queryResult: null,
|
|
180
|
+
});
|
|
133
181
|
})
|
|
134
182
|
.then(done)
|
|
135
|
-
.catch(reject)
|
|
136
|
-
})
|
|
183
|
+
.catch(reject);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Retrieves a file from the database.
|
|
189
|
+
*
|
|
190
|
+
* @param {string} fileId - The ID of the file to be retrieved.
|
|
191
|
+
* @returns {Promise} A promise that resolves with the file document, or rejects if an error occurs.
|
|
192
|
+
*/
|
|
193
|
+
getFile(fileId) {
|
|
194
|
+
const CollectionModel = DataProvider.getCollection("cms", "file");
|
|
195
|
+
|
|
196
|
+
return CollectionModel.findOne({ _id: fileId }).exec();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Retrieves the link of a file.
|
|
201
|
+
*
|
|
202
|
+
* @param {string} fileId - The ID of the file to get the link for.
|
|
203
|
+
* @returns {Promise} A promise that resolves with the file link, or rejects if an error occurs.
|
|
204
|
+
*/
|
|
205
|
+
async getFileLink(fileId) {
|
|
206
|
+
const fileDoc = await FileService.instance.getFile(fileId);
|
|
207
|
+
|
|
208
|
+
const link =
|
|
209
|
+
config.staticPath.rootPath +
|
|
210
|
+
`/${fileDoc.format}/${fileDoc.tag}/` +
|
|
211
|
+
fileDoc.fileName;
|
|
212
|
+
|
|
213
|
+
return link;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async getFilePath(fileId) {
|
|
217
|
+
const { fileName, format, tag } = await FileService.instance.getFile(
|
|
218
|
+
fileId
|
|
219
|
+
);
|
|
220
|
+
const fullPath = pathModule.join(
|
|
221
|
+
FileService.instance.directory,
|
|
222
|
+
format,
|
|
223
|
+
tag,
|
|
224
|
+
fileName
|
|
225
|
+
);
|
|
226
|
+
return fullPath;
|
|
137
227
|
}
|
|
138
228
|
}
|
|
139
229
|
|
|
140
|
-
FileService.instance = new FileService()
|
|
141
|
-
module.exports = FileService.instance;
|
|
230
|
+
FileService.instance = new FileService();
|
|
231
|
+
module.exports = FileService.instance;
|
|
@@ -14,18 +14,21 @@ class UserManager {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* Sets a custom method for generating verification codes.
|
|
18
|
+
*
|
|
19
|
+
* @param {Function} generatorMethod - A function that returns a random verification code.
|
|
20
|
+
* @returns {void}
|
|
19
21
|
*/
|
|
20
|
-
setCustomVerificationCodeGeneratorMethod(
|
|
21
|
-
this.verificationCodeGeneratorMethod =
|
|
22
|
+
setCustomVerificationCodeGeneratorMethod(generatorMethod) {
|
|
23
|
+
this.verificationCodeGeneratorMethod = generatorMethod;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* @param {string}
|
|
28
|
-
* @returns {
|
|
27
|
+
* Get a user by their ID.
|
|
28
|
+
*
|
|
29
|
+
* @param {string} id - The ID of the user.
|
|
30
|
+
* @returns {Promise<User>} A promise that resolves to the user.
|
|
31
|
+
* @throws {Error} If the user is not found.
|
|
29
32
|
*/
|
|
30
33
|
generateVerificationCode(id, idType) {
|
|
31
34
|
if (this.verificationCodeGeneratorMethod)
|
|
@@ -37,6 +40,7 @@ class UserManager {
|
|
|
37
40
|
|
|
38
41
|
/**
|
|
39
42
|
* Get a user by their ID.
|
|
43
|
+
*
|
|
40
44
|
* @param {string} id - The ID of the user.
|
|
41
45
|
* @returns {Promise<User>} A promise that resolves to the user.
|
|
42
46
|
* @throws {string} If the user is not found.
|
|
@@ -63,6 +67,7 @@ class UserManager {
|
|
|
63
67
|
|
|
64
68
|
/**
|
|
65
69
|
* Get a user by their identity.
|
|
70
|
+
*
|
|
66
71
|
* @param {string} id - The identity of the user.
|
|
67
72
|
* @param {string} idType - The type of the identity (phone or email).
|
|
68
73
|
* @returns {Promise<User>} A promise that resolves to the user.
|
|
@@ -95,6 +100,7 @@ class UserManager {
|
|
|
95
100
|
|
|
96
101
|
/**
|
|
97
102
|
* Get a user by their token.
|
|
103
|
+
*
|
|
98
104
|
* @param {string} token - The token of the user.
|
|
99
105
|
* @returns {Promise<User>} A promise that resolves to the user.
|
|
100
106
|
*/
|
|
@@ -105,6 +111,7 @@ class UserManager {
|
|
|
105
111
|
|
|
106
112
|
/**
|
|
107
113
|
* Check if a verification code is valid.
|
|
114
|
+
*
|
|
108
115
|
* @param {string} id - The ID of the user.
|
|
109
116
|
* @param {string} code - The verification code.
|
|
110
117
|
* @returns {boolean} Whether the verification code is valid.
|
|
@@ -123,6 +130,7 @@ class UserManager {
|
|
|
123
130
|
|
|
124
131
|
/**
|
|
125
132
|
* Login a user and return their token.
|
|
133
|
+
*
|
|
126
134
|
* @param {string} id - The ID of the user.
|
|
127
135
|
* @param {string} idType - The type of the ID (phone or email).
|
|
128
136
|
* @param {string} password - The password of the user.
|
|
@@ -172,6 +180,7 @@ class UserManager {
|
|
|
172
180
|
|
|
173
181
|
/**
|
|
174
182
|
* Issue a token for a user.
|
|
183
|
+
*
|
|
175
184
|
* @param {string} email - The email of the user.
|
|
176
185
|
* @returns {Promise<string>} A promise that resolves to the token of the user.
|
|
177
186
|
* @throws {string} If the user is not found.
|
|
@@ -199,6 +208,7 @@ class UserManager {
|
|
|
199
208
|
|
|
200
209
|
/**
|
|
201
210
|
* Login as an anonymous user.
|
|
211
|
+
*
|
|
202
212
|
* @returns {Promise<string>} A promise that resolves to the token of the anonymous user.
|
|
203
213
|
* @throws {string} If the anonymous user is not found.
|
|
204
214
|
*/
|
|
@@ -245,6 +255,7 @@ class UserManager {
|
|
|
245
255
|
|
|
246
256
|
/**
|
|
247
257
|
* Register a temporary ID.
|
|
258
|
+
*
|
|
248
259
|
* @param {string} id - The ID to register.
|
|
249
260
|
* @param {string} type - The type of the ID.
|
|
250
261
|
* @param {string} code - The verification code.
|
|
@@ -255,6 +266,7 @@ class UserManager {
|
|
|
255
266
|
|
|
256
267
|
/**
|
|
257
268
|
* Submit a password for a temporary ID.
|
|
269
|
+
*
|
|
258
270
|
* @param {string} id - The ID.
|
|
259
271
|
* @param {string} password - The password.
|
|
260
272
|
* @param {string} code - The verification code.
|
|
@@ -285,6 +297,7 @@ class UserManager {
|
|
|
285
297
|
|
|
286
298
|
/**
|
|
287
299
|
* Change the password for a temporary ID.
|
|
300
|
+
*
|
|
288
301
|
* @param {string} id - The ID.
|
|
289
302
|
* @param {string} password - The new password.
|
|
290
303
|
* @param {string} code - The verification code.
|
|
@@ -310,6 +323,7 @@ class UserManager {
|
|
|
310
323
|
|
|
311
324
|
/**
|
|
312
325
|
* Register a user.
|
|
326
|
+
*
|
|
313
327
|
* @param {Object} detail - The details of the user.
|
|
314
328
|
* @returns {Promise<string>} A promise that resolves to the ID of the new user.
|
|
315
329
|
* @throws {string} If the user could not be registered.
|
|
@@ -342,6 +356,7 @@ class UserManager {
|
|
|
342
356
|
|
|
343
357
|
/**
|
|
344
358
|
* Change the password of a user.
|
|
359
|
+
*
|
|
345
360
|
* @param {Object} query - The query to find the user.
|
|
346
361
|
* @param {string} newPass - The new password.
|
|
347
362
|
* @returns {Promise<void>} A promise that resolves when the operation is complete.
|
package/test.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
const { createRest } = require('.');
|
|
2
|
-
const { PermissionTypes } = require('./src/class/security');
|
|
3
|
-
|
|
4
|
-
{ createRest } require('./src/application');
|
|
5
|
-
{PermissionTypes} require('./src/class/security');
|
|
6
|
-
|
|
7
|
-
createRest({
|
|
8
|
-
uploadDirectory: 'uploads',
|
|
9
|
-
port: '3001'
|
|
10
|
-
});
|