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.WMS;
11 import static org.tailormap.api.persistence.json.GeoServiceProtocol.WMTS;
12 import static org.tailormap.api.persistence.json.GeoServiceProtocol.XYZ;
13 import static org.tailormap.api.security.AuthorizationService.ACCESS_TYPE_READ;
14
15 import com.fasterxml.jackson.core.JsonProcessingException;
16 import com.fasterxml.jackson.databind.ObjectMapper;
17 import java.io.IOException;
18 import java.lang.invoke.MethodHandles;
19 import java.time.OffsetDateTime;
20 import java.time.ZoneId;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.NoSuchElementException;
26 import java.util.Optional;
27 import java.util.Set;
28 import java.util.UUID;
29 import org.apache.solr.client.solrj.SolrServerException;
30 import org.quartz.SchedulerException;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.springframework.beans.factory.annotation.Value;
34 import org.springframework.boot.SpringApplication;
35 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
36 import org.springframework.boot.context.event.ApplicationReadyEvent;
37 import org.springframework.context.ApplicationContext;
38 import org.springframework.context.event.EventListener;
39 import org.springframework.core.io.ClassPathResource;
40 import org.springframework.transaction.annotation.Transactional;
41 import org.tailormap.api.admin.model.TaskSchedule;
42 import org.tailormap.api.geotools.featuresources.FeatureSourceFactoryHelper;
43 import org.tailormap.api.geotools.featuresources.JDBCFeatureSourceHelper;
44 import org.tailormap.api.geotools.featuresources.WFSFeatureSourceHelper;
45 import org.tailormap.api.persistence.Application;
46 import org.tailormap.api.persistence.Catalog;
47 import org.tailormap.api.persistence.Configuration;
48 import org.tailormap.api.persistence.GeoService;
49 import org.tailormap.api.persistence.Group;
50 import org.tailormap.api.persistence.Page;
51 import org.tailormap.api.persistence.SearchIndex;
52 import org.tailormap.api.persistence.TMFeatureSource;
53 import org.tailormap.api.persistence.TMFeatureType;
54 import org.tailormap.api.persistence.Upload;
55 import org.tailormap.api.persistence.User;
56 import org.tailormap.api.persistence.helper.GeoServiceHelper;
57 import org.tailormap.api.persistence.json.AppContent;
58 import org.tailormap.api.persistence.json.AppLayerSettings;
59 import org.tailormap.api.persistence.json.AppSettings;
60 import org.tailormap.api.persistence.json.AppTreeLayerNode;
61 import org.tailormap.api.persistence.json.AppTreeLevelNode;
62 import org.tailormap.api.persistence.json.AppTreeNode;
63 import org.tailormap.api.persistence.json.AttributeSettings;
64 import org.tailormap.api.persistence.json.AuthorizationRule;
65 import org.tailormap.api.persistence.json.AuthorizationRuleDecision;
66 import org.tailormap.api.persistence.json.Bounds;
67 import org.tailormap.api.persistence.json.CatalogNode;
68 import org.tailormap.api.persistence.json.FeatureTypeRef;
69 import org.tailormap.api.persistence.json.FeatureTypeTemplate;
70 import org.tailormap.api.persistence.json.GeoServiceDefaultLayerSettings;
71 import org.tailormap.api.persistence.json.GeoServiceLayerSettings;
72 import org.tailormap.api.persistence.json.GeoServiceSettings;
73 import org.tailormap.api.persistence.json.JDBCConnectionProperties;
74 import org.tailormap.api.persistence.json.MenuItem;
75 import org.tailormap.api.persistence.json.PageTile;
76 import org.tailormap.api.persistence.json.ServiceAuthentication;
77 import org.tailormap.api.persistence.json.TailormapObjectRef;
78 import org.tailormap.api.persistence.json.TileLayerHiDpiMode;
79 import org.tailormap.api.repository.ApplicationRepository;
80 import org.tailormap.api.repository.CatalogRepository;
81 import org.tailormap.api.repository.ConfigurationRepository;
82 import org.tailormap.api.repository.FeatureSourceRepository;
83 import org.tailormap.api.repository.GeoServiceRepository;
84 import org.tailormap.api.repository.GroupRepository;
85 import org.tailormap.api.repository.PageRepository;
86 import org.tailormap.api.repository.SearchIndexRepository;
87 import org.tailormap.api.repository.UploadRepository;
88 import org.tailormap.api.repository.UserRepository;
89 import org.tailormap.api.scheduling.FailingPocTask;
90 import org.tailormap.api.scheduling.IndexTask;
91 import org.tailormap.api.scheduling.InterruptablePocTask;
92 import org.tailormap.api.scheduling.PocTask;
93 import org.tailormap.api.scheduling.TMJobDataMap;
94 import org.tailormap.api.scheduling.Task;
95 import org.tailormap.api.scheduling.TaskManagerService;
96 import org.tailormap.api.scheduling.TaskType;
97 import org.tailormap.api.security.InternalAdminAuthentication;
98 import org.tailormap.api.solr.SolrHelper;
99 import org.tailormap.api.solr.SolrService;
100 import org.tailormap.api.viewer.model.AppStyling;
101 import org.tailormap.api.viewer.model.Component;
102 import org.tailormap.api.viewer.model.ComponentConfig;
103
104
105
106
107
108 @org.springframework.context.annotation.Configuration
109 @ConditionalOnProperty(name = "tailormap-api.database.populate-testdata", havingValue = "true")
110 public class PopulateTestData {
111
112 private static final Logger logger =
113 LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
114 private final ApplicationContext appContext;
115 private final UserRepository userRepository;
116 private final GroupRepository groupRepository;
117 private final CatalogRepository catalogRepository;
118 private final GeoServiceRepository geoServiceRepository;
119 private final GeoServiceHelper geoServiceHelper;
120 private final SolrService solrService;
121 private final TaskManagerService taskManagerService;
122 private final FeatureSourceRepository featureSourceRepository;
123 private final ApplicationRepository applicationRepository;
124 private final ConfigurationRepository configurationRepository;
125 private final SearchIndexRepository searchIndexRepository;
126 private final FeatureSourceFactoryHelper featureSourceFactoryHelper;
127 private final UploadRepository uploadRepository;
128 private final PageRepository pageRepository;
129
130 @Value("${spatial.dbs.connect:false}")
131 private boolean connectToSpatialDbs;
132
133 @Value("#{'${tailormap-api.database.populate-testdata.categories}'.split(',')}")
134 private Set<String> categories;
135
136 @Value("${spatial.dbs.localhost:true}")
137 private boolean connectToSpatialDbsAtLocalhost;
138
139 @Value("${tailormap-api.database.populate-testdata.admin-hashed-password}")
140 private String adminHashedPassword;
141
142 @Value("${tailormap-api.database.populate-testdata.exit:false}")
143 private boolean exit;
144
145 @Value("${MAP5_URL:#{null}}")
146 private String map5url;
147
148 @Value("${tailormap-api.solr-batch-size:1000}")
149 private int solrBatchSize;
150
151 @Value("${tailormap-api.solr-geometry-validation-rule:repairBuffer0}")
152 private String solrGeometryValidationRule;
153
154 public PopulateTestData(
155 ApplicationContext appContext,
156 UserRepository userRepository,
157 GroupRepository groupRepository,
158 CatalogRepository catalogRepository,
159 GeoServiceRepository geoServiceRepository,
160 GeoServiceHelper geoServiceHelper,
161 SolrService solrService,
162 TaskManagerService taskManagerService,
163 FeatureSourceRepository featureSourceRepository,
164 ApplicationRepository applicationRepository,
165 ConfigurationRepository configurationRepository,
166 FeatureSourceFactoryHelper featureSourceFactoryHelper,
167 SearchIndexRepository searchIndexRepository,
168 UploadRepository uploadRepository,
169 PageRepository pageRepository) {
170 this.appContext = appContext;
171 this.userRepository = userRepository;
172 this.groupRepository = groupRepository;
173 this.catalogRepository = catalogRepository;
174 this.geoServiceRepository = geoServiceRepository;
175 this.geoServiceHelper = geoServiceHelper;
176 this.solrService = solrService;
177 this.taskManagerService = taskManagerService;
178 this.featureSourceRepository = featureSourceRepository;
179 this.applicationRepository = applicationRepository;
180 this.configurationRepository = configurationRepository;
181 this.featureSourceFactoryHelper = featureSourceFactoryHelper;
182 this.searchIndexRepository = searchIndexRepository;
183 this.uploadRepository = uploadRepository;
184 this.pageRepository = pageRepository;
185 }
186
187 @EventListener(ApplicationReadyEvent.class)
188 @Transactional
189 public void populate() throws Exception {
190 InternalAdminAuthentication.setInSecurityContext();
191 try {
192
193
194 createTestUsersAndGroups();
195 createConfigurationTestData();
196 if (categories.contains("catalog")) {
197 createCatalogTestData();
198 }
199 if (categories.contains("apps")) {
200 createAppTestData();
201 }
202 if (categories.contains("search-index")) {
203 try {
204 createSolrIndex();
205 } catch (Exception e) {
206 logger.error("Exception creating Solr Index for testdata (continuing)", e);
207 }
208 }
209 if (categories.contains("tasks")) {
210 createScheduledTasks();
211 }
212 if (categories.contains("pages")) {
213 createPages();
214 }
215 logger.info("Test entities created");
216 } finally {
217 InternalAdminAuthentication.clearSecurityContextAuthentication();
218 }
219 if (exit) {
220
221
222 new Thread(() -> {
223 try {
224 logger.info("Exiting in 10 seconds");
225 Thread.sleep(10000);
226 } catch (InterruptedException ignored) {
227
228 }
229 SpringApplication.exit(appContext, () -> 0);
230 System.exit(0);
231 })
232 .start();
233 }
234 }
235
236 public void createTestUsersAndGroups() throws NoSuchElementException {
237 Group groupFoo = new Group().setName("test-foo").setDescription("Used for integration tests.");
238 groupRepository.save(groupFoo);
239
240 Group groupBar = new Group().setName("test-bar").setDescription("Used for integration tests.");
241 groupBar.addOrUpdateAdminProperty("group-property", true, true);
242 groupBar.addOrUpdateAdminProperty("group-private-property", 999.9, false);
243 groupRepository.save(groupBar);
244
245 Group groupBaz = new Group().setName("test-baz").setDescription("Used for integration tests.");
246 groupRepository.save(groupBaz);
247
248
249 User u = new User().setUsername("user").setPassword("{noop}user").setEmail("user@example.com");
250 u.getGroups().addAll(List.of(groupFoo, groupBar, groupBaz));
251 userRepository.save(u);
252
253
254 u = new User().setUsername("tm-admin").setPassword(adminHashedPassword);
255 u.addOrUpdateAdminProperty("some-property", "some-value", true);
256 u.addOrUpdateAdminProperty("admin-property", "private-value", false);
257 u.getGroups().add(groupRepository.findById(Group.ADMIN).orElseThrow());
258 u.getGroups().add(groupBar);
259 userRepository.save(u);
260 }
261
262 private final List<AuthorizationRule> ruleAnonymousRead = List.of(new AuthorizationRule()
263 .groupName(Group.ANONYMOUS)
264 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW)));
265
266 private final List<AuthorizationRule> ruleLoggedIn = List.of(new AuthorizationRule()
267 .groupName(Group.AUTHENTICATED)
268 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW)));
269
270 @SuppressWarnings("PMD.AvoidUsingHardCodedIP")
271 private void createCatalogTestData() throws Exception {
272 Catalog catalog = catalogRepository.findById(Catalog.MAIN).orElseThrow();
273 CatalogNode rootCatalogNode = catalog.getNodes().get(0);
274 CatalogNode catalogNode = new CatalogNode().id("test").title("Test services");
275 rootCatalogNode.addChildrenItem(catalogNode.getId());
276 catalog.getNodes().add(catalogNode);
277
278 String osmAttribution = "© [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors";
279
280 Bounds rdTileGridExtent =
281 new Bounds().minx(-285401.92).maxx(595401.92).miny(22598.08).maxy(903401.92);
282
283 Upload legend = new Upload()
284 .setCategory(Upload.CATEGORY_LEGEND)
285 .setFilename("gemeentegebied-legend.png")
286 .setMimeType("image/png")
287 .setContent(new ClassPathResource("test/gemeentegebied-legend.png").getContentAsByteArray())
288 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
289 uploadRepository.save(legend);
290
291 Collection<GeoService> services = List.of(
292 new GeoService()
293 .setId("demo")
294 .setProtocol(WMS)
295 .setTitle("Demo")
296 .setPublished(true)
297 .setAuthorizationRules(ruleAnonymousRead)
298 .setUrl("https://demo.tailormap.com/geoserver/geodata/ows?SERVICE=WMS"),
299 new GeoService()
300 .setId("osm")
301 .setProtocol(XYZ)
302 .setTitle("OSM")
303 .setUrl("https://tile.openstreetmap.org/{z}/{x}/{y}.png")
304 .setAuthorizationRules(ruleAnonymousRead)
305 .setSettings(new GeoServiceSettings()
306 .xyzCrs("EPSG:3857")
307 .layerSettings(Map.of(
308 "xyz",
309 new GeoServiceLayerSettings()
310 .attribution(osmAttribution)
311 .maxZoom(19)))),
312
313 new GeoService()
314 .setId("snapshot-geoserver")
315 .setProtocol(WMS)
316 .setTitle("Test GeoServer")
317 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
318 .setAuthorizationRules(ruleAnonymousRead)
319 .setPublished(true),
320 new GeoService()
321 .setId("filtered-snapshot-geoserver")
322 .setProtocol(WMS)
323 .setTitle("Test GeoServer (with authorization rules)")
324 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
325 .setAuthorizationRules(List.of(
326 new AuthorizationRule()
327 .groupName("test-foo")
328 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW)),
329 new AuthorizationRule()
330 .groupName("test-baz")
331 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW))))
332 .setSettings(new GeoServiceSettings()
333 .layerSettings(Map.of(
334 "BGT",
335 new GeoServiceLayerSettings()
336 .addAuthorizationRulesItem(new AuthorizationRule()
337 .groupName("test-foo")
338 .decisions(Map.of(
339 ACCESS_TYPE_READ, AuthorizationRuleDecision.DENY)))
340 .addAuthorizationRulesItem(new AuthorizationRule()
341 .groupName("test-baz")
342 .decisions(Map.of(
343 ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW))))))
344 .setPublished(true),
345 new GeoService()
346 .setId("snapshot-geoserver-proxied")
347 .setProtocol(WMS)
348 .setTitle("Test GeoServer (proxied)")
349 .setUrl("https://snapshot.tailormap.nl/geoserver/wms")
350 .setAuthorizationRules(ruleAnonymousRead)
351 .setSettings(new GeoServiceSettings().useProxy(true)),
352 new GeoService()
353 .setId("openbasiskaart")
354 .setProtocol(WMTS)
355 .setTitle("Openbasiskaart")
356 .setUrl("https://www.openbasiskaart.nl/mapcache/wmts")
357 .setAuthorizationRules(ruleAnonymousRead)
358 .setSettings(new GeoServiceSettings()
359 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
360 .layerSettings(Map.of(
361 "osm",
362 new GeoServiceLayerSettings()
363 .title("Openbasiskaart")
364 .hiDpiDisabled(false)
365 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
366 .hiDpiSubstituteLayer("osm-hq")))),
367 new GeoService()
368 .setId("openbasiskaart-proxied")
369 .setProtocol(WMTS)
370 .setTitle("Openbasiskaart (proxied)")
371 .setUrl("https://www.openbasiskaart.nl/mapcache/wmts")
372 .setAuthorizationRules(ruleAnonymousRead)
373
374
375 .setAuthentication(new ServiceAuthentication()
376 .method(ServiceAuthentication.MethodEnum.PASSWORD)
377 .username("test")
378 .password("test"))
379 .setSettings(new GeoServiceSettings()
380 .useProxy(true)
381 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
382 .layerSettings(Map.of(
383 "osm",
384 new GeoServiceLayerSettings()
385 .hiDpiDisabled(false)
386 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
387 .hiDpiSubstituteLayer("osm-hq")))),
388 new GeoService()
389 .setId("openbasiskaart-tms")
390 .setProtocol(XYZ)
391 .setTitle("Openbasiskaart (TMS)")
392 .setUrl("https://openbasiskaart.nl/mapcache/tms/1.0.0/osm@rd/{z}/{x}/{-y}.png")
393 .setAuthorizationRules(ruleAnonymousRead)
394 .setSettings(
395 new GeoServiceSettings()
396 .xyzCrs("EPSG:28992")
397 .defaultLayerSettings(
398 new GeoServiceDefaultLayerSettings().attribution(osmAttribution))
399 .layerSettings(
400 Map.of(
401 "xyz",
402 new GeoServiceLayerSettings()
403 .maxZoom(15)
404 .tileGridExtent(rdTileGridExtent)
405 .hiDpiDisabled(false)
406 .hiDpiMode(
407 TileLayerHiDpiMode
408 .SUBSTITUTELAYERTILEPIXELRATIOONLY)
409 .hiDpiSubstituteLayer(
410 "https://openbasiskaart.nl/mapcache/tms/1.0.0/osm-hq@rd-hq/{z}/{x}/{-y}.png")))),
411 new GeoService()
412 .setId("pdok-hwh-luchtfotorgb")
413 .setProtocol(WMTS)
414 .setTitle("PDOK HWH luchtfoto")
415 .setUrl("https://service.pdok.nl/hwh/luchtfotorgb/wmts/v1_0")
416 .setAuthorizationRules(ruleAnonymousRead)
417 .setPublished(true)
418 .setSettings(new GeoServiceSettings()
419 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
420 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl)")
421 .hiDpiDisabled(false))
422 .putLayerSettingsItem(
423 "Actueel_orthoHR", new GeoServiceLayerSettings().title("Luchtfoto"))),
424 new GeoService()
425 .setId("b3p-mapproxy-luchtfoto")
426 .setProtocol(XYZ)
427 .setTitle("Luchtfoto (TMS)")
428 .setUrl("https://mapproxy.b3p.nl/tms/1.0.0/luchtfoto/EPSG28992/{z}/{x}/{-y}.jpeg")
429 .setAuthorizationRules(ruleAnonymousRead)
430 .setPublished(true)
431 .setSettings(new GeoServiceSettings()
432 .xyzCrs("EPSG:28992")
433 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
434 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl)")
435 .hiDpiDisabled(false))
436 .layerSettings(Map.of(
437 "xyz",
438 new GeoServiceLayerSettings()
439 .maxZoom(14)
440 .tileGridExtent(rdTileGridExtent)
441 .hiDpiMode(TileLayerHiDpiMode.SHOWNEXTZOOMLEVEL)))),
442 new GeoService()
443 .setId("at-basemap")
444 .setProtocol(WMTS)
445 .setTitle("basemap.at")
446 .setUrl("https://mapsneu.wien.gv.at/basemapneu/1.0.0/WMTSCapabilities.xml")
447 .setAuthorizationRules(ruleAnonymousRead)
448 .setPublished(true)
449 .setSettings(new GeoServiceSettings()
450 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
451 .attribution("© [basemap.at](https://basemap.at)")
452 .hiDpiDisabled(true))
453 .layerSettings(Map.of(
454 "geolandbasemap",
455 new GeoServiceLayerSettings()
456 .title("Basemap")
457 .hiDpiDisabled(false)
458 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERTILEPIXELRATIOONLY)
459 .hiDpiSubstituteLayer("bmaphidpi"),
460 "bmaporthofoto30cm",
461 new GeoServiceLayerSettings()
462 .title("Orthophoto")
463 .hiDpiDisabled(false)))),
464 new GeoService()
465 .setId("pdok-kadaster-bestuurlijkegebieden")
466 .setProtocol(WMS)
467 .setUrl("https://service.pdok.nl/kadaster/bestuurlijkegebieden/wms/v1_0?service=WMS")
468 .setAuthorizationRules(ruleAnonymousRead)
469 .setSettings(new GeoServiceSettings()
470 .defaultLayerSettings(new GeoServiceDefaultLayerSettings()
471 .description("This layer shows an administrative boundary."))
472
473 .serverType(GeoServiceSettings.ServerTypeEnum.MAPSERVER)
474 .useProxy(true)
475 .putLayerSettingsItem(
476 "Gemeentegebied",
477 new GeoServiceLayerSettings()
478 .legendImageId(legend.getId().toString())))
479 .setPublished(true)
480 .setTitle("PDOK Kadaster bestuurlijke gebieden"),
481 new GeoService()
482 .setId("bestuurlijkegebieden-proxied")
483 .setProtocol(WMS)
484 .setUrl("https://service.pdok.nl/kadaster/bestuurlijkegebieden/wms/v1_0?service=WMS")
485 .setAuthorizationRules(ruleAnonymousRead)
486
487
488
489 .setAuthentication(new ServiceAuthentication()
490 .method(ServiceAuthentication.MethodEnum.PASSWORD)
491 .username("test")
492 .password("test"))
493 .setSettings(new GeoServiceSettings()
494
495 .serverType(GeoServiceSettings.ServerTypeEnum.MAPSERVER)
496 .useProxy(true))
497 .setPublished(true)
498 .setTitle("Bestuurlijke gebieden (proxied met auth)")
499
500 );
501
502 if (map5url != null) {
503 GeoServiceLayerSettings osmAttr = new GeoServiceLayerSettings().attribution(osmAttribution);
504 GeoServiceLayerSettings map5Attr = new GeoServiceLayerSettings()
505 .attribution("Kaarten: [Map5.nl](https://map5.nl), data: " + osmAttribution);
506 services = new ArrayList<>(services);
507 services.add(new GeoService()
508 .setId("map5")
509 .setProtocol(WMTS)
510 .setTitle("Map5")
511 .setUrl(map5url)
512 .setAuthorizationRules(ruleAnonymousRead)
513 .setSettings(new GeoServiceSettings()
514 .defaultLayerSettings(new GeoServiceDefaultLayerSettings().hiDpiDisabled(true))
515 .layerSettings(Map.of(
516 "openlufo",
517 new GeoServiceLayerSettings()
518 .attribution("© [Beeldmateriaal.nl](https://beeldmateriaal.nl), "
519 + osmAttribution),
520 "luforoadslabels",
521 osmAttr,
522 "map5topo",
523 new GeoServiceLayerSettings()
524 .attribution(map5Attr.getAttribution())
525 .hiDpiDisabled(false)
526 .hiDpiMode(TileLayerHiDpiMode.SUBSTITUTELAYERSHOWNEXTZOOMLEVEL)
527 .hiDpiSubstituteLayer("map5topo_hq"),
528 "map5topo_gray",
529 map5Attr,
530 "map5topo_simple",
531 map5Attr,
532 "map5topo_simple_gray",
533 map5Attr,
534 "opensimpletopo",
535 osmAttr,
536 "opensimpletopo_gray",
537 osmAttr,
538 "opentopo",
539 osmAttr,
540 "opentopo_gray",
541 osmAttr))));
542 }
543
544 for (GeoService geoService : services) {
545 geoServiceHelper.loadServiceCapabilities(geoService);
546
547 geoServiceRepository.save(geoService);
548 catalogNode.addItemsItem(new TailormapObjectRef()
549 .kind(TailormapObjectRef.KindEnum.GEO_SERVICE)
550 .id(geoService.getId()));
551 }
552
553 CatalogNode wfsFeatureSourceCatalogNode =
554 new CatalogNode().id("wfs_feature_sources").title("WFS feature sources");
555 rootCatalogNode.addChildrenItem(wfsFeatureSourceCatalogNode.getId());
556 catalog.getNodes().add(wfsFeatureSourceCatalogNode);
557
558 services.stream().filter(s -> s.getProtocol() == WMS).forEach(s -> {
559 geoServiceHelper.findAndSaveRelatedWFS(s);
560 List<TMFeatureSource> linkedSources = featureSourceRepository.findByLinkedServiceId(s.getId());
561 for (TMFeatureSource linkedSource : linkedSources) {
562 wfsFeatureSourceCatalogNode.addItemsItem(new TailormapObjectRef()
563 .kind(TailormapObjectRef.KindEnum.FEATURE_SOURCE)
564 .id(linkedSource.getId().toString()));
565 }
566 });
567
568 String geodataPassword = "980f1c8A-25933b2";
569
570 Map<String, TMFeatureSource> featureSources = Map.of(
571 "postgis",
572 new TMFeatureSource()
573 .setProtocol(TMFeatureSource.Protocol.JDBC)
574 .setTitle("PostGIS")
575 .setJdbcConnection(new JDBCConnectionProperties()
576 .dbtype(JDBCConnectionProperties.DbtypeEnum.POSTGIS)
577 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "postgis")
578 .port(connectToSpatialDbsAtLocalhost ? 54322 : 5432)
579 .database("geodata")
580 .schema("public")
581 .additionalProperties(Map.of("connectionOptions", "?ApplicationName=tailormap-api")))
582 .setAuthentication(new ServiceAuthentication()
583 .method(ServiceAuthentication.MethodEnum.PASSWORD)
584 .username("geodata")
585 .password(geodataPassword)),
586 "postgis_osm",
587 new TMFeatureSource()
588 .setProtocol(TMFeatureSource.Protocol.JDBC)
589 .setTitle("PostGIS OSM")
590 .setJdbcConnection(new JDBCConnectionProperties()
591 .dbtype(JDBCConnectionProperties.DbtypeEnum.POSTGIS)
592 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "postgis")
593 .port(connectToSpatialDbsAtLocalhost ? 54322 : 5432)
594 .database("geodata")
595 .schema("osm")
596 .additionalProperties(Map.of("connectionOptions", "?ApplicationName=tailormap-api")))
597 .setAuthentication(new ServiceAuthentication()
598 .method(ServiceAuthentication.MethodEnum.PASSWORD)
599 .username("geodata")
600 .password(geodataPassword)),
601 "oracle",
602 new TMFeatureSource()
603 .setProtocol(TMFeatureSource.Protocol.JDBC)
604 .setTitle("Oracle")
605 .setJdbcConnection(new JDBCConnectionProperties()
606 .dbtype(JDBCConnectionProperties.DbtypeEnum.ORACLE)
607 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "oracle")
608 .database("/FREEPDB1")
609 .schema("GEODATA")
610 .additionalProperties(Map.of("connectionOptions", "?oracle.jdbc.J2EE13Compliant=true")))
611 .setAuthentication(new ServiceAuthentication()
612 .method(ServiceAuthentication.MethodEnum.PASSWORD)
613 .username("geodata")
614 .password(geodataPassword)),
615 "sqlserver",
616 new TMFeatureSource()
617 .setProtocol(TMFeatureSource.Protocol.JDBC)
618 .setTitle("MS SQL Server")
619 .setJdbcConnection(new JDBCConnectionProperties()
620 .dbtype(JDBCConnectionProperties.DbtypeEnum.SQLSERVER)
621 .host(connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "sqlserver")
622 .database("geodata")
623 .schema("dbo")
624 .additionalProperties(Map.of("connectionOptions", ";encrypt=false")))
625 .setAuthentication(new ServiceAuthentication()
626 .method(ServiceAuthentication.MethodEnum.PASSWORD)
627 .username("geodata")
628 .password(geodataPassword)),
629 "pdok-kadaster-bestuurlijkegebieden",
630 new TMFeatureSource()
631 .setProtocol(TMFeatureSource.Protocol.WFS)
632 .setUrl(
633 "https://service.pdok.nl/kadaster/bestuurlijkegebieden/wfs/v1_0?service=WFS&VERSION=2.0.0")
634 .setTitle("Bestuurlijke gebieden")
635 .setNotes(
636 "Overzicht van de bestuurlijke indeling van Nederland in gemeenten en provincies alsmede de rijksgrens. Gegevens zijn afgeleid uit de Basisregistratie Kadaster (BRK)."));
637 featureSourceRepository.saveAll(featureSources.values());
638
639 new WFSFeatureSourceHelper().loadCapabilities(featureSources.get("pdok-kadaster-bestuurlijkegebieden"));
640 geoServiceRepository.findById("pdok-kadaster-bestuurlijkegebieden").ifPresent(geoService -> {
641 geoService
642 .getSettings()
643 .getLayerSettings()
644 .put(
645 "Provinciegebied",
646 new GeoServiceLayerSettings()
647 .description("The administrative boundary of Dutch Provinces, connected to a WFS.")
648 .featureType(new FeatureTypeRef()
649 .featureSourceId(featureSources
650 .get("pdok-kadaster-bestuurlijkegebieden")
651 .getId())
652 .featureTypeName("bestuurlijkegebieden:Provinciegebied"))
653 .title("Provinciegebied (WFS)"));
654 geoServiceRepository.save(geoService);
655 });
656
657 geoServiceRepository.findById("bestuurlijkegebieden-proxied").ifPresent(geoService -> {
658 geoService
659 .getSettings()
660 .getLayerSettings()
661 .put(
662 "Provinciegebied",
663 new GeoServiceLayerSettings()
664 .featureType(new FeatureTypeRef()
665 .featureSourceId(featureSources
666 .get("pdok-kadaster-bestuurlijkegebieden")
667 .getId())
668 .featureTypeName("bestuurlijkegebieden:Provinciegebied"))
669 .title("Provinciegebied (WFS, proxied met auth)"));
670 geoServiceRepository.save(geoService);
671 });
672
673 CatalogNode featureSourceCatalogNode =
674 new CatalogNode().id("feature_sources").title("Test feature sources");
675 rootCatalogNode.addChildrenItem(featureSourceCatalogNode.getId());
676 catalog.getNodes().add(featureSourceCatalogNode);
677
678 for (TMFeatureSource featureSource : featureSources.values()) {
679 featureSourceCatalogNode.addItemsItem(new TailormapObjectRef()
680 .kind(TailormapObjectRef.KindEnum.FEATURE_SOURCE)
681 .id(featureSource.getId().toString()));
682 }
683 catalogRepository.save(catalog);
684
685 if (connectToSpatialDbs) {
686 featureSources.values().forEach(fs -> {
687 try {
688 if (fs.getProtocol() == TMFeatureSource.Protocol.JDBC) {
689 new JDBCFeatureSourceHelper().loadCapabilities(fs);
690 } else if (fs.getProtocol() == TMFeatureSource.Protocol.WFS) {
691 new WFSFeatureSourceHelper().loadCapabilities(fs);
692 }
693 } catch (Exception e) {
694 logger.error("Error loading capabilities for feature source {}", fs.getTitle(), e);
695 }
696 });
697
698 services.stream()
699
700
701 .filter(s -> s.getId().startsWith("snapshot-geoserver"))
702 .forEach(s -> s.getSettings()
703 .layerSettings(Map.of(
704 "postgis:begroeidterreindeel",
705 new GeoServiceLayerSettings()
706 .description(
707 """
708 This layer shows data from https:
709
710 https:
711 .featureType(new FeatureTypeRef()
712 .featureSourceId(featureSources
713 .get("postgis")
714 .getId())
715 .featureTypeName("begroeidterreindeel")),
716 "postgis:bak",
717 new GeoServiceLayerSettings()
718 .featureType(new FeatureTypeRef()
719 .featureSourceId(featureSources
720 .get("postgis")
721 .getId())
722 .featureTypeName("bak")),
723 "postgis:kadastraal_perceel",
724 new GeoServiceLayerSettings()
725 .description("cadastral parcel label points")
726 .featureType(new FeatureTypeRef()
727 .featureSourceId(featureSources
728 .get("postgis")
729 .getId())
730 .featureTypeName("kadastraal_perceel")),
731 "sqlserver:wegdeel",
732 new GeoServiceLayerSettings()
733 .attribution(
734 "CC BY 4.0 [BGT/Kadaster](https://www.nationaalgeoregister.nl/geonetwork/srv/api/records/2cb4769c-b56e-48fa-8685-c48f61b9a319)")
735 .description(
736 """
737 This layer shows data from [MS SQL Server](https:
738
739 https:
740 .featureType(new FeatureTypeRef()
741 .featureSourceId(featureSources
742 .get("sqlserver")
743 .getId())
744 .featureTypeName("wegdeel")),
745 "oracle:WATERDEEL",
746 new GeoServiceLayerSettings()
747 .description("This layer shows data from Oracle Spatial.")
748 .featureType(new FeatureTypeRef()
749 .featureSourceId(featureSources
750 .get("oracle")
751 .getId())
752 .featureTypeName("WATERDEEL")),
753 "postgis:osm_polygon",
754 new GeoServiceLayerSettings()
755 .description("This layer shows OSM data from postgis.")
756 .featureType(new FeatureTypeRef()
757 .featureSourceId(featureSources
758 .get("postgis_osm")
759 .getId())
760 .featureTypeName("osm_polygon")))));
761 }
762
763 featureSources.get("pdok-kadaster-bestuurlijkegebieden").getFeatureTypes().stream()
764 .filter(ft -> ft.getName().equals("bestuurlijkegebieden:Provinciegebied"))
765 .findFirst()
766 .ifPresent(ft -> {
767 ft.getSettings().addHideAttributesItem("identificatie");
768 ft.getSettings().addHideAttributesItem("ligtInLandCode");
769 ft.getSettings().addHideAttributesItem("fuuid");
770 ft.getSettings().putAttributeSettingsItem("naam", new AttributeSettings().title("Naam"));
771 ft.getSettings()
772 .setTemplate(
773 new FeatureTypeTemplate()
774 .templateLanguage("simple")
775 .markupLanguage("markdown")
776 .template(
777 """
778 ### Provincie
779 Deze provincie heet **{{naam}}** en ligt in _{{ligtInLandNaam}}_.
780
781 | Attribuut | Waarde |
782 | --------- | ------------------ |
783 | `code` | {{code}} |
784 | `naam` | {{naam}} |
785 | `ligt in` | {{ligtInLandNaam}} |"""));
786 });
787
788 featureSources.get("postgis").getFeatureTypes().stream()
789 .filter(ft -> ft.getName().equals("begroeidterreindeel"))
790 .findFirst()
791 .ifPresent(ft -> {
792 ft.getSettings().addHideAttributesItem("terminationdate");
793 ft.getSettings().addHideAttributesItem("geom_kruinlijn");
794 ft.getSettings().putAttributeSettingsItem("gmlid", new AttributeSettings().title("GML ID"));
795 ft.getSettings()
796 .putAttributeSettingsItem("identificatie", new AttributeSettings().title("Identificatie"));
797 ft.getSettings()
798 .putAttributeSettingsItem(
799 "tijdstipregistratie", new AttributeSettings().title("Registratie"));
800 ft.getSettings()
801 .putAttributeSettingsItem(
802 "eindregistratie", new AttributeSettings().title("Eind registratie"));
803 ft.getSettings().putAttributeSettingsItem("class", new AttributeSettings().title("Klasse"));
804 ft.getSettings()
805 .putAttributeSettingsItem("bronhouder", new AttributeSettings().title("Bronhouder"));
806 ft.getSettings()
807 .putAttributeSettingsItem("inonderzoek", new AttributeSettings().title("In onderzoek"));
808 ft.getSettings()
809 .putAttributeSettingsItem(
810 "relatievehoogteligging", new AttributeSettings().title("Relatieve hoogteligging"));
811 ft.getSettings()
812 .putAttributeSettingsItem("bgt_status", new AttributeSettings().title("BGT status"));
813 ft.getSettings()
814 .putAttributeSettingsItem("plus_status", new AttributeSettings().title("Plus-status"));
815 ft.getSettings()
816 .putAttributeSettingsItem(
817 "plus_fysiekvoorkomen", new AttributeSettings().title("Plus-fysiek voorkomen"));
818 ft.getSettings()
819 .putAttributeSettingsItem(
820 "begroeidterreindeeloptalud", new AttributeSettings().title("Op talud"));
821 ft.getSettings().addAttributeOrderItem("identificatie");
822 ft.getSettings().addAttributeOrderItem("bronhouder");
823 ft.getSettings().addAttributeOrderItem("class");
824 });
825
826 featureSources.get("postgis").getFeatureTypes().stream()
827 .filter(ft -> ft.getName().equals("bak"))
828 .findFirst()
829 .ifPresent(ft -> {
830 ft.getSettings().addHideAttributesItem("gmlid");
831 ft.getSettings().addHideAttributesItem("lv_publicatiedatum");
832 ft.getSettings().addHideAttributesItem("creationdate");
833 ft.getSettings().addHideAttributesItem("tijdstipregistratie");
834 ft.getSettings().addHideAttributesItem("eindregistratie");
835 ft.getSettings().addHideAttributesItem("terminationdate");
836 ft.getSettings().addHideAttributesItem("inonderzoek");
837 ft.getSettings().addHideAttributesItem("relatievehoogteligging");
838 ft.getSettings().addHideAttributesItem("bgt_status");
839 ft.getSettings().addHideAttributesItem("plus_status");
840 ft.getSettings().addHideAttributesItem("function_");
841 ft.getSettings().addHideAttributesItem("plus_type");
842 });
843
844 featureSources.get("postgis").getFeatureTypes().stream()
845 .filter(ft -> ft.getName().equals("kadastraal_perceel"))
846 .findFirst()
847 .ifPresent(ft -> {
848 ft.getSettings().addHideAttributesItem("gml_id");
849 });
850 }
851
852 public void createAppTestData() throws Exception {
853 Upload logo = new Upload()
854 .setCategory(Upload.CATEGORY_APP_LOGO)
855 .setFilename("gradient.svg")
856 .setMimeType("image/svg+xml")
857 .setContent(new ClassPathResource("test/gradient-logo.svg").getContentAsByteArray())
858 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
859 uploadRepository.save(logo);
860
861 List<AppTreeNode> baseNodes = List.of(
862 new AppTreeLayerNode()
863 .objectType("AppTreeLayerNode")
864 .id("lyr:openbasiskaart:osm")
865 .serviceId("openbasiskaart")
866 .layerName("osm")
867 .visible(true),
868 new AppTreeLayerNode()
869 .objectType("AppTreeLayerNode")
870 .id("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR")
871 .serviceId("pdok-hwh-luchtfotorgb")
872 .layerName("Actueel_orthoHR")
873 .visible(false));
874
875 Application app = new Application()
876 .setName("default")
877 .setTitle("Tailormap demo")
878 .setCrs("EPSG:28992")
879 .setAuthorizationRules(ruleAnonymousRead)
880 .setComponents(List.of(
881 new Component()
882 .type("SIMPLE_SEARCH")
883 .config(new ComponentConfig()
884 .enabled(true)
885 .putAdditionalProperty("municipalities", List.of("0344"))),
886 new Component().type("EDIT").config(new ComponentConfig().enabled(true)),
887 new Component()
888 .type("COORDINATE_LINK_WINDOW")
889 .config(new ComponentConfig()
890 .enabled(true)
891 .putAdditionalProperty(
892 "urls",
893 List.of(
894 Map.of(
895 "id",
896 "google-maps",
897 "url",
898 "https://www.google.com/maps/@[lat],[lon],18z",
899 "alias",
900 "Google Maps",
901 "projection",
902 "EPSG:4326"),
903 Map.of(
904 "id",
905 "tm-demo",
906 "url",
907 "https://demo.tailormap.com/#@[X],[Y],18",
908 "alias",
909 "Tailormap demo",
910 "projection",
911 "EPSG:28992"))))))
912 .setContentRoot(new AppContent()
913 .addBaseLayerNodesItem(new AppTreeLevelNode()
914 .objectType("AppTreeLevelNode")
915 .id("root-base-layers")
916 .root(true)
917 .title("Base layers")
918 .childrenIds(List.of(
919 "lyr:openbasiskaart:osm",
920 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR",
921 "lyr:openbasiskaart-proxied:osm",
922 "lyr:openbasiskaart-tms:xyz",
923 "lyr:b3p-mapproxy-luchtfoto:xyz")))
924 .addBaseLayerNodesItem(
925
926
927 new AppTreeLayerNode()
928 .objectType("AppTreeLayerNode")
929 .id("lyr:openbasiskaart-proxied:osm")
930 .serviceId("openbasiskaart-proxied")
931 .layerName("osm")
932 .visible(false))
933 .addBaseLayerNodesItem(new AppTreeLayerNode()
934 .objectType("AppTreeLayerNode")
935 .id("lyr:openbasiskaart-tms:xyz")
936 .serviceId("openbasiskaart-tms")
937 .layerName("xyz")
938 .visible(false))
939 .addBaseLayerNodesItem(new AppTreeLayerNode()
940 .objectType("AppTreeLayerNode")
941 .id("lyr:b3p-mapproxy-luchtfoto:xyz")
942 .serviceId("b3p-mapproxy-luchtfoto")
943 .layerName("xyz")
944 .visible(false))
945 .addLayerNodesItem(new AppTreeLevelNode()
946 .objectType("AppTreeLevelNode")
947 .id("root")
948 .root(true)
949 .title("Layers")
950 .childrenIds(List.of(
951 "lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied",
952 "lyr:bestuurlijkegebieden-proxied:Provinciegebied",
953 "lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied",
954 "lyr:snapshot-geoserver:postgis:begroeidterreindeel",
955 "lyr:snapshot-geoserver:postgis:bak",
956 "lyr:snapshot-geoserver:postgis:kadastraal_perceel",
957 "lyr:snapshot-geoserver:sqlserver:wegdeel",
958 "lyr:snapshot-geoserver:oracle:WATERDEEL",
959 "lyr:snapshot-geoserver:BGT",
960 "lvl:proxied",
961 "lvl:osm",
962 "lvl:archeo")))
963 .addLayerNodesItem(new AppTreeLayerNode()
964 .objectType("AppTreeLayerNode")
965 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied")
966 .serviceId("pdok-kadaster-bestuurlijkegebieden")
967 .layerName("Provinciegebied")
968 .visible(true))
969
970
971
972 .addLayerNodesItem(new AppTreeLayerNode()
973 .objectType("AppTreeLayerNode")
974 .id("lyr:bestuurlijkegebieden-proxied:Provinciegebied")
975 .serviceId("bestuurlijkegebieden-proxied")
976 .layerName("Provinciegebied")
977 .visible(false))
978 .addLayerNodesItem(new AppTreeLayerNode()
979 .objectType("AppTreeLayerNode")
980 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied")
981 .serviceId("pdok-kadaster-bestuurlijkegebieden")
982 .layerName("Gemeentegebied")
983 .visible(true))
984 .addLayerNodesItem(new AppTreeLayerNode()
985 .objectType("AppTreeLayerNode")
986 .id("lyr:snapshot-geoserver:postgis:begroeidterreindeel")
987 .serviceId("snapshot-geoserver")
988 .layerName("postgis:begroeidterreindeel")
989 .visible(true))
990 .addLayerNodesItem(new AppTreeLayerNode()
991 .objectType("AppTreeLayerNode")
992 .id("lyr:snapshot-geoserver:postgis:bak")
993 .serviceId("snapshot-geoserver")
994 .layerName("postgis:bak")
995 .visible(false))
996 .addLayerNodesItem(new AppTreeLayerNode()
997 .objectType("AppTreeLayerNode")
998 .id("lyr:snapshot-geoserver:postgis:kadastraal_perceel")
999 .serviceId("snapshot-geoserver")
1000 .layerName("postgis:kadastraal_perceel")
1001 .visible(false))
1002 .addLayerNodesItem(new AppTreeLayerNode()
1003 .objectType("AppTreeLayerNode")
1004 .id("lyr:snapshot-geoserver:sqlserver:wegdeel")
1005 .serviceId("snapshot-geoserver")
1006 .layerName("sqlserver:wegdeel")
1007 .visible(true))
1008 .addLayerNodesItem(new AppTreeLayerNode()
1009 .objectType("AppTreeLayerNode")
1010 .id("lyr:snapshot-geoserver:oracle:WATERDEEL")
1011 .serviceId("snapshot-geoserver")
1012 .layerName("oracle:WATERDEEL")
1013 .visible(true))
1014 .addLayerNodesItem(new AppTreeLayerNode()
1015 .objectType("AppTreeLayerNode")
1016 .id("lyr:snapshot-geoserver:BGT")
1017 .serviceId("snapshot-geoserver")
1018 .layerName("BGT")
1019 .visible(false))
1020 .addLayerNodesItem(new AppTreeLevelNode()
1021 .objectType("AppTreeLevelNode")
1022 .id("lvl:proxied")
1023 .title("Proxied")
1024 .childrenIds(List.of("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")))
1025 .addLayerNodesItem(new AppTreeLayerNode()
1026 .objectType("AppTreeLayerNode")
1027 .id("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")
1028 .serviceId("snapshot-geoserver-proxied")
1029 .layerName("postgis:begroeidterreindeel")
1030 .visible(false))
1031 .addLayerNodesItem(new AppTreeLevelNode()
1032 .objectType("AppTreeLevelNode")
1033 .id("lvl:osm")
1034 .title("OSM")
1035 .childrenIds(List.of("lyr:snapshot-geoserver:postgis:osm_polygon")))
1036 .addLayerNodesItem(new AppTreeLayerNode()
1037 .objectType("AppTreeLayerNode")
1038 .id("lyr:snapshot-geoserver:postgis:osm_polygon")
1039 .serviceId("snapshot-geoserver")
1040 .layerName("postgis:osm_polygon")
1041 .visible(false))
1042 .addLayerNodesItem(new AppTreeLevelNode()
1043 .objectType("AppTreeLevelNode")
1044 .id("lvl:archeo")
1045 .title("Archeology")
1046 .childrenIds(List.of("lyr:demo:geomorfologie")))
1047 .addLayerNodesItem(new AppTreeLayerNode()
1048 .objectType("AppTreeLayerNode")
1049 .id("lyr:demo:geomorfologie")
1050 .serviceId("demo")
1051 .layerName("geomorfologie")
1052 .visible(true)))
1053 .setStyling(new AppStyling().logo(logo.getId().toString()))
1054 .setSettings(new AppSettings()
1055 .putLayerSettingsItem("lyr:openbasiskaart:osm", new AppLayerSettings().title("Openbasiskaart"))
1056 .putLayerSettingsItem(
1057 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR", new AppLayerSettings().title("Luchtfoto"))
1058 .putLayerSettingsItem(
1059 "lyr:openbasiskaart-proxied:osm",
1060 new AppLayerSettings().title("Openbasiskaart (proxied)"))
1061 .putLayerSettingsItem(
1062 "lyr:snapshot-geoserver:oracle:WATERDEEL",
1063 new AppLayerSettings()
1064 .opacity(50)
1065 .title("Waterdeel overridden title")
1066 .editable(true)
1067 .description("This is the layer description from the app layer setting.")
1068 .attribution(
1069 "CC BY 4.0 [BGT/Kadaster](https://www.nationaalgeoregister.nl/geonetwork/srv/api/records/2cb4769c-b56e-48fa-8685-c48f61b9a319)"))
1070 .putLayerSettingsItem(
1071 "lyr:snapshot-geoserver:postgis:osm_polygon",
1072 new AppLayerSettings()
1073 .description("OpenStreetMap polygon data in EPSG:3857")
1074 .opacity(60)
1075 .editable(true)
1076 .title("OSM Polygon (EPSG:3857)")
1077 .attribution(
1078 "© [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors"))
1079 .putLayerSettingsItem(
1080 "lyr:snapshot-geoserver:postgis:begroeidterreindeel",
1081 new AppLayerSettings()
1082 .editable(true)
1083 .addHideAttributesItem("begroeidterreindeeloptalud")
1084 .addReadOnlyAttributesItem("eindregistratie"))
1085 .putLayerSettingsItem(
1086 "lyr:snapshot-geoserver:postgis:kadastraal_perceel",
1087 new AppLayerSettings().editable(true).addReadOnlyAttributesItem("aanduiding"))
1088 .putLayerSettingsItem(
1089 "lyr:snapshot-geoserver:sqlserver:wegdeel", new AppLayerSettings().editable(true))
1090 .putLayerSettingsItem(
1091 "lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel",
1092 new AppLayerSettings().editable(false)));
1093
1094 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1095 app.setInitialExtent(
1096 new Bounds().minx(130011d).miny(458031d).maxx(132703d).maxy(459995d));
1097 app.setMaxExtent(new Bounds().minx(-285401d).miny(22598d).maxx(595401d).maxy(903401d));
1098
1099 if (map5url != null) {
1100 AppTreeLevelNode root =
1101 (AppTreeLevelNode) app.getContentRoot().getBaseLayerNodes().get(0);
1102 List<String> childrenIds = new ArrayList<>(root.getChildrenIds());
1103 childrenIds.add("lyr:map5:map5topo");
1104 childrenIds.add("lyr:map5:map5topo_simple");
1105 childrenIds.add("lvl:luchtfoto-labels");
1106 root.setChildrenIds(childrenIds);
1107 app.getSettings()
1108 .putLayerSettingsItem("lyr:map5:map5topo", new AppLayerSettings().title("Map5"))
1109 .putLayerSettingsItem("lyr:map5:map5topo_simple", new AppLayerSettings().title("Map5 simple"));
1110 app.getContentRoot()
1111 .addBaseLayerNodesItem(new AppTreeLayerNode()
1112 .objectType("AppTreeLayerNode")
1113 .id("lyr:map5:map5topo")
1114 .serviceId("map5")
1115 .layerName("map5topo")
1116 .visible(false))
1117 .addBaseLayerNodesItem(new AppTreeLayerNode()
1118 .objectType("AppTreeLayerNode")
1119 .id("lyr:map5:map5topo_simple")
1120 .serviceId("map5")
1121 .layerName("map5topo_simple")
1122 .visible(false))
1123 .addBaseLayerNodesItem(new AppTreeLevelNode()
1124 .objectType("AppTreeLevelNode")
1125 .id("lvl:luchtfoto-labels")
1126 .title("Luchtfoto met labels")
1127 .addChildrenIdsItem("lyr:map5:luforoadslabels")
1128 .addChildrenIdsItem("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR2"))
1129 .addBaseLayerNodesItem(new AppTreeLayerNode()
1130 .objectType("AppTreeLayerNode")
1131 .id("lyr:map5:luforoadslabels")
1132 .serviceId("map5")
1133 .layerName("luforoadslabels")
1134 .visible(false))
1135 .addBaseLayerNodesItem(new AppTreeLayerNode()
1136 .objectType("AppTreeLayerNode")
1137 .id("lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR2")
1138 .serviceId("pdok-hwh-luchtfotorgb")
1139 .layerName("Actueel_orthoHR")
1140 .visible(false));
1141 }
1142
1143 applicationRepository.save(app);
1144
1145 app = new Application()
1146 .setName("base")
1147 .setTitle("Service base app")
1148 .setCrs("EPSG:28992")
1149 .setAuthorizationRules(ruleAnonymousRead)
1150 .setContentRoot(new AppContent()
1151 .addBaseLayerNodesItem(new AppTreeLevelNode()
1152 .objectType("AppTreeLevelNode")
1153 .id("root-base-layers")
1154 .root(true)
1155 .title("Base layers")
1156 .childrenIds(List.of(
1157 "lyr:openbasiskaart:osm", "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR"))));
1158 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1159 applicationRepository.save(app);
1160
1161 app = new Application()
1162 .setName("secured")
1163 .setTitle("secured app")
1164 .setCrs("EPSG:28992")
1165 .setAuthorizationRules(ruleLoggedIn)
1166 .setContentRoot(new AppContent()
1167 .addBaseLayerNodesItem(new AppTreeLevelNode()
1168 .objectType("AppTreeLevelNode")
1169 .id("root-base-layers")
1170 .root(true)
1171 .title("Base layers")
1172 .childrenIds(List.of(
1173 "lyr:openbasiskaart:osm",
1174 "lyr:pdok-hwh-luchtfotorgb:Actueel_orthoHR",
1175 "lyr:openbasiskaart-proxied:osm")))
1176 .addBaseLayerNodesItem(new AppTreeLayerNode()
1177 .objectType("AppTreeLayerNode")
1178 .id("lyr:openbasiskaart-proxied:osm")
1179 .serviceId("openbasiskaart-proxied")
1180 .layerName("osm")
1181 .visible(false))
1182 .addLayerNodesItem(new AppTreeLevelNode()
1183 .objectType("AppTreeLevelNode")
1184 .id("root")
1185 .root(true)
1186 .title("Layers")
1187 .childrenIds(List.of(
1188 "lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied",
1189 "lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied",
1190 "lvl:proxied")))
1191 .addLayerNodesItem(new AppTreeLayerNode()
1192 .objectType("AppTreeLayerNode")
1193 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Gemeentegebied")
1194 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1195 .layerName("Gemeentegebied")
1196 .visible(true))
1197 .addLayerNodesItem(new AppTreeLayerNode()
1198 .objectType("AppTreeLayerNode")
1199 .id("lyr:pdok-kadaster-bestuurlijkegebieden:Provinciegebied")
1200 .serviceId("pdok-kadaster-bestuurlijkegebieden")
1201 .layerName("Provinciegebied")
1202 .visible(false))
1203 .addLayerNodesItem(new AppTreeLevelNode()
1204 .objectType("AppTreeLevelNode")
1205 .id("lvl:proxied")
1206 .title("Proxied")
1207 .childrenIds(List.of("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")))
1208 .addLayerNodesItem(new AppTreeLayerNode()
1209 .objectType("AppTreeLayerNode")
1210 .id("lyr:snapshot-geoserver-proxied:postgis:begroeidterreindeel")
1211 .serviceId("snapshot-geoserver-proxied")
1212 .layerName("postgis:begroeidterreindeel")
1213 .visible(false)))
1214 .setSettings(new AppSettings()
1215 .putLayerSettingsItem(
1216 "lyr:openbasiskaart-proxied:osm",
1217 new AppLayerSettings().title("Openbasiskaart (proxied)")));
1218
1219 app.getContentRoot().getBaseLayerNodes().addAll(baseNodes);
1220 applicationRepository.save(app);
1221
1222 app = new Application()
1223 .setName("secured-auth")
1224 .setTitle("secured (with authorizations)")
1225 .setCrs("EPSG:28992")
1226 .setAuthorizationRules(List.of(
1227 new AuthorizationRule()
1228 .groupName("test-foo")
1229 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW)),
1230 new AuthorizationRule()
1231 .groupName("test-bar")
1232 .decisions(Map.of(ACCESS_TYPE_READ, AuthorizationRuleDecision.ALLOW))))
1233 .setContentRoot(new AppContent()
1234 .addLayerNodesItem(new AppTreeLevelNode()
1235 .objectType("AppTreeLevelNode")
1236 .id("root")
1237 .root(true)
1238 .title("Layers")
1239 .childrenIds(List.of("lyr:needs-auth", "lyr:public")))
1240 .addLayerNodesItem(new AppTreeLevelNode()
1241 .objectType("AppTreeLevelNode")
1242 .id("lvl:public")
1243 .title("Public")
1244 .childrenIds(List.of("lyr:snapshot-geoserver:BGT")))
1245 .addLayerNodesItem(new AppTreeLevelNode()
1246 .objectType("AppTreeLevelNode")
1247 .id("lvl:needs-auth")
1248 .title("Needs auth")
1249 .childrenIds(List.of(
1250 "lyr:filtered-snapshot-geoserver:BGT",
1251 "lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")))
1252 .addLayerNodesItem(new AppTreeLayerNode()
1253 .objectType("AppTreeLayerNode")
1254 .id("lyr:filtered-snapshot-geoserver:BGT")
1255 .serviceId("filtered-snapshot-geoserver")
1256 .layerName("BGT")
1257 .visible(true))
1258 .addLayerNodesItem(new AppTreeLayerNode()
1259 .objectType("AppTreeLayerNode")
1260 .id("lyr:filtered-snapshot-geoserver:postgis:begroeidterreindeel")
1261 .serviceId("filtered-snapshot-geoserver")
1262 .layerName("postgis:begroeidterreindeel")
1263 .visible(true))
1264 .addLayerNodesItem(new AppTreeLayerNode()
1265 .objectType("AppTreeLayerNode")
1266 .id("lyr:snapshot-geoserver:BGT")
1267 .serviceId("snapshot-geoserver")
1268 .layerName("BGT")
1269 .visible(true)));
1270
1271 applicationRepository.save(app);
1272
1273 app = new Application()
1274 .setName("austria")
1275 .setCrs("EPSG:3857")
1276 .setAuthorizationRules(ruleAnonymousRead)
1277 .setTitle("Austria")
1278 .setInitialExtent(
1279 new Bounds().minx(987982d).miny(5799551d).maxx(1963423d).maxy(6320708d))
1280 .setMaxExtent(
1281 new Bounds().minx(206516d).miny(5095461d).maxx(3146930d).maxy(7096232d))
1282 .setContentRoot(new AppContent()
1283 .addBaseLayerNodesItem(new AppTreeLevelNode()
1284 .objectType("AppTreeLevelNode")
1285 .id("root-base-layers")
1286 .root(true)
1287 .title("Base layers")
1288 .childrenIds(List.of(
1289 "lyr:at-basemap:geolandbasemap",
1290 "lyr:at-basemap:orthofoto",
1291 "lvl:orthofoto-labels",
1292 "lyr:osm:xyz")))
1293 .addBaseLayerNodesItem(new AppTreeLayerNode()
1294 .objectType("AppTreeLayerNode")
1295 .id("lyr:at-basemap:geolandbasemap")
1296 .serviceId("at-basemap")
1297 .layerName("geolandbasemap")
1298 .visible(true))
1299 .addBaseLayerNodesItem(new AppTreeLayerNode()
1300 .objectType("AppTreeLayerNode")
1301 .id("lyr:at-basemap:orthofoto")
1302 .serviceId("at-basemap")
1303 .layerName("bmaporthofoto30cm")
1304 .visible(false))
1305 .addBaseLayerNodesItem(new AppTreeLevelNode()
1306 .objectType("AppTreeLevelNode")
1307 .id("lvl:orthofoto-labels")
1308 .title("Orthophoto with labels")
1309 .childrenIds(List.of("lyr:at-basemap:bmapoverlay", "lyr:at-basemap:orthofoto_2")))
1310 .addBaseLayerNodesItem(new AppTreeLayerNode()
1311 .objectType("AppTreeLayerNode")
1312 .id("lyr:at-basemap:bmapoverlay")
1313 .serviceId("at-basemap")
1314 .layerName("bmapoverlay")
1315 .visible(false))
1316 .addBaseLayerNodesItem(new AppTreeLayerNode()
1317 .objectType("AppTreeLayerNode")
1318 .id("lyr:at-basemap:orthofoto_2")
1319 .serviceId("at-basemap")
1320 .layerName("bmaporthofoto30cm")
1321 .visible(false))
1322 .addBaseLayerNodesItem(new AppTreeLayerNode()
1323 .objectType("AppTreeLayerNode")
1324 .id("lyr:osm:xyz")
1325 .serviceId("osm")
1326 .layerName("xyz")
1327 .visible(false)));
1328
1329 applicationRepository.save(app);
1330
1331 Configuration config = new Configuration();
1332 config.setKey(Configuration.DEFAULT_APP);
1333 config.setValue("default");
1334 configurationRepository.save(config);
1335 config = new Configuration();
1336 config.setKey(Configuration.DEFAULT_BASE_APP);
1337 config.setValue("base");
1338 configurationRepository.save(config);
1339 }
1340
1341 private void createConfigurationTestData() throws JsonProcessingException {
1342 Configuration config = new Configuration();
1343 config.setKey("test");
1344 config.setAvailableForViewer(true);
1345 config.setValue("test value");
1346 config.setJsonValue(new ObjectMapper().readTree("{ \"someProperty\": 1, \"nestedObject\": { \"num\": 42 } }"));
1347 configurationRepository.save(config);
1348 }
1349
1350 @Transactional
1351 public void createSolrIndex() throws Exception {
1352 if (connectToSpatialDbs) {
1353
1354
1355 featureSourceRepository.flush();
1356
1357 logger.info("Creating Solr index");
1358 @SuppressWarnings("PMD.AvoidUsingHardCodedIP")
1359 final String solrUrl = "http://" + (connectToSpatialDbsAtLocalhost ? "127.0.0.1" : "solr") + ":8983/solr/";
1360 this.solrService.setSolrUrl(solrUrl);
1361 SolrHelper solrHelper = new SolrHelper(this.solrService.getSolrClientForIndexing())
1362 .withBatchSize(solrBatchSize)
1363 .withGeometryValidationRule(solrGeometryValidationRule);
1364 GeoService geoService =
1365 geoServiceRepository.findById("snapshot-geoserver").orElseThrow();
1366 Application defaultApp = applicationRepository.findByName("default");
1367
1368 TMFeatureType begroeidterreindeelFT = geoService.findFeatureTypeForLayer(
1369 geoService.findLayer("postgis:begroeidterreindeel"), featureSourceRepository);
1370
1371 TMFeatureType wegdeelFT = geoService.findFeatureTypeForLayer(
1372 geoService.findLayer("sqlserver:wegdeel"), featureSourceRepository);
1373
1374 TMFeatureType kadastraalPerceelFT = geoService.findFeatureTypeForLayer(
1375 geoService.findLayer("postgis:kadastraal_perceel"), featureSourceRepository);
1376
1377 try (solrHelper) {
1378 SearchIndex begroeidterreindeelIndex = null;
1379 if (begroeidterreindeelFT != null) {
1380 begroeidterreindeelIndex = new SearchIndex()
1381 .setName("Begroeidterreindeel")
1382 .setFeatureTypeId(begroeidterreindeelFT.getId())
1383 .setSearchFieldsUsed(List.of("class", "plus_fysiekvoorkomen", "bronhouder"))
1384 .setSearchDisplayFieldsUsed(List.of("class", "plus_fysiekvoorkomen"));
1385 begroeidterreindeelIndex = searchIndexRepository.save(begroeidterreindeelIndex);
1386 begroeidterreindeelIndex = solrHelper.addFeatureTypeIndex(
1387 begroeidterreindeelIndex,
1388 begroeidterreindeelFT,
1389 featureSourceFactoryHelper,
1390 searchIndexRepository);
1391 begroeidterreindeelIndex = searchIndexRepository.save(begroeidterreindeelIndex);
1392 }
1393
1394 SearchIndex kadastraalPerceelIndex = null;
1395 if (kadastraalPerceelFT != null) {
1396 kadastraalPerceelIndex = new SearchIndex()
1397 .setName("kadastraal_perceel")
1398 .setFeatureTypeId(kadastraalPerceelFT.getId())
1399 .setSearchFieldsUsed(List.of("aanduiding"))
1400 .setSearchDisplayFieldsUsed(List.of("aanduiding"));
1401 kadastraalPerceelIndex = searchIndexRepository.save(kadastraalPerceelIndex);
1402 kadastraalPerceelIndex = solrHelper.addFeatureTypeIndex(
1403 kadastraalPerceelIndex,
1404 kadastraalPerceelFT,
1405 featureSourceFactoryHelper,
1406 searchIndexRepository);
1407 kadastraalPerceelIndex = searchIndexRepository.save(kadastraalPerceelIndex);
1408 }
1409
1410 SearchIndex wegdeelIndex = null;
1411 if (wegdeelFT != null) {
1412 wegdeelIndex = new SearchIndex()
1413 .setName("Wegdeel")
1414 .setFeatureTypeId(wegdeelFT.getId())
1415 .setSearchFieldsUsed(List.of(
1416 "function_", "plus_fysiekvoorkomenwegdeel", "surfacematerial", "bronhouder"))
1417 .setSearchDisplayFieldsUsed(List.of("function_", "plus_fysiekvoorkomenwegdeel"));
1418 wegdeelIndex = searchIndexRepository.save(wegdeelIndex);
1419 wegdeelIndex = solrHelper.addFeatureTypeIndex(
1420 wegdeelIndex, wegdeelFT, featureSourceFactoryHelper, searchIndexRepository);
1421 wegdeelIndex = searchIndexRepository.save(wegdeelIndex);
1422
1423 featureSourceRepository
1424 .getByTitle("PostGIS")
1425 .flatMap(fs -> fs.getFeatureTypes().stream()
1426 .filter(ft -> ft.getName().equals("bak"))
1427 .findFirst())
1428 .ifPresent(ft -> {
1429 SearchIndex bak = new SearchIndex()
1430 .setName("bak")
1431 .setFeatureTypeId(ft.getId())
1432 .setSearchFieldsUsed(List.of("gmlid", "identificatie", "plus_type"))
1433 .setSearchDisplayFieldsUsed(List.of("gmlid", "plus_type", "bronhouder"));
1434 searchIndexRepository.save(bak);
1435 try {
1436 bak = solrHelper.addFeatureTypeIndex(
1437 bak, ft, featureSourceFactoryHelper, searchIndexRepository);
1438 searchIndexRepository.save(bak);
1439 } catch (IOException | SolrServerException e) {
1440 throw new RuntimeException(e);
1441 }
1442 });
1443 }
1444
1445 AppTreeLayerNode begroeidTerreindeelLayerNode = defaultApp
1446 .getAllAppTreeLayerNode()
1447 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:postgis:begroeidterreindeel"))
1448 .findFirst()
1449 .orElse(null);
1450
1451 if (begroeidTerreindeelLayerNode != null && begroeidterreindeelIndex != null) {
1452 defaultApp
1453 .getAppLayerSettings(begroeidTerreindeelLayerNode)
1454 .setSearchIndexId(begroeidterreindeelIndex.getId());
1455 }
1456
1457 AppTreeLayerNode kadastraalPerceelLayerNode = defaultApp
1458 .getAllAppTreeLayerNode()
1459 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:postgis:kadastraal_perceel"))
1460 .findFirst()
1461 .orElse(null);
1462
1463 if (kadastraalPerceelLayerNode != null && kadastraalPerceelIndex != null) {
1464 defaultApp
1465 .getAppLayerSettings(kadastraalPerceelLayerNode)
1466 .setSearchIndexId(kadastraalPerceelIndex.getId());
1467 }
1468
1469 AppTreeLayerNode wegdeel = defaultApp
1470 .getAllAppTreeLayerNode()
1471 .filter(node -> node.getId().equals("lyr:snapshot-geoserver:sqlserver:wegdeel"))
1472 .findFirst()
1473 .orElse(null);
1474
1475 if (wegdeel != null && wegdeelIndex != null) {
1476 defaultApp.getAppLayerSettings(wegdeel).setSearchIndexId(wegdeelIndex.getId());
1477 }
1478
1479 applicationRepository.save(defaultApp);
1480 }
1481 }
1482 }
1483
1484 private void createScheduledTasks() {
1485 try {
1486 logger.info("Creating POC tasks");
1487 logger.info(
1488 "Created 15 minutely task with key: {}",
1489 taskManagerService.createTask(
1490 PocTask.class,
1491 new TMJobDataMap(Map.of(
1492 Task.TYPE_KEY,
1493 TaskType.POC.getValue(),
1494 "foo",
1495 "foobar",
1496 Task.DESCRIPTION_KEY,
1497 "POC task that runs every 15 minutes")),
1498 "0 0/15 * 1/1 * ? *"));
1499 logger.info(
1500 "Created hourly task with key: {}",
1501 taskManagerService.createTask(
1502 PocTask.class,
1503 new TMJobDataMap(Map.of(
1504 Task.TYPE_KEY,
1505 TaskType.POC.getValue(),
1506 "foo",
1507 "bar",
1508 Task.DESCRIPTION_KEY,
1509 "POC task that runs every hour",
1510 Task.PRIORITY_KEY,
1511 10)),
1512 "0 0 0/1 1/1 * ? *"));
1513
1514 logger.info(
1515 "Created hourly failing task with key: {}",
1516 taskManagerService.createTask(
1517 FailingPocTask.class,
1518 new TMJobDataMap(Map.of(
1519 Task.TYPE_KEY,
1520 TaskType.FAILINGPOC.getValue(),
1521 Task.DESCRIPTION_KEY,
1522 "POC task that fails every hour with low priority",
1523 Task.PRIORITY_KEY,
1524 100)),
1525 "0 0 0/1 1/1 * ? *"));
1526 logger.info(
1527 "Created daily task with key: {}",
1528 taskManagerService.createTask(
1529 InterruptablePocTask.class,
1530 new TMJobDataMap(Map.of(
1531 Task.TYPE_KEY,
1532 TaskType.INTERRUPTABLEPOC.getValue(),
1533 Task.DESCRIPTION_KEY,
1534 "Interruptable POC task that runs every 15 minutes",
1535 Task.PRIORITY_KEY,
1536 5)),
1537 "0 0/15 * 1/1 * ? *"));
1538 } catch (SchedulerException e) {
1539 logger.error("Error creating scheduled one or more poc tasks", e);
1540 }
1541
1542 if (categories.contains("search-index")) {
1543 logger.info("Creating INDEX tasks");
1544 List.of("Begroeidterreindeel", "kadastraal_perceel")
1545 .forEach(name -> searchIndexRepository.findByName(name).ifPresent(index -> {
1546 index.setSchedule(new TaskSchedule()
1547
1548 .cronExpression("0 0 0/1 1/1 * ? *")
1549
1550
1551 .description("Update Solr index \" " + name + "\" every hour"));
1552 try {
1553 final UUID uuid = taskManagerService.createTask(
1554 IndexTask.class,
1555 new TMJobDataMap(Map.of(
1556 Task.TYPE_KEY,
1557 TaskType.INDEX,
1558 Task.DESCRIPTION_KEY,
1559 index.getSchedule().getDescription(),
1560 IndexTask.INDEX_KEY,
1561 index.getId().toString(),
1562 Task.PRIORITY_KEY,
1563 10)),
1564 index.getSchedule().getCronExpression());
1565
1566 index.getSchedule().setUuid(uuid);
1567 searchIndexRepository.save(index);
1568
1569 logger.info("Created task to update Solr index with key: {}", uuid);
1570 } catch (SchedulerException e) {
1571 logger.error("Error creating scheduled solr index task", e);
1572 }
1573 }));
1574 }
1575 }
1576
1577 private void createPages() throws IOException {
1578 Upload logo = new Upload()
1579 .setCategory(Upload.CATEGORY_PORTAL_IMAGE)
1580 .setFilename("gradient.svg")
1581 .setMimeType("image/svg+xml")
1582 .setContent(new ClassPathResource("test/gradient-logo.svg").getContentAsByteArray())
1583 .setLastModified(OffsetDateTime.now(ZoneId.systemDefault()));
1584 uploadRepository.save(logo);
1585
1586 Page about = new Page();
1587 about.setName("about");
1588 about.setType("page");
1589 about.setContent("About Tailormap");
1590 about.setContent("""
1591 # About Tailormap
1592
1593 This is a page about *Tailormap*. It doesn't say much yet.
1594 """);
1595 pageRepository.save(about);
1596
1597 Page page = new Page();
1598 page.setName("home");
1599 page.setType("page");
1600 page.setTitle("Tailormap - Home");
1601 page.setContent(
1602 """
1603 # Welcome to Tailormap!
1604
1605 This page is only visible when you implement a frontend to display pages, or get it (including a simple CMS)
1606 from [B3Partners](https:
1607 """);
1608 page.setClassName(null);
1609 page.setTiles(List.of(
1610 new PageTile()
1611 .id(UUID.randomUUID().toString())
1612 .title("Default app")
1613 .applicationId(Optional.ofNullable(applicationRepository.findByName("default"))
1614 .map(Application::getId)
1615 .orElse(null))
1616 .image(logo.getId().toString())
1617 .content("*Default app* tile content")
1618 .filterRequireAuthorization(false)
1619 .openInNewWindow(false),
1620 new PageTile()
1621 .id(UUID.randomUUID().toString())
1622 .title("Secured app")
1623 .applicationId(Optional.ofNullable(applicationRepository.findByName("secured"))
1624 .map(Application::getId)
1625 .orElse(null))
1626 .filterRequireAuthorization(true)
1627 .content("Secure app, only shown if user has authorization")
1628 .openInNewWindow(false),
1629 new PageTile()
1630 .id(UUID.randomUUID().toString())
1631 .title("Secured app (unfiltered)")
1632 .applicationId(Optional.ofNullable(applicationRepository.findByName("secured"))
1633 .map(Application::getId)
1634 .orElse(null))
1635 .filterRequireAuthorization(false)
1636 .content("Secure app, tile shown to everyone")
1637 .openInNewWindow(false),
1638 new PageTile()
1639 .id(UUID.randomUUID().toString())
1640 .title("About")
1641 .pageId(about.getId())
1642 .openInNewWindow(false),
1643 new PageTile()
1644 .id(UUID.randomUUID().toString())
1645 .title("B3Partners")
1646 .url("https://www.b3partners.nl/")
1647 .openInNewWindow(true)));
1648 pageRepository.save(page);
1649
1650 Configuration c = new Configuration();
1651 c.setKey(HOME_PAGE);
1652 c.setValue(page.getId().toString());
1653 configurationRepository.save(c);
1654
1655 List<MenuItem> globalMenuItems = List.of(
1656 new MenuItem().pageId(about.getId()).label("About").openInNewWindow(false),
1657 new MenuItem()
1658 .label("B3Partners website")
1659 .url("https://www.b3partners.nl/")
1660 .openInNewWindow(true)
1661 .exclusiveOnPageId(about.getId()));
1662 c = new Configuration();
1663 c.setKey(PORTAL_MENU);
1664 c.setJsonValue(new ObjectMapper().valueToTree(globalMenuItems));
1665 configurationRepository.save(c);
1666 }
1667 }