@opengis/gis 0.2.168 → 0.2.170
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/{CardIcon-DzERD2T8.js → CardIcon-DXaESte6.js} +1 -1
- package/dist/{EntityTablePage-DAVJRQLe.js → EntityTablePage-BwyMNhrm.js} +1 -1
- package/dist/{ExtentOutlineLayer.vue_vue_type_script_setup_true_lang-B-6axJUY.js → ExtentOutlineLayer.vue_vue_type_script_setup_true_lang-DrHke0pk.js} +1 -1
- package/dist/{HeaderActions.vue_vue_type_script_setup_true_lang-D1iwSeRN.js → HeaderActions.vue_vue_type_script_setup_true_lang-9Rm8Dhc4.js} +1 -1
- package/dist/{MapSettings-wVix8wMh.js → MapSettings-E1aNltts.js} +1 -1
- package/dist/{RastersTablePage-u3oN_h_n.js → RastersTablePage-CJblEi8a.js} +1 -1
- package/dist/{cartocss-BIveBlgY.js → cartocss-Dv2QILZ2.js} +5 -5
- package/dist/{import-utils-DkKPU_Nd.js → import-utils-CL-V2wSj.js} +1 -1
- package/dist/{index-C3bl1qBS.js → index-Bi60lcRm.js} +4768 -4718
- package/dist/index.css +1 -1
- package/dist/index.js +1 -1
- package/dist/index.umd.cjs +31 -31
- package/dist/{raster-CfTJZx5p.js → raster-nn-sOUb9.js} +3 -3
- package/dist/{register-dV5ipRhb.js → register-CjHXBGr5.js} +3 -3
- package/dist/{service-DWC5gq3L.js → service-l3Csdnxm.js} +8 -7
- package/dist/{vs-datatable-Cd2Gp4jo.js → vs-datatable-CJlE3-mz.js} +3 -2
- package/module/test/map/addr.json +303 -0
- package/module/test/map/{addr.yml → addr1.yml} +3 -1
- package/module/test/select/address.str_id.sql +3 -0
- package/package.json +10 -10
- package/plugin.js +21 -12
- package/server/plugins/mapnik/funcs/checkRasterFile.js +1 -3
- package/server/routes/cartocss/cartocss.route.js +31 -0
- package/server/routes/cartocss/cartocss.route.test.js +79 -0
- package/server/routes/cartocss/cartocss.schema.js +73 -0
- package/server/routes/{gis/cartocss → cartocss/functions}/add.cartocss.js +8 -11
- package/server/routes/{gis/cartocss → cartocss/functions}/get.cartocss.js +11 -13
- package/server/routes/gis/functions/checkXML.js +107 -0
- package/server/routes/gis/functions/dashboard.js +24 -0
- package/server/routes/gis/gis.route.js +26 -0
- package/server/routes/gis/gis.route.test.js +34 -0
- package/server/routes/gis/gis.schema.js +1 -0
- package/server/routes/map/{controllers → functions}/clearTiles.js +9 -8
- package/server/routes/map/{controllers → functions}/geojson.js +43 -43
- package/server/routes/map/{controllers → functions}/gis.convert.js +15 -23
- package/server/routes/map/{controllers → functions}/gis.icon.js +23 -10
- package/server/routes/map/{controllers → functions}/jsonData.js +72 -71
- package/server/routes/map/{controllers → functions}/layerList.js +17 -17
- package/server/routes/map/{controllers → functions}/map.js +8 -9
- package/server/routes/map/{controllers → functions}/mapCatalog.js +7 -7
- package/server/routes/map/functions/mapCatalogAttribute.js +54 -0
- package/server/routes/map/{controllers → functions}/mapFeatures.js +22 -18
- package/server/routes/map/{controllers → functions}/mapFormat.js +25 -28
- package/server/routes/map/{controllers → functions}/mapTiles.js +39 -30
- package/server/routes/map/{controllers → functions}/maps.js +3 -3
- package/server/routes/map/{controllers → functions}/marker_icon.js +1 -1
- package/server/routes/map/{controllers → functions}/parseGeoFile.js +10 -11
- package/server/routes/map/{controllers → functions}/pointHeight.js +3 -7
- package/server/routes/map/{controllers → functions}/vtile.js +5 -3
- package/server/routes/map/{vtile1.js → functions/vtile1.js} +39 -33
- package/server/routes/map/map.route.js +280 -0
- package/server/routes/map/map.route.test.js +503 -0
- package/server/routes/map/map.schema.js +356 -0
- package/server/routes/mapnik/{controllers → functions}/clearTiles.js +26 -29
- package/server/routes/mapnik/{controllers → functions}/createXml.js +17 -20
- package/server/routes/mapnik/{controllers → functions}/createXmlMulti.js +11 -15
- package/server/routes/mapnik/{controllers → functions}/fileSearch.js +6 -9
- package/server/routes/mapnik/functions/fileStat.js +28 -0
- package/server/routes/mapnik/{controllers → functions}/pretile.js +29 -35
- package/server/routes/mapnik/{controllers → functions}/rasterInfo.js +19 -10
- package/server/routes/mapnik/{controllers → functions}/readDir.js +4 -4
- package/server/routes/mapnik/functions/rtile.js +164 -0
- package/server/routes/mapnik/{controllers → functions}/uploadRaster.js +19 -24
- package/server/routes/mapnik/functions/uploadXML.js +27 -0
- package/server/routes/mapnik/mapnik.route.js +102 -0
- package/server/routes/mapnik/mapnik.route.test.js +371 -0
- package/server/routes/mapnik/mapnik.schema.mjs +190 -0
- package/server/routes/mapnik.prefixless/functions/mapnikLogger.js +31 -0
- package/server/routes/{mapnik/controllers → mapnik.prefixless/functions}/mapnikStat.js +7 -5
- package/server/routes/mapnik.prefixless/mapnik.prefixless.route.js +20 -0
- package/server/routes/mapnik.prefixless/mapnik.prefixless.route.test.js +91 -0
- package/server/routes/mapnik.prefixless/mapnik.prefixless.schema.mjs +27 -0
- package/server/routes/maps/functions/add.map.js +42 -0
- package/server/routes/{map/maps → maps/functions}/del.map.js +6 -7
- package/server/routes/{map/maps → maps/functions}/get.map.js +12 -11
- package/server/routes/maps/maps.route.js +58 -0
- package/server/routes/maps/maps.route.test.js +231 -0
- package/server/routes/maps/maps.schema.js +10 -0
- package/server/routes/metadata/functions/editMetadata.js +35 -0
- package/server/routes/metadata/functions/metadataXML.js +19 -0
- package/server/routes/metadata/metadata.route.js +26 -0
- package/server/routes/metadata/metadata.route.test.js +47 -0
- package/server/routes/metadata/metadata.schema.js +53 -0
- package/server/routes/{gis/ogc → ogc/functions}/map.info.point.js +22 -29
- package/server/routes/ogc/ogc.route.js +21 -0
- package/server/routes/ogc/ogc.route.test.js +54 -0
- package/server/routes/ogc/ogc.schema.js +16 -0
- package/server/routes/permissions/functions/catalog.permissions.edit.js +20 -0
- package/server/routes/permissions/functions/catalog.permissions.js +13 -0
- package/server/routes/permissions/{controllers → functions}/gis.catalog.js +10 -10
- package/server/routes/permissions/permissions.route.js +35 -0
- package/server/routes/permissions/permissions.route.test.js +35 -0
- package/server/routes/permissions/permissions.schema.js +44 -0
- package/server/routes/registers/functions/add.registry.js +37 -0
- package/server/routes/{gis/registers/funcs → registers/functions}/classifiers.js +2 -2
- package/server/routes/{gis/registers → registers/functions}/del.registry.js +5 -5
- package/server/routes/{gis/registers/funcs → registers/functions}/get.info.js +9 -5
- package/server/routes/{gis/registers → registers/functions}/gis.export.js +27 -21
- package/server/routes/{gis/registers → registers/functions}/gis.registry.js +22 -15
- package/server/routes/{gis/registers → registers/functions}/gis.registry.list.js +12 -10
- package/server/routes/{gis/registers/funcs → registers/functions}/handleRegistryRequest.js +12 -11
- package/server/routes/registers/registers.route.js +80 -0
- package/server/routes/registers/registers.route.test.js +145 -0
- package/server/routes/registers/registers.schema.js +246 -0
- package/server/routes/{gis/services → services/functions}/add.service.js +14 -16
- package/server/routes/services/functions/create.route.js +93 -0
- package/server/routes/{gis/services → services/functions}/del.service.js +5 -5
- package/server/routes/{gis/services → services/functions}/get.service.users.js +15 -13
- package/server/routes/services/functions/get.services.col.js +34 -0
- package/server/routes/{gis/services → services/functions}/get.services.js +21 -16
- package/server/routes/services/services.route.js +76 -0
- package/server/routes/services/services.route.test.js +168 -0
- package/server/routes/services/services.schema.js +278 -0
- package/server/routes/widgets/functions/add.widget.js +39 -0
- package/server/routes/widgets/functions/del.widget.js +18 -0
- package/server/routes/{map/widgets → widgets/functions}/get.widget.js +12 -11
- package/server/routes/widgets/widgets.route.js +61 -0
- package/server/routes/widgets/widgets.route.test.js +144 -0
- package/server/routes/widgets/widgets.schema.js +25 -0
- package/module/cls.json +0 -7
- package/module/gis/card/gis.metadata.table/main_info.hbs +0 -21
- package/module/gis/card/gis.metadata.table/metadata_info.hbs +0 -28
- package/module/gis/card/gis.metadata.table/other.hbs +0 -26
- package/module/gis/card/gis.rasters.table/main_info.hbs +0 -27
- package/module/gis/card/gis.registers.table/cls.hbs +0 -36
- package/module/gis/card/gis.registers.table/columns.hbs +0 -89
- package/module/gis/card/gis.registers.table/filters.hbs +0 -80
- package/module/gis/card/gis.registers.table/main_info.hbs +0 -35
- package/module/gis/card/gis.registers.table/source.hbs +0 -45
- package/module/gis/card/gis.services.table/attributes.hbs +0 -91
- package/module/gis/card/gis.services.table/filters.hbs +0 -83
- package/module/gis/card/gis.services.table/main_info.hbs +0 -27
- package/module/gis/card/gis.services.table/source.hbs +0 -26
- package/module/test/cls/bp_build_type.json +0 -37
- package/module/test/cls/doc_status.json +0 -32
- package/module/test/cls/ts.temp_status.json +0 -18
- package/module/test/cls/ts.temp_structure.ts_class.json +0 -50
- package/module/test/cls/ts.temp_type.json +0 -10
- package/module/test/layer/bp.json +0 -60
- package/module/test/layer/bp1.yml +0 -33
- package/module/test/layer/individual.yml +0 -54
- package/module/test/layer/ts.linking_passport.yml +0 -56
- package/module/test/layer/ts.temp_structure.yml +0 -51
- package/module/test/map/bp_myo.json +0 -44
- package/module/test/map/bpf.json +0 -44
- package/module/test/map/main.json +0 -39
- package/module/test/map/mbd.json +0 -92
- package/module/test/map/ts.json +0 -53
- package/module/test/select/address_id.json +0 -3
- package/module/test/select/address_id.sql +0 -8
- package/module/test/select/core.user_uid.sql +0 -1
- package/module/test/table/data_address.street.table.json +0 -70
- package/module/test/table/data_bp_myo.bp.table.json +0 -123
- package/server/routes/gis/checkXML.js +0 -117
- package/server/routes/gis/dashboard.js +0 -29
- package/server/routes/gis/index.mjs +0 -92
- package/server/routes/gis/metadata/editMetadata.js +0 -34
- package/server/routes/gis/metadata/metadataXML.js +0 -13
- package/server/routes/gis/registers/add.registry.js +0 -35
- package/server/routes/gis/registers/insert.columns.js +0 -107
- package/server/routes/gis/registers/insert.filters.js +0 -110
- package/server/routes/gis/services/create.route.js +0 -96
- package/server/routes/gis/services/get.services.col.js +0 -33
- package/server/routes/map/controllers/mapCatalogAttribute.js +0 -56
- package/server/routes/map/index.mjs +0 -259
- package/server/routes/map/maps/add.map.js +0 -43
- package/server/routes/map/widgets/add.widget.js +0 -39
- package/server/routes/map/widgets/del.widget.js +0 -23
- package/server/routes/mapnik/controllers/fileStat.js +0 -28
- package/server/routes/mapnik/controllers/mapnikLogger.js +0 -29
- package/server/routes/mapnik/controllers/rtile.js +0 -167
- package/server/routes/mapnik/index.js +0 -40
- package/server/routes/permissions/controllers/catalog.permissions.edit.js +0 -22
- package/server/routes/permissions/controllers/catalog.permissions.js +0 -8
- package/server/routes/permissions/index.mjs +0 -18
- /package/server/routes/map/{controllers/pin → pin}/circle1.svg +0 -0
- /package/server/routes/map/{controllers/pin → pin}/circle2.svg +0 -0
- /package/server/routes/map/{controllers/pin → pin}/none.svg +0 -0
- /package/server/routes/map/{controllers/pin → pin}/pin.svg +0 -0
- /package/server/routes/map/{controllers/pin → pin}/pin1.svg +0 -0
- /package/server/routes/map/{controllers/pin → pin}/pin2.svg +0 -0
- /package/server/routes/map/{controllers/pin → pin}/pin3.svg +0 -0
- /package/server/routes/map/{controllers/pin → pin}/pin4.svg +0 -0
- /package/server/routes/map/{controllers/pin → pin}/pin5.svg +0 -0
- /package/server/routes/map/{controllers/pin → pin}/pin6.svg +0 -0
- /package/server/routes/map/{controllers/pin → pin}/pin7.svg +0 -0
- /package/server/routes/permissions/{controllers/utils → functions}/get.permissions.js +0 -0
- /package/server/routes/{gis/registers/funcs → registers/functions}/columns.js +0 -0
- /package/server/routes/{gis/registers/funcs → registers/functions}/content.type.js +0 -0
- /package/server/routes/{gis/registers → registers/functions}/map.registry.js +0 -0
- /package/server/routes/{gis/services → services/functions}/get.layer.geom.js +0 -0
- /package/server/routes/{gis/services → services/functions}/legend.auto.js +0 -0
|
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
4
4
|
|
|
5
5
|
import * as solidIcons from '@fortawesome/free-solid-svg-icons';
|
|
6
6
|
import sharp from 'sharp';
|
|
7
|
+
import { BadRequestError, NotFoundError } from '@opengis/fastify-table/errors.js';
|
|
7
8
|
|
|
8
9
|
const iconFilenamePattern = /^([a-z][a-z0-9]*)-(s|m|l|xl)-(fa|ar)-([a-z0-9-]+)\+([a-f0-9]{3,8})\.(png|svg)$/i;
|
|
9
10
|
const validColorLengths = new Set([3, 4, 6, 8]);
|
|
@@ -48,7 +49,7 @@ const pinConfig = {
|
|
|
48
49
|
};
|
|
49
50
|
|
|
50
51
|
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
51
|
-
const pinDirectory = path.join(dirname, 'pin');
|
|
52
|
+
const pinDirectory = path.join(dirname, '../pin');
|
|
52
53
|
const iconDirectory = path.join(process.cwd(), 'log', 'icon');
|
|
53
54
|
const iconDirectoryReady = mkdir(iconDirectory, { recursive: true });
|
|
54
55
|
|
|
@@ -192,16 +193,28 @@ async function getIcon(options, nocache = false) {
|
|
|
192
193
|
return icon;
|
|
193
194
|
}
|
|
194
195
|
|
|
195
|
-
export default async function gisIconApi(
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
export default async function gisIconApi({ name, nocache }) {
|
|
197
|
+
if (!name) {
|
|
198
|
+
throw BadRequestError('not enough params: name');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const options = parseIconFilename(name);
|
|
202
|
+
|
|
203
|
+
if (!options) {
|
|
204
|
+
throw BadRequestError('invalid icon name');
|
|
205
|
+
}
|
|
198
206
|
|
|
199
|
-
const nocache = !!req.query?.nocache;
|
|
200
207
|
const image = await getIcon(options, nocache);
|
|
201
|
-
if (!image) return reply.status(404).send('icon not found');
|
|
202
208
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
209
|
+
if (!image) {
|
|
210
|
+
throw NotFoundError('icon not found');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
headers: {
|
|
215
|
+
'Content-Type': contentTypeByFormat[options.format],
|
|
216
|
+
'Cache-Control': nocache ? 'no-cache' : 'public, max-age=31536000, immutable'
|
|
217
|
+
},
|
|
218
|
+
data: image
|
|
219
|
+
}
|
|
207
220
|
}
|
|
@@ -10,9 +10,12 @@ import {
|
|
|
10
10
|
} from '@opengis/fastify-table/utils.js';
|
|
11
11
|
|
|
12
12
|
import rootFolder from '../../../plugins/mapnik/funcs/rootFolder.mjs';
|
|
13
|
+
import { BadRequestError, NotFoundError } from '@opengis/fastify-table/errors.js';
|
|
13
14
|
|
|
14
15
|
const systemColumns = ['uid', 'cdate', 'editor_id', 'editor_date', 'created_by', 'created_at', 'updated_by', 'updated_at', 'geom'];
|
|
15
16
|
|
|
17
|
+
const unittest = process.env.NODE_ENV === 'test' || process.env.VITEST;
|
|
18
|
+
|
|
16
19
|
/**
|
|
17
20
|
* Повертає JSON дані для реєстру на основі налаштувань з gis.registers
|
|
18
21
|
*
|
|
@@ -25,19 +28,15 @@ const systemColumns = ['uid', 'cdate', 'editor_id', 'editor_date', 'created_by',
|
|
|
25
28
|
* @param {boolean} query.nocache - не використовувати кеш
|
|
26
29
|
*/
|
|
27
30
|
export default async function jsonData({
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
sql,
|
|
36
|
-
nocache
|
|
37
|
-
} = query;
|
|
38
|
-
|
|
31
|
+
layer,
|
|
32
|
+
page = 1,
|
|
33
|
+
limit = 100,
|
|
34
|
+
// where,
|
|
35
|
+
sql,
|
|
36
|
+
nocache
|
|
37
|
+
}, pg = pgClients.client) {
|
|
39
38
|
if (!layer) {
|
|
40
|
-
|
|
39
|
+
throw BadRequestError('not enough params: layer (register_id)');
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
const registerId = layer.replace('.json', '');
|
|
@@ -46,7 +45,7 @@ export default async function jsonData({
|
|
|
46
45
|
const offset = (pageNum - 1) * limitNum;
|
|
47
46
|
|
|
48
47
|
if (!pg.pk?.['gis.registers']) {
|
|
49
|
-
|
|
48
|
+
throw NotFoundError('registers table not found');
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
const register = await pg.query(
|
|
@@ -61,10 +60,10 @@ export default async function jsonData({
|
|
|
61
60
|
from gis.registers
|
|
62
61
|
where register_id = $1 and is_active = true and is_public = true`,
|
|
63
62
|
[registerId],
|
|
64
|
-
).then(
|
|
63
|
+
).then(r => r.rows?.[0]);
|
|
65
64
|
|
|
66
65
|
if (!register) {
|
|
67
|
-
|
|
66
|
+
throw NotFoundError('register not found or not available');
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
const {
|
|
@@ -76,11 +75,11 @@ export default async function jsonData({
|
|
|
76
75
|
} = register;
|
|
77
76
|
|
|
78
77
|
if (!table) {
|
|
79
|
-
|
|
78
|
+
throw BadRequestError('invalid register table_name');
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
if (!pg.pk?.[table]?.length) {
|
|
83
|
-
|
|
82
|
+
throw NotFoundError('table not found');
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
const meta = await getMeta({ pg, table });
|
|
@@ -102,11 +101,11 @@ export default async function jsonData({
|
|
|
102
101
|
).join(', ');
|
|
103
102
|
|
|
104
103
|
if (!props) {
|
|
105
|
-
|
|
104
|
+
throw BadRequestError('no columns to select');
|
|
106
105
|
}
|
|
107
106
|
|
|
108
107
|
const cacheHash = createHash('md5')
|
|
109
|
-
.update([registerId, where
|
|
108
|
+
.update([registerId, /*where,*/ registerQuery, pageNum, limitNum].filter(el => el).join('-'))
|
|
110
109
|
.digest('hex');
|
|
111
110
|
|
|
112
111
|
const today = new Date().toISOString().split('T')[0];
|
|
@@ -120,17 +119,19 @@ export default async function jsonData({
|
|
|
120
119
|
const ageInMs = Date.now() - birthtimeMs;
|
|
121
120
|
if (ageInMs < 86400000) {
|
|
122
121
|
const content = await readFile(filepath, 'utf8');
|
|
123
|
-
return
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
return {
|
|
123
|
+
headers: {
|
|
124
|
+
'Content-Type': 'application/json',
|
|
125
|
+
'Cache-Control': 'public, max-age=86400',
|
|
126
|
+
},
|
|
127
|
+
data: content
|
|
128
|
+
}
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
const whereConditions = [
|
|
132
133
|
registerQuery || '1=1',
|
|
133
|
-
where
|
|
134
|
+
/*where ||*/ 'true',
|
|
134
135
|
].join(' AND ');
|
|
135
136
|
|
|
136
137
|
const quotedTable = table.split('.').map(el => `"${el}"`).join('.');
|
|
@@ -150,56 +151,56 @@ export default async function jsonData({
|
|
|
150
151
|
OFFSET ${offset}
|
|
151
152
|
`;
|
|
152
153
|
|
|
153
|
-
if (sql ===
|
|
154
|
-
if (sql ===
|
|
155
|
-
|
|
156
|
-
try {
|
|
157
|
-
const [countResult, dataResult] = await Promise.all([
|
|
158
|
-
pg.query(countQuery),
|
|
159
|
-
pg.query(dataQuery),
|
|
160
|
-
]);
|
|
161
|
-
|
|
162
|
-
const total = parseInt(countResult.rows[0]?.total || 0, 10);
|
|
163
|
-
const rows = dataResult.rows || [];
|
|
164
|
-
|
|
165
|
-
// Обробка класифікаторів
|
|
166
|
-
if (columns && Array.isArray(columns)) {
|
|
167
|
-
const classifiers = columns
|
|
168
|
-
.filter(col => col.data && ['select', 'badge', 'tags', 'integer', 'text', 'text[]'].includes(col.format))
|
|
169
|
-
.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.data }), {});
|
|
170
|
-
|
|
171
|
-
if (Object.keys(classifiers).length > 0) {
|
|
172
|
-
await metaFormat({
|
|
173
|
-
rows,
|
|
174
|
-
table,
|
|
175
|
-
cls: classifiers,
|
|
176
|
-
suffix: true,
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
}
|
|
154
|
+
if (sql === 1) return { countQuery, dataQuery };
|
|
155
|
+
if (sql === 2) return filepath.replace(/\\/g, '/');
|
|
156
|
+
|
|
180
157
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
limit: limitNum,
|
|
186
|
-
pages: Math.ceil(total / limitNum),
|
|
187
|
-
data: rows,
|
|
188
|
-
};
|
|
158
|
+
const [countResult, dataResult] = await Promise.all([
|
|
159
|
+
pg.query(countQuery),
|
|
160
|
+
pg.query(dataQuery),
|
|
161
|
+
]);
|
|
189
162
|
|
|
190
|
-
|
|
163
|
+
const total = parseInt(countResult.rows[0]?.total || 0, 10);
|
|
164
|
+
const rows = dataResult.rows || [];
|
|
191
165
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
166
|
+
// Обробка класифікаторів
|
|
167
|
+
if (columns && Array.isArray(columns)) {
|
|
168
|
+
const classifiers = columns
|
|
169
|
+
.filter(col => col.data && ['select', 'badge', 'tags', 'integer', 'text', 'text[]'].includes(col.format))
|
|
170
|
+
.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.data }), {});
|
|
171
|
+
|
|
172
|
+
if (Object.keys(classifiers).length > 0) {
|
|
173
|
+
await metaFormat({
|
|
174
|
+
rows,
|
|
175
|
+
table,
|
|
176
|
+
cls: classifiers,
|
|
177
|
+
suffix: true,
|
|
178
|
+
});
|
|
195
179
|
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const result = {
|
|
183
|
+
register_id: registerId,
|
|
184
|
+
total,
|
|
185
|
+
page: pageNum,
|
|
186
|
+
limit: limitNum,
|
|
187
|
+
pages: Math.ceil(total / limitNum),
|
|
188
|
+
data: rows,
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const jsonString = JSON.stringify(result);
|
|
196
192
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
.header('Cache-Control', nocache ? 'no-cache' : 'public, max-age=86400')
|
|
201
|
-
.send(jsonString);
|
|
202
|
-
} catch (err) {
|
|
203
|
-
return reply.status(500).send({ error: err.message });
|
|
193
|
+
if (!nocache && !unittest) {
|
|
194
|
+
await mkdir(path.dirname(filepath), { recursive: true });
|
|
195
|
+
await writeFile(filepath, jsonString, 'utf8');
|
|
204
196
|
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
headers: {
|
|
200
|
+
'Content-Type': 'application/json',
|
|
201
|
+
'Cache-Control': nocache ? 'no-cache' : 'public, max-age=86400',
|
|
202
|
+
},
|
|
203
|
+
data: jsonString
|
|
204
|
+
}
|
|
205
|
+
|
|
205
206
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
pgClients, yml2json, getTemplates, getTemplate,
|
|
3
3
|
} from '@opengis/fastify-table/utils.js';
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
import getPermissions from '../../permissions/functions/get.permissions.js';
|
|
5
6
|
|
|
6
7
|
export default async function layerList({
|
|
7
|
-
|
|
8
|
-
},
|
|
9
|
-
|
|
8
|
+
sql, uid,
|
|
9
|
+
}, pg = pgClients.client) {
|
|
10
|
+
|
|
10
11
|
const layers = getTemplates('layer');
|
|
11
12
|
const files = Promise.all(layers.map(async (el) => {
|
|
12
13
|
const layer = await getTemplate('layer', el[0]);
|
|
@@ -15,25 +16,24 @@ export default async function layerList({
|
|
|
15
16
|
|
|
16
17
|
if (!pg.pk?.['gis.services'] && !pg.pk?.['gis.ogc_service'] && !pg.pk?.['gis.rasters'] && !pg.pk?.['gis.cartocss']) {
|
|
17
18
|
return files;
|
|
18
|
-
// return reply.status(404).send('services table not found');
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const { all_layers, layer_list } =
|
|
21
|
+
const { all_layers, layer_list } = uid ? await getPermissions({ pg, uid }) : { all_layers: false, layer_list: [] };
|
|
22
22
|
|
|
23
23
|
const whereServices = (all_layers === true) ? '1=1'
|
|
24
|
-
: (
|
|
24
|
+
: (uid && !all_layers) ? '( s.is_public or s.service_id = any($1))'
|
|
25
25
|
: 'is_public';
|
|
26
26
|
|
|
27
27
|
const whereOgcServices = (all_layers === true) ? '1=1'
|
|
28
|
-
: (
|
|
28
|
+
: (uid && !all_layers) ? '( s.ispublic or s.ogc_service_id = any($1))'
|
|
29
29
|
: 'ispublic';
|
|
30
30
|
|
|
31
31
|
const whereRasters = (all_layers === true) ? '1=1'
|
|
32
|
-
: (
|
|
32
|
+
: (uid && !all_layers) ? '(s.is_public or s.raster_id = any($1))'
|
|
33
33
|
: 'is_public';
|
|
34
34
|
|
|
35
35
|
const whereCartocss = (all_layers === true) ? '1=1'
|
|
36
|
-
: (
|
|
36
|
+
: (uid && !all_layers) ? '(s.is_public or s.cartocss_id = any($1))'
|
|
37
37
|
: 'is_public';
|
|
38
38
|
const q = `
|
|
39
39
|
select * from
|
|
@@ -71,20 +71,20 @@ export default async function layerList({
|
|
|
71
71
|
)q order by q.name
|
|
72
72
|
`;
|
|
73
73
|
|
|
74
|
-
if (
|
|
74
|
+
if (uid && sql) return q;
|
|
75
75
|
|
|
76
|
-
const rows = await pg.query(q, (
|
|
76
|
+
const rows = await pg.query(q, (uid && !all_layers) ? [layer_list] : []).then(r => r.rows || []);
|
|
77
77
|
|
|
78
78
|
const totals = pg.queryCache ? await pg.queryCache('select json_object_agg(oid::regclass, reltuples) from pg_class')
|
|
79
|
-
.then(
|
|
79
|
+
.then(r => r.rows?.[0]?.json_object_agg || {}) : {};
|
|
80
80
|
rows.filter(row => row.source_path).forEach(row => Object.assign(row, { count: totals[row.source_path] || 0 }));
|
|
81
81
|
|
|
82
82
|
const groupIds = rows.map(el => el.group_id).filter(Boolean);
|
|
83
|
-
const groupNames = groupIds.length ? await pg.query('select json_object_agg(group_id,group_name) from gis.group_list where group_id=any($1)', [groupIds]).then(
|
|
83
|
+
const groupNames = groupIds.length ? await pg.query('select json_object_agg(group_id,group_name) from gis.group_list where group_id=any($1)', [groupIds]).then(r => r.rows?.[0]?.json_object_agg || {}) : {};
|
|
84
84
|
rows.filter(el => el.group_id).forEach(row => Object.assign(row, { group_name: groupNames[row.group_id] }));
|
|
85
85
|
|
|
86
86
|
if (!rows.length) {
|
|
87
|
-
return
|
|
87
|
+
return [];
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
// parse service style
|
|
@@ -98,5 +98,5 @@ export default async function layerList({
|
|
|
98
98
|
|
|
99
99
|
// return files;
|
|
100
100
|
|
|
101
|
-
return
|
|
101
|
+
return rows.concat(files);
|
|
102
102
|
}
|
|
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'url';
|
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
5
|
|
|
6
6
|
import { config, getMeta, getTemplate, getTemplateSync, pgClients, getSelect, getSelectVal, getTemplatePath } from '@opengis/fastify-table/utils.js';
|
|
7
|
+
import { NotFoundError } from '@opengis/fastify-table/errors.js';
|
|
7
8
|
|
|
8
9
|
const { prefix = '/api' } = config;
|
|
9
10
|
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -13,7 +14,7 @@ const maps = getTemplatePath('map')?.map?.(el => {
|
|
|
13
14
|
return { slug: el[0], name };
|
|
14
15
|
});
|
|
15
16
|
|
|
16
|
-
async function processObject(loadTemplate, pg = pgClients.client, unittest) {
|
|
17
|
+
async function processObject(loadTemplate, pg = pgClients.client, unittest = process.env.NODE_ENV === 'test' || process.env.VITEST) {
|
|
17
18
|
// default center for all maps (frontend dependends on it)
|
|
18
19
|
const { bbox = [], center = [30, 50] } = loadTemplate?.source_path && pg.pk?.[loadTemplate.source_path]
|
|
19
20
|
? await pg.query(`select
|
|
@@ -96,29 +97,27 @@ async function processObject(loadTemplate, pg = pgClients.client, unittest) {
|
|
|
96
97
|
return loadTemplate;
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
export default async function map({ pg = pgClients.client
|
|
100
|
-
const { slug } = params;
|
|
101
|
-
|
|
100
|
+
export default async function map({ slug }, pg = pgClients.client) {
|
|
102
101
|
const loadTemplate = await getTemplate('map', slug);
|
|
103
102
|
|
|
104
103
|
if (!loadTemplate) {
|
|
105
|
-
|
|
104
|
+
throw NotFoundError('map not found');
|
|
106
105
|
}
|
|
107
106
|
|
|
108
107
|
if (!Array.isArray(loadTemplate)) {
|
|
109
|
-
await processObject(loadTemplate, pg
|
|
108
|
+
await processObject(loadTemplate, pg);
|
|
110
109
|
return { ...loadTemplate, maps };
|
|
111
110
|
}
|
|
112
111
|
|
|
113
112
|
const index = loadTemplate?.find?.(el => el[0].split('.').shift() === 'index')?.[1];
|
|
114
113
|
|
|
115
114
|
if (!index) {
|
|
116
|
-
|
|
115
|
+
throw NotFoundError('map index not found');
|
|
117
116
|
}
|
|
118
117
|
|
|
119
|
-
await processObject(index, pg
|
|
118
|
+
await processObject(index, pg);
|
|
120
119
|
|
|
121
120
|
const layers = loadTemplate?.filter?.(el => el[0].split('.').shift() !== 'index')?.map(el => ({ ...el[1], id: el[0].replace('.yml', '').replace('.json', '') }));
|
|
122
121
|
|
|
123
|
-
return
|
|
122
|
+
return { ...index, layers, maps };
|
|
124
123
|
}
|
|
@@ -14,7 +14,7 @@ function getBBox(coordinates) {
|
|
|
14
14
|
);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export default async function mapCatalog({ pg = pgClients.client
|
|
17
|
+
export default async function mapCatalog({ } = {}, pg = pgClients.client) {
|
|
18
18
|
const { rows: services = [] } = pg.pk?.['gis.services']
|
|
19
19
|
? await pg.query(`select
|
|
20
20
|
service_id as id, name, service_type, service_url as url,
|
|
@@ -50,17 +50,17 @@ export default async function mapCatalog({ pg = pgClients.client }, reply) {
|
|
|
50
50
|
from gis.rasters where is_active and is_public`
|
|
51
51
|
)
|
|
52
52
|
: {};
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
|
|
54
|
+
const { rows: ogc = [] } = pg.pk?.['gis.ogc_service']
|
|
55
55
|
? await pg.query(
|
|
56
56
|
`select
|
|
57
57
|
service_id as id, name, 'raster' as source_type, url
|
|
58
58
|
from gis.ogc_service `
|
|
59
59
|
)
|
|
60
60
|
: {};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
64
|
rasters.forEach(el => {
|
|
65
65
|
el.url = `${prefix}/layer-rtile/${el.id}/{z}/{x}/{y}.png`;
|
|
66
66
|
});
|
|
@@ -69,5 +69,5 @@ export default async function mapCatalog({ pg = pgClients.client }, reply) {
|
|
|
69
69
|
el.bbox = getBBox(el.bbox);
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
return
|
|
72
|
+
return { services, rasters: rasters.concat(ogc) };
|
|
73
73
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { BadRequestError } from "@opengis/fastify-table/errors.js";
|
|
2
|
+
import { pgClients, getMeta, getSelect, getSelectVal } from "@opengis/fastify-table/utils.js";
|
|
3
|
+
|
|
4
|
+
export default async function mapCatalogAttribute({ service, attr, cls: queryCls }, pg = pgClients.client) {
|
|
5
|
+
if (!service) {
|
|
6
|
+
throw BadRequestError('not enough params: service');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (!attr) {
|
|
10
|
+
throw BadRequestError('not enough params: attr');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!pg.pk?.['gis.services']) {
|
|
14
|
+
throw NotFoundError('services table not found');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const source = await pg.query(
|
|
18
|
+
'select source_path from gis.services where service_id=$1 and is_active and is_public',
|
|
19
|
+
[service]
|
|
20
|
+
).then(r => r.rows?.[0]?.source_path);
|
|
21
|
+
|
|
22
|
+
if (!source) {
|
|
23
|
+
throw NotFoundError('service not found');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const cls = await getSelect(queryCls || attr, pg);
|
|
27
|
+
const colname = queryCls ? attr : attr.split(':').pop();
|
|
28
|
+
|
|
29
|
+
if (!colname) {
|
|
30
|
+
throw BadRequestError('invalid params: attr');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const columns = await getMeta({ pg, table: source }).then(r => r.columns || []);
|
|
34
|
+
const { dataTypeID } = columns.find(col => col.name === colname) || {};
|
|
35
|
+
|
|
36
|
+
const q = dataTypeID && pg.pgType[dataTypeID]?.includes('[]')
|
|
37
|
+
? `select unnest(${colname})::text as id,count(*) from ${source} group by unnest(${colname}) limit 100`
|
|
38
|
+
: `select ${colname}::text as id,count(*) from ${source} group by ${colname} limit 100`;
|
|
39
|
+
|
|
40
|
+
const countArr = await pg.queryCache(q).then(r => r.rows || []);
|
|
41
|
+
|
|
42
|
+
const clsData = await getSelectVal({ pg, values: countArr.map(el => el.id), name: queryCls || attr });
|
|
43
|
+
|
|
44
|
+
const legend = countArr.map(cel => {
|
|
45
|
+
const data = cls?.arr?.find(c => c.id?.toString?.() === cel.id?.toString?.()) || { text: clsData?.[cel.id]?.text || clsData?.[cel.id] };
|
|
46
|
+
return { ...cel, ...data };
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const { min, max } = await pg.queryCache(
|
|
50
|
+
`select min(${attr}), max(${attr}) from ${source} where 1=1`,
|
|
51
|
+
).then(r => r.rows?.[0] || {});
|
|
52
|
+
|
|
53
|
+
return { legend, min, max };
|
|
54
|
+
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BadRequestError, NotFoundError } from '@opengis/fastify-table/errors.js';
|
|
2
|
+
import {
|
|
3
|
+
getMeta, getFilterSQL, getTemplate, metaFormat, pgClients, yml2json,
|
|
4
|
+
} from '@opengis/fastify-table/utils.js';
|
|
2
5
|
|
|
3
6
|
const layerMetaColumns = ['id', 'name', 'label', 'source', 'table', 'pk', 'geomColumn', 'srid', 'cls', 'htmls'];
|
|
4
7
|
|
|
5
|
-
export default async function mapFeaturesPoint({
|
|
6
|
-
const { slug, id } = params;
|
|
7
|
-
const { x, y, sql } = query;
|
|
8
|
-
|
|
8
|
+
export default async function mapFeaturesPoint({ slug, id, x, y, sql }, pg = pgClients.client) {
|
|
9
9
|
if (!slug) {
|
|
10
|
-
|
|
10
|
+
throw BadRequestError('not enough params: slug');
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
if (!(x && y) && !id) {
|
|
14
|
-
|
|
14
|
+
throw BadRequestError('not enough params: xy');
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const loadTemplate = await getTemplate('map', slug);
|
|
18
18
|
|
|
19
19
|
if (!loadTemplate) {
|
|
20
|
-
|
|
20
|
+
throw NotFoundError('map not found');
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
const index = loadTemplate?.find?.(el => el[0].split('.').shift() === 'index')?.[1];
|
|
@@ -26,21 +26,21 @@ export default async function mapFeaturesPoint({ pg = pgClients.client, params =
|
|
|
26
26
|
? loadTemplate?.layers
|
|
27
27
|
: loadTemplate?.filter?.(el => el[0].split('.').shift() !== 'index')?.map(el => ({ ...el[1], id: el[0].replace('.yml', '').replace('.json', '') }));
|
|
28
28
|
|
|
29
|
-
const serviceLayers = await Promise.all(layers1.filter(el => typeof el === 'string').map(async (layer) => {
|
|
29
|
+
const serviceLayers = await Promise.all((layers1 || []).filter(el => typeof el === 'string').map(async (layer) => {
|
|
30
30
|
const layerData = await getTemplate('layer', layer);
|
|
31
31
|
const serviceData = layerData || await pg.query('select service_id as id, *, st_asgeojson(bbox)::json as bbox, st_asgeojson(center)::json as center from gis.services where service_id=$1', [layer]).then(el => el.rows?.[0]);
|
|
32
32
|
serviceData.style = yml2json(serviceData.style);
|
|
33
33
|
return { ...serviceData, id: layer, visible: true };
|
|
34
34
|
}));
|
|
35
35
|
|
|
36
|
-
const layers = layers1.filter(el => el && typeof el === 'object').concat(serviceLayers);
|
|
36
|
+
const layers = (layers1 || []).filter(el => el && typeof el === 'object').concat(serviceLayers);
|
|
37
37
|
|
|
38
38
|
if (!layers?.length) {
|
|
39
|
-
|
|
39
|
+
throw NotFoundError('map layers not found');
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
if (!layers.filter(el => el.source_path).length) {
|
|
43
|
-
|
|
43
|
+
throw NotFoundError('map layers sources not provided');
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
const point = `srid=4326;point(${x} ${y})`; // 30, 50
|
|
@@ -48,7 +48,9 @@ export default async function mapFeaturesPoint({ pg = pgClients.client, params =
|
|
|
48
48
|
const { srids } = await pg.queryCache?.('select json_agg(srid) as srids from spatial_ref_sys').then(el => el.rows?.[0] || {}) || {};
|
|
49
49
|
|
|
50
50
|
await Promise.all(layers.map(async (layer, idx) => {
|
|
51
|
-
const {
|
|
51
|
+
const {
|
|
52
|
+
source_path: source, srid = 4326, id: layerId, name,
|
|
53
|
+
} = layer;
|
|
52
54
|
|
|
53
55
|
const loadTable = await getTemplate('table', source);
|
|
54
56
|
const meta = await getMeta({ pg, table: loadTable?.table || source });
|
|
@@ -100,19 +102,21 @@ export default async function mapFeaturesPoint({ pg = pgClients.client, params =
|
|
|
100
102
|
where ${where}`;
|
|
101
103
|
}).join(' union all ').concat(' order by distance');
|
|
102
104
|
|
|
103
|
-
if (sql ===
|
|
105
|
+
if (sql === 1) return q;
|
|
104
106
|
|
|
105
107
|
const { rows: objects = [] } = await pg.query(q);
|
|
106
108
|
|
|
107
109
|
if (!objects.length) {
|
|
108
|
-
return
|
|
110
|
+
return `object not found: ${id}`;
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
const layerData = layers.find((el) => (el.id || el.name) === objects[0].layer) || {};
|
|
112
114
|
const rows = objects.slice(0, 1).map(el => ({ ...el.data, data: undefined }));
|
|
113
115
|
|
|
114
116
|
const { cls, htmls } = layerData;
|
|
115
|
-
await metaFormat({
|
|
117
|
+
await metaFormat({
|
|
118
|
+
rows, cls, htmls, sufix: false,
|
|
119
|
+
}, pg);
|
|
116
120
|
|
|
117
121
|
const resp = {
|
|
118
122
|
meta: {
|
|
@@ -125,5 +129,5 @@ export default async function mapFeaturesPoint({ pg = pgClients.client, params =
|
|
|
125
129
|
},
|
|
126
130
|
};
|
|
127
131
|
|
|
128
|
-
return
|
|
129
|
-
}
|
|
132
|
+
return resp;
|
|
133
|
+
}
|