1
2
3
4
5
6 package org.tailormap.api.configuration.dev;
7
8 import static org.tailormap.api.persistence.Configuration.HOME_PAGE;
9 import static org.tailormap.api.persistence.Configuration.PORTAL_MENU;
10 import static org.tailormap.api.persistence.json.GeoServiceProtocol.QUANTIZEDMESH;
11 import static org.tailormap.api.persistence.json.GeoServiceProtocol.TILES3D;
12 import static org.tailormap.api.persistence.json.GeoServiceProtocol.WMS;
13 import static org.tailormap.api.persistence.json.GeoServiceProtocol.WMTS;
14 import static org.tailormap.api.persistence.json.GeoServiceProtocol.XYZ;
15 import static org.tailormap.api.persistence.json.HiddenLayerFunctionalityEnum.ATTRIBUTE_LIST;
16 import static org.tailormap.api.persistence.json.HiddenLayerFunctionalityEnum.EXPORT;
17 import static org.tailormap.api.persistence.json.HiddenLayerFunctionalityEnum.FEATURE_INFO;
18 import static org.tailormap.api.security.AuthorisationService.ACCESS_TYPE_VIEW;
19
20 import com.fasterxml.jackson.core.JsonProcessingException;
21 import com.fasterxml.jackson.databind.ObjectMapper;
22 import java.io.IOException;
23 import java.lang.invoke.MethodHandles;
24 import java.nio.charset.StandardCharsets;
25 import java.sql.SQLException;
26 import java.time.OffsetDateTime;
27 import java.time.ZoneId;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.NoSuchElementException;
33 import java.util.Optional;
34 import java.util.Properties;
35 import java.util.Set;
36 import java.util.UUID;
37 import org.apache.solr.client.solrj.SolrServerException;
38 import org.quartz.SchedulerException;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.springframework.beans.factory.annotation.Value;
42 import org.springframework.boot.SpringApplication;
43 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
44 import org.springframework.boot.context.event.ApplicationReadyEvent;
45 import org.springframework.context.ApplicationContext;
46 import org.springframework.context.event.EventListener;
47 import org.springframework.core.io.ClassPathResource;
48 import org.springframework.jdbc.core.simple.JdbcClient;
49 import org.springframework.transaction.annotation.Transactional;
50 import org.springframework.util.PropertyPlaceholderHelper;
51 import org.tailormap.api.admin.model.TaskSchedule;
52 import org.tailormap.api.geotools.featuresources.AttachmentsHelper;
53 import org.tailormap.api.geotools.featuresources.FeatureSourceFactoryHelper;
54 import org.tailormap.api.geotools.featuresources.JDBCFeatureSourceHelper;
55 import org.tailormap.api.geotools.featuresources.WFSFeatureSourceHelper;
56 import org.tailormap.api.persistence.Application;
57 import org.tailormap.api.persistence.Catalog;
58 import org.tailormap.api.persistence.Configuration;
59 import org.tailormap.api.persistence.GeoService;
60 import org.tailormap.api.persistence.Group;
61 import org.tailormap.api.persistence.Page;
62 import org.tailormap.api.persistence.SearchIndex;
63 import org.tailormap.api.persistence.TMFeatureSource;
64 import org.tailormap.api.persistence.TMFeatureType;
65 import org.tailormap.api.persistence.Upload;
66 import org.tailormap.api.persistence.User;
67 import org.tailormap.api.persistence.helper.GeoServiceHelper;
68 import org.tailormap.api.persistence.json.AppContent;
69 import org.tailormap.api.persistence.json.AppLayerSettings;
70 import org.tailormap.api.persistence.json.AppSettings;
71 import org.tailormap.api.persistence.json.AppTreeLayerNode;
72 import org.tailormap.api.persistence.json.AppTreeLevelNode;
73 import org.tailormap.api.persistence.json.AppTreeNode;
74 import org.tailormap.api.persistence.json.AppUiSettings;
75 import org.tailormap.api.persistence.json.AttachmentAttributeType;
76 import org.tailormap.api.persistence.json.AttributeSettings;
77 import org.tailormap.api.persistence.json.AttributeValueSettings;
78 import org.tailormap.api.persistence.json.AuthorizationRule;
79 import org.tailormap.api.persistence.json.AuthorizationRuleDecision;
80 import org.tailormap.api.persistence.json.Bounds;
81 import org.tailormap.api.persistence.json.CatalogNode;
82 import org.tailormap.api.persistence.json.FeatureTypeRef;
83 import org.tailormap.api.persistence.json.FeatureTypeTemplate;
84 import org.tailormap.api.persistence.json.Filter;
85 import org.tailormap.api.persistence.json.FilterEditConfiguration;
86 import org.tailormap.api.persistence.json.FilterGroup;
87 import org.tailormap.api.persistence.json.GeoServiceDefaultLayerSettings;
88 import org.tailormap.api.persistence.json.GeoServiceLayerSettings;
89 import org.tailormap.api.persistence.json.GeoServiceSettings;
90 import org.tailormap.api.persistence.json.JDBCConnectionProperties;
91 import org.tailormap.api.persistence.json.MenuItem;
92 import org.tailormap.api.persistence.json.PageTile;
93 import org.tailormap.api.persistence.json.ServiceAuthentication;
94 import org.tailormap.api.persistence.json.TailormapObjectRef;
95 import org.tailormap.api.persistence.json.TileLayerHiDpiMode;
96 import org.tailormap.api.repository.ApplicationRepository;
97 import org.tailormap.api.repository.CatalogRepository;
98 import org.tailormap.api.repository.ConfigurationRepository;
99 import org.tailormap.api.repository.FeatureSourceRepository;
100 import org.tailormap.api.repository.GeoServiceRepository;
101 import org.tailormap.api.repository.GroupRepository;
102 import org.tailormap.api.repository.PageRepository;
103 import org.tailormap.api.repository.SearchIndexRepository;
104 import org.tailormap.api.repository.UploadRepository;
105 import org.tailormap.api.repository.UserRepository;
106 import org.tailormap.api.scheduling.IndexTask;
107 import org.tailormap.api.scheduling.TMJobDataMap;
108 import org.tailormap.api.scheduling.Task;
109 import org.tailormap.api.scheduling.TaskManagerService;
110 import org.tailormap.api.scheduling.TaskType;
111 import org.tailormap.api.security.InternalAdminAuthentication;
112 import org.tailormap.api.solr.SolrHelper;
113 import org.tailormap.api.solr.SolrService;
114 import org.tailormap.api.viewer.model.AppStyling;
115 import org.tailormap.api.viewer.model.Component;
116 import org.tailormap.api.viewer.model.ComponentConfig;
117
118
119
120
121
122 @org.springframework.context.annotation.Configuration
123 @ConditionalOnProperty(name = "tailormap-api.database.populate-testdata", havingValue = "true")
124 public class PopulateTestData {
125
126 private static final Logger logger =
127 LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
128 private final ApplicationContext appContext;
129 private final UserRepository userRepository;
130 private final GroupRepository groupRepository;
131 private final CatalogRepository catalogRepository;
132 private final GeoServiceRepository geoServiceRepository;
133 private final GeoServiceHelper geoServiceHelper;
134 private final SolrService solrService;
135 private final TaskManagerService taskManagerService;
136 private final FeatureSourceRepository featureSourceRepository;
137 private final ApplicationRepository applicationRepository;
138 private final ConfigurationRepository configurationRepository;
139 private final SearchIndexRepository searchIndexRepository;
140 private final FeatureSourceFactoryHelper featureSourceFactoryHelper;
141 private final UploadRepository uploadRepository;
142 private final PageRepository pageRepository;
143 private final JdbcClient jdbcClient;
144
145 @Value("${spatial.dbs.connect:false}")
146 private boolean connectToSpatialDbs;
147
148 @Value("#{'${tailormap-api.database.populate-testdata.categories}'.split(',')}")
149 private Set<String> categories;
150
151 @Value("${spatial.dbs.localhost:true}")
152 private boolean connectToSpatialDbsAtLocalhost;
153
154 @Value("${tailormap-api.database.populate-testdata.admin-hashed-password}")
155 private String adminHashedPassword;
156
157 @Value("${tailormap-api.database.populate-testdata.exit:false}")
158 private boolean exit;
159
160 @Value("${MAP5_URL:#{null}}")
161 private String map5url;
162
163 private final String tiles3dProxyUsername = "b3p";
164
165
166 private final String tiles3dProxyPassword = "cOxPlJFWmtndFk0eVg5VdL";
167
168 @Value("${tailormap-api.solr-batch-size:1000}")
169 private int solrBatchSize;
170
171 @Value("${tailormap-api.solr-geometry-validation-rule:repairBuffer0}")
172 private String solrGeometryValidationRule;
173
174 public PopulateTestData(
175 ApplicationContext appContext,
176 UserRepository userRepository,
177 GroupRepository groupRepository,
178 CatalogRepository catalogRepository,
179 GeoServiceRepository geoServiceRepository,
180 GeoServiceHelper geoServiceHelper,
181 SolrService solrService,
182 TaskManagerService taskManagerService,
183 FeatureSourceRepository featureSourceRepository,
184 ApplicationRepository applicationRepository,
185 ConfigurationRepository configurationRepository,
186 FeatureSourceFactoryHelper featureSourceFactoryHelper,
187 SearchIndexRepository searchIndexRepository,
188 UploadRepository uploadRepository,
189 PageRepository pageRepository,
190 JdbcClient jdbcClient) {
191 this.appContext = appContext;
192 this.userRepository = userRepository;
193 this.groupRepository = groupRepository;
194 this.catalogRepository = catalogRepository;
195 this.geoServiceRepository = geoServiceRepository;
196 this.geoServiceHelper = geoServiceHelper;
197 this.solrService = solrService;
198 this.taskManagerService = taskManagerService;
199 this.featureSourceRepository = featureSourceRepository;
200 this.applicationRepository = applicationRepository;
201 this.configurationRepository = configurationRepository;
202 this.featureSourceFactoryHelper = featureSourceFactoryHelper;
203 this.searchIndexRepository = searchIndexRepository;
204 this.uploadRepository = uploadRepository;
205 this.pageRepository = pageRepository;
206 this.jdbcClient = jdbcClient;
207 }
208
209 @EventListener(ApplicationReadyEvent.class)
210 @Transactional
211 public void populate() throws Exception {
212 InternalAdminAuthentication.setInSecurityContext();
213 try {
214
215
216 createTestUsersAndGroups();
217 createConfigurationTestData();
218 if (categories.contains("catalog")) {
219 createCatalogTestData();
220 }
221 if (categories.contains("apps")) {
222 createAppTestData();
223 }
224 if (categories.contains("search-index")) {
225 try {
226 createSolrIndex();
227 } catch (Exception e) {
228 logger.error("Exception creating Solr Index for testdata (continuing)", e);
229 }
230 }
231 if (categories.contains("search-index")) {
232 createSearchIndexTasks();
233 }
234 if (categories.contains("pages")) {
235 createPages();
236 }
237 logger.info("Test entities created");
238 if (categories.contains("drawing")) {
239 insertTestDrawing();
240 logger.info("Test drawing created");
241 try {
242 insertDrawingStyle();
243 logger.info("Test drawing style created");
244 } catch (Exception e) {
245 logger.error("Exception creating drawing style", e);
246 }
247 }
248 } finally {
249 InternalAdminAuthentication.clearSecurityContextAuthentication();
250 }
251 if (exit) {
252
253
254 new Thread(() -> {
255 try {
256 logger.info("Exiting in 10 seconds");
257 Thread.sleep(10000);
258 } catch (InterruptedException ignored) {
259
260 }
261 SpringApplication.exit(appContext, () -> 0);
262 System.exit(0);
263 })
264 .start();
265 }
266 }
267
268 public void createTestUsersAndGroups() throws NoSuchElementException {
269 Group groupFoo = new Group().setName("test-foo").setDescription("Used for integration tests.");
270 groupRepository.save(groupFoo);
271
272 Group groupBar = new Group().setName("test-bar").setDescription("Used for integration tests.");
273 groupBar.addOrUpdateAdminProperty("group-property", true, true);
274 groupBar.addOrUpdateAdminProperty("group-private-property", 999.9, false);
275 groupRepository.save(groupBar);
276
277 Group groupBaz = new Group().setName("test-baz").setDescription("Used for integration tests.");
278 groupRepository.save(groupBaz);
279
280
281 User u = new User().setUsername("user").setPassword("{noop}user").setEmail("user@example.com");
282 u.getGroups().addAll(List.of(groupFoo, groupBar, groupBaz));
283 userRepository.save(u);
284
285
286 u = new User()
287 .setUsername("foo")
288 .setPassword("{noop}foo")
289 .setEmail("foo@example.com")
290 .setName("Foo only user");
291 u.getGroups().add(groupFoo);
292 userRepository.save(u);
293
294 u = new User()
295 .setUsername("disabled")
296 .setPassword("{noop}disabled")
297 .setEmail("disabled@example.com")
298 .setEnabled(false);
299 userRepository.save(u);
300
301 u = new User()
302 .setUsername("expired")
303 .setPassword("{noop}expired")
304 .setEmail("expired@example.com")
305 .setValidUntil(
306 OffsetDateTime.now(ZoneId.systemDefault()).minusDays(1).toZonedDateTime());
307 userRepository.save(u);
308
309
310 u = new User().setUsername("tm-admin").setPassword(adminHashedPassword);
311 u.addOrUpdateAdminProperty("some-property", "some-value", true);
312 u.addOrUpdateAdminProperty("admin-property", "private-value", false);
313 u.getGroups().add(groupRepository.findById(Group.ADMIN).orElseThrow());
314 u.getGroups().add(groupBar);
315 userRepository.save(u);
316 }
317
318 private final List<AuthorizationRule> ruleAnonymousRead = List.of(new AuthorizationRule()
319 .groupName(Group.ANONYMOUS)
320 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW)));
321
322 private final List<AuthorizationRule> ruleLoggedIn = List.of(new AuthorizationRule()
323 .groupName(Group.AUTHENTICATED)
324 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW)));
325
326 @SuppressWarnings("PMD.AvoidUsingHardCodedIP")
327 private void createCatalogTestData() throws Exception {
328 Catalog catalog = catalogRepository.findById(Catalog.MAIN).orElseThrow();
329 CatalogNode rootCatalogNode = catalog.getNodes().getFirst();
330 CatalogNode catalogNode = new CatalogNode().id("test").title("Test services");
331 rootCatalogNode.addChildrenItem(catalogNode.getId());
332 catalog.getNodes().add(catalogNode);
333
334 String osmAttribution = "© [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors";
335
336 Bounds rdTileGridExtent =
337 new Bounds().minx(-285401.92).maxx(595401.92).miny(22598.08).maxy(903401.92);
338
339 Upload legend = new Upload()
340 .setCategory(Upload.CATEGORY_LEGEND)
341 .setFilename("gemeentegebied-legend.png")
342 .setMimeType("image/png")
343 .setContent(new ClassPathResource("test/gemeentegebied-legend.png").getContentAsByteArray())
344 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
345 uploadRepository.save(legend);
346
347 Collection<GeoService> services = List.of(
348 new GeoService()
349 .setId("demo")
350 .setProtocol(WMS)
351 .setTitle("Demo")
352 .setPublished(true)
353 .setAuthorizationRules(ruleAnonymousRead)
354 .setUrl("https://demo.tailormap.com/geoserver/geodata/ows?SERVICE=WMS"),
355 new GeoService()
356 .setId("osm")
357 .setProtocol(XYZ)
358 .setTitle("OSM")
359 .setUrl("https://tile.openstreetmap.org/{z}/{x}/{y}.png")
360 .setAuthorizationRules(ruleAnonymousRead)
361 .setSettings(new GeoServiceSettings()
362 .xyzCrs("EPSG:3857")
363 .layerSettings(Map.of(
364 "xyz",
365 new GeoServiceLayerSettings()
366 .attribution(osmAttribution)
367 .maxZoom(19)))),
368
369 new GeoService()
370 .setId("snapshot-geoserver")
371 .setProtocol(WMS)
372 .setTitle("Test GeoServer")
373 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
374 .setAuthorizationRules(ruleAnonymousRead)
375 .setPublished(true),
376 new GeoService()
377 .setId("filtered-snapshot-geoserver")
378 .setProtocol(WMS)
379 .setTitle("Test GeoServer (with authorization rules)")
380 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
381 .setAuthorizationRules(List.of(
382 new AuthorizationRule()
383 .groupName("test-foo")
384 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW)),
385 new AuthorizationRule()
386 .groupName("test-baz")
387 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW))))
388 .setSettings(new GeoServiceSettings()
389 .layerSettings(Map.of(
390 "BGT",
391 new GeoServiceLayerSettings()
392 .addAuthorizationRulesItem(new AuthorizationRule()
393 .groupName("test-foo")
394 .decisions(Map.of(
395 ACCESS_TYPE_VIEW, AuthorizationRuleDecision.DENY)))
396 .addAuthorizationRulesItem(new AuthorizationRule()
397 .groupName("test-baz")
398 .decisions(Map.of(
399 ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW))))))
400 .setPublished(true),
401 new GeoService()
402 .setId("snapshot-geoserver-proxied")
403 .setProtocol(WMS)
404 .setTitle("Test GeoServer (proxied)")
405 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
406 .setAuthorizationRules(ruleAnonymousRead)
407 .setSettings(new GeoServiceSettings().useProxy(true)),
408 new GeoService()
409 .setId("openbasiskaart")
410 .setProtocol(WMTS)
411 .setTitle("Openbasiskaart")
412 .setUrl("https://www.openbasiskaart.nl/mapcache/wmts")
413 .setAuthorizationRules(ruleAnonymousRead)
414 .setSettings(new GeoServiceSettings()
415 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
416 .layerSettings(Map.of(
417 "osm",
418 new GeoServiceLayerSettings()
419 .title("Openbasiskaart")
420 .hiDpiDisabled(false)
421 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
422 .hiDpiSubstituteLayer("osm-hq")))),
423 new GeoService()
424 .setId("openbasiskaart-proxied")
425 .setProtocol(WMTS)
426 .setTitle("Openbasiskaart (proxied)")
427 .setUrl("https://www.openbasiskaart.nl/mapcache/wmts")
428 .setAuthorizationRules(ruleAnonymousRead)
429
430
431 .setAuthentication(new ServiceAuthentication()
432 .method(ServiceAuthentication.MethodEnum.PASSWORD)
433 .username("test")
434 .password("test"))
435 .setSettings(new GeoServiceSettings()
436 .useProxy(true)
437 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
438 .layerSettings(Map.of(
439 "osm",
440 new GeoServiceLayerSettings()
441 .hiDpiDisabled(false)
442 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
443 .hiDpiSubstituteLayer("osm-hq")))),
444 new GeoService()
445 .setId("openbasiskaart-tms")
446 .setProtocol(XYZ)
447 .setTitle("Openbasiskaart (TMS)")
448 .setUrl("https://openbasiskaart.nl/mapcache/tms/1.0.0/osm@rd/{z}/{x}/{-y}.png")
449 .setAuthorizationRules(ruleAnonymousRead)
450 .setSettings(
451 new GeoServiceSettings()
452 .xyzCrs("EPSG:28992")
453 .defaultLayerSettings(
454 new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
455 .layerSettings(
456 Map.of(
457 "xyz",
458 new GeoServiceLayerSettings()
459 .maxZoom(15)
460 .tileGridExtent(rdTileGridExtent)
461 .hiDpiDisabled(false)
462 .hiDpiMode(
463 TileLayerHiDpiMode
464 .SUBSTITUTELAYERTILEPIXELRATIOONLY)
465 .hiDpiSubstituteLayer(
466 "https://openbasiskaart.nl/mapcache/tms/1.0.0/osm-hq@rd-hq/{z}/{x}/{-y}.png")))),
467 new GeoService()
468 .setId("pdok-hwh-luchtfotorgb")
469 .setProtocol(WMTS)
470 .setTitle("PDOK HWH luchtfoto")
471 .setUrl("https://service.pdok.nl/hwh/luchtfotorgb/wmts/v1_0")
472 .setAuthorizationRules(ruleAnonymousRead)
473 .setPublished(true)
474 .setSettings(new GeoServiceSettings()
475 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
476 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl)")
477 .hiDpiDisabled(false))
478 .putLayerSettingsItem(
479 "Actueel_orthoHR", new GeoServiceLayerSettings().title("Luchtfoto"))),
480 new GeoService()
481 .setId("b3p-mapproxy-luchtfoto")
482 .setProtocol(XYZ)
483 .setTitle("Luchtfoto (TMS)")
484 .setUrl("https://mapproxy.b3p.nl/tms/1.0.0/luchtfoto/EPSG28992/{z}/{x}/{-y}.jpeg")
485 .setAuthorizationRules(ruleAnonymousRead)
486 .setPublished(true)
487 .setSettings(new GeoServiceSettings()
488 .xyzCrs("EPSG:28992")
489 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
490 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl)")
491 .hiDpiDisabled(false))
492 .layerSettings(Map.of(
493 "xyz",
494 new GeoServiceLayerSettings()
495 .maxZoom(14)
496 .tileGridExtent(rdTileGridExtent)
497 .hiDpiMode(TileLayerHiDpiMode.SHOWNEXTZOOMLEVEL)))),
498 new GeoService()
499 .setId("at-basemap")
500 .setProtocol(WMTS)
501 .setTitle("basemap.at")
502 .setUrl("https://mapsneu.wien.gv.at/basemapneu/1.0.0/WMTSCapabilities.xml")
503 .setAuthorizationRules(ruleAnonymousRead)
504 .setPublished(true)
505 .setSettings(new GeoServiceSettings()
506 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
507 .attribution("© [basemap.at](https://basemap.at)")
508 .hiDpiDisabled(true))
509 .layerSettings(Map.of(
510 "geolandbasemap",
511 new GeoServiceLayerSettings()
512 .title("Basemap")
513 .hiDpiDisabled(false)
514 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERTILEPIXELRATIOONLY)
515 .hiDpiSubstituteLayer("bmaphidpi"),
516 "bmaporthofoto30cm",
517 new GeoServiceLayerSettings()
518 .title("Orthophoto")
519 .hiDpiDisabled(false)))),
520 new GeoService()
521 .setId("pdok-kadaster-bestuurlijkegebieden")
522 .setProtocol(WMS)
523 .setUrl("https://service.pdok.nl/kadaster/bestuurlijkegebieden/wms/v1_0?service=WMS")
524 .setAuthorizationRules(ruleAnonymousRead)
525 .setSettings(new GeoServiceSettings()
526 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
527 .description("This layer shows an administrative boundary."))
528
529 .serverType(GeoServiceSettings.ServerTypeEnum.MAPSERVER)
530 .useProxy(true)
531 .putLayerSettingsItem(
532 "Gemeentegebied",
533 new GeoServiceLayerSettings()
534 .legendImageId(legend.getId().toString())))
535 .setPublished(true)
536 .setTitle("PDOK Kadaster bestuurlijke gebieden"),
537 new GeoService()
538 .setId("bestuurlijkegebieden-proxied")
539 .setProtocol(WMS)
540 .setUrl("https://service.pdok.nl/kadaster/bestuurlijkegebieden/wms/v1_0?service=WMS")
541 .setAuthorizationRules(ruleAnonymousRead)
542
543
544
545 .setAuthentication(new ServiceAuthentication()
546 .method(ServiceAuthentication.MethodEnum.PASSWORD)
547 .username("test")
548 .password("test"))
549 .setSettings(new GeoServiceSettings()
550
551 .serverType(GeoServiceSettings.ServerTypeEnum.MAPSERVER)
552 .useProxy(true))
553 .setPublished(true)
554 .setTitle("Bestuurlijke gebieden (proxied met auth)"),
555 new GeoService()
556 .setId("3dbag_utrecht")
557 .setProtocol(TILES3D)
558 .setUrl("https://3dtilesnederland.nl/tiles/1.0/implicit/nederland/344.json")
559 .setTitle("3D BAG Utrecht")
560 .setPublished(true)
561 .setAuthorizationRules(ruleAnonymousRead),
562 new GeoService()
563 .setId("ahn_terrain_model")
564 .setProtocol(QUANTIZEDMESH)
565 .setUrl(
566 "https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1/collections/digitaalterreinmodel")
567 .setTitle("AHN Terrain Model")
568 .setPublished(true)
569 .setAuthorizationRules(ruleAnonymousRead),
570 new GeoService()
571 .setId("3d_basisvoorziening_gebouwen_proxy")
572 .setProtocol(TILES3D)
573 .setUrl(
574 "https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1_0/collections/gebouwen/3dtiles")
575 .setTitle("3D Basisvoorziening Gebouwen Proxy")
576 .setPublished(true)
577 .setAuthorizationRules(ruleAnonymousRead)
578 .setSettings(new GeoServiceSettings().useProxy(true)),
579 new GeoService()
580 .setId("3d_utrecht_proxied_auth")
581 .setProtocol(TILES3D)
582 .setUrl("https://snapshot.tailormap.nl/tiles3d-proxy/3dtiles")
583 .setTitle("3D Utrecht Proxied with Authorization")
584 .setPublished(true)
585 .setAuthorizationRules(ruleAnonymousRead)
586 .setAuthentication(new ServiceAuthentication()
587 .method(ServiceAuthentication.MethodEnum.PASSWORD)
588 .username(tiles3dProxyUsername)
589 .password(tiles3dProxyPassword))
590 .setSettings(new GeoServiceSettings().useProxy(true))
591
592 );
593
594 if (map5url != null) {
595 GeoServiceLayerSettings osmAttr = new GeoServiceLayerSettings().attribution(osmAttribution);
596 GeoServiceLayerSettings map5Attr = new GeoServiceLayerSettings()
597 .attribution("Kaarten: [Map5.nl](https://map5.nl), data: " + osmAttribution);
598 services = new ArrayList<>(services);
599 services.add(new GeoService()
600 .setId("map5")
601 .setProtocol(WMTS)
602 .setTitle("Map5")
603 .setUrl(map5url)
604 .setAuthorizationRules(ruleAnonymousRead)
605 .setSettings(new GeoServiceSettings()
606 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().hiDpiDisabled(true))
607 .layerSettings(Map.of(
608 "openlufo",
609 new GeoServiceLayerSettings()
610 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl), "
611 + osmAttribution),
612 "luforoadslabels",
613 osmAttr,
614 "map5topo",
615 new GeoServiceLayerSettings()
616 .attribution(map5Attr.getAttribution())
617 .hiDpiDisabled(false)
618 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
619 .hiDpiSubstituteLayer("map5topo_hq"),
620 "map5topo_gray",
621 map5Attr,
622 "map5topo_simple",
623 map5Attr,
624 "map5topo_simple_gray",
625 map5Attr,
626 "opensimpletopo",
627 osmAttr,
628 "opensimpletopo_gray",
629 osmAttr,
630 "opentopo",
631 osmAttr,
632 "opentopo_gray",
633 osmAttr))));
634 }
635
636 for (GeoService geoService : services) {
637 try {
638 geoServiceHelper.loadServiceCapabilities(geoService);
639 } catch (Exception e) {
640 logger.error(
641 "Error loading capabilities for {} service URL {}: {}, {}",
642 geoService.getProtocol().getValue(),
643 geoService.getUrl(),
644 e.getClass(),
645 e.getMessage());
646 }
647
648 geoServiceRepository.save(geoService);
649 catalogNode.addItemsItem(new TailormapObjectRef()
650 .kind(TailormapObjectRef.KindEnum.GEO_SERVICE)
651 .id(geoService.getId()));
652 }
653
654 CatalogNode wfsFeatureSourceCatalogNode =
655 new CatalogNode().id("wfs_feature_sources").title("WFS feature sources");
656 rootCatalogNode.addChildrenItem(wfsFeatureSourceCatalogNode.getId());
657 catalog.getNodes().add(wfsFeatureSourceCatalogNode);
658
659 services.stream().filter(s -> s.getProtocol() == WMS).forEach(s -> {
660 geoServiceHelper.findAndSaveRelatedWFS(s);
661 List<TMFeatureSource> linkedSources = featureSourceRepository.findByLinkedServiceId(s.getId());
662 for (TMFeatureSource linkedSource : linkedSources) {
663 wfsFeatureSourceCatalogNode.addItemsItem(new TailormapObjectRef()
664 .kind(TailormapObjectRef.KindEnum.FEATURE_SOURCE)
665 .id(linkedSource.getId().toString()));
666 }
667 });
668
669 String geodataPassword = "980f1c8A-25933b2";
670
671 Map<String, TMFeatureSource> featureSources = Map.of(
672 "postgis",
673 new TMFeatureSource()
674 .setProtocol(TMFeatureSource.Protocol.JDBC)
675 .setTitle("PostGIS")
676 .setJdbcConnection(new JDBCConnectionProperties()
677 .dbtype(JDBCConnectionProperties.DbtypeEnum.POSTGIS)
678 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "postgis")
679 .port(connectToSpatialDbsAtLocalhost ? 54322 : 5432)
680 .database("geodata")
681 .schema("public")
682 .additionalProperties(Map.of("connectionOptions", "?ApplicationName=tailormap-api")))
683 .setAuthentication(new ServiceAuthentication()
684 .method(ServiceAuthentication.MethodEnum.PASSWORD)
685 .username("geodata")
686 .password(geodataPassword)),
687 "postgis_osm",
688 new TMFeatureSource()
689 .setProtocol(TMFeatureSource.Protocol.JDBC)
690 .setTitle("PostGIS OSM")
691 .setJdbcConnection(new JDBCConnectionProperties()
692 .dbtype(JDBCConnectionProperties.DbtypeEnum.POSTGIS)
693 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "postgis")
694 .port(connectToSpatialDbsAtLocalhost ? 54322 : 5432)
695 .database("geodata")
696 .schema("osm")
697 .additionalProperties(Map.of("connectionOptions", "?ApplicationName=tailormap-api")))
698 .setAuthentication(new ServiceAuthentication()
699 .method(ServiceAuthentication.MethodEnum.PASSWORD)
700 .username("geodata")
701 .password(geodataPassword)),
702 "oracle",
703 new TMFeatureSource()
704 .setProtocol(TMFeatureSource.Protocol.JDBC)
705 .setTitle("Oracle")
706 .setJdbcConnection(new JDBCConnectionProperties()
707 .dbtype(JDBCConnectionProperties.DbtypeEnum.ORACLE)
708 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "oracle")
709 .database("/FREEPDB1")
710 .schema("GEODATA")
711 .additionalProperties(Map.of("connectionOptions", "?oracle.jdbc.J2EE13Compliant=true")))
712 .setAuthentication(new ServiceAuthentication()
713 .method(ServiceAuthentication.MethodEnum.PASSWORD)
714 .username("geodata")
715 .password(geodataPassword)),
716 "sqlserver",
717 new TMFeatureSource()
718 .setProtocol(TMFeatureSource.Protocol.JDBC)
719 .setTitle("MS SQL Server")
720 .setJdbcConnection(new JDBCConnectionProperties()
721 .dbtype(JDBCConnectionProperties.DbtypeEnum.SQLSERVER)
722 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "sqlserver")
723 .database("geodata")
724 .schema("dbo")
725 .additionalProperties(Map.of("connectionOptions", ";encrypt=false")))
726 .setAuthentication(new ServiceAuthentication()
727 .method(ServiceAuthentication.MethodEnum.PASSWORD)
728 .username("geodata")
729 .password(geodataPassword)),
730 "pdok-kadaster-bestuurlijkegebieden",
731 new TMFeatureSource()
732 .setProtocol(TMFeatureSource.Protocol.WFS)
733 .setUrl(
734 "https://service.pdok.nl/kadaster/bestuurlijkegebieden/wfs/v1_0?service=WFS&VERSION=2.0.0")
735 .setTitle("Bestuurlijke gebieden")
736 .setNotes(
737 "Overzicht van de bestuurlijke indeling van Nederland in gemeenten en provincies alsmede de rijksgrens. Gegevens zijn afgeleid uit de Basisregistratie Kadaster (BRK)."));
738 featureSourceRepository.saveAll(featureSources.values());
739
740 new WFSFeatureSourceHelper().loadCapabilities(featureSources.get("pdok-kadaster-bestuurlijkegebieden"));
741 geoServiceRepository.findById("pdok-kadaster-bestuurlijkegebieden").ifPresent(geoService -> {
742 geoService
743 .getSettings()
744 .getLayerSettings()
745 .put(
746 "Provinciegebied",
747 new GeoServiceLayerSettings()
748 .description("The administrative boundary of Dutch Provinces, connected to a WFS.")
749 .featureType(new FeatureTypeRef()
750 .featureSourceId(featureSources
751 .get("pdok-kadaster-bestuurlijkegebieden")
752 .getId())
753 .featureTypeName("bestuurlijkegebieden:Provinciegebied"))
754 .title("Provinciegebied (WFS)"));
755 geoServiceRepository.save(geoService);
756 });
757
758 geoServiceRepository.findById("bestuurlijkegebieden-proxied").ifPresent(geoService -> {
759 geoService
760 .getSettings()
761 .getLayerSettings()
762 .put(
763 "Provinciegebied",
764 new GeoServiceLayerSettings()
765 .featureType(new FeatureTypeRef()
766 .featureSourceId(featureSources
767 .get("pdok-kadaster-bestuurlijkegebieden")
768 .getId())
769 .featureTypeName("bestuurlijkegebieden:Provinciegebied"))
770 .title("Provinciegebied (WFS, proxied met auth)"));
771 geoServiceRepository.save(geoService);
772 });
773
774 CatalogNode featureSourceCatalogNode =
775 new CatalogNode().id("feature_sources").title("Test feature sources");
776 rootCatalogNode.addChildrenItem(featureSourceCatalogNode.getId());
777 catalog.getNodes().add(featureSourceCatalogNode);
778
779 for (TMFeatureSource featureSource : featureSources.values()) {
780 featureSourceCatalogNode.addItemsItem(new TailormapObjectRef()
781 .kind(TailormapObjectRef.KindEnum.FEATURE_SOURCE)
782 .id(featureSource.getId().toString()));
783 }
784 catalogRepository.save(catalog);
785
786 if (connectToSpatialDbs) {
787 featureSources.values().forEach(fs -> {
788 try {
789 if (fs.getProtocol() == TMFeatureSource.Protocol.JDBC) {
790 new JDBCFeatureSourceHelper().loadCapabilities(fs);
791 } else if (fs.getProtocol() == TMFeatureSource.Protocol.WFS) {
792 new WFSFeatureSourceHelper().loadCapabilities(fs);
793 }
794 } catch (Exception e) {
795 logger.error("Error loading capabilities for feature source {}", fs.getTitle(), e);
796 }
797 });
798
799 services.stream()
800
801
802 .filter(s -> s.getId().startsWith("snapshot-geoserver"))
803 .forEach(s -> s.getSettings()
804 .layerSettings(Map.of(
805 "postgis:begroeidterreindeel",
806 new GeoServiceLayerSettings()
807 .description(
808 """
809 This layer shows data from https:
810
811 https:
812 .featureType(new FeatureTypeRef()
813 .featureSourceId(featureSources
814 .get("postgis")
815 .getId())
816 .featureTypeName("begroeidterreindeel")),
817 "postgis:bak",
818 new GeoServiceLayerSettings()
819 .featureType(new FeatureTypeRef()
820 .featureSourceId(featureSources
821 .get("postgis")
822 .getId())
823 .featureTypeName("bak")),
824 "postgis:kadastraal_perceel",
825 new GeoServiceLayerSettings()
826 .description("cadastral parcel label points")
827 .featureType(new FeatureTypeRef()
828 .featureSourceId(featureSources
829 .get("postgis")
830 .getId())
831 .featureTypeName("kadastraal_perceel")),
832 "sqlserver:wegdeel",
833 new GeoServiceLayerSettings()
834 .attribution(
835 "CC BY 4.0 [BGT/Kadaster](https://www.nationaalgeoregister.nl/geonetwork/srv/api/records/2cb4769c-b56e-48fa-8685-c48f61b9a319)")
836 .description(
837 """
838 This layer shows data from [MS SQL Server](https:
839
840 https:
841 .featureType(new FeatureTypeRef()
842 .featureSourceId(featureSources
843 .get("sqlserver")
844 .getId())
845 .featureTypeName("wegdeel")),
846 "oracle:WATERDEEL",
847 new GeoServiceLayerSettings()
848 .description("This layer shows data from Oracle Spatial.")
849 .featureType(new FeatureTypeRef()
850 .featureSourceId(featureSources
851 .get("oracle")
852 .getId())
853 .featureTypeName("WATERDEEL")),
854 "postgis:osm_polygon",
855 new GeoServiceLayerSettings()
856 .description("This layer shows OSM data from postgis.")
857 .featureType(new FeatureTypeRef()
858 .featureSourceId(featureSources
859 .get("postgis_osm")
860 .getId())
861 .featureTypeName("osm_polygon")))));
862 }
863
864 featureSources.get("pdok-kadaster-bestuurlijkegebieden").getFeatureTypes().stream()
865 .filter(ft -> ft.getName().equals("bestuurlijkegebieden:Provinciegebied"))
866 .findFirst()
867 .ifPresent(ft -> {
868 ft.getSettings().addHideAttributesItem("identificatie");
869 ft.getSettings().addHideAttributesItem("ligtInLandCode");
870 ft.getSettings().addHideAttributesItem("fuuid");
871 ft.getSettings().putAttributeSettingsItem("naam", new AttributeSettings().title("Naam"));
872 ft.getSettings()
873 .setTemplate(
874 new FeatureTypeTemplate()
875 .templateLanguage("simple")
876 .markupLanguage("markdown")
877 .template(
878 """
879 ### Provincie
880 Deze provincie heet **{{naam}}** en ligt in _{{ligtInLandNaam}}_.
881
882 | Attribuut | Waarde |
883 | --------- | ------------------ |
884 | `code` | {{code}} |
885 | `naam` | {{naam}} |
886 | `ligt in` | {{ligtInLandNaam}} |"""));
887 });
888
889 featureSources.get("postgis").getFeatureTypes().stream()
890 .filter(ft -> ft.getName().equals("begroeidterreindeel"))
891 .findFirst()
892 .ifPresent(ft -> {
893 ft.getSettings().addHideAttributesItem("terminationdate");
894 ft.getSettings().addHideAttributesItem("geom_kruinlijn");
895 ft.getSettings().putAttributeSettingsItem("gmlid", new AttributeSettings().title("GML ID"));
896 ft.getSettings()
897 .putAttributeSettingsItem("identificatie", new AttributeSettings().title("Identificatie"));
898 ft.getSettings()
899 .putAttributeSettingsItem(
900 "tijdstipregistratie", new AttributeSettings().title("Registratie"));
901 ft.getSettings()
902 .putAttributeSettingsItem(
903 "eindregistratie", new AttributeSettings().title("Eind registratie"));
904 ft.getSettings().putAttributeSettingsItem("class", new AttributeSettings().title("Klasse"));
905 ft.getSettings()
906 .putAttributeSettingsItem("bronhouder", new AttributeSettings().title("Bronhouder"));
907 ft.getSettings()
908 .putAttributeSettingsItem("inonderzoek", new AttributeSettings().title("In onderzoek"));
909 ft.getSettings()
910 .putAttributeSettingsItem(
911 "relatievehoogteligging", new AttributeSettings().title("Relatieve hoogteligging"));
912 ft.getSettings()
913 .putAttributeSettingsItem("bgt_status", new AttributeSettings().title("BGT status"));
914 ft.getSettings()
915 .putAttributeSettingsItem("plus_status", new AttributeSettings().title("Plus-status"));
916 ft.getSettings()
917 .putAttributeSettingsItem(
918 "plus_fysiekvoorkomen", new AttributeSettings().title("Plus-fysiek voorkomen"));
919 ft.getSettings()
920 .putAttributeSettingsItem(
921 "begroeidterreindeeloptalud", new AttributeSettings().title("Op talud"));
922 ft.getSettings().addAttributeOrderItem("identificatie");
923 ft.getSettings().addAttributeOrderItem("bronhouder");
924 ft.getSettings().addAttributeOrderItem("class");
925 ft.getSettings()
926 .addAttachmentAttributesItem(new AttachmentAttributeType()
927 .attributeName("bijlage")
928 .maxAttachmentSize(4_000_000L)
929 .mimeType("image/jpeg, image/svg+xml, .png, image/*"));
930 try {
931 AttachmentsHelper.createAttachmentTableForFeatureType(ft);
932 } catch (IOException | SQLException e) {
933 throw new RuntimeException("Failed to create attachments table", e);
934 }
935 ft.getSettings().addEditableAttributesItem("identificatie");
936 ft.getSettings().addEditableAttributesItem("bronhouder");
937 ft.getSettings().addEditableAttributesItem("class");
938 ft.getSettings().addEditableAttributesItem("gmlid");
939 ft.getSettings().addEditableAttributesItem("lv_publicatiedatum");
940 ft.getSettings().addEditableAttributesItem("creationdate");
941 ft.getSettings().addEditableAttributesItem("tijdstipregistratie");
942 ft.getSettings().addEditableAttributesItem("eindregistratie");
943 ft.getSettings().addEditableAttributesItem("terminationdate");
944 ft.getSettings().addEditableAttributesItem("inonderzoek");
945 ft.getSettings().addEditableAttributesItem("relatievehoogteligging");
946 ft.getSettings().addEditableAttributesItem("bgt_status");
947 ft.getSettings().addEditableAttributesItem("plus_status");
948 ft.getSettings().addEditableAttributesItem("plus_fysiekvoorkomen");
949 ft.getSettings().addEditableAttributesItem("begroeidterreindeeloptalud");
950 });
951
952 featureSources.get("postgis").getFeatureTypes().stream()
953 .filter(ft -> ft.getName().equals("bak"))
954 .findFirst()
955 .ifPresent(ft -> {
956 ft.getSettings().addHideAttributesItem("gmlid");
957 ft.getSettings().addHideAttributesItem("lv_publicatiedatum");
958 ft.getSettings().addHideAttributesItem("creationdate");
959 ft.getSettings().addHideAttributesItem("tijdstipregistratie");
960 ft.getSettings().addHideAttributesItem("eindregistratie");
961 ft.getSettings().addHideAttributesItem("terminationdate");
962 ft.getSettings().addHideAttributesItem("inonderzoek");
963 ft.getSettings().addHideAttributesItem("relatievehoogteligging");
964 ft.getSettings().addHideAttributesItem("bgt_status");
965 ft.getSettings().addHideAttributesItem("plus_status");
966 ft.getSettings().addHideAttributesItem("function_");
967 ft.getSettings().addHideAttributesItem("plus_type");
968 });
969
970 featureSources.get("oracle").getFeatureTypes().stream()
971 .filter(ft -> ft.getName().equals("WATERDEEL"))
972 .findFirst()
973 .ifPresent(ft -> {
974 ft.getSettings()
975 .addAttachmentAttributesItem(new AttachmentAttributeType()
976 .attributeName("bijlage")
977 .maxAttachmentSize(4_000_000L)
978 .mimeType("image/jpeg, image/svg+xml, .png, image/*"));
979 try {
980 AttachmentsHelper.createAttachmentTableForFeatureType(ft);
981 } catch (IOException | SQLException e) {
982 throw new RuntimeException("Failed to create attachments table", e);
983 }
984 ft.getSettings().addEditableAttributesItem("GMLID");
985 ft.getSettings().addEditableAttributesItem("IDENTIFICATIE");
986 ft.getSettings().addEditableAttributesItem("LV_PUBLICATIEDATUM");
987 ft.getSettings().addEditableAttributesItem("CREATIONDATE");
988 ft.getSettings().addEditableAttributesItem("TIJDSTIPREGISTRATIE");
989 ft.getSettings().addEditableAttributesItem("EINDREGISTRATIE");
990 ft.getSettings().addEditableAttributesItem("TERMINATIONDATE");
991 ft.getSettings().addEditableAttributesItem("BRONHOUDER");
992 ft.getSettings().addEditableAttributesItem("INONDERZOEK");
993 ft.getSettings().addEditableAttributesItem("RELATIEVEHOOGTELIGGING");
994 ft.getSettings().addEditableAttributesItem("BGT_STATUS");
995 ft.getSettings().addEditableAttributesItem("PLUS_STATUS");
996 ft.getSettings().addEditableAttributesItem("CLASS");
997 ft.getSettings().addEditableAttributesItem("PLUS_TYPE");
998 });
999 featureSources.get("sqlserver").getFeatureTypes().stream()
1000 .filter(ft -> ft.getName().equals("wegdeel"))
1001 .findFirst()
1002 .ifPresent(ft -> {
1003 ft.getSettings()
1004 .addAttachmentAttributesItem(new AttachmentAttributeType()
1005 .attributeName("bijlage")
1006 .maxAttachmentSize(4_000_000L)
1007 .mimeType("image/jpeg, image/svg+xml, .png, image/*"));
1008 try {
1009 AttachmentsHelper.createAttachmentTableForFeatureType(ft);
1010 } catch (IOException | SQLException e) {
1011 throw new RuntimeException("Failed to create attachments table", e);
1012 }
1013 ft.getSettings().addEditableAttributesItem("gmlid");
1014 ft.getSettings().addEditableAttributesItem("identificatie");
1015 ft.getSettings().addEditableAttributesItem("lv_publicatiedatum");
1016 ft.getSettings().addEditableAttributesItem("creationdate");
1017 ft.getSettings().addEditableAttributesItem("tijdstipregistratie");
1018 ft.getSettings().addEditableAttributesItem("eindregistratie");
1019 ft.getSettings().addEditableAttributesItem("terminationdate");
1020 ft.getSettings().addEditableAttributesItem("bronhouder");
1021 ft.getSettings().addEditableAttributesItem("inonderzoek");
1022 ft.getSettings().addEditableAttributesItem("relatievehoogteligging");
1023 ft.getSettings().addEditableAttributesItem("bgt_status");
1024 ft.getSettings().addEditableAttributesItem("plus_status");
1025 ft.getSettings().addEditableAttributesItem("function_");
1026 ft.getSettings().addEditableAttributesItem("plus_functiewegdeel");
1027 ft.getSettings().addEditableAttributesItem("plus_fysiekvoorkomenwegdeel");
1028 ft.getSettings().addEditableAttributesItem("surfacematerial");
1029 ft.getSettings().addEditableAttributesItem("wegdeeloptalud");
1030 });
1031
1032 featureSources.get("postgis").getFeatureTypes().stream()
1033 .filter(ft -> ft.getName().equals("kadastraal_perceel"))
1034 .findFirst()
1035 .ifPresent(ft -> ft.getSettings().addHideAttributesItem("gml_id"));
1036
1037 featureSources.get("postgis_osm").getFeatureTypes().stream()
1038 .filter(ft -> ft.getName().equals("osm_polygon"))
1039 .findFirst()
1040 .ifPresent(ft -> {
1041 ft.getSettings().addEditableAttributesItem("osm_id");
1042 ft.getSettings().addEditableAttributesItem("building");
1043 ft.getSettings().addEditableAttributesItem("z_order");
1044 });
1045 }
1046
1047 public void createAppTestData() throws Exception {
1048 Upload logo = new Upload()
1049 .setCategory(Upload.CATEGORY_APP_LOGO)
1050 .setFilename("gradient.svg")
1051 .setMimeType("image/svg+xml")
1052 .setContent(new ClassPathResource("test/gradient-logo.svg").getContentAsByteArray())
1053 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
1054 uploadRepository.save(logo);
1055
1056 List<AppTreeNode> baseNodes = List.of(
1057 new AppTreeLayerNode()
1058 .objectType("AppTreeLayerNode")
1059 .id("lyr:openbasiskaart:osm")
1060 .serviceId("openbasiskaart")
1061 .layerName("osm")
1062 .visible(true),
1063 new AppTreeLayerNode()
1064 .objectType("AppTreeLayerNode")
1065 .id("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR")
1066 .serviceId("pdok-hwh-luchtfotorgb")
1067 .layerName("Actueel_orthoHR")
1068 .visible(false));
1069
1070 Application app = new Application()
1071 .setName("default")
1072 .setTitle("Tailormap demo")
1073 .setCrs("EPSG:28992")
1074 .setAuthorizationRules(ruleAnonymousRead)
1075 .setComponents(List.of(
1076 new Component()
1077 .type("SIMPLE_SEARCH")
1078 .config(new ComponentConfig()
1079 .enabled(true)
1080 .putAdditionalProperty("municipalities", List.of("0344"))),
1081 new Component().type("EDIT").config(new ComponentConfig().enabled(true)),
1082 new Component()
1083 .type("TOC")
1084 .config(new ComponentConfig()
1085 .enabled(true)
1086 .putAdditionalProperty("showEditLayerIcon", true)),
1087 new Component()
1088 .type("COORDINATE_LINK_WINDOW")
1089 .config(new ComponentConfig()
1090 .enabled(true)
1091 .putAdditionalProperty(
1092 "urls",
1093 List.of(
1094 Map.of(
1095 "id",
1096 "google-maps",
1097 "url",
1098 "https://www.google.com/maps/@[lat],[lon],18z",
1099 "alias",
1100 "Google Maps",
1101 "projection",
1102 "EPSG:4326"),
1103 Map.of(
1104 "id",
1105 "tm-demo",
1106 "url",
1107 "https://demo.tailormap.com/#@[X],[Y],18",
1108 "alias",
1109 "Tailormap demo",
1110 "projection",
1111 "EPSG:28992"))))))
1112 .setContentRoot(new AppContent()
1113 .addBaseLayerNodesItem(new AppTreeLevelNode()
1114 .objectType("AppTreeLevelNode")
1115 .id("root-base-layers")
1116 .root(true)
1117 .title("Base layers")
1118 .childrenIds(List.of(
1119 "lyr:openbasiskaart:osm",
1120 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR",
1121 "lyr:openbasiskaart-proxied:osm",
1122 "lyr:openbasiskaart-tms:xyz",
1123 "lyr:b3p-mapproxy-luchtfoto:xyz")))
1124 .addBaseLayerNodesItem(
1125
1126
1127 new AppTreeLayerNode()
1128 .objectType("AppTreeLayerNode")
1129 .id("lyr:openbasiskaart-proxied:osm")
1130 .serviceId("openbasiskaart-proxied")
1131 .layerName("osm")
1132 .visible(false))
1133 .addBaseLayerNodesItem(new AppTreeLayerNode()
1134 .objectType("AppTreeLayerNode")
1135 .id("lyr:openbasiskaart-tms:xyz")
1136 .serviceId("openbasiskaart-tms")
1137 .layerName("xyz")
1138 .visible(false))
1139 .addBaseLayerNodesItem(new AppTreeLayerNode()
1140 .objectType("AppTreeLayerNode")
1141 .id("lyr:b3p-mapproxy-luchtfoto:xyz")
1142 .serviceId("b3p-mapproxy-luchtfoto")
1143 .layerName("xyz")
1144 .visible(false))
1145 .addLayerNodesItem(new AppTreeLevelNode()
1146 .objectType("AppTreeLevelNode")
1147 .id("root")
1148 .root(true)
1149 .title("Layers")
1150 .childrenIds(List.of(
1151 "lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied",
1152 "lyr:bestuurlijkegebieden-proxied:Provinciegebied",
1153 "lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied",
1154 "lyr:snapshot-geoserver:postgis:begroeidterreindeel",
1155 "lyr:snapshot-geoserver:postgis:bak",
1156 "lyr:snapshot-geoserver:postgis:kadastraal_perceel",
1157 "lyr:snapshot-geoserver:sqlserver:wegdeel",
1158 "lyr:snapshot-geoserver:oracle:WATERDEEL",
1159 "lyr:snapshot-geoserver:BGT",
1160 "lvl:proxied",
1161 "lvl:osm",
1162 "lvl:archeo")))
1163 .addLayerNodesItem(new AppTreeLayerNode()
1164 .objectType("AppTreeLayerNode")
1165 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied")
1166 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1167 .layerName("Provinciegebied")
1168 .visible(true))
1169
1170
1171
1172 .addLayerNodesItem(new AppTreeLayerNode()
1173 .objectType("AppTreeLayerNode")
1174 .id("lyr:bestuurlijkegebieden-proxied:Provinciegebied")
1175 .serviceId("bestuurlijkegebieden-proxied")
1176 .layerName("Provinciegebied")
1177 .visible(false))
1178 .addLayerNodesItem(new AppTreeLayerNode()
1179 .objectType("AppTreeLayerNode")
1180 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied")
1181 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1182 .layerName("Gemeentegebied")
1183 .visible(true))
1184 .addLayerNodesItem(new AppTreeLayerNode()
1185 .objectType("AppTreeLayerNode")
1186 .id("lyr:snapshot-geoserver:postgis:begroeidterreindeel")
1187 .serviceId("snapshot-geoserver")
1188 .layerName("postgis:begroeidterreindeel")
1189 .visible(true))
1190 .addLayerNodesItem(new AppTreeLayerNode()
1191 .objectType("AppTreeLayerNode")
1192 .id("lyr:snapshot-geoserver:postgis:bak")
1193 .serviceId("snapshot-geoserver")
1194 .layerName("postgis:bak")
1195 .visible(false))
1196 .addLayerNodesItem(new AppTreeLayerNode()
1197 .objectType("AppTreeLayerNode")
1198 .id("lyr:snapshot-geoserver:postgis:kadastraal_perceel")
1199 .serviceId("snapshot-geoserver")
1200 .layerName("postgis:kadastraal_perceel")
1201 .visible(false))
1202 .addLayerNodesItem(new AppTreeLayerNode()
1203 .objectType("AppTreeLayerNode")
1204 .id("lyr:snapshot-geoserver:sqlserver:wegdeel")
1205 .serviceId("snapshot-geoserver")
1206 .layerName("sqlserver:wegdeel")
1207 .visible(true))
1208 .addLayerNodesItem(new AppTreeLayerNode()
1209 .objectType("AppTreeLayerNode")
1210 .id("lyr:snapshot-geoserver:oracle:WATERDEEL")
1211 .serviceId("snapshot-geoserver")
1212 .layerName("oracle:WATERDEEL")
1213 .visible(true))
1214 .addLayerNodesItem(new AppTreeLayerNode()
1215 .objectType("AppTreeLayerNode")
1216 .id("lyr:snapshot-geoserver:BGT")
1217 .serviceId("snapshot-geoserver")
1218 .layerName("BGT")
1219 .visible(false))
1220 .addLayerNodesItem(new AppTreeLevelNode()
1221 .objectType("AppTreeLevelNode")
1222 .id("lvl:proxied")
1223 .title("Proxied")
1224 .childrenIds(List.of("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")))
1225 .addLayerNodesItem(new AppTreeLayerNode()
1226 .objectType("AppTreeLayerNode")
1227 .id("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")
1228 .serviceId("snapshot-geoserver-proxied")
1229 .layerName("postgis:begroeidterreindeel")
1230 .visible(false))
1231 .addLayerNodesItem(new AppTreeLevelNode()
1232 .objectType("AppTreeLevelNode")
1233 .id("lvl:osm")
1234 .title("OSM")
1235 .childrenIds(List.of("lyr:snapshot-geoserver:postgis:osm_polygon")))
1236 .addLayerNodesItem(new AppTreeLayerNode()
1237 .objectType("AppTreeLayerNode")
1238 .id("lyr:snapshot-geoserver:postgis:osm_polygon")
1239 .serviceId("snapshot-geoserver")
1240 .layerName("postgis:osm_polygon")
1241 .visible(false))
1242 .addLayerNodesItem(new AppTreeLevelNode()
1243 .objectType("AppTreeLevelNode")
1244 .id("lvl:archeo")
1245 .title("Archeology")
1246 .childrenIds(List.of("lyr:demo:geomorfologie")))
1247 .addLayerNodesItem(new AppTreeLayerNode()
1248 .objectType("AppTreeLayerNode")
1249 .id("lyr:demo:geomorfologie")
1250 .serviceId("demo")
1251 .layerName("geomorfologie")
1252 .visible(true)))
1253 .setStyling(new AppStyling().logo(logo.getId().toString()))
1254 .setSettings(new AppSettings()
1255 .putLayerSettingsItem("lyr:openbasiskaart:osm", new AppLayerSettings().title("Openbasiskaart"))
1256 .putLayerSettingsItem(
1257 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR", new AppLayerSettings().title("Luchtfoto"))
1258 .putLayerSettingsItem(
1259 "lyr:openbasiskaart-proxied:osm",
1260 new AppLayerSettings().title("Openbasiskaart (proxied)"))
1261 .putLayerSettingsItem(
1262 "lyr:snapshot-geoserver:oracle:WATERDEEL",
1263 new AppLayerSettings()
1264 .opacity(50)
1265 .title("Waterdeel overridden title")
1266 .editable(true)
1267 .description("This is the layer description from the app layer setting.")
1268 .attribution(
1269 "CC BY 4.0 [BGT/Kadaster](https://www.nationaalgeoregister.nl/geonetwork/srv/api/records/2cb4769c-b56e-48fa-8685-c48f61b9a319)"))
1270 .putLayerSettingsItem(
1271 "lyr:snapshot-geoserver:postgis:osm_polygon",
1272 new AppLayerSettings()
1273 .description("OpenStreetMap polygon data in EPSG:3857")
1274 .opacity(60)
1275 .editable(true)
1276 .title("OSM Polygon (EPSG:3857)")
1277 .attribution(
1278 "© [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors"))
1279 .putLayerSettingsItem(
1280 "lyr:snapshot-geoserver:postgis:begroeidterreindeel",
1281 new AppLayerSettings()
1282 .editable(true)
1283 .addHideAttributesItem("begroeidterreindeeloptalud")
1284 .addReadOnlyAttributesItem("eindregistratie"))
1285 .putLayerSettingsItem(
1286 "lyr:snapshot-geoserver:postgis:kadastraal_perceel",
1287 new AppLayerSettings().editable(true).addReadOnlyAttributesItem("aanduiding"))
1288 .putLayerSettingsItem(
1289 "lyr:snapshot-geoserver:sqlserver:wegdeel", new AppLayerSettings().editable(true))
1290 .putLayerSettingsItem(
1291 "lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel",
1292 new AppLayerSettings().editable(false))
1293 .putLayerSettingsItem(
1294 "lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied",
1295 new AppLayerSettings()
1296 .hiddenFunctionality(Set.of(FEATURE_INFO, ATTRIBUTE_LIST, EXPORT)))
1297 .addFilterGroupsItem(new FilterGroup()
1298 .id("filtergroup1")
1299 .source("PRESET")
1300 .type(FilterGroup.TypeEnum.ATTRIBUTE)
1301 .layerIds(List.of("lyr:snapshot-geoserver:postgis:begroeidterreindeel"))
1302 .operator(FilterGroup.OperatorEnum.AND)
1303 .addFiltersItem(new Filter()
1304 .id("filter1")
1305 .type(Filter.TypeEnum.ATTRIBUTE)
1306 .condition(Filter.ConditionEnum.BEFORE)
1307 .addValueItem("2025-06-05")
1308 .attribute("creationdate")
1309 .attributeType(Filter.AttributeTypeEnum.DATE))
1310 .addFiltersItem(new Filter()
1311 .id("filter2")
1312 .type(Filter.TypeEnum.ATTRIBUTE)
1313 .condition(Filter.ConditionEnum.UNIQUE_VALUES)
1314 .addValueItem("bodembedekkers")
1315 .addValueItem("bosplantsoen")
1316 .addValueItem("gras- en kruidachtigen")
1317 .attribute("plus_fysiekvoorkomen")
1318 .attributeType(Filter.AttributeTypeEnum.STRING)
1319 .editConfiguration(new FilterEditConfiguration()
1320 .filterTool(FilterEditConfiguration.FilterToolEnum.CHECKBOX)
1321 .attributeValuesSettings(List.of(
1322 new AttributeValueSettings()
1323 .value("bodembedekkers")
1324 .initiallySelected(true)
1325 .selectable(true)
1326 .alias("Bodembedekkers"),
1327 new AttributeValueSettings()
1328 .value("bosplantsoen")
1329 .initiallySelected(true)
1330 .selectable(true)
1331 .alias("Bosplantsoen"),
1332 new AttributeValueSettings()
1333 .value("gras- en kruidachtigen")
1334 .initiallySelected(true)
1335 .selectable(true)
1336 .alias("Gras- en kruidachtigen"),
1337 new AttributeValueSettings()
1338 .value("griend en hakhout")
1339 .initiallySelected(false)
1340 .selectable(true),
1341 new AttributeValueSettings()
1342 .value("heesters")
1343 .initiallySelected(false)
1344 .selectable(true),
1345 new AttributeValueSettings()
1346 .value("planten")
1347 .initiallySelected(false)
1348 .selectable(true),
1349 new AttributeValueSettings()
1350 .value("struikrozen")
1351 .initiallySelected(false)
1352 .selectable(true),
1353 new AttributeValueSettings()
1354 .value("waardeOnbekend")
1355 .initiallySelected(false)
1356 .selectable(true))))))
1357 .addFilterGroupsItem(new FilterGroup()
1358 .id("filtergroup2")
1359 .source("PRESET")
1360 .type(FilterGroup.TypeEnum.ATTRIBUTE)
1361 .layerIds(List.of("lyr:snapshot-geoserver:postgis:kadastraal_perceel"))
1362 .operator(FilterGroup.OperatorEnum.AND)
1363 .addFiltersItem(new Filter()
1364 .id("filter3")
1365 .type(Filter.TypeEnum.ATTRIBUTE)
1366 .condition(Filter.ConditionEnum.u)
1367 .addValueItem("1")
1368 .addValueItem("12419")
1369 .attribute("perceelnummer")
1370 .attributeType(Filter.AttributeTypeEnum.DOUBLE)
1371 .editConfiguration(new FilterEditConfiguration()
1372 .filterTool(FilterEditConfiguration.FilterToolEnum.SLIDER)
1373 .initialLowerValue(1d)
1374 .initialUpperValue(12419d)
1375 .minimumValue(1d)
1376 .maximumValue(12419d)))));
1377
1378 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1379 app.setInitialExtent(
1380 new Bounds().minx(130011d).miny(458031d).maxx(132703d).maxy(459995d));
1381 app.setMaxExtent(new Bounds().minx(-285401d).miny(22598d).maxx(595401d).maxy(903401d));
1382
1383 if (map5url != null) {
1384 AppTreeLevelNode root =
1385 (AppTreeLevelNode) app.getContentRoot().getBaseLayerNodes().getFirst();
1386 List<String> childrenIds = new ArrayList<>(root.getChildrenIds());
1387 childrenIds.add("lyr:map5:map5topo");
1388 childrenIds.add("lyr:map5:map5topo_simple");
1389 childrenIds.add("lvl:luchtfoto-labels");
1390 root.setChildrenIds(childrenIds);
1391 app.getSettings()
1392 .putLayerSettingsItem("lyr:map5:map5topo", new AppLayerSettings().title("Map5"))
1393 .putLayerSettingsItem("lyr:map5:map5topo_simple", new AppLayerSettings().title("Map5 simple"));
1394 app.getContentRoot()
1395 .addBaseLayerNodesItem(new AppTreeLayerNode()
1396 .objectType("AppTreeLayerNode")
1397 .id("lyr:map5:map5topo")
1398 .serviceId("map5")
1399 .layerName("map5topo")
1400 .visible(false))
1401 .addBaseLayerNodesItem(new AppTreeLayerNode()
1402 .objectType("AppTreeLayerNode")
1403 .id("lyr:map5:map5topo_simple")
1404 .serviceId("map5")
1405 .layerName("map5topo_simple")
1406 .visible(false))
1407 .addBaseLayerNodesItem(new AppTreeLevelNode()
1408 .objectType("AppTreeLevelNode")
1409 .id("lvl:luchtfoto-labels")
1410 .title("Luchtfoto met labels")
1411 .addChildrenIdsItem("lyr:map5:luforoadslabels")
1412 .addChildrenIdsItem("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR2"))
1413 .addBaseLayerNodesItem(new AppTreeLayerNode()
1414 .objectType("AppTreeLayerNode")
1415 .id("lyr:map5:luforoadslabels")
1416 .serviceId("map5")
1417 .layerName("luforoadslabels")
1418 .visible(false))
1419 .addBaseLayerNodesItem(new AppTreeLayerNode()
1420 .objectType("AppTreeLayerNode")
1421 .id("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR2")
1422 .serviceId("pdok-hwh-luchtfotorgb")
1423 .layerName("Actueel_orthoHR")
1424 .visible(false));
1425 }
1426
1427 applicationRepository.save(app);
1428
1429 app = new Application()
1430 .setName("base")
1431 .setTitle("Service base app")
1432 .setCrs("EPSG:28992")
1433 .setAuthorizationRules(ruleAnonymousRead)
1434 .setContentRoot(new AppContent()
1435 .addBaseLayerNodesItem(new AppTreeLevelNode()
1436 .objectType("AppTreeLevelNode")
1437 .id("root-base-layers")
1438 .root(true)
1439 .title("Base layers")
1440 .childrenIds(List.of(
1441 "lyr:openbasiskaart:osm", "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR"))));
1442 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1443 applicationRepository.save(app);
1444
1445 app = new Application()
1446 .setName("secured")
1447 .setTitle("secured app")
1448 .setCrs("EPSG:28992")
1449 .setAuthorizationRules(ruleLoggedIn)
1450 .setContentRoot(new AppContent()
1451 .addBaseLayerNodesItem(new AppTreeLevelNode()
1452 .objectType("AppTreeLevelNode")
1453 .id("root-base-layers")
1454 .root(true)
1455 .title("Base layers")
1456 .childrenIds(List.of(
1457 "lyr:openbasiskaart:osm",
1458 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR",
1459 "lyr:openbasiskaart-proxied:osm")))
1460 .addBaseLayerNodesItem(new AppTreeLayerNode()
1461 .objectType("AppTreeLayerNode")
1462 .id("lyr:openbasiskaart-proxied:osm")
1463 .serviceId("openbasiskaart-proxied")
1464 .layerName("osm")
1465 .visible(false))
1466 .addLayerNodesItem(new AppTreeLevelNode()
1467 .objectType("AppTreeLevelNode")
1468 .id("root")
1469 .root(true)
1470 .title("Layers")
1471 .childrenIds(List.of(
1472 "lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied",
1473 "lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied",
1474 "lvl:proxied")))
1475 .addLayerNodesItem(new AppTreeLayerNode()
1476 .objectType("AppTreeLayerNode")
1477 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied")
1478 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1479 .layerName("Gemeentegebied")
1480 .visible(true))
1481 .addLayerNodesItem(new AppTreeLayerNode()
1482 .objectType("AppTreeLayerNode")
1483 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied")
1484 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1485 .layerName("Provinciegebied")
1486 .visible(false))
1487 .addLayerNodesItem(new AppTreeLevelNode()
1488 .objectType("AppTreeLevelNode")
1489 .id("lvl:proxied")
1490 .title("Proxied")
1491 .childrenIds(List.of("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")))
1492 .addLayerNodesItem(new AppTreeLayerNode()
1493 .objectType("AppTreeLayerNode")
1494 .id("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")
1495 .serviceId("snapshot-geoserver-proxied")
1496 .layerName("postgis:begroeidterreindeel")
1497 .visible(false)))
1498 .setSettings(new AppSettings()
1499 .putLayerSettingsItem(
1500 "lyr:openbasiskaart-proxied:osm",
1501 new AppLayerSettings().title("Openbasiskaart (proxied)")));
1502
1503 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1504 applicationRepository.save(app);
1505
1506 app = new Application()
1507 .setName("secured-auth")
1508 .setTitle("secured (with authorizations)")
1509 .setCrs("EPSG:28992")
1510 .setAuthorizationRules(List.of(
1511 new AuthorizationRule()
1512 .groupName("test-foo")
1513 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW)),
1514 new AuthorizationRule()
1515 .groupName("test-bar")
1516 .decisions(Map.of(ACCESS_TYPE_VIEW, AuthorizationRuleDecision.ALLOW))))
1517 .setContentRoot(new AppContent()
1518 .addLayerNodesItem(new AppTreeLevelNode()
1519 .objectType("AppTreeLevelNode")
1520 .id("root")
1521 .root(true)
1522 .title("Layers")
1523 .childrenIds(List.of("lvl:needs-auth", "lvl:public")))
1524 .addLayerNodesItem(new AppTreeLevelNode()
1525 .objectType("AppTreeLevelNode")
1526 .id("lvl:public")
1527 .title("Public")
1528 .childrenIds(List.of("lyr:snapshot-geoserver:BGT")))
1529 .addLayerNodesItem(new AppTreeLevelNode()
1530 .objectType("AppTreeLevelNode")
1531 .id("lvl:needs-auth")
1532 .title("Needs auth")
1533 .childrenIds(List.of(
1534 "lyr:filtered-snapshot-geoserver:BGT",
1535 "lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")))
1536 .addLayerNodesItem(new AppTreeLayerNode()
1537 .objectType("AppTreeLayerNode")
1538 .id("lyr:filtered-snapshot-geoserver:BGT")
1539 .serviceId("filtered-snapshot-geoserver")
1540 .layerName("BGT")
1541 .visible(true))
1542 .addLayerNodesItem(new AppTreeLayerNode()
1543 .objectType("AppTreeLayerNode")
1544 .id("lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")
1545 .serviceId("filtered-snapshot-geoserver")
1546 .layerName("postgis:begroeidterreindeel")
1547 .visible(true))
1548 .addLayerNodesItem(new AppTreeLayerNode()
1549 .objectType("AppTreeLayerNode")
1550 .id("lyr:snapshot-geoserver:BGT")
1551 .serviceId("snapshot-geoserver")
1552 .layerName("BGT")
1553 .visible(true)));
1554
1555 applicationRepository.save(app);
1556
1557 app = new Application()
1558 .setName("austria")
1559 .setCrs("EPSG:3857")
1560 .setAuthorizationRules(ruleAnonymousRead)
1561 .setTitle("Austria")
1562 .setInitialExtent(
1563 new Bounds().minx(987982d).miny(5799551d).maxx(1963423d).maxy(6320708d))
1564 .setMaxExtent(
1565 new Bounds().minx(206516d).miny(5095461d).maxx(3146930d).maxy(7096232d))
1566 .setContentRoot(new AppContent()
1567 .addBaseLayerNodesItem(new AppTreeLevelNode()
1568 .objectType("AppTreeLevelNode")
1569 .id("root-base-layers")
1570 .root(true)
1571 .title("Base layers")
1572 .childrenIds(List.of(
1573 "lyr:at-basemap:geolandbasemap",
1574 "lyr:at-basemap:orthofoto",
1575 "lvl:orthofoto-labels",
1576 "lyr:osm:xyz")))
1577 .addBaseLayerNodesItem(new AppTreeLayerNode()
1578 .objectType("AppTreeLayerNode")
1579 .id("lyr:at-basemap:geolandbasemap")
1580 .serviceId("at-basemap")
1581 .layerName("geolandbasemap")
1582 .visible(true))
1583 .addBaseLayerNodesItem(new AppTreeLayerNode()
1584 .objectType("AppTreeLayerNode")
1585 .id("lyr:at-basemap:orthofoto")
1586 .serviceId("at-basemap")
1587 .layerName("bmaporthofoto30cm")
1588 .visible(false))
1589 .addBaseLayerNodesItem(new AppTreeLevelNode()
1590 .objectType("AppTreeLevelNode")
1591 .id("lvl:orthofoto-labels")
1592 .title("Orthophoto with labels")
1593 .childrenIds(List.of("lyr:at-basemap:bmapoverlay", "lyr:at-basemap:orthofoto_2")))
1594 .addBaseLayerNodesItem(new AppTreeLayerNode()
1595 .objectType("AppTreeLayerNode")
1596 .id("lyr:at-basemap:bmapoverlay")
1597 .serviceId("at-basemap")
1598 .layerName("bmapoverlay")
1599 .visible(false))
1600 .addBaseLayerNodesItem(new AppTreeLayerNode()
1601 .objectType("AppTreeLayerNode")
1602 .id("lyr:at-basemap:orthofoto_2")
1603 .serviceId("at-basemap")
1604 .layerName("bmaporthofoto30cm")
1605 .visible(false))
1606 .addBaseLayerNodesItem(new AppTreeLayerNode()
1607 .objectType("AppTreeLayerNode")
1608 .id("lyr:osm:xyz")
1609 .serviceId("osm")
1610 .layerName("xyz")
1611 .visible(false)));
1612
1613 applicationRepository.save(app);
1614
1615 app = new Application()
1616 .setName("3d_utrecht")
1617 .setCrs("EPSG:3857")
1618 .setAuthorizationRules(ruleLoggedIn)
1619 .setTitle("3D Utrecht")
1620 .setInitialExtent(
1621 new Bounds().minx(558390d).miny(6818485d).maxx(566751d).maxy(6824036d))
1622 .setMaxExtent(
1623 new Bounds().minx(91467d).miny(6496479d).maxx(1037043d).maxy(7147453d))
1624 .setSettings(new AppSettings().uiSettings(new AppUiSettings().enable3D(true)))
1625 .setContentRoot(new AppContent()
1626 .addBaseLayerNodesItem(new AppTreeLevelNode()
1627 .objectType("AppTreeLevelNode")
1628 .id("root-base-layers")
1629 .root(true)
1630 .title("Base layers")
1631 .childrenIds(List.of("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR", "lyr:osm:xyz")))
1632 .addBaseLayerNodesItem(new AppTreeLayerNode()
1633 .objectType("AppTreeLayerNode")
1634 .id("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR")
1635 .serviceId("pdok-hwh-luchtfotorgb")
1636 .layerName("Actueel_orthoHR")
1637 .visible(true))
1638 .addBaseLayerNodesItem(new AppTreeLayerNode()
1639 .objectType("AppTreeLayerNode")
1640 .id("lyr:osm:xyz")
1641 .serviceId("osm")
1642 .layerName("xyz")
1643 .visible(false))
1644 .addLayerNodesItem(new AppTreeLevelNode()
1645 .objectType("AppTreeLevelNode")
1646 .id("root")
1647 .root(true)
1648 .title("Layers")
1649 .childrenIds(List.of(
1650 "lyr:3dbag_utrecht:tiles3d",
1651 "lyr:snapshot-geoserver:postgis:begroeidterreindeel",
1652 "lyr:3d_basisvoorziening_gebouwen_proxy:tiles3d",
1653 "lyr:3d_utrecht_proxied_auth:tiles3d")))
1654 .addLayerNodesItem(new AppTreeLayerNode()
1655 .objectType("AppTreeLayerNode")
1656 .id("lyr:3dbag_utrecht:tiles3d")
1657 .serviceId("3dbag_utrecht")
1658 .layerName("tiles3d")
1659 .visible(true))
1660 .addLayerNodesItem(new AppTreeLayerNode()
1661 .objectType("AppTreeLayerNode")
1662 .id("lyr:3d_basisvoorziening_gebouwen_proxy:tiles3d")
1663 .serviceId("3d_basisvoorziening_gebouwen_proxy")
1664 .layerName("tiles3d")
1665 .visible(false))
1666 .addLayerNodesItem(new AppTreeLayerNode()
1667 .objectType("AppTreeLayerNode")
1668 .id("lyr:3d_utrecht_proxied_auth:tiles3d")
1669 .serviceId("3d_utrecht_proxied_auth")
1670 .layerName("tiles3d")
1671 .visible(false))
1672 .addLayerNodesItem(new AppTreeLayerNode()
1673 .objectType("AppTreeLayerNode")
1674 .id("lyr:snapshot-geoserver:postgis:begroeidterreindeel")
1675 .serviceId("snapshot-geoserver")
1676 .layerName("postgis:begroeidterreindeel")
1677 .visible(true))
1678 .addTerrainLayerNodesItem(new AppTreeLevelNode()
1679 .objectType("AppTreeLevelNode")
1680 .id("root-terrain-layers")
1681 .root(true)
1682 .title("Terrain Layers")
1683 .childrenIds(List.of("lyr:ahn_terrain_model:quantizedmesh")))
1684 .addTerrainLayerNodesItem(new AppTreeLayerNode()
1685 .objectType("AppTreeLayerNode")
1686 .id("lyr:ahn_terrain_model:quantizedmesh")
1687 .serviceId("ahn_terrain_model")
1688 .layerName("quantizedmesh")
1689 .visible(false)));
1690
1691 applicationRepository.save(app);
1692
1693 app = new Application()
1694 .setName("public-with-auth")
1695 .setTitle("Public app with one restricted layer in a group")
1696 .setCrs("EPSG:28992")
1697 .setAuthorizationRules(ruleAnonymousRead)
1698 .setInitialExtent(
1699 new Bounds().minx(130011d).miny(458031d).maxx(132703d).maxy(459995d))
1700 .setMaxExtent(
1701 new Bounds().minx(-285401d).miny(22598d).maxx(595401d).maxy(903401d))
1702 .setStyling(new AppStyling().logo(logo.getId().toString()))
1703 .setContentRoot(new AppContent()
1704 .addBaseLayerNodesItem(new AppTreeLevelNode()
1705 .objectType("AppTreeLevelNode")
1706 .id("root")
1707 .root(true)
1708 .title("Basemaps")
1709 .childrenIds(List.of("lyr:openbasiskaart:osm")))
1710 .addBaseLayerNodesItem(new AppTreeLayerNode()
1711 .objectType("AppTreeLayerNode")
1712 .id("lyr:openbasiskaart:osm")
1713 .serviceId("openbasiskaart")
1714 .layerName("osm")
1715 .visible(true))
1716 .addLayerNodesItem(new AppTreeLevelNode()
1717 .objectType("AppTreeLevelNode")
1718 .id("root")
1719 .root(true)
1720 .title("Application layers")
1721 .childrenIds(List.of(
1722 "lyr:snapshot-geoserver:postgis:kadastraal_perceel", "xpfhl34VmghkU12nP9Jer")))
1723 .addLayerNodesItem(new AppTreeLayerNode()
1724 .objectType("AppTreeLayerNode")
1725 .id("lyr:snapshot-geoserver:postgis:kadastraal_perceel")
1726 .serviceId("snapshot-geoserver")
1727 .layerName("postgis:kadastraal_perceel")
1728 .visible(true))
1729 .addLayerNodesItem(new AppTreeLevelNode()
1730 .id("xpfhl34VmghkU12nP9Jer")
1731 .root(false)
1732 .title("restricted")
1733 .objectType("AppTreeLevelNode")
1734 .childrenIds(List.of("lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")))
1735 .addLayerNodesItem(new AppTreeLayerNode()
1736 .objectType("AppTreeLayerNode")
1737 .id("lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")
1738 .visible(true)
1739 .serviceId("filtered-snapshot-geoserver")
1740 .layerName("postgis:begroeidterreindeel")))
1741 .setSettings(new AppSettings());
1742
1743 applicationRepository.save(app);
1744
1745 Configuration config = new Configuration();
1746 config.setKey(Configuration.DEFAULT_APP);
1747 config.setValue("default");
1748 configurationRepository.save(config);
1749 config = new Configuration();
1750 config.setKey(Configuration.DEFAULT_BASE_APP);
1751 config.setValue("base");
1752 configurationRepository.save(config);
1753 }
1754
1755 private void createConfigurationTestData() throws JsonProcessingException {
1756 Configuration config = new Configuration();
1757 config.setKey("test");
1758 config.setAvailableForViewer(true);
1759 config.setValue("test value");
1760 config.setJsonValue(new ObjectMapper().readTree("{ \"someProperty\": 1, \"nestedObject\": { \"num\": 42 } }"));
1761 configurationRepository.save(config);
1762 }
1763
1764 @Transactional
1765 public void createSolrIndex() throws Exception {
1766 if (connectToSpatialDbs) {
1767
1768
1769 featureSourceRepository.flush();
1770
1771 logger.info("Creating Solr index");
1772 @SuppressWarnings("PMD.AvoidUsingHardCodedIP")
1773 final String solrUrl = "http://" + (connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "solr") + ":8983/solr/";
1774 this.solrService.setSolrUrl(solrUrl);
1775 SolrHelper solrHelper = new SolrHelper(this.solrService.getSolrClientForIndexing())
1776 .withBatchSize(solrBatchSize)
1777 .withGeometryValidationRule(solrGeometryValidationRule);
1778 GeoService geoService =
1779 geoServiceRepository.findById("snapshot-geoserver").orElseThrow();
1780 Application defaultApp = applicationRepository.findByName("default");
1781
1782 TMFeatureType begroeidterreindeelFT = geoService.findFeatureTypeForLayer(
1783 geoService.findLayer("postgis:begroeidterreindeel"), featureSourceRepository);
1784
1785 TMFeatureType wegdeelFT = geoService.findFeatureTypeForLayer(
1786 geoService.findLayer("sqlserver:wegdeel"), featureSourceRepository);
1787
1788 TMFeatureType kadastraalPerceelFT = geoService.findFeatureTypeForLayer(
1789 geoService.findLayer("postgis:kadastraal_perceel"), featureSourceRepository);
1790
1791 try (solrHelper) {
1792 SearchIndex begroeidterreindeelIndex = null;
1793 if (begroeidterreindeelFT != null) {
1794 begroeidterreindeelIndex = new SearchIndex()
1795 .setName("Begroeidterreindeel")
1796 .setFeatureTypeId(begroeidterreindeelFT.getId())
1797 .setSearchFieldsUsed(List.of("class", "plus_fysiekvoorkomen", "bronhouder"))
1798 .setSearchDisplayFieldsUsed(List.of("class", "plus_fysiekvoorkomen"));
1799 begroeidterreindeelIndex = searchIndexRepository.save(begroeidterreindeelIndex);
1800 begroeidterreindeelIndex = solrHelper.addFeatureTypeIndex(
1801 begroeidterreindeelIndex,
1802 begroeidterreindeelFT,
1803 featureSourceFactoryHelper,
1804 searchIndexRepository);
1805 begroeidterreindeelIndex = searchIndexRepository.save(begroeidterreindeelIndex);
1806 }
1807
1808 SearchIndex kadastraalPerceelIndex = null;
1809 if (kadastraalPerceelFT != null) {
1810 kadastraalPerceelIndex = new SearchIndex()
1811 .setName("kadastraal_perceel")
1812 .setFeatureTypeId(kadastraalPerceelFT.getId())
1813 .setSearchFieldsUsed(List.of("aanduiding"))
1814 .setSearchDisplayFieldsUsed(List.of("aanduiding"));
1815 kadastraalPerceelIndex = searchIndexRepository.save(kadastraalPerceelIndex);
1816 kadastraalPerceelIndex = solrHelper.addFeatureTypeIndex(
1817 kadastraalPerceelIndex,
1818 kadastraalPerceelFT,
1819 featureSourceFactoryHelper,
1820 searchIndexRepository);
1821 kadastraalPerceelIndex = searchIndexRepository.save(kadastraalPerceelIndex);
1822 }
1823
1824 SearchIndex wegdeelIndex = null;
1825 if (wegdeelFT != null) {
1826 wegdeelIndex = new SearchIndex()
1827 .setName("Wegdeel")
1828 .setFeatureTypeId(wegdeelFT.getId())
1829 .setSearchFieldsUsed(List.of(
1830 "function_", "plus_fysiekvoorkomenwegdeel", "surfacematerial", "bronhouder"))
1831 .setSearchDisplayFieldsUsed(List.of("function_", "plus_fysiekvoorkomenwegdeel"));
1832 wegdeelIndex = searchIndexRepository.save(wegdeelIndex);
1833 wegdeelIndex = solrHelper.addFeatureTypeIndex(
1834 wegdeelIndex, wegdeelFT, featureSourceFactoryHelper, searchIndexRepository);
1835 wegdeelIndex = searchIndexRepository.save(wegdeelIndex);
1836 }
1837
1838 featureSourceRepository
1839 .getByTitle("PostGIS")
1840 .flatMap(fs -> fs.getFeatureTypes().stream()
1841 .filter(ft -> ft.getName().equals("bak"))
1842 .findFirst())
1843 .ifPresent(ft -> {
1844 SearchIndex bak = new SearchIndex()
1845 .setName("bak")
1846 .setFeatureTypeId(ft.getId())
1847 .setSearchFieldsUsed(List.of("gmlid", "identificatie", "plus_type"))
1848 .setSearchDisplayFieldsUsed(List.of("gmlid", "plus_type", "bronhouder"));
1849 searchIndexRepository.save(bak);
1850 try {
1851 bak = solrHelper.addFeatureTypeIndex(
1852 bak, ft, featureSourceFactoryHelper, searchIndexRepository);
1853 searchIndexRepository.save(bak);
1854 } catch (IOException | SolrServerException e) {
1855 throw new RuntimeException(e);
1856 }
1857 });
1858
1859
1860
1861 featureSourceRepository
1862 .getByTitle("PostGIS OSM")
1863 .flatMap(fs -> fs.getFeatureTypes().stream()
1864 .filter(ft -> ft.getName().equals("osm_roads"))
1865 .findFirst())
1866 .ifPresent(ft -> {
1867 SearchIndex osm_no_pk = new SearchIndex()
1868 .setName("osm_no_pk")
1869 .setFeatureTypeId(ft.getId())
1870 .setSearchFieldsUsed(List.of("landuse", "osm_id", "natural", "boundary"))
1871 .setSearchDisplayFieldsUsed(
1872 List.of("landuse", "osm_id", "natural", "amenity", "boundary"));
1873 searchIndexRepository.save(osm_no_pk);
1874 });
1875
1876 AppTreeLayerNode begroeidTerreindeelLayerNode = defaultApp
1877 .getAllAppTreeLayerNode()
1878 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:postgis:begroeidterreindeel"))
1879 .findFirst()
1880 .orElse(null);
1881
1882 if (begroeidTerreindeelLayerNode != null && begroeidterreindeelIndex != null) {
1883 defaultApp
1884 .getAppLayerSettings(begroeidTerreindeelLayerNode)
1885 .setSearchIndexId(begroeidterreindeelIndex.getId());
1886 }
1887
1888 AppTreeLayerNode kadastraalPerceelLayerNode = defaultApp
1889 .getAllAppTreeLayerNode()
1890 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:postgis:kadastraal_perceel"))
1891 .findFirst()
1892 .orElse(null);
1893
1894 if (kadastraalPerceelLayerNode != null && kadastraalPerceelIndex != null) {
1895 defaultApp
1896 .getAppLayerSettings(kadastraalPerceelLayerNode)
1897 .setSearchIndexId(kadastraalPerceelIndex.getId());
1898 }
1899
1900 AppTreeLayerNode wegdeel = defaultApp
1901 .getAllAppTreeLayerNode()
1902 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:sqlserver:wegdeel"))
1903 .findFirst()
1904 .orElse(null);
1905
1906 if (wegdeel != null && wegdeelIndex != null) {
1907 defaultApp.getAppLayerSettings(wegdeel).setSearchIndexId(wegdeelIndex.getId());
1908 }
1909
1910 applicationRepository.save(defaultApp);
1911 }
1912 }
1913 }
1914
1915 private void createSearchIndexTasks() {
1916 logger.info("Creating search index tasks");
1917 List.of("Begroeidterreindeel", "kadastraal_perceel")
1918 .forEach(name -> searchIndexRepository.findByName(name).ifPresent(index -> {
1919 index.setSchedule(new TaskSchedule()
1920
1921 .cronExpression("0 0 0/1 1/1 * ? *")
1922
1923
1924 .description("Update Solr index \"" + name + "\" every hour"));
1925 try {
1926 final UUID uuid = taskManagerService.createTask(
1927 IndexTask.class,
1928 new TMJobDataMap(Map.of(
1929 Task.TYPE_KEY,
1930 TaskType.INDEX,
1931 Task.DESCRIPTION_KEY,
1932 index.getSchedule().getDescription(),
1933 IndexTask.INDEX_KEY,
1934 index.getId().toString(),
1935 Task.PRIORITY_KEY,
1936 10)),
1937 index.getSchedule().getCronExpression());
1938
1939 index.getSchedule().setUuid(uuid);
1940 searchIndexRepository.save(index);
1941
1942 logger.info("Created task to update Solr index with key: {}", uuid);
1943 } catch (SchedulerException e) {
1944 logger.error("Error creating scheduled solr index task", e);
1945 }
1946 }));
1947 }
1948
1949 private void createPages() throws IOException {
1950 Upload logo = new Upload()
1951 .setCategory(Upload.CATEGORY_PORTAL_IMAGE)
1952 .setFilename("gradient.svg")
1953 .setMimeType("image/svg+xml")
1954 .setContent(new ClassPathResource("test/gradient-logo.svg").getContentAsByteArray())
1955 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
1956 uploadRepository.save(logo);
1957
1958 Page about = new Page();
1959 about.setName("about");
1960 about.setType("page");
1961 about.setContent("About Tailormap");
1962 about.setContent("""
1963 # About Tailormap
1964
1965 This is a page about *Tailormap*. It doesn't say much yet.
1966 """);
1967 pageRepository.save(about);
1968
1969 Page page = new Page();
1970 page.setName("home");
1971 page.setType("page");
1972 page.setTitle("Tailormap - Home");
1973 page.setContent(
1974 """
1975 # Welcome to Tailormap!
1976
1977 This page is only visible when you implement a frontend to display pages, or get it (including a simple CMS)
1978 from [B3Partners](https:
1979 """);
1980 page.setClassName(null);
1981 page.setTiles(List.of(
1982 new PageTile()
1983 .id(UUID.randomUUID().toString())
1984 .title("Default app")
1985 .applicationId(Optional.ofNullable(applicationRepository.findByName("default"))
1986 .map(Application::getId)
1987 .orElse(null))
1988 .image(logo.getId().toString())
1989 .content("*Default app* tile content")
1990 .filterRequireAuthorization(false)
1991 .openInNewWindow(false),
1992 new PageTile()
1993 .id(UUID.randomUUID().toString())
1994 .title("Secured app")
1995 .applicationId(Optional.ofNullable(applicationRepository.findByName("secured"))
1996 .map(Application::getId)
1997 .orElse(null))
1998 .filterRequireAuthorization(true)
1999 .content("Secure app, only shown if user has authorization")
2000 .openInNewWindow(false),
2001 new PageTile()
2002 .id(UUID.randomUUID().toString())
2003 .title("Secured app (unfiltered)")
2004 .applicationId(Optional.ofNullable(applicationRepository.findByName("secured"))
2005 .map(Application::getId)
2006 .orElse(null))
2007 .filterRequireAuthorization(false)
2008 .content("Secure app, tile shown to everyone")
2009 .openInNewWindow(false),
2010 new PageTile()
2011 .id(UUID.randomUUID().toString())
2012 .title("About")
2013 .pageId(about.getId())
2014 .openInNewWindow(false),
2015 new PageTile()
2016 .id(UUID.randomUUID().toString())
2017 .title("B3Partners")
2018 .url("https://www.b3partners.nl/")
2019 .openInNewWindow(true)));
2020 pageRepository.save(page);
2021
2022 Configuration c = new Configuration();
2023 c.setKey(HOME_PAGE);
2024 c.setValue(page.getId().toString());
2025 configurationRepository.save(c);
2026
2027 List<MenuItem> globalMenuItems = List.of(
2028 new MenuItem().pageId(about.getId()).label("About").openInNewWindow(false),
2029 new MenuItem()
2030 .label("B3Partners website")
2031 .url("https://www.b3partners.nl/")
2032 .openInNewWindow(true)
2033 .exclusiveOnPageId(about.getId()));
2034 c = new Configuration();
2035 c.setKey(PORTAL_MENU);
2036 c.setJsonValue(new ObjectMapper().valueToTree(globalMenuItems));
2037 configurationRepository.save(c);
2038 }
2039
2040 private void insertTestDrawing() {
2041
2042 try {
2043 this.jdbcClient
2044 .sql(
2045 """
2046 INSERT INTO data.drawing (id,name,description,domain_data,"access",created_by,created_at,updated_by,updated_at,srid,"version") VALUES
2047 ('38faa008-013e-49d4-9528-8f58c94d8791'::uuid,'Testcase','A private access drawing that is inserted as part of the testdata','{"items": 1, "domain": "test drawings"}','private','tm-admin','2025-02-27 17:53:36.095164+01','tm-admin','2025-02-27 17:54:19.384961+01',28992,1);
2048 """)
2049 .update();
2050
2051 this.jdbcClient
2052 .sql(
2053 """
2054 INSERT INTO data.drawing_feature (drawing_id,id,geometry,properties) VALUES
2055 ('38faa008-013e-49d4-9528-8f58c94d8791'::uuid, '394e0d4a-b374-4d00-94c8-1758ea70e9d9'::uuid, 'SRID=28992;POLYGON ((131982.01 458929.27, 131957.31 458755.45, 132072.39 458736.69, 132099.06 458910.51, 131982.01 458929.27))'::public.geometry, '{"type": "POLYGON", "style": {"label": "", "marker": "circle", "fillColor": "rgb(117, 117, 117)", "labelSize": 15, "labelColor": "rgb(0, 0, 0)", "markerSize": 5, "fillOpacity": 30, "strokeColor": "rgb(98, 54, 255)", "strokeWidth": 3, "strokeOpacity": 100, "markerRotation": 0, "markerFillColor": "rgb(98, 54, 255)", "labelOutlineColor": "rgb(189, 189, 189)", "markerStrokeColor": "rgb(98, 54, 255)", "markerStrokeWidth": 1}}'::jsonb),
2056 ('38faa008-013e-49d4-9528-8f58c94d8791'::uuid, '89fc320c-41a3-4635-8d98-39d822339692'::uuid, 'SRID=28992;POINT (131897.55 458971.24)'::public.geometry, '{"type": "CIRCLE", "style": {"label": "CIRCLE", "marker": "circle", "fillColor": "rgb(117, 117, 117)", "labelSize": 15, "labelColor": "rgb(0, 0, 0)", "markerSize": 5, "fillOpacity": 30, "strokeColor": "rgb(98, 54, 255)", "strokeWidth": 3, "strokeOpacity": 100, "markerRotation": 0, "markerFillColor": "rgb(98, 54, 255)", "labelOutlineColor": "rgb(189, 189, 189)", "markerStrokeColor": "rgb(98, 54, 255)", "markerStrokeWidth": 1}, "radius": 14.989999999990687}'::jsonb),
2057 ('38faa008-013e-49d4-9528-8f58c94d8791'::uuid, '5d6252cc-25b6-4a43-9053-0779b86895a7'::uuid, 'SRID=28992;LINESTRING (131920.76 458754.96, 131923.73 458783.1, 131930.15 458793.97, 131945.95 458912.98, 131967.68 458946.06)'::public.geometry, '{"type": "LINE", "style": {"label": "", "marker": "circle", "fillColor": "rgb(255, 82, 82)", "labelSize": 15, "labelColor": "rgb(0, 0, 0)", "markerSize": 5, "fillOpacity": 30, "strokeColor": "rgb(255, 82, 82)", "strokeWidth": 13, "strokeOpacity": 100, "markerRotation": 0, "markerFillColor": "rgb(98, 54, 255)", "labelOutlineColor": "rgb(189, 189, 189)", "markerStrokeColor": "rgb(98, 54, 255)", "markerStrokeWidth": 1}}'::jsonb)
2058 """)
2059 .update();
2060 } catch (Exception any) {
2061 logger.error("Error inserting test drawing in data schema, some tests may fail", any);
2062 }
2063 }
2064
2065 private void insertDrawingStyle() throws IOException {
2066 Upload upload = new Upload()
2067 .setCategory(Upload.CATEGORY_DRAWING_STYLE_IMAGE)
2068 .setMimeType("image/svg+xml")
2069 .setFilename("ISO_7001_PI_PF_007.svg")
2070 .setContent(new ClassPathResource("test/ISO_7001_PI_PF_007.svg").getContentAsByteArray())
2071 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
2072 upload = uploadRepository.save(upload);
2073 UUID drinkwaterImageId = upload.getId();
2074
2075 upload = new Upload()
2076 .setCategory(Upload.CATEGORY_DRAWING_STYLE_IMAGE)
2077 .setMimeType("image/svg+xml")
2078 .setFilename("lichtpunt.svg")
2079 .setContent(new ClassPathResource("test/lichtpunt.svg").getContentAsByteArray())
2080 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
2081 upload = uploadRepository.save(upload);
2082 UUID lichtpuntImageId = upload.getId();
2083
2084 upload = new Upload()
2085 .setCategory(Upload.CATEGORY_DRAWING_STYLE_IMAGE)
2086 .setMimeType("image/svg+xml")
2087 .setFilename("ISO_7010_E003_-_First_aid_sign.svg")
2088 .setContent(new ClassPathResource("test/ISO_7010_E003_-_First_aid_sign.svg").getContentAsByteArray())
2089 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
2090 upload = uploadRepository.save(upload);
2091 UUID firstAidImageId = upload.getId();
2092
2093 Properties props = new Properties();
2094 props.putAll(Map.of(
2095 "water-uuid", drinkwaterImageId.toString(),
2096 "lichtpunt-uuid", lichtpuntImageId.toString(),
2097 "first-aid-uuid", firstAidImageId.toString()));
2098
2099 String drawingStyles =
2100 new ClassPathResource("test/object-drawing-style.json").getContentAsString(StandardCharsets.UTF_8);
2101 drawingStyles = new PropertyPlaceholderHelper("${", "}").replacePlaceholders(drawingStyles, props);
2102
2103
2104 upload = new Upload()
2105 .setCategory(Upload.CATEGORY_DRAWING_STYLE)
2106 .setMimeType("application/json")
2107 .setFilename("object-drawing-style.json")
2108 .setContent(drawingStyles.getBytes(StandardCharsets.UTF_8))
2109 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
2110 uploadRepository.save(upload);
2111 }
2112 }