diff --git a/connectors/google/google-drive/element-templates/google-drive-outbound-connector.json b/connectors/google/google-drive/element-templates/google-drive-outbound-connector.json
index 3a9f07aa9a..e55438df4c 100644
--- a/connectors/google/google-drive/element-templates/google-drive-outbound-connector.json
+++ b/connectors/google/google-drive/element-templates/google-drive-outbound-connector.json
@@ -163,6 +163,12 @@
}, {
"name" : "Create file from template",
"value" : "file"
+ }, {
+ "name" : "Upload file",
+ "value" : "upload"
+ }, {
+ "name" : "Download file",
+ "value" : "download"
} ]
}, {
"id" : "resource.name",
@@ -177,6 +183,11 @@
"name" : "resource.name",
"type" : "zeebe:input"
},
+ "condition" : {
+ "property" : "resource.type",
+ "oneOf" : [ "folder", "file" ],
+ "type" : "simple"
+ },
"type" : "String"
}, {
"id" : "resource.parent",
@@ -189,6 +200,11 @@
"name" : "resource.parent",
"type" : "zeebe:input"
},
+ "condition" : {
+ "property" : "resource.type",
+ "oneOf" : [ "folder", "file", "upload" ],
+ "type" : "simple"
+ },
"type" : "String"
}, {
"id" : "resource.additionalGoogleDriveProperties",
@@ -241,6 +257,44 @@
"type" : "simple"
},
"type" : "String"
+ }, {
+ "id" : "resource.downloadData.fileId",
+ "label" : "File ID",
+ "optional" : false,
+ "constraints" : {
+ "notEmpty" : true
+ },
+ "feel" : "optional",
+ "group" : "operationDetails",
+ "binding" : {
+ "name" : "resource.downloadData.fileId",
+ "type" : "zeebe:input"
+ },
+ "condition" : {
+ "property" : "resource.type",
+ "equals" : "download",
+ "type" : "simple"
+ },
+ "type" : "String"
+ }, {
+ "id" : "resource.uploadData.document",
+ "label" : "Document",
+ "optional" : false,
+ "constraints" : {
+ "notEmpty" : true
+ },
+ "feel" : "required",
+ "group" : "operationDetails",
+ "binding" : {
+ "name" : "resource.uploadData.document",
+ "type" : "zeebe:input"
+ },
+ "condition" : {
+ "property" : "resource.type",
+ "equals" : "upload",
+ "type" : "simple"
+ },
+ "type" : "String"
}, {
"id" : "resultVariable",
"label" : "Result variable",
diff --git a/connectors/google/google-drive/element-templates/hybrid/google-drive-outbound-connector-hybrid.json b/connectors/google/google-drive/element-templates/hybrid/google-drive-outbound-connector-hybrid.json
index bb63c5a67a..4e6d067f1d 100644
--- a/connectors/google/google-drive/element-templates/hybrid/google-drive-outbound-connector-hybrid.json
+++ b/connectors/google/google-drive/element-templates/hybrid/google-drive-outbound-connector-hybrid.json
@@ -168,6 +168,12 @@
}, {
"name" : "Create file from template",
"value" : "file"
+ }, {
+ "name" : "Upload file",
+ "value" : "upload"
+ }, {
+ "name" : "Download file",
+ "value" : "download"
} ]
}, {
"id" : "resource.name",
@@ -182,6 +188,11 @@
"name" : "resource.name",
"type" : "zeebe:input"
},
+ "condition" : {
+ "property" : "resource.type",
+ "oneOf" : [ "folder", "file" ],
+ "type" : "simple"
+ },
"type" : "String"
}, {
"id" : "resource.parent",
@@ -194,6 +205,11 @@
"name" : "resource.parent",
"type" : "zeebe:input"
},
+ "condition" : {
+ "property" : "resource.type",
+ "oneOf" : [ "folder", "file", "upload" ],
+ "type" : "simple"
+ },
"type" : "String"
}, {
"id" : "resource.additionalGoogleDriveProperties",
@@ -246,6 +262,44 @@
"type" : "simple"
},
"type" : "String"
+ }, {
+ "id" : "resource.downloadData.fileId",
+ "label" : "File ID",
+ "optional" : false,
+ "constraints" : {
+ "notEmpty" : true
+ },
+ "feel" : "optional",
+ "group" : "operationDetails",
+ "binding" : {
+ "name" : "resource.downloadData.fileId",
+ "type" : "zeebe:input"
+ },
+ "condition" : {
+ "property" : "resource.type",
+ "equals" : "download",
+ "type" : "simple"
+ },
+ "type" : "String"
+ }, {
+ "id" : "resource.uploadData.document",
+ "label" : "Document",
+ "optional" : false,
+ "constraints" : {
+ "notEmpty" : true
+ },
+ "feel" : "required",
+ "group" : "operationDetails",
+ "binding" : {
+ "name" : "resource.uploadData.document",
+ "type" : "zeebe:input"
+ },
+ "condition" : {
+ "property" : "resource.type",
+ "equals" : "upload",
+ "type" : "simple"
+ },
+ "type" : "String"
}, {
"id" : "resultVariable",
"label" : "Result variable",
diff --git a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveClient.java b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveClient.java
index d5d101f8e8..19d2750e40 100644
--- a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveClient.java
+++ b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveClient.java
@@ -51,4 +51,12 @@ public BatchUpdateDocumentResponse updateDocument(
throw new RuntimeException(e);
}
}
+
+ public Drive getDriveService() {
+ return driveService;
+ }
+
+ public Docs getDocsService() {
+ return docsService;
+ }
}
diff --git a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveFunction.java b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveFunction.java
index d40dc78d6f..b41d2df67c 100644
--- a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveFunction.java
+++ b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveFunction.java
@@ -9,7 +9,7 @@
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.gdrive.model.GoogleDriveResult;
+import io.camunda.connector.gdrive.mapper.DocumentMapper;
import io.camunda.connector.gdrive.model.request.GoogleDriveRequest;
import io.camunda.connector.gdrive.supliers.GoogleDocsServiceSupplier;
import io.camunda.connector.generator.java.annotation.ElementTemplate;
@@ -53,16 +53,21 @@ public GoogleDriveFunction(final GoogleDriveService service) {
@Override
public Object execute(final OutboundConnectorContext context) {
+
var request = context.bindVariables(GoogleDriveRequest.class);
+ service.setDocumentMapper(new DocumentMapper(context));
+
return executeConnector(request);
}
- private GoogleDriveResult executeConnector(final GoogleDriveRequest request) {
+ private Object executeConnector(final GoogleDriveRequest request) {
LOGGER.debug("Executing my connector with request {}", request);
+
GoogleDriveClient drive =
new GoogleDriveClient(
GoogleDriveServiceSupplier.createDriveClientInstance(request.getAuthentication()),
GoogleDocsServiceSupplier.createDocsClientInstance(request.getAuthentication()));
+
return service.execute(drive, request.getResource());
}
}
diff --git a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveService.java b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveService.java
index 0a9265e4be..ab7eb083a7 100644
--- a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveService.java
+++ b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/GoogleDriveService.java
@@ -6,37 +6,53 @@
*/
package io.camunda.connector.gdrive;
+import com.google.api.client.http.ByteArrayContent;
import com.google.api.client.json.JsonParser;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.docs.v1.model.BatchUpdateDocumentResponse;
import com.google.api.services.docs.v1.model.Request;
+import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File;
import com.google.common.reflect.TypeToken;
+import io.camunda.connector.gdrive.mapper.DocumentMapper;
import io.camunda.connector.gdrive.model.GoogleDriveResult;
import io.camunda.connector.gdrive.model.MimeTypeUrl;
import io.camunda.connector.gdrive.model.request.Resource;
import io.camunda.connector.gdrive.model.request.Template;
import io.camunda.connector.gdrive.model.request.Type;
import io.camunda.connector.gdrive.model.request.Variables;
+import io.camunda.document.Document;
import io.camunda.google.supplier.GsonComponentSupplier;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class GoogleDriveService {
+
+ public static final long MAX_DIRECT_UPLOAD_FILE_SIZE_BYTES = 5_242_880L; // 5MB
private static final Logger LOGGER = LoggerFactory.getLogger(GoogleDriveService.class);
private final GsonFactory gsonFactory = GsonComponentSupplier.gsonFactoryInstance();
+ private DocumentMapper documentMapper;
+
+ public GoogleDriveService(DocumentMapper documentMapper) {
+ this.documentMapper = documentMapper;
+ }
+
public GoogleDriveService() {}
- public GoogleDriveResult execute(final GoogleDriveClient client, final Resource resource) {
+ public Object execute(final GoogleDriveClient client, final Resource resource) {
return switch (resource.type()) {
case FOLDER -> createFolder(client, resource);
case FILE -> createFile(client, resource);
+ case UPLOAD -> uploadFile(client, resource);
+ case DOWNLOAD -> downloadFile(client, resource);
};
}
@@ -116,4 +132,55 @@ private void updateWithRequests(
metaData.getMimeType());
}
}
+
+ private GoogleDriveResult uploadFile(final GoogleDriveClient client, final Resource resource) {
+ try {
+ var document = resource.uploadData().document();
+ File fileMetaData = prepareFileMetaData(document, resource.parent());
+
+ var content =
+ new ByteArrayContent(document.metadata().getContentType(), document.asByteArray());
+
+ Drive drive = client.getDriveService();
+ Drive.Files.Create createRequest = drive.files().create(fileMetaData, content);
+
+ if (document.metadata().getSize() > MAX_DIRECT_UPLOAD_FILE_SIZE_BYTES) {
+ createRequest.getMediaHttpUploader().setProgressListener(new LoggerProgressListener());
+ }
+
+ File file = createRequest.execute();
+ return new GoogleDriveResult(file.getId(), MimeTypeUrl.getFileUrl(file.getId()));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Document downloadFile(final GoogleDriveClient client, final Resource resource) {
+ Drive drive = client.getDriveService();
+ try {
+ String fileId = resource.downloadData().fileId();
+ File fileMetaData = drive.files().get(fileId).execute();
+ try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+ drive.files().get(fileId).executeMediaAndDownloadTo(outputStream);
+ return documentMapper.mapToDocument(outputStream.toByteArray(), fileMetaData);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private File prepareFileMetaData(Document document, String parent) {
+ File fileMetaData = new File();
+ fileMetaData.setName(document.metadata().getFileName());
+
+ Optional.ofNullable(parent)
+ .filter(StringUtils::isNoneBlank)
+ .ifPresent(folder -> fileMetaData.setParents(List.of(folder)));
+
+ return fileMetaData;
+ }
+
+ public void setDocumentMapper(DocumentMapper documentMapper) {
+ this.documentMapper = documentMapper;
+ }
}
diff --git a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/LoggerProgressListener.java b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/LoggerProgressListener.java
new file mode 100644
index 0000000000..517bb7bbb8
--- /dev/null
+++ b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/LoggerProgressListener.java
@@ -0,0 +1,41 @@
+/*
+ * 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.gdrive;
+
+import com.google.api.client.googleapis.media.MediaHttpUploader;
+import com.google.api.client.googleapis.media.MediaHttpUploaderProgressListener;
+import java.io.IOException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Resumable upload official example: ...
+ */
+public class LoggerProgressListener implements MediaHttpUploaderProgressListener {
+ private static final Logger LOGGER = LoggerFactory.getLogger(LoggerProgressListener.class);
+
+ @Override
+ public void progressChanged(MediaHttpUploader uploader) throws IOException {
+ switch (uploader.getUploadState()) {
+ case NOT_STARTED:
+ LOGGER.debug("Upload not started");
+ break;
+ case INITIATION_STARTED:
+ LOGGER.debug("Initiation has started!");
+ break;
+ case INITIATION_COMPLETE:
+ LOGGER.debug("Initiation is complete!");
+ break;
+ case MEDIA_IN_PROGRESS:
+ LOGGER.debug("Upload progress: {}", uploader.getProgress());
+ break;
+ case MEDIA_COMPLETE:
+ LOGGER.debug("Upload is complete!");
+ }
+ }
+}
diff --git a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/mapper/DocumentMapper.java b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/mapper/DocumentMapper.java
new file mode 100644
index 0000000000..f136b8b8ae
--- /dev/null
+++ b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/mapper/DocumentMapper.java
@@ -0,0 +1,29 @@
+/*
+ * 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.gdrive.mapper;
+
+import com.google.api.services.drive.model.File;
+import io.camunda.connector.api.outbound.OutboundConnectorContext;
+import io.camunda.document.Document;
+import io.camunda.document.store.DocumentCreationRequest;
+
+public class DocumentMapper {
+
+ private final OutboundConnectorContext context;
+
+ public DocumentMapper(OutboundConnectorContext context) {
+ this.context = context;
+ }
+
+ public Document mapToDocument(byte[] bytes, File fileMetaData) {
+ return context.createDocument(
+ DocumentCreationRequest.from(bytes)
+ .contentType(fileMetaData.getMimeType())
+ .fileName(fileMetaData.getName())
+ .build());
+ }
+}
diff --git a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/MimeTypeUrl.java b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/MimeTypeUrl.java
index dc3d0ebf54..33a12426b3 100644
--- a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/MimeTypeUrl.java
+++ b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/MimeTypeUrl.java
@@ -18,6 +18,8 @@ public enum MimeTypeUrl {
"application/vnd.google-apps.presentation", "https://docs.google.com/presentation/d/%s"),
FORM("application/vnd.google-apps.form", "https://docs.google.com/forms/d/%s");
+ public static final String FILE_TEMPLATE_URL = "https://drive.google.com/file/d/%s/view";
+
private String mimeType;
private String templateUrl;
@@ -41,6 +43,10 @@ public static String getResourceUrl(final String mimeType, final String id) {
.orElse(null);
}
+ public static String getFileUrl(final String id) {
+ return String.format(FILE_TEMPLATE_URL, id);
+ }
+
public String getMimeType() {
return mimeType;
}
diff --git a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/DownloadData.java b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/DownloadData.java
new file mode 100644
index 0000000000..574b396b26
--- /dev/null
+++ b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/DownloadData.java
@@ -0,0 +1,22 @@
+/*
+ * 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.gdrive.model.request;
+
+import io.camunda.connector.generator.dsl.Property;
+import io.camunda.connector.generator.java.annotation.TemplateProperty;
+
+public record DownloadData(
+ @TemplateProperty(
+ group = "operationDetails",
+ label = "File ID",
+ feel = Property.FeelMode.optional,
+ condition =
+ @TemplateProperty.PropertyCondition(
+ property = "resource.type",
+ equals = "download"),
+ constraints = @TemplateProperty.PropertyConstraints(notEmpty = true))
+ String fileId) {}
diff --git a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/Resource.java b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/Resource.java
index 3db4f48264..cd286f9f24 100644
--- a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/Resource.java
+++ b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/Resource.java
@@ -15,7 +15,6 @@
import io.camunda.connector.generator.java.annotation.TemplateProperty.PropertyCondition;
import io.camunda.connector.generator.java.annotation.TemplateProperty.PropertyConstraints;
import jakarta.validation.Valid;
-import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
public record Resource(
@@ -28,7 +27,9 @@ public record Resource(
constraints = @PropertyConstraints(notEmpty = true),
choices = {
@DropdownPropertyChoice(label = "Create folder", value = "folder"),
- @DropdownPropertyChoice(label = "Create file from template", value = "file")
+ @DropdownPropertyChoice(label = "Create file from template", value = "file"),
+ @DropdownPropertyChoice(label = "Upload file", value = "upload"),
+ @DropdownPropertyChoice(label = "Download file", value = "download")
})
@NotNull
Type type,
@@ -36,8 +37,12 @@ public record Resource(
id = "name",
label = "New resource name",
group = "operationDetails",
- feel = FeelMode.optional)
- @NotEmpty
+ feel = FeelMode.optional,
+ condition =
+ @TemplateProperty.PropertyCondition(
+ property = "resource.type",
+ oneOf = {"folder", "file"}),
+ constraints = @TemplateProperty.PropertyConstraints(notEmpty = true))
String name,
@TemplateProperty(
id = "parent",
@@ -47,7 +52,11 @@ public record Resource(
+ "If left empty, a new resource will appear in the root folder",
group = "operationDetails",
optional = true,
- feel = FeelMode.optional)
+ feel = FeelMode.optional,
+ condition =
+ @TemplateProperty.PropertyCondition(
+ property = "resource.type",
+ oneOf = {"folder", "file", "upload"}))
String parent,
@TemplateProperty(
id = "additionalGoogleDriveProperties",
@@ -57,4 +66,6 @@ public record Resource(
optional = true,
condition = @PropertyCondition(property = "resource.type", equals = "folder"))
JsonNode additionalGoogleDriveProperties,
- @Valid Template template) {}
+ @Valid Template template,
+ @Valid DownloadData downloadData,
+ @Valid UploadData uploadData) {}
diff --git a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/Type.java b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/Type.java
index 5405731bc8..b8dc8a97fa 100644
--- a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/Type.java
+++ b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/Type.java
@@ -12,5 +12,9 @@ public enum Type {
@JsonProperty("folder")
FOLDER,
@JsonProperty("file")
- FILE
+ FILE,
+ @JsonProperty("upload")
+ UPLOAD,
+ @JsonProperty("download")
+ DOWNLOAD
}
diff --git a/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/UploadData.java b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/UploadData.java
new file mode 100644
index 0000000000..97f764e8be
--- /dev/null
+++ b/connectors/google/google-drive/src/main/java/io/camunda/connector/gdrive/model/request/UploadData.java
@@ -0,0 +1,22 @@
+/*
+ * 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.gdrive.model.request;
+
+import io.camunda.connector.generator.dsl.Property;
+import io.camunda.connector.generator.java.annotation.TemplateProperty;
+import io.camunda.document.Document;
+
+public record UploadData(
+ @TemplateProperty(
+ group = "operationDetails",
+ label = "Document",
+ feel = Property.FeelMode.required,
+ type = TemplateProperty.PropertyType.String,
+ condition =
+ @TemplateProperty.PropertyCondition(property = "resource.type", equals = "upload"),
+ constraints = @TemplateProperty.PropertyConstraints(notEmpty = true))
+ Document document) {}
diff --git a/connectors/google/google-drive/src/test/java/io/camunda/connector/gdrive/GoogleDriveFunctionTest.java b/connectors/google/google-drive/src/test/java/io/camunda/connector/gdrive/GoogleDriveFunctionTest.java
index 15f3003e8a..d35d72d97a 100644
--- a/connectors/google/google-drive/src/test/java/io/camunda/connector/gdrive/GoogleDriveFunctionTest.java
+++ b/connectors/google/google-drive/src/test/java/io/camunda/connector/gdrive/GoogleDriveFunctionTest.java
@@ -8,11 +8,14 @@
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
import io.camunda.connector.api.outbound.OutboundConnectorContext;
import io.camunda.connector.gdrive.model.GoogleDriveResult;
+import io.camunda.connector.gdrive.model.MimeTypeUrl;
import io.camunda.connector.gdrive.model.request.Resource;
import io.camunda.connector.validation.impl.DefaultValidationProvider;
+import io.camunda.document.Document;
import java.io.IOException;
import java.util.stream.Stream;
import org.junit.jupiter.api.DisplayName;
@@ -24,13 +27,17 @@ class GoogleDriveFunctionTest extends BaseTest {
private static final String SUCCESS_CASES_RESOURCE_PATH =
"src/test/resources/requests/request-success-test-cases.json";
+ private static final String SUCCESS_UPLOAD_RESOURCE_PATH =
+ "src/test/resources/requests/file-success-upload.json";
+ private static final String SUCCESS_DOWNLOAD_RESOURCE_PATH =
+ "src/test/resources/requests/file-success-download.json";
@DisplayName("Should execute connector and return success result")
@ParameterizedTest(name = "Executing test case # {index}")
@MethodSource("successRequestCases")
void execute_shouldExecuteAndReturnResultWhenGiveContext(String input) {
// Given
- GoogleDriveService googleDriveServiceMock = Mockito.mock(GoogleDriveService.class);
+ GoogleDriveService googleDriveServiceMock = mock(GoogleDriveService.class);
GoogleDriveFunction service = new GoogleDriveFunction(googleDriveServiceMock);
OutboundConnectorContext context =
@@ -53,7 +60,65 @@ void execute_shouldExecuteAndReturnResultWhenGiveContext(String input) {
assertThat(((GoogleDriveResult) execute).getGoogleDriveResourceUrl()).isEqualTo(FILE_URL);
}
+ @ParameterizedTest(name = "Executing test case # {index}")
+ @MethodSource("successUploadCases")
+ void execute_shouldExecuteFileUpload(String input) {
+ // Given
+ GoogleDriveService googleDriveServiceMock = mock(GoogleDriveService.class);
+ GoogleDriveFunction service = new GoogleDriveFunction(googleDriveServiceMock);
+
+ OutboundConnectorContext context =
+ getContextBuilderWithSecrets()
+ .variables(input)
+ .validation(new DefaultValidationProvider())
+ .build();
+
+ GoogleDriveResult googleDriveResult = new GoogleDriveResult();
+ googleDriveResult.setGoogleDriveResourceId(FILE_ID);
+ googleDriveResult.setGoogleDriveResourceUrl(
+ String.format(MimeTypeUrl.FILE_TEMPLATE_URL, FILE_ID));
+
+ Mockito.when(googleDriveServiceMock.execute(any(GoogleDriveClient.class), any(Resource.class)))
+ .thenReturn(googleDriveResult);
+ // When
+ Object execute = service.execute(context);
+ // Then
+ assertThat(execute).isInstanceOf(GoogleDriveResult.class);
+ assertThat(((GoogleDriveResult) execute).getGoogleDriveResourceId()).isEqualTo(FILE_ID);
+ assertThat(((GoogleDriveResult) execute).getGoogleDriveResourceUrl())
+ .isEqualTo((String.format(MimeTypeUrl.FILE_TEMPLATE_URL, FILE_ID)));
+ }
+
+ @ParameterizedTest(name = "Executing test case # {index}")
+ @MethodSource("successDownloadCases")
+ void execute_shouldExecuteFileDownload(String input) {
+ // Given
+ GoogleDriveService googleDriveServiceMock = mock(GoogleDriveService.class);
+ GoogleDriveFunction service = new GoogleDriveFunction(googleDriveServiceMock);
+
+ OutboundConnectorContext context =
+ getContextBuilderWithSecrets()
+ .variables(input)
+ .validation(new DefaultValidationProvider())
+ .build();
+
+ Mockito.when(googleDriveServiceMock.execute(any(GoogleDriveClient.class), any(Resource.class)))
+ .thenReturn(mock(Document.class));
+
+ var result = (Document) service.execute(context);
+
+ assertThat(result).isInstanceOf(Document.class);
+ }
+
private static Stream successRequestCases() throws IOException {
return BaseTest.loadTestCasesFromResourceFile(SUCCESS_CASES_RESOURCE_PATH);
}
+
+ private static Stream successUploadCases() throws IOException {
+ return BaseTest.loadTestCasesFromResourceFile(SUCCESS_UPLOAD_RESOURCE_PATH);
+ }
+
+ private static Stream successDownloadCases() throws IOException {
+ return BaseTest.loadTestCasesFromResourceFile(SUCCESS_DOWNLOAD_RESOURCE_PATH);
+ }
}
diff --git a/connectors/google/google-drive/src/test/java/io/camunda/connector/gdrive/GoogleDriveServiceTest.java b/connectors/google/google-drive/src/test/java/io/camunda/connector/gdrive/GoogleDriveServiceTest.java
index edc49cc122..83f134ddf7 100644
--- a/connectors/google/google-drive/src/test/java/io/camunda/connector/gdrive/GoogleDriveServiceTest.java
+++ b/connectors/google/google-drive/src/test/java/io/camunda/connector/gdrive/GoogleDriveServiceTest.java
@@ -9,21 +9,25 @@
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.*;
+import com.google.api.client.http.AbstractInputStreamContent;
import com.google.api.services.docs.v1.model.BatchUpdateDocumentResponse;
import com.google.api.services.docs.v1.model.Request;
+import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File;
+import io.camunda.connector.document.annotation.jackson.DocumentReferenceModel;
+import io.camunda.connector.gdrive.mapper.DocumentMapper;
import io.camunda.connector.gdrive.model.GoogleDriveResult;
import io.camunda.connector.gdrive.model.MimeTypeUrl;
-import io.camunda.connector.gdrive.model.request.GoogleDriveRequest;
+import io.camunda.connector.gdrive.model.request.*;
+import io.camunda.document.Document;
import java.io.IOException;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor;
@@ -37,13 +41,15 @@ class GoogleDriveServiceTest extends BaseTest {
private static final String SUCCESS_FILE_CASES_RESOURCE_PATH =
"src/test/resources/requests/file-success-test-cases.json";
+ private DocumentMapper documentMapper;
private GoogleDriveService service;
private GoogleDriveClient googleDriveClient;
private File file;
@BeforeEach
public void before() {
- service = new GoogleDriveService();
+ documentMapper = mock(DocumentMapper.class);
+ service = new GoogleDriveService(documentMapper);
googleDriveClient = mock(GoogleDriveClient.class);
file = new File();
file.setId(FILE_ID);
@@ -60,7 +66,7 @@ void execute_shouldCreateFolderFromRequest(String input) {
GoogleDriveRequest request = context.bindVariables(GoogleDriveRequest.class);
ArgumentCaptor captor = ArgumentCaptor.forClass(File.class);
// When
- GoogleDriveResult execute = service.execute(googleDriveClient, request.getResource());
+ var execute = (GoogleDriveResult) service.execute(googleDriveClient, request.getResource());
// Then
Mockito.verify(googleDriveClient).createWithMetadata(captor.capture());
File value = captor.getValue();
@@ -84,7 +90,7 @@ void execute_shouldCreateFileFromRequest(String input) {
Mockito.when(googleDriveClient.createWithTemplate(any(), eq(templateId))).thenReturn(file);
ArgumentCaptor captor = ArgumentCaptor.forClass(File.class);
// When
- GoogleDriveResult execute = service.execute(googleDriveClient, request.getResource());
+ var execute = (GoogleDriveResult) service.execute(googleDriveClient, request.getResource());
// Then
Mockito.verify(googleDriveClient).createWithTemplate(captor.capture(), eq(templateId));
File value = captor.getValue();
@@ -105,7 +111,7 @@ void execute_shouldCreateFileWithoutTemplate(String input) {
Mockito.when(googleDriveClient.createWithTemplate(any(), eq(templateId))).thenReturn(file);
ArgumentCaptor captor = ArgumentCaptor.forClass(File.class);
// When
- GoogleDriveResult execute = service.execute(googleDriveClient, request.getResource());
+ var execute = (GoogleDriveResult) service.execute(googleDriveClient, request.getResource());
// Then
Mockito.verify(googleDriveClient).createWithTemplate(captor.capture(), eq(templateId));
File value = captor.getValue();
@@ -133,7 +139,7 @@ void execute_shouldCreateFileAndUpdateDocument(String input) {
Mockito.when(googleDriveClient.updateDocument(any(), any())).thenReturn(response);
ArgumentCaptor> captor = ArgumentCaptor.forClass(List.class);
// When
- GoogleDriveResult execute = service.execute(googleDriveClient, request.getResource());
+ var execute = (GoogleDriveResult) service.execute(googleDriveClient, request.getResource());
// Then
verify(googleDriveClient).updateDocument(eq(FILE_ID), captor.capture());
@@ -161,6 +167,49 @@ void execute_shouldDoNotUpdateDocumentIfTypeNotDocument(String input) {
verify(googleDriveClient, never()).updateDocument(any(), any());
}
+ @Test
+ void execute_shouldUploadFile() throws IOException {
+ // Given
+ var docMetadata =
+ new DocumentReferenceModel.CamundaDocumentMetadataModel(
+ "image/png", null, 66497L, "picture", null, null, null);
+
+ Document document = Mockito.mock(Document.class);
+ when(document.metadata()).thenReturn(docMetadata);
+ when(document.asByteArray()).thenReturn(new byte[1]);
+
+ var resource =
+ new Resource(Type.UPLOAD, null, null, null, null, null, new UploadData(document));
+
+ Drive drive = mock(Drive.class, Mockito.RETURNS_DEEP_STUBS);
+
+ when(googleDriveClient.getDriveService()).thenReturn(drive);
+ when(drive.files().create(any(File.class), any(AbstractInputStreamContent.class)).execute())
+ .thenReturn(new File().setId("1"));
+
+ var result = service.execute(googleDriveClient, resource);
+ assertThat(result).isInstanceOf(GoogleDriveResult.class);
+ assertThat(((GoogleDriveResult) result).getGoogleDriveResourceId()).isEqualTo("1");
+ assertThat(((GoogleDriveResult) result).getGoogleDriveResourceUrl())
+ .isEqualTo(String.format(MimeTypeUrl.FILE_TEMPLATE_URL, "1"));
+ }
+
+ @Test
+ void execute_shouldDownloadFile() throws IOException {
+ var resource = new Resource(Type.DOWNLOAD, null, null, null, null, new DownloadData("1"), null);
+
+ when(documentMapper.mapToDocument(any(), any(File.class))).thenReturn(mock(Document.class));
+ Drive drive = mock(Drive.class, Mockito.RETURNS_DEEP_STUBS);
+ when(googleDriveClient.getDriveService()).thenReturn(drive);
+ when(drive.files().get(anyString()).execute()).thenReturn(new File());
+ Drive.Files.Get getFile = mock(Drive.Files.Get.class);
+ doNothing().when(getFile).executeAndDownloadTo(any());
+
+ var result = service.execute(googleDriveClient, resource);
+
+ assertThat(result).isInstanceOf(Document.class);
+ }
+
private static Stream successFolderRequestCases() throws IOException {
return BaseTest.loadTestCasesFromResourceFile(SUCCESS_FOLDER_CASES_RESOURCE_PATH);
}
diff --git a/connectors/google/google-drive/src/test/java/io/camunda/connector/gdrive/mapper/DocumentMapperTest.java b/connectors/google/google-drive/src/test/java/io/camunda/connector/gdrive/mapper/DocumentMapperTest.java
new file mode 100644
index 0000000000..6f19dc1b5f
--- /dev/null
+++ b/connectors/google/google-drive/src/test/java/io/camunda/connector/gdrive/mapper/DocumentMapperTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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.gdrive.mapper;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import com.google.api.services.drive.model.File;
+import io.camunda.connector.api.outbound.OutboundConnectorContext;
+import io.camunda.connector.test.outbound.OutboundConnectorContextBuilder;
+import org.junit.jupiter.api.Test;
+
+class DocumentMapperTest {
+
+ @Test
+ void mapToDocument() {
+ OutboundConnectorContext context = OutboundConnectorContextBuilder.create().build();
+ DocumentMapper mapper = new DocumentMapper(context);
+
+ File file = new File();
+ file.setMimeType("text/plain");
+ file.setName("book.txt");
+ var document = mapper.mapToDocument(new byte[1], file);
+
+ assertThat(document.metadata().getFileName()).isEqualTo("book.txt");
+ assertThat(document.metadata().getContentType()).isEqualTo("text/plain");
+ }
+}
diff --git a/connectors/google/google-drive/src/test/resources/requests/file-success-download.json b/connectors/google/google-drive/src/test/resources/requests/file-success-download.json
new file mode 100644
index 0000000000..b7c68debe8
--- /dev/null
+++ b/connectors/google/google-drive/src/test/resources/requests/file-success-download.json
@@ -0,0 +1,24 @@
+[
+ {
+ "resource" : {
+ "type" : "upload",
+ "uploadData" : {
+ "document" : {
+ "camunda.document.type" : "camunda",
+ "storeId" : "in-memory",
+ "documentId" : "ffcf4b5e-6427-40aa-9131-65c142a8f380",
+ "metadata" : {
+ "contentType" : "image/png",
+ "fileName" : "google-my-business-logo-png-transparent.png",
+ "size" : 66497,
+ "customProperties" : { }
+ }
+ }
+ }
+ },
+ "authentication" : {
+ "authType" : "bearer",
+ "bearerToken" : "{{secrets.MyToken}}"
+ }
+ }
+]
\ No newline at end of file
diff --git a/connectors/google/google-drive/src/test/resources/requests/file-success-upload.json b/connectors/google/google-drive/src/test/resources/requests/file-success-upload.json
new file mode 100644
index 0000000000..213173fa68
--- /dev/null
+++ b/connectors/google/google-drive/src/test/resources/requests/file-success-upload.json
@@ -0,0 +1,25 @@
+[
+ {
+ "resource": {
+ "type": "upload",
+ "parent": "1naPUVnG7at2Z058e1uMYHj3PHo3DrdCZ",
+ "uploadData": {
+ "document": {
+ "camunda.document.type": "camunda",
+ "storeId": "in-memory",
+ "documentId": "ffcf4b5e-6427-40aa-9131-65c142a8f380",
+ "metadata": {
+ "contentType": "image/png",
+ "fileName": "google-my-business-logo-png-transparent.png",
+ "size": 66497,
+ "customProperties": {}
+ }
+ }
+ }
+ },
+ "authentication": {
+ "authType": "bearer",
+ "bearerToken": "{{secrets.MyToken}}"
+ }
+ }
+]
\ No newline at end of file
diff --git a/connectors/google/google-drive/src/test/resources/requests/request-fail-test-cases.json b/connectors/google/google-drive/src/test/resources/requests/request-fail-test-cases.json
index a53b5e1f63..d65da9890b 100644
--- a/connectors/google/google-drive/src/test/resources/requests/request-fail-test-cases.json
+++ b/connectors/google/google-drive/src/test/resources/requests/request-fail-test-cases.json
@@ -10,50 +10,6 @@
"parent":"1wF4ME7XcM_6ZIaNCMADMXawzV5"
}
},
- {
- "testDescription": "Folder without a name",
- "authentication": {
- "authType": "bearer",
- "bearerToken": "MyRealToken"
- },
- "resource": {
- "type":"folder",
- "additionalGoogleDriveProperties":{
- "description":"xxx"
- },
- "parent":"1wF4ME7XcM_6ZIaNCMADMXawzV5DpVqXw"
- }
- },
- {
- "testDescription": "File without a name",
- "authentication": {
- "authType": "bearer",
- "bearerToken": "myRealToken"
- },
- "resource": {
- "type": "file",
- "parent": "optional my idFolderParent",
- "additionalGoogleDriveProperties": {
- "description": " description"
- },
- "template": {
- "id": "myTemplateId",
- "variables": {
- "requests":[
- {
- "replaceAllText":{
- "containsText":{
- "text":"replaceFrom",
- "matchCase":"true"
- },
- "replaceText":"replaceTo"
- }
- }
- ]
- }
- }
- }
- },
{
"resource": {
"type": "file",