@opengis/cms 0.0.57 → 0.0.58
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/README.md +131 -131
- package/dist/AddNewItemInTree-05PSSEFi.js +76 -0
- package/dist/ArticlesPage-CFjE_cw_.js +298 -0
- package/dist/CollectionsBreadcrumb-BCxeRikP.js +4 -0
- package/dist/CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-umRzB5mY.js +53 -0
- package/dist/CollectionsPage-DHfPNql6.js +124 -0
- package/dist/{CreateForm-BMOBeP4G.js → CreateForm-5FvT45vH.js} +1 -1
- package/dist/Dashboard-C1eGscNd.js +358 -0
- package/dist/EditCollectionPage-DIr1tdtn.js +187 -0
- package/dist/{EmptyData-DaZt_nAm.js → EmptyData-DxPrSXhV.js} +1 -1
- package/dist/{MenuAddPage-Bf48Z-ah.js → MenuAddPage-D-p3gFgm.js} +40 -35
- package/dist/MenuBody-rN5j4YBu.js +125 -0
- package/dist/MenuItemPage-BoJw885D.js +1027 -0
- package/dist/MenuList-DFEBS0NB.js +172 -0
- package/dist/MenuPage-BCZB_S8j.js +107 -0
- package/dist/MenuWrapper-AZ_8s-zd.js +12 -0
- package/dist/MonacoEditor-Db-3Jc3E.js +4 -0
- package/dist/{UniversalTable.vue_vue_type_script_setup_true_lang-CJGTsd1V.js → UniversalTable-CzqPG-tY.js} +12 -12
- package/dist/{UniversalTablePagination.vue_vue_type_script_setup_true_lang-GYZd_gkA.js → UniversalTablePagination-4gL47A7I.js} +1 -1
- package/dist/VsFormTags-CMjiu9sY.js +114 -0
- package/dist/VsPreview-DwETkOpb.js +63 -0
- package/dist/contentForm-CtMhQTG0.js +489 -0
- package/dist/getField-CpwVE28P.js +179 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.html +29 -29
- package/dist/index.js +72 -71
- package/dist/style.css +1 -1
- package/dist/vs-builder-edit-D-q1o8tF.js +604 -0
- package/dist/vs-builder-monaco-B3Jj0V31.js +33 -0
- package/dist/vs-builder-preview-BH4VAM3a.js +44 -0
- package/dist/vs-form-custom-datatable-BDZo48w3.js +317 -0
- package/dist/vs-form-integer-BZ855R3g.js +61 -0
- package/dist/vs-form-media-select-NY27EaG1.js +837 -0
- package/dist/vs-form-reference-list-Dtv8fJJU.js +1536 -0
- package/dist/vs-form-reletion-link-BhzNQszm.js +34 -0
- package/dist/vs-form-tiptap-DDFQjRjY.js +4 -0
- package/dist/vs-form-tiptap.vue_vue_type_script_setup_true_lang-DGgsqXwg.js +11 -0
- package/dist/vs-richtext-md-C098v_6Q.js +4 -0
- package/dist/vs-richtext-md.vue_vue_type_script_setup_true_lang-Ct8uTV-J.js +14 -0
- package/input-types.json +9 -9
- package/locales/en.json +815 -814
- package/locales/uk.json +813 -812
- package/module/cms/cls/content.status.json +17 -17
- package/module/cms/cls/user_type.json +9 -9
- package/module/cms/form/admin.users.form.json +77 -77
- package/module/cms/select/cms.page_type.sql +1 -1
- package/module/cms/select/news_tag_id.sql +11 -11
- package/module/cms/table/admin.users.table.json +53 -53
- package/module/cms/table/collection.default.table.json +96 -96
- package/module/cms/table/single.default.table.json +116 -116
- package/package.json +68 -68
- package/plugin.js +43 -43
- package/server/app.js +35 -35
- package/server/config.js +4 -4
- package/server/functions/getContent.js +45 -45
- package/server/functions/getDraftKey.js +22 -22
- package/server/functions/getSearchData.js +31 -31
- package/server/functions/getTags.js +30 -30
- package/server/functions/getUser.js +27 -27
- package/server/functions/utils/mock.reply.js +55 -55
- package/server/index.js +22 -22
- package/server/migrations/fixes.sql +129 -129
- package/server/migrations/site.sql +595 -595
- package/server/plugins/adminHook.js +78 -78
- package/server/plugins/hook.js +59 -59
- package/server/plugins/vite.js +75 -75
- package/server/routes/category/controllers/cms.category.delete.js +21 -21
- package/server/routes/category/controllers/cms.category.get.js +17 -17
- package/server/routes/category/controllers/cms.category.list.js +16 -16
- package/server/routes/category/controllers/cms.category.post.js +21 -21
- package/server/routes/category/controllers/cms.category.put.js +23 -23
- package/server/routes/category/index.mjs +22 -22
- package/server/routes/cms/controllers/cmsStat.js +55 -55
- package/server/routes/cms/controllers/cmsSuggest.js +57 -57
- package/server/routes/cms/controllers/deleteContent.js +113 -113
- package/server/routes/cms/controllers/deleteMedia.js +76 -76
- package/server/routes/cms/controllers/downloadMedia.js +84 -84
- package/server/routes/cms/controllers/getContent.js +113 -113
- package/server/routes/cms/controllers/getContentBySlug.js +93 -93
- package/server/routes/cms/controllers/insertContent.js +217 -217
- package/server/routes/cms/controllers/listMedia.js +155 -155
- package/server/routes/cms/controllers/metadataMedia.js +39 -39
- package/server/routes/cms/controllers/properties.get.js +18 -18
- package/server/routes/cms/controllers/properties.post.js +99 -99
- package/server/routes/cms/controllers/searchContent.js +214 -214
- package/server/routes/cms/controllers/translate.js +89 -89
- package/server/routes/cms/controllers/updateContent.js +266 -266
- package/server/routes/cms/controllers/uploadMedia.js +79 -79
- package/server/routes/cms/functions/getSettings.js +48 -48
- package/server/routes/cms/index.mjs +112 -112
- package/server/routes/cms/utils/additionalData.js +35 -35
- package/server/routes/cms/utils/getCollection.js +89 -89
- package/server/routes/cms/utils/getSingle.js +188 -188
- package/server/routes/cms/utils/inputTypes.js +5 -5
- package/server/routes/cms/utils/insertContentLocalization.js +104 -104
- package/server/routes/cms/utils/requestTranslation.js +85 -85
- package/server/routes/cms/utils/updateLocalization.js +47 -47
- package/server/routes/cmsSpace/controllers/deleteSpace.js +25 -25
- package/server/routes/cmsSpace/controllers/getSpaces.js +27 -27
- package/server/routes/cmsSpace/controllers/insertSpace.js +21 -21
- package/server/routes/cmsSpace/controllers/updateSpace.js +23 -23
- package/server/routes/cmsSpace/index.mjs +20 -20
- package/server/routes/contentType/controllers/addContentType.js +160 -160
- package/server/routes/contentType/controllers/contentTypeList.js +54 -54
- package/server/routes/contentType/controllers/delContentType.js +75 -75
- package/server/routes/contentType/controllers/editContentType.js +88 -88
- package/server/routes/contentType/controllers/getContentType.js +65 -65
- package/server/routes/contentType/index.mjs +35 -35
- package/server/routes/contentType/utils/updateContents.js +44 -44
- package/server/routes/contentType/utils/updateCustomContentTable.js +53 -53
- package/server/routes/feedback/controllers/email.list.js +24 -24
- package/server/routes/feedback/controllers/feedback.js +48 -48
- package/server/routes/feedback/controllers/feedback.list.js +37 -37
- package/server/routes/feedback/controllers/news.subscriptions.js +44 -44
- package/server/routes/feedback/index.mjs +71 -71
- package/server/routes/logs/controllers/export.user.logs.js +77 -77
- package/server/routes/logs/controllers/user.logs.js +44 -44
- package/server/routes/logs/index.mjs +9 -9
- package/server/routes/menu/controllers/addMenu.js +37 -37
- package/server/routes/menu/controllers/delMenu.js +31 -31
- package/server/routes/menu/controllers/editMenu.js +41 -41
- package/server/routes/menu/controllers/getMenu.js +24 -24
- package/server/routes/menu/functions/getMenu.js +50 -50
- package/server/routes/menu/index.mjs +13 -13
- package/server/routes/migration/controllers/collectionToCustom.js +137 -137
- package/server/routes/migration/index.mjs +8 -8
- package/server/routes/root.mjs +8 -8
- package/server/routes/tags/controllers/add.tags.js +24 -24
- package/server/routes/tags/controllers/del.tags.js +19 -19
- package/server/routes/tags/controllers/edit.tags.js +25 -25
- package/server/routes/tags/controllers/get.tags.js +15 -15
- package/server/routes/tags/index.mjs +14 -14
- package/server/templates/cls/cms.category_type.json +9 -9
- package/server/templates/cls/cms.content_review_status.json +9 -9
- package/server/templates/cls/cms.content_status.json +9 -9
- package/server/templates/cls/cms.content_type.json +9 -9
- package/server/templates/cls/cms.lang.json +9 -9
- package/server/templates/page/login.html +126 -126
- package/utils.d.ts +52 -52
- package/utils.js +8 -8
- package/dist/ArticlesPage-BcR1hbds.js +0 -286
- package/dist/BuilderPage-CK_osM89.js +0 -386
- package/dist/CollectionsBreadcrumb.vue_vue_type_script_setup_true_lang-CnOe9ORD.js +0 -45
- package/dist/CollectionsPage-JfmrHNR_.js +0 -110
- package/dist/EditCollectionPage-Cw3GQYRe.js +0 -809
- package/dist/MenuItemPage-CXn5HC8j.js +0 -1366
- package/dist/MenuPage-tJZtK46W.js +0 -106
- package/dist/contentForm-B6gHgGkz.js +0 -586
- package/dist/getField-Y5WXnRR0.js +0 -2948
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
import { getMeta } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
import inputTypes from '../../cms/utils/inputTypes.js';
|
|
4
|
-
|
|
5
|
-
const types = {
|
|
6
|
-
number: 'numeric',
|
|
7
|
-
datetime: 'timestamp without time zone',
|
|
8
|
-
boolean: 'boolean',
|
|
9
|
-
date: 'date',
|
|
10
|
-
array: 'text[]',
|
|
11
|
-
FileList: 'text[]',
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default async function updateCustomContentTable({ pg, id, columns = [] }) {
|
|
15
|
-
if (!pg?.pk || !id) return null;
|
|
16
|
-
|
|
17
|
-
const { table_name: tablename, dbcolumns } = await pg.query(
|
|
18
|
-
`select table_name, columns as dbcolumns from site.content_types where content_type_id = $1`,
|
|
19
|
-
[id],
|
|
20
|
-
).then(el => el.rows?.[0] || {});
|
|
21
|
-
|
|
22
|
-
if (!tablename) return null;
|
|
23
|
-
|
|
24
|
-
const droppedColumns = (dbcolumns || []).filter(el => columns.findIndex(col => col.name === el.name) === -1);
|
|
25
|
-
// console.log(droppedColumns);
|
|
26
|
-
|
|
27
|
-
const q = `create table if not exists data."${tablename}"
|
|
28
|
-
( id text not null default next_id() PRIMARY KEY );
|
|
29
|
-
${droppedColumns.map(col => `
|
|
30
|
-
alter table data."${tablename}" add column if not exists "${col.name}" text;
|
|
31
|
-
alter table data."${tablename}" alter column "${col.name}" drop not null;`).join('\n')}
|
|
32
|
-
${columns?.filter?.(col => col.name)?.map?.(col => `
|
|
33
|
-
alter table data."${tablename}" add column if not exists "${col.name}" ${types[col.type] || inputTypes[col.type] || 'text'} ${col.required ? ' not null ' : ''};
|
|
34
|
-
alter table data."${tablename}" alter column "${col.name}" ${col.required ? ' set ' : ' drop '} not null;
|
|
35
|
-
alter table data."${tablename}" alter column "${col.name}" set default ${col.default ? col.default : 'null'};
|
|
36
|
-
comment on column data."${tablename}"."${col.name}" is ${col.label ? `'${col.label.replace(/'/g, "''")}'` : 'null'} `
|
|
37
|
-
).join(';') || ''}`;
|
|
38
|
-
await pg.query(q);
|
|
39
|
-
await pg.query(`alter table data."${tablename}" add column if not exists created_at timestamp with time zone not null default now()`);
|
|
40
|
-
await pg.query(`alter table data."${tablename}" add column if not exists updated_at timestamp with time zone not null default now()`);
|
|
41
|
-
await pg.query(`alter table data."${tablename}" add column if not exists created_by text`);
|
|
42
|
-
await pg.query(`alter table data."${tablename}" add column if not exists updated_by text`);
|
|
43
|
-
await pg.query(`alter table data."${tablename}" drop constraint if exists c${id}_slug_unique;alter table data."${tablename}" add constraint c${id}_slug_unique UNIQUE (slug);`);
|
|
44
|
-
|
|
45
|
-
// force meta columns refresh to avoid crud skips
|
|
46
|
-
await getMeta({ pg, table: `data.${tablename}` }, true);
|
|
47
|
-
|
|
48
|
-
// if (pg?.pk && pg.tlist && !pg.tlist.find(el => el === `data.${tablename}`)) {
|
|
49
|
-
// pg.pk[`data.${tablename}`] = 'id';
|
|
50
|
-
// pg.tlist?.push?.(`data.${tablename}`);
|
|
51
|
-
// }
|
|
52
|
-
|
|
53
|
-
return null;
|
|
1
|
+
import { getMeta } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
import inputTypes from '../../cms/utils/inputTypes.js';
|
|
4
|
+
|
|
5
|
+
const types = {
|
|
6
|
+
number: 'numeric',
|
|
7
|
+
datetime: 'timestamp without time zone',
|
|
8
|
+
boolean: 'boolean',
|
|
9
|
+
date: 'date',
|
|
10
|
+
array: 'text[]',
|
|
11
|
+
FileList: 'text[]',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default async function updateCustomContentTable({ pg, id, columns = [] }) {
|
|
15
|
+
if (!pg?.pk || !id) return null;
|
|
16
|
+
|
|
17
|
+
const { table_name: tablename, dbcolumns } = await pg.query(
|
|
18
|
+
`select table_name, columns as dbcolumns from site.content_types where content_type_id = $1`,
|
|
19
|
+
[id],
|
|
20
|
+
).then(el => el.rows?.[0] || {});
|
|
21
|
+
|
|
22
|
+
if (!tablename) return null;
|
|
23
|
+
|
|
24
|
+
const droppedColumns = (dbcolumns || []).filter(el => columns.findIndex(col => col.name === el.name) === -1);
|
|
25
|
+
// console.log(droppedColumns);
|
|
26
|
+
|
|
27
|
+
const q = `create table if not exists data."${tablename}"
|
|
28
|
+
( id text not null default next_id() PRIMARY KEY );
|
|
29
|
+
${droppedColumns.map(col => `
|
|
30
|
+
alter table data."${tablename}" add column if not exists "${col.name}" text;
|
|
31
|
+
alter table data."${tablename}" alter column "${col.name}" drop not null;`).join('\n')}
|
|
32
|
+
${columns?.filter?.(col => col.name)?.map?.(col => `
|
|
33
|
+
alter table data."${tablename}" add column if not exists "${col.name}" ${types[col.type] || inputTypes[col.type] || 'text'} ${col.required ? ' not null ' : ''};
|
|
34
|
+
alter table data."${tablename}" alter column "${col.name}" ${col.required ? ' set ' : ' drop '} not null;
|
|
35
|
+
alter table data."${tablename}" alter column "${col.name}" set default ${col.default ? col.default : 'null'};
|
|
36
|
+
comment on column data."${tablename}"."${col.name}" is ${col.label ? `'${col.label.replace(/'/g, "''")}'` : 'null'} `
|
|
37
|
+
).join(';') || ''}`;
|
|
38
|
+
await pg.query(q);
|
|
39
|
+
await pg.query(`alter table data."${tablename}" add column if not exists created_at timestamp with time zone not null default now()`);
|
|
40
|
+
await pg.query(`alter table data."${tablename}" add column if not exists updated_at timestamp with time zone not null default now()`);
|
|
41
|
+
await pg.query(`alter table data."${tablename}" add column if not exists created_by text`);
|
|
42
|
+
await pg.query(`alter table data."${tablename}" add column if not exists updated_by text`);
|
|
43
|
+
await pg.query(`alter table data."${tablename}" drop constraint if exists c${id}_slug_unique;alter table data."${tablename}" add constraint c${id}_slug_unique UNIQUE (slug);`);
|
|
44
|
+
|
|
45
|
+
// force meta columns refresh to avoid crud skips
|
|
46
|
+
await getMeta({ pg, table: `data.${tablename}` }, true);
|
|
47
|
+
|
|
48
|
+
// if (pg?.pk && pg.tlist && !pg.tlist.find(el => el === `data.${tablename}`)) {
|
|
49
|
+
// pg.pk[`data.${tablename}`] = 'id';
|
|
50
|
+
// pg.tlist?.push?.(`data.${tablename}`);
|
|
51
|
+
// }
|
|
52
|
+
|
|
53
|
+
return null;
|
|
54
54
|
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
export default async function feedbackList(req, reply) {
|
|
2
|
-
const { pg, user = {}, query } = req;
|
|
3
|
-
const { uid } = user;
|
|
4
|
-
if (!uid) return reply.code(401).send({ message: 'Not authorized', status: 401 });
|
|
5
|
-
|
|
6
|
-
const { page = 1, limit = 16 } = query;
|
|
7
|
-
const offset = limit * (page - 1) || 0;
|
|
8
|
-
|
|
9
|
-
const { total, filtered } = await pg.one(`select count(*)::int as total from site.feedback`)
|
|
10
|
-
|
|
11
|
-
const { rows = [] } = await pg.query(`
|
|
12
|
-
select
|
|
13
|
-
row_number() over(order by created_at desc) as num,
|
|
14
|
-
subscription_id,
|
|
15
|
-
email,
|
|
16
|
-
created_at,
|
|
17
|
-
enabled
|
|
18
|
-
from site.subscription
|
|
19
|
-
order by created_at desc
|
|
20
|
-
limit ${limit} offset ${offset}
|
|
21
|
-
`);
|
|
22
|
-
|
|
23
|
-
const status = rows?.length ? 200 : 204;
|
|
24
|
-
return reply.code(status).send({ message: { total, filtered, rows }, status })
|
|
1
|
+
export default async function feedbackList(req, reply) {
|
|
2
|
+
const { pg, user = {}, query } = req;
|
|
3
|
+
const { uid } = user;
|
|
4
|
+
if (!uid) return reply.code(401).send({ message: 'Not authorized', status: 401 });
|
|
5
|
+
|
|
6
|
+
const { page = 1, limit = 16 } = query;
|
|
7
|
+
const offset = limit * (page - 1) || 0;
|
|
8
|
+
|
|
9
|
+
const { total, filtered } = await pg.one(`select count(*)::int as total from site.feedback`)
|
|
10
|
+
|
|
11
|
+
const { rows = [] } = await pg.query(`
|
|
12
|
+
select
|
|
13
|
+
row_number() over(order by created_at desc) as num,
|
|
14
|
+
subscription_id,
|
|
15
|
+
email,
|
|
16
|
+
created_at,
|
|
17
|
+
enabled
|
|
18
|
+
from site.subscription
|
|
19
|
+
order by created_at desc
|
|
20
|
+
limit ${limit} offset ${offset}
|
|
21
|
+
`);
|
|
22
|
+
|
|
23
|
+
const status = rows?.length ? 200 : 204;
|
|
24
|
+
return reply.code(status).send({ message: { total, filtered, rows }, status })
|
|
25
25
|
}
|
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
import { pgClients, dataInsert, config } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
const refererAllow = config?.refererAllow || ['127.0.0.1', 'localhost', 'softpro.ua', 'opengis.info'];
|
|
4
|
-
|
|
5
|
-
function checkReferer(headers) {
|
|
6
|
-
if (config?.local) return true;
|
|
7
|
-
if (!headers?.referer) return false;
|
|
8
|
-
return refererAllow.some(allowed => headers.referer.includes(allowed));
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default async function feedback({ body = {}, pg = pgClients.client, headers, params }, reply) {
|
|
12
|
-
reply
|
|
13
|
-
.header('Access-Control-Allow-Origin', '*')
|
|
14
|
-
.header('Access-Control-Allow-Methods', 'POST, OPTIONS')
|
|
15
|
-
.header('Access-Control-Allow-Headers', 'Content-Type');
|
|
16
|
-
|
|
17
|
-
if (!checkReferer(headers)) {
|
|
18
|
-
return reply.status(403).send('access restricted');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if ((params?.type !== 'vacancy') && (!body?.message_text || !body?.email)) {
|
|
22
|
-
return reply.status(400).send('message_text and email is required');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if ((params?.type === 'vacancy') && !body?.user_name) {
|
|
26
|
-
return reply.status(400).send('user_name is required');
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const allowedFields = ['title', 'message_text', 'email', 'phone', 'user_name', 'resume_link', 'linkedin_link', 'portfolio_link', 'telegram_link'];
|
|
30
|
-
const data = Object.fromEntries(
|
|
31
|
-
Object.entries(body).filter(([key]) => allowedFields.includes(key))
|
|
32
|
-
);
|
|
33
|
-
data["feedback_type"] = params?.type;
|
|
34
|
-
|
|
35
|
-
const { rows } = await dataInsert({
|
|
36
|
-
table: 'site.feedback',
|
|
37
|
-
data: {
|
|
38
|
-
...data,
|
|
39
|
-
headers
|
|
40
|
-
},
|
|
41
|
-
pg
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
if (!rows?.length) {
|
|
45
|
-
return reply.status(500).send('insert error');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return reply.status(200).send('Звернення додано успішно');
|
|
1
|
+
import { pgClients, dataInsert, config } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
const refererAllow = config?.refererAllow || ['127.0.0.1', 'localhost', 'softpro.ua', 'opengis.info'];
|
|
4
|
+
|
|
5
|
+
function checkReferer(headers) {
|
|
6
|
+
if (config?.local) return true;
|
|
7
|
+
if (!headers?.referer) return false;
|
|
8
|
+
return refererAllow.some(allowed => headers.referer.includes(allowed));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default async function feedback({ body = {}, pg = pgClients.client, headers, params }, reply) {
|
|
12
|
+
reply
|
|
13
|
+
.header('Access-Control-Allow-Origin', '*')
|
|
14
|
+
.header('Access-Control-Allow-Methods', 'POST, OPTIONS')
|
|
15
|
+
.header('Access-Control-Allow-Headers', 'Content-Type');
|
|
16
|
+
|
|
17
|
+
if (!checkReferer(headers)) {
|
|
18
|
+
return reply.status(403).send('access restricted');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if ((params?.type !== 'vacancy') && (!body?.message_text || !body?.email)) {
|
|
22
|
+
return reply.status(400).send('message_text and email is required');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if ((params?.type === 'vacancy') && !body?.user_name) {
|
|
26
|
+
return reply.status(400).send('user_name is required');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const allowedFields = ['title', 'message_text', 'email', 'phone', 'user_name', 'resume_link', 'linkedin_link', 'portfolio_link', 'telegram_link'];
|
|
30
|
+
const data = Object.fromEntries(
|
|
31
|
+
Object.entries(body).filter(([key]) => allowedFields.includes(key))
|
|
32
|
+
);
|
|
33
|
+
data["feedback_type"] = params?.type;
|
|
34
|
+
|
|
35
|
+
const { rows } = await dataInsert({
|
|
36
|
+
table: 'site.feedback',
|
|
37
|
+
data: {
|
|
38
|
+
...data,
|
|
39
|
+
headers
|
|
40
|
+
},
|
|
41
|
+
pg
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (!rows?.length) {
|
|
45
|
+
return reply.status(500).send('insert error');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return reply.status(200).send('Звернення додано успішно');
|
|
49
49
|
}
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import { getFilterSQL } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
export default async function feedbackList(req, reply) {
|
|
4
|
-
const { pg, user = {}, query } = req;
|
|
5
|
-
const { uid } = user;
|
|
6
|
-
if (!uid) return reply.code(401).send({ message: 'Not authorized', status: 401 });
|
|
7
|
-
|
|
8
|
-
const { page = 1, limit = 16, filter = null } = query;
|
|
9
|
-
const offset = limit * (page - 1) || 0;
|
|
10
|
-
|
|
11
|
-
const { q: filterQuery } = await getFilterSQL({
|
|
12
|
-
filter, table: 'site.feedback'
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const { total, filtered } = await pg.one(`select count(*)::int as total, (count(*) filter(where ${filterQuery ? `${filterQuery}` : '1=1'}))::int as filtered from site.feedback`)
|
|
16
|
-
|
|
17
|
-
const { rows = [] } = await pg.query(`
|
|
18
|
-
select
|
|
19
|
-
row_number() over(order by created_at desc) as num,
|
|
20
|
-
email,
|
|
21
|
-
message_id,
|
|
22
|
-
user_name,
|
|
23
|
-
message_text,
|
|
24
|
-
feedback_type,
|
|
25
|
-
phone,
|
|
26
|
-
created_at,
|
|
27
|
-
linkedin_link,
|
|
28
|
-
portfolio_link,
|
|
29
|
-
telegram_link
|
|
30
|
-
from site.feedback
|
|
31
|
-
where created_at is not null ${filterQuery ? `and ${filterQuery}` : ''}
|
|
32
|
-
order by created_at desc
|
|
33
|
-
limit ${limit} offset ${offset}
|
|
34
|
-
`);
|
|
35
|
-
|
|
36
|
-
const status = rows?.length ? 200 : 204;
|
|
37
|
-
return reply.code(status).send({ message: { total, filtered, rows }, status })
|
|
1
|
+
import { getFilterSQL } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
export default async function feedbackList(req, reply) {
|
|
4
|
+
const { pg, user = {}, query } = req;
|
|
5
|
+
const { uid } = user;
|
|
6
|
+
if (!uid) return reply.code(401).send({ message: 'Not authorized', status: 401 });
|
|
7
|
+
|
|
8
|
+
const { page = 1, limit = 16, filter = null } = query;
|
|
9
|
+
const offset = limit * (page - 1) || 0;
|
|
10
|
+
|
|
11
|
+
const { q: filterQuery } = await getFilterSQL({
|
|
12
|
+
filter, table: 'site.feedback'
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const { total, filtered } = await pg.one(`select count(*)::int as total, (count(*) filter(where ${filterQuery ? `${filterQuery}` : '1=1'}))::int as filtered from site.feedback`)
|
|
16
|
+
|
|
17
|
+
const { rows = [] } = await pg.query(`
|
|
18
|
+
select
|
|
19
|
+
row_number() over(order by created_at desc) as num,
|
|
20
|
+
email,
|
|
21
|
+
message_id,
|
|
22
|
+
user_name,
|
|
23
|
+
message_text,
|
|
24
|
+
feedback_type,
|
|
25
|
+
phone,
|
|
26
|
+
created_at,
|
|
27
|
+
linkedin_link,
|
|
28
|
+
portfolio_link,
|
|
29
|
+
telegram_link
|
|
30
|
+
from site.feedback
|
|
31
|
+
where created_at is not null ${filterQuery ? `and ${filterQuery}` : ''}
|
|
32
|
+
order by created_at desc
|
|
33
|
+
limit ${limit} offset ${offset}
|
|
34
|
+
`);
|
|
35
|
+
|
|
36
|
+
const status = rows?.length ? 200 : 204;
|
|
37
|
+
return reply.code(status).send({ message: { total, filtered, rows }, status })
|
|
38
38
|
}
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import { pgClients, config } from '@opengis/fastify-table/utils.js';
|
|
2
|
-
|
|
3
|
-
const refererAllow = config?.refererAllow || ['127.0.0.1', 'localhost', 'softpro.ua', 'opengis.info'];
|
|
4
|
-
|
|
5
|
-
function checkReferer(headers) {
|
|
6
|
-
if (config?.local) return true;
|
|
7
|
-
if (!headers?.referer) return false;
|
|
8
|
-
return refererAllow.some(allowed => headers.referer.includes(allowed));
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export default async function subscribeToNews({
|
|
12
|
-
body = {},
|
|
13
|
-
pg = pgClients.client,
|
|
14
|
-
headers
|
|
15
|
-
}, reply) {
|
|
16
|
-
reply
|
|
17
|
-
.header('Access-Control-Allow-Origin', '*')
|
|
18
|
-
.header('Access-Control-Allow-Methods', 'POST, OPTIONS')
|
|
19
|
-
.header('Access-Control-Allow-Headers', 'Content-Type');
|
|
20
|
-
|
|
21
|
-
if (!checkReferer(headers)) {
|
|
22
|
-
return reply.status(403).send('access restricted');
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const { email } = body;
|
|
26
|
-
if (!email) return reply.status(400).send('email is required');
|
|
27
|
-
|
|
28
|
-
const { rows: subscriptions } = await pg.query(`
|
|
29
|
-
SELECT subscription_id
|
|
30
|
-
FROM site.subscription
|
|
31
|
-
WHERE email = $1
|
|
32
|
-
LIMIT 1
|
|
33
|
-
`, [email]);
|
|
34
|
-
|
|
35
|
-
if (subscriptions?.length === 0) {
|
|
36
|
-
await pg.query(`
|
|
37
|
-
INSERT INTO site.subscription (email)
|
|
38
|
-
VALUES ($1)
|
|
39
|
-
`, [email]);
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return reply.status(200).send('Успішно');
|
|
44
|
-
}
|
|
1
|
+
import { pgClients, config } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
const refererAllow = config?.refererAllow || ['127.0.0.1', 'localhost', 'softpro.ua', 'opengis.info'];
|
|
4
|
+
|
|
5
|
+
function checkReferer(headers) {
|
|
6
|
+
if (config?.local) return true;
|
|
7
|
+
if (!headers?.referer) return false;
|
|
8
|
+
return refererAllow.some(allowed => headers.referer.includes(allowed));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default async function subscribeToNews({
|
|
12
|
+
body = {},
|
|
13
|
+
pg = pgClients.client,
|
|
14
|
+
headers
|
|
15
|
+
}, reply) {
|
|
16
|
+
reply
|
|
17
|
+
.header('Access-Control-Allow-Origin', '*')
|
|
18
|
+
.header('Access-Control-Allow-Methods', 'POST, OPTIONS')
|
|
19
|
+
.header('Access-Control-Allow-Headers', 'Content-Type');
|
|
20
|
+
|
|
21
|
+
if (!checkReferer(headers)) {
|
|
22
|
+
return reply.status(403).send('access restricted');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { email } = body;
|
|
26
|
+
if (!email) return reply.status(400).send('email is required');
|
|
27
|
+
|
|
28
|
+
const { rows: subscriptions } = await pg.query(`
|
|
29
|
+
SELECT subscription_id
|
|
30
|
+
FROM site.subscription
|
|
31
|
+
WHERE email = $1
|
|
32
|
+
LIMIT 1
|
|
33
|
+
`, [email]);
|
|
34
|
+
|
|
35
|
+
if (subscriptions?.length === 0) {
|
|
36
|
+
await pg.query(`
|
|
37
|
+
INSERT INTO site.subscription (email)
|
|
38
|
+
VALUES ($1)
|
|
39
|
+
`, [email]);
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return reply.status(200).send('Успішно');
|
|
44
|
+
}
|
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
import feedback from './controllers/feedback.js';
|
|
2
|
-
import newsSubs from './controllers/news.subscriptions.js';
|
|
3
|
-
import feedbackList from './controllers/feedback.list.js';
|
|
4
|
-
import emailList from './controllers/email.list.js';
|
|
5
|
-
|
|
6
|
-
export default async function route(fastify) {
|
|
7
|
-
fastify.route({
|
|
8
|
-
method: 'POST',
|
|
9
|
-
url: '/cms-feedback/:type',
|
|
10
|
-
handler: feedback,
|
|
11
|
-
config: {
|
|
12
|
-
policy: ['public'],
|
|
13
|
-
},
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
fastify.route({
|
|
17
|
-
method: 'GET',
|
|
18
|
-
url: '/feedback',
|
|
19
|
-
handler: feedbackList,
|
|
20
|
-
config: {
|
|
21
|
-
policy: ['public'],
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
fastify.route({
|
|
26
|
-
method: 'GET',
|
|
27
|
-
url: '/email-list',
|
|
28
|
-
handler: emailList,
|
|
29
|
-
config: {
|
|
30
|
-
policy: ['public'],
|
|
31
|
-
},
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
fastify.route({
|
|
35
|
-
method: 'OPTIONS',
|
|
36
|
-
url: '/cms-feedback/:type',
|
|
37
|
-
handler: (req, reply) => {
|
|
38
|
-
reply
|
|
39
|
-
.header('Access-Control-Allow-Origin', '*')
|
|
40
|
-
.header('Access-Control-Allow-Methods', 'POST, OPTIONS')
|
|
41
|
-
.header('Access-Control-Allow-Headers', 'Content-Type')
|
|
42
|
-
.send();
|
|
43
|
-
},
|
|
44
|
-
config: {
|
|
45
|
-
policy: ['public'],
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
fastify.route({
|
|
50
|
-
method: 'POST',
|
|
51
|
-
url: '/cms-subscribtion',
|
|
52
|
-
handler: newsSubs,
|
|
53
|
-
config: {
|
|
54
|
-
policy: ['public'],
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
fastify.route({
|
|
59
|
-
method: 'OPTIONS',
|
|
60
|
-
url: '/cms-subscribtion',
|
|
61
|
-
handler: (req, reply) => {
|
|
62
|
-
reply
|
|
63
|
-
.header('Access-Control-Allow-Origin', '*')
|
|
64
|
-
.header('Access-Control-Allow-Methods', 'POST, OPTIONS')
|
|
65
|
-
.header('Access-Control-Allow-Headers', 'Content-Type')
|
|
66
|
-
.send();
|
|
67
|
-
},
|
|
68
|
-
config: {
|
|
69
|
-
policy: ['public'],
|
|
70
|
-
},
|
|
71
|
-
});
|
|
1
|
+
import feedback from './controllers/feedback.js';
|
|
2
|
+
import newsSubs from './controllers/news.subscriptions.js';
|
|
3
|
+
import feedbackList from './controllers/feedback.list.js';
|
|
4
|
+
import emailList from './controllers/email.list.js';
|
|
5
|
+
|
|
6
|
+
export default async function route(fastify) {
|
|
7
|
+
fastify.route({
|
|
8
|
+
method: 'POST',
|
|
9
|
+
url: '/cms-feedback/:type',
|
|
10
|
+
handler: feedback,
|
|
11
|
+
config: {
|
|
12
|
+
policy: ['public'],
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
fastify.route({
|
|
17
|
+
method: 'GET',
|
|
18
|
+
url: '/feedback',
|
|
19
|
+
handler: feedbackList,
|
|
20
|
+
config: {
|
|
21
|
+
policy: ['public'],
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
fastify.route({
|
|
26
|
+
method: 'GET',
|
|
27
|
+
url: '/email-list',
|
|
28
|
+
handler: emailList,
|
|
29
|
+
config: {
|
|
30
|
+
policy: ['public'],
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
fastify.route({
|
|
35
|
+
method: 'OPTIONS',
|
|
36
|
+
url: '/cms-feedback/:type',
|
|
37
|
+
handler: (req, reply) => {
|
|
38
|
+
reply
|
|
39
|
+
.header('Access-Control-Allow-Origin', '*')
|
|
40
|
+
.header('Access-Control-Allow-Methods', 'POST, OPTIONS')
|
|
41
|
+
.header('Access-Control-Allow-Headers', 'Content-Type')
|
|
42
|
+
.send();
|
|
43
|
+
},
|
|
44
|
+
config: {
|
|
45
|
+
policy: ['public'],
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
fastify.route({
|
|
50
|
+
method: 'POST',
|
|
51
|
+
url: '/cms-subscribtion',
|
|
52
|
+
handler: newsSubs,
|
|
53
|
+
config: {
|
|
54
|
+
policy: ['public'],
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
fastify.route({
|
|
59
|
+
method: 'OPTIONS',
|
|
60
|
+
url: '/cms-subscribtion',
|
|
61
|
+
handler: (req, reply) => {
|
|
62
|
+
reply
|
|
63
|
+
.header('Access-Control-Allow-Origin', '*')
|
|
64
|
+
.header('Access-Control-Allow-Methods', 'POST, OPTIONS')
|
|
65
|
+
.header('Access-Control-Allow-Headers', 'Content-Type')
|
|
66
|
+
.send();
|
|
67
|
+
},
|
|
68
|
+
config: {
|
|
69
|
+
policy: ['public'],
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
72
|
}
|