@modular-rest/server 1.11.13 → 1.11.15
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/.nvmrc +1 -0
- package/.prettierrc.json +9 -0
- package/.releaserc.json +24 -0
- package/README.md +79 -94
- package/dist/application.d.ts +29 -0
- package/dist/application.js +217 -0
- package/dist/class/cms_trigger.d.ts +52 -0
- package/dist/class/cms_trigger.js +47 -0
- package/dist/class/collection_definition.d.ts +112 -0
- package/dist/class/collection_definition.js +87 -0
- package/dist/class/combinator.d.ts +43 -0
- package/dist/class/combinator.js +174 -0
- package/dist/class/database_trigger.d.ts +90 -0
- package/dist/class/database_trigger.js +64 -0
- package/dist/class/db_schemas.d.ts +25 -0
- package/dist/class/db_schemas.js +28 -0
- package/dist/class/directory.d.ts +20 -0
- package/dist/class/directory.js +87 -0
- package/dist/class/paginator.d.ts +31 -0
- package/dist/class/paginator.js +43 -0
- package/dist/class/reply.d.ts +29 -0
- package/dist/class/reply.js +44 -0
- package/dist/class/security.d.ts +186 -0
- package/dist/class/security.js +178 -0
- package/dist/class/trigger_operator.d.ts +92 -0
- package/dist/class/trigger_operator.js +99 -0
- package/dist/class/user.d.ts +81 -0
- package/dist/class/user.js +151 -0
- package/dist/class/validator.d.ts +19 -0
- package/dist/class/validator.js +101 -0
- package/dist/config.d.ts +113 -0
- package/dist/config.js +26 -0
- package/dist/defult-permissions.d.ts +2 -0
- package/dist/defult-permissions.js +31 -0
- package/dist/events.d.ts +23 -0
- package/dist/events.js +47 -0
- package/dist/helper/data_insertion.d.ts +38 -0
- package/dist/helper/data_insertion.js +110 -0
- package/dist/helper/presetup_services.d.ts +60 -0
- package/dist/helper/presetup_services.js +108 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.js +79 -0
- package/dist/middlewares.d.ts +53 -0
- package/dist/middlewares.js +106 -0
- package/dist/play-test.d.ts +1 -0
- package/dist/play-test.js +9 -0
- package/dist/services/data_provider/router.d.ts +4 -0
- package/dist/services/data_provider/router.js +412 -0
- package/dist/services/data_provider/service.d.ts +132 -0
- package/dist/services/data_provider/service.js +253 -0
- package/dist/services/data_provider/typeCasters.d.ts +9 -0
- package/dist/services/data_provider/typeCasters.js +18 -0
- package/dist/services/file/db.d.ts +1 -0
- package/dist/services/file/db.js +31 -0
- package/dist/services/file/router.d.ts +4 -0
- package/dist/services/file/router.js +115 -0
- package/dist/services/file/service.d.ts +204 -0
- package/dist/services/file/service.js +341 -0
- package/dist/services/functions/router.d.ts +4 -0
- package/dist/services/functions/router.js +68 -0
- package/dist/services/functions/service.d.ts +132 -0
- package/dist/services/functions/service.js +159 -0
- package/dist/services/jwt/router.d.ts +4 -0
- package/dist/services/jwt/router.js +99 -0
- package/dist/services/jwt/service.d.ts +97 -0
- package/dist/services/jwt/service.js +135 -0
- package/dist/services/user_manager/db.d.ts +1 -0
- package/dist/services/user_manager/db.js +75 -0
- package/dist/services/user_manager/permissionManager.d.ts +19 -0
- package/dist/services/user_manager/permissionManager.js +42 -0
- package/dist/services/user_manager/router.d.ts +4 -0
- package/dist/services/user_manager/router.js +195 -0
- package/dist/services/user_manager/service.d.ts +317 -0
- package/dist/services/user_manager/service.js +632 -0
- package/docs/.keep +0 -0
- package/docs/system-access-type.md +26 -0
- package/package.json +59 -46
- package/src/application.ts +206 -0
- package/src/class/cms_trigger.ts +62 -0
- package/src/class/collection_definition.ts +134 -0
- package/src/class/combinator.ts +176 -0
- package/src/class/database_trigger.ts +105 -0
- package/src/class/db_schemas.ts +44 -0
- package/src/class/{directory.js → directory.ts} +40 -18
- package/src/class/paginator.ts +51 -0
- package/src/class/reply.ts +59 -0
- package/src/class/security.ts +250 -0
- package/src/class/trigger_operator.ts +142 -0
- package/src/class/user.ts +199 -0
- package/src/class/validator.ts +123 -0
- package/src/config.ts +122 -0
- package/src/defult-permissions.ts +31 -0
- package/src/events.ts +59 -0
- package/src/helper/data_insertion.ts +94 -0
- package/src/helper/presetup_services.ts +96 -0
- package/src/index.ts +146 -0
- package/src/middlewares.ts +75 -0
- package/src/play-test.ts +8 -0
- package/src/services/data_provider/router.ts +484 -0
- package/src/services/data_provider/service.ts +306 -0
- package/src/services/data_provider/typeCasters.ts +15 -0
- package/src/services/file/db.ts +29 -0
- package/src/services/file/router.ts +88 -0
- package/src/services/file/service.ts +387 -0
- package/src/services/functions/router.ts +35 -0
- package/src/services/functions/service.ts +203 -0
- package/src/services/jwt/router.ts +73 -0
- package/src/services/jwt/service.ts +139 -0
- package/src/services/user_manager/db.ts +87 -0
- package/src/services/user_manager/permissionManager.ts +49 -0
- package/src/services/user_manager/router.ts +193 -0
- package/src/services/user_manager/service.ts +703 -0
- package/tsconfig.json +16 -9
- package/typedoc.mjs +41 -0
- package/LICENSE +0 -21
- package/package-lock.json +0 -1373
- package/src/application.js +0 -239
- package/src/class/cms_trigger.js +0 -20
- package/src/class/collection_definition.js +0 -33
- package/src/class/combinator.js +0 -133
- package/src/class/database_trigger.js +0 -20
- package/src/class/db_schemas.js +0 -18
- package/src/class/paginator.js +0 -31
- package/src/class/reply.js +0 -37
- package/src/class/security.js +0 -141
- package/src/class/trigger_operator.js +0 -39
- package/src/class/user.js +0 -112
- package/src/class/validator.js +0 -91
- package/src/config.js +0 -67
- package/src/events.js +0 -15
- package/src/helper/data_insertion.js +0 -64
- package/src/helper/presetup_services.js +0 -31
- package/src/index.js +0 -66
- package/src/middlewares.js +0 -44
- package/src/services/data_provider/router.js +0 -552
- package/src/services/data_provider/service.js +0 -262
- package/src/services/data_provider/typeCasters.js +0 -10
- package/src/services/file/db.js +0 -29
- package/src/services/file/router.js +0 -92
- package/src/services/file/service.js +0 -231
- package/src/services/functions/router.js +0 -37
- package/src/services/functions/service.js +0 -74
- package/src/services/jwt/router.js +0 -82
- package/src/services/jwt/service.js +0 -37
- package/src/services/user_manager/db.js +0 -83
- package/src/services/user_manager/permissionManager.js +0 -43
- package/src/services/user_manager/router.js +0 -176
- package/src/services/user_manager/service.js +0 -377
- package/types/application.d.ts +0 -97
- package/types/class/cms_trigger.d.ts +0 -24
- package/types/class/collection_definition.d.ts +0 -36
- package/types/class/combinator.d.ts +0 -30
- package/types/class/database_trigger.d.ts +0 -28
- package/types/class/db_schemas.d.ts +0 -2
- package/types/class/directory.d.ts +0 -2
- package/types/class/paginator.d.ts +0 -8
- package/types/class/reply.d.ts +0 -8
- package/types/class/security.d.ts +0 -109
- package/types/class/trigger_operator.d.ts +0 -19
- package/types/class/user.d.ts +0 -24
- package/types/class/validator.d.ts +0 -9
- package/types/config.d.ts +0 -101
- package/types/events.d.ts +0 -7
- package/types/helper/data_insertion.d.ts +0 -4
- package/types/helper/presetup_services.d.ts +0 -5
- package/types/index.d.ts +0 -72
- package/types/middlewares.d.ts +0 -10
- package/types/services/data_provider/router.d.ts +0 -3
- package/types/services/data_provider/service.d.ts +0 -40
- package/types/services/data_provider/typeCasters.d.ts +0 -3
- package/types/services/file/db.d.ts +0 -3
- package/types/services/file/router.d.ts +0 -3
- package/types/services/file/service.d.ts +0 -81
- package/types/services/functions/router.d.ts +0 -3
- package/types/services/functions/service.d.ts +0 -23
- package/types/services/jwt/router.d.ts +0 -3
- package/types/services/jwt/service.d.ts +0 -10
- package/types/services/user_manager/db.d.ts +0 -3
- package/types/services/user_manager/permissionManager.d.ts +0 -3
- package/types/services/user_manager/router.d.ts +0 -3
- package/types/services/user_manager/service.d.ts +0 -131
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TypeCasters = exports.triggers = exports.name = void 0;
|
|
7
|
+
exports.addCollectionDefinitionByList = addCollectionDefinitionByList;
|
|
8
|
+
exports.getCollection = getCollection;
|
|
9
|
+
exports.checkAccess = checkAccess;
|
|
10
|
+
exports.getAsID = getAsID;
|
|
11
|
+
exports.performPopulateToQueryObject = performPopulateToQueryObject;
|
|
12
|
+
exports.performAdditionalOptionsToQueryObject = performAdditionalOptionsToQueryObject;
|
|
13
|
+
const mongoose_1 = __importDefault(require("mongoose"));
|
|
14
|
+
const security_1 = require("../../class/security");
|
|
15
|
+
const trigger_operator_1 = __importDefault(require("../../class/trigger_operator"));
|
|
16
|
+
exports.triggers = trigger_operator_1.default;
|
|
17
|
+
const typeCasters_1 = __importDefault(require("./typeCasters"));
|
|
18
|
+
exports.TypeCasters = typeCasters_1.default;
|
|
19
|
+
/**
|
|
20
|
+
* Service name constant
|
|
21
|
+
* @constant {string}
|
|
22
|
+
*/
|
|
23
|
+
exports.name = 'dataProvider';
|
|
24
|
+
// Set mongoose options
|
|
25
|
+
mongoose_1.default.set('useCreateIndex', true);
|
|
26
|
+
// Database connections and collections storage
|
|
27
|
+
const connections = {};
|
|
28
|
+
const collections = {};
|
|
29
|
+
const permissionDefinitions = {};
|
|
30
|
+
/**
|
|
31
|
+
* Connects to a database and sets up collections based on collection definitions
|
|
32
|
+
* @function connectToDatabaseByCollectionDefinitionList
|
|
33
|
+
* @param {string} dbName - Name of the database to connect to
|
|
34
|
+
* @param {CollectionDefinition[]} [collectionDefinitionList=[]] - List of collection definitions
|
|
35
|
+
* @param {MongoOption} mongoOption - MongoDB connection options
|
|
36
|
+
* @returns {Promise<void>} A promise that resolves when the connection is established
|
|
37
|
+
* @throws {Error} If triggers are not properly configured
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
function connectToDatabaseByCollectionDefinitionList(dbName, collectionDefinitionList = [], mongoOption) {
|
|
41
|
+
return new Promise((done, reject) => {
|
|
42
|
+
// Create db connection
|
|
43
|
+
const fullDbName = (mongoOption.dbPrefix || '') + dbName;
|
|
44
|
+
const connectionString = mongoOption.mongoBaseAddress;
|
|
45
|
+
console.info(`- Connecting to database: ${fullDbName}`);
|
|
46
|
+
const connection = mongoose_1.default.createConnection(connectionString, {
|
|
47
|
+
useUnifiedTopology: true,
|
|
48
|
+
useNewUrlParser: true,
|
|
49
|
+
dbName: fullDbName,
|
|
50
|
+
});
|
|
51
|
+
// Store connection
|
|
52
|
+
connections[dbName] = connection;
|
|
53
|
+
// add db models from schemas
|
|
54
|
+
collectionDefinitionList.forEach(collectionDefinition => {
|
|
55
|
+
const collection = collectionDefinition.collection;
|
|
56
|
+
const schema = collectionDefinition.schema;
|
|
57
|
+
if (collections[dbName] == undefined)
|
|
58
|
+
collections[dbName] = {};
|
|
59
|
+
if (permissionDefinitions[dbName] == undefined)
|
|
60
|
+
permissionDefinitions[dbName] = {};
|
|
61
|
+
// create model from schema
|
|
62
|
+
// and store in on global collection object
|
|
63
|
+
const model = connection.model(collection, schema);
|
|
64
|
+
collections[dbName][collection] = model;
|
|
65
|
+
// define Access Definition from component permissions
|
|
66
|
+
// and store it on global access definition object
|
|
67
|
+
permissionDefinitions[dbName][collection] = new security_1.AccessDefinition({
|
|
68
|
+
database: dbName,
|
|
69
|
+
collection: collection,
|
|
70
|
+
permissionList: collectionDefinition.permissions,
|
|
71
|
+
});
|
|
72
|
+
// add trigger
|
|
73
|
+
if (collectionDefinition.triggers != undefined) {
|
|
74
|
+
if (!Array.isArray(collectionDefinition.triggers)) {
|
|
75
|
+
throw new Error('Triggers must be an array');
|
|
76
|
+
}
|
|
77
|
+
collectionDefinition.triggers.forEach(trigger => {
|
|
78
|
+
trigger_operator_1.default.addTrigger({
|
|
79
|
+
...trigger,
|
|
80
|
+
database: collectionDefinition.database,
|
|
81
|
+
collection: collectionDefinition.collection,
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
connection.on('connected', () => {
|
|
87
|
+
console.info(`- ${fullDbName} database has been connected`);
|
|
88
|
+
done();
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Adds collection definitions and connects to their respective databases
|
|
94
|
+
* @function addCollectionDefinitionByList
|
|
95
|
+
* @param {CollectionDefinitionListOption} options - Collection definition options
|
|
96
|
+
* @returns {Promise<void>} A promise that resolves when all collections are set up
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* await addCollectionDefinitionByList({
|
|
100
|
+
* list: [
|
|
101
|
+
* new CollectionDefinition({
|
|
102
|
+
* database: 'myapp',
|
|
103
|
+
* collection: 'users',
|
|
104
|
+
* schema: userSchema,
|
|
105
|
+
* permissions: [new Permission({ type: 'user_access', read: true })]
|
|
106
|
+
* })
|
|
107
|
+
* ],
|
|
108
|
+
* mongoOption: {
|
|
109
|
+
* mongoBaseAddress: 'mongodb://localhost:27017',
|
|
110
|
+
* dbPrefix: 'myapp_'
|
|
111
|
+
* }
|
|
112
|
+
* });
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
async function addCollectionDefinitionByList({ list, mongoOption, }) {
|
|
116
|
+
// Group collection definitions by database
|
|
117
|
+
const dbGroups = {};
|
|
118
|
+
list.forEach(collectionDefinition => {
|
|
119
|
+
if (!dbGroups[collectionDefinition.database]) {
|
|
120
|
+
dbGroups[collectionDefinition.database] = [];
|
|
121
|
+
}
|
|
122
|
+
dbGroups[collectionDefinition.database].push(collectionDefinition);
|
|
123
|
+
});
|
|
124
|
+
// Connect to each database
|
|
125
|
+
const connectionPromises = Object.entries(dbGroups).map(([dbName, collectionDefinitionList]) => connectToDatabaseByCollectionDefinitionList(dbName, collectionDefinitionList, mongoOption));
|
|
126
|
+
await Promise.all(connectionPromises);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Gets a Mongoose model for a specific collection
|
|
130
|
+
* @function getCollection
|
|
131
|
+
* @param {string} db - Database name
|
|
132
|
+
* @param {string} collection - Collection name
|
|
133
|
+
* @returns {Model<T>} Mongoose model for the collection
|
|
134
|
+
* @throws {Error} If the collection doesn't exist
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const userModel = getCollection('myapp', 'users');
|
|
138
|
+
* const users = await userModel.find();
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
function getCollection(db, collection) {
|
|
142
|
+
if (!collections[db] || !collections[db][collection]) {
|
|
143
|
+
throw new Error(`Collection ${collection} not found in database ${db}`);
|
|
144
|
+
}
|
|
145
|
+
return collections[db][collection];
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Gets the permission list for a specific operation on a collection
|
|
149
|
+
* @function _getPermissionList
|
|
150
|
+
* @param {string} db - Database name
|
|
151
|
+
* @param {string} collection - Collection name
|
|
152
|
+
* @param {string} operationType - Type of operation (read/write)
|
|
153
|
+
* @returns {any[]} List of permissions
|
|
154
|
+
* @private
|
|
155
|
+
*/
|
|
156
|
+
function _getPermissionList(db, collection, operationType) {
|
|
157
|
+
if (!permissionDefinitions[db] || !permissionDefinitions[db][collection]) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
return permissionDefinitions[db][collection].permissionList;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Checks if a user has access to perform an operation on a collection
|
|
164
|
+
* @function checkAccess
|
|
165
|
+
* @param {string} db - Database name
|
|
166
|
+
* @param {string} collection - Collection name
|
|
167
|
+
* @param {string} operationType - Type of operation (read/write)
|
|
168
|
+
* @param {Record<string, any>} queryOrDoc - Query or document being accessed
|
|
169
|
+
* @param {User} user - User performing the operation
|
|
170
|
+
* @returns {boolean} Whether the user has access
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const hasAccess = checkAccess('myapp', 'users', 'read', {}, currentUser);
|
|
174
|
+
* if (hasAccess) {
|
|
175
|
+
* const users = await getCollection('myapp', 'users').find();
|
|
176
|
+
* }
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
function checkAccess(db, collection, operationType, queryOrDoc, user) {
|
|
180
|
+
const permissionList = _getPermissionList(db, collection, operationType);
|
|
181
|
+
return permissionList.some(permission => {
|
|
182
|
+
if (permission.accessType === 'god_access')
|
|
183
|
+
return true;
|
|
184
|
+
if (permission.accessType === 'anonymous_access' && user.type === 'anonymous')
|
|
185
|
+
return true;
|
|
186
|
+
if (permission.accessType === 'user_access' && user.type === 'user')
|
|
187
|
+
return true;
|
|
188
|
+
return false;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Converts a string ID to a MongoDB ObjectId
|
|
193
|
+
* @function getAsID
|
|
194
|
+
* @param {string} strId - String ID to convert
|
|
195
|
+
* @returns {mongoose.Types.ObjectId | undefined} MongoDB ObjectId or undefined if invalid
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* const id = getAsID('507f1f77bcf86cd799439011');
|
|
199
|
+
* if (id) {
|
|
200
|
+
* const doc = await collection.findById(id);
|
|
201
|
+
* }
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
function getAsID(strId) {
|
|
205
|
+
try {
|
|
206
|
+
return mongoose_1.default.Types.ObjectId(strId);
|
|
207
|
+
}
|
|
208
|
+
catch (e) {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Applies populate options to a Mongoose query
|
|
214
|
+
* @function performPopulateToQueryObject
|
|
215
|
+
* @param {Query<T, any>} queryObj - Mongoose query object
|
|
216
|
+
* @param {PopulateOptions[]} [popArr=[]] - Array of populate options
|
|
217
|
+
* @returns {Query<T, any>} Query with populate options applied
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* const query = collection.find();
|
|
221
|
+
* const populatedQuery = performPopulateToQueryObject(query, [
|
|
222
|
+
* { path: 'author', select: 'name email' }
|
|
223
|
+
* ]);
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
function performPopulateToQueryObject(queryObj, popArr = []) {
|
|
227
|
+
popArr.forEach(pop => {
|
|
228
|
+
queryObj.populate(pop);
|
|
229
|
+
});
|
|
230
|
+
return queryObj;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Applies additional options to a Mongoose query
|
|
234
|
+
* @function performAdditionalOptionsToQueryObject
|
|
235
|
+
* @param {Query<T, any>} queryObj - Mongoose query object
|
|
236
|
+
* @param {Record<string, any>} options - Additional query options
|
|
237
|
+
* @returns {Query<T, any>} Query with additional options applied
|
|
238
|
+
* @example
|
|
239
|
+
* ```typescript
|
|
240
|
+
* const query = collection.find();
|
|
241
|
+
* const queryWithOptions = performAdditionalOptionsToQueryObject(query, {
|
|
242
|
+
* sort: { createdAt: -1 },
|
|
243
|
+
* limit: 10
|
|
244
|
+
* });
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
function performAdditionalOptionsToQueryObject(queryObj, options) {
|
|
248
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
249
|
+
// @ts-ignore
|
|
250
|
+
queryObj[key](value);
|
|
251
|
+
});
|
|
252
|
+
return queryObj;
|
|
253
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const mongoose_1 = __importDefault(require("mongoose"));
|
|
7
|
+
/**
|
|
8
|
+
* Type casting functions for MongoDB types
|
|
9
|
+
*/
|
|
10
|
+
const TypeCasters = {
|
|
11
|
+
ObjectId: mongoose_1.default.Types.ObjectId,
|
|
12
|
+
Date: (dateValue) => {
|
|
13
|
+
const strDate = dateValue.toString();
|
|
14
|
+
const mongoDateFormateInString = new Date(strDate).toISOString().split('T')[0];
|
|
15
|
+
return new Date(mongoDateFormateInString);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
exports.default = TypeCasters;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const db_schemas_1 = __importDefault(require("../../class/db_schemas"));
|
|
7
|
+
const collection_definition_1 = require("../../class/collection_definition");
|
|
8
|
+
const security_1 = require("../../class/security");
|
|
9
|
+
const config_1 = require("../../config");
|
|
10
|
+
module.exports = [
|
|
11
|
+
new collection_definition_1.CollectionDefinition({
|
|
12
|
+
database: 'cms',
|
|
13
|
+
collection: 'file',
|
|
14
|
+
schema: db_schemas_1.default.file,
|
|
15
|
+
permissions: [
|
|
16
|
+
new security_1.Permission({
|
|
17
|
+
accessType: security_1.PermissionTypes.upload_file_access,
|
|
18
|
+
read: true,
|
|
19
|
+
write: true,
|
|
20
|
+
onlyOwnData: false,
|
|
21
|
+
}),
|
|
22
|
+
new security_1.Permission({
|
|
23
|
+
accessType: security_1.PermissionTypes.remove_file_access,
|
|
24
|
+
read: true,
|
|
25
|
+
write: true,
|
|
26
|
+
onlyOwnData: false,
|
|
27
|
+
}),
|
|
28
|
+
],
|
|
29
|
+
triggers: config_1.config.fileTriggers || [],
|
|
30
|
+
}),
|
|
31
|
+
];
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.main = exports.name = void 0;
|
|
40
|
+
const koa_router_1 = __importDefault(require("koa-router"));
|
|
41
|
+
const validator_1 = require("../../class/validator");
|
|
42
|
+
const reply_1 = require("../../class/reply");
|
|
43
|
+
const security_1 = require("./../../class/security");
|
|
44
|
+
const DataService = __importStar(require("./../data_provider/service"));
|
|
45
|
+
const service_1 = require("./service");
|
|
46
|
+
const middleware = __importStar(require("../../middlewares"));
|
|
47
|
+
const name = 'file';
|
|
48
|
+
exports.name = name;
|
|
49
|
+
const fileRouter = new koa_router_1.default();
|
|
50
|
+
exports.main = fileRouter;
|
|
51
|
+
fileRouter.use('/', middleware.auth, async (ctx, next) => {
|
|
52
|
+
await next();
|
|
53
|
+
});
|
|
54
|
+
fileRouter.post('/', async (ctx) => {
|
|
55
|
+
const body = ctx.request.body;
|
|
56
|
+
// validate result
|
|
57
|
+
const bodyValidate = (0, validator_1.validateObject)(body, 'tag');
|
|
58
|
+
// fields validation
|
|
59
|
+
if (!bodyValidate.isValid) {
|
|
60
|
+
ctx.status = 412;
|
|
61
|
+
ctx.body = (0, reply_1.create)('e', { e: bodyValidate.requires });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
// Access validation
|
|
65
|
+
const hasAccess = DataService.checkAccess('cms', 'file', security_1.AccessTypes.write, body, ctx.state.user);
|
|
66
|
+
if (!hasAccess) {
|
|
67
|
+
ctx.throw(403, 'access denied');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const files = ctx.request.files;
|
|
71
|
+
const file = files && files.file;
|
|
72
|
+
let result;
|
|
73
|
+
if (!file) {
|
|
74
|
+
ctx.status = 412;
|
|
75
|
+
result = (0, reply_1.create)('f', { message: 'file field required' });
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
await service_1.main
|
|
79
|
+
.storeFile({
|
|
80
|
+
file: file,
|
|
81
|
+
ownerId: ctx.state.user.id,
|
|
82
|
+
tag: body.tag,
|
|
83
|
+
})
|
|
84
|
+
.then(file => {
|
|
85
|
+
result = (0, reply_1.create)('s', { file });
|
|
86
|
+
})
|
|
87
|
+
.catch(error => {
|
|
88
|
+
ctx.status = 412;
|
|
89
|
+
result = (0, reply_1.create)('e', error);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
ctx.body = result;
|
|
93
|
+
});
|
|
94
|
+
fileRouter.delete('/', async (ctx) => {
|
|
95
|
+
const body = ctx.request.query;
|
|
96
|
+
// validate
|
|
97
|
+
const bodyValidate = (0, validator_1.validateObject)(body, 'id');
|
|
98
|
+
let result;
|
|
99
|
+
if (!bodyValidate.isValid) {
|
|
100
|
+
ctx.status = 412;
|
|
101
|
+
result = (0, reply_1.create)('f', { message: 'some fields required.', error: bodyValidate.requires });
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
await service_1.main
|
|
105
|
+
.removeFile(body.id)
|
|
106
|
+
.then(() => {
|
|
107
|
+
result = (0, reply_1.create)('s');
|
|
108
|
+
})
|
|
109
|
+
.catch(e => {
|
|
110
|
+
ctx.status = 412;
|
|
111
|
+
result = (0, reply_1.create)('e', { error: e });
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
ctx.body = result;
|
|
115
|
+
});
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { IFile } from '../../class/db_schemas';
|
|
2
|
+
/**
|
|
3
|
+
* Service name constant
|
|
4
|
+
* @constant {string}
|
|
5
|
+
*/
|
|
6
|
+
export declare const name = "file";
|
|
7
|
+
/**
|
|
8
|
+
* File storage detail interface
|
|
9
|
+
* @interface StoredFileDetail
|
|
10
|
+
* @property {string} fileName - Generated unique filename
|
|
11
|
+
* @property {string} fullPath - Full path to the stored file
|
|
12
|
+
* @property {string} fileFormat - File format/extension
|
|
13
|
+
*/
|
|
14
|
+
interface StoredFileDetail {
|
|
15
|
+
fileName: string;
|
|
16
|
+
fullPath: string;
|
|
17
|
+
fileFormat: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* File upload options interface
|
|
21
|
+
* @interface StoreFileOptions
|
|
22
|
+
* @property {Object} file - File details
|
|
23
|
+
* @property {string} file.path - Temporary file path
|
|
24
|
+
* @property {string} file.type - MIME type of the file
|
|
25
|
+
* @property {string} file.name - Original filename
|
|
26
|
+
* @property {number} file.size - File size in bytes
|
|
27
|
+
* @property {string} ownerId - ID of the file owner
|
|
28
|
+
* @property {string} tag - Tag for file organization
|
|
29
|
+
* @property {boolean} [removeFileAfterStore=true] - Whether to remove the temporary file after storage
|
|
30
|
+
*/
|
|
31
|
+
interface StoreFileOptions {
|
|
32
|
+
file: {
|
|
33
|
+
path: string;
|
|
34
|
+
type: string;
|
|
35
|
+
name: string;
|
|
36
|
+
size: number;
|
|
37
|
+
};
|
|
38
|
+
ownerId: string;
|
|
39
|
+
tag: string;
|
|
40
|
+
removeFileAfterStore?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* File service for handling file storage and retrieval.
|
|
44
|
+
*
|
|
45
|
+
* This service provides functionality for storing, retrieving, and managing files.
|
|
46
|
+
* It handles file storage on disk and maintains file metadata in the database.
|
|
47
|
+
* Files are organized by format and tag in the upload directory.
|
|
48
|
+
*/
|
|
49
|
+
declare class FileService {
|
|
50
|
+
/**
|
|
51
|
+
* @hidden
|
|
52
|
+
*/
|
|
53
|
+
private directory;
|
|
54
|
+
/**
|
|
55
|
+
* @hidden
|
|
56
|
+
*/
|
|
57
|
+
static instance: FileService;
|
|
58
|
+
/**
|
|
59
|
+
* @hidden
|
|
60
|
+
*/
|
|
61
|
+
constructor();
|
|
62
|
+
/**
|
|
63
|
+
* @hidden
|
|
64
|
+
*
|
|
65
|
+
* Sets the upload directory for file storage
|
|
66
|
+
* @param {string} directory - Directory path for file storage
|
|
67
|
+
* @throws {Error} If directory is invalid or not writable
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* import { fileService } from '@modular-rest/server';
|
|
71
|
+
*
|
|
72
|
+
* fileService.setUploadDirectory('/path/to/uploads');
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
setUploadDirectory(directory: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* @hidden
|
|
78
|
+
*
|
|
79
|
+
* Creates stored file details with unique filename
|
|
80
|
+
* @param {string} fileType - MIME type of the file
|
|
81
|
+
* @param {string} tag - Tag for file organization
|
|
82
|
+
* @returns {StoredFileDetail} Storage details including filename and path
|
|
83
|
+
* @throws {Error} If upload directory is not set
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* import { fileService } from '@modular-rest/server';
|
|
88
|
+
*
|
|
89
|
+
* const details = fileService.createStoredDetail('image/jpeg', 'profile');
|
|
90
|
+
* // Returns: { fileName: '1234567890.jpeg', fullPath: '/uploads/jpeg/profile/1234567890.jpeg', fileFormat: 'jpeg' }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
createStoredDetail(fileType: string, tag: string): StoredFileDetail;
|
|
94
|
+
/**
|
|
95
|
+
* @hidden
|
|
96
|
+
*
|
|
97
|
+
* Stores a file, removes the temporary file, and saves metadata to database
|
|
98
|
+
* @param {StoreFileOptions} options - File storage options
|
|
99
|
+
* @returns {Promise<IFile>} Promise resolving to stored file document
|
|
100
|
+
* @throws {Error} If upload directory is not set or storage fails
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* import { fileService } from '@modular-rest/server';
|
|
104
|
+
*
|
|
105
|
+
* const file = await fileService.storeFile({
|
|
106
|
+
* file: {
|
|
107
|
+
* path: '/tmp/upload.jpg',
|
|
108
|
+
* type: 'image/jpeg',
|
|
109
|
+
* name: 'profile.jpg',
|
|
110
|
+
* size: 1024
|
|
111
|
+
* },
|
|
112
|
+
* ownerId: 'user123',
|
|
113
|
+
* tag: 'profile',
|
|
114
|
+
* removeFileAfterStore: true
|
|
115
|
+
* });
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
storeFile({ file, ownerId, tag, removeFileAfterStore }: StoreFileOptions): Promise<IFile>;
|
|
119
|
+
/**
|
|
120
|
+
* @hidden
|
|
121
|
+
*
|
|
122
|
+
* Removes a file from the disk
|
|
123
|
+
* @param {string} path - File path to remove
|
|
124
|
+
* @returns {Promise<void>} Promise resolving when file is removed
|
|
125
|
+
* @throws {Error} If file removal fails
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* import { fileService } from '@modular-rest/server';
|
|
129
|
+
*
|
|
130
|
+
* await fileService.removeFromDisc('/uploads/jpeg/profile/1234567890.jpeg');
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
removeFromDisc(path: string): Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Removes a file from both database and disk
|
|
136
|
+
*
|
|
137
|
+
* @param {string} fileId - File ID to remove
|
|
138
|
+
* @returns {Promise<void>} Promise resolving when file is removed
|
|
139
|
+
* @throws {Error} If file is not found or removal fails
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* import { fileService } from '@modular-rest/server';
|
|
143
|
+
*
|
|
144
|
+
* try {
|
|
145
|
+
* await fileService.removeFile('file123');
|
|
146
|
+
* console.log('File removed successfully');
|
|
147
|
+
* } catch (error) {
|
|
148
|
+
* console.error('Failed to remove file:', error);
|
|
149
|
+
* }
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
removeFile(fileId: string): Promise<void>;
|
|
153
|
+
/**
|
|
154
|
+
* Retrieves a file document from the database
|
|
155
|
+
*
|
|
156
|
+
* @param {string} fileId - File ID to retrieve
|
|
157
|
+
* @returns {Promise<IFile>} Promise resolving to file document
|
|
158
|
+
* @throws {Error} If collection model is not found or file is not found
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* import { fileService } from '@modular-rest/server';
|
|
162
|
+
*
|
|
163
|
+
* const fileDoc = await fileService.getFile('file123');
|
|
164
|
+
* console.log('File details:', fileDoc);
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
getFile(fileId: string): Promise<IFile>;
|
|
168
|
+
/**
|
|
169
|
+
* Retrieves the public URL link for a file
|
|
170
|
+
*
|
|
171
|
+
* @param {string} fileId - File ID to get link for
|
|
172
|
+
* @returns {Promise<string>} Promise resolving to file URL
|
|
173
|
+
* @throws {Error} If static path root is not defined or file is not found
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* import { fileService } from '@modular-rest/server';
|
|
177
|
+
*
|
|
178
|
+
* const link = await fileService.getFileLink('file123');
|
|
179
|
+
* // Returns: '/static/jpeg/profile/1234567890.jpeg'
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
getFileLink(fileId: string): Promise<string>;
|
|
183
|
+
/**
|
|
184
|
+
* Gets the full filesystem path for a file
|
|
185
|
+
*
|
|
186
|
+
* @param {string} fileId - File ID to get path for
|
|
187
|
+
* @returns {Promise<string>} Promise resolving to full file path
|
|
188
|
+
* @throws {Error} If upload directory is not set or file is not found
|
|
189
|
+
* @example
|
|
190
|
+
* ```typescript
|
|
191
|
+
* import { fileService } from '@modular-rest/server';
|
|
192
|
+
*
|
|
193
|
+
* const path = await fileService.getFilePath('file123');
|
|
194
|
+
* // Returns: '/uploads/jpeg/profile/1234567890.jpeg'
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
getFilePath(fileId: string): Promise<string>;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Main file service instance
|
|
201
|
+
* @constant {FileService}
|
|
202
|
+
*/
|
|
203
|
+
export declare const main: FileService;
|
|
204
|
+
export {};
|