diff --git a/src/main/java/org/tailormap/api/controller/AttachmentsController.java b/src/main/java/org/tailormap/api/controller/AttachmentsController.java index e5cf9fc17..a3e3a616b 100644 --- a/src/main/java/org/tailormap/api/controller/AttachmentsController.java +++ b/src/main/java/org/tailormap/api/controller/AttachmentsController.java @@ -12,12 +12,14 @@ import java.nio.ByteBuffer; import java.sql.SQLException; import java.util.List; +import java.util.NoSuchElementException; import java.util.Set; import java.util.UUID; import org.geotools.api.data.Query; import org.geotools.api.data.SimpleFeatureSource; import org.geotools.api.filter.Filter; import org.geotools.api.filter.FilterFactory; +import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.factory.CommonFactoryFinder; import org.geotools.util.factory.GeoTools; import org.slf4j.Logger; @@ -31,7 +33,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.server.ResponseStatusException; import org.tailormap.api.annotation.AppRestController; @@ -74,7 +76,7 @@ public AttachmentsController(EditUtil editUtil, FeatureSourceFactoryHelper featu * @param fileData the attachment file data * @return the response entity */ - @PutMapping( + @PostMapping( path = { "${tailormap-api.base-path}/{viewerKind}/{viewerName}/layer/{appLayerId}/feature/{featureId}/attachments" }, @@ -94,7 +96,7 @@ public ResponseEntity addAttachment( TMFeatureType tmFeatureType = editUtil.getEditableFeatureType(application, appTreeLayerNode, service, layer); - checkFeatureExists(tmFeatureType, featureId); + Object primaryKey = getFeaturePrimaryKeyByFid(tmFeatureType, featureId); Set<@Valid AttachmentAttributeType> attachmentAttrSet = tmFeatureType.getSettings().getAttachmentAttributes(); @@ -104,9 +106,8 @@ public ResponseEntity addAttachment( AttachmentAttributeType attachmentAttributeType = attachmentAttrSet.stream() .filter(attr -> (attr.getAttributeName().equals(attachment.getAttributeName()) - && java.util.Arrays.stream(attr.getMimeType().split(",")) - .map(String::trim) - .anyMatch(mime -> mime.equals(attachment.getMimeType())) + // TODO check attr.getMimeType() as "accept" attribute for HTML file input (null, mime types but + // also extensions) && (attr.getMaxAttachmentSize() == null || attr.getMaxAttachmentSize() >= fileData.length))) .findFirst() .orElseThrow(() -> new ResponseStatusException( @@ -121,7 +122,7 @@ public ResponseEntity addAttachment( AttachmentMetadata response; try { - response = AttachmentsHelper.insertAttachment(tmFeatureType, attachment, featureId, fileData); + response = AttachmentsHelper.insertAttachment(tmFeatureType, attachment, primaryKey, fileData); } catch (IOException | SQLException e) { throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); } @@ -155,11 +156,11 @@ public ResponseEntity> listAttachments( TMFeatureType tmFeatureType = editUtil.getEditableFeatureType(application, appTreeLayerNode, service, layer); checkFeatureTypeSupportsAttachments(tmFeatureType); - checkFeatureExists(tmFeatureType, featureId); + Object primaryKey = getFeaturePrimaryKeyByFid(tmFeatureType, featureId); List response; try { - response = AttachmentsHelper.listAttachmentsForFeature(tmFeatureType, featureId); + response = AttachmentsHelper.listAttachmentsForFeature(tmFeatureType, primaryKey); } catch (IOException | SQLException e) { throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); } @@ -232,20 +233,27 @@ public ResponseEntity getAttachment( } } - private void checkFeatureExists(TMFeatureType tmFeatureType, String featureId) throws ResponseStatusException { + private Object getFeaturePrimaryKeyByFid(TMFeatureType tmFeatureType, String featureId) + throws ResponseStatusException { final Filter fidFilter = ff.id(ff.featureId(featureId)); SimpleFeatureSource fs = null; + SimpleFeatureIterator sfi = null; try { fs = featureSourceFactoryHelper.openGeoToolsFeatureSource(tmFeatureType); Query query = new Query(); query.setFilter(fidFilter); - if (fs.getCount(query) < 1) { - throw new ResponseStatusException( - HttpStatus.NOT_FOUND, "Feature with id " + featureId + " does not exist"); - } + query.setPropertyNames(tmFeatureType.getPrimaryKeyAttribute()); + sfi = fs.getFeatures(query).features(); + return sfi.next().getAttribute(tmFeatureType.getPrimaryKeyAttribute()); + } catch (NoSuchElementException e) { + throw new ResponseStatusException( + HttpStatus.NOT_FOUND, "Feature with id %s does not exist".formatted(featureId)); } catch (IOException e) { - throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); + throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), e); } finally { + if (sfi != null) { + sfi.close(); + } if (fs != null) { fs.getDataStore().dispose(); } diff --git a/src/main/java/org/tailormap/api/geotools/featuresources/AttachmentsHelper.java b/src/main/java/org/tailormap/api/geotools/featuresources/AttachmentsHelper.java index db3c9a1a7..b3b6c4215 100644 --- a/src/main/java/org/tailormap/api/geotools/featuresources/AttachmentsHelper.java +++ b/src/main/java/org/tailormap/api/geotools/featuresources/AttachmentsHelper.java @@ -370,7 +370,7 @@ private static byte[] asBytes(UUID uuid) { } public static AttachmentMetadata insertAttachment( - TMFeatureType featureType, AttachmentMetadata attachment, String featureId, byte[] fileData) + TMFeatureType featureType, AttachmentMetadata attachment, Object primaryKey, byte[] fileData) throws IOException, SQLException { // create uuid here so we don't have to deal with DB-specific returning/generated key syntax @@ -384,7 +384,7 @@ public static AttachmentMetadata insertAttachment( "Adding attachment {} for feature {}:{}, type {}: {} (bytes: {})", attachment.getAttachmentId(), featureType.getName(), - featureId, + primaryKey, attachment.getMimeType(), attachment, fileData.length); @@ -410,15 +410,11 @@ public static AttachmentMetadata insertAttachment( try { ds = (JDBCDataStore) new JDBCFeatureSourceHelper().createDataStore(featureType.getFeatureSource()); - Class typeOfPK = ds.getSchema(featureType.getName()) - .getDescriptor(featureType.getPrimaryKeyAttribute()) - .getType() - .getBinding(); - try (Connection conn = ds.getDataSource().getConnection(); PreparedStatement stmt = conn.prepareStatement(insertSql)) { - stmt.setObject(1, featureId, ds.getMapping(typeOfPK)); + stmt.setObject(1, primaryKey); + if (featureType .getFeatureSource() .getJdbcConnection() @@ -478,7 +474,7 @@ public static void deleteAttachment(UUID attachmentId, TMFeatureType featureType } } - public static List listAttachmentsForFeature(TMFeatureType featureType, String featureId) + public static List listAttachmentsForFeature(TMFeatureType featureType, Object primaryKey) throws IOException, SQLException { String querySql = MessageFormat.format( @@ -504,7 +500,7 @@ public static List listAttachmentsForFeature(TMFeatureType f try (Connection conn = ds.getDataSource().getConnection(); PreparedStatement stmt = conn.prepareStatement(querySql)) { - stmt.setString(1, featureId); + stmt.setObject(1, primaryKey); try (ResultSet rs = stmt.executeQuery()) { while (rs.next()) {