From dd87835f311ae1b8d2aa58b9014e425e032b5faa Mon Sep 17 00:00:00 2001 From: Mario Serrano Leones Date: Fri, 13 Sep 2024 06:55:35 -0500 Subject: [PATCH 1/2] upgrade to DynamiaTools v5.3 and AWS SDK v2.28.0 --- sources/core/pom.xml | 4 +- .../modules/entityfile/UploadedFileInfo.java | 4 + sources/pom.xml | 16 +- sources/s3/pom.xml | 8 +- .../entityfiles/s3/S3EntityFileStorage.java | 247 +++++++++++------- .../modules/entityfiles/s3/S3Utils.java | 224 ++++++++++++++++ sources/ui/pom.xml | 4 +- .../entityfile/ui/EntityFileController.java | 4 +- .../ui/components/DirectoryBox.java | 12 +- .../ui/components/DirectoryExplorer.java | 28 +- .../ui/components/EntityFileDownloadlink.java | 2 + .../ui/components/EntityFileImage.java | 7 +- .../ui/components/EntityFileUploadlink.java | 4 +- .../ui/components/FilesCountImage.java | 8 +- .../ui/components/StorageCombobox.java | 2 + 15 files changed, 432 insertions(+), 142 deletions(-) create mode 100644 sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3Utils.java diff --git a/sources/core/pom.xml b/sources/core/pom.xml index 29badad..3479cc3 100644 --- a/sources/core/pom.xml +++ b/sources/core/pom.xml @@ -22,11 +22,11 @@ tools.dynamia.modules.entityfiles.parent tools.dynamia.modules - 7.1.2 + 7.2.0 Dynamia Modules - EntityFiles - Core tools.dynamia.modules.entityfiles - 7.1.2 + 7.2.0 https://www.dynamia.tools/modules/entityfiles diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/UploadedFileInfo.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/UploadedFileInfo.java index 16e39d1..c818d0e 100644 --- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/UploadedFileInfo.java +++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/UploadedFileInfo.java @@ -115,6 +115,10 @@ public void setContentType(String contentType) { this.contentType = contentType; } + public boolean hasInputStream() { + return inputStream != null; + } + public InputStream getInputStream() { if (inputStream == null) { try { diff --git a/sources/pom.xml b/sources/pom.xml index 03a27f8..50b14b4 100644 --- a/sources/pom.xml +++ b/sources/pom.xml @@ -22,7 +22,7 @@ tools.dynamia.modules tools.dynamia.modules.entityfiles.parent pom - 7.1.2 + 7.2.0 Dynamia Modules - EntityFiles https://dynamia.tools/modules/entityfiles DynamiaTools extension to attach files to entities @@ -63,9 +63,9 @@ UTF-8 - 5.2.0 + 5.3.0 3.3.3 - 1.12.771 + 2.28.0 17 3.13.0 UTF-8 @@ -88,7 +88,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.13 + 1.7.0 true ossrh @@ -99,7 +99,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.5.0 + 3.10.0 false none @@ -108,7 +108,7 @@ org.apache.maven.plugins maven-source-plugin - 3.3.0 + 3.3.1 @@ -122,7 +122,7 @@ commons-io commons-io - 2.15.1 + 2.16.1 @@ -175,7 +175,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.0.1 + 3.1.0 sign-artifacts diff --git a/sources/s3/pom.xml b/sources/s3/pom.xml index 41ea7e3..2849e36 100644 --- a/sources/s3/pom.xml +++ b/sources/s3/pom.xml @@ -23,12 +23,12 @@ tools.dynamia.modules tools.dynamia.modules.entityfiles.parent - 7.1.2 + 7.2.0 Dynamia Modules - EntityFiles - S3 tools.dynamia.modules.entityfiles.s3 - 7.1.2 + 7.2.0 https://www.dynamia.tools/modules/entityfiles @@ -53,8 +53,8 @@ ${project.parent.version} - com.amazonaws - aws-java-sdk-s3 + software.amazon.awssdk + s3 ${aws.version} diff --git a/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java b/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java index 618fcd0..0900745 100644 --- a/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java +++ b/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java @@ -17,23 +17,17 @@ package tools.dynamia.modules.entityfiles.s3; -import com.amazonaws.AmazonClientException; -import com.amazonaws.AmazonServiceException; -import com.amazonaws.ClientConfiguration; -import com.amazonaws.Protocol; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.regions.Regions; -import com.amazonaws.services.s3.AmazonS3; -import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import com.amazonaws.services.s3.model.CannedAccessControlList; -import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; -import com.amazonaws.services.s3.model.ObjectMetadata; -import com.amazonaws.services.s3.model.PutObjectRequest; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; +import software.amazon.awssdk.core.async.AsyncRequestBody; +import software.amazon.awssdk.services.s3.S3AsyncClient; +import software.amazon.awssdk.services.s3.model.ObjectCannedACL; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest; import tools.dynamia.commons.SimpleCache; import tools.dynamia.commons.logger.LoggingService; import tools.dynamia.commons.logger.SLF4JLoggingService; @@ -46,13 +40,16 @@ import tools.dynamia.modules.entityfile.domain.EntityFile; import tools.dynamia.modules.entityfile.enums.EntityFileType; -import java.io.ByteArrayInputStream; import java.io.File; import java.net.URL; import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * {@link EntityFileStorage} implementation that store files in Amazon S3 service. @@ -65,14 +62,18 @@ public class S3EntityFileStorage implements EntityFileStorage { public static final String AWS_ACCESS_KEY_ID = "AWS_ACCESS_KEY_ID"; public static final String AWS_SECRET_KEY = "AWS_SECRET_KEY"; public static final String AWS_S3_ENDPOINT = "AWS_S3_ENDPOINT"; + public static final String AWS_S3_REGION = "AWS_S3_REGION"; public static final String AWS_S3_BUCKET = "AWS_S3_BUCKET"; - private final LoggingService logger = new SLF4JLoggingService(S3EntityFileStorage.class); + private static final Logger log = LoggerFactory.getLogger(S3EntityFileStorage.class); + private final LoggingService logger = new SLF4JLoggingService(S3EntityFileStorage.class, "S3"); private final SimpleCache URL_CACHE = new SimpleCache<>(); private final SimpleCache PARAMS_CACHE = new SimpleCache<>(); public static final String ID = "AWSS3Storage"; + private S3AsyncClient s3Client; + private final ExecutorService executorService = Executors.newCachedThreadPool(); @Autowired private Environment environment; @@ -88,6 +89,13 @@ public String getName() { return "AWS S3 Storage"; } + /** + * Upload entity file to S3 bucket + * + * @param entityFile the entity file + * @param fileInfo the uploade file info + * @return the S3 client + */ @Override public void upload(EntityFile entityFile, UploadedFileInfo fileInfo) { try { @@ -97,49 +105,72 @@ public void upload(EntityFile entityFile, UploadedFileInfo fileInfo) { // Metadata - File tmpFile = null; + File fileToUpload; long sourceLength = 0; long length = fileInfo.getLength(); if (fileInfo.getSource() instanceof File file) { sourceLength = file.length(); - tmpFile = file; - } else if (fileInfo.getInputStream() instanceof Path path) { + fileToUpload = file; + } else if (fileInfo.getSource() instanceof Path path) { sourceLength = path.toFile().length(); - tmpFile = path.toFile(); + fileToUpload = path.toFile(); + } else { + fileToUpload = null; } if (length <= 0 && sourceLength > 0) { length = sourceLength; } - ObjectMetadata metadata = new ObjectMetadata(); - metadata.addUserMetadata("accountId", entityFile.getAccountId().toString()); - metadata.addUserMetadata("uuid", entityFile.getUuid()); - metadata.addUserMetadata("creator", entityFile.getCreator()); - metadata.addUserMetadata("databaseId", String.valueOf(entityFile.getId())); - metadata.setContentLength(length); - metadata.setContentType(URLConnection.guessContentTypeFromName(entityFile.getName())); + final var metadata = Map.of( + "accountId", entityFile.getAccountId().toString(), + "uuid", entityFile.getUuid(), + "creator", entityFile.getCreator(), + "databaseId", String.valueOf(entityFile.getId()) + ); + final var contentType = URLConnection.guessContentTypeFromName(entityFile.getName()); final var key = folder + fileName; final var bucket = getBucketName(); - PutObjectRequest request = new PutObjectRequest(bucket, key, fileInfo.getInputStream(), metadata); - request.setCannedAcl(entityFile.isShared() ? CannedAccessControlList.PublicRead : CannedAccessControlList.Private); - - var result = getConnection().putObject(request); - logger.info("EntityFile " + entityFile + " uploaded to S3 Bucket " + getBucketName() + " / " + key); - - - if (tmpFile != null && tmpFile.delete()) { - logger.info("Deleted temporal file: " + tmpFile); + PutObjectRequest request = PutObjectRequest.builder() + .bucket(bucket) + .key(key) + .metadata(metadata) + .contentLength(length) + .contentType(contentType) + .acl(entityFile.isShared() ? ObjectCannedACL.PUBLIC_READ : ObjectCannedACL.PRIVATE) + .build(); + + + AsyncRequestBody body = null; + if (fileToUpload != null && fileToUpload.exists()) { + logger.info("Uploading file " + fileToUpload.getPath() + " to " + key); + body = AsyncRequestBody.fromFile(fileToUpload); + } else if (fileInfo.hasInputStream()) { + logger.info("Uploading input stream from " + fileInfo.getFullName() + " to " + key); + body = AsyncRequestBody.fromInputStream(fileInfo.getInputStream(), length, executorService); } + getClient().putObject(request, body) + .whenComplete((response, throwable) -> { + if (throwable != null) { + logger.error("Error uploading entity file " + entityFile.getName() + " to S3", throwable); + throw new EntityFileException("Error uploading file " + entityFile.getName(), throwable); + } else { + logger.info("Entity file " + entityFile.getName() + " uploaded"); + } + + if (fileToUpload != null && fileToUpload.delete()) { + logger.info("Deleted temporal file: " + fileToUpload); + } + }); - } catch (AmazonClientException amazonClientException) { - logger.error("Error uploading entity file " + entityFile.getName() + " to S3", amazonClientException); - throw new EntityFileException("Error uploading file " + entityFile.getName(), amazonClientException); + } catch (Exception e) { + logger.error("Error sending PUT request for entity file " + entityFile.getName() + " to S3", e); + throw new EntityFileException("Error sending PUT request fo file " + entityFile.getName(), e); } } @@ -163,21 +194,19 @@ public StoredEntityFile download(EntityFile entityFile) { return new S3StoredEntityFile(entityFile, url, new File(fileName)); } - private String generateSignedURL(String bucketName, String fileName) { - try { - GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, fileName); - return getConnection().generatePresignedUrl(request).toString(); + protected String generateSignedURL(String bucketName, String fileName) { + + + PresignedGetObjectRequest presignedRequest = S3Utils.generatePresignedObjetRequest(bucketName, fileName, Duration.ofMinutes(30)); + logger.info("Presigned URL: [{}]", presignedRequest.url().toString()); + logger.info("HTTP method: [{}]", presignedRequest.httpRequest().method()); + + return presignedRequest.url().toExternalForm(); - } catch (AmazonClientException amazonClientException) { - logger.error("Error generating URL for " + bucketName + " => " + fileName, amazonClientException); - return "#"; - } } private String generateStaticURL(String bucketName, String fileName) { - String endpoint = getEndpoint(); - fileName = fileName.replace(" ", "%20"); - return String.format("https://%s.%s/%s", bucketName, endpoint, fileName); + return S3Utils.generateStaticURL(bucketName, fileName, getRegion()); } @@ -204,25 +233,30 @@ private String getFileName(EntityFile entityFile) { return subfolder + storedFileName; } - private AmazonS3 getConnection() { - ClientConfiguration clientConfig = new ClientConfiguration(); - clientConfig.setProtocol(Protocol.HTTPS); + /** + * Get or build a S3 async client using static credentials + * + * @return S3 Async client + */ + protected S3AsyncClient getClient() { + + if (s3Client == null) { + s3Client = S3Utils.buildS3AsyncClient(getAccessKey(), getSecretKey(), getRegion()) + .build(); + } + return s3Client; - AWSCredentials credentials = new BasicAWSCredentials(getAccessKey(), getSecretKey()); - return AmazonS3ClientBuilder.standard() - .withCredentials(new AWSStaticCredentialsProvider(credentials)) - .withRegion(Regions.US_EAST_1) - .withRegionalUsEast1EndpointEnabled(true) - .withClientConfiguration(clientConfig) - .build(); } - private String getAccountFolderName(Long accountId) { + protected String getAccountFolderName(Long accountId) { return "account" + accountId + "/"; } - private String generateThumbnailURL(EntityFile entityFile, int w, int h) { + /** + * Generate thumbnail url + */ + protected String generateThumbnailURL(EntityFile entityFile, int w, int h) { if (entityFile.getType() == EntityFileType.IMAGE || EntityFileType.getFileType(entityFile.getExtension()) == EntityFileType.IMAGE) { String urlKey = entityFile.getUuid() + w + "x" + h; String url = URL_CACHE.get(urlKey); @@ -244,10 +278,13 @@ private String generateThumbnailURL(EntityFile entityFile, int w, int h) { } } - private void createAndUploadThumbnail(EntityFile entityFile, String bucketName, String folder, String fileName, String thumbfileName, - int w, int h) throws AmazonClientException { + /** + * Create and upload thumbnail + */ + protected void createAndUploadThumbnail(EntityFile entityFile, String bucketName, String folder, String fileName, String thumbfileName, + int w, int h) { try { - final var key = folder + fileName; + File localDestination = File.createTempFile(System.currentTimeMillis() + "file", entityFile.getName()); File localThumbDestination = File.createTempFile(System.currentTimeMillis() + "thumb", entityFile.getName()); @@ -259,20 +296,33 @@ private void createAndUploadThumbnail(EntityFile entityFile, String bucketName, // metadata - ObjectMetadata metadata = new ObjectMetadata(); - metadata.addUserMetadata("thumbnail", "true"); - metadata.addUserMetadata("description", entityFile.getDescription()); - metadata.addUserMetadata("uuid", entityFile.getUuid()); - metadata.addUserMetadata("width", String.valueOf(w)); - metadata.addUserMetadata("height", String.valueOf(h)); - metadata.setContentType("image/" + entityFile.getExtension()); - metadata.setContentLength(localThumbDestination.length()); - - PutObjectRequest request = new PutObjectRequest(bucketName, folder + thumbfileName, localThumbDestination); - request.setMetadata(metadata); - request.setCannedAcl(CannedAccessControlList.PublicRead); - - getConnection().putObject(request); + var metadata = Map.of( + "thumbnail", "true", + "description", entityFile.getDescription(), + "uuid", entityFile.getUuid(), + "width", String.valueOf(w), + "height", String.valueOf(h)); + + String key = folder + thumbfileName; + PutObjectRequest request = PutObjectRequest.builder() + .bucket(bucketName) + .key(key) + .contentLength(localThumbDestination.length()) + .contentType("image/" + entityFile.getExtension()) + .acl(ObjectCannedACL.PUBLIC_READ) + .build(); + + + getClient().putObject(request, AsyncRequestBody.fromFile(localThumbDestination)) + .whenComplete((putObjectResponse, throwable) -> { + if (throwable != null) { + logger.error("Error uploading thumbnail " + localDestination, throwable); + } else { + logger.info("Thumbnail uploaded " + key); + } + + localThumbDestination.delete(); + }); } catch (Exception e) { logger.error("Error creating thumbnail for " + entityFile.getName() + " " + w + "x" + h + " " + fileName, e); @@ -280,23 +330,23 @@ private void createAndUploadThumbnail(EntityFile entityFile, String bucketName, } public boolean objectExists(String bucketName, String key) { - try { - getConnection().getObjectMetadata(bucketName, key); - } catch (AmazonServiceException e) { - return false; - } - return true; + return S3Utils.objectExists(getClient(), bucketName, key); } @Override public void delete(EntityFile entityFile) { - throw new UnsupportedOperationException("Not supported yet."); - } - - - public void resetConnection() { - + String folder = getAccountFolderName(entityFile.getAccountId()); + String key = folder + getFileName(entityFile); + + S3Utils.deleteFile(getClient(), getBucketName(), key) + .whenComplete((deleteObjectResponse, throwable) -> { + if (throwable != null) { + logger.error("Error deleting entity file " + entityFile.getName() + " from S3", throwable); + } else { + logger.info("Entity file " + entityFile.getName() + " deleted from S3"); + } + }); } @@ -312,15 +362,23 @@ public String getAccessKey() { return getParameter(AWS_ACCESS_KEY_ID); } - private String getParameter(String name) { - var param = PARAMS_CACHE.getOrLoad(name, s -> { + public String getRegion() { + var region = getParameter(AWS_S3_REGION); + if (region == null || region.isBlank()) { + region = "us-east-1"; + } + return region; + } + + + protected String getParameter(String name) { + return PARAMS_CACHE.getOrLoad(name, s -> { var value = ApplicationParameters.get().getValue(name); if (value == null) { value = environment.getProperty(name); } return value; }); - return param; } public String getSecretKey() { @@ -331,6 +389,7 @@ public String getSecretKey() { public void reloadParams() { PARAMS_CACHE.clear(); URL_CACHE.clear(); + s3Client = null; } class S3StoredEntityFile extends StoredEntityFile { diff --git a/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3Utils.java b/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3Utils.java new file mode 100644 index 0000000..4f5fc82 --- /dev/null +++ b/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3Utils.java @@ -0,0 +1,224 @@ +package tools.dynamia.modules.entityfiles.s3; + +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentials; +import software.amazon.awssdk.core.async.AsyncRequestBody; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3AsyncClient; +import software.amazon.awssdk.services.s3.S3AsyncClientBuilder; +import software.amazon.awssdk.services.s3.model.*; +import software.amazon.awssdk.services.s3.presigner.S3Presigner; +import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest; +import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest; +import tools.dynamia.commons.StringUtils; + +import java.io.File; +import java.nio.file.Path; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +/** + * Utility class to work AWS S3 Buckets + */ +public class S3Utils { + + + /** + * Get credentials from access key and secret key + * + * @param accessKey the access key + * @param secretKey the secret key + * @return the aws credentials + */ + public static AwsCredentials getCredentials(String accessKey, String secretKey) { + return AwsBasicCredentials.create(accessKey, secretKey); + } + + /** + * Build S3AsyncClient + * + * @param accessKey the access key + * @param secretKey the secret key + * @param region the region + * @return the S3AsyncClient + */ + public static S3AsyncClientBuilder buildS3AsyncClient(String accessKey, String secretKey, String region) { + return S3AsyncClient.builder() + .credentialsProvider(() -> getCredentials(accessKey, secretKey)) + .region(Region.of(region)); + + } + + /** + * Upload file to S3 bucket + * + * @param s3Client the S3AsyncClient + * @param bucketName the bucket name + * @param key the key + * @param file the file + * @return the CompletableFuture + */ + public static CompletableFuture uploadFile(S3AsyncClient s3Client, String bucketName, String key, File file) { + return s3Client.putObject(PutObjectRequest.builder() + .bucket(bucketName) + .key(key) + .build(), AsyncRequestBody.fromFile(file)); + } + + /** + * Delete file from S3 bucket + * + * @param s3Cliente the S3AsyncClient + * @param bucketName the bucket name + * @param key the key + * @return the CompletableFuture + */ + public static CompletableFuture deleteFile(S3AsyncClient s3Cliente, String bucketName, String key) { + DeleteObjectRequest request = DeleteObjectRequest.builder() + .bucket(bucketName) + .key(key) + .build(); + + return s3Cliente.deleteObject(request); + } + + /** + * Generate presigned URL for S3 object + * + * @param bucketName the bucket name + * @param key the key + * @param duration the duration + * @return the presigned URL + */ + public static PresignedGetObjectRequest generatePresignedObjetRequest(String bucketName, String key, Duration duration) { + + try (S3Presigner presigner = S3Presigner.create()) { + + GetObjectRequest objectRequest = GetObjectRequest.builder() + .bucket(bucketName) + .key(key) + .build(); + + GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder() + .signatureDuration(duration) + .getObjectRequest(objectRequest) + .build(); + + return presigner.presignGetObject(presignRequest); + } + } + + /** + * Generate static URL for S3 object + * + * @param bucketName the bucket name + * @param key the key + * @param region the region + * @return the static URL + */ + public static String generateStaticURL(String bucketName, String key, String region) { + String endpoint = "s3." + region + ".amazonaws.com"; + key = key.replace(" ", "%20"); + return String.format("https://%s.%s/%s", bucketName, endpoint, key); + } + + /** + * Get regions + * + * @return the list of regions + */ + public static List getRegions() { + return Region.regions().stream().map(Region::id).toList(); + } + + /** + * Check if object exists in S3 bucket + * + * @param client the S3AsyncClient + * @param bucketName the bucket name + * @param key the key + * @return true if object exists, false otherwise + */ + public static boolean objectExists(S3AsyncClient client, String bucketName, String key) { + try { + getObjectAttributes(client, bucketName, key).wait(); + } catch (Exception e) { + return false; + } + return true; + } + + /** + * Get object attributes + * + * @param client the S3AsyncClient + * @param bucketName the bucket name + * @param key the key + * @return the CompletableFuture + */ + public static CompletableFuture getObjectAttributes(S3AsyncClient client, String bucketName, String key) { + return client.getObjectAttributes(builder -> builder.bucket(bucketName).key(key)); + } + + /** + * Head object + * + * @param client the S3AsyncClient + * @param bucketName the bucket name + * @param key the key + * @return the CompletableFuture + */ + public static CompletableFuture headObject(S3AsyncClient client, String bucketName, String key) { + return client.headObject(builder -> builder.bucket(bucketName).key(key)); + } + + /** + * Download file + * + * @param client the S3AsyncClient + * @param bucketName the bucket name + * @param key the key + * @param destination the destination + * @return the CompletableFuture + */ + public static CompletableFuture downloadFile(S3AsyncClient client, String bucketName, String key, File destination) { + return downloadFile(client, bucketName, key, destination.toPath()); + } + + /** + * Download file + * + * @param client the S3AsyncClient + * @param bucketName the bucket name + * @param key the key + * @param destination the destination + * @return the CompletableFuture + */ + public static CompletableFuture downloadFile(S3AsyncClient client, String bucketName, String key, Path destination) { + GetObjectRequest request = GetObjectRequest + .builder() + .bucket(bucketName) + .key(key) + .build(); + return client.getObject(request, destination); + } + + /** + * Download file + * + * @param client the S3AsyncClient + * @param bucketName the bucket name + * @param key the key + * @return the File + */ + public static File downloadFile(S3AsyncClient client, String bucketName, String key) { + try { + File tmpFile = File.createTempFile("tmpFile", StringUtils.getFilenameExtension(key)); + downloadFile(client, bucketName, key, tmpFile).wait(); + return tmpFile; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/sources/ui/pom.xml b/sources/ui/pom.xml index 33e9d98..8ed45fc 100644 --- a/sources/ui/pom.xml +++ b/sources/ui/pom.xml @@ -22,11 +22,11 @@ tools.dynamia.modules.entityfiles.parent tools.dynamia.modules - 7.1.2 + 7.2.0 Dynamia Modules - EntityFiles UI tools.dynamia.modules.entityfiles.ui - 7.1.2 + 7.2.0 https://www.dynamia.tools/modules/entityfiles diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFileController.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFileController.java index 62b1328..c65020a 100644 --- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFileController.java +++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFileController.java @@ -30,16 +30,18 @@ import tools.dynamia.zk.crud.ui.EntityTreeNode; import tools.dynamia.zk.crud.ui.LazyEntityTreeNode; +import java.io.Serial; import java.util.List; public class EntityFileController extends TreeCrudController { - private EntityFileService service; + private final EntityFileService service; private Object targetEntity; /** * */ + @Serial private static final long serialVersionUID = 7926996145692421296L; public EntityFileController() { diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryBox.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryBox.java index f50eace..68e8bed 100644 --- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryBox.java +++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryBox.java @@ -27,6 +27,8 @@ import tools.dynamia.zk.BindingComponentIndex; import tools.dynamia.zk.ComponentAliasIndex; +import java.io.Serial; + /** * * @author Mario Serrano Leones @@ -36,24 +38,22 @@ public class DirectoryBox extends Bandbox { /** * */ - private static final long serialVersionUID = -7769832324226733919L; + @Serial + private static final long serialVersionUID = -7769832324226733919L; static { BindingComponentIndex.getInstance().put("value", DirectoryBox.class); ComponentAliasIndex.getInstance().add(DirectoryBox.class); } - private DirectoryExplorer explorer; - private Bandpopup popup; - public DirectoryBox() { this(null); } public DirectoryBox(String value) throws WrongValueException { super(value); - explorer = new DirectoryExplorer(); - popup = new Bandpopup(); + DirectoryExplorer explorer = new DirectoryExplorer(); + Bandpopup popup = new Bandpopup(); popup.appendChild(explorer); popup.setWidth("400px"); diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryExplorer.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryExplorer.java index 02d6195..49c6c10 100644 --- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryExplorer.java +++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/DirectoryExplorer.java @@ -76,8 +76,8 @@ private void init() { private void initModel() { FileInfo file = new FileInfo(new File("/")); - rootNode = new EntityTreeNode(file); - treeModel = new EntityTreeModel(rootNode); + rootNode = new EntityTreeNode<>(file); + treeModel = new EntityTreeModel<>(rootNode); for (EntityTreeNode entityTreeNode : getSubdirectories(file)) { rootNode.addChild(entityTreeNode); } @@ -86,18 +86,14 @@ private void initModel() { } private Collection> getSubdirectories(FileInfo file) { - File[] subs = file.getFile().listFiles(new FileFilter() { - - @Override - public boolean accept(File pathname) { - if (pathname.isDirectory()) { - if (!isShowHiddenFolders()) { - return !pathname.isHidden() && !pathname.getName().startsWith("."); - } - return true; + File[] subs = file.getFile().listFiles(pathname -> { + if (pathname.isDirectory()) { + if (!isShowHiddenFolders()) { + return !pathname.isHidden() && !pathname.getName().startsWith("."); } - return false; + return true; } + return false; }); List> subdirectories = new ArrayList>(); @@ -107,13 +103,7 @@ public boolean accept(File pathname) { } } - Collections.sort(subdirectories, new Comparator>() { - - @Override - public int compare(EntityTreeNode o1, EntityTreeNode o2) { - return o1.getData().getName().compareTo(o2.getData().getName()); - } - }); + subdirectories.sort(Comparator.comparing(o -> o.getData().getName())); return subdirectories; } diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileDownloadlink.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileDownloadlink.java index 4c12207..24fb126 100644 --- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileDownloadlink.java +++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileDownloadlink.java @@ -18,6 +18,7 @@ package tools.dynamia.modules.entityfile.ui.components; import java.io.FileInputStream; +import java.io.Serial; import java.net.URL; import org.zkoss.util.media.AMedia; @@ -42,6 +43,7 @@ public class EntityFileDownloadlink extends Toolbarbutton { /** * */ + @Serial private static final long serialVersionUID = -2182747459195865750L; static { diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java index 99d2c1d..139c8ab 100644 --- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java +++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java @@ -30,15 +30,18 @@ import tools.dynamia.zk.ComponentAliasIndex; import tools.dynamia.zk.ImageCache; +import java.io.Serial; + public class EntityFileImage extends Image { - private static SimpleCache URL_CACHE = new SimpleCache<>(); - private static SimpleCache URL_THUMB_CACHE = new SimpleCache<>(); + private static final SimpleCache URL_CACHE = new SimpleCache<>(); + private static final SimpleCache URL_THUMB_CACHE = new SimpleCache<>(); /** * */ + @Serial private static final long serialVersionUID = -2182747459195865750L; static { diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileUploadlink.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileUploadlink.java index 9f83c64..9bb7e89 100644 --- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileUploadlink.java +++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileUploadlink.java @@ -29,12 +29,14 @@ import tools.dynamia.zk.ui.Uploadlink; import java.io.File; +import java.io.Serial; public class EntityFileUploadlink extends Uploadlink { /** * */ + @Serial private static final long serialVersionUID = -2182747459195865750L; static { @@ -43,7 +45,7 @@ public class EntityFileUploadlink extends Uploadlink { } private EntityFile entityFile; - private EntityFileService service = Containers.get().findObject(EntityFileService.class); + private final EntityFileService service = Containers.get().findObject(EntityFileService.class); private boolean shared; private String subfolder; private String storedFileName; diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/FilesCountImage.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/FilesCountImage.java index 9d00974..5d7ab9c 100644 --- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/FilesCountImage.java +++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/FilesCountImage.java @@ -25,11 +25,14 @@ import tools.dynamia.zk.ComponentAliasIndex; import tools.dynamia.zk.util.ZKUtil; +import java.io.Serial; + public class FilesCountImage extends A { /** * */ + @Serial private static final long serialVersionUID = 1L; private IconSize iconSize = IconSize.SMALL; private String icon = "attachment"; @@ -50,10 +53,9 @@ public FilesCountImage(int value) { public void setValue(int value) { try { - int count = value; - if (count > 0) { + if (value > 0) { ZKUtil.configureComponentIcon(icon, this, iconSize); - setTooltiptext(count + " archivos adjuntos"); + setTooltiptext(value + " archivos adjuntos"); } else { setImage(null); getChildren().clear(); diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/StorageCombobox.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/StorageCombobox.java index dc9d954..84cf28a 100644 --- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/StorageCombobox.java +++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/StorageCombobox.java @@ -17,6 +17,7 @@ package tools.dynamia.modules.entityfile.ui.components; +import java.io.Serial; import java.util.Optional; import org.zkoss.zul.Combobox; @@ -33,6 +34,7 @@ public class StorageCombobox extends Combobox { /** * */ + @Serial private static final long serialVersionUID = 3507817129731334840L; static { From a3735207ad3d3cb403c31c3d5c79d2982b2e7484 Mon Sep 17 00:00:00 2001 From: Mario Serrano Leones Date: Mon, 30 Sep 2024 11:36:26 -0500 Subject: [PATCH 2/2] upgrade to AWS SDK v2.28 --- .../LocalEntityFileStorageController.java | 34 +++++++ .../modules/entityfile/domain/EntityFile.java | 1 + .../local/LocalEntityFileStorage.java | 7 ++ .../local/LocalEntityFileStorageConfig.java | 28 +----- .../local/LocalEntityFileStorageHandler.java | 39 +++----- .../service/impl/EntityFileServiceImpl.java | 12 ++- sources/pom.xml | 4 +- .../entityfiles/s3/S3EntityFileStorage.java | 12 +-- ...er.java => EntityFilesModuleProvider.java} | 99 ++++++++++--------- .../ui/actions/ViewFileURLAction.java | 4 +- .../ui/components/EntityFileImage.java | 2 +- .../META-INF/descriptors/EntityFileConfig.yml | 9 +- 12 files changed, 136 insertions(+), 115 deletions(-) create mode 100644 sources/core/src/main/java/tools/dynamia/modules/entityfile/controller/LocalEntityFileStorageController.java rename sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/{EntityFilesInstaller.java => EntityFilesModuleProvider.java} (77%) diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/controller/LocalEntityFileStorageController.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/controller/LocalEntityFileStorageController.java new file mode 100644 index 0000000..7b9fb79 --- /dev/null +++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/controller/LocalEntityFileStorageController.java @@ -0,0 +1,34 @@ +package tools.dynamia.modules.entityfile.controller; + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import tools.dynamia.integration.sterotypes.Controller; +import tools.dynamia.modules.entityfile.local.LocalEntityFileStorageHandler; + +@Controller +public class LocalEntityFileStorageController { + + private final LocalEntityFileStorageHandler handler; + + public LocalEntityFileStorageController(LocalEntityFileStorageHandler handler) { + this.handler = handler; + } + + @GetMapping(value = "/storage/{file}") + public ResponseEntity get(@PathVariable String file, @RequestParam("uuid") String uuid, HttpServletRequest request) { + var resource = handler.getResource(file, uuid, request); + if (resource != null && resource.exists() && resource.isReadable()) { + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") + .body(resource); + } else { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } +} diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/domain/EntityFile.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/domain/EntityFile.java index 3a52742..f128e7c 100644 --- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/domain/EntityFile.java +++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/domain/EntityFile.java @@ -32,6 +32,7 @@ import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; + import java.util.List; @Entity diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorage.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorage.java index 77be073..fa255e5 100644 --- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorage.java +++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorage.java @@ -18,6 +18,8 @@ package tools.dynamia.modules.entityfile.local; import org.springframework.core.env.Environment; +import tools.dynamia.commons.logger.LoggingService; +import tools.dynamia.commons.logger.SLF4JLoggingService; import tools.dynamia.domain.ValidationError; import tools.dynamia.domain.query.Parameters; import tools.dynamia.domain.services.CrudService; @@ -37,6 +39,8 @@ @Service public class LocalEntityFileStorage implements EntityFileStorage { + private final LoggingService logger = new SLF4JLoggingService(LocalEntityFileStorage.class, "Local: "); + public static final String ID = "LocalStorage"; private static final String LOCAL_FILES_LOCATION = "LOCAL_FILES_LOCATION"; private static final String LOCAL_USE_HTTPS = "LOCAL_USE_HTTPS"; @@ -71,9 +75,12 @@ public void upload(EntityFile entityFile, UploadedFileInfo fileInfo) { File realFile = getRealFile(entityFile); try { + IOUtils.copy(fileInfo.getInputStream(), realFile); entityFile.setSize(realFile.length()); + logger.info("Uploaded to server: " + realFile); } catch (IOException e) { + logger.error("Error upload local file " + realFile, e); throw new EntityFileException("Error upload local file " + realFile, e); } diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageConfig.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageConfig.java index 01560d8..f659ac5 100644 --- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageConfig.java +++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageConfig.java @@ -17,34 +17,16 @@ package tools.dynamia.modules.entityfile.local; -import java.util.HashMap; -import java.util.Map; - import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; +import tools.dynamia.modules.entityfile.service.EntityFileService; @Configuration class LocalEntityFileStorageConfig { - @Bean - public SimpleUrlHandlerMapping localHandler() { - - ResourceHttpRequestHandler handler = localEntityFileStorageHandler(); - - Map map = new HashMap<>(); - - map.put("storage/**", handler); - - SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); - mapping.setUrlMap(map); - - return mapping; - } - @Bean - public LocalEntityFileStorageHandler localEntityFileStorageHandler() { - return new LocalEntityFileStorageHandler(); - } + @Bean + public LocalEntityFileStorageHandler localEntityFileStorageHandler(LocalEntityFileStorage storage, EntityFileService service) { + return new LocalEntityFileStorageHandler(storage, service); + } } diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageHandler.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageHandler.java index 5178889..0d1b1ff 100644 --- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageHandler.java +++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/local/LocalEntityFileStorageHandler.java @@ -23,7 +23,6 @@ import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; -import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; import tools.dynamia.commons.StringUtils; import tools.dynamia.integration.Containers; @@ -36,21 +35,21 @@ import tools.dynamia.modules.entityfile.enums.EntityFileType; import tools.dynamia.modules.entityfile.service.EntityFileService; -public class LocalEntityFileStorageHandler extends ResourceHttpRequestHandler { +public class LocalEntityFileStorageHandler { private static final String UUID = "/uuid/"; - private LocalEntityFileStorage storage; - private EntityFileService service; + private final LocalEntityFileStorage storage; + private final EntityFileService service; private EntityFileAccountProvider accountProvider; - @Override - protected Resource getResource(HttpServletRequest request) { - if (service == null) { - service = Containers.get().findObject(EntityFileService.class); - } - if (storage == null) { - storage = Containers.get().findObject(LocalEntityFileStorage.class); - } + public LocalEntityFileStorageHandler(LocalEntityFileStorage storage, EntityFileService service) { + this.storage = storage; + this.service = service; + } + + + public Resource getResource(String fileName, String uuid, HttpServletRequest request) { + if (accountProvider == null) { accountProvider = Containers.get().findObject(EntityFileAccountProvider.class); @@ -60,23 +59,11 @@ protected Resource getResource(HttpServletRequest request) { } File file = null; - String uuid = getParam(request, "uuid", null); - - if (uuid == null) { - String path = request.getPathInfo(); - if (path.contains(UUID)) { - uuid = path.substring(path.lastIndexOf(UUID) + UUID.length()); - uuid = StringUtils.removeFilenameExtension(uuid); - } - } - - if (uuid == null) { - return null; - } - Long currentAccountId = accountProvider.getAccountId(); EntityFile entityFile = service.getEntityFile(uuid); + + if (entityFile != null && (currentAccountId == null || currentAccountId.equals(0L) || entityFile.isShared() || entityFile.getAccountId().equals(currentAccountId))) { StoredEntityFile storedEntityFile = storage.download(entityFile); diff --git a/sources/core/src/main/java/tools/dynamia/modules/entityfile/service/impl/EntityFileServiceImpl.java b/sources/core/src/main/java/tools/dynamia/modules/entityfile/service/impl/EntityFileServiceImpl.java index b6f7918..79cfb64 100644 --- a/sources/core/src/main/java/tools/dynamia/modules/entityfile/service/impl/EntityFileServiceImpl.java +++ b/sources/core/src/main/java/tools/dynamia/modules/entityfile/service/impl/EntityFileServiceImpl.java @@ -18,6 +18,9 @@ package tools.dynamia.modules.entityfile.service.impl; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Root; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -101,7 +104,7 @@ private EntityFile createDir(EntityFile parent, Object targetEntity, String name @Override @Transactional public EntityFile createEntityFile(UploadedFileInfo fileInfo, Object target, String description) { - logger.info("Creating new entity file for " + target + ", file: " + fileInfo.getFullName()); + logger.info("Creating new entity file for " + (target != null ? target : "temporal entity") + ", file: " + fileInfo.getFullName()); EntityFile entityFile = new EntityFile(); entityFile.setDescription(description); entityFile.setContentType(fileInfo.getContentType()); @@ -294,8 +297,11 @@ public void download(EntityFile entityFile, File outputFile) { @Override public EntityFile getEntityFile(String uuid) { try { - return crudService.findSingle(EntityFile.class, QueryParameters.with("uuid", QueryConditions.eq(uuid)) - .add("accountId", QueryConditions.isNotNull())); + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(EntityFile.class); + Root root = query.from(EntityFile.class); + query.select(root).where(cb.equal(root.get("uuid"), uuid)); + return entityManager.createQuery(query).setMaxResults(1).getSingleResult(); } catch (Exception e) { logger.error("Error loading entity file with uuid: " + uuid + ". " + e.getMessage(), e); diff --git a/sources/pom.xml b/sources/pom.xml index 50b14b4..978a58b 100644 --- a/sources/pom.xml +++ b/sources/pom.xml @@ -63,9 +63,9 @@ UTF-8 - 5.3.0 + 5.2.1 3.3.3 - 2.28.0 + 2.28.11 17 3.13.0 UTF-8 diff --git a/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java b/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java index 0900745..a30cf70 100644 --- a/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java +++ b/sources/s3/src/main/java/tools/dynamia/modules/entityfiles/s3/S3EntityFileStorage.java @@ -65,7 +65,7 @@ public class S3EntityFileStorage implements EntityFileStorage { public static final String AWS_S3_REGION = "AWS_S3_REGION"; public static final String AWS_S3_BUCKET = "AWS_S3_BUCKET"; private static final Logger log = LoggerFactory.getLogger(S3EntityFileStorage.class); - private final LoggingService logger = new SLF4JLoggingService(S3EntityFileStorage.class, "S3"); + private final LoggingService logger = new SLF4JLoggingService(S3EntityFileStorage.class, "S3: "); private final SimpleCache URL_CACHE = new SimpleCache<>(); private final SimpleCache PARAMS_CACHE = new SimpleCache<>(); @@ -126,10 +126,10 @@ public void upload(EntityFile entityFile, UploadedFileInfo fileInfo) { final var metadata = Map.of( - "accountId", entityFile.getAccountId().toString(), + "accountId", entityFile.getAccountId() != null ? entityFile.getAccountId().toString() : "", "uuid", entityFile.getUuid(), - "creator", entityFile.getCreator(), - "databaseId", String.valueOf(entityFile.getId()) + "creator", entityFile.getCreator() != null ? entityFile.getCreator() : "anonymous", + "databaseId", entityFile.getId() != null ? String.valueOf(entityFile.getId()) : "" ); final var contentType = URLConnection.guessContentTypeFromName(entityFile.getName()); @@ -198,8 +198,8 @@ protected String generateSignedURL(String bucketName, String fileName) { PresignedGetObjectRequest presignedRequest = S3Utils.generatePresignedObjetRequest(bucketName, fileName, Duration.ofMinutes(30)); - logger.info("Presigned URL: [{}]", presignedRequest.url().toString()); - logger.info("HTTP method: [{}]", presignedRequest.httpRequest().method()); + logger.info("Presigned URL: " + presignedRequest.url().toString()); + logger.info("HTTP method: " + presignedRequest.httpRequest().method()); return presignedRequest.url().toExternalForm(); diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesInstaller.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesModuleProvider.java similarity index 77% rename from sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesInstaller.java rename to sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesModuleProvider.java index 7cecab6..7ed9e94 100644 --- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesInstaller.java +++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/EntityFilesModuleProvider.java @@ -1,49 +1,50 @@ - -/* - * Copyright (C) 2023 Dynamia Soluciones IT S.A.S - NIT 900302344-1 - * Colombia / South America - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package tools.dynamia.modules.entityfile.ui; - -import tools.dynamia.crud.cfg.ConfigPage; -import tools.dynamia.integration.sterotypes.Provider; -import tools.dynamia.navigation.Module; -import tools.dynamia.navigation.ModuleProvider; -import tools.dynamia.navigation.PageGroup; - - -/** - * - * @author Mario Serrano Leones - */ -@Provider -public class EntityFilesInstaller implements ModuleProvider { - - @Override - public Module getModule() { - Module module = Module.getRef("system"); - - PageGroup pg = new PageGroup("config", "Configuracion"); - module.addPageGroup(pg); - { - pg.addPage(new ConfigPage("entityFile", "Archivos", "EntityFileCFG")); - - } - - return module; - } - -} + +/* + * Copyright (C) 2023 Dynamia Soluciones IT S.A.S - NIT 900302344-1 + * Colombia / South America + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tools.dynamia.modules.entityfile.ui; + +import tools.dynamia.crud.cfg.ConfigPage; +import tools.dynamia.integration.sterotypes.Provider; +import tools.dynamia.navigation.Module; +import tools.dynamia.navigation.ModuleProvider; +import tools.dynamia.navigation.PageGroup; + + +/** + * @author Mario Serrano Leones + */ +@Provider +public class EntityFilesModuleProvider implements ModuleProvider { + + @Override + public Module getModule() { + Module module = Module.getRef("system") + .name("System") + .icon("settings"); + + PageGroup pg = new PageGroup("config", "Configuration"); + module.addPageGroup(pg); + { + pg.addPage(new ConfigPage("entityFile", "Entity Files", "EntityFileCFG")); + + } + + return module; + } + +} diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/actions/ViewFileURLAction.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/actions/ViewFileURLAction.java index 9e2b1ab..0d90b7b 100644 --- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/actions/ViewFileURLAction.java +++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/actions/ViewFileURLAction.java @@ -21,6 +21,7 @@ import tools.dynamia.actions.ActionGroup; import tools.dynamia.actions.InstallAction; import tools.dynamia.actions.ReadableOnly; +import tools.dynamia.ui.UIMessages; @InstallAction public class ViewFileURLAction extends AbstractEntityFileAction implements ReadableOnly { @@ -35,7 +36,8 @@ public ViewFileURLAction() { @Override public void actionPerformed(EntityFileActionEvent evt) { if (evt.getEntityFile() != null) { - Messagebox.show(evt.getEntityFile().getStoredEntityFile().getUrl()); + String url = evt.getEntityFile().getStoredEntityFile().getUrl(); + UIMessages.showMessageDialog("
" + url + "
"); } } } diff --git a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java index 139c8ab..2879fc3 100644 --- a/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java +++ b/sources/ui/src/main/java/tools/dynamia/modules/entityfile/ui/components/EntityFileImage.java @@ -53,7 +53,7 @@ public class EntityFileImage extends Image { private boolean thumbnail = false; private int thumbnailHeight = 64; private int thumbnailWidth = 64; - private String noPhotoPath = "/zkau/web/tools/images/no-photo.jpg"; + private String noPhotoPath = "/static/dynamia-tools/images/no-photo.jpg"; public EntityFile getValue() { return entityFile; diff --git a/sources/ui/src/main/resources/META-INF/descriptors/EntityFileConfig.yml b/sources/ui/src/main/resources/META-INF/descriptors/EntityFileConfig.yml index 0b814c4..68518e2 100644 --- a/sources/ui/src/main/resources/META-INF/descriptors/EntityFileConfig.yml +++ b/sources/ui/src/main/resources/META-INF/descriptors/EntityFileConfig.yml @@ -39,10 +39,11 @@ fields: params: parameterName: AWS_S3_BUCKET cacheable: true - s3Endpoint: - label: Endpoint + s3Region: + label: Region params: - parameterName: AWS_S3_ENDPOINT + parameterName: AWS_S3_REGION + defaultValue: us-east-1 cacheable: true s3User: label: Identity @@ -58,7 +59,7 @@ fields: groups: s3: label: Amazon Web Service (S3) - fields: [ s3BucketName,s3Endpoint,s3User,s3Secret ] + fields: [ s3BucketName,s3Region,s3User,s3Secret ] layout: columns: 4 \ No newline at end of file