@opengis/fastify-table 1.1.42 → 1.1.44
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/Changelog.md +6 -0
- package/README.md +26 -26
- package/config.js +10 -10
- package/cron/controllers/cronApi.js +22 -22
- package/cron/controllers/utils/cronList.js +1 -1
- package/cron/funcs/addCron.js +4 -3
- package/cron/index.js +10 -10
- package/crud/controllers/deleteCrud.js +17 -8
- package/crud/controllers/insert.js +29 -21
- package/crud/controllers/update.js +32 -21
- package/crud/controllers/utils/checkXSS.js +45 -45
- package/crud/controllers/utils/xssInjection.js +72 -72
- package/crud/funcs/getAccess.js +19 -15
- package/crud/funcs/getToken.js +27 -27
- package/crud/funcs/isFileExists.js +13 -13
- package/crud/funcs/setToken.js +53 -53
- package/crud/index.js +3 -3
- package/index.js +8 -2
- package/notification/controllers/testEmail.js +3 -2
- package/notification/funcs/addNotification.js +4 -2
- package/notification/funcs/sendNotification.js +5 -4
- package/notification/funcs/utils/sendEmail.js +39 -39
- package/package.json +5 -5
- package/pg/funcs/getPG.js +1 -1
- package/redis/funcs/getRedis.js +23 -23
- package/server/migrations/log.sql +80 -80
- package/table/controllers/card.js +74 -44
- package/table/controllers/data.js +33 -19
- package/table/controllers/form.js +18 -4
- package/table/controllers/table.js +34 -17
- package/table/controllers/utils/gisIRColumn.js +2 -3
- package/table/index.js +1 -1
- package/test/api/applyHook.test.js +4 -5
- package/test/api/crud.xss.test.js +6 -14
- package/test/config.example +18 -18
- package/test/funcs/pg.test.js +34 -34
- package/test/funcs/redis.test.js +19 -19
- package/test/helper/formatDate.test.js +62 -0
- package/test/templates/cls/test.json +9 -9
- package/test/templates/form/cp_building.form.json +32 -32
- package/test/templates/select/account_id.json +3 -3
- package/test/templates/select/storage.data.json +2 -2
- package/test/templates/table/gis.dataset.table.json +20 -20
- package/util/controllers/next.id.js +4 -4
- package/util/controllers/properties.add.js +6 -3
- package/util/controllers/properties.get.js +19 -19
- package/util/index.js +23 -23
- package/utils.js +5 -3
- package/widget/controllers/widget.set.js +3 -1
- package/notification/hook/onWidgetSet.js +0 -63
package/crud/funcs/getAccess.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import getMeta from '../../pg/funcs/getMeta.js';
|
|
2
2
|
import getTemplate from '../../table/controllers/utils/getTemplate.js';
|
|
3
3
|
import config from '../../config.js';
|
|
4
|
+
import pgClients from '../../pg/pgClients.js';
|
|
4
5
|
|
|
5
|
-
const q = `select a.route_id as id, b.actions, b.scope
|
|
6
|
+
const q = `select a.route_id as id, coalesce(b.actions,array['get']) as actions, b.scope
|
|
6
7
|
from admin.routes a
|
|
7
8
|
left join admin.access b on
|
|
8
9
|
a.route_id=b.route_id
|
|
@@ -16,36 +17,39 @@ left join admin.user_roles d on
|
|
|
16
17
|
then d.expiration > CURRENT_DATE
|
|
17
18
|
else 1=1
|
|
18
19
|
end )
|
|
19
|
-
where a.route_id
|
|
20
|
+
where $1 in (a.route_id, a.alias) and $2 in (b.user_uid, d.user_uid)`;
|
|
20
21
|
|
|
21
|
-
export default async function getAccess(
|
|
22
|
-
if (config.
|
|
22
|
+
export default async function getAccess({ table, id, user }) {
|
|
23
|
+
if (config.auth?.disable || user?.user_type?.includes('admin')) {
|
|
23
24
|
return { actions: ['get', 'edit', 'del'], my: true, query: '1=1' };
|
|
24
25
|
}
|
|
25
|
-
|
|
26
|
-
const {
|
|
27
|
-
|
|
26
|
+
|
|
27
|
+
const { client: pg } = pgClients || {};
|
|
28
|
+
const { uid, user_type: userType } = user || {};
|
|
29
|
+
|
|
30
|
+
if (!uid || !table) return null;
|
|
28
31
|
|
|
29
32
|
if (!pg.pk?.['admin.access']) return null;
|
|
30
33
|
|
|
31
|
-
const
|
|
32
|
-
if (!table) return null;
|
|
34
|
+
const body = await getTemplate('table', table) || {};
|
|
35
|
+
if (!body?.table) return null;
|
|
33
36
|
|
|
34
|
-
const { scope = 'my', actions = [] } = await pg.
|
|
35
|
-
// console.log(scope, actions);
|
|
37
|
+
const { scope = 'my', actions = [] } = await pg.query(q, [table, uid]).then((res) => res.rows?.[0] || {});
|
|
36
38
|
|
|
37
|
-
const { columns = [] } = await getMeta(table);
|
|
38
|
-
const columnList = columns.map((el) => el.name || el).join(',');
|
|
39
|
+
const { columns = [] } = await getMeta({ table: body?.table });
|
|
39
40
|
|
|
40
41
|
const query = userType?.includes('admin') ? '1=1' : {
|
|
41
42
|
my: `uid='${uid}'`,
|
|
42
|
-
responsible:
|
|
43
|
+
responsible: columns.map((el) => el?.name || el).includes('responsible_id')
|
|
43
44
|
? `responsible_id='${uid}'`
|
|
44
45
|
: `uid='${uid}'`,
|
|
45
46
|
all: '1=1',
|
|
46
47
|
}[scope];
|
|
47
48
|
|
|
48
|
-
const { my } = pg.pk?.[table] && id
|
|
49
|
+
const { my } = pg.pk?.[body?.table] && id
|
|
50
|
+
? await pg.query(`select uid=$1 as my from ${body?.table} where ${pg.pk?.[body?.table]}=$2`, [uid, id])
|
|
51
|
+
.then((res) => res.rows?.[0] || {})
|
|
52
|
+
: {};
|
|
49
53
|
|
|
50
54
|
return {
|
|
51
55
|
scope, actions, query, my,
|
package/crud/funcs/getToken.js
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import getRedis from '../../redis/funcs/getRedis.js';
|
|
2
|
-
import config from '../../config.js';
|
|
3
|
-
|
|
4
|
-
function sprintf(str, ...args) {
|
|
5
|
-
return str.replace(/%s/g, () => args.shift());
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const keys = {
|
|
9
|
-
r: '%s:token:view:%s',
|
|
10
|
-
a: '%s:token:add:%s',
|
|
11
|
-
w: '%s:token:edit:%s',
|
|
12
|
-
e: '%s:token:exec:%s',
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
async function getToken({
|
|
16
|
-
uid, token, mode = 'r', json,
|
|
17
|
-
}) {
|
|
18
|
-
if (mode === 'r') return token;
|
|
19
|
-
|
|
20
|
-
const rclient = getRedis({ db: 0 });
|
|
21
|
-
|
|
22
|
-
const key = sprintf(keys[mode], config?.pg?.database, uid?.toString());
|
|
23
|
-
const id = await rclient.hget(key, token);
|
|
24
|
-
return json && id?.[0] === '{' ? JSON.parse(id) : id;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default getToken;
|
|
1
|
+
import getRedis from '../../redis/funcs/getRedis.js';
|
|
2
|
+
import config from '../../config.js';
|
|
3
|
+
|
|
4
|
+
function sprintf(str, ...args) {
|
|
5
|
+
return str.replace(/%s/g, () => args.shift());
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const keys = {
|
|
9
|
+
r: '%s:token:view:%s',
|
|
10
|
+
a: '%s:token:add:%s',
|
|
11
|
+
w: '%s:token:edit:%s',
|
|
12
|
+
e: '%s:token:exec:%s',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
async function getToken({
|
|
16
|
+
uid, token, mode = 'r', json,
|
|
17
|
+
}) {
|
|
18
|
+
if (mode === 'r') return token;
|
|
19
|
+
|
|
20
|
+
const rclient = getRedis({ db: 0 });
|
|
21
|
+
|
|
22
|
+
const key = sprintf(keys[mode], config?.pg?.database, uid?.toString());
|
|
23
|
+
const id = await rclient.hget(key, token);
|
|
24
|
+
return json && id?.[0] === '{' ? JSON.parse(id) : id;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default getToken;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { access } from 'fs/promises';
|
|
2
|
-
|
|
3
|
-
const isFileExists = async (filepath) => {
|
|
4
|
-
try {
|
|
5
|
-
await access(filepath);
|
|
6
|
-
return true;
|
|
7
|
-
}
|
|
8
|
-
catch (err) {
|
|
9
|
-
return false;
|
|
10
|
-
}
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export default isFileExists;
|
|
1
|
+
import { access } from 'fs/promises';
|
|
2
|
+
|
|
3
|
+
const isFileExists = async (filepath) => {
|
|
4
|
+
try {
|
|
5
|
+
await access(filepath);
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
catch (err) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default isFileExists;
|
package/crud/funcs/setToken.js
CHANGED
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
import { createHash, randomUUID } from 'crypto';
|
|
2
|
-
|
|
3
|
-
import config from '../../config.js';
|
|
4
|
-
import getRedis from '../../redis/funcs/getRedis.js';
|
|
5
|
-
|
|
6
|
-
const generateCodes = (ids, userToken) => {
|
|
7
|
-
const token = userToken || randomUUID();
|
|
8
|
-
const notNullIds = ids.filter((el) => el);
|
|
9
|
-
const obj = {};
|
|
10
|
-
const codes = notNullIds.reduce((acc, id) => {
|
|
11
|
-
const newToken = createHash('sha1').update(token + id).digest('base64url').replace(/-/g, '');
|
|
12
|
-
acc[newToken] = id; obj[id] = newToken;
|
|
13
|
-
return acc;
|
|
14
|
-
}, {});
|
|
15
|
-
return { codes, obj };
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
function setToken({
|
|
19
|
-
ids: idsOrigin, mode = 'r', uid, referer, array,
|
|
20
|
-
}) {
|
|
21
|
-
const rclient2 = getRedis({ db: 0 });
|
|
22
|
-
// const rclient5 = getRedis({ db: 0, funcs });
|
|
23
|
-
|
|
24
|
-
if (!uid) return { user: 'empty' };
|
|
25
|
-
if (!Object.keys(idsOrigin).length) return { ids: 'empty' };
|
|
26
|
-
|
|
27
|
-
const ids = idsOrigin.map((el) => (typeof el === 'object' ? JSON.stringify(el) : el));
|
|
28
|
-
// update/delete
|
|
29
|
-
|
|
30
|
-
if (mode === 'r') return null;
|
|
31
|
-
|
|
32
|
-
// TODO generate salt
|
|
33
|
-
const { codes, obj } = generateCodes(ids, uid);
|
|
34
|
-
|
|
35
|
-
if (!Object.keys(codes).length) return { ids: 'empty' };
|
|
36
|
-
|
|
37
|
-
rclient2.hmset(`${config.pg.database}:token:${{
|
|
38
|
-
e: 'exec', r: 'view', w: 'edit', a: 'add',
|
|
39
|
-
}[mode]}:${uid}`, codes);
|
|
40
|
-
|
|
41
|
-
// log token for debug. add extra data - uid, mode, date
|
|
42
|
-
/* const dt = new Date().toISOString();
|
|
43
|
-
const codesLog = Object.keys(codes).reduce((acc, key) => {
|
|
44
|
-
acc[key] = `{"referer": "${referer}" ,"uid":"${uid}","mode":"${mode}","date":"${dt}",${codes[key].substr(1)}`;
|
|
45
|
-
return acc;
|
|
46
|
-
}, {});
|
|
47
|
-
rclient5.hmset(`${config.pg.database}:token:edit`, codesLog); // 'EX', 64800 */
|
|
48
|
-
|
|
49
|
-
// TODO дополнительно писать в hset token -> uid
|
|
50
|
-
return array ? Object.values(obj) : obj;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export default setToken;
|
|
1
|
+
import { createHash, randomUUID } from 'crypto';
|
|
2
|
+
|
|
3
|
+
import config from '../../config.js';
|
|
4
|
+
import getRedis from '../../redis/funcs/getRedis.js';
|
|
5
|
+
|
|
6
|
+
const generateCodes = (ids, userToken) => {
|
|
7
|
+
const token = userToken || randomUUID();
|
|
8
|
+
const notNullIds = ids.filter((el) => el);
|
|
9
|
+
const obj = {};
|
|
10
|
+
const codes = notNullIds.reduce((acc, id) => {
|
|
11
|
+
const newToken = createHash('sha1').update(token + id).digest('base64url').replace(/-/g, '');
|
|
12
|
+
acc[newToken] = id; obj[id] = newToken;
|
|
13
|
+
return acc;
|
|
14
|
+
}, {});
|
|
15
|
+
return { codes, obj };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function setToken({
|
|
19
|
+
ids: idsOrigin, mode = 'r', uid, referer, array,
|
|
20
|
+
}) {
|
|
21
|
+
const rclient2 = getRedis({ db: 0 });
|
|
22
|
+
// const rclient5 = getRedis({ db: 0, funcs });
|
|
23
|
+
|
|
24
|
+
if (!uid) return { user: 'empty' };
|
|
25
|
+
if (!Object.keys(idsOrigin).length) return { ids: 'empty' };
|
|
26
|
+
|
|
27
|
+
const ids = idsOrigin.map((el) => (typeof el === 'object' ? JSON.stringify(el) : el));
|
|
28
|
+
// update/delete
|
|
29
|
+
|
|
30
|
+
if (mode === 'r') return null;
|
|
31
|
+
|
|
32
|
+
// TODO generate salt
|
|
33
|
+
const { codes, obj } = generateCodes(ids, uid);
|
|
34
|
+
|
|
35
|
+
if (!Object.keys(codes).length) return { ids: 'empty' };
|
|
36
|
+
|
|
37
|
+
rclient2.hmset(`${config.pg.database}:token:${{
|
|
38
|
+
e: 'exec', r: 'view', w: 'edit', a: 'add',
|
|
39
|
+
}[mode]}:${uid}`, codes);
|
|
40
|
+
|
|
41
|
+
// log token for debug. add extra data - uid, mode, date
|
|
42
|
+
/* const dt = new Date().toISOString();
|
|
43
|
+
const codesLog = Object.keys(codes).reduce((acc, key) => {
|
|
44
|
+
acc[key] = `{"referer": "${referer}" ,"uid":"${uid}","mode":"${mode}","date":"${dt}",${codes[key].substr(1)}`;
|
|
45
|
+
return acc;
|
|
46
|
+
}, {});
|
|
47
|
+
rclient5.hmset(`${config.pg.database}:token:edit`, codesLog); // 'EX', 64800 */
|
|
48
|
+
|
|
49
|
+
// TODO дополнительно писать в hset token -> uid
|
|
50
|
+
return array ? Object.values(obj) : obj;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default setToken;
|
package/crud/index.js
CHANGED
|
@@ -28,9 +28,9 @@ async function plugin(fastify, config = {}) {
|
|
|
28
28
|
fastify.decorate('isFileExists', isFileExists);
|
|
29
29
|
|
|
30
30
|
// api
|
|
31
|
-
fastify.put(`${prefix}/table/:table/:id
|
|
32
|
-
fastify.delete(`${prefix}/table/:table/:id
|
|
33
|
-
fastify.post(`${prefix}/table/:table
|
|
31
|
+
fastify.put(`${prefix}/table/:table/:id?`, { schema: tableSchema }, update);
|
|
32
|
+
fastify.delete(`${prefix}/table/:table/:id?`, { schema: tableSchema }, deleteCrud);
|
|
33
|
+
fastify.post(`${prefix}/table/:table?`, { schema: tableSchema }, insert);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export default plugin;
|
package/index.js
CHANGED
|
@@ -20,7 +20,7 @@ import userPlugin from './user/index.js';
|
|
|
20
20
|
|
|
21
21
|
// import pgClients from './pg/pgClients.js';
|
|
22
22
|
|
|
23
|
-
import { addTemplateDir, execMigrations } from './utils.js';
|
|
23
|
+
import { addTemplateDir, execMigrations, logger } from './utils.js';
|
|
24
24
|
|
|
25
25
|
async function plugin(fastify, opt) {
|
|
26
26
|
// console.log(opt);
|
|
@@ -65,8 +65,14 @@ async function plugin(fastify, opt) {
|
|
|
65
65
|
return reply.status(error.statusCode || 500).send(config.local ? error.toString() : 'ServerError');
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
+
execMigrations().catch(err => console.log(err));
|
|
68
69
|
// core migrations
|
|
69
|
-
|
|
70
|
+
/* try {
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
logger.error(err);
|
|
75
|
+
} */
|
|
70
76
|
|
|
71
77
|
if (!fastify.funcs) {
|
|
72
78
|
fastify.addHook('onRequest', async (req) => {
|
|
@@ -2,6 +2,8 @@ import path from 'path';
|
|
|
2
2
|
import { existsSync } from 'fs';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
|
|
5
|
+
import config from '../../config.js';
|
|
6
|
+
|
|
5
7
|
const fileName = fileURLToPath(import.meta.url);
|
|
6
8
|
const dirName = path.dirname(fileName);
|
|
7
9
|
|
|
@@ -10,7 +12,7 @@ import notification from '../funcs/sendNotification.js';
|
|
|
10
12
|
export default async function testNotification({
|
|
11
13
|
pg, funcs = {}, log, query = {}, session = {},
|
|
12
14
|
}) {
|
|
13
|
-
const { local } =
|
|
15
|
+
const { local } = config || {};
|
|
14
16
|
if (!session?.passport?.user?.user_type?.includes('admin') && !local) {
|
|
15
17
|
return { message: 'Forbidden', status: 403 };
|
|
16
18
|
}
|
|
@@ -27,7 +29,6 @@ export default async function testNotification({
|
|
|
27
29
|
const file = [path.join(dirName, '../../', 'changelog.md'), path.join(dirName, 'utils', 'pin-m-ty-media-record-outline+303070.png')].filter((el) => existsSync(el));
|
|
28
30
|
const data = await notification({
|
|
29
31
|
pg,
|
|
30
|
-
funcs,
|
|
31
32
|
log,
|
|
32
33
|
to,
|
|
33
34
|
template,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import dataInsert from '../../crud/funcs/dataInsert.js';
|
|
2
|
+
|
|
1
3
|
export default async function addNotification({
|
|
2
|
-
pg,
|
|
4
|
+
pg, session = {}, subject, body, link, uid, entity,
|
|
3
5
|
}) {
|
|
4
6
|
const { uid: author } = session.passport?.user || {};
|
|
5
|
-
const res = await
|
|
7
|
+
const res = await dataInsert({
|
|
6
8
|
pg,
|
|
7
9
|
table: 'crm.notifications',
|
|
8
10
|
data: {
|
|
@@ -3,26 +3,28 @@ const emailReg = /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-
|
|
|
3
3
|
|
|
4
4
|
// eslint-disable-next-line import/no-relative-packages
|
|
5
5
|
// import downloadFile from '../../../fastify-file/file/funcs/downloadFile.js'; // test only
|
|
6
|
+
import { handlebars } from '@opengis/fastify-hb/utils.js';
|
|
6
7
|
import pgClients from '../../pg/pgClients.js';
|
|
7
8
|
import sendEmail from './utils/sendEmail.js';
|
|
8
9
|
import getTemplate from '../../table/controllers/utils/getTemplate.js';
|
|
9
10
|
import getRedis from '../../redis/funcs/getRedis.js';
|
|
10
11
|
|
|
11
12
|
async function generateNotificationContent({
|
|
12
|
-
pg,
|
|
13
|
+
pg, table, template, id, message, data: data1,
|
|
13
14
|
}) {
|
|
14
15
|
if (template) {
|
|
15
16
|
const data = table && id ? await pg.one(`select * from ${table} where ${pg.pk[table]}=$1`, [id]) : data1;
|
|
16
17
|
// console.log(data);
|
|
17
18
|
const body = await getTemplate('pt', template);
|
|
18
19
|
// console.log(body);
|
|
19
|
-
const html =
|
|
20
|
+
const html = handlebars.compile(body || template || 'template not found')(data || {});
|
|
20
21
|
// console.log(html);
|
|
21
22
|
return html;
|
|
22
23
|
}
|
|
23
24
|
return message;
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
// to do: refactor fastify-file to remove funcs completely
|
|
26
28
|
export default async function notification({
|
|
27
29
|
pg: pg1,
|
|
28
30
|
funcs,
|
|
@@ -67,7 +69,7 @@ export default async function notification({
|
|
|
67
69
|
|
|
68
70
|
try {
|
|
69
71
|
const html = await generateNotificationContent({
|
|
70
|
-
pg,
|
|
72
|
+
pg, table, template, id, message, data,
|
|
71
73
|
});
|
|
72
74
|
|
|
73
75
|
// return html;
|
|
@@ -86,7 +88,6 @@ export default async function notification({
|
|
|
86
88
|
const toEmail = Array.isArray(to) ? to.map((emails) => emails.match(emailReg)?.join(',')) : to;
|
|
87
89
|
|
|
88
90
|
const result = await sendEmail({
|
|
89
|
-
funcs,
|
|
90
91
|
attachments,
|
|
91
92
|
html,
|
|
92
93
|
subject: title,
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import nodemailer from 'nodemailer';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (!to?.length) {
|
|
17
|
-
throw new Error('empty to list');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const { mailSetting = {} } = config;
|
|
21
|
-
|
|
22
|
-
/*= == check service and setting === */
|
|
23
|
-
if (!mailSetting.service) {
|
|
24
|
-
throw new Error('service is not defined in config');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
Object.assign(mailSetting, { rejectUnauthorized: false });
|
|
28
|
-
|
|
29
|
-
if (mailSetting.port === 465) {
|
|
30
|
-
Object.assign(mailSetting, { secure: true });
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const transport = nodemailer.createTransport(mailSetting);
|
|
34
|
-
|
|
35
|
-
const result = await transport.sendMail({
|
|
36
|
-
from: from || mailSetting.from, to, subject, html, attachments,
|
|
37
|
-
});
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
1
|
+
import nodemailer from 'nodemailer';
|
|
2
|
+
|
|
3
|
+
import config from '../../../config.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Надсилає поваідомлення на пошту
|
|
7
|
+
*
|
|
8
|
+
* @type function
|
|
9
|
+
* @alias sendEmail
|
|
10
|
+
* @summary Функція здійснює розсилку по email
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export default async function sendEmail({
|
|
14
|
+
to, from, subject, html, attachments,
|
|
15
|
+
}) {
|
|
16
|
+
if (!to?.length) {
|
|
17
|
+
throw new Error('empty to list');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { mailSetting = {} } = config;
|
|
21
|
+
|
|
22
|
+
/*= == check service and setting === */
|
|
23
|
+
if (!mailSetting.service) {
|
|
24
|
+
throw new Error('service is not defined in config');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Object.assign(mailSetting, { rejectUnauthorized: false });
|
|
28
|
+
|
|
29
|
+
if (mailSetting.port === 465) {
|
|
30
|
+
Object.assign(mailSetting, { secure: true });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const transport = nodemailer.createTransport(mailSetting);
|
|
34
|
+
|
|
35
|
+
const result = await transport.sendMail({
|
|
36
|
+
from: from || mailSetting.from, to, subject, html, attachments,
|
|
37
|
+
});
|
|
38
|
+
return result;
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengis/fastify-table",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.44",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "core-plugins",
|
|
6
6
|
"main": "index.js",
|
|
@@ -9,16 +9,16 @@
|
|
|
9
9
|
"test": "node --test"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@opengis/fastify-hb": "^1.1.0",
|
|
13
12
|
"@fastify/sensible": "^5.0.0",
|
|
14
13
|
"@fastify/url-data": "^5.4.0",
|
|
14
|
+
"@opengis/fastify-hb": "^1.4.2",
|
|
15
15
|
"fastify": "^4.26.1",
|
|
16
16
|
"fastify-plugin": "^4.0.0",
|
|
17
17
|
"ioredis": "^5.3.2",
|
|
18
|
+
"nodemailer": "^6.5.0",
|
|
18
19
|
"pg": "^8.11.3",
|
|
19
20
|
"pino-abstract-transport": "^2.0.0",
|
|
20
|
-
"rotating-file-stream": "^3.2.3"
|
|
21
|
-
"nodemailer": "^6.5.0"
|
|
21
|
+
"rotating-file-stream": "^3.2.3"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"eslint": "^8.49.0",
|
|
@@ -26,4 +26,4 @@
|
|
|
26
26
|
},
|
|
27
27
|
"author": "Softpro",
|
|
28
28
|
"license": "ISC"
|
|
29
|
-
}
|
|
29
|
+
}
|
package/pg/funcs/getPG.js
CHANGED
|
@@ -7,7 +7,7 @@ function getPG(param) {
|
|
|
7
7
|
const {
|
|
8
8
|
user, password, host, port, db, database, name: origin, funcs,
|
|
9
9
|
} = param || {};
|
|
10
|
-
if (funcs?.config) Object.assign(config, { ...funcs.config }); // unit test
|
|
10
|
+
// if (funcs?.config) Object.assign(config, { ...funcs.config }); // unit test
|
|
11
11
|
const name = origin || db || database || param || 'client';
|
|
12
12
|
if (pgClients[name]) return pgClients[name];
|
|
13
13
|
|
package/redis/funcs/getRedis.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import Redis from 'ioredis';
|
|
2
|
-
import config from '../../config.js';
|
|
3
|
-
import redisClients from './redisClients.js';
|
|
4
|
-
|
|
5
|
-
function getRedis({ db } = { db: 0 }) {
|
|
6
|
-
if (!config.redis) return null;
|
|
7
|
-
if (redisClients[db]) return redisClients[db];
|
|
8
|
-
|
|
9
|
-
const redisConfig = {
|
|
10
|
-
db,
|
|
11
|
-
keyPrefix: `${config.db}:`,
|
|
12
|
-
host: config.redis?.host || '127.0.0.1',
|
|
13
|
-
port: config.redis?.port || 6379, // Redis port
|
|
14
|
-
family: 4, // 4 (IPv4) or 6 (IPv6)
|
|
15
|
-
closeClient: true,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
redisClients[db] = new Redis(redisConfig);
|
|
19
|
-
|
|
20
|
-
return redisClients[db];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default getRedis;
|
|
1
|
+
import Redis from 'ioredis';
|
|
2
|
+
import config from '../../config.js';
|
|
3
|
+
import redisClients from './redisClients.js';
|
|
4
|
+
|
|
5
|
+
function getRedis({ db } = { db: 0 }) {
|
|
6
|
+
if (!config.redis) return null;
|
|
7
|
+
if (redisClients[db]) return redisClients[db];
|
|
8
|
+
|
|
9
|
+
const redisConfig = {
|
|
10
|
+
db,
|
|
11
|
+
keyPrefix: `${config.db}:`,
|
|
12
|
+
host: config.redis?.host || '127.0.0.1',
|
|
13
|
+
port: config.redis?.port || 6379, // Redis port
|
|
14
|
+
family: 4, // 4 (IPv4) or 6 (IPv6)
|
|
15
|
+
closeClient: true,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
redisClients[db] = new Redis(redisConfig);
|
|
19
|
+
|
|
20
|
+
return redisClients[db];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default getRedis;
|