Skip to content

Commit

Permalink
feat(drive): document upload and download
Browse files Browse the repository at this point in the history
  • Loading branch information
DenovVasil committed Jan 23, 2025
1 parent fb7977e commit 602fb6a
Show file tree
Hide file tree
Showing 18 changed files with 537 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@
}, {
"name" : "Create file from template",
"value" : "file"
}, {
"name" : "Upload file",
"value" : "upload"
}, {
"name" : "Download file",
"value" : "download"
} ]
}, {
"id" : "resource.name",
Expand All @@ -177,6 +183,11 @@
"name" : "resource.name",
"type" : "zeebe:input"
},
"condition" : {
"property" : "resource.type",
"oneOf" : [ "folder", "file" ],
"type" : "simple"
},
"type" : "String"
}, {
"id" : "resource.parent",
Expand All @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@
}, {
"name" : "Create file from template",
"value" : "file"
}, {
"name" : "Upload file",
"value" : "upload"
}, {
"name" : "Download file",
"value" : "download"
} ]
}, {
"id" : "resource.name",
Expand All @@ -182,6 +188,11 @@
"name" : "resource.name",
"type" : "zeebe:input"
},
"condition" : {
"property" : "resource.type",
"oneOf" : [ "folder", "file" ],
"type" : "simple"
},
"type" : "String"
}, {
"id" : "resource.parent",
Expand All @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,12 @@ public BatchUpdateDocumentResponse updateDocument(
throw new RuntimeException(e);
}
}

public Drive getDriveService() {
return driveService;
}

public Docs getDocsService() {
return docsService;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
};
}

Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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: <a
* href="https://developers.google.com/api-client-library/java/google-api-java-client/media-upload#implementation">...</a>
*/
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!");
}
}
}
Original file line number Diff line number Diff line change
@@ -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());
}
}
Loading

0 comments on commit 602fb6a

Please sign in to comment.