@opengis/gis 0.2.100 → 0.2.102
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/index.css +1 -1
- package/dist/index.js +5443 -5272
- package/dist/index.umd.cjs +31 -30
- package/module/gis/form/gis.cartocss.form.json +7 -0
- package/module/test/cls/doc_status.json +31 -31
- package/module/test/select/core.user_uid.sql +1 -1
- package/package.json +2 -2
- package/server/migrations/cartocss.sql +2 -0
- package/server/routes/gis/checkXML.js +7 -7
- package/server/routes/gis/index.mjs +1 -1
- package/server/routes/gis/metadata/editMetadata.js +1 -1
- package/server/routes/map/controllers/mapFormat.js +19 -22
- package/server/routes/map/index.mjs +24 -1
- package/server/routes/mapnik/controllers/rtile.js +5 -3
|
@@ -30,6 +30,13 @@
|
|
|
30
30
|
"type": "Switcher",
|
|
31
31
|
"data": "yes_no"
|
|
32
32
|
},
|
|
33
|
+
"is_static": {
|
|
34
|
+
"ua": "Чи є карта статичною?",
|
|
35
|
+
"i": "Генерація тайлів без TTL",
|
|
36
|
+
"col": 6,
|
|
37
|
+
"type": "Switcher",
|
|
38
|
+
"data": "yes_no"
|
|
39
|
+
},
|
|
33
40
|
"enabled": {
|
|
34
41
|
"ua": "Чи включена карта?",
|
|
35
42
|
"col": 6,
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"id": "1",
|
|
4
|
-
"text": "Діючий",
|
|
5
|
-
"color": "#1ab394"
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
"id": "2",
|
|
9
|
-
"text": "Зупинений",
|
|
10
|
-
"color": "#ed82c8"
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"id": "3",
|
|
14
|
-
"text": "Скасований",
|
|
15
|
-
"color": "#4a4a4a"
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"id": "5",
|
|
19
|
-
"text": "Проектний",
|
|
20
|
-
"color": "#6495ed"
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"id": "7",
|
|
24
|
-
"text": "Очікує розгляду",
|
|
25
|
-
"color": "#92b8ef"
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"id": "10",
|
|
29
|
-
"text": "Архівний",
|
|
30
|
-
"color": "#d48428"
|
|
31
|
-
}
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "1",
|
|
4
|
+
"text": "Діючий",
|
|
5
|
+
"color": "#1ab394"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"id": "2",
|
|
9
|
+
"text": "Зупинений",
|
|
10
|
+
"color": "#ed82c8"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "3",
|
|
14
|
+
"text": "Скасований",
|
|
15
|
+
"color": "#4a4a4a"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "5",
|
|
19
|
+
"text": "Проектний",
|
|
20
|
+
"color": "#6495ed"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "7",
|
|
24
|
+
"text": "Очікує розгляду",
|
|
25
|
+
"color": "#92b8ef"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "10",
|
|
29
|
+
"text": "Архівний",
|
|
30
|
+
"color": "#d48428"
|
|
31
|
+
}
|
|
32
32
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
select uid, coalesce(coalesce(sur_name,'')||coalesce(' '||user_name,'') ||coalesce(' '||father_name,''),login) as text from admin.users
|
|
1
|
+
select uid, coalesce(coalesce(sur_name,'')||coalesce(' '||user_name,'') ||coalesce(' '||father_name,''),login) as text from admin.users
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ create table if not exists gis.cartocss(
|
|
|
14
14
|
group_id text constraint services_group_id_fkey references group_list,
|
|
15
15
|
is_public boolean default false not null,
|
|
16
16
|
enabled boolean default true not null,
|
|
17
|
+
is_static boolean not null default false,
|
|
17
18
|
geom public.geometry
|
|
18
19
|
);
|
|
19
20
|
|
|
@@ -23,3 +24,4 @@ alter table gis.cartocss add column if not exists card_auto boolean not null def
|
|
|
23
24
|
alter table gis.cartocss add column if not exists card_html text;
|
|
24
25
|
alter table gis.cartocss add column if not exists card_table text;
|
|
25
26
|
alter table gis.cartocss add column if not exists card_columns text;
|
|
27
|
+
alter table gis.cartocss add column if not exists is_static boolean not null default false;
|
|
@@ -33,13 +33,13 @@ export default async function checkXML(req, reply) {
|
|
|
33
33
|
|
|
34
34
|
if (uploadStatus.exists === false) {
|
|
35
35
|
errors.raster += 1;
|
|
36
|
-
send(`${idx}/${rasters.length} ERROR: GetRasterStatus: not uploaded (raster:${row.raster_id})`);
|
|
36
|
+
send(`${idx}/${rasters.length} ERROR: GetRasterStatus: not uploaded (raster:${row.raster_id}/${row.name})`);
|
|
37
37
|
return null;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
if (uploadStatus.finished === false) {
|
|
41
41
|
errors.raster += 1;
|
|
42
|
-
send(`${idx}/${rasters.length} ERROR: GetRasterStatus: upload not finished (raster:${row.raster_id})`);
|
|
42
|
+
send(`${idx}/${rasters.length} ERROR: GetRasterStatus: upload not finished (raster:${row.raster_id}/${row.name})`);
|
|
43
43
|
return null;
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -50,7 +50,7 @@ export default async function checkXML(req, reply) {
|
|
|
50
50
|
|
|
51
51
|
if (rasterInfo.err) {
|
|
52
52
|
errors.raster += 1;
|
|
53
|
-
send(`${idx}/${rasters.length} ERROR: GetRasterInfo: ${rasterInfo.err} (raster:${row.raster_id})`);
|
|
53
|
+
send(`${idx}/${rasters.length} ERROR: GetRasterInfo: ${rasterInfo.err} (raster:${row.raster_id}/${row.name})`);
|
|
54
54
|
return null;
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -63,11 +63,11 @@ export default async function checkXML(req, reply) {
|
|
|
63
63
|
|
|
64
64
|
if (data.err) {
|
|
65
65
|
errors.raster += 1;
|
|
66
|
-
send(`${idx}/${rasters.length} ERROR: RenderTile: ${data.err} (raster:${row.raster_id})`);
|
|
66
|
+
send(`${idx}/${rasters.length} ERROR: RenderTile: ${data.err} (raster:${row.raster_id}/${row.name})`);
|
|
67
67
|
return null;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
send(`${idx}/${rasters.length} OK: (raster:${row.raster_id})`);
|
|
70
|
+
send(`${idx}/${rasters.length} OK: (raster:${row.raster_id}/${row.name})`);
|
|
71
71
|
successCount += 1;
|
|
72
72
|
}),
|
|
73
73
|
Promise.resolve(),
|
|
@@ -87,11 +87,11 @@ export default async function checkXML(req, reply) {
|
|
|
87
87
|
|
|
88
88
|
if (data.err) {
|
|
89
89
|
errors.css += 1;
|
|
90
|
-
send(`${idx}/${css.length} ERROR: RenderTile: ${data.err} (css:${row.cartocss_id})`);
|
|
90
|
+
send(`${idx}/${css.length} ERROR: RenderTile: ${data.err} (css:${row.cartocss_id}/${row.name})`);
|
|
91
91
|
return null;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
send(`${idx}/${css.length} OK: (css:${row.cartocss_id})`);
|
|
94
|
+
send(`${idx}/${css.length} OK: (css:${row.cartocss_id}/${row.name})`);
|
|
95
95
|
successCount += 1;
|
|
96
96
|
}),
|
|
97
97
|
Promise.resolve(),
|
|
@@ -41,7 +41,7 @@ const editMetadataSchema = {
|
|
|
41
41
|
params: {
|
|
42
42
|
type: 'object',
|
|
43
43
|
properties: {
|
|
44
|
-
type: { type: 'string', enum: ['raster', 'css', 'dataset'] },
|
|
44
|
+
type: { type: 'string', enum: ['raster', 'css', 'dataset', 'service'] },
|
|
45
45
|
id: { type: 'string' },
|
|
46
46
|
},
|
|
47
47
|
required: ['type', 'id'],
|
|
@@ -9,7 +9,7 @@ export default async function editMetadata(req, reply) {
|
|
|
9
9
|
raster: 'select 1 from gis.rasters where raster_id = $1',
|
|
10
10
|
css: 'select 1 from gis.cartocss where cartocss_id = $1',
|
|
11
11
|
dataset: 'select 1 from gis.dataset where dataset_id = $1',
|
|
12
|
-
|
|
12
|
+
service: 'select 1 from gis.services where service_id = $1',
|
|
13
13
|
}[type];
|
|
14
14
|
|
|
15
15
|
if (!q) {
|
|
@@ -6,31 +6,28 @@ import {
|
|
|
6
6
|
const excluded = ['created_by', 'created_at', 'updated_by', 'geom', 'id', 'uid', 'updated_at', 'cdate', 'editor_date', 'editor_id'];
|
|
7
7
|
|
|
8
8
|
function getLayerTableQuery({
|
|
9
|
-
el, id, point,
|
|
9
|
+
el, id, point, nogeom, radius,
|
|
10
10
|
}, pg = pgClients.client) {
|
|
11
11
|
const {
|
|
12
12
|
gcol: geom = 'geom', table, pk = pg.pk[el.table], query: tableQuery, srid, columns,
|
|
13
13
|
} = el;
|
|
14
|
-
const
|
|
14
|
+
const buffer = `ST_Buffer('${point}'::geography, ${radius || 50})::geometry`;
|
|
15
15
|
const q = `SELECT
|
|
16
16
|
${pk} as "id"
|
|
17
17
|
,'${el.key}' as "key"
|
|
18
18
|
${nogeom ? '' : `,st_asgeojson(${srid !== 4326 ? `st_transform(${geom}, 4326)` : geom})::json as geom`}, ${srid !== 4326 ? `st_transform(${geom}, 4326)` : geom}::box2d as box2d, ${columns ? `row_to_json(t)` : 'null'} as "data"
|
|
19
19
|
${point ? `,st_distance(${el.srid !== 4326 ? `st_transform(${geom}, 4326)` : geom},'${point} ') as distance` : ''}
|
|
20
20
|
FROM ${table} t WHERE ${tableQuery || '1 = 1'} and st_isvalid(${geom}) and st_srid(${geom}) > 0
|
|
21
|
-
and ${point
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
then st_distance(${srid !== 4326 ? `st_transform(${geom}, 4326)` : geom},'${point}') < ${step}
|
|
27
|
-
else false end` : `${id ? `${pk}='${id.replace(/'/g, "")}'` : '2=2'}`
|
|
28
|
-
} ${point ? 'order by distance' : ''} limit 1`;
|
|
21
|
+
and ${point
|
|
22
|
+
? `case when ST_GeometryType(${geom}) in ('ST_Polygon','ST_MultiPolygon', 'ST_LineString','ST_MultiLineString', 'ST_MultiPoint', 'ST_Point') then st_intersects(${srid !== 4326 ? `st_transform(${geom}, 4326)` : geom}, ${buffer}) else false end`
|
|
23
|
+
: '1=1'}
|
|
24
|
+
and ${id ? `${pk}='${id.replace(/'/g, "")}'` : '2=2'}
|
|
25
|
+
${point ? 'order by distance' : ''} limit 10`;
|
|
29
26
|
return q;
|
|
30
27
|
}
|
|
31
28
|
|
|
32
29
|
async function getLayersData({
|
|
33
|
-
id, lng, lat, cartocss, nogeom,
|
|
30
|
+
id, lng, lat, cartocss, nogeom, radius,
|
|
34
31
|
}, pg = pgClients.client) {
|
|
35
32
|
if (!(lng && lat) && !id) {
|
|
36
33
|
return { error: 'not enough params: lat / lng' };
|
|
@@ -42,14 +39,12 @@ async function getLayersData({
|
|
|
42
39
|
|
|
43
40
|
const point = lng && lat ? `srid=4326;point(${lng} ${lat})`.replace(/'/g, "''") : null;
|
|
44
41
|
|
|
45
|
-
const srids = pg?.queryCache ? await pg.queryCache('select json_agg(srid) from public.spatial_ref_sys').then(el => el.rows?.[0]?.json_agg || []) : [];
|
|
46
|
-
|
|
47
42
|
const q = cartocss.card_table
|
|
48
43
|
? getLayerTableQuery({
|
|
49
|
-
el: { key: cartocss.card_table, table: cartocss.card_table, columns: cartocss.card_columns }, id, point,
|
|
44
|
+
el: { key: cartocss.card_table, table: cartocss.card_table, columns: cartocss.card_columns }, id, point, nogeom, radius,
|
|
50
45
|
}, pg)
|
|
51
46
|
: cartocss.config.filter((el, idx, arr) => el.key && el.table && pg.pk?.[el.table] && arr.map(item => item.table).indexOf(el.table) === idx).map(el => getLayerTableQuery({
|
|
52
|
-
el, id, point,
|
|
47
|
+
el, id, point, nogeom, radius,
|
|
53
48
|
}, pg)).join(' union all ');
|
|
54
49
|
|
|
55
50
|
// console.time(q);
|
|
@@ -79,6 +74,7 @@ async function getLayersData({
|
|
|
79
74
|
: Object.keys(rows[0] || {}).map(key => ({ name: key, format: 'text' }));
|
|
80
75
|
|
|
81
76
|
return {
|
|
77
|
+
ids: rows.map(row => row.id),
|
|
82
78
|
rows,
|
|
83
79
|
data,
|
|
84
80
|
columns,
|
|
@@ -88,7 +84,7 @@ async function getLayersData({
|
|
|
88
84
|
}
|
|
89
85
|
|
|
90
86
|
async function getTableData({
|
|
91
|
-
service, layer, id, user,
|
|
87
|
+
service, layer, id, user, nogeom,
|
|
92
88
|
}, pg = pgClients.client) {
|
|
93
89
|
const {
|
|
94
90
|
source_path: tname, card, template,
|
|
@@ -115,7 +111,7 @@ async function getTableData({
|
|
|
115
111
|
const filteredColumns = columnNames.filter(name => !excluded.includes(name));
|
|
116
112
|
|
|
117
113
|
const rows = await pg.query(
|
|
118
|
-
`SELECT ${pk} as "id", st_asgeojson(geom)::json as geom, geom::box2d as box2d ${filteredColumns?.length > 0 ? ',' : ''} ${filteredColumns.map((n) => `"${n}"`).join(', ')} FROM ${tname} WHERE ${pk} = $1`,
|
|
114
|
+
`SELECT ${pk} as "id", ${!nogeom ? 'st_asgeojson(geom)::json as geom, geom::box2d as box2d' : ''} ${!nogeom && filteredColumns?.length > 0 ? ',' : ''} ${filteredColumns.map((n) => `"${n}"`).join(', ')} FROM ${tname} WHERE ${pk} = $1`,
|
|
119
115
|
[id],
|
|
120
116
|
).then(el => el.rows || []);
|
|
121
117
|
|
|
@@ -142,7 +138,7 @@ async function getTableData({
|
|
|
142
138
|
|
|
143
139
|
export default async function mapFormat({ pg = pgClients.client, query = {}, user }, reply) {
|
|
144
140
|
const {
|
|
145
|
-
layer, id, lat, lng, nogeom,
|
|
141
|
+
layer, id, lat, lng, nogeom, radius = 50,
|
|
146
142
|
} = query;
|
|
147
143
|
|
|
148
144
|
const t1 = Date.now();
|
|
@@ -158,7 +154,7 @@ export default async function mapFormat({ pg = pgClients.client, query = {}, use
|
|
|
158
154
|
return reply.status(400).send({ error: 'not enough query params: id', code: 400 });
|
|
159
155
|
}
|
|
160
156
|
|
|
161
|
-
if (cartocss && !cartocss.config?.length) {
|
|
157
|
+
if (cartocss && !(cartocss.config?.length || cartocss.card_table)) {
|
|
162
158
|
return reply.status(400).send({ error: 'invalid layer settings: empty config', code: 400 });
|
|
163
159
|
}
|
|
164
160
|
|
|
@@ -167,10 +163,10 @@ export default async function mapFormat({ pg = pgClients.client, query = {}, use
|
|
|
167
163
|
}
|
|
168
164
|
|
|
169
165
|
const {
|
|
170
|
-
rows, data, columns, classifiers, tname, template, error, code = 500, htmlTemplate,
|
|
166
|
+
ids, rows, data, columns, classifiers, tname, template, error, code = 500, htmlTemplate,
|
|
171
167
|
} = cartocss
|
|
172
168
|
? await getLayersData({
|
|
173
|
-
cartocss, id, lng, lat, nogeom,
|
|
169
|
+
cartocss, id, lng, lat, radius, nogeom,
|
|
174
170
|
}, pg)
|
|
175
171
|
: await getTableData({
|
|
176
172
|
service, layer, id, user, nogeom,
|
|
@@ -210,8 +206,9 @@ export default async function mapFormat({ pg = pgClients.client, query = {}, use
|
|
|
210
206
|
|
|
211
207
|
const res = {
|
|
212
208
|
time: Date.now() - t1,
|
|
209
|
+
ids,
|
|
213
210
|
id: fullRow.id,
|
|
214
|
-
|
|
211
|
+
data: fullRow,
|
|
215
212
|
columns,
|
|
216
213
|
template,
|
|
217
214
|
html,
|
|
@@ -47,6 +47,29 @@ const schemaInfo = {
|
|
|
47
47
|
},
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
+
const mapFormatSchema = {
|
|
51
|
+
querystring: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {
|
|
54
|
+
lat: {
|
|
55
|
+
type: 'number',
|
|
56
|
+
minimum: 1,
|
|
57
|
+
maximum: 90,
|
|
58
|
+
},
|
|
59
|
+
lng: {
|
|
60
|
+
type: 'number',
|
|
61
|
+
minimum: -180,
|
|
62
|
+
maximum: 180,
|
|
63
|
+
},
|
|
64
|
+
radius: {
|
|
65
|
+
type: 'number',
|
|
66
|
+
minimum: 1,
|
|
67
|
+
maximum: 1000,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
50
73
|
const publicParams = { config: { policy: 'L0' }, schema: schemaInfo, package: 'gis' }; // * L0 === public
|
|
51
74
|
const privilegedParams = { config: { policy: 'L1', role: 'admin' }, schema: schemaInfo, package: 'gis' }; // ? just auth or admin
|
|
52
75
|
|
|
@@ -137,6 +160,6 @@ export default async function route(app) {
|
|
|
137
160
|
}
|
|
138
161
|
|
|
139
162
|
if (!app.hasRoute({ method: 'GET', url: '/api/map-format' })) {
|
|
140
|
-
app.get('/map-format', publicParams, mapFormat);
|
|
163
|
+
app.get('/map-format', { ...publicParams, schema: mapFormatSchema }, mapFormat);
|
|
141
164
|
}
|
|
142
165
|
}
|
|
@@ -3,7 +3,7 @@ import { createHash } from 'node:crypto';
|
|
|
3
3
|
import Sphericalmercator from '@mapbox/sphericalmercator';
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
-
config, logger, pgClients,
|
|
6
|
+
config, logger, pgClients,
|
|
7
7
|
} from '@opengis/fastify-table/utils.js';
|
|
8
8
|
|
|
9
9
|
import mapnik from '../../../plugins/mapnik/funcs/mapnik.js';
|
|
@@ -54,7 +54,7 @@ export default async function rtile({
|
|
|
54
54
|
: {};
|
|
55
55
|
|
|
56
56
|
const carto = pg.pk?.['gis.cartocss']
|
|
57
|
-
? await pg.queryCache('select cartocss_id, source_path, is_public from gis.cartocss where cartocss_id=$1::text', { args: [id], table: 'gis.cartocss' }).then(el => el.rows?.[0] || {})
|
|
57
|
+
? await pg.queryCache('select cartocss_id, source_path, is_public, is_static from gis.cartocss where cartocss_id=$1::text', { args: [id], table: 'gis.cartocss' }).then(el => el.rows?.[0] || {})
|
|
58
58
|
: {};
|
|
59
59
|
|
|
60
60
|
if (carto.cartocss_id) {
|
|
@@ -62,6 +62,7 @@ export default async function rtile({
|
|
|
62
62
|
id: carto.cartocss_id,
|
|
63
63
|
source_path: carto.source_path,
|
|
64
64
|
is_public: carto.is_public,
|
|
65
|
+
is_static: carto.is_static,
|
|
65
66
|
type: 'css',
|
|
66
67
|
});
|
|
67
68
|
}
|
|
@@ -82,7 +83,7 @@ export default async function rtile({
|
|
|
82
83
|
|
|
83
84
|
try {
|
|
84
85
|
const ttl = (query.nocache ? '0' : null)
|
|
85
|
-
|| (data.type === 'css' ? '
|
|
86
|
+
|| (data.type === 'css' && !data.is_static ? '1w' : null);
|
|
86
87
|
|
|
87
88
|
const md5 = data.source_path
|
|
88
89
|
? createHash('md5').update(data.source_path).digest('hex')
|
|
@@ -110,6 +111,7 @@ export default async function rtile({
|
|
|
110
111
|
base64_path: base64,
|
|
111
112
|
raster: !!data.id,
|
|
112
113
|
carto: data.type === 'css',
|
|
114
|
+
is_static: data.type === 'css' ? data.is_static : true,
|
|
113
115
|
};
|
|
114
116
|
}
|
|
115
117
|
|