View Javadoc
1   /*
2    * Copyright (C) 2022 B3Partners B.V.
3    *
4    * SPDX-License-Identifier: MIT
5    */
6   package org.tailormap.api.controller;
7   
8   import static org.tailormap.api.persistence.helper.TMAttributeTypeHelper.isGeometry;
9   import static org.tailormap.api.persistence.helper.TMFeatureTypeHelper.getConfiguredAttributes;
10  
11  import io.micrometer.core.annotation.Timed;
12  import java.io.Serializable;
13  import java.util.Set;
14  import org.springframework.http.HttpStatus;
15  import org.springframework.http.MediaType;
16  import org.springframework.http.ResponseEntity;
17  import org.springframework.transaction.annotation.Transactional;
18  import org.springframework.validation.annotation.Validated;
19  import org.springframework.web.bind.annotation.GetMapping;
20  import org.springframework.web.bind.annotation.ModelAttribute;
21  import org.springframework.web.bind.annotation.RequestMapping;
22  import org.springframework.web.server.ResponseStatusException;
23  import org.tailormap.api.annotation.AppRestController;
24  import org.tailormap.api.persistence.Application;
25  import org.tailormap.api.persistence.Form;
26  import org.tailormap.api.persistence.GeoService;
27  import org.tailormap.api.persistence.TMFeatureType;
28  import org.tailormap.api.persistence.helper.TMFeatureTypeHelper;
29  import org.tailormap.api.persistence.json.AppLayerSettings;
30  import org.tailormap.api.persistence.json.AppTreeLayerNode;
31  import org.tailormap.api.persistence.json.GeoServiceLayer;
32  import org.tailormap.api.persistence.json.TMAttributeDescriptor;
33  import org.tailormap.api.persistence.json.TMAttributeType;
34  import org.tailormap.api.persistence.json.TMGeometryType;
35  import org.tailormap.api.repository.FeatureSourceRepository;
36  import org.tailormap.api.repository.FormRepository;
37  import org.tailormap.api.viewer.model.Attribute;
38  import org.tailormap.api.viewer.model.LayerDetails;
39  import org.tailormap.api.viewer.model.LayerDetailsForm;
40  
41  @AppRestController
42  @Validated
43  @RequestMapping(
44      path = "${tailormap-api.base-path}/{viewerKind}/{viewerName}/layer/{appLayerId}/describe",
45      produces = MediaType.APPLICATION_JSON_VALUE)
46  public class LayerDescriptionController {
47  
48    private final FeatureSourceRepository featureSourceRepository;
49    private final TMFeatureTypeHelper featureTypeHelper;
50    private final FormRepository formRepository;
51  
52    public LayerDescriptionController(
53        FeatureSourceRepository featureSourceRepository,
54        TMFeatureTypeHelper featureTypeHelper,
55        FormRepository formRepository) {
56      this.featureSourceRepository = featureSourceRepository;
57      this.featureTypeHelper = featureTypeHelper;
58      this.formRepository = formRepository;
59    }
60  
61    @Transactional
62    @GetMapping
63    @Timed(value = "get_layer_description", description = "Get layer description")
64    public ResponseEntity<Serializable> getAppLayerDescription(
65        @ModelAttribute Application application,
66        @ModelAttribute AppTreeLayerNode appTreeLayerNode,
67        @ModelAttribute GeoService service,
68        @ModelAttribute GeoServiceLayer layer) {
69  
70      if (layer == null) {
71        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Can't find layer " + appTreeLayerNode);
72      }
73  
74      TMFeatureType tmft = service.findFeatureTypeForLayer(layer, featureSourceRepository);
75      if (tmft == null) {
76        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Layer does not have feature type");
77      }
78  
79      LayerDetails r = new LayerDetails()
80          .id(appTreeLayerNode.getId())
81          .serviceId(appTreeLayerNode.getServiceId())
82          .featureTypeName(tmft.getName())
83          .geometryAttribute(tmft.getDefaultGeometryAttribute())
84          // TODO deduce from tmft.getDefaultGeometryAttribute()
85          .geometryAttributeIndex(null /* TODO */)
86          .geometryType(tmft.getDefaultGeometryDescriptor()
87              .map(TMAttributeDescriptor::getType)
88              .map(TMAttributeType::getValue)
89              .map(TMGeometryType::fromValue)
90              .orElse(null))
91          .editable(TMFeatureTypeHelper.isEditable(application, appTreeLayerNode, tmft))
92          .attachmentAttributes(featureTypeHelper.getAttachmentAttributesWithMaxFileUploadSize(tmft).stream()
93              .toList());
94  
95      AppLayerSettings appLayerSettings = application.getAppLayerSettings(appTreeLayerNode);
96  
97      Form form;
98      if (appLayerSettings.getFormId() != null) {
99        form = formRepository.findById(appLayerSettings.getFormId()).orElse(null);
100       if (form != null) {
101         r.setForm(new LayerDetailsForm().options(form.getOptions()).fields(form.getFields()));
102       }
103     }
104 
105     Set<String> editableAttributes = TMFeatureTypeHelper.getEditableAttributes(tmft, appLayerSettings);
106 
107     getConfiguredAttributes(tmft, appLayerSettings).values().stream()
108         .map(attributeWithSettings -> {
109           TMAttributeDescriptor a = attributeWithSettings.attributeDescriptor();
110           return new Attribute()
111               .name(a.getName())
112               .alias(attributeWithSettings.settings().getTitle())
113               // Only return generic 'geometry' type for now, frontend doesn't
114               // handle different geometry types. For the default geometry
115               // attribute there is a specific geometry type set
116               .type(isGeometry(a.getType()) ? TMAttributeType.GEOMETRY : a.getType())
117               // primary key can never be edited
118               .editable(!a.getName().equals(tmft.getPrimaryKeyAttribute())
119                   && editableAttributes.contains(a.getName()))
120               .defaultValue(a.getDefaultValue())
121               .nullable(a.getNullable());
122         })
123         .forEach(r::addAttributesItem);
124 
125     return ResponseEntity.ok(r);
126   }
127 }