@opengis/fastify-table 1.2.10 → 1.2.12
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/index.js +9 -8
- package/package.json +1 -1
- package/server/migrations/template.sql +35 -0
- package/server/plugins/migration/exec.migrations.js +37 -0
- package/server/plugins/migration/exec.sql.js +46 -0
- package/server/plugins/migration/get.caller.dir.js +26 -0
- package/server/plugins/policy/funcs/checkPolicy.js +2 -2
- package/utils.js +3 -1
- package/server/plugins/migration/funcs/exec.migrations.js +0 -86
package/index.js
CHANGED
|
@@ -48,7 +48,15 @@ async function plugin(fastify, opt) {
|
|
|
48
48
|
|
|
49
49
|
fastify.register(import('@opengis/fastify-hb'));
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
const filename = fileURLToPath(import.meta.url);
|
|
52
|
+
const cwd = path.dirname(filename);
|
|
53
|
+
|
|
54
|
+
// core migrations (second argument for core only)
|
|
55
|
+
execMigrations(path.join(cwd, 'server/migrations'), true).catch(err => console.log(err));
|
|
56
|
+
|
|
57
|
+
// core templates && cls
|
|
58
|
+
config.templates?.forEach(el => addTemplateDir(el));
|
|
59
|
+
addTemplateDir(path.join(cwd, 'module/core'));
|
|
52
60
|
|
|
53
61
|
// plugins / utils / funcs
|
|
54
62
|
policyPlugin(fastify);
|
|
@@ -67,12 +75,5 @@ async function plugin(fastify, opt) {
|
|
|
67
75
|
propertiesRoutes(fastify, opt);
|
|
68
76
|
tableRoutes(fastify, opt);
|
|
69
77
|
utilRoutes(fastify, opt);
|
|
70
|
-
|
|
71
|
-
// core templates && cls
|
|
72
|
-
const filename = fileURLToPath(import.meta.url);
|
|
73
|
-
const cwd = path.dirname(filename);
|
|
74
|
-
|
|
75
|
-
config.templates?.forEach(el => addTemplateDir(el));
|
|
76
|
-
addTemplateDir(path.join(cwd, 'module/core'));
|
|
77
78
|
}
|
|
78
79
|
export default fp(plugin);
|
package/package.json
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
create schema if not exists admin;
|
|
2
|
+
|
|
3
|
+
-- DROP TABLE is exists admin.templates;
|
|
4
|
+
CREATE TABLE if not exists admin.templates();
|
|
5
|
+
ALTER TABLE admin.templates add column if not exists template_id text NOT NULL DEFAULT next_id();
|
|
6
|
+
ALTER TABLE admin.templates DROP CONSTRAINT if exists admin_templates_template_id_pkey cascade;
|
|
7
|
+
ALTER TABLE admin.templates DROP CONSTRAINT if exists admin_templates_name_type_unique;
|
|
8
|
+
|
|
9
|
+
ALTER TABLE admin.templates add column if not exists name text;
|
|
10
|
+
ALTER TABLE admin.templates add column if not exists title text;
|
|
11
|
+
ALTER TABLE admin.templates add column if not exists type text;
|
|
12
|
+
ALTER TABLE admin.templates add column if not exists route_id text;
|
|
13
|
+
ALTER TABLE admin.templates add column if not exists enabled boolean;
|
|
14
|
+
ALTER TABLE admin.templates alter column enabled set default true;
|
|
15
|
+
ALTER TABLE admin.templates add column if not exists body text;
|
|
16
|
+
|
|
17
|
+
ALTER TABLE admin.templates add column if not exists uid text;
|
|
18
|
+
ALTER TABLE admin.templates add column if not exists cdate timestamp without time zone DEFAULT date_trunc('seconds'::text, now());
|
|
19
|
+
ALTER TABLE admin.templates alter column cdate set DEFAULT date_trunc('seconds'::text, now());
|
|
20
|
+
ALTER TABLE admin.templates add column if not exists editor_id text;
|
|
21
|
+
ALTER TABLE admin.templates add column if not exists editor_date timestamp without time zone;
|
|
22
|
+
|
|
23
|
+
ALTER TABLE admin.templates add CONSTRAINT admin_templates_template_id_pkey PRIMARY KEY (template_id);
|
|
24
|
+
ALTER TABLE admin.templates add CONSTRAINT admin_templates_name_type_unique UNIQUE (name, type);
|
|
25
|
+
|
|
26
|
+
COMMENT ON TABLE admin.templates IS 'Шаблони для друку';
|
|
27
|
+
|
|
28
|
+
COMMENT ON COLUMN admin.templates.uid IS 'ID користувача';
|
|
29
|
+
|
|
30
|
+
COMMENT ON COLUMN admin.templates.name IS 'Систамна назва шаблону';
|
|
31
|
+
COMMENT ON COLUMN admin.templates.title IS 'Назва шаблону українською';
|
|
32
|
+
COMMENT ON COLUMN admin.templates.type IS 'Тип вихідних даних шаблону (demo/user)';
|
|
33
|
+
COMMENT ON COLUMN admin.templates.route_id IS 'ID інтерфейсу';
|
|
34
|
+
COMMENT ON COLUMN admin.templates.enabled IS 'On / Off';
|
|
35
|
+
COMMENT ON COLUMN admin.templates.body IS 'Body HTML';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { readdirSync, existsSync } from 'node:fs';
|
|
3
|
+
|
|
4
|
+
import config from '../../../config.js';
|
|
5
|
+
import execSql from './exec.sql.js';
|
|
6
|
+
// import getCallerDir from './get.caller.dir.js';
|
|
7
|
+
|
|
8
|
+
const time = Date.now();
|
|
9
|
+
|
|
10
|
+
export default async function execMigrations(dirPath, iscore) {
|
|
11
|
+
if (
|
|
12
|
+
!dirPath
|
|
13
|
+
|| (config.migrationsCore === false && iscore)
|
|
14
|
+
|| config.migrations === false
|
|
15
|
+
) {
|
|
16
|
+
console.log('migrations skip', 'core: ', !!iscore, 'dir: ', dirPath || 'not specified');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
console.log('migrations start', dirPath, Date.now() - time);
|
|
21
|
+
|
|
22
|
+
const exists = existsSync(dirPath);
|
|
23
|
+
|
|
24
|
+
if (exists) {
|
|
25
|
+
// get directory sql file list
|
|
26
|
+
const content = readdirSync(dirPath, { withFileTypes: true })
|
|
27
|
+
?.filter((el) => el.isFile() && path.extname(el.name) === '.sql')
|
|
28
|
+
?.map((el) => el.name) || [];
|
|
29
|
+
|
|
30
|
+
// execute sql files
|
|
31
|
+
if (content?.length) {
|
|
32
|
+
await content.reduce((promise, filename) => promise.then(() => execSql(path.join(dirPath, filename))), Promise.resolve());
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log('migrations finish', dirPath, exists, Date.now() - time);
|
|
37
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
|
|
4
|
+
import { logger, pgClients } from '../../../utils.js';
|
|
5
|
+
|
|
6
|
+
export default async function execSql(filepath, pg = pgClients.client) {
|
|
7
|
+
const start = Date.now();
|
|
8
|
+
|
|
9
|
+
if (!filepath) return null;
|
|
10
|
+
|
|
11
|
+
const filename = path.basename(filepath);
|
|
12
|
+
|
|
13
|
+
if (!existsSync(filepath)) {
|
|
14
|
+
logger.file('migration/notfound', {
|
|
15
|
+
filepath,
|
|
16
|
+
result: 'not found',
|
|
17
|
+
});
|
|
18
|
+
console.log(filepath, 'warn', 'not found', Date.now() - start);
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const sql = readFileSync(filepath, 'utf-8');
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
console.log(filename, 'start', Date.now() - start);
|
|
26
|
+
await pg.query(sql);
|
|
27
|
+
console.log(filename, 'finish', Date.now() - start);
|
|
28
|
+
logger.file('migration/success', {
|
|
29
|
+
filepath,
|
|
30
|
+
result: 'success',
|
|
31
|
+
time: Date.now() - start,
|
|
32
|
+
});
|
|
33
|
+
return 'ok';
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
console.log(filename, 'error', err.toString(), Date.now() - start);
|
|
37
|
+
logger.file('migration/error', {
|
|
38
|
+
filepath,
|
|
39
|
+
result: 'error',
|
|
40
|
+
error: err.toString(),
|
|
41
|
+
stack: err.stack,
|
|
42
|
+
time: Date.now() - start,
|
|
43
|
+
});
|
|
44
|
+
return err.toString();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
export default function getCallerDir() {
|
|
4
|
+
const originalFunc = Error.prepareStackTrace;
|
|
5
|
+
|
|
6
|
+
let callerfile;
|
|
7
|
+
try {
|
|
8
|
+
const err = new Error();
|
|
9
|
+
// let currentfile;
|
|
10
|
+
|
|
11
|
+
Error.prepareStackTrace = function (err, stack) { return stack; };
|
|
12
|
+
|
|
13
|
+
const currentfile = err.stack.shift().getFileName();
|
|
14
|
+
|
|
15
|
+
while (err.stack.length) {
|
|
16
|
+
callerfile = err.stack.shift().getFileName();
|
|
17
|
+
|
|
18
|
+
if (currentfile !== callerfile) break;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch (err) { }
|
|
22
|
+
|
|
23
|
+
Error.prepareStackTrace = originalFunc;
|
|
24
|
+
|
|
25
|
+
return path.dirname(callerfile);
|
|
26
|
+
}
|
|
@@ -27,9 +27,9 @@ export default function checkPolicy(req, reply) {
|
|
|
27
27
|
const { policy = [] } = routeOptions?.config || {};
|
|
28
28
|
|
|
29
29
|
/*= == 0.Check superadmin access === */
|
|
30
|
-
if (policy.includes('
|
|
30
|
+
if (policy.includes('admin') && user?.user_type !== 'admin') {
|
|
31
31
|
logger.file('policy/access', {
|
|
32
|
-
path, method, params, query, body, message: 'access restricted: not
|
|
32
|
+
path, method, params, query, body, message: 'access restricted: not admin', uid: user?.uid,
|
|
33
33
|
});
|
|
34
34
|
return reply.status(403).send('access restricted: 0');
|
|
35
35
|
}
|
package/utils.js
CHANGED
|
@@ -49,7 +49,8 @@ import checkXSS from './server/plugins/policy/funcs/checkXSS.js';
|
|
|
49
49
|
import applyHook from './server/plugins/hook/funcs/applyHook.js';
|
|
50
50
|
import applyHookSync from './server/plugins/hook/funcs/applyHookSync.js';
|
|
51
51
|
import addHook from './server/plugins/hook/funcs/addHook.js';
|
|
52
|
-
import execMigrations from './server/plugins/migration/
|
|
52
|
+
import execMigrations from './server/plugins/migration/exec.migrations.js';
|
|
53
|
+
import execSql from './server/plugins/migration/exec.sql.js';
|
|
53
54
|
|
|
54
55
|
// cron
|
|
55
56
|
import addCron from './server/plugins/cron/funcs/addCron.js';
|
|
@@ -74,6 +75,7 @@ export {
|
|
|
74
75
|
getFilterSQL,
|
|
75
76
|
addCron,
|
|
76
77
|
execMigrations,
|
|
78
|
+
execSql,
|
|
77
79
|
getRedis,
|
|
78
80
|
redisClients,
|
|
79
81
|
logger,
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
const time = Date.now();
|
|
5
|
-
|
|
6
|
-
import getPG from '../../pg/funcs/getPG.js';
|
|
7
|
-
|
|
8
|
-
function getCallerDir() {
|
|
9
|
-
const originalFunc = Error.prepareStackTrace;
|
|
10
|
-
|
|
11
|
-
let callerfile;
|
|
12
|
-
try {
|
|
13
|
-
const err = new Error();
|
|
14
|
-
// let currentfile;
|
|
15
|
-
|
|
16
|
-
Error.prepareStackTrace = function (err, stack) { return stack; };
|
|
17
|
-
|
|
18
|
-
const currentfile = err.stack.shift().getFileName();
|
|
19
|
-
|
|
20
|
-
while (err.stack.length) {
|
|
21
|
-
callerfile = err.stack.shift().getFileName();
|
|
22
|
-
|
|
23
|
-
if (currentfile !== callerfile) break;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
catch (err) { }
|
|
27
|
-
|
|
28
|
-
Error.prepareStackTrace = originalFunc;
|
|
29
|
-
|
|
30
|
-
return path.dirname(callerfile);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function sequence(files, data, fn) {
|
|
34
|
-
return files.reduce((promise, filename) => promise.then(() => fn({
|
|
35
|
-
...data, filename,
|
|
36
|
-
})), Promise.resolve());
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async function execSql({
|
|
40
|
-
pg, dir, filename,
|
|
41
|
-
}) {
|
|
42
|
-
const start = Date.now();
|
|
43
|
-
const filepath = path.join(dir, filename);
|
|
44
|
-
const sql = fs.readFileSync(filepath, 'utf-8');
|
|
45
|
-
try {
|
|
46
|
-
console.log(filename, 'start', Date.now() - start);
|
|
47
|
-
await pg.query(sql);
|
|
48
|
-
console.log(filename, 'finish', Date.now() - start);
|
|
49
|
-
}
|
|
50
|
-
catch (err) {
|
|
51
|
-
console.log(filepath, 'error', err.toString(), Date.now() - start);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export default async function execMigrations(opt) {
|
|
56
|
-
try {
|
|
57
|
-
const pg = opt?.pg || getPG({ name: 'client' });
|
|
58
|
-
const rootDir = getCallerDir();
|
|
59
|
-
const subdir = () => {
|
|
60
|
-
if (rootDir.endsWith('plugins')) {
|
|
61
|
-
return '../..';
|
|
62
|
-
} if (path.basename(rootDir) === 'server') {
|
|
63
|
-
return '..';
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
const dir = path.join(rootDir.replace(/\\/g, '/').replace(/^file:\/\/\//, ''), subdir() || '', 'server/migrations');
|
|
67
|
-
|
|
68
|
-
console.log('migrations start', dir, Date.now() - time);
|
|
69
|
-
const exists = fs.existsSync(dir);
|
|
70
|
-
if (exists) {
|
|
71
|
-
// get directory sql file list
|
|
72
|
-
const content = fs.readdirSync(dir, { withFileTypes: true })
|
|
73
|
-
?.filter((el) => el.isFile() && path.extname(el.name) === '.sql')
|
|
74
|
-
?.map((el) => el.name) || [];
|
|
75
|
-
|
|
76
|
-
// execute sql files
|
|
77
|
-
if (content?.length) {
|
|
78
|
-
await sequence(content, { pg, dir }, execSql);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
console.log('migrations finish', dir, exists, Date.now() - time);
|
|
82
|
-
}
|
|
83
|
-
catch (err) {
|
|
84
|
-
console.error('migrations error', err.toString(), Date.now() - time);
|
|
85
|
-
}
|
|
86
|
-
}
|