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