@opengis/gis 0.2.167 → 0.2.169

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.
Files changed (249) hide show
  1. package/dist/{CardIcon-golqfa-Y.js → CardIcon-xkRDr3_E.js} +1 -1
  2. package/dist/{EntityTablePage-BhmxePgR.js → EntityTablePage-D1IR5Bmq.js} +1 -1
  3. package/dist/{ExtentOutlineLayer.vue_vue_type_script_setup_true_lang-BFa27smR.js → ExtentOutlineLayer.vue_vue_type_script_setup_true_lang-BJKIgAkD.js} +1 -1
  4. package/dist/{HeaderActions.vue_vue_type_script_setup_true_lang-Dp0MjgnU.js → HeaderActions.vue_vue_type_script_setup_true_lang-BU8__ouG.js} +1 -1
  5. package/dist/{MapSettings-F_DT3xKl.js → MapSettings-DIOlNpt6.js} +1 -1
  6. package/dist/{RastersTablePage-3rXQ0baG.js → RastersTablePage-OD1VqHP8.js} +1 -1
  7. package/dist/{cartocss-CN-UrS7V.js → cartocss-BiamDcNB.js} +5 -5
  8. package/dist/{import-utils-F5ErbNz1.js → import-utils-CvUG1jV0.js} +1 -1
  9. package/dist/{index-CdB0VXro.js → index-C6W8IkTm.js} +1224 -1221
  10. package/dist/index.css +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/index.umd.cjs +53 -40
  13. package/dist/{raster-DWmiWlf7.js → raster-BbIiZGoX.js} +3 -3
  14. package/dist/{register-D1jLD0hK.js → register-Dt2QoLZ3.js} +3 -3
  15. package/dist/service-CdUYntMi.js +3472 -0
  16. package/dist/{vs-datatable-BWItxbtK.js → vs-datatable-BELnJrfM.js} +2 -3
  17. package/module/gis/card/gis.metadata.table/index.yml +22 -22
  18. package/module/gis/card/gis.rasters.table/index.yml +11 -11
  19. package/module/gis/card/gis.registers.table/index.yml +23 -23
  20. package/module/gis/card/gis.services.table/index.yml +25 -25
  21. package/module/gis/cls/bool.yes_no.json +12 -12
  22. package/module/gis/cls/encoding.json +14 -14
  23. package/module/gis/cls/geom_type.json +14 -14
  24. package/module/gis/cls/gis.column_type.json +34 -34
  25. package/module/gis/cls/gis.column_view_type.json +26 -26
  26. package/module/gis/cls/gis.filter_type.json +22 -22
  27. package/module/gis/cls/language.json +10 -10
  28. package/module/gis/cls/meta.service_type.json +42 -42
  29. package/module/gis/cls/ogc.service.json +21 -21
  30. package/module/gis/cls/source_type.json +10 -10
  31. package/module/gis/cls/standarts.json +6 -6
  32. package/module/gis/cls/topic_category.json +106 -106
  33. package/module/gis/cls/update_frequency.json +29 -29
  34. package/module/gis/cls/view.json +21 -21
  35. package/module/gis/form/feedback.answer.form.json +10 -10
  36. package/module/gis/form/gis.cartocss.form.json +64 -64
  37. package/module/gis/form/gis.group_list.form.json +17 -17
  38. package/module/gis/form/gis.maps.form.json +61 -61
  39. package/module/gis/form/gis.metadata.form.json +240 -240
  40. package/module/gis/form/gis.metadata_new.form.json +195 -195
  41. package/module/gis/form/gis.ogc_service.form.json +51 -51
  42. package/module/gis/form/gis.rasters.form.json +76 -76
  43. package/module/gis/form/gis.registers.form.json +124 -124
  44. package/module/gis/form/gis.registers_column.form.json +84 -84
  45. package/module/gis/form/gis.registers_filter.form.json +65 -65
  46. package/module/gis/form/gis.services.form.json +111 -111
  47. package/module/gis/form/gis.services_attributes.form.json +75 -75
  48. package/module/gis/form/gis.services_filter.form.json +65 -65
  49. package/module/gis/menu.json +43 -43
  50. package/module/gis/select/admin.cls.name.sql +9 -9
  51. package/module/gis/select/layer_list.sql +7 -7
  52. package/module/gis/select/layer_list_text.sql +7 -7
  53. package/module/gis/select/pg.column_name.geometry.sql +12 -12
  54. package/module/gis/select/pg.columns.parent.sql +6 -6
  55. package/module/gis/select/pg.table_name.sql +17 -17
  56. package/module/gis/select/service_id.sql +1 -1
  57. package/module/gis/select/srid.sql +7 -7
  58. package/module/gis/table/gis.cartocss.table.json +74 -74
  59. package/module/gis/table/gis.group_list.table.json +58 -58
  60. package/module/gis/table/gis.maps.table.json +110 -110
  61. package/module/gis/table/gis.metadata.table.json +70 -70
  62. package/module/gis/table/gis.metadata_new.table.json +137 -137
  63. package/module/gis/table/gis.ogc_service.table.json +100 -100
  64. package/module/gis/table/gis.rasters.table.json +113 -113
  65. package/module/gis/table/gis.registers.table.json +143 -143
  66. package/module/gis/table/gis.services.table.json +120 -120
  67. package/module/gis/table/site.gis.registers.table.json +88 -88
  68. package/module/gis/table/site.gis.services.table.json +106 -106
  69. package/module/gis/templates/ISO19136_2017_gml_template.xml +330 -330
  70. package/module/gis/tokens.yml +5 -5
  71. package/module/permissions/form/permissions.users.form.json +151 -151
  72. package/module/permissions/table/gis.permissions.table.json +97 -97
  73. package/module/test/map/addr.json +303 -0
  74. package/module/test/map/{addr.yml → addr1.yml} +3 -1
  75. package/module/test/select/address.str_id.sql +3 -0
  76. package/package.json +10 -10
  77. package/plugin.js +21 -12
  78. package/server/plugins/mapnik/funcs/checkRasterFile.js +1 -3
  79. package/server/routes/cartocss/cartocss.route.js +31 -0
  80. package/server/routes/cartocss/cartocss.route.test.js +79 -0
  81. package/server/routes/cartocss/cartocss.schema.js +73 -0
  82. package/server/routes/{gis/cartocss → cartocss/functions}/add.cartocss.js +8 -11
  83. package/server/routes/{gis/cartocss → cartocss/functions}/get.cartocss.js +11 -13
  84. package/server/routes/gis/functions/checkXML.js +107 -0
  85. package/server/routes/gis/functions/dashboard.js +24 -0
  86. package/server/routes/gis/gis.route.js +26 -0
  87. package/server/routes/gis/gis.route.test.js +34 -0
  88. package/server/routes/gis/gis.schema.js +1 -0
  89. package/server/routes/map/{controllers → functions}/clearTiles.js +9 -8
  90. package/server/routes/map/{controllers → functions}/geojson.js +43 -43
  91. package/server/routes/map/{controllers → functions}/gis.convert.js +15 -23
  92. package/server/routes/map/{controllers → functions}/gis.icon.js +23 -10
  93. package/server/routes/map/{controllers → functions}/jsonData.js +72 -71
  94. package/server/routes/map/{controllers → functions}/layerList.js +17 -17
  95. package/server/routes/map/{controllers → functions}/map.js +8 -9
  96. package/server/routes/map/{controllers → functions}/mapCatalog.js +7 -7
  97. package/server/routes/map/functions/mapCatalogAttribute.js +54 -0
  98. package/server/routes/map/{controllers → functions}/mapFeatures.js +22 -18
  99. package/server/routes/map/{controllers → functions}/mapFormat.js +25 -28
  100. package/server/routes/map/{controllers → functions}/mapTiles.js +39 -30
  101. package/server/routes/map/{controllers → functions}/maps.js +3 -3
  102. package/server/routes/map/{controllers → functions}/marker_icon.js +1 -1
  103. package/server/routes/map/{controllers → functions}/parseGeoFile.js +10 -11
  104. package/server/routes/map/{controllers → functions}/pointHeight.js +3 -7
  105. package/server/routes/map/{controllers → functions}/vtile.js +5 -3
  106. package/server/routes/map/{vtile1.js → functions/vtile1.js} +39 -33
  107. package/server/routes/map/map.route.js +280 -0
  108. package/server/routes/map/map.route.test.js +503 -0
  109. package/server/routes/map/map.schema.js +356 -0
  110. package/server/routes/mapnik/{controllers → functions}/clearTiles.js +26 -29
  111. package/server/routes/mapnik/{controllers → functions}/createXml.js +17 -20
  112. package/server/routes/mapnik/{controllers → functions}/createXmlMulti.js +11 -15
  113. package/server/routes/mapnik/{controllers → functions}/fileSearch.js +6 -9
  114. package/server/routes/mapnik/functions/fileStat.js +28 -0
  115. package/server/routes/mapnik/{controllers → functions}/pretile.js +29 -35
  116. package/server/routes/mapnik/{controllers → functions}/rasterInfo.js +19 -10
  117. package/server/routes/mapnik/{controllers → functions}/readDir.js +4 -4
  118. package/server/routes/mapnik/functions/rtile.js +164 -0
  119. package/server/routes/mapnik/{controllers → functions}/uploadRaster.js +19 -24
  120. package/server/routes/mapnik/functions/uploadXML.js +27 -0
  121. package/server/routes/mapnik/mapnik.route.js +102 -0
  122. package/server/routes/mapnik/mapnik.route.test.js +371 -0
  123. package/server/routes/mapnik/mapnik.schema.mjs +190 -0
  124. package/server/routes/mapnik.prefixless/functions/mapnikLogger.js +31 -0
  125. package/server/routes/{mapnik/controllers → mapnik.prefixless/functions}/mapnikStat.js +7 -5
  126. package/server/routes/mapnik.prefixless/mapnik.prefixless.route.js +20 -0
  127. package/server/routes/mapnik.prefixless/mapnik.prefixless.route.test.js +91 -0
  128. package/server/routes/mapnik.prefixless/mapnik.prefixless.schema.mjs +27 -0
  129. package/server/routes/maps/functions/add.map.js +42 -0
  130. package/server/routes/{map/maps → maps/functions}/del.map.js +6 -7
  131. package/server/routes/{map/maps → maps/functions}/get.map.js +12 -11
  132. package/server/routes/maps/maps.route.js +58 -0
  133. package/server/routes/maps/maps.route.test.js +231 -0
  134. package/server/routes/maps/maps.schema.js +10 -0
  135. package/server/routes/metadata/functions/editMetadata.js +35 -0
  136. package/server/routes/metadata/functions/metadataXML.js +19 -0
  137. package/server/routes/metadata/metadata.route.js +26 -0
  138. package/server/routes/metadata/metadata.route.test.js +47 -0
  139. package/server/routes/metadata/metadata.schema.js +53 -0
  140. package/server/routes/{gis/ogc → ogc/functions}/map.info.point.js +22 -29
  141. package/server/routes/ogc/ogc.route.js +21 -0
  142. package/server/routes/ogc/ogc.route.test.js +54 -0
  143. package/server/routes/ogc/ogc.schema.js +16 -0
  144. package/server/routes/permissions/functions/catalog.permissions.edit.js +20 -0
  145. package/server/routes/permissions/functions/catalog.permissions.js +13 -0
  146. package/server/routes/permissions/{controllers → functions}/gis.catalog.js +10 -10
  147. package/server/routes/permissions/permissions.route.js +35 -0
  148. package/server/routes/permissions/permissions.route.test.js +35 -0
  149. package/server/routes/permissions/permissions.schema.js +44 -0
  150. package/server/routes/registers/functions/add.registry.js +37 -0
  151. package/server/routes/{gis/registers/funcs → registers/functions}/classifiers.js +2 -2
  152. package/server/routes/{gis/registers → registers/functions}/del.registry.js +5 -5
  153. package/server/routes/{gis/registers/funcs → registers/functions}/get.info.js +9 -5
  154. package/server/routes/{gis/registers → registers/functions}/gis.export.js +27 -21
  155. package/server/routes/{gis/registers → registers/functions}/gis.registry.js +22 -15
  156. package/server/routes/{gis/registers → registers/functions}/gis.registry.list.js +12 -10
  157. package/server/routes/{gis/registers/funcs → registers/functions}/handleRegistryRequest.js +12 -11
  158. package/server/routes/registers/registers.route.js +80 -0
  159. package/server/routes/registers/registers.route.test.js +145 -0
  160. package/server/routes/registers/registers.schema.js +246 -0
  161. package/server/routes/{gis/services → services/functions}/add.service.js +14 -16
  162. package/server/routes/services/functions/create.route.js +93 -0
  163. package/server/routes/{gis/services → services/functions}/del.service.js +5 -5
  164. package/server/routes/{gis/services → services/functions}/get.service.users.js +15 -13
  165. package/server/routes/services/functions/get.services.col.js +34 -0
  166. package/server/routes/{gis/services → services/functions}/get.services.js +21 -16
  167. package/server/routes/services/services.route.js +76 -0
  168. package/server/routes/services/services.route.test.js +168 -0
  169. package/server/routes/services/services.schema.js +278 -0
  170. package/server/routes/widgets/functions/add.widget.js +39 -0
  171. package/server/routes/widgets/functions/del.widget.js +18 -0
  172. package/server/routes/{map/widgets → widgets/functions}/get.widget.js +12 -11
  173. package/server/routes/widgets/widgets.route.js +61 -0
  174. package/server/routes/widgets/widgets.route.test.js +144 -0
  175. package/server/routes/widgets/widgets.schema.js +25 -0
  176. package/dist/service-JGNtth-y.js +0 -2593
  177. package/module/cls.json +0 -7
  178. package/module/gis/card/gis.metadata.table/main_info.hbs +0 -21
  179. package/module/gis/card/gis.metadata.table/metadata_info.hbs +0 -28
  180. package/module/gis/card/gis.metadata.table/other.hbs +0 -26
  181. package/module/gis/card/gis.rasters.table/main_info.hbs +0 -27
  182. package/module/gis/card/gis.registers.table/cls.hbs +0 -36
  183. package/module/gis/card/gis.registers.table/columns.hbs +0 -89
  184. package/module/gis/card/gis.registers.table/filters.hbs +0 -80
  185. package/module/gis/card/gis.registers.table/main_info.hbs +0 -35
  186. package/module/gis/card/gis.registers.table/source.hbs +0 -45
  187. package/module/gis/card/gis.services.table/attributes.hbs +0 -91
  188. package/module/gis/card/gis.services.table/filters.hbs +0 -83
  189. package/module/gis/card/gis.services.table/main_info.hbs +0 -27
  190. package/module/gis/card/gis.services.table/source.hbs +0 -26
  191. package/module/test/cls/bp_build_type.json +0 -37
  192. package/module/test/cls/doc_status.json +0 -32
  193. package/module/test/cls/ts.temp_status.json +0 -18
  194. package/module/test/cls/ts.temp_structure.ts_class.json +0 -50
  195. package/module/test/cls/ts.temp_type.json +0 -10
  196. package/module/test/layer/bp.json +0 -60
  197. package/module/test/layer/bp1.yml +0 -33
  198. package/module/test/layer/individual.yml +0 -54
  199. package/module/test/layer/ts.linking_passport.yml +0 -56
  200. package/module/test/layer/ts.temp_structure.yml +0 -51
  201. package/module/test/map/bp_myo.json +0 -44
  202. package/module/test/map/bpf.json +0 -44
  203. package/module/test/map/main.json +0 -39
  204. package/module/test/map/mbd.json +0 -92
  205. package/module/test/map/ts.json +0 -53
  206. package/module/test/select/address_id.json +0 -3
  207. package/module/test/select/address_id.sql +0 -8
  208. package/module/test/select/core.user_uid.sql +0 -1
  209. package/module/test/table/data_address.street.table.json +0 -70
  210. package/module/test/table/data_bp_myo.bp.table.json +0 -123
  211. package/server/routes/gis/checkXML.js +0 -117
  212. package/server/routes/gis/dashboard.js +0 -29
  213. package/server/routes/gis/index.mjs +0 -92
  214. package/server/routes/gis/metadata/editMetadata.js +0 -34
  215. package/server/routes/gis/metadata/metadataXML.js +0 -13
  216. package/server/routes/gis/registers/add.registry.js +0 -35
  217. package/server/routes/gis/registers/insert.columns.js +0 -107
  218. package/server/routes/gis/registers/insert.filters.js +0 -110
  219. package/server/routes/gis/services/create.route.js +0 -96
  220. package/server/routes/gis/services/get.services.col.js +0 -33
  221. package/server/routes/map/controllers/mapCatalogAttribute.js +0 -56
  222. package/server/routes/map/index.mjs +0 -259
  223. package/server/routes/map/maps/add.map.js +0 -43
  224. package/server/routes/map/widgets/add.widget.js +0 -39
  225. package/server/routes/map/widgets/del.widget.js +0 -23
  226. package/server/routes/mapnik/controllers/fileStat.js +0 -28
  227. package/server/routes/mapnik/controllers/mapnikLogger.js +0 -29
  228. package/server/routes/mapnik/controllers/rtile.js +0 -167
  229. package/server/routes/mapnik/index.js +0 -40
  230. package/server/routes/permissions/controllers/catalog.permissions.edit.js +0 -22
  231. package/server/routes/permissions/controllers/catalog.permissions.js +0 -8
  232. package/server/routes/permissions/index.mjs +0 -18
  233. /package/server/routes/map/{controllers/pin → pin}/circle1.svg +0 -0
  234. /package/server/routes/map/{controllers/pin → pin}/circle2.svg +0 -0
  235. /package/server/routes/map/{controllers/pin → pin}/none.svg +0 -0
  236. /package/server/routes/map/{controllers/pin → pin}/pin.svg +0 -0
  237. /package/server/routes/map/{controllers/pin → pin}/pin1.svg +0 -0
  238. /package/server/routes/map/{controllers/pin → pin}/pin2.svg +0 -0
  239. /package/server/routes/map/{controllers/pin → pin}/pin3.svg +0 -0
  240. /package/server/routes/map/{controllers/pin → pin}/pin4.svg +0 -0
  241. /package/server/routes/map/{controllers/pin → pin}/pin5.svg +0 -0
  242. /package/server/routes/map/{controllers/pin → pin}/pin6.svg +0 -0
  243. /package/server/routes/map/{controllers/pin → pin}/pin7.svg +0 -0
  244. /package/server/routes/permissions/{controllers/utils → functions}/get.permissions.js +0 -0
  245. /package/server/routes/{gis/registers/funcs → registers/functions}/columns.js +0 -0
  246. /package/server/routes/{gis/registers/funcs → registers/functions}/content.type.js +0 -0
  247. /package/server/routes/{gis/registers → registers/functions}/map.registry.js +0 -0
  248. /package/server/routes/{gis/services → services/functions}/get.layer.geom.js +0 -0
  249. /package/server/routes/{gis/services → services/functions}/legend.auto.js +0 -0
@@ -2,6 +2,7 @@ import { config, pgClients } from '@opengis/fastify-table/utils.js';
2
2
 
3
3
  import mapnik from '../../../plugins/mapnik/funcs/mapnik.js';
4
4
  import cartoBounds from '../../mapnik/functions/cartoBounds.js';
5
+ import { NotFoundError, NotImplementedError } from '@opengis/fastify-table/errors.js';
5
6
 
6
7
  const { RenderTile } = mapnik();
7
8
 
@@ -10,39 +11,36 @@ const { prefix = '/api' } = config;
10
11
  const exclude = ['created_at', 'updated_at', 'created_by', 'updated_by'];
11
12
 
12
13
  export default async function checkCarto({
13
- pg = pgClients.client, params, query, user,
14
- }, reply) {
14
+ id, sql, nocache, isAdmin,
15
+ }, pg = pgClients.client) {
15
16
  const time = Date.now();
16
17
  if (!config.mapnik?.server) {
17
- return reply.status(400).send({ error: 'mapnik server address needed', code: 400 });
18
+ throw NotImplementedError('mapnik server address needed');
18
19
  }
19
20
 
20
- const { sql } = query || {};
21
-
22
21
  // extract all columns, migrations-agnostic
23
- const cartocss = await pg.query('select *, ARRAY[ST_XMin(geom), ST_YMin(geom), ST_XMax(geom), ST_YMax(geom)] as bounds, st_asgeojson(geom)::json as geom, source_path from gis.cartocss where cartocss_id=$1', [params.id]).then(el => el.rows?.[0]);
22
+ const cartocss = await pg.query('select *, ARRAY[ST_XMin(geom), ST_YMin(geom), ST_XMax(geom), ST_YMax(geom)] as bounds, st_asgeojson(geom)::json as geom, source_path from gis.cartocss where cartocss_id=$1', [id]).then(r => r.rows?.[0]);
24
23
 
25
24
  if (!cartocss) {
26
- return reply.status(404).send({ error: `cartocss not found: ${params.id}`, code: 404 });
25
+ throw NotFoundError(`cartocss not found: ${id}`);
27
26
  }
28
27
 
29
28
  // filter system columns
30
29
  Object.keys(cartocss).filter(key => exclude.includes(key)).forEach(key => delete cartocss[key]);
31
30
 
32
31
  const rtile = await RenderTile({
33
- name: cartocss.source_path ? `vector/${cartocss.source_path}` : params.id, // required for cartocss
32
+ name: cartocss.source_path ? `vector/${cartocss.source_path}` : id, // required for cartocss
34
33
  width: 256,
35
34
  bbox: [3713463.7081504324, 6088362.176970857, 3713616.5822070027, 6088515.051027427],
36
35
  ttl: '0',
37
- // debug: query.debug,
38
36
  }).catch(err => ({ err: err.toString() }));
39
37
 
40
38
  // skip empty bounds[null,null,null,null]
41
- const bounds = cartocss.bounds && cartocss.geom && !(query.nocache && user?.user_type?.includes?.('admin')) ? cartocss.bounds : await cartoBounds({
42
- id: params.id, dataset: cartocss.config, table: cartocss.card_table, sql,
39
+ const bounds = cartocss.bounds && cartocss.geom && !(nocache && isAdmin) ? cartocss.bounds : await cartoBounds({
40
+ id: id, dataset: cartocss.config, table: cartocss.card_table, sql,
43
41
  }, pg).catch(err => ({ err: err.toString() }));
44
42
 
45
- if (!(cartocss.bounds && cartocss.geom) && sql && user?.user_type?.includes?.('admin')) {
43
+ if (!(cartocss.bounds && cartocss.geom) && sql && isAdmin) {
46
44
  return bounds;
47
45
  }
48
46
 
@@ -50,7 +48,7 @@ export default async function checkCarto({
50
48
  time: Date.now() - time,
51
49
  ...cartocss,
52
50
  info: !!(cartocss.card_auto || (cartocss.card_html && cartocss.card_table)),
53
- url: `${prefix}/gis-rtile/${params.id}/{z}/{x}/{y}.png`,
51
+ url: `${prefix}/gis-rtile/${id}/{z}/{x}/{y}.png`,
54
52
  bounds,
55
53
  render: !!rtile.base64,
56
54
  renderError: rtile.err && config.local ? rtile.err : !!rtile.err,
@@ -0,0 +1,107 @@
1
+ import path from 'node:path';
2
+
3
+ import mapnik from "../../../plugins/mapnik/funcs/mapnik.js";
4
+
5
+ export default async function checkXML(pg, send = () => { }) {
6
+ if (!pg?.pk) {
7
+ throw new Error("empty pg");
8
+ }
9
+
10
+ const {
11
+ GetRasterStatus, GetRasterInfo, RenderTile,
12
+ } = mapnik();
13
+
14
+ const errors = { raster: 0, css: 0, service: 0 };
15
+
16
+ const rasters = pg.pk['gis.rasters'] ? await pg.query('select * from gis.rasters').then(r => r.rows || []) : [];
17
+
18
+ const css = pg.pk['gis.cartocss'] ? await pg.query('select * from gis.cartocss').then(r => r.rows || []) : [];
19
+
20
+ const dataset = pg.pk['gis.dataset'] && false ? await pg.query('select * from gis.dataset').then(r => r.rows || []) : [];
21
+
22
+ const total = rasters.length + css.length + dataset.length;
23
+ let successCount = 0;
24
+
25
+ send(`Всього растрів: ${rasters.length || '0'}`);
26
+
27
+ await rasters.reduce(
28
+ (promise, row, idx) => promise.then(async () => {
29
+ const uploadStatus = path.extname(row.source_path) ? await GetRasterStatus({ path: row.source_path }) : {};
30
+
31
+ if (uploadStatus.exists === false) {
32
+ errors.raster += 1;
33
+ send(`${idx}/${rasters.length} ERROR: GetRasterStatus: not uploaded (raster:${row.raster_id}/${row.name})`);
34
+ return null;
35
+ }
36
+
37
+ if (uploadStatus.finished === false) {
38
+ errors.raster += 1;
39
+ send(`${idx}/${rasters.length} ERROR: GetRasterStatus: upload not finished (raster:${row.raster_id}/${row.name})`);
40
+ return null;
41
+ }
42
+
43
+ const rasterInfo = await GetRasterInfo({
44
+ path: row.source_path,
45
+ }).catch(err => ({ err }));
46
+
47
+ if (rasterInfo.err) {
48
+ errors.raster += 1;
49
+ send(`${idx}/${rasters.length} ERROR: GetRasterInfo: ${rasterInfo.err} (raster:${row.raster_id}/${row.name})`);
50
+ return null;
51
+ }
52
+
53
+ const data = await RenderTile({
54
+ path: row.source_path,
55
+ width: 256,
56
+ bbox: [3713463.7081504324, 6088362.176970857, 3713616.5822070027, 6088515.051027427], // /:id/18/155363/91245.png
57
+ ttl: '0',
58
+ }).catch(err => ({ err: err.toString() }));
59
+
60
+ if (data.err) {
61
+ errors.raster += 1;
62
+ send(`${idx}/${rasters.length} ERROR: RenderTile: ${data.err} (raster:${row.raster_id}/${row.name})`);
63
+ return null;
64
+ }
65
+
66
+ send(`${idx}/${rasters.length} OK: (raster:${row.raster_id}/${row.name})`);
67
+ successCount += 1;
68
+ }),
69
+ Promise.resolve(),
70
+ );
71
+
72
+ send(`Всього CSS: ${css.length || '0'}`);
73
+
74
+ await css.reduce(
75
+ (promise, row, idx) => promise.then(async () => {
76
+ const data = await RenderTile({
77
+ path: row.source_path,
78
+ name: row.source_path ? undefined : row.cartocss_id,
79
+ width: 256,
80
+ bbox: [3713463.7081504324, 6088362.176970857, 3713616.5822070027, 6088515.051027427], // /:id/18/155363/91245.png
81
+ ttl: '0',
82
+ }).catch(err => ({ err: err.toString() }));
83
+
84
+ if (data.err) {
85
+ errors.css += 1;
86
+ send(`${idx}/${css.length} ERROR: RenderTile: ${data.err} (css:${row.cartocss_id}/${row.name})`);
87
+ return null;
88
+ }
89
+
90
+ send(`${idx}/${css.length} OK: (css:${row.cartocss_id}/${row.name})`);
91
+ successCount += 1;
92
+ }),
93
+ Promise.resolve(),
94
+ );
95
+
96
+ send(`Всього наборів: ${dataset.length || '0'}`);
97
+ // ? place dataset check logic here
98
+
99
+ const errorCount = Object.keys(errors).reduce((acc, curr) => acc + errors[curr], 0);
100
+ send(`Всього помилок: ${errorCount || '0'}`);
101
+ send(`Помилки растрів: ${errors.raster || '0'}`);
102
+ send(`Помилки CSS: ${errors.css || '0'}`);
103
+ send(`Помилки наборів: ${errors.dataset || '0'}`);
104
+
105
+ send(`Успіх: ${successCount || '0'}/${total || '0'}`);
106
+
107
+ }
@@ -0,0 +1,24 @@
1
+ import { pgClients } from '@opengis/fastify-table/utils.js';
2
+
3
+ export default async function getDashboard({ pg = pgClients.client }) {
4
+
5
+ const statsQuery = `
6
+ SELECT
7
+ (SELECT COUNT(*)::int FROM gis.services) as services_count,
8
+ (SELECT COUNT(*)::int FROM gis.registers) as registers_count,
9
+ (SELECT COUNT(*)::int FROM gis.maps) as maps_count,
10
+ (SELECT COUNT(*)::int FROM gis.ogc_service) as ogc_count
11
+ `;
12
+
13
+ const stats = await pg.query(statsQuery).then(r => r.rows?.[0] || {});
14
+
15
+ return {
16
+ cards: {
17
+ services: stats.services_count || 0,
18
+ registers: stats.registers_count || 0,
19
+ maps: stats.maps_count || 0,
20
+ ogc: stats.ogc_count || 0,
21
+ },
22
+ };
23
+
24
+ }
@@ -0,0 +1,26 @@
1
+ import getDashboard from './functions/dashboard.js';
2
+ import checkXML from './functions/checkXML.js';
3
+
4
+ import { logger, eventStream, pgClients } from '@opengis/fastify-table/utils.js';
5
+
6
+ const privateParams = { config: { policy: 'L1', package: 'gis' } };
7
+ const publicParams = { config: { policy: 'L0', package: 'gis' } };
8
+
9
+ async function route(app) {
10
+ app.get('/gis-check', privateParams, async (req, reply) => {
11
+ const { pg = pgClients.client } = req;
12
+ const callback = process.env.NODE_ENV === 'test' || process.env.VITEST
13
+ ? console.log
14
+ : eventStream(reply);
15
+ try {
16
+ await checkXML(pg, callback);
17
+ } catch (err) {
18
+ logger.error(err);
19
+ callback(process.env.local === 'true' ? err.toString() : 'check error');
20
+ } finally {
21
+ callback('finish', true);
22
+ }
23
+ });
24
+ app.get('/dashboard', publicParams, getDashboard); // no params required
25
+ }
26
+ export default route;
@@ -0,0 +1,34 @@
1
+ import { beforeAll, describe, expect, test } from 'vitest';
2
+
3
+ import { build, injectWithHeaders } from '../../../test/helper.js';
4
+
5
+ const user = { id: '2', type: 'admin' };
6
+
7
+ beforeAll(async () => {
8
+ await build();
9
+ });
10
+
11
+ describe('GIS routes', () => {
12
+ test('GET /gis-check returns 200', async () => {
13
+ const res = await injectWithHeaders({
14
+ url: '/api/gis-check',
15
+ headers: { uid: user.id, user_type: user.type }
16
+ });
17
+
18
+ // event stream
19
+ expect(res.statusCode).toBe(200);
20
+ });
21
+
22
+ test('GET /dashboard returns 200', async () => {
23
+ const res = await injectWithHeaders({
24
+ url: '/api/dashboard',
25
+ });
26
+
27
+ expect(res.statusCode).toBe(200);
28
+ expect(res.body).toHaveProperty('cards');
29
+ expect(res.body.cards).toHaveProperty('services');
30
+ expect(res.body.cards).toHaveProperty('registers');
31
+ expect(res.body.cards).toHaveProperty('maps');
32
+ expect(res.body.cards).toHaveProperty('ogc');
33
+ });
34
+ });
@@ -0,0 +1 @@
1
+ export default null;
@@ -5,14 +5,15 @@ import {
5
5
  } from 'node:fs/promises';
6
6
 
7
7
  import rootFolder from '../../../plugins/mapnik/funcs/rootFolder.mjs';
8
+ import { BadRequestError, NotFoundError } from '@opengis/fastify-table/errors.js';
8
9
 
9
10
  export default async function clearTiles({
10
- params, query, user,
11
- }, reply) {
12
- const filepath = path.join(rootFolder, 'vtile', params.id);
11
+ id, debug,
12
+ }) {
13
+ const filepath = path.join(rootFolder, 'vtile', id);
13
14
 
14
- if (query.debug && user?.user_type?.includes?.('admin')) {
15
- return filepath;
15
+ if (debug) {
16
+ return { filepath };
16
17
  }
17
18
 
18
19
  const exists = existsSync(filepath);
@@ -21,14 +22,14 @@ export default async function clearTiles({
21
22
  const count = isDirectory ? await readdir(filepath).then(el => el.length) : 0;
22
23
 
23
24
  if (isDirectory && count === 0) {
24
- return reply.status(404).send({ error: 'Тайли не знайдено', code: 404 });
25
+ throw NotFoundError('Тайли не знайдено');
25
26
  }
26
27
 
27
28
  if (isDirectory && exists) {
28
29
  await rm(filepath, { force: true, recursive: true });
29
30
  await mkdir(filepath, { recursive: true });
30
- return reply.status(200).send({ message: 'Тайли очищено', code: 200 });
31
+ return { message: 'Тайли очищено', code: 200 };
31
32
  }
32
33
 
33
- return reply.status(400).send({ error: 'Некорректний параметр: id', code: 400 });
34
+ throw BadRequestError('Некорректний параметр: id');
34
35
  }
@@ -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'];
15
16
 
17
+ const unittest = process.env.NODE_ENV === 'test' || process.env.VITEST;
18
+
16
19
  /**
17
20
  * Повертає GeoJSON для сервісу на основі налаштувань з gis.services
18
21
  *
@@ -21,20 +24,18 @@ const systemColumns = ['uid', 'cdate', 'editor_id', 'editor_date', 'created_by',
21
24
  * @param {string} query.sql - повернути SQL запит замість даних
22
25
  * @param {boolean} query.nocache - не використовувати кеш
23
26
  */
24
- export default async function geojson({
25
- pg = pgClients.client, params = {}, query = {}, unittest,
26
- }, reply) {
27
- const { layer } = params;
28
- const { sql, nocache, srid, type, extent } = query;
29
27
 
28
+ export default async function geojson({
29
+ layer, sql, nocache, srid, type, extent,
30
+ }, pg = pgClients.client) {
30
31
  if (!layer) {
31
- return reply.status(400).send('not enough params: layer (service_id)');
32
+ throw BadRequestError('not enough params: layer (service_id)');
32
33
  }
33
34
 
34
35
  const serviceId = layer.replace('.json', '');
35
36
 
36
37
  if (!pg.pk?.['gis.services']) {
37
- return reply.status(404).send('services table not found');
38
+ throw NotFoundError('services table not found');
38
39
  }
39
40
 
40
41
  const service = await pg.query(
@@ -50,10 +51,10 @@ export default async function geojson({
50
51
  from gis.services
51
52
  where service_id = $1 and is_active = true and is_public = true`,
52
53
  [serviceId],
53
- ).then(el => el.rows?.[0]);
54
+ ).then(r => r.rows?.[0]);
54
55
 
55
56
  if (!service) {
56
- return reply.status(404).send('service not found or not available');
57
+ throw NotFoundError('service not found or not available');
57
58
  }
58
59
 
59
60
  const {
@@ -66,20 +67,17 @@ export default async function geojson({
66
67
  } = service;
67
68
 
68
69
  if (!source) {
69
- return reply.status(400).send('invalid service source path');
70
+ throw BadRequestError('invalid service source path');
70
71
  }
71
72
 
72
- const table = source;
73
-
74
- if (!pg.pk?.[table]?.length) {
75
- return reply.status(404).send('layer table not found');
73
+ if (!pg.pk?.[source]?.length) {
74
+ throw NotFoundError('layer table not found');
76
75
  }
77
76
 
78
- const meta = await getMeta({ pg, table });
79
- const { columns = [] } = meta || {};
77
+ const { columns = [], geom: metaGeom } = await getMeta({ pg, table: source }) || {};
80
78
 
81
- const geom = gc || meta?.geom || 'geom';
82
- const pk = pg.pk?.[table] || columns[0]?.name;
79
+ const geom = gc || metaGeom || 'geom';
80
+ const pk = pg.pk?.[source] || columns[0]?.name;
83
81
 
84
82
  let attributeColumns = [];
85
83
  if (attributes && Array.isArray(attributes)) {
@@ -113,11 +111,14 @@ export default async function geojson({
113
111
  const ageInMs = Date.now() - birthtimeMs;
114
112
  if (ageInMs < 86400000) {
115
113
  const content = await readFile(filepath, 'utf8');
116
- return reply
117
- .status(200)
118
- .header('Content-Type', 'application/json')
119
- .header('Cache-Control', 'public, max-age=86400')
120
- .send(content);
114
+
115
+ return {
116
+ headers: {
117
+ 'Content-Type': 'application/json',
118
+ 'Cache-Control': 'public, max-age=86400',
119
+ },
120
+ data: content
121
+ }
121
122
  }
122
123
  }
123
124
 
@@ -136,7 +137,7 @@ export default async function geojson({
136
137
  geomExpression = `st_transform(${geomExpression}, 4326)`;
137
138
  }
138
139
 
139
- const quotedTable = table.split('.').map(el => `"${el}"`).join('.');
140
+ const quotedTable = source.split('.').map(el => `"${el}"`).join('.');
140
141
  const quotedGeom = `"${geom}"`;
141
142
 
142
143
  const geomFinal = `st_force2d(${geomExpression.replace(new RegExp(`(\\b)${geom}(\\b)`, 'g'), `$1${quotedGeom}$2`)})`;
@@ -159,29 +160,28 @@ export default async function geojson({
159
160
  ) f
160
161
  `;
161
162
 
162
- if (sql === '1') return q;
163
- if (sql === '2') return filepath.replace(/\\/g, '/');
163
+ if (sql === 1) return q;
164
+ if (sql === 2) return filepath.replace(/\\/g, '/');
164
165
 
165
- try {
166
- const result = await pg.query(q);
167
- const geojsonData = result.rows[0] || { type: 'FeatureCollection', features: [] };
168
166
 
169
- geojsonData.service_id = serviceId;
170
- geojsonData.count = geojsonData.features?.length || 0;
167
+ const geojsonData = await pg.query(q)
168
+ .then(r => r.rows?.[0] || { type: 'FeatureCollection', features: [] });
171
169
 
172
- const jsonString = JSON.stringify(geojsonData);
170
+ geojsonData.service_id = serviceId;
171
+ geojsonData.count = geojsonData.features?.length || 0;
173
172
 
174
- if (!nocache && !unittest) {
175
- await mkdir(path.dirname(filepath), { recursive: true });
176
- await writeFile(filepath, jsonString, 'utf8');
177
- }
173
+ const jsonString = JSON.stringify(geojsonData);
174
+
175
+ if (!nocache && !unittest) {
176
+ await mkdir(path.dirname(filepath), { recursive: true });
177
+ await writeFile(filepath, jsonString, 'utf8');
178
+ }
178
179
 
179
- return reply
180
- .status(200)
181
- .header('Content-Type', 'application/json')
182
- .header('Cache-Control', nocache ? 'no-cache' : 'public, max-age=86400')
183
- .send(jsonString);
184
- } catch (err) {
185
- return reply.status(500).send({ error: err.message });
180
+ return {
181
+ headers: {
182
+ 'Content-Type': 'application/json',
183
+ 'Cache-Control': nocache ? 'no-cache' : 'public, max-age=86400',
184
+ },
185
+ data: jsonString
186
186
  }
187
187
  }
@@ -1,6 +1,8 @@
1
1
  import path from "node:path";
2
2
 
3
3
  import { downloadFile } from "@opengis/fastify-table/utils.js";
4
+ import { BadRequestError, ConflictError, NotFoundError } from "@opengis/fastify-table/errors.js";
5
+
4
6
  import mapnik from "../../../plugins/mapnik/funcs/mapnik.js";
5
7
 
6
8
  const { ConvertVector } = mapnik();
@@ -20,41 +22,35 @@ function resolveExtension(filename) {
20
22
  * @body {string} [filepath] - шлях до файлу на сервері (legacy)
21
23
  * @body {number} [srid=4326] - цільовий EPSG код
22
24
  */
23
- export default async function gisConvert({ body = {} }, reply) {
24
- const { file, filename, filepath, srid = 4326, encoding } = body;
25
-
25
+ export default async function gisConvert({ file, filename, filepath, encoding }) {
26
26
  let data;
27
27
  let sourceName;
28
28
 
29
29
  if (typeof file === "string" && file) {
30
30
  if (!filename || typeof filename !== "string") {
31
- return reply
32
- .status(400)
33
- .send({ error: "Потрібен параметр filename разом з file", code: 400 });
31
+ throw BadRequestError("Потрібен параметр filename разом з file");
34
32
  }
33
+
35
34
  data = Buffer.from(file, "base64");
36
35
  sourceName = path.basename(filename);
37
36
  } else if (typeof filepath === "string" && filepath) {
37
+ const filepath1 = filepath.replace(/%2e/g, ".").replace(/%2E/g, ".");
38
+ if (filepath1.includes('..')) {
39
+ throw ConflictError('path traversals are not allowed');
40
+ }
38
41
  data = await downloadFile(filepath, { buffer: true });
39
42
  if (!data) {
40
- return reply
41
- .status(404)
42
- .send({ error: `Файл не знайдено: ${filepath}`, code: 404 });
43
+ throw NotFoundError(`Файл не знайдено: ${filepath}`);
43
44
  }
44
45
  sourceName = path.basename(filepath);
45
46
  } else {
46
- return reply.status(400).send({
47
- error: "Потрібен параметр file (base64) або filepath",
48
- code: 400,
49
- });
47
+ throw BadRequestError("Потрібен параметр file (base64) або filepath");
50
48
  }
51
49
 
52
50
  const ext = resolveExtension(sourceName);
51
+
53
52
  if (!ALLOWED_FORMAT.has(ext)) {
54
- return reply.status(400).send({
55
- error: `Непідтримуване розширення: .${ext}. Підтримується: ${[...ALLOWED_FORMAT].join(", ")}`,
56
- code: 400,
57
- });
53
+ throw BadRequestError(`Непідтримуване розширення: .${ext}. Підтримується: ${[...ALLOWED_FORMAT].join(", ")}`);
58
54
  }
59
55
 
60
56
  const res = await ConvertVector({
@@ -63,11 +59,7 @@ export default async function gisConvert({ body = {} }, reply) {
63
59
  // srs: +srid, // target srs, 4326 by default
64
60
  encoding,
65
61
  filename: sourceName,
66
- }).catch((err) => ({ err }));
67
-
68
- if (res?.err) {
69
- return reply.code(500).send(res.err);
70
- }
62
+ });
71
63
 
72
- return reply.send(JSON.parse(res.geojson));
64
+ return JSON.parse(res.geojson);
73
65
  }
@@ -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(req, reply) {
196
- const options = parseIconFilename(req.params?.['*'] || '');
197
- if (!options) return reply.status(400).send('invalid icon name');
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
- return reply
204
- .type(contentTypeByFormat[options.format])
205
- .header('Cache-Control', nocache ? 'no-cache' : 'public, max-age=31536000, immutable')
206
- .send(image);
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
  }