From 69f51a6bf5463cd93550e6985adc0307e98e7371 Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Wed, 20 Nov 2024 17:07:01 +0100 Subject: [PATCH 01/13] feature(s3-connector): initial commit --- connectors/aws/aws-s3/pom.xml | 30 ++++++++++++++++++ .../connector/aws/s3/S3ConnectorFunction.java | 31 +++++++++++++++++++ .../connector/aws/s3/model/S3Request.java | 5 +++ ...tor.api.outbound.OutboundConnectorFunction | 1 + connectors/pom.xml | 1 + 5 files changed, 68 insertions(+) create mode 100644 connectors/aws/aws-s3/pom.xml create mode 100644 connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java create mode 100644 connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java create mode 100644 connectors/aws/aws-s3/src/main/resources/META-INF/services/io.camunda.connector.api.outbound.OutboundConnectorFunction diff --git a/connectors/aws/aws-s3/pom.xml b/connectors/aws/aws-s3/pom.xml new file mode 100644 index 0000000000..e4c437dde1 --- /dev/null +++ b/connectors/aws/aws-s3/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + io.camunda.connector + connectors-parent + 8.7.0-SNAPSHOT + ../../pom.xml + + + aws-s3 + + + 21 + 21 + UTF-8 + + + + + io.camunda.connector + connector-aws-base + ${project.version} + + + + + \ No newline at end of file diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java new file mode 100644 index 0000000000..0708d0068d --- /dev/null +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java @@ -0,0 +1,31 @@ +package io.camunda.connector.aws.s3; + +import io.camunda.connector.api.annotation.OutboundConnector; +import io.camunda.connector.api.outbound.OutboundConnectorContext; +import io.camunda.connector.api.outbound.OutboundConnectorFunction; +import io.camunda.connector.aws.s3.model.S3Request; +import io.camunda.connector.generator.java.annotation.ElementTemplate; + +@OutboundConnector( + name = "AWS S3", + inputVariables = {"authentication", "configuration"}, + type = "io.camunda:aws-s3:1") +@ElementTemplate( + id = "io.camunda.connectors.aws.s3.v1", + name = "AWS S3 Outbound Connector", + description = "Execute S3 requests", + inputDataClass = S3Request.class, + version = 1, + propertyGroups = { + @ElementTemplate.PropertyGroup(id = "authentication", label = "Authentication"), + @ElementTemplate.PropertyGroup(id = "configuration", label = "Configuration"), + }, + documentationRef = "https://docs.camunda.io/docs/", + icon = "icon.svg") +public class S3ConnectorFunction implements OutboundConnectorFunction { + + @Override + public Object execute(OutboundConnectorContext context) throws Exception { + return null; + } +} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java new file mode 100644 index 0000000000..7955a11b2a --- /dev/null +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java @@ -0,0 +1,5 @@ +package io.camunda.connector.aws.s3.model; + +import io.camunda.connector.aws.model.impl.AwsBaseRequest; + +public class S3Request extends AwsBaseRequest {} diff --git a/connectors/aws/aws-s3/src/main/resources/META-INF/services/io.camunda.connector.api.outbound.OutboundConnectorFunction b/connectors/aws/aws-s3/src/main/resources/META-INF/services/io.camunda.connector.api.outbound.OutboundConnectorFunction new file mode 100644 index 0000000000..132adea638 --- /dev/null +++ b/connectors/aws/aws-s3/src/main/resources/META-INF/services/io.camunda.connector.api.outbound.OutboundConnectorFunction @@ -0,0 +1 @@ +io.camunda.connector.aws.s3.S3ConnectorFunction \ No newline at end of file diff --git a/connectors/pom.xml b/connectors/pom.xml index b6016f0e38..c3cc5f2cd2 100644 --- a/connectors/pom.xml +++ b/connectors/pom.xml @@ -32,6 +32,7 @@ soap webhook idp-extraction + aws/aws-s3 From bbd529ef04601138d403c5bc1c4e0e18c9d45b6b Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Tue, 3 Dec 2024 09:36:24 +0100 Subject: [PATCH 02/13] feature(s3-connector): checkpoint s3 connector --- .../io/camunda/connector/aws/s3/model/DeleteS3Action.java | 4 ++++ .../io/camunda/connector/aws/s3/model/DownloadS3Action.java | 3 +++ .../main/java/io/camunda/connector/aws/s3/model/S3Action.java | 3 +++ .../io/camunda/connector/aws/s3/model/UploadS3Action.java | 3 +++ 4 files changed, 13 insertions(+) create mode 100644 connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java create mode 100644 connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java create mode 100644 connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java create mode 100644 connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java new file mode 100644 index 0000000000..3480392969 --- /dev/null +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java @@ -0,0 +1,4 @@ +package io.camunda.connector.aws.s3.model; + +public class DeleteS3Action { +} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java new file mode 100644 index 0000000000..31f9a76f40 --- /dev/null +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java @@ -0,0 +1,3 @@ +package io.camunda.connector.aws.s3.model; + +public final class UploadS3Action implements S3Action {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java new file mode 100644 index 0000000000..74113d2d09 --- /dev/null +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java @@ -0,0 +1,3 @@ +package io.camunda.connector.aws.s3.model; + +public sealed interface S3Data {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java new file mode 100644 index 0000000000..967d1b0606 --- /dev/null +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java @@ -0,0 +1,3 @@ +package io.camunda.connector.aws.s3.model; + +public final class DeleteS3Action implements S3Action {} From 7a5253922874d674e4fedc0196a74d76d0073085 Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Tue, 3 Dec 2024 09:39:43 +0100 Subject: [PATCH 03/13] feature(s3-connector): checkpoint s3 connector --- .../connector/aws/s3/S3ConnectorFunction.java | 4 ++++ .../aws/s3/model/DeleteS3Action.java | 3 +-- .../aws/s3/model/DownloadS3Action.java | 2 +- .../connector/aws/s3/model/S3Action.java | 11 ++++++++- .../connector/aws/s3/model/S3Request.java | 23 ++++++++++++++++++- .../aws/s3/model/UploadS3Action.java | 2 +- 6 files changed, 39 insertions(+), 6 deletions(-) diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java index 0708d0068d..68859967be 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java @@ -19,6 +19,10 @@ propertyGroups = { @ElementTemplate.PropertyGroup(id = "authentication", label = "Authentication"), @ElementTemplate.PropertyGroup(id = "configuration", label = "Configuration"), + @ElementTemplate.PropertyGroup(id = "action", label = "Action"), + @ElementTemplate.PropertyGroup(id = "deleteObject", label = "Delete an object"), + @ElementTemplate.PropertyGroup(id = "uploadObject", label = "Upload an object"), + @ElementTemplate.PropertyGroup(id = "downloadObject", label = "Download an object"), }, documentationRef = "https://docs.camunda.io/docs/", icon = "icon.svg") diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java index 3480392969..967d1b0606 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java @@ -1,4 +1,3 @@ package io.camunda.connector.aws.s3.model; -public class DeleteS3Action { -} +public final class DeleteS3Action implements S3Action {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java index 31f9a76f40..30c448c27d 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java @@ -1,3 +1,3 @@ package io.camunda.connector.aws.s3.model; -public final class UploadS3Action implements S3Action {} +public final class DownloadS3Action implements S3Action {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java index 74113d2d09..220df5ee84 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java @@ -1,3 +1,12 @@ package io.camunda.connector.aws.s3.model; -public sealed interface S3Data {} +import io.camunda.connector.generator.java.annotation.TemplateDiscriminatorProperty; +import io.camunda.connector.generator.java.annotation.TemplateSubType; + +@TemplateDiscriminatorProperty( + label = "Action", + group = "action", + name = "action", + defaultValue = "uploadObject") +@TemplateSubType(id = "action", label = "Action") +public sealed interface S3Action permits DeleteS3Action, DownloadS3Action, UploadS3Action {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java index 7955a11b2a..8c645ac042 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java @@ -1,5 +1,26 @@ package io.camunda.connector.aws.s3.model; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import io.camunda.connector.aws.model.impl.AwsBaseRequest; +import io.camunda.connector.generator.java.annotation.NestedProperties; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; -public class S3Request extends AwsBaseRequest {} +public class S3Request extends AwsBaseRequest { + + @JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.EXTERNAL_PROPERTY, + property = "action") + @JsonSubTypes( + value = { + @JsonSubTypes.Type(value = DeleteS3Action.class, name = "deleteObject"), + @JsonSubTypes.Type(value = UploadS3Action.class, name = "uploadObject"), + @JsonSubTypes.Type(value = DownloadS3Action.class, name = "downloadObject"), + }) + @Valid + @NotNull + @NestedProperties(addNestedPath = false) + private S3Action data; +} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java index 967d1b0606..31f9a76f40 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java @@ -1,3 +1,3 @@ package io.camunda.connector.aws.s3.model; -public final class DeleteS3Action implements S3Action {} +public final class UploadS3Action implements S3Action {} From 58c4e3dd15aa52ca221e99b8800b96b31f531fce Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Tue, 3 Dec 2024 10:50:30 +0100 Subject: [PATCH 04/13] feature(s3-connector): checkpoint s3 connector --- .../connector/aws/s3/S3ConnectorFunction.java | 8 ++++- .../aws/s3/model/DeleteS3Action.java | 34 ++++++++++++++++++- .../aws/s3/model/DownloadS3Action.java | 34 ++++++++++++++++++- .../connector/aws/s3/model/S3Action.java | 6 ++++ .../connector/aws/s3/model/S3Request.java | 6 ++++ .../aws/s3/model/UploadS3Action.java | 10 +++++- 6 files changed, 94 insertions(+), 4 deletions(-) diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java index 68859967be..4d1fccf373 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java @@ -1,3 +1,9 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ package io.camunda.connector.aws.s3; import io.camunda.connector.api.annotation.OutboundConnector; @@ -19,7 +25,7 @@ propertyGroups = { @ElementTemplate.PropertyGroup(id = "authentication", label = "Authentication"), @ElementTemplate.PropertyGroup(id = "configuration", label = "Configuration"), - @ElementTemplate.PropertyGroup(id = "action", label = "Action"), + @ElementTemplate.PropertyGroup(id = "action", label = "Action t"), @ElementTemplate.PropertyGroup(id = "deleteObject", label = "Delete an object"), @ElementTemplate.PropertyGroup(id = "uploadObject", label = "Upload an object"), @ElementTemplate.PropertyGroup(id = "downloadObject", label = "Download an object"), diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java index 967d1b0606..23771a8cf2 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java @@ -1,3 +1,35 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ package io.camunda.connector.aws.s3.model; -public final class DeleteS3Action implements S3Action {} +import io.camunda.connector.generator.dsl.Property; +import io.camunda.connector.generator.java.annotation.TemplateProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +public record DeleteS3Action( + @TemplateProperty( + label = "AWS bucket", + id = "deleteActionBucket", + group = "deleteObject", + tooltip = "Bucket from where an object should be deleted", + feel = Property.FeelMode.optional, + binding = @TemplateProperty.PropertyBinding(name = "action.bucket")) + @Valid + @NotNull + String bucket, + @TemplateProperty( + label = "AWS key", + id = "deleteActionKey", + group = "deleteObject", + tooltip = "Key of the object which should be deleted", + feel = Property.FeelMode.optional, + binding = @TemplateProperty.PropertyBinding(name = "action.key")) + @Valid + @NotNull + String key) + implements S3Action {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java index 30c448c27d..42feee4642 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java @@ -1,3 +1,35 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ package io.camunda.connector.aws.s3.model; -public final class DownloadS3Action implements S3Action {} +import io.camunda.connector.generator.dsl.Property; +import io.camunda.connector.generator.java.annotation.TemplateProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +public record DownloadS3Action( + @TemplateProperty( + label = "AWS bucket", + id = "downloadActionBucket", + group = "downloadObject", + tooltip = "Bucket from where an object should be downloaded", + feel = Property.FeelMode.optional, + binding = @TemplateProperty.PropertyBinding(name = "action.bucket")) + @Valid + @NotNull + String bucket, + @TemplateProperty( + label = "AWS key", + id = "downloadActionKey", + group = "downloadObject", + tooltip = "Key of the object which should be download", + feel = Property.FeelMode.optional, + binding = @TemplateProperty.PropertyBinding(name = "action.key")) + @Valid + @NotNull + String key) + implements S3Action {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java index 220df5ee84..fe28d89da3 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java @@ -1,3 +1,9 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ package io.camunda.connector.aws.s3.model; import io.camunda.connector.generator.java.annotation.TemplateDiscriminatorProperty; diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java index 8c645ac042..4a05770288 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java @@ -1,3 +1,9 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ package io.camunda.connector.aws.s3.model; import com.fasterxml.jackson.annotation.JsonSubTypes; diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java index 31f9a76f40..1f0b817aca 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java @@ -1,3 +1,11 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ package io.camunda.connector.aws.s3.model; -public final class UploadS3Action implements S3Action {} +import io.camunda.document.Document; + +public record UploadS3Action(String bucket, Document document) implements S3Action {} From bc406ba9b361656eecb99da6615a4909b48a67c9 Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Wed, 4 Dec 2024 15:47:59 +0100 Subject: [PATCH 05/13] feature(s3-connector): checkpoint s3 connector 3 --- .../aws-s3-outbound-connector.json | 370 +++++++++++++++++ .../aws-s3-outbound-connector-hybrid.json | 375 ++++++++++++++++++ connectors/aws/aws-s3/pom.xml | 58 ++- .../connector/aws/s3/S3ConnectorFunction.java | 14 +- .../connector/aws/s3/core/S3Executor.java | 143 +++++++ .../aws/s3/model/DeleteS3Action.java | 2 + .../aws/s3/model/DownloadS3Action.java | 16 +- .../connector/aws/s3/model/S3Action.java | 2 +- .../connector/aws/s3/model/S3Request.java | 14 +- .../aws/s3/model/UploadS3Action.java | 39 +- .../aws/s3/response/DeleteResponse.java | 9 + .../aws/s3/response/DownloadResponse.java | 11 + .../aws/s3/response/UploadResponse.java | 9 + .../aws/aws-s3/src/main/resources/icon.svg | 34 ++ 14 files changed, 1081 insertions(+), 15 deletions(-) create mode 100644 connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json create mode 100644 connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json create mode 100644 connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java create mode 100644 connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DeleteResponse.java create mode 100644 connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DownloadResponse.java create mode 100644 connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/UploadResponse.java create mode 100644 connectors/aws/aws-s3/src/main/resources/icon.svg diff --git a/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json b/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json new file mode 100644 index 0000000000..aa48e9f275 --- /dev/null +++ b/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json @@ -0,0 +1,370 @@ +{ + "$schema" : "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json", + "name" : "AWS S3 Outbound Connector", + "id" : "io.camunda.connectors.aws.s3.v1", + "description" : "Execute S3 requests", + "documentationRef" : "https://docs.camunda.io/docs/", + "version" : 1, + "category" : { + "id" : "connectors", + "name" : "Connectors" + }, + "appliesTo" : [ "bpmn:Task" ], + "elementType" : { + "value" : "bpmn:ServiceTask" + }, + "groups" : [ { + "id" : "authentication", + "label" : "Authentication" + }, { + "id" : "configuration", + "label" : "Configuration" + }, { + "id" : "action", + "label" : "Action" + }, { + "id" : "deleteObject", + "label" : "Delete an object" + }, { + "id" : "uploadObject", + "label" : "Upload an object" + }, { + "id" : "downloadObject", + "label" : "Download an object" + }, { + "id" : "output", + "label" : "Output mapping" + }, { + "id" : "error", + "label" : "Error handling" + }, { + "id" : "retries", + "label" : "Retries" + } ], + "properties" : [ { + "value" : "io.camunda:aws-s3:1", + "binding" : { + "property" : "type", + "type" : "zeebe:taskDefinition" + }, + "type" : "Hidden" + }, { + "id" : "authentication.type", + "label" : "Authentication", + "description" : "Specify AWS authentication strategy. Learn more at the documentation page", + "value" : "credentials", + "group" : "authentication", + "binding" : { + "name" : "authentication.type", + "type" : "zeebe:input" + }, + "type" : "Dropdown", + "choices" : [ { + "name" : "Default Credentials Chain (Hybrid/Self-Managed only)", + "value" : "defaultCredentialsChain" + }, { + "name" : "Credentials", + "value" : "credentials" + } ] + }, { + "id" : "authentication.accessKey", + "label" : "Access key", + "description" : "Provide an IAM access key tailored to a user, equipped with the necessary permissions", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "authentication", + "binding" : { + "name" : "authentication.accessKey", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "authentication.type", + "equals" : "credentials", + "type" : "simple" + }, + "type" : "String" + }, { + "id" : "authentication.secretKey", + "label" : "Secret key", + "description" : "Provide a secret key of a user with permissions to invoke specified AWS Lambda function", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "authentication", + "binding" : { + "name" : "authentication.secretKey", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "authentication.type", + "equals" : "credentials", + "type" : "simple" + }, + "type" : "String" + }, { + "id" : "configuration.region", + "label" : "Region", + "description" : "Specify the AWS region", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "configuration", + "binding" : { + "name" : "configuration.region", + "type" : "zeebe:input" + }, + "type" : "String" + }, { + "id" : "configuration.endpoint", + "label" : "Endpoint", + "description" : "Specify endpoint if need to use custom endpoint", + "optional" : true, + "group" : "configuration", + "binding" : { + "name" : "configuration.endpoint", + "type" : "zeebe:input" + }, + "type" : "Hidden" + }, { + "id" : "actionDiscriminator", + "label" : "Action", + "value" : "uploadObject", + "group" : "action", + "binding" : { + "name" : "actionDiscriminator", + "type" : "zeebe:input" + }, + "type" : "Dropdown", + "choices" : [ { + "name" : "Delete document", + "value" : "deleteObject" + }, { + "name" : "Download document", + "value" : "downloadObject" + }, { + "name" : "Upload document", + "value" : "uploadObject" + } ] + }, { + "id" : "deleteActionBucket", + "label" : "AWS bucket", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "deleteObject", + "binding" : { + "name" : "action.bucket", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "deleteObject", + "type" : "simple" + }, + "tooltip" : "Bucket from where an object should be deleted", + "type" : "String" + }, { + "id" : "deleteActionKey", + "label" : "AWS key", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "deleteObject", + "binding" : { + "name" : "action.key", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "deleteObject", + "type" : "simple" + }, + "tooltip" : "Key of the object which should be deleted", + "type" : "String" + }, { + "id" : "uploadActionBucket", + "label" : "AWS bucket", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "uploadObject", + "binding" : { + "name" : "action.bucket", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "uploadObject", + "type" : "simple" + }, + "tooltip" : "Bucket from where an object should be uploaded", + "type" : "String" + }, { + "id" : "uploadActionKey", + "label" : "AWS key", + "optional" : true, + "feel" : "optional", + "group" : "uploadObject", + "binding" : { + "name" : "action.key", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "uploadObject", + "type" : "simple" + }, + "tooltip" : "Key of the uploaded object, if not given. The file name from the document metadata will be used", + "type" : "String" + }, { + "id" : "uploadActionDocument", + "label" : "Document", + "optional" : false, + "feel" : "required", + "group" : "uploadObject", + "binding" : { + "name" : "action.document", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "uploadObject", + "type" : "simple" + }, + "tooltip" : "Document to be uploaded on AWS S3", + "type" : "String" + }, { + "id" : "downloadActionBucket", + "label" : "AWS bucket", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "downloadObject", + "binding" : { + "name" : "action.bucket", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "downloadObject", + "type" : "simple" + }, + "tooltip" : "Bucket from where an object should be downloaded", + "type" : "String" + }, { + "id" : "downloadActionKey", + "label" : "AWS key", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "downloadObject", + "binding" : { + "name" : "action.key", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "downloadObject", + "type" : "simple" + }, + "tooltip" : "Key of the object which should be download", + "type" : "String" + }, { + "id" : "downloadActionAsFile", + "label" : "Create document", + "optional" : false, + "value" : true, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "downloadObject", + "binding" : { + "name" : "action.asFile", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "downloadObject", + "type" : "simple" + }, + "tooltip" : "....", + "type" : "Boolean" + }, { + "id" : "resultVariable", + "label" : "Result variable", + "description" : "Name of variable to store the response in", + "group" : "output", + "binding" : { + "key" : "resultVariable", + "type" : "zeebe:taskHeader" + }, + "type" : "String" + }, { + "id" : "resultExpression", + "label" : "Result expression", + "description" : "Expression to map the response into process variables", + "feel" : "required", + "group" : "output", + "binding" : { + "key" : "resultExpression", + "type" : "zeebe:taskHeader" + }, + "type" : "Text" + }, { + "id" : "errorExpression", + "label" : "Error expression", + "description" : "Expression to handle errors. Details in the documentation.", + "feel" : "required", + "group" : "error", + "binding" : { + "key" : "errorExpression", + "type" : "zeebe:taskHeader" + }, + "type" : "Text" + }, { + "id" : "retryCount", + "label" : "Retries", + "description" : "Number of retries", + "value" : "3", + "feel" : "optional", + "group" : "retries", + "binding" : { + "property" : "retries", + "type" : "zeebe:taskDefinition" + }, + "type" : "String" + }, { + "id" : "retryBackoff", + "label" : "Retry backoff", + "description" : "ISO-8601 duration to wait between retries", + "value" : "PT0S", + "feel" : "optional", + "group" : "retries", + "binding" : { + "key" : "retryBackoff", + "type" : "zeebe:taskHeader" + }, + "type" : "String" + } ], + "icon" : { + "contents" : "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MjgiIGhlaWdodD0iNTEyIiB2aWV3Qm94PSIwIDAgNDI4IDUxMiI+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5jbHMtMSB7CiAgICAgICAgZmlsbDogI2UyNTQ0NDsKICAgICAgfQoKICAgICAgLmNscy0xLCAuY2xzLTIsIC5jbHMtMyB7CiAgICAgICAgZmlsbC1ydWxlOiBldmVub2RkOwogICAgICB9CgogICAgICAuY2xzLTIgewogICAgICAgIGZpbGw6ICM3YjFkMTM7CiAgICAgIH0KCiAgICAgIC5jbHMtMyB7CiAgICAgICAgZmlsbDogIzU4MTUwZDsKICAgICAgfQogICAgPC9zdHlsZT4KICA8L2RlZnM+CiAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMzc4LDk5TDI5NSwyNTdsODMsMTU4LDM0LTE5VjExOFoiLz4KICA8cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0zNzgsOTlMMjEyLDExOCwxMjcuNSwyNTcsMjEyLDM5NmwxNjYsMTlWOTlaIi8+CiAgPHBhdGggY2xhc3M9ImNscy0zIiBkPSJNNDMsOTlMMTYsMTExVjQwM2wyNywxMkwyMTIsMjU3WiIvPgogIDxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTQyLjYzNyw5OC42NjdsMTY5LjU4Nyw0Ny4xMTFWMzcyLjQ0NEw0Mi42MzcsNDE1LjExMVY5OC42NjdaIi8+CiAgPHBhdGggY2xhc3M9ImNscy0zIiBkPSJNMjEyLjMxMywxNzAuNjY3bC03Mi4wMDgtMTEuNTU2LDcyLjAwOC04MS43NzgsNzEuODMsODEuNzc4WiIvPgogIDxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTI4NC4xNDMsMTU5LjExMWwtNzEuOTE5LDExLjczMy03MS45MTktMTEuNzMzVjc3LjMzMyIvPgogIDxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTIxMi4zMTMsMzQyLjIyMmwtNzIuMDA4LDEzLjMzNCw3Mi4wMDgsNzAuMjIyLDcxLjgzLTcwLjIyMloiLz4KICA8cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0yMTIsMTZMMTQwLDU0VjE1OWw3Mi4yMjQtMjAuMzMzWiIvPgogIDxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTIxMi4yMjQsMTk2LjQ0NGwtNzEuOTE5LDcuODIzVjMwOS4xMDVsNzEuOTE5LDguMjI4VjE5Ni40NDRaIi8+CiAgPHBhdGggY2xhc3M9ImNscy0yIiBkPSJNMjEyLjIyNCwzNzMuMzMzTDE0MC4zMDUsMzU1LjNWNDU4LjM2M0wyMTIuMjI0LDQ5NlYzNzMuMzMzWiIvPgogIDxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTI4NC4xNDMsMzU1LjNsLTcxLjkxOSwxOC4wMzhWNDk2bDcxLjkxOS0zNy42MzdWMzU1LjNaIi8+CiAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMjEyLjIyNCwxOTYuNDQ0bDcxLjkxOSw3LjgyM1YzMDkuMTA1bC03MS45MTksOC4yMjhWMTk2LjQ0NFoiLz4KICA8cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0yMTIsMTZsNzIsMzhWMTU5bC03Mi0yMFYxNloiLz4KPC9zdmc+Cg==" + } +} \ No newline at end of file diff --git a/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json b/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json new file mode 100644 index 0000000000..e23e6620e8 --- /dev/null +++ b/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json @@ -0,0 +1,375 @@ +{ + "$schema" : "https://unpkg.com/@camunda/zeebe-element-templates-json-schema/resources/schema.json", + "name" : "Hybrid AWS S3 Outbound Connector", + "id" : "io.camunda.connectors.aws.s3.v1-hybrid", + "description" : "Execute S3 requests", + "documentationRef" : "https://docs.camunda.io/docs/", + "version" : 1, + "category" : { + "id" : "connectors", + "name" : "Connectors" + }, + "appliesTo" : [ "bpmn:Task" ], + "elementType" : { + "value" : "bpmn:ServiceTask" + }, + "groups" : [ { + "id" : "taskDefinitionType", + "label" : "Task definition type" + }, { + "id" : "authentication", + "label" : "Authentication" + }, { + "id" : "configuration", + "label" : "Configuration" + }, { + "id" : "action", + "label" : "Action" + }, { + "id" : "deleteObject", + "label" : "Delete an object" + }, { + "id" : "uploadObject", + "label" : "Upload an object" + }, { + "id" : "downloadObject", + "label" : "Download an object" + }, { + "id" : "output", + "label" : "Output mapping" + }, { + "id" : "error", + "label" : "Error handling" + }, { + "id" : "retries", + "label" : "Retries" + } ], + "properties" : [ { + "id" : "taskDefinitionType", + "value" : "io.camunda:aws-s3:1", + "group" : "taskDefinitionType", + "binding" : { + "property" : "type", + "type" : "zeebe:taskDefinition" + }, + "type" : "String" + }, { + "id" : "authentication.type", + "label" : "Authentication", + "description" : "Specify AWS authentication strategy. Learn more at the documentation page", + "value" : "credentials", + "group" : "authentication", + "binding" : { + "name" : "authentication.type", + "type" : "zeebe:input" + }, + "type" : "Dropdown", + "choices" : [ { + "name" : "Default Credentials Chain (Hybrid/Self-Managed only)", + "value" : "defaultCredentialsChain" + }, { + "name" : "Credentials", + "value" : "credentials" + } ] + }, { + "id" : "authentication.accessKey", + "label" : "Access key", + "description" : "Provide an IAM access key tailored to a user, equipped with the necessary permissions", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "authentication", + "binding" : { + "name" : "authentication.accessKey", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "authentication.type", + "equals" : "credentials", + "type" : "simple" + }, + "type" : "String" + }, { + "id" : "authentication.secretKey", + "label" : "Secret key", + "description" : "Provide a secret key of a user with permissions to invoke specified AWS Lambda function", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "authentication", + "binding" : { + "name" : "authentication.secretKey", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "authentication.type", + "equals" : "credentials", + "type" : "simple" + }, + "type" : "String" + }, { + "id" : "configuration.region", + "label" : "Region", + "description" : "Specify the AWS region", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "configuration", + "binding" : { + "name" : "configuration.region", + "type" : "zeebe:input" + }, + "type" : "String" + }, { + "id" : "configuration.endpoint", + "label" : "Endpoint", + "description" : "Specify endpoint if need to use custom endpoint", + "optional" : true, + "group" : "configuration", + "binding" : { + "name" : "configuration.endpoint", + "type" : "zeebe:input" + }, + "type" : "Hidden" + }, { + "id" : "actionDiscriminator", + "label" : "Action", + "value" : "uploadObject", + "group" : "action", + "binding" : { + "name" : "actionDiscriminator", + "type" : "zeebe:input" + }, + "type" : "Dropdown", + "choices" : [ { + "name" : "Delete document", + "value" : "deleteObject" + }, { + "name" : "Download document", + "value" : "downloadObject" + }, { + "name" : "Upload document", + "value" : "uploadObject" + } ] + }, { + "id" : "deleteActionBucket", + "label" : "AWS bucket", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "deleteObject", + "binding" : { + "name" : "action.bucket", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "deleteObject", + "type" : "simple" + }, + "tooltip" : "Bucket from where an object should be deleted", + "type" : "String" + }, { + "id" : "deleteActionKey", + "label" : "AWS key", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "deleteObject", + "binding" : { + "name" : "action.key", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "deleteObject", + "type" : "simple" + }, + "tooltip" : "Key of the object which should be deleted", + "type" : "String" + }, { + "id" : "uploadActionBucket", + "label" : "AWS bucket", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "uploadObject", + "binding" : { + "name" : "action.bucket", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "uploadObject", + "type" : "simple" + }, + "tooltip" : "Bucket from where an object should be uploaded", + "type" : "String" + }, { + "id" : "uploadActionKey", + "label" : "AWS key", + "optional" : true, + "feel" : "optional", + "group" : "uploadObject", + "binding" : { + "name" : "action.key", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "uploadObject", + "type" : "simple" + }, + "tooltip" : "Key of the uploaded object, if not given. The file name from the document metadata will be used", + "type" : "String" + }, { + "id" : "uploadActionDocument", + "label" : "Document", + "optional" : false, + "feel" : "required", + "group" : "uploadObject", + "binding" : { + "name" : "action.document", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "uploadObject", + "type" : "simple" + }, + "tooltip" : "Document to be uploaded on AWS S3", + "type" : "String" + }, { + "id" : "downloadActionBucket", + "label" : "AWS bucket", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "downloadObject", + "binding" : { + "name" : "action.bucket", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "downloadObject", + "type" : "simple" + }, + "tooltip" : "Bucket from where an object should be downloaded", + "type" : "String" + }, { + "id" : "downloadActionKey", + "label" : "AWS key", + "optional" : false, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "downloadObject", + "binding" : { + "name" : "action.key", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "downloadObject", + "type" : "simple" + }, + "tooltip" : "Key of the object which should be download", + "type" : "String" + }, { + "id" : "downloadActionAsFile", + "label" : "Create document", + "optional" : false, + "value" : true, + "constraints" : { + "notEmpty" : true + }, + "feel" : "optional", + "group" : "downloadObject", + "binding" : { + "name" : "action.asFile", + "type" : "zeebe:input" + }, + "condition" : { + "property" : "actionDiscriminator", + "equals" : "downloadObject", + "type" : "simple" + }, + "tooltip" : "....", + "type" : "Boolean" + }, { + "id" : "resultVariable", + "label" : "Result variable", + "description" : "Name of variable to store the response in", + "group" : "output", + "binding" : { + "key" : "resultVariable", + "type" : "zeebe:taskHeader" + }, + "type" : "String" + }, { + "id" : "resultExpression", + "label" : "Result expression", + "description" : "Expression to map the response into process variables", + "feel" : "required", + "group" : "output", + "binding" : { + "key" : "resultExpression", + "type" : "zeebe:taskHeader" + }, + "type" : "Text" + }, { + "id" : "errorExpression", + "label" : "Error expression", + "description" : "Expression to handle errors. Details in the documentation.", + "feel" : "required", + "group" : "error", + "binding" : { + "key" : "errorExpression", + "type" : "zeebe:taskHeader" + }, + "type" : "Text" + }, { + "id" : "retryCount", + "label" : "Retries", + "description" : "Number of retries", + "value" : "3", + "feel" : "optional", + "group" : "retries", + "binding" : { + "property" : "retries", + "type" : "zeebe:taskDefinition" + }, + "type" : "String" + }, { + "id" : "retryBackoff", + "label" : "Retry backoff", + "description" : "ISO-8601 duration to wait between retries", + "value" : "PT0S", + "feel" : "optional", + "group" : "retries", + "binding" : { + "key" : "retryBackoff", + "type" : "zeebe:taskHeader" + }, + "type" : "String" + } ], + "icon" : { + "contents" : "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MjgiIGhlaWdodD0iNTEyIiB2aWV3Qm94PSIwIDAgNDI4IDUxMiI+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5jbHMtMSB7CiAgICAgICAgZmlsbDogI2UyNTQ0NDsKICAgICAgfQoKICAgICAgLmNscy0xLCAuY2xzLTIsIC5jbHMtMyB7CiAgICAgICAgZmlsbC1ydWxlOiBldmVub2RkOwogICAgICB9CgogICAgICAuY2xzLTIgewogICAgICAgIGZpbGw6ICM3YjFkMTM7CiAgICAgIH0KCiAgICAgIC5jbHMtMyB7CiAgICAgICAgZmlsbDogIzU4MTUwZDsKICAgICAgfQogICAgPC9zdHlsZT4KICA8L2RlZnM+CiAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMzc4LDk5TDI5NSwyNTdsODMsMTU4LDM0LTE5VjExOFoiLz4KICA8cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0zNzgsOTlMMjEyLDExOCwxMjcuNSwyNTcsMjEyLDM5NmwxNjYsMTlWOTlaIi8+CiAgPHBhdGggY2xhc3M9ImNscy0zIiBkPSJNNDMsOTlMMTYsMTExVjQwM2wyNywxMkwyMTIsMjU3WiIvPgogIDxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTQyLjYzNyw5OC42NjdsMTY5LjU4Nyw0Ny4xMTFWMzcyLjQ0NEw0Mi42MzcsNDE1LjExMVY5OC42NjdaIi8+CiAgPHBhdGggY2xhc3M9ImNscy0zIiBkPSJNMjEyLjMxMywxNzAuNjY3bC03Mi4wMDgtMTEuNTU2LDcyLjAwOC04MS43NzgsNzEuODMsODEuNzc4WiIvPgogIDxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTI4NC4xNDMsMTU5LjExMWwtNzEuOTE5LDExLjczMy03MS45MTktMTEuNzMzVjc3LjMzMyIvPgogIDxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTIxMi4zMTMsMzQyLjIyMmwtNzIuMDA4LDEzLjMzNCw3Mi4wMDgsNzAuMjIyLDcxLjgzLTcwLjIyMloiLz4KICA8cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0yMTIsMTZMMTQwLDU0VjE1OWw3Mi4yMjQtMjAuMzMzWiIvPgogIDxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTIxMi4yMjQsMTk2LjQ0NGwtNzEuOTE5LDcuODIzVjMwOS4xMDVsNzEuOTE5LDguMjI4VjE5Ni40NDRaIi8+CiAgPHBhdGggY2xhc3M9ImNscy0yIiBkPSJNMjEyLjIyNCwzNzMuMzMzTDE0MC4zMDUsMzU1LjNWNDU4LjM2M0wyMTIuMjI0LDQ5NlYzNzMuMzMzWiIvPgogIDxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTI4NC4xNDMsMzU1LjNsLTcxLjkxOSwxOC4wMzhWNDk2bDcxLjkxOS0zNy42MzdWMzU1LjNaIi8+CiAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMjEyLjIyNCwxOTYuNDQ0bDcxLjkxOSw3LjgyM1YzMDkuMTA1bC03MS45MTksOC4yMjhWMTk2LjQ0NFoiLz4KICA8cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0yMTIsMTZsNzIsMzhWMTU5bC03Mi0yMFYxNloiLz4KPC9zdmc+Cg==" + } +} \ No newline at end of file diff --git a/connectors/aws/aws-s3/pom.xml b/connectors/aws/aws-s3/pom.xml index e4c437dde1..ed716ceee4 100644 --- a/connectors/aws/aws-s3/pom.xml +++ b/connectors/aws/aws-s3/pom.xml @@ -3,6 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 + io.camunda.connector connectors-parent @@ -10,13 +11,22 @@ ../../pom.xml - aws-s3 + connector-aws-s3 + Camunda Connector AWS S3 + connector-aws-s3 + jar - - 21 - 21 - UTF-8 - + + + Camunda Self-Managed Free Edition license + + https://camunda.com/legal/terms/cloud-terms-and-conditions/camunda-cloud-self-managed-free-edition-terms/ + + + + Camunda Self-Managed Enterprise Edition license + + @@ -24,7 +34,43 @@ connector-aws-base ${project.version} + + software.amazon.awssdk + s3 + ${version.software-aws-java-sdk} + + + software.amazon.awssdk + s3-transfer-manager + ${version.software-aws-java-sdk} + + + + + io.camunda.connector + element-template-generator-maven-plugin + ${project.version} + + + + io.camunda.connector.aws.s3.S3ConnectorFunction + + + io.camunda.connectors.aws.s3.v1 + aws-s3-outbound-connector.json + + + true + + + + io.camunda.connector:connector-aws-base + + + + + \ No newline at end of file diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java index 4d1fccf373..cbaa3a7c8b 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java @@ -9,12 +9,16 @@ import io.camunda.connector.api.annotation.OutboundConnector; import io.camunda.connector.api.outbound.OutboundConnectorContext; import io.camunda.connector.api.outbound.OutboundConnectorFunction; +import io.camunda.connector.aws.s3.core.S3Executor; import io.camunda.connector.aws.s3.model.S3Request; import io.camunda.connector.generator.java.annotation.ElementTemplate; +import io.camunda.document.Document; +import io.camunda.document.store.DocumentCreationRequest; +import java.util.function.Function; @OutboundConnector( name = "AWS S3", - inputVariables = {"authentication", "configuration"}, + inputVariables = {"authentication", "configuration", "actionDiscriminator", "action"}, type = "io.camunda:aws-s3:1") @ElementTemplate( id = "io.camunda.connectors.aws.s3.v1", @@ -25,7 +29,7 @@ propertyGroups = { @ElementTemplate.PropertyGroup(id = "authentication", label = "Authentication"), @ElementTemplate.PropertyGroup(id = "configuration", label = "Configuration"), - @ElementTemplate.PropertyGroup(id = "action", label = "Action t"), + @ElementTemplate.PropertyGroup(id = "action", label = "Action"), @ElementTemplate.PropertyGroup(id = "deleteObject", label = "Delete an object"), @ElementTemplate.PropertyGroup(id = "uploadObject", label = "Upload an object"), @ElementTemplate.PropertyGroup(id = "downloadObject", label = "Download an object"), @@ -35,7 +39,9 @@ public class S3ConnectorFunction implements OutboundConnectorFunction { @Override - public Object execute(OutboundConnectorContext context) throws Exception { - return null; + public Object execute(OutboundConnectorContext context) { + Function createDocument = context::createDocument; + S3Request s3Request = context.bindVariables(S3Request.class); + return S3Executor.create(s3Request, createDocument).execute(s3Request.getData()); } } diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java new file mode 100644 index 0000000000..bfa92cb407 --- /dev/null +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java @@ -0,0 +1,143 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ +package io.camunda.connector.aws.s3.core; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.connector.aws.CredentialsProviderSupportV2; +import io.camunda.connector.aws.s3.model.*; +import io.camunda.connector.aws.s3.response.DeleteResponse; +import io.camunda.connector.aws.s3.response.DownloadResponse; +import io.camunda.connector.aws.s3.response.UploadResponse; +import io.camunda.document.Document; +import io.camunda.document.store.DocumentCreationRequest; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Optional; +import java.util.function.Function; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; + +public class S3Executor { + + private static final Logger log = LoggerFactory.getLogger(S3Executor.class); + private final S3Client s3Client; + private final Function createDocument; + + public S3Executor( + S3Request s3Request, Function createDocument) { + this.s3Client = + S3Client.builder() + .credentialsProvider(CredentialsProviderSupportV2.credentialsProvider(s3Request)) + .region(Region.of(s3Request.getConfiguration().region())) + .build(); + this.createDocument = createDocument; + } + + public static S3Executor create( + S3Request s3Request, Function createDocument) { + return new S3Executor(s3Request, createDocument); + } + + public Object execute(S3Action s3Action) { + return switch (s3Action) { + case DeleteS3Action deleteS3Action -> delete(deleteS3Action); + case DownloadS3Action downloadS3Action -> download(downloadS3Action); + case UploadS3Action uploadS3Action -> upload(uploadS3Action); + }; + } + + private Object upload(UploadS3Action uploadS3Action) { + Long contentLength = uploadS3Action.document().metadata().getSize(); + String contentType = uploadS3Action.document().metadata().getContentType(); + + PutObjectRequest putObjectRequest = + PutObjectRequest.builder() + .bucket(uploadS3Action.bucket()) + .key( + Optional.ofNullable(uploadS3Action.key()) + .orElse(uploadS3Action.document().metadata().getFileName())) + .contentLength(contentLength) + .contentType(contentType) + .build(); + + this.s3Client.putObject( + putObjectRequest, + RequestBody.fromInputStream(uploadS3Action.document().asInputStream(), contentLength)); + + return new UploadResponse( + uploadS3Action.bucket(), + uploadS3Action.key(), + String.format( + "https://%s.s3.amazonaws.com/%s", uploadS3Action.bucket(), uploadS3Action.key())); + } + + private DownloadResponse download(DownloadS3Action downloadS3Action) { + GetObjectRequest getObjectRequest = + GetObjectRequest.builder() + .bucket(downloadS3Action.bucket()) + .key(downloadS3Action.key()) + .build(); + + ResponseInputStream getObjectResponse = + this.s3Client.getObject(getObjectRequest); + + if (!downloadS3Action.asFile()) { + try { + return retrieveResponseWithContent( + downloadS3Action.bucket(), downloadS3Action.key(), getObjectResponse); + } catch (IOException e) { + log.error("An error occurred while trying to read and parse the downloaded file", e); + throw new RuntimeException(e); + } + } else { + return this.createDocument + .andThen( + document -> + new DownloadResponse( + downloadS3Action.bucket(), downloadS3Action.key(), document, null)) + .apply( + DocumentCreationRequest.from(getObjectResponse) + .contentType(getObjectResponse.response().contentType()) + .fileName(downloadS3Action.key()) + .build()); + } + } + + private DownloadResponse retrieveResponseWithContent( + String bucket, String key, ResponseInputStream responseResponseInputStream) + throws IOException { + byte[] rawBytes = responseResponseInputStream.readAllBytes(); + return switch (responseResponseInputStream.response().contentType()) { + case "text/plain" -> + new DownloadResponse(bucket, key, null, new String(rawBytes, StandardCharsets.UTF_8)); + case "application/json" -> + new DownloadResponse(bucket, key, null, new ObjectMapper().readTree(rawBytes)); + default -> + new DownloadResponse(bucket, key, null, Base64.getEncoder().encodeToString(rawBytes)); + }; + } + + private DeleteResponse delete(DeleteS3Action deleteS3Action) { + DeleteObjectRequest deleteObjectRequest = + DeleteObjectRequest.builder() + .bucket(deleteS3Action.bucket()) + .key(deleteS3Action.key()) + .build(); + + this.s3Client.deleteObject(deleteObjectRequest); + return new DeleteResponse(deleteS3Action.bucket(), deleteS3Action.key()); + } +} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java index 23771a8cf2..0e9f2b053f 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java @@ -8,9 +8,11 @@ import io.camunda.connector.generator.dsl.Property; import io.camunda.connector.generator.java.annotation.TemplateProperty; +import io.camunda.connector.generator.java.annotation.TemplateSubType; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; +@TemplateSubType(id = "deleteObject", label = "Delete document") public record DeleteS3Action( @TemplateProperty( label = "AWS bucket", diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java index 42feee4642..49ea2d2a88 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java @@ -8,9 +8,11 @@ import io.camunda.connector.generator.dsl.Property; import io.camunda.connector.generator.java.annotation.TemplateProperty; +import io.camunda.connector.generator.java.annotation.TemplateSubType; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; +@TemplateSubType(id = "downloadObject", label = "Download document") public record DownloadS3Action( @TemplateProperty( label = "AWS bucket", @@ -31,5 +33,17 @@ public record DownloadS3Action( binding = @TemplateProperty.PropertyBinding(name = "action.key")) @Valid @NotNull - String key) + String key, + @TemplateProperty( + label = "Create document", + id = "downloadActionAsFile", + group = "downloadObject", + tooltip = "....", + type = TemplateProperty.PropertyType.Boolean, + defaultValueType = TemplateProperty.DefaultValueType.Boolean, + defaultValue = "true", + binding = @TemplateProperty.PropertyBinding(name = "action.asFile")) + @Valid + @NotNull + boolean asFile) implements S3Action {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java index fe28d89da3..84de7d4238 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java @@ -12,7 +12,7 @@ @TemplateDiscriminatorProperty( label = "Action", group = "action", - name = "action", + name = "actionDiscriminator", defaultValue = "uploadObject") @TemplateSubType(id = "action", label = "Action") public sealed interface S3Action permits DeleteS3Action, DownloadS3Action, UploadS3Action {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java index 4a05770288..c13e31f97a 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java @@ -18,7 +18,7 @@ public class S3Request extends AwsBaseRequest { @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, - property = "action") + property = "actionDiscriminator") @JsonSubTypes( value = { @JsonSubTypes.Type(value = DeleteS3Action.class, name = "deleteObject"), @@ -28,5 +28,15 @@ public class S3Request extends AwsBaseRequest { @Valid @NotNull @NestedProperties(addNestedPath = false) - private S3Action data; + private S3Action action; + + public S3Request() {} + + public S3Action getData() { + return action; + } + + public void setData(S3Action data) { + this.action = data; + } } diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java index 1f0b817aca..7fd49c88e8 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java @@ -6,6 +6,43 @@ */ package io.camunda.connector.aws.s3.model; +import io.camunda.connector.generator.dsl.Property; +import io.camunda.connector.generator.java.annotation.TemplateProperty; +import io.camunda.connector.generator.java.annotation.TemplateSubType; import io.camunda.document.Document; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; -public record UploadS3Action(String bucket, Document document) implements S3Action {} +@TemplateSubType(id = "uploadObject", label = "Upload document") +public record UploadS3Action( + @TemplateProperty( + label = "AWS bucket", + id = "uploadActionBucket", + group = "uploadObject", + tooltip = "Bucket from where an object should be uploaded", + feel = Property.FeelMode.optional, + binding = @TemplateProperty.PropertyBinding(name = "action.bucket")) + @Valid + @NotNull + String bucket, + @TemplateProperty( + label = "AWS key", + id = "uploadActionKey", + group = "uploadObject", + tooltip = + "Key of the uploaded object, if not given. The file name from the document metadata will be used", + optional = true, + feel = Property.FeelMode.optional, + binding = @TemplateProperty.PropertyBinding(name = "action.key")) + @Valid + String key, + @TemplateProperty( + label = "Document", + group = "uploadObject", + id = "uploadActionDocument", + tooltip = "Document to be uploaded on AWS S3", + type = TemplateProperty.PropertyType.String, + feel = Property.FeelMode.required, + binding = @TemplateProperty.PropertyBinding(name = "action.document")) + Document document) + implements S3Action {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DeleteResponse.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DeleteResponse.java new file mode 100644 index 0000000000..93bb9958fa --- /dev/null +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DeleteResponse.java @@ -0,0 +1,9 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ +package io.camunda.connector.aws.s3.response; + +public record DeleteResponse(String bucket, String key) {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DownloadResponse.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DownloadResponse.java new file mode 100644 index 0000000000..de252ee3d6 --- /dev/null +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DownloadResponse.java @@ -0,0 +1,11 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ +package io.camunda.connector.aws.s3.response; + +import io.camunda.document.Document; + +public record DownloadResponse(String bucket, String key, Document document, Object content) {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/UploadResponse.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/UploadResponse.java new file mode 100644 index 0000000000..688942d0a1 --- /dev/null +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/UploadResponse.java @@ -0,0 +1,9 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ +package io.camunda.connector.aws.s3.response; + +public record UploadResponse(String bucket, String key, String link) {} diff --git a/connectors/aws/aws-s3/src/main/resources/icon.svg b/connectors/aws/aws-s3/src/main/resources/icon.svg new file mode 100644 index 0000000000..3f63be51fa --- /dev/null +++ b/connectors/aws/aws-s3/src/main/resources/icon.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + From c773f264c1f0e85eea814294c6f3405ff171f883 Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Wed, 4 Dec 2024 15:49:28 +0100 Subject: [PATCH 06/13] feature(s3-connector): checkpoint s3 connector; pom commit --- connectors/aws/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/connectors/aws/pom.xml b/connectors/aws/pom.xml index bd2cc77c92..77c3845741 100644 --- a/connectors/aws/pom.xml +++ b/connectors/aws/pom.xml @@ -27,6 +27,7 @@ aws-bedrock aws-comprehend aws-textract + aws-s3 From 1491a7730a69be42b37746550118aafd3af1519f Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Wed, 4 Dec 2024 15:49:42 +0100 Subject: [PATCH 07/13] feature(s3-connector): checkpoint s3 connector; pom commit --- bundle/default-bundle/pom.xml | 4 ++++ bundle/pom.xml | 5 +++++ .../client/jakarta/utils/JakartaUtils.java | 20 ++++++++++++++----- connectors/pom.xml | 1 - 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/bundle/default-bundle/pom.xml b/bundle/default-bundle/pom.xml index 20e6852152..d125eaa4a2 100644 --- a/bundle/default-bundle/pom.xml +++ b/bundle/default-bundle/pom.xml @@ -37,6 +37,10 @@ io.camunda.connector connector-aws-bedrock + + io.camunda.connector + connector-aws-s3 + io.camunda.connector connector-aws-textract diff --git a/bundle/pom.xml b/bundle/pom.xml index ec364f3c57..b87a055f53 100644 --- a/bundle/pom.xml +++ b/bundle/pom.xml @@ -144,6 +144,11 @@ connector-aws-sagemaker ${project.version} + + io.camunda.connector + connector-aws-s3 + ${project.version} + io.camunda.connector connector-email diff --git a/connectors/email/src/main/java/io/camunda/connector/email/client/jakarta/utils/JakartaUtils.java b/connectors/email/src/main/java/io/camunda/connector/email/client/jakarta/utils/JakartaUtils.java index aa1e8ccb55..ef904daba4 100644 --- a/connectors/email/src/main/java/io/camunda/connector/email/client/jakarta/utils/JakartaUtils.java +++ b/connectors/email/src/main/java/io/camunda/connector/email/client/jakarta/utils/JakartaUtils.java @@ -20,8 +20,10 @@ import io.camunda.connector.email.outbound.protocols.actions.SortFieldPop3; import io.camunda.connector.email.outbound.protocols.actions.SortOrder; import jakarta.mail.*; +import jakarta.mail.internet.ContentType; import jakarta.mail.internet.MimeMultipart; import jakarta.validation.constraints.NotNull; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.time.OffsetDateTime; @@ -32,9 +34,9 @@ public class JakartaUtils { + public static final String HTML_CHARSET = "text/html; charset=utf-8"; private static final Logger LOGGER = LoggerFactory.getLogger(JakartaUtils.class); private static final String REGEX_PATH_SPLITTER = "[./]"; - public static final String HTML_CHARSET = "text/html; charset=utf-8"; public Session createSession(Configuration configuration) { return Session.getInstance( @@ -282,11 +284,19 @@ private void processBodyPart( throws MessagingException, IOException { BodyPart bodyPart = multipart.getBodyPart(i); switch (bodyPart.getContent()) { - case InputStream attachment when bodyPart - .getDisposition() - .equalsIgnoreCase(Part.ATTACHMENT) -> + case InputStream attachment when Part.ATTACHMENT.equalsIgnoreCase( + bodyPart.getDisposition()) -> + emailBodyBuilder.addAttachment( + new EmailAttachment( + attachment, + bodyPart.getFileName(), + new ContentType(bodyPart.getContentType()).getBaseType())); + case String textAttachment when Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition()) -> emailBodyBuilder.addAttachment( - new EmailAttachment(attachment, bodyPart.getFileName(), bodyPart.getContentType())); + new EmailAttachment( + new ByteArrayInputStream(textAttachment.getBytes()), + bodyPart.getFileName(), + new ContentType(bodyPart.getContentType()).getBaseType())); case String plainText when bodyPart.isMimeType("text/plain") -> emailBodyBuilder.withBodyAsPlainText(plainText); case String html when bodyPart.isMimeType("text/html") -> diff --git a/connectors/pom.xml b/connectors/pom.xml index c3cc5f2cd2..b6016f0e38 100644 --- a/connectors/pom.xml +++ b/connectors/pom.xml @@ -32,7 +32,6 @@ soap webhook idp-extraction - aws/aws-s3 From 491244c07436b4c3ab7d73706811e26e0b184df5 Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Wed, 4 Dec 2024 17:29:29 +0100 Subject: [PATCH 08/13] feature(s3-connector): all features done --- .../connector/aws/s3/core/S3Executor.java | 16 +- .../io/camunda/connector/aws/s3/BaseTest.java | 65 +++++++ .../aws/s3/S3ConnectorFunctionTest.java | 79 +++++++++ .../connector/aws/s3/core/S3ExecutorTest.java | 162 ++++++++++++++++++ .../actions/deleteActionsExample.json | 15 ++ .../actions/downloadActionsExample.json | 18 ++ .../actions/uploadActionsExample.json | 22 +++ 7 files changed, 369 insertions(+), 8 deletions(-) create mode 100644 connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/BaseTest.java create mode 100644 connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java create mode 100644 connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java create mode 100644 connectors/aws/aws-s3/src/test/resources/actions/deleteActionsExample.json create mode 100644 connectors/aws/aws-s3/src/test/resources/actions/downloadActionsExample.json create mode 100644 connectors/aws/aws-s3/src/test/resources/actions/uploadActionsExample.json diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java index bfa92cb407..e17e5bacab 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java @@ -36,19 +36,19 @@ public class S3Executor { private final S3Client s3Client; private final Function createDocument; - public S3Executor( - S3Request s3Request, Function createDocument) { - this.s3Client = - S3Client.builder() - .credentialsProvider(CredentialsProviderSupportV2.credentialsProvider(s3Request)) - .region(Region.of(s3Request.getConfiguration().region())) - .build(); + public S3Executor(S3Client s3Client, Function createDocument) { + this.s3Client = s3Client; this.createDocument = createDocument; } public static S3Executor create( S3Request s3Request, Function createDocument) { - return new S3Executor(s3Request, createDocument); + return new S3Executor( + S3Client.builder() + .credentialsProvider(CredentialsProviderSupportV2.credentialsProvider(s3Request)) + .region(Region.of(s3Request.getConfiguration().region())) + .build(), + createDocument); } public Object execute(S3Action s3Action) { diff --git a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/BaseTest.java b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/BaseTest.java new file mode 100644 index 0000000000..0941fd87d7 --- /dev/null +++ b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/BaseTest.java @@ -0,0 +1,65 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ +package io.camunda.connector.aws.s3; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.file.Files.readString; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.camunda.connector.api.json.ConnectorsObjectMapperSupplier; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.stream.Stream; +import org.junit.jupiter.params.provider.Arguments; + +public class BaseTest { + + public static Stream loadUploadActionVariables() { + try { + return loadTestCasesFromResourceFile("src/test/resources/actions/uploadActionsExample.json"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static Stream loadDownloadActionVariables() { + try { + return loadTestCasesFromResourceFile( + "src/test/resources/actions/downloadActionsExample.json"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static Stream loadDeleteActionVariables() { + try { + return loadTestCasesFromResourceFile("src/test/resources/actions/deleteActionsExample.json"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + protected static Stream loadTestCasesFromResourceFile(final String fileWithTestCasesUri) + throws IOException { + final String cases = readString(new File(fileWithTestCasesUri).toPath(), UTF_8); + final ObjectMapper mapper = ConnectorsObjectMapperSupplier.getCopy(); + var array = mapper.readValue(cases, ArrayList.class); + return array.stream() + .map( + value -> { + try { + return mapper.writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + }) + .map(Arguments::of); + } +} diff --git a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java new file mode 100644 index 0000000000..9bd8a160c9 --- /dev/null +++ b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java @@ -0,0 +1,79 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ +package io.camunda.connector.aws.s3; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import io.camunda.connector.aws.s3.core.S3Executor; +import io.camunda.connector.aws.s3.response.DeleteResponse; +import io.camunda.connector.aws.s3.response.DownloadResponse; +import io.camunda.connector.aws.s3.response.UploadResponse; +import io.camunda.connector.test.outbound.OutboundConnectorContextBuilder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +class S3ConnectorFunctionTest extends BaseTest { + + @ParameterizedTest + @MethodSource("loadUploadActionVariables") + void executeUploadActionReturnsCorrectResult(String variables) { + + var bedrockConnectorFunction = new S3ConnectorFunction(); + var context = OutboundConnectorContextBuilder.create().variables(variables).build(); + + var s3Executor = Mockito.mock(S3Executor.class); + + try (MockedStatic s3ExecutorMockedStatic = Mockito.mockStatic(S3Executor.class)) { + s3ExecutorMockedStatic.when(() -> S3Executor.create(any(), any())).thenReturn(s3Executor); + when(s3Executor.execute(any())).thenReturn(new UploadResponse("test", "test", "link")); + var response = bedrockConnectorFunction.execute(context); + Assertions.assertNotNull(response); + Assertions.assertInstanceOf(UploadResponse.class, response); + } + } + + @ParameterizedTest + @MethodSource("loadDownloadActionVariables") + void executeDownloadActionReturnsCorrectResult(String variables) { + + var bedrockConnectorFunction = new S3ConnectorFunction(); + var context = OutboundConnectorContextBuilder.create().variables(variables).build(); + + var s3Executor = Mockito.mock(S3Executor.class); + + try (MockedStatic s3ExecutorMockedStatic = Mockito.mockStatic(S3Executor.class)) { + s3ExecutorMockedStatic.when(() -> S3Executor.create(any(), any())).thenReturn(s3Executor); + when(s3Executor.execute(any())).thenReturn(new DownloadResponse("test", "test", null, null)); + var response = bedrockConnectorFunction.execute(context); + Assertions.assertNotNull(response); + Assertions.assertInstanceOf(DownloadResponse.class, response); + } + } + + @ParameterizedTest + @MethodSource("loadDeleteActionVariables") + void executeDeleteActionReturnsCorrectResult(String variables) { + + var bedrockConnectorFunction = new S3ConnectorFunction(); + var context = OutboundConnectorContextBuilder.create().variables(variables).build(); + + var s3Executor = Mockito.mock(S3Executor.class); + + try (MockedStatic s3ExecutorMockedStatic = Mockito.mockStatic(S3Executor.class)) { + s3ExecutorMockedStatic.when(() -> S3Executor.create(any(), any())).thenReturn(s3Executor); + when(s3Executor.execute(any())).thenReturn(new DeleteResponse("test", "test")); + var response = bedrockConnectorFunction.execute(context); + Assertions.assertNotNull(response); + Assertions.assertInstanceOf(DeleteResponse.class, response); + } + } +} diff --git a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java new file mode 100644 index 0000000000..16a09eb64c --- /dev/null +++ b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java @@ -0,0 +1,162 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ +package io.camunda.connector.aws.s3.core; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import io.camunda.connector.aws.s3.model.DeleteS3Action; +import io.camunda.connector.aws.s3.model.DownloadS3Action; +import io.camunda.connector.aws.s3.model.S3Action; +import io.camunda.connector.aws.s3.model.UploadS3Action; +import io.camunda.connector.aws.s3.response.DeleteResponse; +import io.camunda.connector.aws.s3.response.DownloadResponse; +import io.camunda.connector.aws.s3.response.UploadResponse; +import io.camunda.document.Document; +import io.camunda.document.store.DocumentCreationRequest; +import java.io.IOException; +import java.util.Base64; +import java.util.function.Function; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.core.ResponseInputStream; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; + +class S3ExecutorTest { + + @Test + void executeDeleteAction() { + S3Client s3Client = mock(S3Client.class); + Function function = doc -> mock(Document.class); + S3Executor executor = new S3Executor(s3Client, function); + S3Action s3Action = new DeleteS3Action("test", "key"); + + Object object = executor.execute(s3Action); + + verify(s3Client, times(1)).deleteObject(any(DeleteObjectRequest.class)); + assertInstanceOf(DeleteResponse.class, object); + } + + @Test + void executeUploadAction() { + S3Client s3Client = mock(S3Client.class); + Function function = doc -> mock(Document.class); + S3Executor executor = new S3Executor(s3Client, function); + Document document = mock(Document.class, RETURNS_DEEP_STUBS); + S3Action s3Action = new UploadS3Action("test", "key", document); + + when(document.metadata().getSize()).thenReturn(42L); + when(document.metadata().getContentType()).thenReturn("application/octet-stream"); + + Object object = executor.execute(s3Action); + + verify(s3Client, times(1)).putObject(any(PutObjectRequest.class), any(RequestBody.class)); + assertInstanceOf(UploadResponse.class, object); + } + + @Test + void executeDownloadAsDocumentAction() { + + S3Client s3Client = mock(S3Client.class); + Function function = doc -> mock(Document.class); + S3Executor executor = new S3Executor(s3Client, function); + ResponseInputStream responseInputStream = mock(ResponseInputStream.class); + GetObjectResponse getObjectResponse = mock(GetObjectResponse.class); + S3Action s3Action = new DownloadS3Action("test", "key", true); + + when(s3Client.getObject(any(GetObjectRequest.class))).thenReturn(responseInputStream); + when(responseInputStream.response()).thenReturn(getObjectResponse); + when(getObjectResponse.contentType()).thenReturn("application/octet-stream"); + Object object = executor.execute(s3Action); + + verify(s3Client, times(1)).getObject(any(GetObjectRequest.class)); + assertInstanceOf(DownloadResponse.class, object); + assertNull(((DownloadResponse) object).content()); + assertNotNull(((DownloadResponse) object).document()); + } + + @Test + void executeDownloadAsTextContentAction() throws IOException { + + S3Client s3Client = mock(S3Client.class); + Function function = doc -> mock(Document.class); + S3Executor executor = new S3Executor(s3Client, function); + ResponseInputStream responseInputStream = mock(ResponseInputStream.class); + GetObjectResponse getObjectResponse = mock(GetObjectResponse.class); + S3Action s3Action = new DownloadS3Action("test", "key", false); + + when(s3Client.getObject(any(GetObjectRequest.class))).thenReturn(responseInputStream); + when(responseInputStream.response()).thenReturn(getObjectResponse); + when(responseInputStream.readAllBytes()).thenReturn("Hello World".getBytes()); + when(getObjectResponse.contentLength()).thenReturn(234L); + when(getObjectResponse.contentType()).thenReturn("text/plain"); + Object object = executor.execute(s3Action); + + verify(s3Client, times(1)).getObject(any(GetObjectRequest.class)); + assertInstanceOf(DownloadResponse.class, object); + assertNotNull(((DownloadResponse) object).content()); + assertNull(((DownloadResponse) object).document()); + assertEquals("Hello World", ((DownloadResponse) object).content()); + } + + @Test + void executeDownloadAsJsonContentAction() throws IOException { + + S3Client s3Client = mock(S3Client.class); + Function function = doc -> mock(Document.class); + S3Executor executor = new S3Executor(s3Client, function); + ResponseInputStream responseInputStream = mock(ResponseInputStream.class); + GetObjectResponse getObjectResponse = mock(GetObjectResponse.class); + S3Action s3Action = new DownloadS3Action("test", "key", false); + + when(s3Client.getObject(any(GetObjectRequest.class))).thenReturn(responseInputStream); + when(responseInputStream.response()).thenReturn(getObjectResponse); + when(responseInputStream.readAllBytes()).thenReturn("{ \"Hello\" : \"World\" }".getBytes()); + when(getObjectResponse.contentLength()).thenReturn(234L); + when(getObjectResponse.contentType()).thenReturn("application/json"); + Object object = executor.execute(s3Action); + + verify(s3Client, times(1)).getObject(any(GetObjectRequest.class)); + assertInstanceOf(DownloadResponse.class, object); + DownloadResponse downloadResponse = (DownloadResponse) object; + assertNotNull(downloadResponse.content()); + assertNull(downloadResponse.document()); + assertEquals("World", ((ObjectNode) downloadResponse.content()).get("Hello").asText()); + } + + @Test + void executeDownloadAsBase64BytesContentAction() throws IOException { + + S3Client s3Client = mock(S3Client.class); + Function function = doc -> mock(Document.class); + S3Executor executor = new S3Executor(s3Client, function); + ResponseInputStream responseInputStream = mock(ResponseInputStream.class); + GetObjectResponse getObjectResponse = mock(GetObjectResponse.class); + S3Action s3Action = new DownloadS3Action("test", "key", false); + + when(s3Client.getObject(any(GetObjectRequest.class))).thenReturn(responseInputStream); + when(responseInputStream.response()).thenReturn(getObjectResponse); + when(responseInputStream.readAllBytes()).thenReturn("Hello".getBytes()); + when(getObjectResponse.contentLength()).thenReturn(234L); + when(getObjectResponse.contentType()).thenReturn("application/octet-stream"); + Object object = executor.execute(s3Action); + + verify(s3Client, times(1)).getObject(any(GetObjectRequest.class)); + assertInstanceOf(DownloadResponse.class, object); + DownloadResponse downloadResponse = (DownloadResponse) object; + assertNotNull(downloadResponse.content()); + assertNull(downloadResponse.document()); + assertEquals( + Base64.getEncoder().encodeToString("Hello".getBytes()), downloadResponse.content()); + } +} diff --git a/connectors/aws/aws-s3/src/test/resources/actions/deleteActionsExample.json b/connectors/aws/aws-s3/src/test/resources/actions/deleteActionsExample.json new file mode 100644 index 0000000000..3f0e048cb0 --- /dev/null +++ b/connectors/aws/aws-s3/src/test/resources/actions/deleteActionsExample.json @@ -0,0 +1,15 @@ +[ + { + "action":{ + "bucket":"connector-aws-s3-test", + "key":"test" + }, "configuration":{ + "region":"eu-central-1" + }, + "authentication":{ + "type":"credentials", + "accessKey":"test", + "secretKey":"test" + }, "actionDiscriminator":"deleteObject" + } +] \ No newline at end of file diff --git a/connectors/aws/aws-s3/src/test/resources/actions/downloadActionsExample.json b/connectors/aws/aws-s3/src/test/resources/actions/downloadActionsExample.json new file mode 100644 index 0000000000..e90a965984 --- /dev/null +++ b/connectors/aws/aws-s3/src/test/resources/actions/downloadActionsExample.json @@ -0,0 +1,18 @@ +[ + { + "action":{ + "bucket":"connector-aws-s3-test", + "key":"attachment", + "asFile":false + }, + "configuration":{ + "region":"eu-central-1" + }, + "authentication":{ + "type":"credentials", + "accessKey":"test", + "secretKey":"test" + }, + "actionDiscriminator":"downloadObject" + } +] \ No newline at end of file diff --git a/connectors/aws/aws-s3/src/test/resources/actions/uploadActionsExample.json b/connectors/aws/aws-s3/src/test/resources/actions/uploadActionsExample.json new file mode 100644 index 0000000000..ea23c5dd78 --- /dev/null +++ b/connectors/aws/aws-s3/src/test/resources/actions/uploadActionsExample.json @@ -0,0 +1,22 @@ +[ + { + "action":{ + "bucket":"connector-aws-s3-test", + "key":"attachment", + "document":{ + "storeId":"in-memory", + "documentId":"41d2a87f-f39c-4ddd-a116-18d2091cc695", + "metadata":{ + "contentType":"text/plain", "size":41730, + "fileName":"test.txt" + }, + "documentType":"camunda" + } + }, "configuration":{"region":"eu-central-1"}, + "authentication":{ + "type":"credentials", + "accessKey":"test", + "secretKey":"test" + }, "actionDiscriminator":"uploadObject" + } +] \ No newline at end of file From 42db6b90187e7c8eff5a993634e9cd6e4424ded2 Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Wed, 11 Dec 2024 09:35:03 +0100 Subject: [PATCH 09/13] feature(s3-connector): correcting after Jonathan comments --- .../connector/aws/s3/S3ConnectorFunction.java | 4 ++-- .../connector/aws/s3/core/S3Executor.java | 10 +++++----- .../model/{ => request}/DeleteS3Action.java | 11 ++++------- .../model/{ => request}/DownloadS3Action.java | 16 ++++++---------- .../aws/s3/model/{ => request}/S3Action.java | 2 +- .../aws/s3/model/{ => request}/S3Request.java | 2 +- .../model/{ => request}/UploadS3Action.java | 10 ++++------ .../{ => model}/response/DeleteResponse.java | 2 +- .../response/DownloadResponse.java | 2 +- .../{ => model}/response/UploadResponse.java | 2 +- .../aws/s3/S3ConnectorFunctionTest.java | 19 +++++++++---------- .../connector/aws/s3/core/S3ExecutorTest.java | 14 +++++++------- 12 files changed, 42 insertions(+), 52 deletions(-) rename connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/{ => request}/DeleteS3Action.java (87%) rename connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/{ => request}/DownloadS3Action.java (84%) rename connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/{ => request}/S3Action.java (93%) rename connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/{ => request}/S3Request.java (96%) rename connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/{ => request}/UploadS3Action.java (91%) rename connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/{ => model}/response/DeleteResponse.java (87%) rename connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/{ => model}/response/DownloadResponse.java (89%) rename connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/{ => model}/response/UploadResponse.java (87%) diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java index cbaa3a7c8b..1555881850 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java @@ -10,7 +10,7 @@ import io.camunda.connector.api.outbound.OutboundConnectorContext; import io.camunda.connector.api.outbound.OutboundConnectorFunction; import io.camunda.connector.aws.s3.core.S3Executor; -import io.camunda.connector.aws.s3.model.S3Request; +import io.camunda.connector.aws.s3.model.request.S3Request; import io.camunda.connector.generator.java.annotation.ElementTemplate; import io.camunda.document.Document; import io.camunda.document.store.DocumentCreationRequest; @@ -34,7 +34,7 @@ @ElementTemplate.PropertyGroup(id = "uploadObject", label = "Upload an object"), @ElementTemplate.PropertyGroup(id = "downloadObject", label = "Download an object"), }, - documentationRef = "https://docs.camunda.io/docs/", + documentationRef = "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/aws-s3/", icon = "icon.svg") public class S3ConnectorFunction implements OutboundConnectorFunction { diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java index e17e5bacab..18b56a0721 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java @@ -8,10 +8,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.camunda.connector.aws.CredentialsProviderSupportV2; -import io.camunda.connector.aws.s3.model.*; -import io.camunda.connector.aws.s3.response.DeleteResponse; -import io.camunda.connector.aws.s3.response.DownloadResponse; -import io.camunda.connector.aws.s3.response.UploadResponse; +import io.camunda.connector.aws.s3.model.request.*; +import io.camunda.connector.aws.s3.model.response.DeleteResponse; +import io.camunda.connector.aws.s3.model.response.DownloadResponse; +import io.camunda.connector.aws.s3.model.response.UploadResponse; import io.camunda.document.Document; import io.camunda.document.store.DocumentCreationRequest; import java.io.IOException; @@ -42,7 +42,7 @@ public S3Executor(S3Client s3Client, Function } public static S3Executor create( - S3Request s3Request, Function createDocument) { + S3Request s3Request, Function createDocument) { return new S3Executor( S3Client.builder() .credentialsProvider(CredentialsProviderSupportV2.credentialsProvider(s3Request)) diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DeleteS3Action.java similarity index 87% rename from connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java rename to connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DeleteS3Action.java index 0e9f2b053f..1f37eb9a1c 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DeleteS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DeleteS3Action.java @@ -4,13 +4,12 @@ * See the License.txt file for more information. You may not use this file * except in compliance with the proprietary license. */ -package io.camunda.connector.aws.s3.model; +package io.camunda.connector.aws.s3.model.request; import io.camunda.connector.generator.dsl.Property; import io.camunda.connector.generator.java.annotation.TemplateProperty; import io.camunda.connector.generator.java.annotation.TemplateSubType; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; @TemplateSubType(id = "deleteObject", label = "Delete document") public record DeleteS3Action( @@ -21,8 +20,7 @@ public record DeleteS3Action( tooltip = "Bucket from where an object should be deleted", feel = Property.FeelMode.optional, binding = @TemplateProperty.PropertyBinding(name = "action.bucket")) - @Valid - @NotNull + @NotBlank String bucket, @TemplateProperty( label = "AWS key", @@ -31,7 +29,6 @@ public record DeleteS3Action( tooltip = "Key of the object which should be deleted", feel = Property.FeelMode.optional, binding = @TemplateProperty.PropertyBinding(name = "action.key")) - @Valid - @NotNull + @NotBlank String key) implements S3Action {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DownloadS3Action.java similarity index 84% rename from connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java rename to connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DownloadS3Action.java index 49ea2d2a88..738d303a05 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/DownloadS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DownloadS3Action.java @@ -4,13 +4,12 @@ * See the License.txt file for more information. You may not use this file * except in compliance with the proprietary license. */ -package io.camunda.connector.aws.s3.model; +package io.camunda.connector.aws.s3.model.request; import io.camunda.connector.generator.dsl.Property; import io.camunda.connector.generator.java.annotation.TemplateProperty; import io.camunda.connector.generator.java.annotation.TemplateSubType; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; @TemplateSubType(id = "downloadObject", label = "Download document") public record DownloadS3Action( @@ -21,8 +20,7 @@ public record DownloadS3Action( tooltip = "Bucket from where an object should be downloaded", feel = Property.FeelMode.optional, binding = @TemplateProperty.PropertyBinding(name = "action.bucket")) - @Valid - @NotNull + @NotBlank String bucket, @TemplateProperty( label = "AWS key", @@ -31,19 +29,17 @@ public record DownloadS3Action( tooltip = "Key of the object which should be download", feel = Property.FeelMode.optional, binding = @TemplateProperty.PropertyBinding(name = "action.key")) - @Valid - @NotNull + @NotBlank String key, @TemplateProperty( label = "Create document", id = "downloadActionAsFile", group = "downloadObject", - tooltip = "....", + tooltip = + "If set to true, a document reference will be created. If set to false, the content will be extracted and provided inside the response.", type = TemplateProperty.PropertyType.Boolean, defaultValueType = TemplateProperty.DefaultValueType.Boolean, defaultValue = "true", binding = @TemplateProperty.PropertyBinding(name = "action.asFile")) - @Valid - @NotNull boolean asFile) implements S3Action {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Action.java similarity index 93% rename from connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java rename to connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Action.java index 84de7d4238..7a9343d963 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Action.java @@ -4,7 +4,7 @@ * See the License.txt file for more information. You may not use this file * except in compliance with the proprietary license. */ -package io.camunda.connector.aws.s3.model; +package io.camunda.connector.aws.s3.model.request; import io.camunda.connector.generator.java.annotation.TemplateDiscriminatorProperty; import io.camunda.connector.generator.java.annotation.TemplateSubType; diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Request.java similarity index 96% rename from connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java rename to connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Request.java index c13e31f97a..017d7fc80b 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/S3Request.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Request.java @@ -4,7 +4,7 @@ * See the License.txt file for more information. You may not use this file * except in compliance with the proprietary license. */ -package io.camunda.connector.aws.s3.model; +package io.camunda.connector.aws.s3.model.request; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadS3Action.java similarity index 91% rename from connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java rename to connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadS3Action.java index 7fd49c88e8..0d9697cbba 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/UploadS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadS3Action.java @@ -4,14 +4,13 @@ * See the License.txt file for more information. You may not use this file * except in compliance with the proprietary license. */ -package io.camunda.connector.aws.s3.model; +package io.camunda.connector.aws.s3.model.request; import io.camunda.connector.generator.dsl.Property; import io.camunda.connector.generator.java.annotation.TemplateProperty; import io.camunda.connector.generator.java.annotation.TemplateSubType; import io.camunda.document.Document; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; @TemplateSubType(id = "uploadObject", label = "Upload document") public record UploadS3Action( @@ -22,8 +21,7 @@ public record UploadS3Action( tooltip = "Bucket from where an object should be uploaded", feel = Property.FeelMode.optional, binding = @TemplateProperty.PropertyBinding(name = "action.bucket")) - @Valid - @NotNull + @NotBlank String bucket, @TemplateProperty( label = "AWS key", @@ -34,7 +32,7 @@ public record UploadS3Action( optional = true, feel = Property.FeelMode.optional, binding = @TemplateProperty.PropertyBinding(name = "action.key")) - @Valid + @NotBlank String key, @TemplateProperty( label = "Document", diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DeleteResponse.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DeleteResponse.java similarity index 87% rename from connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DeleteResponse.java rename to connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DeleteResponse.java index 93bb9958fa..94499db2bc 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DeleteResponse.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DeleteResponse.java @@ -4,6 +4,6 @@ * See the License.txt file for more information. You may not use this file * except in compliance with the proprietary license. */ -package io.camunda.connector.aws.s3.response; +package io.camunda.connector.aws.s3.model.response; public record DeleteResponse(String bucket, String key) {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DownloadResponse.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DownloadResponse.java similarity index 89% rename from connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DownloadResponse.java rename to connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DownloadResponse.java index de252ee3d6..33fb8b3ba3 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/DownloadResponse.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DownloadResponse.java @@ -4,7 +4,7 @@ * See the License.txt file for more information. You may not use this file * except in compliance with the proprietary license. */ -package io.camunda.connector.aws.s3.response; +package io.camunda.connector.aws.s3.model.response; import io.camunda.document.Document; diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/UploadResponse.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/UploadResponse.java similarity index 87% rename from connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/UploadResponse.java rename to connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/UploadResponse.java index 688942d0a1..f2125e6079 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/response/UploadResponse.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/UploadResponse.java @@ -4,6 +4,6 @@ * See the License.txt file for more information. You may not use this file * except in compliance with the proprietary license. */ -package io.camunda.connector.aws.s3.response; +package io.camunda.connector.aws.s3.model.response; public record UploadResponse(String bucket, String key, String link) {} diff --git a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java index 9bd8a160c9..475b9d2fe1 100644 --- a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java +++ b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java @@ -6,14 +6,13 @@ */ package io.camunda.connector.aws.s3; -import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import io.camunda.connector.aws.s3.core.S3Executor; -import io.camunda.connector.aws.s3.response.DeleteResponse; -import io.camunda.connector.aws.s3.response.DownloadResponse; -import io.camunda.connector.aws.s3.response.UploadResponse; +import io.camunda.connector.aws.s3.model.response.DeleteResponse; +import io.camunda.connector.aws.s3.model.response.DownloadResponse; +import io.camunda.connector.aws.s3.model.response.UploadResponse; import io.camunda.connector.test.outbound.OutboundConnectorContextBuilder; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; @@ -27,7 +26,7 @@ class S3ConnectorFunctionTest extends BaseTest { @MethodSource("loadUploadActionVariables") void executeUploadActionReturnsCorrectResult(String variables) { - var bedrockConnectorFunction = new S3ConnectorFunction(); + var s3ConnectorFunction = new S3ConnectorFunction(); var context = OutboundConnectorContextBuilder.create().variables(variables).build(); var s3Executor = Mockito.mock(S3Executor.class); @@ -35,7 +34,7 @@ void executeUploadActionReturnsCorrectResult(String variables) { try (MockedStatic s3ExecutorMockedStatic = Mockito.mockStatic(S3Executor.class)) { s3ExecutorMockedStatic.when(() -> S3Executor.create(any(), any())).thenReturn(s3Executor); when(s3Executor.execute(any())).thenReturn(new UploadResponse("test", "test", "link")); - var response = bedrockConnectorFunction.execute(context); + var response = s3ConnectorFunction.execute(context); Assertions.assertNotNull(response); Assertions.assertInstanceOf(UploadResponse.class, response); } @@ -45,7 +44,7 @@ void executeUploadActionReturnsCorrectResult(String variables) { @MethodSource("loadDownloadActionVariables") void executeDownloadActionReturnsCorrectResult(String variables) { - var bedrockConnectorFunction = new S3ConnectorFunction(); + var s3ConnectorFunction = new S3ConnectorFunction(); var context = OutboundConnectorContextBuilder.create().variables(variables).build(); var s3Executor = Mockito.mock(S3Executor.class); @@ -53,7 +52,7 @@ void executeDownloadActionReturnsCorrectResult(String variables) { try (MockedStatic s3ExecutorMockedStatic = Mockito.mockStatic(S3Executor.class)) { s3ExecutorMockedStatic.when(() -> S3Executor.create(any(), any())).thenReturn(s3Executor); when(s3Executor.execute(any())).thenReturn(new DownloadResponse("test", "test", null, null)); - var response = bedrockConnectorFunction.execute(context); + var response = s3ConnectorFunction.execute(context); Assertions.assertNotNull(response); Assertions.assertInstanceOf(DownloadResponse.class, response); } @@ -63,7 +62,7 @@ void executeDownloadActionReturnsCorrectResult(String variables) { @MethodSource("loadDeleteActionVariables") void executeDeleteActionReturnsCorrectResult(String variables) { - var bedrockConnectorFunction = new S3ConnectorFunction(); + var s3ConnectorFunction = new S3ConnectorFunction(); var context = OutboundConnectorContextBuilder.create().variables(variables).build(); var s3Executor = Mockito.mock(S3Executor.class); @@ -71,7 +70,7 @@ void executeDeleteActionReturnsCorrectResult(String variables) { try (MockedStatic s3ExecutorMockedStatic = Mockito.mockStatic(S3Executor.class)) { s3ExecutorMockedStatic.when(() -> S3Executor.create(any(), any())).thenReturn(s3Executor); when(s3Executor.execute(any())).thenReturn(new DeleteResponse("test", "test")); - var response = bedrockConnectorFunction.execute(context); + var response = s3ConnectorFunction.execute(context); Assertions.assertNotNull(response); Assertions.assertInstanceOf(DeleteResponse.class, response); } diff --git a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java index 16a09eb64c..43f60625ba 100644 --- a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java +++ b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java @@ -11,13 +11,13 @@ import static org.mockito.Mockito.*; import com.fasterxml.jackson.databind.node.ObjectNode; -import io.camunda.connector.aws.s3.model.DeleteS3Action; -import io.camunda.connector.aws.s3.model.DownloadS3Action; -import io.camunda.connector.aws.s3.model.S3Action; -import io.camunda.connector.aws.s3.model.UploadS3Action; -import io.camunda.connector.aws.s3.response.DeleteResponse; -import io.camunda.connector.aws.s3.response.DownloadResponse; -import io.camunda.connector.aws.s3.response.UploadResponse; +import io.camunda.connector.aws.s3.model.request.DeleteS3Action; +import io.camunda.connector.aws.s3.model.request.DownloadS3Action; +import io.camunda.connector.aws.s3.model.request.S3Action; +import io.camunda.connector.aws.s3.model.request.UploadS3Action; +import io.camunda.connector.aws.s3.model.response.DeleteResponse; +import io.camunda.connector.aws.s3.model.response.DownloadResponse; +import io.camunda.connector.aws.s3.model.response.UploadResponse; import io.camunda.document.Document; import io.camunda.document.store.DocumentCreationRequest; import java.io.IOException; From 3f3b3c664fdc9b6a4911e71033e9e3dec87f7a25 Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Wed, 11 Dec 2024 12:33:17 +0100 Subject: [PATCH 10/13] feature(s3-connector): minor corrections --- .../element-templates/aws-s3-outbound-connector.json | 11 +++++------ .../hybrid/aws-s3-outbound-connector-hybrid.json | 11 +++++------ .../camunda/connector/aws/s3/S3ConnectorFunction.java | 3 ++- .../io/camunda/connector/aws/s3/core/S3Executor.java | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json b/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json index aa48e9f275..1c2e0b02fa 100644 --- a/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json +++ b/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json @@ -3,7 +3,7 @@ "name" : "AWS S3 Outbound Connector", "id" : "io.camunda.connectors.aws.s3.v1", "description" : "Execute S3 requests", - "documentationRef" : "https://docs.camunda.io/docs/", + "documentationRef" : "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/aws-s3/", "version" : 1, "category" : { "id" : "connectors", @@ -216,6 +216,9 @@ "id" : "uploadActionKey", "label" : "AWS key", "optional" : true, + "constraints" : { + "notEmpty" : true + }, "feel" : "optional", "group" : "uploadObject", "binding" : { @@ -291,9 +294,6 @@ "label" : "Create document", "optional" : false, "value" : true, - "constraints" : { - "notEmpty" : true - }, "feel" : "optional", "group" : "downloadObject", "binding" : { @@ -305,7 +305,7 @@ "equals" : "downloadObject", "type" : "simple" }, - "tooltip" : "....", + "tooltip" : "If set to true, a document reference will be created. If set to false, the content will be extracted and provided inside the response.", "type" : "Boolean" }, { "id" : "resultVariable", @@ -356,7 +356,6 @@ "label" : "Retry backoff", "description" : "ISO-8601 duration to wait between retries", "value" : "PT0S", - "feel" : "optional", "group" : "retries", "binding" : { "key" : "retryBackoff", diff --git a/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json b/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json index e23e6620e8..a33b5ab9d7 100644 --- a/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json +++ b/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json @@ -3,7 +3,7 @@ "name" : "Hybrid AWS S3 Outbound Connector", "id" : "io.camunda.connectors.aws.s3.v1-hybrid", "description" : "Execute S3 requests", - "documentationRef" : "https://docs.camunda.io/docs/", + "documentationRef" : "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/aws-s3/", "version" : 1, "category" : { "id" : "connectors", @@ -221,6 +221,9 @@ "id" : "uploadActionKey", "label" : "AWS key", "optional" : true, + "constraints" : { + "notEmpty" : true + }, "feel" : "optional", "group" : "uploadObject", "binding" : { @@ -296,9 +299,6 @@ "label" : "Create document", "optional" : false, "value" : true, - "constraints" : { - "notEmpty" : true - }, "feel" : "optional", "group" : "downloadObject", "binding" : { @@ -310,7 +310,7 @@ "equals" : "downloadObject", "type" : "simple" }, - "tooltip" : "....", + "tooltip" : "If set to true, a document reference will be created. If set to false, the content will be extracted and provided inside the response.", "type" : "Boolean" }, { "id" : "resultVariable", @@ -361,7 +361,6 @@ "label" : "Retry backoff", "description" : "ISO-8601 duration to wait between retries", "value" : "PT0S", - "feel" : "optional", "group" : "retries", "binding" : { "key" : "retryBackoff", diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java index 1555881850..0ec57a3538 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java @@ -34,7 +34,8 @@ @ElementTemplate.PropertyGroup(id = "uploadObject", label = "Upload an object"), @ElementTemplate.PropertyGroup(id = "downloadObject", label = "Download an object"), }, - documentationRef = "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/aws-s3/", + documentationRef = + "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/aws-s3/", icon = "icon.svg") public class S3ConnectorFunction implements OutboundConnectorFunction { diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java index 18b56a0721..6e554402c4 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java @@ -42,7 +42,7 @@ public S3Executor(S3Client s3Client, Function } public static S3Executor create( - S3Request s3Request, Function createDocument) { + S3Request s3Request, Function createDocument) { return new S3Executor( S3Client.builder() .credentialsProvider(CredentialsProviderSupportV2.credentialsProvider(s3Request)) From 0a9c23f602e2574dfc84d097af7b3c6f447655ba Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Wed, 18 Dec 2024 11:14:30 +0100 Subject: [PATCH 11/13] feature(s3-connector): minor corrections before rebase --- .../connector/aws/s3/S3ConnectorFunction.java | 2 +- .../connector/aws/s3/core/S3Executor.java | 37 +++++++++++-------- .../aws/s3/model/request/S3Action.java | 2 +- .../aws/s3/model/request/S3Request.java | 8 ++-- ...{UploadS3Action.java => UploadObject.java} | 4 +- .../s3/model/response/DownloadResponse.java | 3 +- .../aws/s3/model/response/Element.java | 11 ++++++ .../aws/s3/S3ConnectorFunctionTest.java | 2 +- .../connector/aws/s3/core/S3ExecutorTest.java | 24 ++++++------ 9 files changed, 53 insertions(+), 40 deletions(-) rename connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/{UploadS3Action.java => UploadObject.java} (95%) create mode 100644 connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/Element.java diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java index 0ec57a3538..83211e6426 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/S3ConnectorFunction.java @@ -43,6 +43,6 @@ public class S3ConnectorFunction implements OutboundConnectorFunction { public Object execute(OutboundConnectorContext context) { Function createDocument = context::createDocument; S3Request s3Request = context.bindVariables(S3Request.class); - return S3Executor.create(s3Request, createDocument).execute(s3Request.getData()); + return S3Executor.create(s3Request, createDocument).execute(s3Request.getAction()); } } diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java index 6e554402c4..9b0e842212 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java @@ -11,6 +11,7 @@ import io.camunda.connector.aws.s3.model.request.*; import io.camunda.connector.aws.s3.model.response.DeleteResponse; import io.camunda.connector.aws.s3.model.response.DownloadResponse; +import io.camunda.connector.aws.s3.model.response.Element; import io.camunda.connector.aws.s3.model.response.UploadResponse; import io.camunda.document.Document; import io.camunda.document.store.DocumentCreationRequest; @@ -55,33 +56,32 @@ public Object execute(S3Action s3Action) { return switch (s3Action) { case DeleteS3Action deleteS3Action -> delete(deleteS3Action); case DownloadS3Action downloadS3Action -> download(downloadS3Action); - case UploadS3Action uploadS3Action -> upload(uploadS3Action); + case UploadObject uploadObject -> upload(uploadObject); }; } - private Object upload(UploadS3Action uploadS3Action) { - Long contentLength = uploadS3Action.document().metadata().getSize(); - String contentType = uploadS3Action.document().metadata().getContentType(); + private Object upload(UploadObject uploadObject) { + Long contentLength = uploadObject.document().metadata().getSize(); + String contentType = uploadObject.document().metadata().getContentType(); PutObjectRequest putObjectRequest = PutObjectRequest.builder() - .bucket(uploadS3Action.bucket()) + .bucket(uploadObject.bucket()) .key( - Optional.ofNullable(uploadS3Action.key()) - .orElse(uploadS3Action.document().metadata().getFileName())) + Optional.ofNullable(uploadObject.key()) + .orElse(uploadObject.document().metadata().getFileName())) .contentLength(contentLength) .contentType(contentType) .build(); this.s3Client.putObject( putObjectRequest, - RequestBody.fromInputStream(uploadS3Action.document().asInputStream(), contentLength)); + RequestBody.fromInputStream(uploadObject.document().asInputStream(), contentLength)); return new UploadResponse( - uploadS3Action.bucket(), - uploadS3Action.key(), - String.format( - "https://%s.s3.amazonaws.com/%s", uploadS3Action.bucket(), uploadS3Action.key())); + uploadObject.bucket(), + uploadObject.key(), + String.format("https://%s.s3.amazonaws.com/%s", uploadObject.bucket(), uploadObject.key())); } private DownloadResponse download(DownloadS3Action downloadS3Action) { @@ -107,7 +107,9 @@ private DownloadResponse download(DownloadS3Action downloadS3Action) { .andThen( document -> new DownloadResponse( - downloadS3Action.bucket(), downloadS3Action.key(), document, null)) + downloadS3Action.bucket(), + downloadS3Action.key(), + new Element.DocumentContent(document))) .apply( DocumentCreationRequest.from(getObjectResponse) .contentType(getObjectResponse.response().contentType()) @@ -122,11 +124,14 @@ private DownloadResponse retrieveResponseWithContent( byte[] rawBytes = responseResponseInputStream.readAllBytes(); return switch (responseResponseInputStream.response().contentType()) { case "text/plain" -> - new DownloadResponse(bucket, key, null, new String(rawBytes, StandardCharsets.UTF_8)); + new DownloadResponse( + bucket, key, new Element.StringContent(new String(rawBytes, StandardCharsets.UTF_8))); case "application/json" -> - new DownloadResponse(bucket, key, null, new ObjectMapper().readTree(rawBytes)); + new DownloadResponse( + bucket, key, new Element.JsonContent(new ObjectMapper().readTree(rawBytes))); default -> - new DownloadResponse(bucket, key, null, Base64.getEncoder().encodeToString(rawBytes)); + new DownloadResponse( + bucket, key, new Element.StringContent(Base64.getEncoder().encodeToString(rawBytes))); }; } diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Action.java index 7a9343d963..9a61a3fd79 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Action.java @@ -15,4 +15,4 @@ name = "actionDiscriminator", defaultValue = "uploadObject") @TemplateSubType(id = "action", label = "Action") -public sealed interface S3Action permits DeleteS3Action, DownloadS3Action, UploadS3Action {} +public sealed interface S3Action permits DeleteS3Action, DownloadS3Action, UploadObject {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Request.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Request.java index 017d7fc80b..ad2054f825 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Request.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Request.java @@ -22,7 +22,7 @@ public class S3Request extends AwsBaseRequest { @JsonSubTypes( value = { @JsonSubTypes.Type(value = DeleteS3Action.class, name = "deleteObject"), - @JsonSubTypes.Type(value = UploadS3Action.class, name = "uploadObject"), + @JsonSubTypes.Type(value = UploadObject.class, name = "uploadObject"), @JsonSubTypes.Type(value = DownloadS3Action.class, name = "downloadObject"), }) @Valid @@ -32,11 +32,11 @@ public class S3Request extends AwsBaseRequest { public S3Request() {} - public S3Action getData() { + public S3Action getAction() { return action; } - public void setData(S3Action data) { - this.action = data; + public void setAction(S3Action action) { + this.action = action; } } diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadObject.java similarity index 95% rename from connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadS3Action.java rename to connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadObject.java index 0d9697cbba..bfd72ac497 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadObject.java @@ -12,8 +12,8 @@ import io.camunda.document.Document; import jakarta.validation.constraints.NotBlank; -@TemplateSubType(id = "uploadObject", label = "Upload document") -public record UploadS3Action( +@TemplateSubType(id = "uploadObject", label = "Upload object") +public record UploadObject( @TemplateProperty( label = "AWS bucket", id = "uploadActionBucket", diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DownloadResponse.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DownloadResponse.java index 33fb8b3ba3..476cf8b08f 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DownloadResponse.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DownloadResponse.java @@ -6,6 +6,5 @@ */ package io.camunda.connector.aws.s3.model.response; -import io.camunda.document.Document; -public record DownloadResponse(String bucket, String key, Document document, Object content) {} +public record DownloadResponse(String bucket, String key, Element element) {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/Element.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/Element.java new file mode 100644 index 0000000000..f20241cebe --- /dev/null +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/Element.java @@ -0,0 +1,11 @@ +package io.camunda.connector.aws.s3.model.response; + +import io.camunda.document.Document; + +public interface Element { + record DocumentContent(Document document) implements Element {} + + record StringContent(String content) implements Element {} + + record JsonContent(Object content) implements Element {} +} diff --git a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java index 475b9d2fe1..bc84fabfad 100644 --- a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java +++ b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/S3ConnectorFunctionTest.java @@ -51,7 +51,7 @@ void executeDownloadActionReturnsCorrectResult(String variables) { try (MockedStatic s3ExecutorMockedStatic = Mockito.mockStatic(S3Executor.class)) { s3ExecutorMockedStatic.when(() -> S3Executor.create(any(), any())).thenReturn(s3Executor); - when(s3Executor.execute(any())).thenReturn(new DownloadResponse("test", "test", null, null)); + when(s3Executor.execute(any())).thenReturn(new DownloadResponse("test", "test", null)); var response = s3ConnectorFunction.execute(context); Assertions.assertNotNull(response); Assertions.assertInstanceOf(DownloadResponse.class, response); diff --git a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java index 43f60625ba..e6efbca24c 100644 --- a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java +++ b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java @@ -14,9 +14,10 @@ import io.camunda.connector.aws.s3.model.request.DeleteS3Action; import io.camunda.connector.aws.s3.model.request.DownloadS3Action; import io.camunda.connector.aws.s3.model.request.S3Action; -import io.camunda.connector.aws.s3.model.request.UploadS3Action; +import io.camunda.connector.aws.s3.model.request.UploadObject; import io.camunda.connector.aws.s3.model.response.DeleteResponse; import io.camunda.connector.aws.s3.model.response.DownloadResponse; +import io.camunda.connector.aws.s3.model.response.Element; import io.camunda.connector.aws.s3.model.response.UploadResponse; import io.camunda.document.Document; import io.camunda.document.store.DocumentCreationRequest; @@ -53,7 +54,7 @@ void executeUploadAction() { Function function = doc -> mock(Document.class); S3Executor executor = new S3Executor(s3Client, function); Document document = mock(Document.class, RETURNS_DEEP_STUBS); - S3Action s3Action = new UploadS3Action("test", "key", document); + S3Action s3Action = new UploadObject("test", "key", document); when(document.metadata().getSize()).thenReturn(42L); when(document.metadata().getContentType()).thenReturn("application/octet-stream"); @@ -81,8 +82,7 @@ void executeDownloadAsDocumentAction() { verify(s3Client, times(1)).getObject(any(GetObjectRequest.class)); assertInstanceOf(DownloadResponse.class, object); - assertNull(((DownloadResponse) object).content()); - assertNotNull(((DownloadResponse) object).document()); + assertInstanceOf(Element.DocumentContent.class, ((DownloadResponse) object).element()); } @Test @@ -104,9 +104,9 @@ void executeDownloadAsTextContentAction() throws IOException { verify(s3Client, times(1)).getObject(any(GetObjectRequest.class)); assertInstanceOf(DownloadResponse.class, object); - assertNotNull(((DownloadResponse) object).content()); - assertNull(((DownloadResponse) object).document()); - assertEquals("Hello World", ((DownloadResponse) object).content()); + assertNotNull(((DownloadResponse) object).element()); + assertInstanceOf(Element.StringContent.class, ((DownloadResponse) object).element()); + assertEquals("Hello World", ((DownloadResponse) object).element()); } @Test @@ -129,9 +129,8 @@ void executeDownloadAsJsonContentAction() throws IOException { verify(s3Client, times(1)).getObject(any(GetObjectRequest.class)); assertInstanceOf(DownloadResponse.class, object); DownloadResponse downloadResponse = (DownloadResponse) object; - assertNotNull(downloadResponse.content()); - assertNull(downloadResponse.document()); - assertEquals("World", ((ObjectNode) downloadResponse.content()).get("Hello").asText()); + assertNotNull(downloadResponse.element()); + assertEquals("World", ((ObjectNode) downloadResponse.element()).get("Hello").asText()); } @Test @@ -154,9 +153,8 @@ void executeDownloadAsBase64BytesContentAction() throws IOException { verify(s3Client, times(1)).getObject(any(GetObjectRequest.class)); assertInstanceOf(DownloadResponse.class, object); DownloadResponse downloadResponse = (DownloadResponse) object; - assertNotNull(downloadResponse.content()); - assertNull(downloadResponse.document()); + assertNotNull(downloadResponse.element()); assertEquals( - Base64.getEncoder().encodeToString("Hello".getBytes()), downloadResponse.content()); + Base64.getEncoder().encodeToString("Hello".getBytes()), downloadResponse.element()); } } From cec8e47577315401e87bf2492c1f0d639ffe7c99 Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Wed, 18 Dec 2024 14:24:09 +0100 Subject: [PATCH 12/13] feature(s3-connector): corrections --- .../aws-s3-outbound-connector.json | 5 +--- .../aws-s3-outbound-connector-hybrid.json | 5 +--- .../connector/aws/s3/core/S3Executor.java | 28 +++++++++---------- ...{DeleteS3Action.java => DeleteObject.java} | 4 +-- ...nloadS3Action.java => DownloadObject.java} | 4 +-- .../aws/s3/model/request/S3Action.java | 2 +- .../aws/s3/model/request/S3Request.java | 4 +-- .../aws/s3/model/request/UploadObject.java | 1 - .../s3/model/response/DownloadResponse.java | 1 - .../aws/s3/model/response/Element.java | 6 ++++ .../connector/aws/s3/core/S3ExecutorTest.java | 14 +++++----- .../actions/uploadActionsExample.json | 2 +- 12 files changed, 37 insertions(+), 39 deletions(-) rename connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/{DeleteS3Action.java => DeleteObject.java} (93%) rename connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/{DownloadS3Action.java => DownloadObject.java} (95%) diff --git a/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json b/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json index 1c2e0b02fa..117737b2ea 100644 --- a/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json +++ b/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json @@ -149,7 +149,7 @@ "name" : "Download document", "value" : "downloadObject" }, { - "name" : "Upload document", + "name" : "Upload object", "value" : "uploadObject" } ] }, { @@ -216,9 +216,6 @@ "id" : "uploadActionKey", "label" : "AWS key", "optional" : true, - "constraints" : { - "notEmpty" : true - }, "feel" : "optional", "group" : "uploadObject", "binding" : { diff --git a/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json b/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json index a33b5ab9d7..95928673b9 100644 --- a/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json +++ b/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json @@ -154,7 +154,7 @@ "name" : "Download document", "value" : "downloadObject" }, { - "name" : "Upload document", + "name" : "Upload object", "value" : "uploadObject" } ] }, { @@ -221,9 +221,6 @@ "id" : "uploadActionKey", "label" : "AWS key", "optional" : true, - "constraints" : { - "notEmpty" : true - }, "feel" : "optional", "group" : "uploadObject", "binding" : { diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java index 9b0e842212..4a21521598 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java @@ -54,8 +54,8 @@ public static S3Executor create( public Object execute(S3Action s3Action) { return switch (s3Action) { - case DeleteS3Action deleteS3Action -> delete(deleteS3Action); - case DownloadS3Action downloadS3Action -> download(downloadS3Action); + case DeleteObject deleteObject -> delete(deleteObject); + case DownloadObject downloadObject -> download(downloadObject); case UploadObject uploadObject -> upload(uploadObject); }; } @@ -84,20 +84,20 @@ private Object upload(UploadObject uploadObject) { String.format("https://%s.s3.amazonaws.com/%s", uploadObject.bucket(), uploadObject.key())); } - private DownloadResponse download(DownloadS3Action downloadS3Action) { + private DownloadResponse download(DownloadObject downloadObject) { GetObjectRequest getObjectRequest = GetObjectRequest.builder() - .bucket(downloadS3Action.bucket()) - .key(downloadS3Action.key()) + .bucket(downloadObject.bucket()) + .key(downloadObject.key()) .build(); ResponseInputStream getObjectResponse = this.s3Client.getObject(getObjectRequest); - if (!downloadS3Action.asFile()) { + if (!downloadObject.asFile()) { try { return retrieveResponseWithContent( - downloadS3Action.bucket(), downloadS3Action.key(), getObjectResponse); + downloadObject.bucket(), downloadObject.key(), getObjectResponse); } catch (IOException e) { log.error("An error occurred while trying to read and parse the downloaded file", e); throw new RuntimeException(e); @@ -107,13 +107,13 @@ private DownloadResponse download(DownloadS3Action downloadS3Action) { .andThen( document -> new DownloadResponse( - downloadS3Action.bucket(), - downloadS3Action.key(), + downloadObject.bucket(), + downloadObject.key(), new Element.DocumentContent(document))) .apply( DocumentCreationRequest.from(getObjectResponse) .contentType(getObjectResponse.response().contentType()) - .fileName(downloadS3Action.key()) + .fileName(downloadObject.key()) .build()); } } @@ -135,14 +135,14 @@ private DownloadResponse retrieveResponseWithContent( }; } - private DeleteResponse delete(DeleteS3Action deleteS3Action) { + private DeleteResponse delete(DeleteObject deleteObject) { DeleteObjectRequest deleteObjectRequest = DeleteObjectRequest.builder() - .bucket(deleteS3Action.bucket()) - .key(deleteS3Action.key()) + .bucket(deleteObject.bucket()) + .key(deleteObject.key()) .build(); this.s3Client.deleteObject(deleteObjectRequest); - return new DeleteResponse(deleteS3Action.bucket(), deleteS3Action.key()); + return new DeleteResponse(deleteObject.bucket(), deleteObject.key()); } } diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DeleteS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DeleteObject.java similarity index 93% rename from connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DeleteS3Action.java rename to connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DeleteObject.java index 1f37eb9a1c..9b08f51cbf 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DeleteS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DeleteObject.java @@ -11,8 +11,8 @@ import io.camunda.connector.generator.java.annotation.TemplateSubType; import jakarta.validation.constraints.NotBlank; -@TemplateSubType(id = "deleteObject", label = "Delete document") -public record DeleteS3Action( +@TemplateSubType(id = "deleteObject", label = "Delete object") +public record DeleteObject( @TemplateProperty( label = "AWS bucket", id = "deleteActionBucket", diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DownloadS3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DownloadObject.java similarity index 95% rename from connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DownloadS3Action.java rename to connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DownloadObject.java index 738d303a05..1cec918434 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DownloadS3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/DownloadObject.java @@ -11,8 +11,8 @@ import io.camunda.connector.generator.java.annotation.TemplateSubType; import jakarta.validation.constraints.NotBlank; -@TemplateSubType(id = "downloadObject", label = "Download document") -public record DownloadS3Action( +@TemplateSubType(id = "downloadObject", label = "Download object") +public record DownloadObject( @TemplateProperty( label = "AWS bucket", id = "downloadActionBucket", diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Action.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Action.java index 9a61a3fd79..9ecbb7d891 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Action.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Action.java @@ -15,4 +15,4 @@ name = "actionDiscriminator", defaultValue = "uploadObject") @TemplateSubType(id = "action", label = "Action") -public sealed interface S3Action permits DeleteS3Action, DownloadS3Action, UploadObject {} +public sealed interface S3Action permits DeleteObject, DownloadObject, UploadObject {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Request.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Request.java index ad2054f825..5cbdd21db8 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Request.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/S3Request.java @@ -21,9 +21,9 @@ public class S3Request extends AwsBaseRequest { property = "actionDiscriminator") @JsonSubTypes( value = { - @JsonSubTypes.Type(value = DeleteS3Action.class, name = "deleteObject"), + @JsonSubTypes.Type(value = DeleteObject.class, name = "deleteObject"), @JsonSubTypes.Type(value = UploadObject.class, name = "uploadObject"), - @JsonSubTypes.Type(value = DownloadS3Action.class, name = "downloadObject"), + @JsonSubTypes.Type(value = DownloadObject.class, name = "downloadObject"), }) @Valid @NotNull diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadObject.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadObject.java index bfd72ac497..9023328b1c 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadObject.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/request/UploadObject.java @@ -32,7 +32,6 @@ public record UploadObject( optional = true, feel = Property.FeelMode.optional, binding = @TemplateProperty.PropertyBinding(name = "action.key")) - @NotBlank String key, @TemplateProperty( label = "Document", diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DownloadResponse.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DownloadResponse.java index 476cf8b08f..1180fc415d 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DownloadResponse.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/DownloadResponse.java @@ -6,5 +6,4 @@ */ package io.camunda.connector.aws.s3.model.response; - public record DownloadResponse(String bucket, String key, Element element) {} diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/Element.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/Element.java index f20241cebe..4721693969 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/Element.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/model/response/Element.java @@ -1,3 +1,9 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. Licensed under a proprietary license. + * See the License.txt file for more information. You may not use this file + * except in compliance with the proprietary license. + */ package io.camunda.connector.aws.s3.model.response; import io.camunda.document.Document; diff --git a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java index e6efbca24c..95496bfd8d 100644 --- a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java +++ b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java @@ -11,8 +11,8 @@ import static org.mockito.Mockito.*; import com.fasterxml.jackson.databind.node.ObjectNode; -import io.camunda.connector.aws.s3.model.request.DeleteS3Action; -import io.camunda.connector.aws.s3.model.request.DownloadS3Action; +import io.camunda.connector.aws.s3.model.request.DeleteObject; +import io.camunda.connector.aws.s3.model.request.DownloadObject; import io.camunda.connector.aws.s3.model.request.S3Action; import io.camunda.connector.aws.s3.model.request.UploadObject; import io.camunda.connector.aws.s3.model.response.DeleteResponse; @@ -40,7 +40,7 @@ void executeDeleteAction() { S3Client s3Client = mock(S3Client.class); Function function = doc -> mock(Document.class); S3Executor executor = new S3Executor(s3Client, function); - S3Action s3Action = new DeleteS3Action("test", "key"); + S3Action s3Action = new DeleteObject("test", "key"); Object object = executor.execute(s3Action); @@ -73,7 +73,7 @@ void executeDownloadAsDocumentAction() { S3Executor executor = new S3Executor(s3Client, function); ResponseInputStream responseInputStream = mock(ResponseInputStream.class); GetObjectResponse getObjectResponse = mock(GetObjectResponse.class); - S3Action s3Action = new DownloadS3Action("test", "key", true); + S3Action s3Action = new DownloadObject("test", "key", true); when(s3Client.getObject(any(GetObjectRequest.class))).thenReturn(responseInputStream); when(responseInputStream.response()).thenReturn(getObjectResponse); @@ -93,7 +93,7 @@ void executeDownloadAsTextContentAction() throws IOException { S3Executor executor = new S3Executor(s3Client, function); ResponseInputStream responseInputStream = mock(ResponseInputStream.class); GetObjectResponse getObjectResponse = mock(GetObjectResponse.class); - S3Action s3Action = new DownloadS3Action("test", "key", false); + S3Action s3Action = new DownloadObject("test", "key", false); when(s3Client.getObject(any(GetObjectRequest.class))).thenReturn(responseInputStream); when(responseInputStream.response()).thenReturn(getObjectResponse); @@ -117,7 +117,7 @@ void executeDownloadAsJsonContentAction() throws IOException { S3Executor executor = new S3Executor(s3Client, function); ResponseInputStream responseInputStream = mock(ResponseInputStream.class); GetObjectResponse getObjectResponse = mock(GetObjectResponse.class); - S3Action s3Action = new DownloadS3Action("test", "key", false); + S3Action s3Action = new DownloadObject("test", "key", false); when(s3Client.getObject(any(GetObjectRequest.class))).thenReturn(responseInputStream); when(responseInputStream.response()).thenReturn(getObjectResponse); @@ -141,7 +141,7 @@ void executeDownloadAsBase64BytesContentAction() throws IOException { S3Executor executor = new S3Executor(s3Client, function); ResponseInputStream responseInputStream = mock(ResponseInputStream.class); GetObjectResponse getObjectResponse = mock(GetObjectResponse.class); - S3Action s3Action = new DownloadS3Action("test", "key", false); + S3Action s3Action = new DownloadObject("test", "key", false); when(s3Client.getObject(any(GetObjectRequest.class))).thenReturn(responseInputStream); when(responseInputStream.response()).thenReturn(getObjectResponse); diff --git a/connectors/aws/aws-s3/src/test/resources/actions/uploadActionsExample.json b/connectors/aws/aws-s3/src/test/resources/actions/uploadActionsExample.json index ea23c5dd78..41de5ce929 100644 --- a/connectors/aws/aws-s3/src/test/resources/actions/uploadActionsExample.json +++ b/connectors/aws/aws-s3/src/test/resources/actions/uploadActionsExample.json @@ -10,7 +10,7 @@ "contentType":"text/plain", "size":41730, "fileName":"test.txt" }, - "documentType":"camunda" + "camunda.document.type":"camunda" } }, "configuration":{"region":"eu-central-1"}, "authentication":{ From f122b343c43486b4e835a269ee48c1a03502f5ca Mon Sep 17 00:00:00 2001 From: Mathias Vandaele Date: Wed, 18 Dec 2024 14:45:30 +0100 Subject: [PATCH 13/13] feature(s3-connector): corrections 2 --- .../aws-s3-outbound-connector.json | 7 +++++-- .../hybrid/aws-s3-outbound-connector-hybrid.json | 7 +++++-- .../camunda/connector/aws/s3/core/S3Executor.java | 5 +---- .../connector/aws/s3/core/S3ExecutorTest.java | 14 ++++++++++---- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json b/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json index 117737b2ea..3d72cb6a73 100644 --- a/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json +++ b/connectors/aws/aws-s3/element-templates/aws-s3-outbound-connector.json @@ -3,6 +3,9 @@ "name" : "AWS S3 Outbound Connector", "id" : "io.camunda.connectors.aws.s3.v1", "description" : "Execute S3 requests", + "metadata" : { + "keywords" : [ ] + }, "documentationRef" : "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/aws-s3/", "version" : 1, "category" : { @@ -143,10 +146,10 @@ }, "type" : "Dropdown", "choices" : [ { - "name" : "Delete document", + "name" : "Delete object", "value" : "deleteObject" }, { - "name" : "Download document", + "name" : "Download object", "value" : "downloadObject" }, { "name" : "Upload object", diff --git a/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json b/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json index 95928673b9..b9c4b1c960 100644 --- a/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json +++ b/connectors/aws/aws-s3/element-templates/hybrid/aws-s3-outbound-connector-hybrid.json @@ -3,6 +3,9 @@ "name" : "Hybrid AWS S3 Outbound Connector", "id" : "io.camunda.connectors.aws.s3.v1-hybrid", "description" : "Execute S3 requests", + "metadata" : { + "keywords" : [ ] + }, "documentationRef" : "https://docs.camunda.io/docs/components/connectors/out-of-the-box-connectors/aws-s3/", "version" : 1, "category" : { @@ -148,10 +151,10 @@ }, "type" : "Dropdown", "choices" : [ { - "name" : "Delete document", + "name" : "Delete object", "value" : "deleteObject" }, { - "name" : "Download document", + "name" : "Download object", "value" : "downloadObject" }, { "name" : "Upload object", diff --git a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java index 4a21521598..a16f862d42 100644 --- a/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java +++ b/connectors/aws/aws-s3/src/main/java/io/camunda/connector/aws/s3/core/S3Executor.java @@ -137,10 +137,7 @@ private DownloadResponse retrieveResponseWithContent( private DeleteResponse delete(DeleteObject deleteObject) { DeleteObjectRequest deleteObjectRequest = - DeleteObjectRequest.builder() - .bucket(deleteObject.bucket()) - .key(deleteObject.key()) - .build(); + DeleteObjectRequest.builder().bucket(deleteObject.bucket()).key(deleteObject.key()).build(); this.s3Client.deleteObject(deleteObjectRequest); return new DeleteResponse(deleteObject.bucket(), deleteObject.key()); diff --git a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java index 95496bfd8d..b62492f9bb 100644 --- a/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java +++ b/connectors/aws/aws-s3/src/test/java/io/camunda/connector/aws/s3/core/S3ExecutorTest.java @@ -10,7 +10,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; -import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.JsonNode; import io.camunda.connector.aws.s3.model.request.DeleteObject; import io.camunda.connector.aws.s3.model.request.DownloadObject; import io.camunda.connector.aws.s3.model.request.S3Action; @@ -106,7 +106,8 @@ void executeDownloadAsTextContentAction() throws IOException { assertInstanceOf(DownloadResponse.class, object); assertNotNull(((DownloadResponse) object).element()); assertInstanceOf(Element.StringContent.class, ((DownloadResponse) object).element()); - assertEquals("Hello World", ((DownloadResponse) object).element()); + assertEquals( + "Hello World", ((Element.StringContent) ((DownloadResponse) object).element()).content()); } @Test @@ -130,7 +131,11 @@ void executeDownloadAsJsonContentAction() throws IOException { assertInstanceOf(DownloadResponse.class, object); DownloadResponse downloadResponse = (DownloadResponse) object; assertNotNull(downloadResponse.element()); - assertEquals("World", ((ObjectNode) downloadResponse.element()).get("Hello").asText()); + assertEquals( + "World", + ((JsonNode) ((Element.JsonContent) downloadResponse.element()).content()) + .get("Hello") + .asText()); } @Test @@ -155,6 +160,7 @@ void executeDownloadAsBase64BytesContentAction() throws IOException { DownloadResponse downloadResponse = (DownloadResponse) object; assertNotNull(downloadResponse.element()); assertEquals( - Base64.getEncoder().encodeToString("Hello".getBytes()), downloadResponse.element()); + Base64.getEncoder().encodeToString("Hello".getBytes()), + ((Element.StringContent) downloadResponse.element()).content()); } }