@ruiapp/rapid-core 0.9.7 → 0.10.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/dist/bootstrapApplicationConfig.d.ts +51 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +276 -50
- package/dist/plugins/auth/services/AuthService.d.ts +7 -1
- package/dist/utilities/fsUtility.d.ts +8 -0
- package/package.json +1 -1
- package/src/bootstrapApplicationConfig.ts +108 -0
- package/src/index.ts +1 -0
- package/src/plugins/auth/AuthPlugin.ts +5 -1
- package/src/plugins/auth/actionHandlers/getMyProfile.ts +3 -13
- package/src/plugins/auth/services/AuthService.ts +29 -2
- package/src/plugins/fileManage/actionHandlers/uploadFile.ts +2 -2
- package/src/plugins/metaManage/services/MetaService.ts +4 -4
- package/src/utilities/fsUtility.ts +76 -0
|
@@ -435,6 +435,57 @@ declare const _default: {
|
|
|
435
435
|
description?: undefined;
|
|
436
436
|
})[];
|
|
437
437
|
indexes?: undefined;
|
|
438
|
+
} | {
|
|
439
|
+
maintainedBy: string;
|
|
440
|
+
namespace: string;
|
|
441
|
+
name: string;
|
|
442
|
+
code: string;
|
|
443
|
+
singularCode: string;
|
|
444
|
+
pluralCode: string;
|
|
445
|
+
schema: string;
|
|
446
|
+
tableName: string;
|
|
447
|
+
properties: ({
|
|
448
|
+
name: string;
|
|
449
|
+
code: string;
|
|
450
|
+
columnName: string;
|
|
451
|
+
type: "integer";
|
|
452
|
+
required: true;
|
|
453
|
+
autoIncrement: true;
|
|
454
|
+
} | {
|
|
455
|
+
name: string;
|
|
456
|
+
code: string;
|
|
457
|
+
columnName: string;
|
|
458
|
+
type: "text";
|
|
459
|
+
required: true;
|
|
460
|
+
autoIncrement?: undefined;
|
|
461
|
+
} | {
|
|
462
|
+
name: string;
|
|
463
|
+
code: string;
|
|
464
|
+
columnName: string;
|
|
465
|
+
type: "text";
|
|
466
|
+
required: false;
|
|
467
|
+
autoIncrement?: undefined;
|
|
468
|
+
} | {
|
|
469
|
+
name: string;
|
|
470
|
+
code: string;
|
|
471
|
+
columnName: string;
|
|
472
|
+
type: "json";
|
|
473
|
+
required: false;
|
|
474
|
+
autoIncrement?: undefined;
|
|
475
|
+
})[];
|
|
476
|
+
indexes: ({
|
|
477
|
+
name: string;
|
|
478
|
+
properties: {
|
|
479
|
+
code: string;
|
|
480
|
+
}[];
|
|
481
|
+
unique: true;
|
|
482
|
+
} | {
|
|
483
|
+
name: string;
|
|
484
|
+
properties: {
|
|
485
|
+
code: string;
|
|
486
|
+
}[];
|
|
487
|
+
unique?: undefined;
|
|
488
|
+
})[];
|
|
438
489
|
})[];
|
|
439
490
|
dataDictionaries: any[];
|
|
440
491
|
routes: {
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { default as EntityManager } from "./dataAccess/entityManager";
|
|
|
13
13
|
export * from "./dataAccess/entityManager";
|
|
14
14
|
export * from "./utilities/accessControlUtility";
|
|
15
15
|
export * from "./utilities/entityUtility";
|
|
16
|
+
export * from "./utilities/fsUtility";
|
|
16
17
|
export * from "./utilities/jwtUtility";
|
|
17
18
|
export * from "./utilities/timeUtility";
|
|
18
19
|
export * from "./utilities/passwordUtility";
|
package/dist/index.js
CHANGED
|
@@ -7,11 +7,11 @@ var events = require('events');
|
|
|
7
7
|
var Router = require('koa-tree-router');
|
|
8
8
|
var qs = require('qs');
|
|
9
9
|
var dayjs = require('dayjs');
|
|
10
|
+
var fs = require('fs');
|
|
11
|
+
var path = require('path');
|
|
10
12
|
var jsonwebtoken = require('jsonwebtoken');
|
|
11
13
|
var crypto = require('crypto');
|
|
12
14
|
var bcrypt = require('bcryptjs');
|
|
13
|
-
var path = require('path');
|
|
14
|
-
var fs = require('fs');
|
|
15
15
|
var uuid = require('uuid');
|
|
16
16
|
var nodemailer = require('nodemailer');
|
|
17
17
|
var cron = require('cron');
|
|
@@ -22,10 +22,10 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
22
22
|
var Router__default = /*#__PURE__*/_interopDefaultLegacy(Router);
|
|
23
23
|
var qs__default = /*#__PURE__*/_interopDefaultLegacy(qs);
|
|
24
24
|
var dayjs__default = /*#__PURE__*/_interopDefaultLegacy(dayjs);
|
|
25
|
+
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
26
|
+
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
25
27
|
var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
|
|
26
28
|
var bcrypt__default = /*#__PURE__*/_interopDefaultLegacy(bcrypt);
|
|
27
|
-
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
28
|
-
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
29
29
|
var nodemailer__default = /*#__PURE__*/_interopDefaultLegacy(nodemailer);
|
|
30
30
|
|
|
31
31
|
function fixBigIntJSONSerialize() {
|
|
@@ -1968,6 +1968,114 @@ var bootstrapApplicationConfig = {
|
|
|
1968
1968
|
},
|
|
1969
1969
|
],
|
|
1970
1970
|
},
|
|
1971
|
+
{
|
|
1972
|
+
maintainedBy: "metaManager",
|
|
1973
|
+
namespace: "meta",
|
|
1974
|
+
name: "page",
|
|
1975
|
+
code: "Page",
|
|
1976
|
+
singularCode: "page",
|
|
1977
|
+
pluralCode: "pages",
|
|
1978
|
+
schema: "public",
|
|
1979
|
+
tableName: "meta_pages",
|
|
1980
|
+
properties: [
|
|
1981
|
+
{
|
|
1982
|
+
name: "id",
|
|
1983
|
+
code: "id",
|
|
1984
|
+
columnName: "id",
|
|
1985
|
+
type: "integer",
|
|
1986
|
+
required: true,
|
|
1987
|
+
autoIncrement: true,
|
|
1988
|
+
},
|
|
1989
|
+
{
|
|
1990
|
+
name: "code",
|
|
1991
|
+
code: "code",
|
|
1992
|
+
columnName: "code",
|
|
1993
|
+
type: "text",
|
|
1994
|
+
required: true,
|
|
1995
|
+
},
|
|
1996
|
+
{
|
|
1997
|
+
name: "parentCode",
|
|
1998
|
+
code: "parentCode",
|
|
1999
|
+
columnName: "parent_code",
|
|
2000
|
+
type: "text",
|
|
2001
|
+
required: false,
|
|
2002
|
+
},
|
|
2003
|
+
{
|
|
2004
|
+
name: "subSystem",
|
|
2005
|
+
code: "subSystem",
|
|
2006
|
+
columnName: "sub_system",
|
|
2007
|
+
type: "text",
|
|
2008
|
+
required: false,
|
|
2009
|
+
},
|
|
2010
|
+
{
|
|
2011
|
+
name: "appCode",
|
|
2012
|
+
code: "appCode",
|
|
2013
|
+
columnName: "app_code",
|
|
2014
|
+
type: "text",
|
|
2015
|
+
required: false,
|
|
2016
|
+
},
|
|
2017
|
+
{
|
|
2018
|
+
name: "routePath",
|
|
2019
|
+
code: "routePath",
|
|
2020
|
+
columnName: "route_path",
|
|
2021
|
+
type: "text",
|
|
2022
|
+
required: false,
|
|
2023
|
+
},
|
|
2024
|
+
{
|
|
2025
|
+
name: "name",
|
|
2026
|
+
code: "name",
|
|
2027
|
+
columnName: "name",
|
|
2028
|
+
type: "text",
|
|
2029
|
+
required: false,
|
|
2030
|
+
},
|
|
2031
|
+
{
|
|
2032
|
+
name: "title",
|
|
2033
|
+
code: "title",
|
|
2034
|
+
columnName: "title",
|
|
2035
|
+
type: "text",
|
|
2036
|
+
required: false,
|
|
2037
|
+
},
|
|
2038
|
+
{
|
|
2039
|
+
name: "config",
|
|
2040
|
+
code: "config",
|
|
2041
|
+
columnName: "config",
|
|
2042
|
+
type: "json",
|
|
2043
|
+
required: false,
|
|
2044
|
+
},
|
|
2045
|
+
{
|
|
2046
|
+
name: "permissionCheck",
|
|
2047
|
+
code: "permissionCheck",
|
|
2048
|
+
columnName: "permission_check",
|
|
2049
|
+
type: "json",
|
|
2050
|
+
required: false,
|
|
2051
|
+
},
|
|
2052
|
+
],
|
|
2053
|
+
indexes: [
|
|
2054
|
+
{
|
|
2055
|
+
name: "meta_pages_code_uindex",
|
|
2056
|
+
properties: [
|
|
2057
|
+
{
|
|
2058
|
+
code: "code",
|
|
2059
|
+
},
|
|
2060
|
+
],
|
|
2061
|
+
unique: true,
|
|
2062
|
+
},
|
|
2063
|
+
{
|
|
2064
|
+
name: "meta_pages_subsystem_appcode_code_idx",
|
|
2065
|
+
properties: [
|
|
2066
|
+
{
|
|
2067
|
+
code: "subSystem",
|
|
2068
|
+
},
|
|
2069
|
+
{
|
|
2070
|
+
code: "appCode",
|
|
2071
|
+
},
|
|
2072
|
+
{
|
|
2073
|
+
code: "code",
|
|
2074
|
+
},
|
|
2075
|
+
],
|
|
2076
|
+
},
|
|
2077
|
+
],
|
|
2078
|
+
},
|
|
1971
2079
|
],
|
|
1972
2080
|
dataDictionaries: [],
|
|
1973
2081
|
routes: [
|
|
@@ -4941,6 +5049,128 @@ function getEntityRelationTargetId(entity, propName, targetColumnName) {
|
|
|
4941
5049
|
}
|
|
4942
5050
|
}
|
|
4943
5051
|
|
|
5052
|
+
async function readFile(path) {
|
|
5053
|
+
return new Promise((resolve, reject) => {
|
|
5054
|
+
fs__default["default"].readFile(path, null, (err, data) => {
|
|
5055
|
+
if (err) {
|
|
5056
|
+
reject(err);
|
|
5057
|
+
}
|
|
5058
|
+
else {
|
|
5059
|
+
resolve(data);
|
|
5060
|
+
}
|
|
5061
|
+
});
|
|
5062
|
+
});
|
|
5063
|
+
}
|
|
5064
|
+
async function copyFile(fromPath, toPath) {
|
|
5065
|
+
return new Promise((resolve, reject) => {
|
|
5066
|
+
fs__default["default"].copyFile(fromPath, toPath, (err) => {
|
|
5067
|
+
if (err) {
|
|
5068
|
+
reject(err);
|
|
5069
|
+
}
|
|
5070
|
+
else {
|
|
5071
|
+
resolve();
|
|
5072
|
+
}
|
|
5073
|
+
});
|
|
5074
|
+
});
|
|
5075
|
+
}
|
|
5076
|
+
async function removeFile(path) {
|
|
5077
|
+
return new Promise((resolve, reject) => {
|
|
5078
|
+
fs__default["default"].rm(path, (err) => {
|
|
5079
|
+
if (err) {
|
|
5080
|
+
reject(err);
|
|
5081
|
+
}
|
|
5082
|
+
else {
|
|
5083
|
+
resolve();
|
|
5084
|
+
}
|
|
5085
|
+
});
|
|
5086
|
+
});
|
|
5087
|
+
}
|
|
5088
|
+
async function moveFile(fromPath, toPath) {
|
|
5089
|
+
return new Promise((resolve, reject) => {
|
|
5090
|
+
fs__default["default"].rename(fromPath, toPath, (err) => {
|
|
5091
|
+
if (err) {
|
|
5092
|
+
reject(err);
|
|
5093
|
+
}
|
|
5094
|
+
else {
|
|
5095
|
+
resolve();
|
|
5096
|
+
}
|
|
5097
|
+
});
|
|
5098
|
+
});
|
|
5099
|
+
}
|
|
5100
|
+
async function appendFile(path, data) {
|
|
5101
|
+
return new Promise((resolve, reject) => {
|
|
5102
|
+
fs__default["default"].appendFile(path, Buffer.from(data), (err) => {
|
|
5103
|
+
if (err) {
|
|
5104
|
+
reject(err);
|
|
5105
|
+
}
|
|
5106
|
+
else {
|
|
5107
|
+
resolve();
|
|
5108
|
+
}
|
|
5109
|
+
});
|
|
5110
|
+
});
|
|
5111
|
+
}
|
|
5112
|
+
async function writeFile(path, data) {
|
|
5113
|
+
return new Promise((resolve, reject) => {
|
|
5114
|
+
fs__default["default"].writeFile(path, Buffer.from(data), (err) => {
|
|
5115
|
+
if (err) {
|
|
5116
|
+
reject(err);
|
|
5117
|
+
}
|
|
5118
|
+
else {
|
|
5119
|
+
resolve();
|
|
5120
|
+
}
|
|
5121
|
+
});
|
|
5122
|
+
});
|
|
5123
|
+
}
|
|
5124
|
+
function ensureDirectoryExists(dirPath) {
|
|
5125
|
+
if (!fs__default["default"].existsSync(dirPath)) {
|
|
5126
|
+
const parentDirPath = path__default["default"].dirname(dirPath);
|
|
5127
|
+
if (parentDirPath == dirPath) {
|
|
5128
|
+
return;
|
|
5129
|
+
}
|
|
5130
|
+
ensureDirectoryExists(parentDirPath);
|
|
5131
|
+
fs__default["default"].mkdirSync(dirPath);
|
|
5132
|
+
}
|
|
5133
|
+
}
|
|
5134
|
+
function enumFileBaseNamesInDirectory(options) {
|
|
5135
|
+
const { dirPath, prefix, fileNameFilter } = options;
|
|
5136
|
+
let fileNames = [];
|
|
5137
|
+
let resolvedDirPath = dirPath;
|
|
5138
|
+
const isRelative = dirPath.startsWith(".") || dirPath.startsWith("..");
|
|
5139
|
+
if (isRelative) {
|
|
5140
|
+
resolvedDirPath = path__default["default"].join(process.cwd(), dirPath);
|
|
5141
|
+
}
|
|
5142
|
+
if (!fs__default["default"].existsSync(resolvedDirPath)) {
|
|
5143
|
+
console.warn(`Directory '${resolvedDirPath}' not found.`);
|
|
5144
|
+
return [];
|
|
5145
|
+
}
|
|
5146
|
+
const files = fs__default["default"].readdirSync(resolvedDirPath);
|
|
5147
|
+
for (const fileName of files) {
|
|
5148
|
+
const filePathName = path__default["default"].join(resolvedDirPath, fileName);
|
|
5149
|
+
const fileStat = fs__default["default"].statSync(filePathName);
|
|
5150
|
+
if (fileStat.isDirectory()) {
|
|
5151
|
+
fileNames = fileNames.concat(enumFileBaseNamesInDirectory({
|
|
5152
|
+
dirPath: filePathName,
|
|
5153
|
+
prefix: prefix ? `${prefix}/${fileName}` : fileName,
|
|
5154
|
+
fileNameFilter,
|
|
5155
|
+
}));
|
|
5156
|
+
}
|
|
5157
|
+
else if (fileStat.isFile()) {
|
|
5158
|
+
if (fileNameFilter && !fileNameFilter(fileName)) {
|
|
5159
|
+
continue;
|
|
5160
|
+
}
|
|
5161
|
+
const baseName = path__default["default"].parse(fileName).name;
|
|
5162
|
+
if (prefix) {
|
|
5163
|
+
fileNames.push(`${prefix}/${baseName}`);
|
|
5164
|
+
}
|
|
5165
|
+
else {
|
|
5166
|
+
fileNames.push(baseName);
|
|
5167
|
+
}
|
|
5168
|
+
}
|
|
5169
|
+
}
|
|
5170
|
+
fileNames.sort();
|
|
5171
|
+
return fileNames;
|
|
5172
|
+
}
|
|
5173
|
+
|
|
4944
5174
|
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
|
4945
5175
|
// This module is browser compatible.
|
|
4946
5176
|
/**
|
|
@@ -5460,7 +5690,7 @@ class MetaService {
|
|
|
5460
5690
|
const tablesInDb = await server.queryDatabaseObject(sqlQueryTableInformations);
|
|
5461
5691
|
const { queryBuilder } = server;
|
|
5462
5692
|
for (const model of applicationConfig.models) {
|
|
5463
|
-
logger.
|
|
5693
|
+
logger.info(`Checking data table for '${model.namespace}.${model.singularCode}'...`);
|
|
5464
5694
|
const expectedTableSchema = model.schema || server.databaseConfig.dbDefaultSchema;
|
|
5465
5695
|
const expectedTableName = model.tableName;
|
|
5466
5696
|
const tableInDb = lodash.find(tablesInDb, { table_schema: expectedTableSchema, table_name: expectedTableName });
|
|
@@ -5477,7 +5707,7 @@ class MetaService {
|
|
|
5477
5707
|
LEFT JOIN pg_catalog.pg_description d ON (d.objoid = st.relid and d.objsubid = c.ordinal_position);`;
|
|
5478
5708
|
const columnsInDb = await server.queryDatabaseObject(sqlQueryColumnInformations, []);
|
|
5479
5709
|
for (const model of applicationConfig.models) {
|
|
5480
|
-
logger.
|
|
5710
|
+
logger.info(`Checking data columns for '${model.namespace}.${model.singularCode}'...`);
|
|
5481
5711
|
for (const property of model.properties) {
|
|
5482
5712
|
let columnDDL = "";
|
|
5483
5713
|
if (isRelationProperty(property)) {
|
|
@@ -5618,7 +5848,7 @@ class MetaService {
|
|
|
5618
5848
|
const expectedTableSchema = model.schema || server.databaseConfig.dbDefaultSchema;
|
|
5619
5849
|
const expectedTableName = model.tableName;
|
|
5620
5850
|
const expectedContraintName = `${expectedTableName}_pk`;
|
|
5621
|
-
logger.
|
|
5851
|
+
logger.info(`Checking pk for '${expectedTableSchema}.${expectedTableName}'...`);
|
|
5622
5852
|
const constraintInDb = lodash.find(constraintsInDb, {
|
|
5623
5853
|
table_schema: expectedTableSchema,
|
|
5624
5854
|
table_name: expectedTableName,
|
|
@@ -5634,7 +5864,7 @@ class MetaService {
|
|
|
5634
5864
|
if (!model.indexes || !model.indexes.length) {
|
|
5635
5865
|
continue;
|
|
5636
5866
|
}
|
|
5637
|
-
logger.
|
|
5867
|
+
logger.info(`Creating indexes of table ${queryBuilder.quoteTable(model)}`);
|
|
5638
5868
|
for (const index of model.indexes) {
|
|
5639
5869
|
const sqlCreateIndex = generateTableIndexDDL(queryBuilder, server, model, index);
|
|
5640
5870
|
try {
|
|
@@ -7094,19 +7324,8 @@ async function handler$c(plugin, ctx, options) {
|
|
|
7094
7324
|
};
|
|
7095
7325
|
return;
|
|
7096
7326
|
}
|
|
7097
|
-
const
|
|
7098
|
-
const
|
|
7099
|
-
const entityManager = server.getEntityManager(userEntitySingularCode);
|
|
7100
|
-
const user = await entityManager.findEntity({
|
|
7101
|
-
filters: [
|
|
7102
|
-
{
|
|
7103
|
-
operator: "eq",
|
|
7104
|
-
field: "id",
|
|
7105
|
-
value: userId,
|
|
7106
|
-
},
|
|
7107
|
-
],
|
|
7108
|
-
properties: profilePropertyCodes,
|
|
7109
|
-
});
|
|
7327
|
+
const authService = server.getService("authService");
|
|
7328
|
+
const user = await authService.getProfileOfUser(userId);
|
|
7110
7329
|
ctx.output = {
|
|
7111
7330
|
user,
|
|
7112
7331
|
};
|
|
@@ -7285,9 +7504,13 @@ var pluginRoutes$7 = [changePassword, getMyProfile$1, resetPassword, signin$1, s
|
|
|
7285
7504
|
class AuthService {
|
|
7286
7505
|
#server;
|
|
7287
7506
|
#jwtKey;
|
|
7288
|
-
|
|
7507
|
+
#userEntitySingularCode;
|
|
7508
|
+
#profilePropertyCodes;
|
|
7509
|
+
constructor(server, options) {
|
|
7289
7510
|
this.#server = server;
|
|
7290
|
-
this.#jwtKey = jwtKey;
|
|
7511
|
+
this.#jwtKey = options.jwtKey;
|
|
7512
|
+
this.#userEntitySingularCode = options.userEntitySingularCode;
|
|
7513
|
+
this.#profilePropertyCodes = options.profilePropertyCodes;
|
|
7291
7514
|
}
|
|
7292
7515
|
createUserAccessToken(options) {
|
|
7293
7516
|
const secretKey = Buffer.from(this.#jwtKey, "base64");
|
|
@@ -7300,6 +7523,22 @@ class AuthService {
|
|
|
7300
7523
|
}, secretKey);
|
|
7301
7524
|
return token;
|
|
7302
7525
|
}
|
|
7526
|
+
async getProfileOfUser(userId) {
|
|
7527
|
+
const userEntitySingularCode = this.#userEntitySingularCode || "oc_user";
|
|
7528
|
+
const profilePropertyCodes = this.#profilePropertyCodes || ["id", "name", "login", "email", "department", "roles", "state", "createdAt"];
|
|
7529
|
+
const entityManager = this.#server.getEntityManager(userEntitySingularCode);
|
|
7530
|
+
const user = await entityManager.findEntity({
|
|
7531
|
+
filters: [
|
|
7532
|
+
{
|
|
7533
|
+
operator: "eq",
|
|
7534
|
+
field: "id",
|
|
7535
|
+
value: userId,
|
|
7536
|
+
},
|
|
7537
|
+
],
|
|
7538
|
+
properties: profilePropertyCodes,
|
|
7539
|
+
});
|
|
7540
|
+
return user;
|
|
7541
|
+
}
|
|
7303
7542
|
}
|
|
7304
7543
|
|
|
7305
7544
|
/**
|
|
@@ -7338,7 +7577,11 @@ class AuthPlugin {
|
|
|
7338
7577
|
server.appendApplicationConfig({ models: pluginModels$6 });
|
|
7339
7578
|
}
|
|
7340
7579
|
async configureServices(server, applicationConfig) {
|
|
7341
|
-
this.#authService = new AuthService(server,
|
|
7580
|
+
this.#authService = new AuthService(server, {
|
|
7581
|
+
jwtKey: server.config.jwtKey,
|
|
7582
|
+
userEntitySingularCode: this.#options.userEntitySingularCode,
|
|
7583
|
+
profilePropertyCodes: this.#options.profilePropertyCodes,
|
|
7584
|
+
});
|
|
7342
7585
|
server.registerService("authService", this.#authService);
|
|
7343
7586
|
}
|
|
7344
7587
|
async configureRoutes(server, applicationConfig) {
|
|
@@ -7373,31 +7616,6 @@ class AuthPlugin {
|
|
|
7373
7616
|
}
|
|
7374
7617
|
}
|
|
7375
7618
|
|
|
7376
|
-
async function readFile(path) {
|
|
7377
|
-
return new Promise((resolve, reject) => {
|
|
7378
|
-
fs__default["default"].readFile(path, null, (err, data) => {
|
|
7379
|
-
if (err) {
|
|
7380
|
-
reject(err);
|
|
7381
|
-
}
|
|
7382
|
-
else {
|
|
7383
|
-
resolve(data);
|
|
7384
|
-
}
|
|
7385
|
-
});
|
|
7386
|
-
});
|
|
7387
|
-
}
|
|
7388
|
-
async function appendFile(path, data) {
|
|
7389
|
-
return new Promise((resolve, reject) => {
|
|
7390
|
-
fs__default["default"].appendFile(path, Buffer.from(data), (err) => {
|
|
7391
|
-
if (err) {
|
|
7392
|
-
reject(err);
|
|
7393
|
-
}
|
|
7394
|
-
else {
|
|
7395
|
-
resolve();
|
|
7396
|
-
}
|
|
7397
|
-
});
|
|
7398
|
-
});
|
|
7399
|
-
}
|
|
7400
|
-
|
|
7401
7619
|
function getFileBaseName(pathname) {
|
|
7402
7620
|
const extName = path__default["default"].extname(pathname);
|
|
7403
7621
|
return path__default["default"].basename(pathname, extName);
|
|
@@ -7511,7 +7729,7 @@ async function handler$8(plugin, ctx, options) {
|
|
|
7511
7729
|
const fileKey = `${uuid.v1()}${extName}`;
|
|
7512
7730
|
const filePathName = path__default["default"].join(server.config.localFileStoragePath, fileKey);
|
|
7513
7731
|
const fileBuffer = await file.arrayBuffer();
|
|
7514
|
-
await
|
|
7732
|
+
await writeFile(filePathName, fileBuffer);
|
|
7515
7733
|
ctx.output = { ok: true, fileKey };
|
|
7516
7734
|
}
|
|
7517
7735
|
|
|
@@ -9706,12 +9924,16 @@ exports.ServerOperationPlugin = ServerOperationPlugin;
|
|
|
9706
9924
|
exports.SettingPlugin = SettingPlugin;
|
|
9707
9925
|
exports.StateMachinePlugin = StateMachinePlugin;
|
|
9708
9926
|
exports.WebhooksPlugin = WebhooksPlugin;
|
|
9927
|
+
exports.appendFile = appendFile;
|
|
9709
9928
|
exports.bootstrapApplicationConfig = bootstrapApplicationConfig$1;
|
|
9929
|
+
exports.copyFile = copyFile;
|
|
9710
9930
|
exports.createJwt = createJwt;
|
|
9711
9931
|
exports.decodeJwt = decodeJwt;
|
|
9712
9932
|
exports.deleteCookie = deleteCookie;
|
|
9713
9933
|
exports.detectChangedFieldsOfEntity = detectChangedFieldsOfEntity;
|
|
9934
|
+
exports.ensureDirectoryExists = ensureDirectoryExists;
|
|
9714
9935
|
exports.entityHelper = entityHelper;
|
|
9936
|
+
exports.enumFileBaseNamesInDirectory = enumFileBaseNamesInDirectory;
|
|
9715
9937
|
exports.formatDateTimeWithTimezone = formatDateTimeWithTimezone;
|
|
9716
9938
|
exports.generateJwtSecretKey = generateJwtSecretKey;
|
|
9717
9939
|
exports.generatePasswordHash = generatePasswordHash;
|
|
@@ -9725,8 +9947,12 @@ exports.isAccessAllowed = isAccessAllowed;
|
|
|
9725
9947
|
exports.licenseHelper = licenseHelper;
|
|
9726
9948
|
exports.mapDbRowToEntity = mapDbRowToEntity;
|
|
9727
9949
|
exports.metaHelper = metaHelper;
|
|
9950
|
+
exports.moveFile = moveFile;
|
|
9951
|
+
exports.readFile = readFile;
|
|
9952
|
+
exports.removeFile = removeFile;
|
|
9728
9953
|
exports.setCookie = setCookie;
|
|
9729
9954
|
exports.tryValidateLicense = tryValidateLicense;
|
|
9730
9955
|
exports.validateLicense = validateLicense;
|
|
9731
9956
|
exports.validatePassword = validatePassword;
|
|
9732
9957
|
exports.verifyJwt = verifyJwt;
|
|
9958
|
+
exports.writeFile = writeFile;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { IRpdServer } from "../../../core/server";
|
|
2
|
+
export type AuthServiceOptions = {
|
|
3
|
+
jwtKey: string;
|
|
4
|
+
userEntitySingularCode?: string;
|
|
5
|
+
profilePropertyCodes?: string[];
|
|
6
|
+
};
|
|
2
7
|
export interface UserAccessToken {
|
|
3
8
|
sub: "userAccessToken";
|
|
4
9
|
aud: string;
|
|
@@ -10,6 +15,7 @@ export interface CreateUserAccessTokenOptions {
|
|
|
10
15
|
}
|
|
11
16
|
export default class AuthService {
|
|
12
17
|
#private;
|
|
13
|
-
constructor(server: IRpdServer,
|
|
18
|
+
constructor(server: IRpdServer, options: AuthServiceOptions);
|
|
14
19
|
createUserAccessToken(options: CreateUserAccessTokenOptions): string;
|
|
20
|
+
getProfileOfUser(userId: number): Promise<any>;
|
|
15
21
|
}
|
|
@@ -4,3 +4,11 @@ export declare function copyFile(fromPath: string, toPath: string): Promise<void
|
|
|
4
4
|
export declare function removeFile(path: string): Promise<void>;
|
|
5
5
|
export declare function moveFile(fromPath: string, toPath: string): Promise<void>;
|
|
6
6
|
export declare function appendFile(path: string, data: ArrayBuffer): Promise<void>;
|
|
7
|
+
export declare function writeFile(path: string, data: ArrayBuffer): Promise<void>;
|
|
8
|
+
export declare function ensureDirectoryExists(dirPath: string): void;
|
|
9
|
+
export type EnumFileBaseNamesOptions = {
|
|
10
|
+
dirPath: string;
|
|
11
|
+
prefix?: string;
|
|
12
|
+
fileNameFilter?: (fileName: string) => boolean;
|
|
13
|
+
};
|
|
14
|
+
export declare function enumFileBaseNamesInDirectory(options: EnumFileBaseNamesOptions): string[];
|
package/package.json
CHANGED
|
@@ -736,6 +736,114 @@ export default {
|
|
|
736
736
|
},
|
|
737
737
|
],
|
|
738
738
|
},
|
|
739
|
+
{
|
|
740
|
+
maintainedBy: "metaManager",
|
|
741
|
+
namespace: "meta",
|
|
742
|
+
name: "page",
|
|
743
|
+
code: "Page",
|
|
744
|
+
singularCode: "page",
|
|
745
|
+
pluralCode: "pages",
|
|
746
|
+
schema: "public",
|
|
747
|
+
tableName: "meta_pages",
|
|
748
|
+
properties: [
|
|
749
|
+
{
|
|
750
|
+
name: "id",
|
|
751
|
+
code: "id",
|
|
752
|
+
columnName: "id",
|
|
753
|
+
type: "integer",
|
|
754
|
+
required: true,
|
|
755
|
+
autoIncrement: true,
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
name: "code",
|
|
759
|
+
code: "code",
|
|
760
|
+
columnName: "code",
|
|
761
|
+
type: "text",
|
|
762
|
+
required: true,
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
name: "parentCode",
|
|
766
|
+
code: "parentCode",
|
|
767
|
+
columnName: "parent_code",
|
|
768
|
+
type: "text",
|
|
769
|
+
required: false,
|
|
770
|
+
},
|
|
771
|
+
{
|
|
772
|
+
name: "subSystem",
|
|
773
|
+
code: "subSystem",
|
|
774
|
+
columnName: "sub_system",
|
|
775
|
+
type: "text",
|
|
776
|
+
required: false,
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
name: "appCode",
|
|
780
|
+
code: "appCode",
|
|
781
|
+
columnName: "app_code",
|
|
782
|
+
type: "text",
|
|
783
|
+
required: false,
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
name: "routePath",
|
|
787
|
+
code: "routePath",
|
|
788
|
+
columnName: "route_path",
|
|
789
|
+
type: "text",
|
|
790
|
+
required: false,
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
name: "name",
|
|
794
|
+
code: "name",
|
|
795
|
+
columnName: "name",
|
|
796
|
+
type: "text",
|
|
797
|
+
required: false,
|
|
798
|
+
},
|
|
799
|
+
{
|
|
800
|
+
name: "title",
|
|
801
|
+
code: "title",
|
|
802
|
+
columnName: "title",
|
|
803
|
+
type: "text",
|
|
804
|
+
required: false,
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
name: "config",
|
|
808
|
+
code: "config",
|
|
809
|
+
columnName: "config",
|
|
810
|
+
type: "json",
|
|
811
|
+
required: false,
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
name: "permissionCheck",
|
|
815
|
+
code: "permissionCheck",
|
|
816
|
+
columnName: "permission_check",
|
|
817
|
+
type: "json",
|
|
818
|
+
required: false,
|
|
819
|
+
},
|
|
820
|
+
],
|
|
821
|
+
indexes: [
|
|
822
|
+
{
|
|
823
|
+
name: "meta_pages_code_uindex",
|
|
824
|
+
properties: [
|
|
825
|
+
{
|
|
826
|
+
code: "code",
|
|
827
|
+
},
|
|
828
|
+
],
|
|
829
|
+
unique: true,
|
|
830
|
+
},
|
|
831
|
+
{
|
|
832
|
+
name: "meta_pages_subsystem_appcode_code_idx",
|
|
833
|
+
properties: [
|
|
834
|
+
{
|
|
835
|
+
code: "subSystem",
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
code: "appCode",
|
|
839
|
+
},
|
|
840
|
+
{
|
|
841
|
+
code: "code",
|
|
842
|
+
},
|
|
843
|
+
],
|
|
844
|
+
},
|
|
845
|
+
],
|
|
846
|
+
},
|
|
739
847
|
],
|
|
740
848
|
dataDictionaries: [],
|
|
741
849
|
routes: [
|
package/src/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ export * from "./dataAccess/entityManager";
|
|
|
20
20
|
|
|
21
21
|
export * from "./utilities/accessControlUtility";
|
|
22
22
|
export * from "./utilities/entityUtility";
|
|
23
|
+
export * from "./utilities/fsUtility";
|
|
23
24
|
export * from "./utilities/jwtUtility";
|
|
24
25
|
export * from "./utilities/timeUtility";
|
|
25
26
|
export * from "./utilities/passwordUtility";
|
|
@@ -62,7 +62,11 @@ class AuthPlugin implements RapidPlugin {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
async configureServices(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
|
|
65
|
-
this.#authService = new AuthService(server,
|
|
65
|
+
this.#authService = new AuthService(server, {
|
|
66
|
+
jwtKey: server.config.jwtKey,
|
|
67
|
+
userEntitySingularCode: this.#options.userEntitySingularCode,
|
|
68
|
+
profilePropertyCodes: this.#options.profilePropertyCodes,
|
|
69
|
+
});
|
|
66
70
|
server.registerService("authService", this.#authService);
|
|
67
71
|
}
|
|
68
72
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ActionHandlerContext } from "~/core/actionHandler";
|
|
2
2
|
import { RapidPlugin } from "~/core/server";
|
|
3
3
|
import AuthPlugin from "../AuthPlugin";
|
|
4
|
+
import AuthService from "../services/AuthService";
|
|
4
5
|
|
|
5
6
|
export const code = "getMyProfile";
|
|
6
7
|
|
|
@@ -18,19 +19,8 @@ export async function handler(plugin: AuthPlugin, ctx: ActionHandlerContext, opt
|
|
|
18
19
|
return;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const entityManager = server.getEntityManager(userEntitySingularCode);
|
|
24
|
-
const user = await entityManager.findEntity({
|
|
25
|
-
filters: [
|
|
26
|
-
{
|
|
27
|
-
operator: "eq",
|
|
28
|
-
field: "id",
|
|
29
|
-
value: userId,
|
|
30
|
-
},
|
|
31
|
-
],
|
|
32
|
-
properties: profilePropertyCodes,
|
|
33
|
-
});
|
|
22
|
+
const authService = server.getService<AuthService>("authService");
|
|
23
|
+
const user = await authService.getProfileOfUser(userId);
|
|
34
24
|
|
|
35
25
|
ctx.output = {
|
|
36
26
|
user,
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { IRpdServer } from "~/core/server";
|
|
2
2
|
import { createJwt } from "~/utilities/jwtUtility";
|
|
3
3
|
|
|
4
|
+
export type AuthServiceOptions = {
|
|
5
|
+
jwtKey: string;
|
|
6
|
+
userEntitySingularCode?: string;
|
|
7
|
+
profilePropertyCodes?: string[];
|
|
8
|
+
};
|
|
9
|
+
|
|
4
10
|
export interface UserAccessToken {
|
|
5
11
|
sub: "userAccessToken";
|
|
6
12
|
aud: string;
|
|
@@ -15,10 +21,14 @@ export interface CreateUserAccessTokenOptions {
|
|
|
15
21
|
export default class AuthService {
|
|
16
22
|
#server: IRpdServer;
|
|
17
23
|
#jwtKey: string;
|
|
24
|
+
#userEntitySingularCode?: string;
|
|
25
|
+
#profilePropertyCodes?: string[];
|
|
18
26
|
|
|
19
|
-
constructor(server: IRpdServer,
|
|
27
|
+
constructor(server: IRpdServer, options: AuthServiceOptions) {
|
|
20
28
|
this.#server = server;
|
|
21
|
-
this.#jwtKey = jwtKey;
|
|
29
|
+
this.#jwtKey = options.jwtKey;
|
|
30
|
+
this.#userEntitySingularCode = options.userEntitySingularCode;
|
|
31
|
+
this.#profilePropertyCodes = options.profilePropertyCodes;
|
|
22
32
|
}
|
|
23
33
|
|
|
24
34
|
createUserAccessToken(options: CreateUserAccessTokenOptions): string {
|
|
@@ -36,4 +46,21 @@ export default class AuthService {
|
|
|
36
46
|
|
|
37
47
|
return token;
|
|
38
48
|
}
|
|
49
|
+
|
|
50
|
+
async getProfileOfUser(userId: number) {
|
|
51
|
+
const userEntitySingularCode = this.#userEntitySingularCode || "oc_user";
|
|
52
|
+
const profilePropertyCodes = this.#profilePropertyCodes || ["id", "name", "login", "email", "department", "roles", "state", "createdAt"];
|
|
53
|
+
const entityManager = this.#server.getEntityManager(userEntitySingularCode);
|
|
54
|
+
const user = await entityManager.findEntity({
|
|
55
|
+
filters: [
|
|
56
|
+
{
|
|
57
|
+
operator: "eq",
|
|
58
|
+
field: "id",
|
|
59
|
+
value: userId,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
properties: profilePropertyCodes,
|
|
63
|
+
});
|
|
64
|
+
return user;
|
|
65
|
+
}
|
|
39
66
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { v1 as uuidv1 } from "uuid";
|
|
2
|
-
import {
|
|
2
|
+
import { writeFile } from "~/utilities/fsUtility";
|
|
3
3
|
import { ActionHandlerContext } from "~/core/actionHandler";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import { isArray } from "lodash";
|
|
@@ -27,7 +27,7 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
|
|
|
27
27
|
const filePathName = path.join(server.config.localFileStoragePath, fileKey);
|
|
28
28
|
|
|
29
29
|
const fileBuffer = await file.arrayBuffer();
|
|
30
|
-
await
|
|
30
|
+
await writeFile(filePathName, fileBuffer);
|
|
31
31
|
|
|
32
32
|
ctx.output = { ok: true, fileKey };
|
|
33
33
|
}
|
|
@@ -156,7 +156,7 @@ export default class MetaService {
|
|
|
156
156
|
const { queryBuilder } = server;
|
|
157
157
|
|
|
158
158
|
for (const model of applicationConfig.models) {
|
|
159
|
-
logger.
|
|
159
|
+
logger.info(`Checking data table for '${model.namespace}.${model.singularCode}'...`);
|
|
160
160
|
|
|
161
161
|
const expectedTableSchema = model.schema || server.databaseConfig.dbDefaultSchema;
|
|
162
162
|
const expectedTableName = model.tableName;
|
|
@@ -176,7 +176,7 @@ export default class MetaService {
|
|
|
176
176
|
const columnsInDb: ColumnInformation[] = await server.queryDatabaseObject(sqlQueryColumnInformations, []);
|
|
177
177
|
|
|
178
178
|
for (const model of applicationConfig.models) {
|
|
179
|
-
logger.
|
|
179
|
+
logger.info(`Checking data columns for '${model.namespace}.${model.singularCode}'...`);
|
|
180
180
|
|
|
181
181
|
for (const property of model.properties) {
|
|
182
182
|
let columnDDL = "";
|
|
@@ -336,7 +336,7 @@ export default class MetaService {
|
|
|
336
336
|
const expectedTableSchema = model.schema || server.databaseConfig.dbDefaultSchema;
|
|
337
337
|
const expectedTableName = model.tableName;
|
|
338
338
|
const expectedContraintName = `${expectedTableName}_pk`;
|
|
339
|
-
logger.
|
|
339
|
+
logger.info(`Checking pk for '${expectedTableSchema}.${expectedTableName}'...`);
|
|
340
340
|
const constraintInDb = find(constraintsInDb, {
|
|
341
341
|
table_schema: expectedTableSchema,
|
|
342
342
|
table_name: expectedTableName,
|
|
@@ -357,7 +357,7 @@ export default class MetaService {
|
|
|
357
357
|
continue;
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
-
logger.
|
|
360
|
+
logger.info(`Creating indexes of table ${queryBuilder.quoteTable(model)}`);
|
|
361
361
|
for (const index of model.indexes) {
|
|
362
362
|
const sqlCreateIndex = generateTableIndexDDL(queryBuilder, server, model, index);
|
|
363
363
|
try {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
2
3
|
|
|
3
4
|
export async function readFile(path: string): Promise<Buffer> {
|
|
4
5
|
return new Promise((resolve, reject) => {
|
|
@@ -59,3 +60,78 @@ export async function appendFile(path: string, data: ArrayBuffer): Promise<void>
|
|
|
59
60
|
});
|
|
60
61
|
});
|
|
61
62
|
}
|
|
63
|
+
|
|
64
|
+
export async function writeFile(path: string, data: ArrayBuffer): Promise<void> {
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
fs.writeFile(path, Buffer.from(data), (err) => {
|
|
67
|
+
if (err) {
|
|
68
|
+
reject(err);
|
|
69
|
+
} else {
|
|
70
|
+
resolve();
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function ensureDirectoryExists(dirPath: string) {
|
|
77
|
+
if (!fs.existsSync(dirPath)) {
|
|
78
|
+
const parentDirPath = path.dirname(dirPath);
|
|
79
|
+
if (parentDirPath == dirPath) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
ensureDirectoryExists(parentDirPath);
|
|
83
|
+
|
|
84
|
+
fs.mkdirSync(dirPath);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type EnumFileBaseNamesOptions = {
|
|
89
|
+
dirPath: string;
|
|
90
|
+
prefix?: string;
|
|
91
|
+
fileNameFilter?: (fileName: string) => boolean;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export function enumFileBaseNamesInDirectory(options: EnumFileBaseNamesOptions): string[] {
|
|
95
|
+
const { dirPath, prefix, fileNameFilter } = options;
|
|
96
|
+
let fileNames = [];
|
|
97
|
+
|
|
98
|
+
let resolvedDirPath = dirPath;
|
|
99
|
+
const isRelative = dirPath.startsWith(".") || dirPath.startsWith("..");
|
|
100
|
+
if (isRelative) {
|
|
101
|
+
resolvedDirPath = path.join(process.cwd(), dirPath);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!fs.existsSync(resolvedDirPath)) {
|
|
105
|
+
console.warn(`Directory '${resolvedDirPath}' not found.`);
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const files = fs.readdirSync(resolvedDirPath);
|
|
110
|
+
for (const fileName of files) {
|
|
111
|
+
const filePathName = path.join(resolvedDirPath, fileName);
|
|
112
|
+
const fileStat = fs.statSync(filePathName);
|
|
113
|
+
if (fileStat.isDirectory()) {
|
|
114
|
+
fileNames = fileNames.concat(
|
|
115
|
+
enumFileBaseNamesInDirectory({
|
|
116
|
+
dirPath: filePathName,
|
|
117
|
+
prefix: prefix ? `${prefix}/${fileName}` : fileName,
|
|
118
|
+
fileNameFilter,
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
} else if (fileStat.isFile()) {
|
|
122
|
+
if (fileNameFilter && !fileNameFilter(fileName)) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const baseName = path.parse(fileName).name;
|
|
127
|
+
if (prefix) {
|
|
128
|
+
fileNames.push(`${prefix}/${baseName}`);
|
|
129
|
+
} else {
|
|
130
|
+
fileNames.push(baseName);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fileNames.sort();
|
|
136
|
+
return fileNames;
|
|
137
|
+
}
|