@opengis/gis 0.1.80 → 0.1.82

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.
@@ -1,5 +1,23 @@
1
- import { dataInsert, dataUpdate, pgClients } from "@opengis/fastify-table/utils.js";
1
+ import { dataDelete, dataInsert, dataUpdate, pgClients } from "@opengis/fastify-table/utils.js";
2
2
 
3
+ async function updateTemplate(client, body, name, uid, id) {
4
+ if (!body || !name || !id) return;
5
+
6
+ await dataDelete({
7
+ pg: client,
8
+ id,
9
+ table: 'admin.templates',
10
+ uid,
11
+ });
12
+ const rowCount = await dataInsert({
13
+ pg: client,
14
+ id,
15
+ table: 'admin.templates',
16
+ data: { body, name },
17
+ uid,
18
+ }).then(el => el.rowCount);
19
+ return rowCount;
20
+ }
3
21
  export default async function addService({
4
22
  method, params = {}, body, pg = pgClients.client, user = {},
5
23
  }, reply) {
@@ -7,24 +25,41 @@ export default async function addService({
7
25
  return reply.status(400).send('not enough params: id');
8
26
  }
9
27
 
10
- if (method === 'POST') {
11
- const { rows = [] } = await dataInsert({
12
- pg,
28
+ const { uid = '0' } = user;
29
+
30
+ const client = await pg.connect();
31
+ try {
32
+ await client.query('begin');
33
+
34
+ if (method === 'POST') {
35
+ const { rows = [] } = await dataInsert({
36
+ pg: client,
37
+ id: params.id,
38
+ table: 'gis.services',
39
+ data: body,
40
+ uid,
41
+ });
42
+ const istemplate = await updateTemplate(client, body.html, body.template, uid, rows[0]?.service_id);
43
+ await client.query('commit');
44
+ return reply.status(200).send(rows[0]);
45
+ }
46
+
47
+
48
+ const row = await dataUpdate({
49
+ pg: client,
13
50
  id: params.id,
14
51
  table: 'gis.services',
15
52
  data: body,
16
- uid: user?.uid,
53
+ uid,
17
54
  });
18
- return reply.status(200).send(rows[0]);
19
- }
55
+ const istemplate = await updateTemplate(client, body.html, body.template, uid, params.id);
56
+ await client.query('commit');
57
+ return reply.status(200).send(row);
20
58
 
21
- const row = await dataUpdate({
22
- pg,
23
- id: params.id,
24
- table: 'gis.services',
25
- data: body,
26
- uid: user?.uid,
27
- });
28
-
29
- return reply.status(200).send(row);
59
+ } catch (err) {
60
+ await client.query('rollback');
61
+ return reply.status(500).send(err.toString());
62
+ } finally {
63
+ client.release();
64
+ }
30
65
  }
@@ -1,4 +1,4 @@
1
- import { getMeta, pgClients, yml2json } from "@opengis/fastify-table/utils.js";
1
+ import { dataUpdate, getMeta, pgClients, yml2json } from "@opengis/fastify-table/utils.js";
2
2
 
3
3
  const table = 'gis.services';
4
4
 
@@ -21,12 +21,33 @@ export default async function getServices({ params = {}, pg = pgClients.client }
21
21
  SELECT
22
22
  service_id, service_key, name, description, keywords, category, holder, group_id, service_type,
23
23
  source_type, service_url, source_path, query, geom_type, geometry_column, sql_list, attributes, filters,
24
- popup, style, legend, card, srid, st_asgeojson(bbox)::json as bbox, st_asgeojson(center)::json as center, is_active as enabled, is_public, is_active, is_downloadable, metadata,
25
- metadata_url, thumbnail_url, created_by, updated_by, updated_at, created_at
24
+ popup, style, legend, card, srid, bbox::box2d as extent, st_asgeojson(bbox)::json as bbox, st_asgeojson(center)::json as center, is_active as enabled, is_public, is_active, is_downloadable, metadata,
25
+ metadata_url, thumbnail_url, created_by, updated_by, updated_at, created_at, template
26
26
  FROM gis.services where ${params.id ? 'service_id=$1' : '1=1'}
27
27
  `, [params.id].filter(Boolean)).then(el => el.rows || []);
28
28
 
29
+ if (params.id && rows[0]?.template) {
30
+ const html = await pg.query('select body from admin.templates where template_id=$1', [params.id]).then(el => el.rows?.[0]?.body);
31
+ Object.assign(rows[0], { html });
32
+ }
33
+
34
+ const noCenterIds = rows.filter(row => !row.center && row.bbox).map(row => row.service_id);
35
+
36
+ const centers = noCenterIds.length ? await pg.query(`SELECT json_object_agg(service_id, st_pointonsurface(bbox)::json) FROM gis.services where service_id=any($1)`, [noCenterIds].filter(Boolean)).then(el => el.rows?.[0]?.json_object_agg || {}) : {};
37
+
38
+ await Promise.all(rows.filter(row => centers[row.service_id]).map(async (row) => {
39
+ // console.log('update service center', row.service_id, JSON.stringify(centers[row.service_id]));
40
+ await dataUpdate({ pg, id: row.service_id, table: 'gis.services', data: { center: centers[row.service_id] } });
41
+ Object.assign(row, { center: centers[row.service_id] });
42
+ }));
43
+
29
44
  rows.forEach(row => Object.assign(row, { style: row.style ? yml2json(row.style) : undefined }));
45
+ rows.forEach(row => Object.assign(row, { center: row.center?.coordinates }));
46
+ rows.filter(row => row.extent).forEach(row => Object.assign(row, {
47
+ extent: row.extent.match(/BOX\(([^)]+)\)/)?.[1]
48
+ ?.replace?.(/ /g, ",")
49
+ ?.split?.(",")
50
+ }));
30
51
 
31
52
  if (params.id && !rows.length) {
32
53
  return reply.status(404).send('service not found');
@@ -37,9 +37,9 @@ export default async function mapFormat(req, reply) {
37
37
  }
38
38
  }
39
39
 
40
- let source_path, attributes, tpl, cardInterface;
40
+ let source_path, tpl, cardInterface, card, template;
41
41
  if (service) {
42
- ({ source_path, attributes, interface: cardInterface } = service);
42
+ ({ source_path, interface: cardInterface, card, template } = service);
43
43
  } else {
44
44
  // git
45
45
  tpl = await getTemplate('map', map);
@@ -48,11 +48,12 @@ export default async function mapFormat(req, reply) {
48
48
  return reply.status(404).send('template not found');
49
49
  };
50
50
  source_path = matchedLayer.source_path;
51
- attributes = matchedLayer.card;
51
+ card = matchedLayer.card;
52
+ template = matchedLayer.template;
52
53
 
53
54
  }
54
55
 
55
- const columns = attributes;
56
+ const columns = card;
56
57
  if (!source_path) return reply.status(404).send('missing source_path');
57
58
 
58
59
  const pk = pg.pk?.[source_path];
@@ -102,13 +103,22 @@ export default async function mapFormat(req, reply) {
102
103
  </div>`);
103
104
  }
104
105
 
105
- const html = `<dl class="divide-y divide-gray-100 py-[5px]">${result.join('')}</dl>`;
106
+ const htmlTemplate = pg?.pk?.['admin.template']
107
+ ? await pg.query('select body from admin.templates where name=$1 limit 1').then(el => el.rows?.[0]?.body)
108
+ : null;
109
+
110
+ const html1 = await handlebars.compile(htmlTemplate || 'template not found')(fullRow);
111
+
112
+ const html = template
113
+ ? html1
114
+ : `<dl class="divide-y divide-gray-100 py-[5px]">${result.join('')}</dl>`;
106
115
 
107
116
  const res = {
108
117
  time: Date.now() - time,
109
118
  id,
110
119
  rows: fullRow,
111
120
  columns,
121
+ template,
112
122
  html
113
123
  };
114
124
  if (service) {
@@ -31,7 +31,8 @@ export default async function markerIconApi(req, reply) {
31
31
  const iconPath = path.join(fileIconDir, params?.data);
32
32
 
33
33
  if (fs.existsSync(iconPath)) {
34
- return fs.createReadStream(iconPath);
34
+ const buffer = fs.readFileSync(iconPath); // works for small files same as stream, but also unit-test-friendly
35
+ return reply.type('image/png').send(buffer);
35
36
  }
36
37
 
37
38
  await downloadImage(`https://data.softpro.ua/api-user/marker/${params.data}`, iconPath).catch(err => {
@@ -60,6 +60,8 @@ export default async function route(app) {
60
60
  app.get('/gis-layer-list', { config: { policy }, }, layerList);
61
61
  }
62
62
 
63
+ app.get('/gis-icon/*', { config: { policy }, schema: {} }, markerIconApi);
64
+ app.get('/icon/*', { config: { policy }, schema: {} }, markerIconApi);
63
65
  app.get('/marker-icon/*', { config: { policy }, schema: {} }, markerIconApi);
64
66
  app.get('/map-format', { config: { policy }, schema: {} }, mapFormat);
65
67
  }
@@ -5,6 +5,7 @@ const headers = {
5
5
  import Sphericalmercator from '@mapbox/sphericalmercator';
6
6
  const mercator = new Sphericalmercator({ size: 256 });
7
7
  import { getTemplate, getMeta, getFilterSQL } from '@opengis/fastify-table/utils.js';
8
+ import yaml from 'js-yaml';
8
9
 
9
10
  export default async function vtile({ params = {}, query, pg, user }, reply) {
10
11
  const { y, z } = params;
@@ -23,7 +24,7 @@ export default async function vtile({ params = {}, query, pg, user }, reply) {
23
24
 
24
25
  const geom = data1?.geometry_column || 'geom';
25
26
  const table = data?.table_name || data1?.source_path;
26
- const style = mapStyle || data?.style || data1?.style;
27
+ const style = mapStyle || data?.style || yaml.load(data1?.style);
27
28
  const filterList = data?.filter_list || data1?.filters;
28
29
  const layerQuery = data?.query || data1?.query;
29
30