@opengis/gis 0.2.76 → 0.2.78

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.
@@ -11,24 +11,18 @@
11
11
  "group_id": {
12
12
  "type": "Autocomplete",
13
13
  "data": "gis.group_list",
14
- "col": 6,
14
+ "col": 12,
15
15
  "ua": "Група"
16
16
  },
17
- "cartocss_key": {
18
- "ua": "Унікальний ключ",
19
- "col": 6,
20
- "type": "Text",
21
- "validators": [
22
- "required"
23
- ]
17
+ "source_path": {
18
+ "ua": "Path",
19
+ "col": 12,
20
+ "type": "Text"
24
21
  },
25
22
  "description": {
26
23
  "ua": "Опис",
27
24
  "col": 12,
28
- "type": "TextArea",
29
- "validators": [
30
- "required"
31
- ]
25
+ "type": "TextArea"
32
26
  },
33
27
  "is_public": {
34
28
  "ua": "Чи є карта публічною?",
@@ -15,6 +15,11 @@
15
15
  "format": "text",
16
16
  "link": "/gis.cartocss/{id}"
17
17
  },
18
+ {
19
+ "ua": "Шлях",
20
+ "name": "source_path",
21
+ "format": "text"
22
+ },
18
23
  {
19
24
  "ua": "Опис",
20
25
  "name": "description",
@@ -30,13 +35,15 @@
30
35
  "ua": "Включений",
31
36
  "name": "enabled",
32
37
  "data": "yes_no",
33
- "format": "badge"
38
+ "format": "boolean",
39
+ "edit": true
34
40
  },
35
41
  {
36
42
  "ua": "Публічний",
37
43
  "name": "is_public",
38
44
  "data": "yes_no",
39
- "format": "badge"
45
+ "format": "boolean",
46
+ "edit": true
40
47
  }
41
48
  ],
42
49
  "filterList": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengis/gis",
3
- "version": "0.2.76",
3
+ "version": "0.2.78",
4
4
  "type": "module",
5
5
  "author": "Softpro",
6
6
  "main": "./dist/index.js",
@@ -52,12 +52,12 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@opengis/core": "^0.0.23",
55
- "@opengis/fastify-table": "^2.0.125",
55
+ "@opengis/fastify-table": "^2.0.132",
56
56
  "@opengis/filter": "0.1.31",
57
57
  "@opengis/form": "^0.0.103",
58
58
  "@opengis/table": "^0.0.27",
59
59
  "@vitejs/plugin-vue": "^5.2.4",
60
- "axios": "^1.13.2",
60
+ "axios": "^1.13.5",
61
61
  "eslint": "^8.57.1",
62
62
  "eslint-config-airbnb": "19.0.4",
63
63
  "eslint-plugin-import": "^2.32.0",
@@ -68,7 +68,7 @@
68
68
  "sass-embedded": "1.86.3",
69
69
  "typescript": "^5.9.3",
70
70
  "vite": "^6.4.1",
71
- "vue": "^3.5.26",
71
+ "vue": "^3.5.28",
72
72
  "vue-router": "4.5.1",
73
73
  "vuedraggable": "^4.1.0"
74
74
  }
@@ -18,3 +18,4 @@ create table if not exists gis.cartocss(
18
18
  );
19
19
 
20
20
  alter table gis.cartocss add column if not exists geom public.geometry;
21
+ alter table gis.cartocss add column if not exists source_path text;
@@ -11,6 +11,8 @@ service MapService {
11
11
  rpc RenderTile(RenderTileRequest) returns (RenderTileOut);
12
12
  rpc ClearTile(ClearTileRequest) returns (ClearTileOut);
13
13
  rpc ReadDir(ReadDirRequest) returns (ReadDirOut);
14
+ rpc FileStat(FileStatRequest) returns (FileStatOut);
15
+ rpc FileSearch(FileSearchRequest) returns (FileSearchOut);
14
16
  rpc CreateXML(CreateXMLRequest) returns (stream JobProgress); // streaming XML creation
15
17
  rpc UploadXML(UploadXMLRequest) returns (UploadXMLOut);
16
18
  rpc UploadRaster(UploadRasterRequest) returns (UploadRasterOut);
@@ -50,6 +52,33 @@ message ClearTileOut {
50
52
  string err = 2;
51
53
  }
52
54
 
55
+ message FileStatRequest {
56
+ string path = 1;
57
+ }
58
+
59
+ message FileStatOut {
60
+ bool exists = 1;
61
+ string name = 2;
62
+ int64 size = 3;
63
+ string adate = 4;
64
+ string cdate = 5;
65
+ string mdate = 6;
66
+ }
67
+
68
+ message FileSearchRequest {
69
+ string path = 1;
70
+ string key = 2;
71
+ string period = 3;
72
+ int64 size = 4;
73
+ }
74
+
75
+ message FileSearchOut {
76
+ bool exists = 1;
77
+ int32 count = 2;
78
+ repeated FileInfo files = 3;
79
+ repeated DirInfo directories = 4;
80
+ }
81
+
53
82
  message ReadDirRequest {
54
83
  string path = 1;
55
84
  }
@@ -58,12 +87,21 @@ message FileInfo {
58
87
  string name = 1;
59
88
  int64 size = 2;
60
89
  string date = 3;
90
+ string dir = 4;
91
+ }
92
+
93
+ message DirInfo {
94
+ string name = 1;
95
+ int64 size = 2;
96
+ string date = 3;
97
+ int64 children = 4;
61
98
  }
62
99
 
63
100
  message ReadDirOut {
64
101
  bool exists = 1;
65
102
  int32 count = 2;
66
103
  repeated FileInfo files = 3;
104
+ repeated DirInfo directories = 4;
67
105
  }
68
106
 
69
107
  message CreateXMLRequest {
@@ -75,12 +113,14 @@ message CreateXMLRequest {
75
113
  string name = 6;
76
114
  string debug = 7;
77
115
  string nocache = 8;
116
+ string proj4 = 9;
78
117
  }
79
118
 
80
119
  message UploadXMLRequest {
81
120
  string name = 1;
82
121
  string xml = 2;
83
122
  string encoding = 3;
123
+ string path = 4;
84
124
  }
85
125
 
86
126
  message UploadXMLOut {
@@ -144,6 +184,7 @@ message GetRasterInfoRequest {
144
184
  string path = 1;
145
185
  string ttl = 2;
146
186
  int64 srid = 3;
187
+ string proj4 = 4;
147
188
  }
148
189
 
149
190
  message FileItem {
@@ -1,29 +1,38 @@
1
- import { dataUpdate } from '@opengis/fastify-table/utils.js';
1
+ import { pgClients, dataUpdate } from '@opengis/fastify-table/utils.js';
2
2
 
3
3
  import uploadXML from '../../mapnik/functions/uploadXML.js';
4
4
 
5
5
  export default async function addCartocss(req, reply) {
6
- const { pg, body, params } = req;
6
+ const {
7
+ pg = pgClients.client, body, params, user,
8
+ } = req;
7
9
 
8
- const { id } = params;
9
- if (!id) return reply.status(400).send({ message: 'id is empty', status: 400 });
10
+ const cartocss = await pg.query('select cartocss_id, source_path, config, style from gis.cartocss where cartocss_id=$1', [params.id]).then(el => el.rows?.[0]);
10
11
 
11
- const { config: dataset, style } = body;
12
- if (!dataset && !style) return reply.status(400).send({ message: 'config, style is empty', status: 400 });
12
+ if (!cartocss) {
13
+ return reply.status(404).send({ error: 'cartocss not found', code: 404 });
14
+ }
13
15
 
14
- const selectCartocss = `select cartocss_id from gis.cartocss where cartocss_id=$1`;
15
- const cartocss = await pg.one(selectCartocss, [id]);
16
- if (!cartocss) return reply.status(404).send({ message: 'cartocss not found', status: 404 });
16
+ const sourcePath = body.source_path || cartocss.source_path;
17
+ const config = body.config || cartocss.config;
18
+ const style = body.style || cartocss.style;
19
+
20
+ const data = { ...body, config };
17
21
 
18
22
  await dataUpdate({
19
23
  pg,
20
- id,
24
+ id: params.id,
21
25
  table: 'gis.cartocss',
22
- data: { config: dataset, style },
23
- uid: req.user?.uid,
26
+ data,
27
+ uid: user?.uid,
24
28
  });
25
29
 
26
- await uploadXML({ id, dataset, style }, pg);
30
+ await uploadXML({
31
+ id: params.id,
32
+ dataset: config,
33
+ style,
34
+ source_path: sourcePath,
35
+ }, pg);
27
36
 
28
- return reply.status(200).send({ message: 'cartocss updated', status: 200 });
37
+ return reply.status(200).send({ message: 'cartocss updated', code: 200 });
29
38
  }
@@ -15,7 +15,7 @@ export default async function checkCarto({
15
15
  return reply.status(400).send({ error: 'mapnik server address needed', code: 400 });
16
16
  }
17
17
 
18
- const cartocss = await pg.query('select config, ARRAY[ST_XMin(geom), ST_YMin(geom), ST_XMax(geom), ST_YMax(geom)] as bounds, cartocss_key,name,description,style,group_id,enabled,is_public from gis.cartocss where cartocss_id=$1', [params.id]).then(el => el.rows?.[0]);
18
+ const cartocss = await pg.query('select config, ARRAY[ST_XMin(geom), ST_YMin(geom), ST_XMax(geom), ST_YMax(geom)] as bounds, cartocss_key,name,description,style,group_id,enabled,is_public, source_path from gis.cartocss where cartocss_id=$1', [params.id]).then(el => el.rows?.[0]);
19
19
 
20
20
  if (!cartocss) {
21
21
  return reply.status(404).send({ error: `cartocss not found: ${params.id}`, code: 404 });
@@ -39,6 +39,11 @@ export default async function layerList({
39
39
  )||'/{z}/{x}/{y}.png',null) as url, 'raster' as service, group_id,
40
40
  null as popup, null as card, null as filters, source_path
41
41
  from gis.rasters s where is_active and ${!user.uid ? 'is_public' : '1=1'}
42
+ union all
43
+ select cartocss_id as id, name, null as category, style, geom::box2d as bbox, st_asgeojson(geom)::json as geom,
44
+ coalesce('/api/gis-rtile/'||cartocss_id||'/{z}/{x}/{y}.png?nottl=1',null) as url, 'cartocss' as service, group_id,
45
+ null as popup, null as card, null as filters, source_path
46
+ from gis.cartocss where enabled and ${!user.uid ? 'is_public' : '1=1'}
42
47
  `;
43
48
 
44
49
  if (user.uid && sql) return q;
@@ -58,7 +63,7 @@ export default async function layerList({
58
63
  }
59
64
 
60
65
  // parse service style
61
- rows.forEach(row => Object.assign(row, { style: row.style ? yml2json(row.style) : null }));
66
+ rows.forEach(row => Object.assign(row, { style: row.style && ['vtile', 'geojson'].includes(row.service) ? yml2json(row.style) : row.style }));
62
67
  // parse extent string to number[]
63
68
  rows.filter(row => row.extent).forEach(row => Object.assign(row, {
64
69
  extent: row.extent.match(/BOX\(([^)]+)\)/)?.[1]
@@ -0,0 +1,94 @@
1
+ import { createHash } from 'node:crypto';
2
+
3
+ import { config, logger, pgClients } from '@opengis/fastify-table/utils.js';
4
+
5
+ import mapnik from '../../../plugins/mapnik/funcs/mapnik.js';
6
+
7
+ const { ClearTile } = mapnik();
8
+
9
+ /**
10
+ * Формування растрового tile cartoCss
11
+ *
12
+ * @method GET
13
+ * @alias rtile
14
+ * @param {String} bbox - bbox
15
+ * @param {Number} height - висота по координатам
16
+ * @param {Number} width - ширина по координатам
17
+ * @param {String} data - стилізація
18
+ * @param {String} lang - мова
19
+ * @param {String} z - координата z
20
+ * @param {String} x - координата y
21
+ * @param {String} y - координата x
22
+ */
23
+
24
+ export default async function clearTiles({
25
+ pg = pgClients.client, params, query,
26
+ }, reply) {
27
+ if (!ClearTile) {
28
+ return reply.status(400).send({ error: 'mapnik server address needed', code: 400 });
29
+ }
30
+
31
+ if (!params.id) {
32
+ return reply.status(400).send({ error: 'not enough params: id', code: 400 });
33
+ }
34
+
35
+ const decodedPath = Buffer.from(params.id, 'base64url').toString('utf-8');
36
+
37
+ const raster = pg.pk?.['gis.rasters']
38
+ ? await pg.query(`select raster_id, source_path from gis.rasters where raster_id=$1::text union all
39
+ select raster_id, source_path from gis.rasters where source_path=$2::text`, [params.id, decodedPath]).then(el => el.rows?.[0] || {})
40
+ : {};
41
+
42
+ const carto = pg.pk?.['gis.cartocss']
43
+ ? await pg.query(`select cartocss_id, source_path from gis.cartocss where cartocss_id=$1::text union all
44
+ select cartocss_id, source_path from gis.cartocss where source_path=$2::text`, [params.id, decodedPath]).then(el => el.rows?.[0] || {})
45
+ : {};
46
+
47
+ if (!raster.raster_id && !carto.cartocss_id) {
48
+ Object.assign(raster, { source_path: decodedPath });
49
+ }
50
+
51
+ if (!raster.source_path && !carto.cartocss_id) {
52
+ return reply.status(404).send({ error: 'raster / cartocss not found', code: 404 });
53
+ }
54
+
55
+ if (query.debug) {
56
+ const md5 = raster.source_path
57
+ ? createHash('md5').update(raster.source_path).digest('hex')
58
+ : undefined;
59
+ const base64 = raster.source_path
60
+ ? Buffer.from(raster.source_path).toString('base64url')
61
+ : undefined;
62
+ return {
63
+ id: raster.raster_id || carto.cartocss_id,
64
+ carto: !!carto.cartocss_id,
65
+ raster: !!raster.raster_id,
66
+ md5_path: md5,
67
+ base64_path: base64,
68
+ source_path: raster.source_path || carto.source_path,
69
+ };
70
+ }
71
+
72
+ try {
73
+ const data = await ClearTile({
74
+ path: carto.cartocss_id ? null : raster.source_path, // for rasters only
75
+ name: carto.cartocss_id && carto.source_path ? `vector/${carto.source_path}` : params.id, // required for cartocss
76
+ });
77
+
78
+ // if empty directory not found (no tiles rendered yet)
79
+ if (data.result === 'skip') {
80
+ return reply.status(200).send({ message: 'tiles directory not found', code: 200 });
81
+ }
82
+
83
+ // if cache deleted or empty directory exists = ok
84
+ if (data.result === 'success') {
85
+ return reply.status(200).send({ message: 'ok', code: 200 });
86
+ }
87
+
88
+ throw new Error(data.err);
89
+ }
90
+ catch (err) {
91
+ logger.file('clearTiles/error', { error: err.toString(), stack: err.stack });
92
+ return reply.status(500).send({ error: config.local ? err.toString() : 'clearTiles error', code: 500 });
93
+ }
94
+ }
@@ -47,12 +47,15 @@ export default async function createXml({
47
47
 
48
48
  const callback = eventStream(reply);
49
49
 
50
+ const proj4 = data.srid && pg.pk?.['public.spatial_ref_sys'] ? await pg.query('select proj4text from public.spatial_ref_sys where srid=$1', [data.srid]).then(el => el.rows?.[0]?.proj4text) : undefined;
51
+
50
52
  // create at xml/:id with name only, always - by path
51
53
  const resp = await CreateXML({
52
54
  path: data.source_path,
53
55
  name: id, // create additional xml named as primary key at xml directory
54
56
  previewZoom: data.raster_zoom, // preview<=>detailed, default = 16 if file size > 1GB
55
- srid: data.srid, // auto detected if not supplied
57
+ // srid: data.srid, // auto detected if not supplied
58
+ proj4,
56
59
  vrt: query.vrt, // force vrt even if relpath leads to single raster file
57
60
  debug: query.debug, // stream debug info
58
61
  nocache: query.nocache, // recreate if exists
@@ -0,0 +1,34 @@
1
+ import mapnik from '../../../plugins/mapnik/funcs/mapnik.js';
2
+
3
+ const { FileSearch } = mapnik();
4
+
5
+ const maxLimit = 100;
6
+
7
+ // example: GET /api/gis-files?dir=tiles/3828667893214610450/13/4884&key=1&size=1675&period=5m
8
+ export default async function fileSearch({
9
+ query,
10
+ }, reply) {
11
+ if (!FileSearch) {
12
+ return reply.status(400).send({ error: 'mapnik server address needed', code: 400 });
13
+ }
14
+
15
+ const {
16
+ dir, key, period, size, page,
17
+ } = query;
18
+
19
+ const limit = Math.min(query.limit || 16, maxLimit);
20
+ const offset = page && page > 0 ? (page - 1) * limit : 0;
21
+
22
+ if (!key && !period && !size) {
23
+ return reply.status(400).send({ error: 'not enough query params: key / period / size', code: 400 });
24
+ }
25
+
26
+ const result = await FileSearch({
27
+ path: dir, key, period, size,
28
+ });
29
+
30
+ return {
31
+ count: result.count,
32
+ data: (result.files || []).slice(offset, offset + limit).map(el => ({ type: 'file', ...el })),
33
+ };
34
+ }
@@ -0,0 +1,27 @@
1
+ import { config } from '@opengis/fastify-table/utils.js';
2
+
3
+ import mapnik from '../../../plugins/mapnik/funcs/mapnik.js';
4
+
5
+ const { FileStat } = mapnik();
6
+
7
+ // example: GET /api/gis-files?path=tiles/3828667893214610450/13/4884/2828.png
8
+ export default async function fileStat({
9
+ query,
10
+ }, reply) {
11
+ if (!config.mapServerAddress) {
12
+ return reply.status(400).send({ error: 'mapnik server not configured', code: 400 });
13
+ }
14
+
15
+ if (config.ready?.mapnik !== true) {
16
+ return reply.status(400).send({ error: 'mapnik server not ready', code: 400 });
17
+ }
18
+
19
+ const { path } = query || {};
20
+
21
+ if (!path) {
22
+ return reply.status(400).send({ error: 'not enough query params: path', code: 400 });
23
+ }
24
+
25
+ const data = await FileStat({ path });
26
+ return { data };
27
+ }
@@ -14,7 +14,7 @@ export default async function rtile({
14
14
  }
15
15
 
16
16
  const raster = pg.pk?.['gis.rasters']
17
- ? await pg.query('select raster_id, source_path, name, description, raster_key, is_active, is_public from gis.rasters where raster_id=$1::text', [params.id])
17
+ ? await pg.query('select raster_id, source_path, name, description, raster_key, is_active, is_public, srid from gis.rasters where raster_id=$1::text', [params.id])
18
18
  .then(el => el.rows?.[0] || {})
19
19
  : {};
20
20
 
@@ -27,12 +27,20 @@ export default async function rtile({
27
27
  Object.assign(raster, { source_path: decodedPath });
28
28
  }
29
29
 
30
+ const proj4 = raster.srid && pg.pk?.['public.spatial_ref_sys'] ? await pg.query('select proj4text from public.spatial_ref_sys where srid=$1', [raster.srid]).then(el => el.rows?.[0]?.proj4text) : undefined;
31
+
30
32
  const { data, cache } = await GetRasterInfo({
31
33
  path: raster.source_path,
34
+ // srid: raster.srid,
35
+ // proj4,
32
36
  ttl: query.nocache ? '0' : '1h',
33
37
  });
34
38
 
39
+ if (query.debug) {
40
+ return { data, cache, raster };
41
+ }
42
+
35
43
  return {
36
- ...data, ...raster, cache, url: `${prefix}/gis-rtile/${Buffer.from(raster.source_path).toString('base64url')}/{z}/{x}/{y}.png`,
37
- };
44
+ ...data, ...raster, cache, url: `${prefix}/gis-rtile/${Buffer.from(raster.source_path).toString('base64url')}/{z}/{x}/{y}.png`,
45
+ };
38
46
  }
@@ -0,0 +1,19 @@
1
+ import mapnik from '../../../plugins/mapnik/funcs/mapnik.js';
2
+
3
+ const { ReadDir } = mapnik();
4
+
5
+ // example: GET /api/gis-files?dir=tiles/3828667893214610450
6
+ export default async function readDir({
7
+ query,
8
+ }, reply) {
9
+ if (!ReadDir) {
10
+ return reply.status(400).send({ error: 'mapnik server address needed', code: 400 });
11
+ }
12
+
13
+ const { dir } = query;
14
+
15
+ const {
16
+ exists = false, count = 0, files = [], directories = [],
17
+ } = await ReadDir({ path: dir });
18
+ return { exists, count, data: files.map(el => ({ type: 'file', ...el })).concat(directories.map(el => ({ type: 'directory', ...el }))) };
19
+ }
@@ -51,10 +51,12 @@ export default async function rtile({
51
51
 
52
52
  // const relpath = raster ? `/map/raster/${raster.source_path}` : null;
53
53
 
54
- const cartoExists = pg.pk?.['gis.cartocss']
55
- ? await pg.query('select cartocss_id from gis.cartocss where cartocss_id=$1::text', [id])
56
- .then(el => el.rows?.[0]?.cartocss_id)
57
- : null;
54
+ const carto = pg.pk?.['gis.cartocss']
55
+ ? await pg.query('select cartocss_id, source_path from gis.cartocss where cartocss_id=$1::text', [id])
56
+ .then(el => el.rows?.[0] || {})
57
+ : {};
58
+
59
+ const cartoExists = !!carto.cartocss_id;
58
60
 
59
61
  if (!raster.raster_id && !cartoExists) {
60
62
  const decodedPath = Buffer.from(id, 'base64url').toString('utf-8');
@@ -68,30 +70,51 @@ export default async function rtile({
68
70
  const bbox = mercator.bbox(y, x, z, false, '900913');
69
71
 
70
72
  try {
73
+ const ttl = (query.nocache ? '0' : null)
74
+ || (cartoExists ? '1h' : null);
75
+
76
+ const md5 = raster.source_path
77
+ ? createHash('md5').update(raster.source_path).digest('hex')
78
+ : undefined;
79
+ const base64 = raster.source_path
80
+ ? Buffer.from(raster.source_path).toString('base64url')
81
+ : undefined;
82
+
71
83
  const data = await RenderTile({
72
84
  path: cartoExists ? null : raster.source_path, // for rasters only
73
- name: id, // required for cartocss
85
+ name: cartoExists && carto.source_path ? `vector/${carto.source_path}` : id, // required for cartocss
74
86
  width: 256,
75
87
  bbox,
76
- ttl: query.nocache ? '0' : '1h',
88
+ ttl,
77
89
  debug: query.debug,
78
90
  });
79
91
 
80
92
  if (query.debug) {
81
- return { ...data, md5_path: createHash('md5').update(raster.source_path).digest('hex'), base64_path: Buffer.from(raster.source_path).toString('base64url') };
93
+ return {
94
+ ...data,
95
+ ttl,
96
+ md5_path: md5,
97
+ base64_path: base64,
98
+ raster: !!raster.raster_id,
99
+ carto: cartoExists,
100
+ };
82
101
  }
83
102
 
84
103
  if (data.err) {
85
- logger.file('rtile/error', { error: data.err });
104
+ logger.file('rtile/error', {
105
+ error: data.err, x, y, z, id: cartoExists ? carto.cartocss_id : raster.raster_id, type: cartoExists ? 'css' : 'raster',
106
+ });
86
107
  return reply.status(500).send({ error: config.local ? data.err : 'render error', code: 500 });
87
108
  }
88
109
 
89
110
  const buffer = Buffer.from(data.base64, 'base64');
90
111
 
91
- return reply.headers({ 'Content-Type': 'image/png', 'Cache-Control': query.nocache ? 'no-store, no-cache, must-revalidate' : 'public, max-age=2592000' }).send(buffer);
112
+ return reply.headers({ 'Content-Type': 'image/png', 'Cache-Control': query.nocache || query.nottl ? 'no-store, no-cache, must-revalidate' : 'public, max-age=2592000' }).send(buffer);
92
113
  }
93
114
  catch (err) {
94
- logger.file('rtile/error', { error: err.toString(), stack: err.stack });
115
+ logger.file('rtile/error', {
116
+ error: err.toString(), stack: err.stack, x, y, z, id: cartoExists ? carto.cartocss_id : raster.raster_id, type: cartoExists ? 'css' : 'raster',
117
+ });
95
118
  return reply.status(500).send({ error: config.local ? err.toString() : 'rtile error', code: 500 });
96
119
  }
97
120
  }
@@ -2,6 +2,7 @@ import { pgClients } from "@opengis/fastify-table/utils.js";
2
2
 
3
3
  export default async function cartoBounds({ id, dataset }, pg = pgClients.client) {
4
4
  const sqlBounds = dataset.map(el => ({ tbl: el.table.split('.'), geom: el.gcol || 'geom' })).map(({ tbl, geom }) => `select ST_EstimatedExtent('${tbl[0]}','${tbl[1]}', '${geom}')`);
5
+ // const sqlBounds = dataset.map(el => ({ srid: el.srid || 4326, tbl: el.table.split('.'), geom: el.gcol || 'geom' })).map(({ tbl, geom, srid }) => `select st_transform(st_setsrid(ST_EstimatedExtent('${tbl[0]}','${tbl[1]}', '${geom}'),${srid}),4326) as st_estimatedextent`);
5
6
 
6
7
  const geom = await pg.query(
7
8
  `update gis.cartocss set
@@ -19,14 +19,14 @@ const getGeomColumn = (geoms, customColumn) => {
19
19
  import cartoBounds from './cartoBounds.js';
20
20
 
21
21
  function cartoData(el, extent, pg) {
22
- const minzoom = el.zoom ? (+el.zoom || 5) : 5;
22
+ const minzoom = el.minzoom ? (+el.minzoom || 5) : 5;
23
23
  const maxzoom = el.maxzoom ? (+el.maxzoom || 22) : 22;
24
24
  const view = `(select ${el.columns || '1'}, ${el.gcol} from ${el.table} where ${el.query || 'true'} ) as data`;
25
25
  const layerBound = extent || [-180, -85, 180, 85];
26
26
 
27
27
  return {
28
- id: el.caption,
29
- name: el.caption,
28
+ id: el.key,
29
+ name: el.key,
30
30
  properties: { minzoom, maxzoom },
31
31
  srs: el.proj4text || '+proj=longlat +datum=WGS84 +no_defs',
32
32
  Datasource: {
@@ -44,7 +44,9 @@ function cartoData(el, extent, pg) {
44
44
  };
45
45
  }
46
46
 
47
- export default async function uploadXML({ id, dataset, style }, pg) {
47
+ export default async function uploadXML({
48
+ id, dataset, style, source_path: relpath,
49
+ }, pg) {
48
50
  if (!id || !dataset?.length || Array.isArray(dataset) === false) {
49
51
  return null;
50
52
  }
@@ -67,7 +69,7 @@ export default async function uploadXML({ id, dataset, style }, pg) {
67
69
  srsList[srid] = await pg.query(`SELECT proj4text from spatial_ref_sys where srid=$1`, [srid])
68
70
  .then(e => e.rows[0]?.proj4text);
69
71
  }
70
- Object.assign(el, { gcol, proj4text: srsList[srid] });
72
+ Object.assign(el, { gcol, proj4text: el.proj4text || srsList[srid] });
71
73
  }));
72
74
 
73
75
  const bounds = await cartoBounds({ id, dataset }, pg);
@@ -96,9 +98,11 @@ export default async function uploadXML({ id, dataset, style }, pg) {
96
98
  throw new Error('xml generation error');
97
99
  }
98
100
  const { status } = await UploadXML({
99
- name: id,
101
+ path: relpath ? `vector/${relpath}` : null,
102
+ name: relpath ? null : id,
100
103
  xml: xmlFileText,
101
104
  });
105
+
102
106
  if (status !== 'success') {
103
107
  throw new Error('xml upload error');
104
108
  }
@@ -5,6 +5,10 @@ import rasterInfo from './controllers/rasterInfo.js';
5
5
  import mapnikStat from './controllers/mapnikStat.js';
6
6
  import mapnikLogger from './controllers/mapnikLogger.js';
7
7
  import createXmlMulti from './controllers/createXmlMulti.js';
8
+ import readDir from './controllers/readDir.js';
9
+ import fileStat from './controllers/fileStat.js';
10
+ import fileSearch from './controllers/fileSearch.js';
11
+ import clearTiles from './controllers/clearTiles.js';
8
12
 
9
13
  const publicParams = { config: { policy: 'L0' }, package: 'gis' }; // L0 === public
10
14
  const adminParams = { config: { policy: 'L1', role: 'admin' }, package: 'gis' };
@@ -18,4 +22,8 @@ export default async function route(app) {
18
22
  app.get('/gis-stat/:period?', adminParams, mapnikStat);
19
23
  app.get('/gis-logger/*', adminParams, mapnikLogger);
20
24
  app.get('/gis-create-xml/:id?', adminParams, createXmlMulti);
25
+ app.get('/gis-files', adminParams, readDir);
26
+ app.get('/gis-file-info', adminParams, fileStat);
27
+ app.get('/gis-file-search', adminParams, fileSearch);
28
+ app.get('/gis-clear-rtile/:id', adminParams, clearTiles);
21
29
  }