diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 5554efe3..f02fa5ce 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -19,10 +19,12 @@ jobs: Test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-java@v1 + - uses: actions/checkout@v4 + - name: Set up Java + uses: actions/setup-java@v3 with: - java-version: "1.8" + java-version: "11" + distribution: 'temurin' - name: create-json id: create-json diff --git a/src/main/java/com/skyflow/VaultClient.java b/src/main/java/com/skyflow/VaultClient.java index ff1c1343..15779cbb 100644 --- a/src/main/java/com/skyflow/VaultClient.java +++ b/src/main/java/com/skyflow/VaultClient.java @@ -3,11 +3,15 @@ import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; import com.skyflow.enums.DetectEntities; +import com.skyflow.enums.DetectOutputTranscriptions; import com.skyflow.errors.ErrorCode; import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.ApiClient; import com.skyflow.generated.rest.ApiClientBuilder; +import com.skyflow.generated.rest.resources.files.FilesClient; +import com.skyflow.generated.rest.resources.files.requests.*; +import com.skyflow.generated.rest.resources.files.types.*; import com.skyflow.generated.rest.resources.query.QueryClient; import com.skyflow.generated.rest.resources.records.RecordsClient; import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; @@ -31,6 +35,8 @@ import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.UpdateRequest; import com.skyflow.vault.detect.*; +import com.skyflow.vault.detect.DeidentifyFileRequest; +import com.skyflow.vault.detect.DeidentifyTextRequest; import com.skyflow.vault.tokens.ColumnValue; import com.skyflow.vault.tokens.DetokenizeData; import com.skyflow.vault.tokens.DetokenizeRequest; @@ -72,6 +78,10 @@ protected StringsClient getDetectTextApi() { return this.apiClient.strings(); } + protected FilesClient getDetectFileAPi(){ + return this.apiClient.files(); + } + protected QueryClient getQueryApi() { return this.apiClient.query(); } @@ -208,8 +218,8 @@ protected void setBearerToken() throws SkyflowException { prioritiseCredentials(); Validations.validateCredentials(this.finalCredentials); if (this.finalCredentials.getApiKey() != null) { - setApiKey(); - return; + LogUtil.printInfoLog(InfoLogs.REUSE_API_KEY.getLog()); + token=this.finalCredentials.getApiKey(); } else if (Token.isExpired(token)) { LogUtil.printInfoLog(InfoLogs.BEARER_TOKEN_EXPIRED.getLog()); token = Utils.generateBearerToken(this.finalCredentials); @@ -382,13 +392,389 @@ private Transformations getTransformations(com.skyflow.vault.detect.Transformati .build(); } - private void setApiKey() { - if (apiKey == null) { - apiKey = this.finalCredentials.getApiKey(); - } else { - LogUtil.printInfoLog(InfoLogs.REUSE_API_KEY.getLog()); + private List getEntityTypes(List entities){ + List mappedEntityTypes = null; + if (entities != null) { + mappedEntityTypes = entities.stream() + .map(detectEntity -> EntityType.valueOf(detectEntity.name())) + .collect(Collectors.toList()); } - this.apiClientBuilder.token(token); + + return mappedEntityTypes; + } + + protected com.skyflow.generated.rest.resources.files.requests.DeidentifyTextRequest getDeidentifyTextFileRequest(DeidentifyFileRequest request, String vaultId, String base64Content){ + List mappedEntityTypes = getEntityTypes(request.getEntities()); + + TokenFormat tokenFormat = request.getTokenFormat(); + + Optional> entityTypes = Optional.empty(); + Optional> entityUniqueCounter = Optional.empty(); + Optional> allowRegex = Optional.ofNullable(request.getAllowRegexList()); + Optional> restrictRegex = Optional.ofNullable(request.getRestrictRegexList()); + Optional transformations = Optional.ofNullable(getTransformations(request.getTransformations())); + + if (tokenFormat != null) { + + if (tokenFormat.getEntityOnly() != null && !tokenFormat.getEntityOnly().isEmpty()) { + entityTypes = Optional.of(tokenFormat.getEntityOnly().stream() + .map(detectEntity -> EntityType.valueOf(detectEntity.name())) + .collect(Collectors.toList())); + } + + if (tokenFormat.getEntityUniqueCounter() != null && !tokenFormat.getEntityUniqueCounter().isEmpty()) { + entityUniqueCounter = Optional.of(tokenFormat.getEntityUniqueCounter().stream() + .map(detectEntity -> EntityType.valueOf(detectEntity.name())) + .collect(Collectors.toList())); + } + } + + TokenTypeWithoutVault tokenType = TokenTypeWithoutVault.builder() + .entityOnly(entityTypes) + .entityUnqCounter(entityUniqueCounter) + .build(); + + DeidentifyTextRequestFile file = DeidentifyTextRequestFile.builder() + .base64(base64Content) + .build(); + + // Build the final request + com.skyflow.generated.rest.resources.files.requests.DeidentifyTextRequest req = + com.skyflow.generated.rest.resources.files.requests.DeidentifyTextRequest.builder() + .vaultId(vaultId) + .file(file) + .entityTypes(mappedEntityTypes) + .tokenType(tokenType) + .allowRegex(allowRegex) + .restrictRegex(restrictRegex) + .transformations(transformations) + .build(); + + return req; + } + + + protected DeidentifyAudioRequest getDeidentifyAudioRequest(DeidentifyFileRequest request, String vaultId, String base64Content, String dataFormat){ + List mappedEntityTypes = getEntityTypes(request.getEntities()); + + TokenFormat tokenFormat = request.getTokenFormat(); + + Optional> entityTypes = Optional.empty(); + Optional> entityUniqueCounter = Optional.empty(); + Optional> allowRegex = Optional.ofNullable(request.getAllowRegexList()); + Optional> restrictRegex = Optional.ofNullable(request.getRestrictRegexList()); + Optional transformations = Optional.ofNullable(getTransformations(request.getTransformations())); + + if (tokenFormat != null) { + + if (tokenFormat.getEntityOnly() != null && !tokenFormat.getEntityOnly().isEmpty()) { + entityTypes = Optional.of(tokenFormat.getEntityOnly().stream() + .map(detectEntity -> EntityType.valueOf(detectEntity.name())) + .collect(Collectors.toList())); + } + + if (tokenFormat.getEntityUniqueCounter() != null && !tokenFormat.getEntityUniqueCounter().isEmpty()) { + entityUniqueCounter = Optional.of(tokenFormat.getEntityUniqueCounter().stream() + .map(detectEntity -> EntityType.valueOf(detectEntity.name())) + .collect(Collectors.toList())); + } + } + + TokenTypeWithoutVault tokenType = TokenTypeWithoutVault.builder() + .entityOnly(entityTypes) + .entityUnqCounter(entityUniqueCounter) + .build(); + + DeidentifyAudioRequestFile deidentifyAudioRequestFile = DeidentifyAudioRequestFile.builder().base64(base64Content).dataFormat(DeidentifyAudioRequestFileDataFormat.valueOf(dataFormat)).build(); + DetectOutputTranscriptions transcription = request.getOutputTranscription(); + DeidentifyAudioRequestOutputTranscription outputTranscriptionType = null; + if (transcription != null) { + outputTranscriptionType = DeidentifyAudioRequestOutputTranscription.valueOf(transcription.name()); + } + + return DeidentifyAudioRequest.builder() + .vaultId(vaultId) + .file(deidentifyAudioRequestFile) + .allowRegex(allowRegex) + .restrictRegex(restrictRegex) + .entityTypes(mappedEntityTypes) + .bleepFrequency(request.getBleep().getFrequency()) + .bleepGain(request.getBleep().getGain()) + .bleepStartPadding(request.getBleep().getStartPadding()) + .bleepStopPadding(request.getBleep().getStopPadding()) + .outputProcessedAudio(request.getOutputProcessedAudio()) + .outputTranscription(outputTranscriptionType) + .tokenType(tokenType) + .transformations(transformations) + .build(); + } + + // Add to VaultClient.java class + protected DeidentifyPdfRequest getDeidentifyPdfRequest(DeidentifyFileRequest request, String vaultId, String base64Content) { + List mappedEntityTypes = getEntityTypes(request.getEntities()); + + TokenFormat tokenFormat = request.getTokenFormat(); + Optional> entityTypes = Optional.empty(); + Optional> entityUniqueCounter = Optional.empty(); + Optional> allowRegex = Optional.ofNullable(request.getAllowRegexList()); + Optional> restrictRegex = Optional.ofNullable(request.getRestrictRegexList()); + Optional transformations = Optional.ofNullable(getTransformations(request.getTransformations())); + + if (tokenFormat != null) { + if (tokenFormat.getEntityOnly() != null && !tokenFormat.getEntityOnly().isEmpty()) { + entityTypes = Optional.of(tokenFormat.getEntityOnly().stream() + .map(detectEntity -> EntityType.valueOf(detectEntity.name())) + .collect(Collectors.toList())); + } + + if (tokenFormat.getEntityUniqueCounter() != null && !tokenFormat.getEntityUniqueCounter().isEmpty()) { + entityUniqueCounter = Optional.of(tokenFormat.getEntityUniqueCounter().stream() + .map(detectEntity -> EntityType.valueOf(detectEntity.name())) + .collect(Collectors.toList())); + } + } + + TokenTypeWithoutVault tokenType = TokenTypeWithoutVault.builder() + .entityOnly(entityTypes) + .entityUnqCounter(entityUniqueCounter) + .build(); + + DeidentifyPdfRequestFile file = DeidentifyPdfRequestFile.builder() + .base64(base64Content) + .build(); + + return DeidentifyPdfRequest.builder() + .vaultId(vaultId) + .file(file) + .density(request.getPixelDensity() != null ? request.getPixelDensity().intValue() : null) + .maxResolution(request.getMaxResolution() != null ? request.getMaxResolution().intValue() : null) + .entityTypes(mappedEntityTypes) + .tokenType(tokenType) + .allowRegex(allowRegex) + .restrictRegex(restrictRegex) + .transformations(transformations) + .build(); + } + + protected DeidentifyImageRequest getDeidentifyImageRequest(DeidentifyFileRequest request, String vaultId, String base64Content, String format) { + List mappedEntityTypes = getEntityTypes(request.getEntities()); + + TokenFormat tokenFormat = request.getTokenFormat(); + Optional> entityTypes = Optional.empty(); + Optional> entityUniqueCounter = Optional.empty(); + Optional> allowRegex = Optional.ofNullable(request.getAllowRegexList()); + Optional> restrictRegex = Optional.ofNullable(request.getRestrictRegexList()); + Optional transformations = Optional.ofNullable(getTransformations(request.getTransformations())); + + TokenTypeWithoutVault tokenType = buildTokenType(tokenFormat, entityTypes, entityUniqueCounter); + + DeidentifyImageRequestFile file = DeidentifyImageRequestFile.builder() + .base64(base64Content) + .dataFormat(DeidentifyImageRequestFileDataFormat.valueOf(format.toUpperCase())) + .build(); + + Optional maskingMethod = Optional.empty(); + if (request.getMaskingMethod() != null) { + maskingMethod = Optional.of(DeidentifyImageRequestMaskingMethod.valueOf(request.getMaskingMethod().name())); + } + + return DeidentifyImageRequest.builder() + .vaultId(vaultId) + .file(file) + .entityTypes(mappedEntityTypes) + .maskingMethod(maskingMethod) + .tokenType(tokenType) + .allowRegex(allowRegex) + .restrictRegex(restrictRegex) + .transformations(transformations) + .outputProcessedImage(request.getOutputProcessedImage()) + .outputOcrText(request.getOutputOcrText()) + .build(); + } + + protected DeidentifyPresentationRequest getDeidentifyPresentationRequest(DeidentifyFileRequest request, String vaultId, String base64Content, String format) { + List mappedEntityTypes = getEntityTypes(request.getEntities()); + TokenFormat tokenFormat = request.getTokenFormat(); + + Optional> entityTypes = Optional.empty(); + Optional> entityUniqueCounter = Optional.empty(); + Optional> allowRegex = Optional.ofNullable(request.getAllowRegexList()); + Optional> restrictRegex = Optional.ofNullable(request.getRestrictRegexList()); + Optional transformations = Optional.ofNullable(getTransformations(request.getTransformations())); + + TokenTypeWithoutVault tokenType = buildTokenType(tokenFormat, entityTypes, entityUniqueCounter); + + DeidentifyPresentationRequestFile file = DeidentifyPresentationRequestFile.builder() + .base64(base64Content) + .dataFormat(DeidentifyPresentationRequestFileDataFormat.valueOf(format.toUpperCase())) + .build(); + + return DeidentifyPresentationRequest.builder() + .vaultId(vaultId) + .file(file) + .entityTypes(mappedEntityTypes) + .tokenType(tokenType) + .allowRegex(allowRegex) + .restrictRegex(restrictRegex) + .transformations(transformations) + .build(); + } + + protected DeidentifySpreadsheetRequest getDeidentifySpreadsheetRequest(DeidentifyFileRequest request, String vaultId, String base64Content, String format) { + List mappedEntityTypes = getEntityTypes(request.getEntities()); + TokenFormat tokenFormat = request.getTokenFormat(); + + Optional> entityTypes = Optional.empty(); + Optional> entityUniqueCounter = Optional.empty(); + Optional> allowRegex = Optional.ofNullable(request.getAllowRegexList()); + Optional> restrictRegex = Optional.ofNullable(request.getRestrictRegexList()); + Optional transformations = Optional.ofNullable(getTransformations(request.getTransformations())); + + TokenTypeWithoutVault tokenType = buildTokenType(tokenFormat, entityTypes, entityUniqueCounter); + + DeidentifySpreadsheetRequestFile file = DeidentifySpreadsheetRequestFile.builder() + .base64(base64Content) + .dataFormat(DeidentifySpreadsheetRequestFileDataFormat.valueOf(format.toUpperCase())) + .build(); + + return DeidentifySpreadsheetRequest.builder() + .vaultId(vaultId) + .file(file) + .entityTypes(mappedEntityTypes) + .tokenType(tokenType) + .allowRegex(allowRegex) + .restrictRegex(restrictRegex) + .transformations(transformations) + .build(); + } + + protected DeidentifyStructuredTextRequest getDeidentifyStructuredTextRequest(DeidentifyFileRequest request, String vaultId, String base64Content, String format) { + List mappedEntityTypes = getEntityTypes(request.getEntities()); + TokenFormat tokenFormat = request.getTokenFormat(); + + Optional> entityTypes = Optional.empty(); + Optional> entityUniqueCounter = Optional.empty(); + Optional> allowRegex = Optional.ofNullable(request.getAllowRegexList()); + Optional> restrictRegex = Optional.ofNullable(request.getRestrictRegexList()); + Optional transformations = Optional.ofNullable(getTransformations(request.getTransformations())); + + TokenTypeWithoutVault tokenType = buildTokenType(tokenFormat, entityTypes, entityUniqueCounter); + + DeidentifyStructuredTextRequestFile file = DeidentifyStructuredTextRequestFile.builder() + .base64(base64Content) + .dataFormat(DeidentifyStructuredTextRequestFileDataFormat.valueOf(format.toUpperCase())) + .build(); + + return DeidentifyStructuredTextRequest.builder() + .vaultId(vaultId) + .file(file) + .entityTypes(mappedEntityTypes) + .tokenType(tokenType) + .allowRegex(allowRegex) + .restrictRegex(restrictRegex) + .transformations(transformations) + .build(); + } + + protected DeidentifyDocumentRequest getDeidentifyDocumentRequest(DeidentifyFileRequest request, String vaultId, String base64Content, String format) { + List mappedEntityTypes = getEntityTypes(request.getEntities()); + TokenFormat tokenFormat = request.getTokenFormat(); + + Optional> entityTypes = Optional.empty(); + Optional> entityUniqueCounter = Optional.empty(); + Optional> allowRegex = Optional.ofNullable(request.getAllowRegexList()); + Optional> restrictRegex = Optional.ofNullable(request.getRestrictRegexList()); + Optional transformations = Optional.ofNullable(getTransformations(request.getTransformations())); + + TokenTypeWithoutVault tokenType = buildTokenType(tokenFormat, entityTypes, entityUniqueCounter); + + DeidentifyDocumentRequestFile file = DeidentifyDocumentRequestFile.builder() + .base64(base64Content) + .dataFormat(DeidentifyDocumentRequestFileDataFormat.valueOf(format.toUpperCase())) + .build(); + + return DeidentifyDocumentRequest.builder() + .vaultId(vaultId) + .file(file) + .entityTypes(mappedEntityTypes) + .tokenType(tokenType) + .allowRegex(allowRegex) + .restrictRegex(restrictRegex) + .transformations(transformations) + .build(); + } + + protected com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest getDeidentifyGenericFileRequest( + DeidentifyFileRequest request, String vaultId, String base64Content, String fileExtension) { + + List mappedEntityTypes = getEntityTypes(request.getEntities()); + + TokenFormat tokenFormat = request.getTokenFormat(); + + Optional> entityTypes = Optional.empty(); + Optional> entityUniqueCounter = Optional.empty(); + Optional> allowRegex = Optional.ofNullable(request.getAllowRegexList()); + Optional> restrictRegex = Optional.ofNullable(request.getRestrictRegexList()); + Optional transformations = Optional.ofNullable(getTransformations(request.getTransformations())); + + if (tokenFormat != null) { + if (tokenFormat.getEntityOnly() != null && !tokenFormat.getEntityOnly().isEmpty()) { + entityTypes = Optional.of(tokenFormat.getEntityOnly().stream() + .map(detectEntity -> EntityType.valueOf(detectEntity.name())) + .collect(Collectors.toList())); + } + + if (tokenFormat.getEntityUniqueCounter() != null && !tokenFormat.getEntityUniqueCounter().isEmpty()) { + entityUniqueCounter = Optional.of(tokenFormat.getEntityUniqueCounter().stream() + .map(detectEntity -> EntityType.valueOf(detectEntity.name())) + .collect(Collectors.toList())); + } + } + + TokenTypeWithoutVault tokenType = TokenTypeWithoutVault.builder() + .entityOnly(entityTypes) + .entityUnqCounter(entityUniqueCounter) + .build(); + + DeidentifyFileRequestFile file = + DeidentifyFileRequestFile.builder() + .base64(base64Content) + .dataFormat(fileExtension != null ? DeidentifyFileRequestFileDataFormat.valueOf(fileExtension.toUpperCase()) : null) + .build(); + + return com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest.builder() + .vaultId(vaultId) + .file(file) + .entityTypes(mappedEntityTypes) + .tokenType(tokenType) + .allowRegex(allowRegex) + .restrictRegex(restrictRegex) + .transformations(transformations) + .build(); + } + + private TokenTypeWithoutVault buildTokenType(TokenFormat tokenFormat, + Optional> entityTypes, + Optional> entityUniqueCounter) { + + if (tokenFormat != null) { + if (tokenFormat.getEntityOnly() != null && !tokenFormat.getEntityOnly().isEmpty()) { + entityTypes = Optional.of(tokenFormat.getEntityOnly().stream() + .map(detectEntity -> EntityType.valueOf(detectEntity.name())) + .collect(Collectors.toList())); + } + + if (tokenFormat.getEntityUniqueCounter() != null && !tokenFormat.getEntityUniqueCounter().isEmpty()) { + entityUniqueCounter = Optional.of(tokenFormat.getEntityUniqueCounter().stream() + .map(detectEntity -> EntityType.valueOf(detectEntity.name())) + .collect(Collectors.toList())); + } + } + + return TokenTypeWithoutVault.builder() + .entityOnly(entityTypes) + .entityUnqCounter(entityUniqueCounter) + .build(); } private void updateVaultURL() { diff --git a/src/main/java/com/skyflow/errors/ErrorMessage.java b/src/main/java/com/skyflow/errors/ErrorMessage.java index 1c9c0202..768b175b 100644 --- a/src/main/java/com/skyflow/errors/ErrorMessage.java +++ b/src/main/java/com/skyflow/errors/ErrorMessage.java @@ -129,6 +129,21 @@ public enum ErrorMessage { InvalidEmptyTextInDeIdentify("%s0 Validation error. The text field is required string and must not be empty string. Specify a valid text."), InvalidNullTextInReIdentify("%s0 Validation error. The text field is required string and must not be null. Specify a valid text."), InvalidEmptyTextInReIdentify("%s0 Validation error. The text field is required string and must not be empty string. Specify a valid text."), + + //Detect Files + InvalidNullFileInDeIdentifyFile("%s0 Validation error. The file field is required and must not be null. Specify a valid file object."), + FileNotFoundToDeidentify("%s0 Validation error. The file to deidentify was not found at the specified path. Verify the file path and try again."), + FileNotReadableToDeidentify("%s0 Validation error. The file to deidentify is not readable. Check the file permissions and try again."), + InvalidPixelDensityToDeidentifyFile("%s0 Validation error. Should be a positive integer. Specify a valid pixel density."), + InvalidMaxResolution("%s0 Validation error. Should be a positive integer. Specify a valid max resolution."), + OutputDirectoryNotFound("%s0 Validation error. The output directory for deidentified files was not found at the specified path. Verify the output directory path and try again."), + InvalidPermission("%s0 Validation error. The output directory for deidentified files is not writable. Check the directory permissions and try again."), + InvalidWaitTime("%s0 Validation error. The wait time for deidentify file operation should be a positive integer. Specify a valid wait time."), + WaitTimeExceedsLimit("%s0 Validation error. The wait time for deidentify file operation exceeds the maximum limit of 64 seconds. Specify a wait time less than or equal to 60 seconds."), + InvalidOrEmptyRunId("%s0 Validation error. The run ID is invalid or empty. Specify a valid run ID."), + FailedToEncodeFile("%s0 Validation error. Failed to encode the file. Ensure the file is in a supported format and try again."), + PollingForResultsFailed("%s0 API error. Polling for results failed. Unable to retrieve the deidentified file"), + FailedtoSaveProcessedFile("%s0 Validation error. Failed to save the processed file. Ensure the output directory is valid and writable."), ; private final String message; diff --git a/src/main/java/com/skyflow/errors/SkyflowException.java b/src/main/java/com/skyflow/errors/SkyflowException.java index a455521d..51807323 100644 --- a/src/main/java/com/skyflow/errors/SkyflowException.java +++ b/src/main/java/com/skyflow/errors/SkyflowException.java @@ -41,18 +41,37 @@ public SkyflowException(int httpCode, Throwable cause, Map> super(cause); this.httpCode = httpCode; setRequestId(responseHeaders); - setResponseBody(responseBody, responseHeaders); + // Determine if responseBody is a JSON string with "error" key or a plain string + if (isJsonWithErrorObject(responseBody)) { + setResponseBodyFromJson(responseBody, responseHeaders); + } else { + this.message = responseBody; + this.details = new JsonArray(); + } } - private void setResponseBody(String responseBody, Map> responseHeaders) { + // Helper to check if responseBody is a JSON string with "error" key + private boolean isJsonWithErrorObject(String responseBody) { + try { + if (responseBody == null) return false; + JsonObject obj = JsonParser.parseString(responseBody).getAsJsonObject(); + return obj.has("error"); + } catch (Exception e) { + return false; + } + } + + // Handles new error structure: {error={grpc_code=3, http_code=400, message=..., http_status=..., details=[]}} + private void setResponseBodyFromJson(String responseBody, Map> responseHeaders) { try { if (responseBody != null) { this.responseBody = JsonParser.parseString(responseBody).getAsJsonObject(); - if (this.responseBody.get("error") != null) { - setGrpcCode(); - setHttpStatus(); - setMessage(); - setDetails(responseHeaders); + if (this.responseBody.has("error")) { + JsonObject errorObj = this.responseBody.getAsJsonObject("error"); + setGrpcCode(errorObj); + setHttpStatus(errorObj); + setMessage(errorObj); + setDetails(errorObj, responseHeaders); } } } catch (JsonSyntaxException e) { @@ -71,21 +90,43 @@ private void setRequestId(Map> responseHeaders) { } } + // For legacy error structure private void setMessage() { JsonElement messageElement = ((JsonObject) responseBody.get("error")).get("message"); this.message = messageElement == null ? null : messageElement.getAsString(); } + // For new error structure + private void setMessage(JsonObject errorObj) { + JsonElement messageElement = errorObj.get("message"); + this.message = messageElement == null ? null : messageElement.getAsString(); + } + + // For legacy error structure private void setGrpcCode() { JsonElement grpcElement = ((JsonObject) responseBody.get("error")).get("grpc_code"); this.grpcCode = grpcElement == null ? null : grpcElement.getAsInt(); } + // For new error structure + private void setGrpcCode(JsonObject errorObj) { + JsonElement grpcElement = errorObj.get("grpc_code"); + this.grpcCode = grpcElement == null ? null : grpcElement.getAsInt(); + } + + // For legacy error structure private void setHttpStatus() { JsonElement statusElement = ((JsonObject) responseBody.get("error")).get("http_status"); this.httpStatus = statusElement == null ? null : statusElement.getAsString(); } + // For new error structure + private void setHttpStatus(JsonObject errorObj) { + JsonElement statusElement = errorObj.get("http_status"); + this.httpStatus = statusElement == null ? null : statusElement.getAsString(); + } + + // For legacy error structure private void setDetails(Map> responseHeaders) { JsonElement detailsElement = ((JsonObject) responseBody.get("error")).get("details"); List errorFromClientHeader = responseHeaders.get("error-from-client"); @@ -101,6 +142,22 @@ private void setDetails(Map> responseHeaders) { } } + // For new error structure + private void setDetails(JsonObject errorObj, Map> responseHeaders) { + JsonElement detailsElement = errorObj.get("details"); + List errorFromClientHeader = responseHeaders.get("error-from-client"); + if (detailsElement != null && detailsElement.isJsonArray()) { + this.details = detailsElement.getAsJsonArray(); + } + if (errorFromClientHeader != null) { + this.details = this.details == null ? new JsonArray() : this.details; + String errorFromClient = errorFromClientHeader.get(0); + JsonObject detailObject = new JsonObject(); + detailObject.addProperty("errorFromClient", errorFromClient); + this.details.add(detailObject); + } + } + public int getHttpCode() { return httpCode; } diff --git a/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java b/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java index b8fd75da..aed28706 100644 --- a/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java +++ b/src/main/java/com/skyflow/generated/rest/core/ClientOptions.java @@ -34,7 +34,7 @@ private ClientOptions( { put("X-Fern-Language", "JAVA"); put("X-Fern-SDK-Name", "com.skyflow.fern:api-sdk"); - put("X-Fern-SDK-Version", "0.0.202"); + put("X-Fern-SDK-Version", "0.0.208"); } }); this.headerSuppliers = headerSuppliers; diff --git a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyImageRequestMaskingMethod.java b/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyImageRequestMaskingMethod.java index 23ae2bcf..8cf5bf3c 100644 --- a/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyImageRequestMaskingMethod.java +++ b/src/main/java/com/skyflow/generated/rest/resources/files/types/DeidentifyImageRequestMaskingMethod.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.annotation.JsonValue; public enum DeidentifyImageRequestMaskingMethod { - BLACKOUT("blackout"), + BLACKBOX("blackbox"), BLUR("blur"); diff --git a/src/main/java/com/skyflow/generated/rest/types/DeidentifyStatusResponseOutputType.java b/src/main/java/com/skyflow/generated/rest/types/DeidentifyStatusResponseOutputType.java index fa272863..547bf414 100644 --- a/src/main/java/com/skyflow/generated/rest/types/DeidentifyStatusResponseOutputType.java +++ b/src/main/java/com/skyflow/generated/rest/types/DeidentifyStatusResponseOutputType.java @@ -6,9 +6,11 @@ import com.fasterxml.jackson.annotation.JsonValue; public enum DeidentifyStatusResponseOutputType { - BASE_64("base64"), + BASE_64("BASE64"), - EFS_PATH("efs_path"); + EFS_PATH("EFS_PATH"), + + UNKNOWN("UNKNOWN"); private final String value; diff --git a/src/main/java/com/skyflow/generated/rest/types/DeidentifyStatusResponseStatus.java b/src/main/java/com/skyflow/generated/rest/types/DeidentifyStatusResponseStatus.java index f350a9e7..4e51e5cf 100644 --- a/src/main/java/com/skyflow/generated/rest/types/DeidentifyStatusResponseStatus.java +++ b/src/main/java/com/skyflow/generated/rest/types/DeidentifyStatusResponseStatus.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.annotation.JsonValue; public enum DeidentifyStatusResponseStatus { - FAILED("failed"), + FAILED("FAILED"), - IN_PROGRESS("in_progress"), + IN_PROGRESS("IN_PROGRESS"), - SUCCESS("success"); + SUCCESS("SUCCESS"); private final String value; diff --git a/src/main/java/com/skyflow/generated/rest/types/ReidentifyStringResponse.java b/src/main/java/com/skyflow/generated/rest/types/ReidentifyStringResponse.java index d9664081..655801c4 100644 --- a/src/main/java/com/skyflow/generated/rest/types/ReidentifyStringResponse.java +++ b/src/main/java/com/skyflow/generated/rest/types/ReidentifyStringResponse.java @@ -20,21 +20,21 @@ @JsonInclude(JsonInclude.Include.NON_ABSENT) @JsonDeserialize(builder = ReidentifyStringResponse.Builder.class) public final class ReidentifyStringResponse { - private final Optional processedText; + private final Optional text; private final Map additionalProperties; - private ReidentifyStringResponse(Optional processedText, Map additionalProperties) { - this.processedText = processedText; + private ReidentifyStringResponse(Optional text, Map additionalProperties) { + this.text = text; this.additionalProperties = additionalProperties; } /** * @return Re-identified text. */ - @JsonProperty("processed_text") - public Optional getProcessedText() { - return processedText; + @JsonProperty("text") + public Optional getText() { + return text; } @java.lang.Override @@ -49,12 +49,12 @@ public Map getAdditionalProperties() { } private boolean equalTo(ReidentifyStringResponse other) { - return processedText.equals(other.processedText); + return text.equals(other.text); } @java.lang.Override public int hashCode() { - return Objects.hash(this.processedText); + return Objects.hash(this.text); } @java.lang.Override @@ -68,7 +68,7 @@ public static Builder builder() { @JsonIgnoreProperties(ignoreUnknown = true) public static final class Builder { - private Optional processedText = Optional.empty(); + private Optional text = Optional.empty(); @JsonAnySetter private Map additionalProperties = new HashMap<>(); @@ -76,23 +76,23 @@ public static final class Builder { private Builder() {} public Builder from(ReidentifyStringResponse other) { - processedText(other.getProcessedText()); + text(other.getText()); return this; } - @JsonSetter(value = "processed_text", nulls = Nulls.SKIP) - public Builder processedText(Optional processedText) { - this.processedText = processedText; + @JsonSetter(value = "text", nulls = Nulls.SKIP) + public Builder text(Optional text) { + this.text = text; return this; } - public Builder processedText(String processedText) { - this.processedText = Optional.ofNullable(processedText); + public Builder text(String text) { + this.text = Optional.ofNullable(text); return this; } public ReidentifyStringResponse build() { - return new ReidentifyStringResponse(processedText, additionalProperties); + return new ReidentifyStringResponse(text, additionalProperties); } } } diff --git a/src/main/java/com/skyflow/logs/ErrorLogs.java b/src/main/java/com/skyflow/logs/ErrorLogs.java index 970f9a17..738c3733 100644 --- a/src/main/java/com/skyflow/logs/ErrorLogs.java +++ b/src/main/java/com/skyflow/logs/ErrorLogs.java @@ -117,7 +117,16 @@ public enum ErrorLogs { INVALID_NULL_TEXT_IN_REIDENTIFY("Invalid %s1 request. The text field is required string and must not be null. Specify a valid text."), INVALID_EMPTY_TEXT_IN_REIDENTIFY("Invalid %s1 request. The text field is required string and must not be empty string. Specify a valid text."), REIDENTIFY_TEXT_REQUEST_REJECTED("ReIdentify text request resulted in failure."), - + DEIDENTIFY_FILE_REQUEST_REJECTED("DeIdentify file request resulted in failure."), + GET_DETECT_RUN_REQUEST_REJECTED("Get detect run request resulted in failure."), + INVALID_NULL_FILE_IN_DEIDENTIFY_FILE("Invalid %s1 request. The file field is required and must not be null. Specify a valid file."), + FILE_NOT_FOUND_TO_DEIDENTIFY("Invalid %s1 request. The file field is required and must not be empty. Specify a valid file."), + FILE_NOT_READABLE_TO_DEIDENTIFY("Invalid %s1 request. The file is not readable. Please check the file permissions or path."), + INVALID_PIXEL_DENSITY_TO_DEIDENTIFY_FILE("Invalid %s1 request. Pixel density must be a positive integer greater than 0. Specify a valid pixel density."), + INVALID_MAX_RESOLUTION("Invalid %s1 request. Max resolution must be a positive integer greater than 0. Specify a valid max resolution."), + INVALID_BLEEP_TO_DEIDENTIFY_AUDIO("Invalid %s1 request. Specify a valid bleep as AudioBleep"), + OUTPUT_DIRECTORY_NOT_FOUND("Invalid %s1 request. The output directory does not exist. Please specify a valid output directory."), + INVALID_PERMISSIONS_FOR_OUTPUT_DIRECTORY("Invalid %s1 request. The output directory is not writable. Please check the permissions or specify a valid output directory."), ; private final String log; diff --git a/src/main/java/com/skyflow/logs/InfoLogs.java b/src/main/java/com/skyflow/logs/InfoLogs.java index 74cd74d7..efd81a49 100644 --- a/src/main/java/com/skyflow/logs/InfoLogs.java +++ b/src/main/java/com/skyflow/logs/InfoLogs.java @@ -83,6 +83,12 @@ public enum InfoLogs { VALIDATE_REIDENTIFY_TEXT_REQUEST("Validating reidentify text request."), REIDENTIFY_TEXT_TRIGGERED("ReIdentify text method triggered."), REIDENTIFY_TEXT_REQUEST_RESOLVED("ReIdentify text request resolved."), + DEIDENTIFY_FILE_TRIGGERED("DeIdentify file method triggered."), + VALIDATE_DEIDENTIFY_FILE_REQUEST("Validating deidentify file request."), + DEIDENTIFY_FILE_REQUEST_RESOLVED("DeIdentify file request resolved."), + DEIDENTIFY_FILE_SUCCESS("File deidentified successfully."), + GET_DETECT_RUN_TRIGGERED("Get detect run method triggered."), + VALIDATE_GET_DETECT_RUN_REQUEST("Validating get detect run request."), REIDENTIFY_TEXT_SUCCESS("Text data re-identified."), ; diff --git a/src/main/java/com/skyflow/utils/validations/Validations.java b/src/main/java/com/skyflow/utils/validations/Validations.java index db73348d..0a71b473 100644 --- a/src/main/java/com/skyflow/utils/validations/Validations.java +++ b/src/main/java/com/skyflow/utils/validations/Validations.java @@ -17,13 +17,13 @@ import com.skyflow.utils.logger.LogUtil; import com.skyflow.vault.connection.InvokeConnectionRequest; import com.skyflow.vault.data.*; -import com.skyflow.vault.detect.DeidentifyTextRequest; -import com.skyflow.vault.detect.ReidentifyTextRequest; +import com.skyflow.vault.detect.*; import com.skyflow.vault.tokens.ColumnValue; import com.skyflow.vault.tokens.DetokenizeData; import com.skyflow.vault.tokens.DetokenizeRequest; import com.skyflow.vault.tokens.TokenizeRequest; +import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; @@ -792,4 +792,103 @@ private static void validateTokensMapWithTokenStrict( } } } + + public static void validateDeidentifyFileRequest(DeidentifyFileRequest request) throws SkyflowException { + if (request == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.EMPTY_REQUEST_BODY.getLog(), InterfaceName.DETECT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRequestBody.getMessage()); + } + + File file = request.getFile(); + if (file == null) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.INVALID_NULL_FILE_IN_DEIDENTIFY_FILE.getLog(), InterfaceName.DETECT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidNullFileInDeIdentifyFile.getMessage()); + } + if (!file.exists() || !file.isFile()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.FILE_NOT_FOUND_TO_DEIDENTIFY.getLog(), InterfaceName.DETECT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.FileNotFoundToDeidentify.getMessage()); + } + if (!file.canRead()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.FILE_NOT_READABLE_TO_DEIDENTIFY.getLog(), InterfaceName.DETECT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.FileNotReadableToDeidentify.getMessage()); + } + + + // Validate pixelDensity and maxResolution + if (request.getPixelDensity() != null && request.getPixelDensity().doubleValue() <= 0) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.INVALID_PIXEL_DENSITY_TO_DEIDENTIFY_FILE.getLog(), InterfaceName.DETECT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidPixelDensityToDeidentifyFile.getMessage()); + } + if (request.getMaxResolution() != null && request.getMaxResolution().doubleValue() <= 0) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.INVALID_MAX_RESOLUTION.getLog(), InterfaceName.DETECT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidMaxResolution.getMessage()); + } + + // Validate AudioBleep + if (request.getBleep() != null) { + if (request.getBleep().getFrequency() == null || request.getBleep().getFrequency() <= 0) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.INVALID_BLEEP_TO_DEIDENTIFY_AUDIO.getLog(), InterfaceName.DETECT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidRequestBody.getMessage()); + } + if (request.getBleep().getGain() == null || request.getBleep().getGain() < 0) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidRequestBody.getMessage()); + } + if (request.getBleep().getStartPadding() == null || request.getBleep().getStartPadding() < 0) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidRequestBody.getMessage()); + } + if (request.getBleep().getStopPadding() == null || request.getBleep().getStopPadding() < 0) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidRequestBody.getMessage()); + } + } + + // Validate outputDirectory if provided + if (request.getOutputDirectory() != null) { + File outDir = new File(request.getOutputDirectory()); + if (!outDir.exists() || !outDir.isDirectory()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.OUTPUT_DIRECTORY_NOT_FOUND.getLog(), InterfaceName.DETECT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.OutputDirectoryNotFound.getMessage()); + } + if (!outDir.canWrite()) { + LogUtil.printErrorLog(Utils.parameterizedString( + ErrorLogs.INVALID_PERMISSIONS_FOR_OUTPUT_DIRECTORY.getLog(), InterfaceName.DETECT.getName() + )); + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidPermission.getMessage()); + } + } + + // Validate waitTime if provided + if (request.getWaitTime() != null && request.getWaitTime() <= 0) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidWaitTime.getMessage()); + } + if(request.getWaitTime() > 64) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.WaitTimeExceedsLimit.getMessage()); + } + } + + public static void validateGetDetectRunRequest(GetDetectRunRequest request) throws SkyflowException { + if (request == null) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.EmptyRequestBody.getMessage()); + } + + String runId = request.getRunId(); + if (runId == null || runId.trim().isEmpty()) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidOrEmptyRunId.getMessage()); + } + } } diff --git a/src/main/java/com/skyflow/vault/controller/DetectController.java b/src/main/java/com/skyflow/vault/controller/DetectController.java index 094b2e76..c7f3cc81 100644 --- a/src/main/java/com/skyflow/vault/controller/DetectController.java +++ b/src/main/java/com/skyflow/vault/controller/DetectController.java @@ -3,21 +3,27 @@ import com.skyflow.VaultClient; import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.ErrorMessage; import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.resources.files.requests.*; import com.skyflow.generated.rest.resources.strings.requests.DeidentifyStringRequest; import com.skyflow.generated.rest.resources.strings.requests.ReidentifyStringRequest; -import com.skyflow.generated.rest.types.DeidentifyStringResponse; -import com.skyflow.generated.rest.types.ReidentifyStringResponse; +import com.skyflow.generated.rest.types.*; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; import com.skyflow.utils.logger.LogUtil; import com.skyflow.utils.validations.Validations; +import com.skyflow.vault.detect.*; +import com.skyflow.vault.detect.DeidentifyFileRequest; +import com.skyflow.vault.detect.DeidentifyFileResponse; import com.skyflow.vault.detect.DeidentifyTextRequest; -import com.skyflow.vault.detect.DeidentifyTextResponse; -import com.skyflow.vault.detect.ReidentifyTextRequest; -import com.skyflow.vault.detect.ReidentifyTextResponse; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.*; public final class DetectController extends VaultClient { @@ -72,7 +78,7 @@ public ReidentifyTextResponse reidentifyText(ReidentifyTextRequest reidentifyTex ReidentifyStringResponse reidentifyStringResponse = super.getDetectTextApi().reidentifyString(request); // Parse the response to ReidentifyTextResponse - reidentifyTextResponse = new ReidentifyTextResponse(reidentifyStringResponse.getAdditionalProperties().get("text").toString()); + reidentifyTextResponse = new ReidentifyTextResponse(reidentifyStringResponse.getText().orElse(null)); LogUtil.printInfoLog(InfoLogs.REIDENTIFY_TEXT_REQUEST_RESOLVED.getLog()); } catch (ApiClientApiException ex) { LogUtil.printErrorLog(ErrorLogs.REIDENTIFY_TEXT_REQUEST_REJECTED.getLog()); @@ -84,4 +90,277 @@ public ReidentifyTextResponse reidentifyText(ReidentifyTextRequest reidentifyTex LogUtil.printInfoLog(InfoLogs.REIDENTIFY_TEXT_SUCCESS.getLog()); return reidentifyTextResponse; } + + public DeidentifyFileResponse deidentifyFile(DeidentifyFileRequest request) throws SkyflowException { + DeidentifyFileResponse response; + LogUtil.printInfoLog(InfoLogs.DEIDENTIFY_FILE_TRIGGERED.getLog()); + try { + LogUtil.printInfoLog(InfoLogs.VALIDATE_DEIDENTIFY_FILE_REQUEST.getLog()); + Validations.validateDeidentifyFileRequest(request); + setBearerToken(); + + String vaultId = super.getVaultConfig().getVaultId(); + + File file = request.getFile(); + String fileName = file.getName(); + String fileExtension = getFileExtension(fileName); + String base64Content; + + try { + base64Content = encodeFileToBase64(file); + } catch (IOException ioe) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.FailedToEncodeFile.getMessage()); + } + + + com.skyflow.generated.rest.types.DeidentifyFileResponse apiResponse = processFileByType(fileExtension, base64Content, request, vaultId); + try { + response = pollForResults(apiResponse.getRunId(), request.getWaitTime()); + } catch (Exception ex) { + throw new SkyflowException(ErrorCode.SERVER_ERROR.getCode(), ErrorMessage.PollingForResultsFailed.getMessage()); +} + + if ("SUCCESS".equalsIgnoreCase(response.getStatus())) { + String base64File = response.getFile(); + if (base64File != null) { + byte[] decodedBytes = Base64.getDecoder().decode(base64File); + String outputDir = request.getOutputDirectory(); + String outputFileName = "processed-" + fileName; + File outputFile; + if (outputDir != null && !outputDir.isEmpty()) { + outputFile = new File(outputDir, outputFileName); + } else { + outputFile = new File(outputFileName); + } + try { + java.nio.file.Files.write(outputFile.toPath(), decodedBytes); + } catch (IOException ioe) { + throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.FailedtoSaveProcessedFile.getMessage()); + } + + } + } + } catch (ApiClientApiException e) { + LogUtil.printErrorLog(ErrorLogs.DEIDENTIFY_FILE_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), e.body().toString()); + } + return response; + } + + private String getFileExtension(String fileName) { + return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); + } + + private String encodeFileToBase64(File file) throws IOException { + byte[] fileContent = Files.readAllBytes(file.toPath()); + return Base64.getEncoder().encodeToString(fileContent); + } + + private DeidentifyFileResponse pollForResults(String runId, Integer maxWaitTime) throws Exception { + int currentWaitTime = 1; + maxWaitTime = maxWaitTime == null ? 64 : maxWaitTime; + + DeidentifyStatusResponse response = null; + + while (true) { + try { + GetRunRequest getRunRequest = GetRunRequest.builder() + .vaultId(super.getVaultConfig().getVaultId()) + .build(); + response = super.getDetectFileAPi() + .getRun(runId, getRunRequest); + + DeidentifyStatusResponseStatus status = response.getStatus(); + + if (Objects.equals(status.toString(), "IN_PROGRESS")) { + if (currentWaitTime >= maxWaitTime) { + return new DeidentifyFileResponse( + null, // file + null, // type + null, // extension + null, // wordCount + null, // charCount + null, // sizeInKb + null, // durationInSeconds + null, // pageCount + null, // slideCount + null, // entities + runId, // runId + "IN_PROGRESS", // status + null // errors + ); + } + + int nextWaitTime = currentWaitTime * 2; + int waitTime; + + if (nextWaitTime >= maxWaitTime) { + waitTime = maxWaitTime - currentWaitTime; + currentWaitTime = maxWaitTime; + } else { + waitTime = nextWaitTime; + currentWaitTime = nextWaitTime; + } + + Thread.sleep(waitTime * 1000); + + } else if (status == DeidentifyStatusResponseStatus.SUCCESS || + status == DeidentifyStatusResponseStatus.FAILED) { + return parseDeidentifyFileResponse(response, runId, status.toString().toLowerCase()); + } + } catch (ApiClientApiException e) { + LogUtil.printErrorLog(ErrorLogs.GET_DETECT_RUN_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), e.body().toString()); + } + } + + } + + + private static synchronized DeidentifyFileResponse parseDeidentifyFileResponse(DeidentifyStatusResponse response, + String runId, String status) { + DeidentifyFileOutput firstOutput = getFirstOutput(response); + + Object wordCharObj = response.getAdditionalProperties().get("word_character_count"); + Integer wordCount = null; + Integer charCount = null; + + if (wordCharObj instanceof Map) { + Map wordCharMap = (Map) wordCharObj; + Object wc = wordCharMap.get("word_count"); + Object cc = wordCharMap.get("character_count"); + if (wc instanceof Number) { + wordCount = ((Number) wc).intValue(); + } + if (cc instanceof Number) { + charCount = ((Number) cc).intValue(); + } + } + + + return new DeidentifyFileResponse( + firstOutput.getProcessedFile().orElse(null), + firstOutput.getProcessedFileType().get().toString(), + firstOutput.getProcessedFileExtension().get(), + wordCount, + charCount, + response.getSize().map(Double::valueOf).orElse(null), + response.getDuration().map(Double::valueOf).orElse(null), + response.getPages().orElse(null), + response.getSlides().orElse(null), + getEntities(response), + runId, + status, + null + ); + } + + private static synchronized DeidentifyFileOutput getFirstOutput(DeidentifyStatusResponse response) { + List outputs = response.getOutput(); + return outputs != null && !outputs.isEmpty() ? outputs.get(0) : null; + } + + private static synchronized List getEntities(DeidentifyStatusResponse response) { + List entities = new ArrayList<>(); + + List outputs = response.getOutput(); + DeidentifyFileOutput deidentifyFileOutput = outputs != null && !outputs.isEmpty() ? outputs.get(1) : null; + + if (deidentifyFileOutput != null) { + entities.add(new FileEntityInfo( + deidentifyFileOutput.getProcessedFile().orElse(null), + deidentifyFileOutput.getProcessedFileType().orElse(null), + deidentifyFileOutput.getProcessedFileExtension().orElse(null) + )); + } + + return entities; + } + + + private com.skyflow.generated.rest.types.DeidentifyFileResponse processFileByType(String fileExtension, String base64Content, + DeidentifyFileRequest request, String vaultId) { + switch(fileExtension.toLowerCase()) { + case "txt": + com.skyflow.generated.rest.resources.files.requests.DeidentifyTextRequest textFileRequest = + super.getDeidentifyTextFileRequest(request, vaultId, base64Content); + return super.getDetectFileAPi().deidentifyText(textFileRequest); + + case "mp3": + case "wav": + DeidentifyAudioRequest audioRequest = + super.getDeidentifyAudioRequest(request, vaultId, base64Content, fileExtension); + return super.getDetectFileAPi().deidentifyAudio(audioRequest); + + case "pdf": + DeidentifyPdfRequest pdfRequest = + super.getDeidentifyPdfRequest(request, vaultId, base64Content); + + return super.getDetectFileAPi().deidentifyPdf(pdfRequest); + + case "jpg": + case "jpeg": + case "png": + case "bmp": + case "tif": + case "tiff": + DeidentifyImageRequest imageRequest = + super.getDeidentifyImageRequest(request, vaultId, base64Content, fileExtension); + return super.getDetectFileAPi().deidentifyImage(imageRequest); + + case "ppt": + case "pptx": + DeidentifyPresentationRequest presentationRequest = + super.getDeidentifyPresentationRequest(request, vaultId, base64Content, fileExtension); + return super.getDetectFileAPi().deidentifyPresentation(presentationRequest); + + case "csv": + case "xls": + case "xlsx": + DeidentifySpreadsheetRequest spreadsheetRequest = + super.getDeidentifySpreadsheetRequest(request, vaultId, base64Content, fileExtension); + return super.getDetectFileAPi().deidentifySpreadsheet(spreadsheetRequest); + + case "doc": + case "docx": + DeidentifyDocumentRequest documentRequest = + super.getDeidentifyDocumentRequest(request, vaultId, base64Content, fileExtension); + return super.getDetectFileAPi().deidentifyDocument(documentRequest); + + case "json": + case "xml": + DeidentifyStructuredTextRequest structuredTextRequest = + super.getDeidentifyStructuredTextRequest(request, vaultId, base64Content, fileExtension); + return super.getDetectFileAPi().deidentifyStructuredText(structuredTextRequest); + + default: + com.skyflow.generated.rest.resources.files.requests.DeidentifyFileRequest genericFileRequest = + super.getDeidentifyGenericFileRequest(request, vaultId, base64Content, fileExtension); + return super.getDetectFileAPi().deidentifyFile(genericFileRequest); + } + } + + public DeidentifyFileResponse getDetectRun(GetDetectRunRequest request) throws SkyflowException { + LogUtil.printInfoLog(InfoLogs.GET_DETECT_RUN_TRIGGERED.getLog()); + try { + LogUtil.printInfoLog(InfoLogs.VALIDATE_GET_DETECT_RUN_REQUEST.getLog()); + Validations.validateGetDetectRunRequest(request); + setBearerToken(); + String runId = request.getRunId(); + String vaultId = super.getVaultConfig().getVaultId(); + + GetRunRequest getRunRequest = + GetRunRequest.builder() + .vaultId(vaultId) + .build(); + + com.skyflow.generated.rest.types.DeidentifyStatusResponse apiResponse = + super.getDetectFileAPi().getRun(runId, getRunRequest); + + return parseDeidentifyFileResponse(apiResponse, runId, apiResponse.getStatus().toString().toLowerCase()); + } catch (ApiClientApiException e) { + LogUtil.printErrorLog(ErrorLogs.GET_DETECT_RUN_REQUEST_REJECTED.getLog()); + throw new SkyflowException(e.statusCode(), e, e.headers(), e.body().toString()); + } + } } \ No newline at end of file diff --git a/src/main/java/com/skyflow/vault/controller/VaultController.java b/src/main/java/com/skyflow/vault/controller/VaultController.java index b32b80a6..104fdaab 100644 --- a/src/main/java/com/skyflow/vault/controller/VaultController.java +++ b/src/main/java/com/skyflow/vault/controller/VaultController.java @@ -6,6 +6,7 @@ import com.skyflow.config.VaultConfig; import com.skyflow.errors.SkyflowException; import com.skyflow.generated.rest.core.ApiClientApiException; +import com.skyflow.generated.rest.core.ApiClientHttpResponse; import com.skyflow.generated.rest.resources.query.requests.QueryServiceExecuteQueryBody; import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; import com.skyflow.generated.rest.resources.records.requests.RecordServiceBulkDeleteRecordBody; @@ -16,6 +17,7 @@ import com.skyflow.generated.rest.types.*; import com.skyflow.logs.ErrorLogs; import com.skyflow.logs.InfoLogs; +import com.skyflow.utils.Constants; import com.skyflow.utils.logger.LogUtil; import com.skyflow.utils.validations.Validations; import com.skyflow.vault.data.*; @@ -109,7 +111,7 @@ private static synchronized HashMap getFormattedQueryRecord(V1Fi public InsertResponse insert(InsertRequest insertRequest) throws SkyflowException { LogUtil.printInfoLog(InfoLogs.INSERT_TRIGGERED.getLog()); V1InsertRecordResponse bulkInsertResult = null; - V1BatchOperationResponse batchInsertResult = null; + ApiClientHttpResponse batchInsertResult = null; ArrayList> insertedFields = new ArrayList<>(); ArrayList> errorFields = new ArrayList<>(); Boolean continueOnError = insertRequest.getContinueOnError(); @@ -119,9 +121,9 @@ public InsertResponse insert(InsertRequest insertRequest) throws SkyflowExceptio setBearerToken(); if (continueOnError) { RecordServiceBatchOperationBody insertBody = super.getBatchInsertRequestBody(insertRequest); - batchInsertResult = super.getRecordsApi().recordServiceBatchOperation(super.getVaultConfig().getVaultId(), insertBody); + batchInsertResult = super.getRecordsApi().withRawResponse().recordServiceBatchOperation(super.getVaultConfig().getVaultId(), insertBody); LogUtil.printInfoLog(InfoLogs.INSERT_REQUEST_RESOLVED.getLog()); - Optional>> records = batchInsertResult.getResponses(); + Optional>> records = batchInsertResult.body().getResponses(); if (records.isPresent()) { List> recordList = records.get(); @@ -133,6 +135,7 @@ public InsertResponse insert(InsertRequest insertRequest) throws SkyflowExceptio if (insertRecord.containsKey("skyflowId")) { insertedFields.add(insertRecord); } else { + insertRecord.put("requestId", batchInsertResult.headers().get("x-request-id").get(0)); errorFields.add(insertRecord); } } @@ -152,7 +155,7 @@ public InsertResponse insert(InsertRequest insertRequest) throws SkyflowExceptio } } catch (ApiClientApiException e) { LogUtil.printErrorLog(ErrorLogs.INSERT_RECORDS_REJECTED.getLog()); - throw e; + throw new SkyflowException(e.statusCode(), e, e.headers(), e.body().toString()); } LogUtil.printInfoLog(InfoLogs.INSERT_SUCCESS.getLog()); return new InsertResponse(insertedFields, errorFields); @@ -160,7 +163,7 @@ public InsertResponse insert(InsertRequest insertRequest) throws SkyflowExceptio public DetokenizeResponse detokenize(DetokenizeRequest detokenizeRequest) throws SkyflowException { LogUtil.printInfoLog(InfoLogs.DETOKENIZE_TRIGGERED.getLog()); - V1DetokenizeResponse result = null; + ApiClientHttpResponse result = null; ArrayList detokenizedFields = new ArrayList<>(); ArrayList errorRecords = new ArrayList<>(); try { @@ -168,18 +171,18 @@ public DetokenizeResponse detokenize(DetokenizeRequest detokenizeRequest) throws Validations.validateDetokenizeRequest(detokenizeRequest); setBearerToken(); V1DetokenizePayload payload = super.getDetokenizePayload(detokenizeRequest); - result = super.getTokensApi().recordServiceDetokenize(super.getVaultConfig().getVaultId(), payload); + result = super.getTokensApi().withRawResponse().recordServiceDetokenize(super.getVaultConfig().getVaultId(), payload); LogUtil.printInfoLog(InfoLogs.DETOKENIZE_REQUEST_RESOLVED.getLog()); -// Map> responseHeaders = result.getHeaders(); -// String requestId = responseHeaders.get(Constants.REQUEST_ID_HEADER_KEY).get(0); - Optional> records = result.getRecords(); + Map> responseHeaders = result.headers(); + String requestId = responseHeaders.get(Constants.REQUEST_ID_HEADER_KEY).get(0); + Optional> records = result.body().getRecords(); if (records.isPresent()) { List recordList = records.get(); for (V1DetokenizeRecordResponse record : recordList) { if (record.getError().isPresent()) { - DetokenizeRecordResponse recordResponse = new DetokenizeRecordResponse(record, "requestId"); + DetokenizeRecordResponse recordResponse = new DetokenizeRecordResponse(record, requestId); errorRecords.add(recordResponse); } else { DetokenizeRecordResponse recordResponse = new DetokenizeRecordResponse(record); @@ -189,8 +192,7 @@ public DetokenizeResponse detokenize(DetokenizeRequest detokenizeRequest) throws } } catch (ApiClientApiException e) { LogUtil.printErrorLog(ErrorLogs.DETOKENIZE_REQUEST_REJECTED.getLog()); -// throw new SkyflowException(e.getCode(), e, e.getResponseHeaders(), e.getResponseBody()); - throw e; + throw new SkyflowException(e.statusCode(), e, e.headers(), e.body().toString()); } if (!errorRecords.isEmpty()) { @@ -261,8 +263,7 @@ public UpdateResponse update(UpdateRequest updateRequest) throws SkyflowExceptio tokensMap = getFormattedUpdateRecord(result); } catch (ApiClientApiException e) { LogUtil.printErrorLog(ErrorLogs.UPDATE_REQUEST_REJECTED.getLog()); -// throw new SkyflowException(e.getCode(), e, e.getResponseHeaders(), e.getResponseBody()); - throw e; + throw new SkyflowException(e.statusCode(), e, e.headers(), e.body().toString()); } LogUtil.printInfoLog(InfoLogs.UPDATE_SUCCESS.getLog()); return new UpdateResponse(skyflowId, tokensMap); @@ -283,8 +284,7 @@ public DeleteResponse delete(DeleteRequest deleteRequest) throws SkyflowExceptio LogUtil.printInfoLog(InfoLogs.DELETE_REQUEST_RESOLVED.getLog()); } catch (ApiClientApiException e) { LogUtil.printErrorLog(ErrorLogs.DELETE_REQUEST_REJECTED.getLog()); -// throw new SkyflowException(e.getCode(), e, e.getResponseHeaders(), e.getResponseBody()); - throw e; + throw new SkyflowException(e.statusCode(), e, e.headers(), e.body().toString()); } LogUtil.printInfoLog(InfoLogs.DELETE_SUCCESS.getLog()); return new DeleteResponse(result.getRecordIdResponse()); @@ -313,8 +313,7 @@ public QueryResponse query(QueryRequest queryRequest) throws SkyflowException { } } catch (ApiClientApiException e) { LogUtil.printErrorLog(ErrorLogs.QUERY_REQUEST_REJECTED.getLog()); -// throw new SkyflowException(e.getCode(), e, e.getResponseHeaders(), e.getResponseBody()); - throw e; + throw new SkyflowException(e.statusCode(), e, e.headers(), e.body().toString()); } LogUtil.printInfoLog(InfoLogs.QUERY_SUCCESS.getLog()); return new QueryResponse(fields); @@ -340,9 +339,7 @@ public TokenizeResponse tokenize(TokenizeRequest tokenizeRequest) throws Skyflow } } catch (ApiClientApiException e) { LogUtil.printErrorLog(ErrorLogs.TOKENIZE_REQUEST_REJECTED.getLog()); -// throw new SkyflowException(e.getCode(), e, e.getResponseHeaders(), e.getResponseBody()); - throw e; - } + throw new SkyflowException(e.statusCode(), e, e.headers(), e.body().toString()); } LogUtil.printInfoLog(InfoLogs.TOKENIZE_SUCCESS.getLog()); return new TokenizeResponse(list); } diff --git a/src/main/java/com/skyflow/vault/detect/AudioBleep.java b/src/main/java/com/skyflow/vault/detect/AudioBleep.java new file mode 100644 index 00000000..1a75f93b --- /dev/null +++ b/src/main/java/com/skyflow/vault/detect/AudioBleep.java @@ -0,0 +1,64 @@ +package com.skyflow.vault.detect; + +public class AudioBleep { + private final AudioBleepBuilder builder; + + private AudioBleep(AudioBleepBuilder builder) { + this.builder = builder; + } + + public static AudioBleepBuilder builder() { + return new AudioBleepBuilder(); + } + + public Double getGain() { + return this.builder.gain; + } + + public Double getFrequency() { + return this.builder.frequency; + } + + public Double getStartPadding() { + return this.builder.startPadding; + } + + public Double getStopPadding() { + return this.builder.stopPadding; + } + + public static final class AudioBleepBuilder { + private Double gain; + private Double frequency; + private Double startPadding; + private Double stopPadding; + + private AudioBleepBuilder() { + // Default constructor + } + + public AudioBleepBuilder gain(Double gain) { + this.gain = gain; + return this; + } + + public AudioBleepBuilder frequency(Double frequency) { + this.frequency = frequency; + return this; + } + + public AudioBleepBuilder startPadding(Double startPadding) { + this.startPadding = startPadding; + return this; + } + + public AudioBleepBuilder stopPadding(Double stopPadding) { + this.stopPadding = stopPadding; + return this; + } + + public AudioBleep build() { + return new AudioBleep(this); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/skyflow/vault/detect/DeidentifyFileRequest.java b/src/main/java/com/skyflow/vault/detect/DeidentifyFileRequest.java new file mode 100644 index 00000000..0024891e --- /dev/null +++ b/src/main/java/com/skyflow/vault/detect/DeidentifyFileRequest.java @@ -0,0 +1,193 @@ +package com.skyflow.vault.detect; + +import com.skyflow.enums.DetectEntities; +import com.skyflow.enums.DetectOutputTranscriptions; +import com.skyflow.enums.MaskingMethod; +import java.io.File; +import java.util.List; + +public class DeidentifyFileRequest { + private final DeidentifyFileRequestBuilder builder; + + private DeidentifyFileRequest(DeidentifyFileRequestBuilder builder) { + this.builder = builder; + } + + public static DeidentifyFileRequestBuilder builder() { + return new DeidentifyFileRequestBuilder(); + } + + public File getFile() { + return this.builder.file; + } + + public List getEntities() { + return this.builder.entities; + } + + public List getAllowRegexList() { + return this.builder.allowRegexList; + } + + public List getRestrictRegexList() { + return this.builder.restrictRegexList; + } + + public TokenFormat getTokenFormat() { + return this.builder.tokenFormat; + } + + public Transformations getTransformations() { + return this.builder.transformations; + } + + public Boolean getOutputProcessedImage() { + return this.builder.outputProcessedImage; + } + + public Boolean getOutputOcrText() { + return this.builder.outputOcrText; + } + + public MaskingMethod getMaskingMethod() { + return this.builder.maskingMethod; + } + + public Number getPixelDensity() { + return this.builder.pixelDensity; + } + + public Number getMaxResolution() { + return this.builder.maxResolution; + } + + public Boolean getOutputProcessedAudio() { + return this.builder.outputProcessedAudio; + } + + public DetectOutputTranscriptions getOutputTranscription() { + return this.builder.outputTranscription; + } + + public AudioBleep getBleep() { + return this.builder.bleep; + } + + public String getOutputDirectory() { + return this.builder.outputDirectory; + } + + public Integer getWaitTime() { + return this.builder.waitTime; + } + + public static final class DeidentifyFileRequestBuilder { + private File file; + private List entities; + private List allowRegexList; + private List restrictRegexList; + private TokenFormat tokenFormat; + private Transformations transformations; + private Boolean outputProcessedImage; + private Boolean outputOcrText; + private MaskingMethod maskingMethod; + private Number pixelDensity; + private Number maxResolution; + private Boolean outputProcessedAudio; + private DetectOutputTranscriptions outputTranscription; + private AudioBleep bleep; + private String outputDirectory; + private Integer waitTime; + + private DeidentifyFileRequestBuilder() { + // Set default values + this.outputProcessedImage = false; + this.outputOcrText = false; + this.outputProcessedAudio = false; + } + + public DeidentifyFileRequestBuilder file(File file) { + this.file = file; + return this; + } + + public DeidentifyFileRequestBuilder entities(List entities) { + this.entities = entities; + return this; + } + + public DeidentifyFileRequestBuilder allowRegexList(List allowRegexList) { + this.allowRegexList = allowRegexList; + return this; + } + + public DeidentifyFileRequestBuilder restrictRegexList(List restrictRegexList) { + this.restrictRegexList = restrictRegexList; + return this; + } + + public DeidentifyFileRequestBuilder tokenFormat(TokenFormat tokenFormat) { + this.tokenFormat = tokenFormat; + return this; + } + + public DeidentifyFileRequestBuilder transformations(Transformations transformations) { + this.transformations = transformations; + return this; + } + + public DeidentifyFileRequestBuilder outputProcessedImage(Boolean outputProcessedImage) { + this.outputProcessedImage = outputProcessedImage != null ? outputProcessedImage : false; + return this; + } + + public DeidentifyFileRequestBuilder outputOcrText(Boolean outputOcrText) { + this.outputOcrText = outputOcrText != null ? outputOcrText : false; + return this; + } + + public DeidentifyFileRequestBuilder maskingMethod(MaskingMethod maskingMethod) { + this.maskingMethod = maskingMethod; + return this; + } + + public DeidentifyFileRequestBuilder pixelDensity(Number pixelDensity) { + this.pixelDensity = pixelDensity; + return this; + } + + public DeidentifyFileRequestBuilder maxResolution(Number maxResolution) { + this.maxResolution = maxResolution; + return this; + } + + public DeidentifyFileRequestBuilder outputProcessedAudio(Boolean outputProcessedAudio) { + this.outputProcessedAudio = outputProcessedAudio != null ? outputProcessedAudio : false; + return this; + } + + public DeidentifyFileRequestBuilder outputTranscription(DetectOutputTranscriptions outputTranscription) { + this.outputTranscription = outputTranscription; + return this; + } + + public DeidentifyFileRequestBuilder bleep(AudioBleep bleep) { + this.bleep = bleep; + return this; + } + + public DeidentifyFileRequestBuilder outputDirectory(String outputDirectory) { + this.outputDirectory = outputDirectory; + return this; + } + + public DeidentifyFileRequestBuilder waitTime(Integer waitTime) { + this.waitTime = waitTime; + return this; + } + + public DeidentifyFileRequest build() { + return new DeidentifyFileRequest(this); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/skyflow/vault/detect/DeidentifyFileResponse.java b/src/main/java/com/skyflow/vault/detect/DeidentifyFileResponse.java new file mode 100644 index 00000000..12a71dc9 --- /dev/null +++ b/src/main/java/com/skyflow/vault/detect/DeidentifyFileResponse.java @@ -0,0 +1,99 @@ +package com.skyflow.vault.detect; + +import com.google.gson.Gson; +import java.util.List; + +public class DeidentifyFileResponse { + private final String file; + private final String type; + private final String extension; + private final Integer wordCount; + private final Integer charCount; + private final Double sizeInKb; + private final Double durationInSeconds; + private final Integer pageCount; + private final Integer slideCount; + private final List entities; + private final String runId; + private final String status; + private final List errors; + + + public DeidentifyFileResponse(String file, String type, String extension, + Integer wordCount, Integer charCount, Double sizeInKb, + Double durationInSeconds, Integer pageCount, Integer slideCount, + List entities, String runId, String status, List errors) { + this.file = file; + this.type = type; + this.extension = extension; + this.wordCount = wordCount; + this.charCount = charCount; + this.sizeInKb = sizeInKb; + this.durationInSeconds = durationInSeconds; + this.pageCount = pageCount; + this.slideCount = slideCount; + this.entities = entities; + this.runId = runId; + this.status = status; + this.errors = errors; + } + + + public String getFile() { + return file; + } + + public String getType() { + return type; + } + + public String getExtension() { + return extension; + } + + public Integer getWordCount() { + return wordCount; + } + + public Integer getCharCount() { + return charCount; + } + + public Double getSizeInKb() { + return sizeInKb; + } + + public Double getDurationInSeconds() { + return durationInSeconds; + } + + public Integer getPageCount() { + return pageCount; + } + + public Integer getSlideCount() { + return slideCount; + } + + public List getEntities() { + return entities; + } + + public String getRunId() { + return runId; + } + + public String getStatus() { + return status; + } + + public List getErrors() { + return errors; + } + + @Override + public String toString() { + Gson gson = new Gson(); + return gson.toJson(this); + } +} \ No newline at end of file diff --git a/src/main/java/com/skyflow/vault/detect/FileEntityInfo.java b/src/main/java/com/skyflow/vault/detect/FileEntityInfo.java new file mode 100644 index 00000000..e177a99a --- /dev/null +++ b/src/main/java/com/skyflow/vault/detect/FileEntityInfo.java @@ -0,0 +1,19 @@ +package com.skyflow.vault.detect; + +import com.skyflow.generated.rest.types.DeidentifyFileOutputProcessedFileType; + +public class FileEntityInfo { + private final String file; + private final String type; + private final String extension; + + public FileEntityInfo(String file, DeidentifyFileOutputProcessedFileType type, String extension) { + this.file = file; + this.type = String.valueOf(type); + this.extension = extension; + } + + public String getFile() { return file; } + public String getType() { return type; } + public String getExtension() { return extension; } +} \ No newline at end of file diff --git a/src/main/java/com/skyflow/vault/detect/GetDetectRunRequest.java b/src/main/java/com/skyflow/vault/detect/GetDetectRunRequest.java new file mode 100644 index 00000000..6ef2ceaf --- /dev/null +++ b/src/main/java/com/skyflow/vault/detect/GetDetectRunRequest.java @@ -0,0 +1,30 @@ +package com.skyflow.vault.detect; + +public class GetDetectRunRequest { + private final String runId; + + private GetDetectRunRequest(GetDetectRunRequestBuilder builder) { + this.runId = builder.runId; + } + + public static GetDetectRunRequestBuilder builder() { + return new GetDetectRunRequestBuilder(); + } + + public String getRunId() { + return this.runId; + } + + public static final class GetDetectRunRequestBuilder { + private String runId; + + public GetDetectRunRequestBuilder runId(String runId) { + this.runId = runId; + return this; + } + + public GetDetectRunRequest build() { + return new GetDetectRunRequest(this); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/skyflow/VaultClientTests.java b/src/test/java/com/skyflow/VaultClientTests.java index 4c177ab4..343c56ad 100644 --- a/src/test/java/com/skyflow/VaultClientTests.java +++ b/src/test/java/com/skyflow/VaultClientTests.java @@ -2,13 +2,15 @@ import com.skyflow.config.Credentials; import com.skyflow.config.VaultConfig; -import com.skyflow.enums.DetectEntities; -import com.skyflow.enums.Env; -import com.skyflow.enums.TokenMode; +import com.skyflow.enums.*; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.SkyflowException; +import com.skyflow.generated.rest.resources.files.requests.*; import com.skyflow.generated.rest.resources.records.RecordsClient; import com.skyflow.generated.rest.resources.records.requests.RecordServiceBatchOperationBody; import com.skyflow.generated.rest.resources.records.requests.RecordServiceInsertRecordBody; import com.skyflow.generated.rest.resources.records.requests.RecordServiceUpdateRecordBody; +import com.skyflow.generated.rest.resources.tokens.TokensClient; import com.skyflow.generated.rest.resources.tokens.requests.V1DetokenizePayload; import com.skyflow.generated.rest.resources.tokens.requests.V1TokenizePayload; import com.skyflow.generated.rest.types.DeidentifyStringResponse; @@ -18,6 +20,8 @@ import com.skyflow.vault.data.InsertRequest; import com.skyflow.vault.data.UpdateRequest; import com.skyflow.vault.detect.*; +import com.skyflow.vault.detect.DeidentifyFileRequest; +import com.skyflow.vault.detect.DeidentifyTextRequest; import com.skyflow.vault.tokens.ColumnValue; import com.skyflow.vault.tokens.DetokenizeData; import com.skyflow.vault.tokens.DetokenizeRequest; @@ -27,9 +31,8 @@ import org.junit.BeforeClass; import org.junit.Test; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; +import java.io.File; +import java.util.*; public class VaultClientTests { private static final String INVALID_EXCEPTION_THROWN = "Should not have thrown any exception"; @@ -58,7 +61,7 @@ public static void setup() { table = "test_table"; value = "test_value"; columnGroup = "test_column_group"; - apiKey = "sky-ab123-abcd1234cdef1234abcd4321cdef4321"; + apiKey = null; insertValues = new ArrayList<>(); insertTokens = new ArrayList<>(); valueMap = new HashMap<>(); @@ -77,20 +80,12 @@ public static void setup() { @Test public void testVaultClientGetRecordsAPI() { try { - Dotenv dotenv = Dotenv.load(); - String bearerToken = dotenv.get("TEST_REUSABLE_TOKEN"); - if (bearerToken == null) { - Assert.fail("TEST_REUSABLE_TOKEN not set in environment variables"); - } - Credentials credentials = new Credentials(); - credentials.setCredentialsString("{\"bearer_token\": \"" + bearerToken + "\"}"); + credentials.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); vaultConfig.setCredentials(credentials); - vaultClient.updateVaultConfig(); + vaultClient = new VaultClient(vaultConfig, credentials); vaultClient.setBearerToken(); - Assert.assertNotNull("ApiClient should not be null after setting the bearer token", vaultClient.getRecordsApi()); - RecordsClient recordsClient = vaultClient.getRecordsApi(); Assert.assertNotNull("RecordsClient should not be null", recordsClient); } catch (Exception e) { @@ -103,16 +98,28 @@ public void testVaultClientGetRecordsAPI() { @Test public void testVaultClientGetTokensAPI() { try { - Assert.assertNotNull(vaultClient.getTokensApi()); + Credentials credentials = new Credentials(); + credentials.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); + vaultConfig.setCredentials(credentials); + vaultClient = new VaultClient(vaultConfig, credentials); + vaultClient.setBearerToken(); + TokensClient tokensClient = vaultClient.getTokensApi(); + Assert.assertNotNull("TokensClient should not be null", tokensClient); } catch (Exception e) { Assert.fail(INVALID_EXCEPTION_THROWN); } } + @Test public void testVaultClientGetQueryAPI() { try { - Assert.assertNotNull(vaultClient.getQueryApi()); + Credentials credentials = new Credentials(); + credentials.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); + vaultConfig.setCredentials(credentials); + + vaultClient = new VaultClient(vaultConfig, credentials); + vaultClient.setBearerToken(); } catch (Exception e) { Assert.fail(INVALID_EXCEPTION_THROWN); } @@ -278,17 +285,10 @@ public void testGetTokenizePayload() { @Test public void testSetBearerToken() { try { - Dotenv dotenv = Dotenv.load(); - String bearerToken = dotenv.get("TEST_REUSABLE_TOKEN"); - if (bearerToken == null) { - Assert.fail("TEST_REUSABLE_TOKEN not set in environment variables"); - } - Credentials credentials = new Credentials(); - credentials.setCredentialsString("{\"bearer_token\": \"" + bearerToken + "\"}"); + credentials.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); vaultConfig.setCredentials(credentials); - vaultClient.updateVaultConfig(); - + vaultClient = new VaultClient(vaultConfig, credentials); vaultClient.setBearerToken(); Assert.assertNotNull(vaultClient.getTokensApi()); @@ -304,8 +304,8 @@ public void testSetBearerToken() { public void testSetBearerTokenWithApiKey() { try { Credentials credentials = new Credentials(); - credentials.setApiKey(apiKey); - vaultConfig.setCredentials(null); + credentials.setApiKey("sky-ab123-abcd1234cdef1234abcd4321cdef4321"); // Use a non-null dummy API key + vaultConfig.setCredentials(credentials); vaultClient.updateVaultConfig(); vaultClient.setCommonCredentials(credentials); @@ -314,19 +314,24 @@ public void testSetBearerTokenWithApiKey() { // re-use scenario vaultClient.setBearerToken(); - // Note: We can't directly access the token from apiClient anymore; this test assumes the token is set correctly - Assert.assertNotNull(vaultClient.getTokensApi()); // Indirectly verifies client is built + + // If no exception is thrown, the test passes + Assert.assertTrue(true); } catch (Exception e) { - Assert.fail(INVALID_EXCEPTION_THROWN); + Assert.fail(INVALID_EXCEPTION_THROWN + ": " + e.getMessage()); } } @Test public void testSetBearerTokenWithEnvCredentials() { try { + Dotenv dotenv = Dotenv.load(); vaultConfig.setCredentials(null); vaultClient.updateVaultConfig(); vaultClient.setCommonCredentials(null); + vaultClient.setBearerToken(); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); Assert.assertNull(vaultClient.getVaultConfig().getCredentials()); } catch (Exception e) { Assert.fail(INVALID_EXCEPTION_THROWN); @@ -418,4 +423,267 @@ public void testGetDeidentifyStringRequest() { .build(); } + + @Test + public void testDeidentifyFileRequestBuilderAndGetters() { + File file = new File("testfile.txt"); + DetectEntities entity = DetectEntities.NAME; + String allowRegex = "^[A-Za-z]+$"; + String restrictRegex = "\\d+"; + TokenFormat tokenFormat = TokenFormat.builder().vaultToken(Collections.singletonList(entity)).build(); + Boolean outputProcessedImage = true; + Boolean outputOcrText = true; + MaskingMethod maskingMethod = MaskingMethod.BLACKBOX; + Double pixelDensity = 300.0; + Double maxResolution = 1024.0; + Boolean outputProcessedAudio = false; + DetectOutputTranscriptions outputTranscription = DetectOutputTranscriptions.TRANSCRIPTION; + AudioBleep bleep = AudioBleep.builder().gain(20.0).build(); + String outputDirectory = "/tmp"; + Integer waitTime = 10; + + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .entities(Arrays.asList(entity)) + .allowRegexList(Collections.singletonList(allowRegex)) + .restrictRegexList(Collections.singletonList(restrictRegex)) + .tokenFormat(tokenFormat) + .outputProcessedImage(outputProcessedImage) + .outputOcrText(outputOcrText) + .maskingMethod(maskingMethod) + .pixelDensity(pixelDensity) + .maxResolution(maxResolution) + .outputProcessedAudio(outputProcessedAudio) + .outputTranscription(outputTranscription) + .bleep(bleep) + .outputDirectory(outputDirectory) + .waitTime(waitTime) + .build(); + + Assert.assertEquals(file, request.getFile()); + Assert.assertEquals(1, request.getEntities().size()); + Assert.assertEquals(allowRegex, request.getAllowRegexList().get(0)); + Assert.assertEquals(restrictRegex, request.getRestrictRegexList().get(0)); + Assert.assertEquals(tokenFormat, request.getTokenFormat()); + Assert.assertEquals(outputProcessedImage, request.getOutputProcessedImage()); + Assert.assertEquals(outputOcrText, request.getOutputOcrText()); + Assert.assertEquals(maskingMethod, request.getMaskingMethod()); + Assert.assertEquals(pixelDensity, request.getPixelDensity()); + Assert.assertEquals(maxResolution, request.getMaxResolution()); + Assert.assertEquals(outputProcessedAudio, request.getOutputProcessedAudio()); + Assert.assertEquals(outputTranscription, request.getOutputTranscription()); + Assert.assertEquals(bleep, request.getBleep()); + Assert.assertEquals(outputDirectory, request.getOutputDirectory()); + Assert.assertEquals(waitTime, request.getWaitTime()); + } + + @Test + public void testDeidentifyFileRequestBuilderDefaults() { + DeidentifyFileRequest request = DeidentifyFileRequest.builder().build(); + Assert.assertNull(request.getFile()); + Assert.assertNull(request.getEntities()); + Assert.assertNull(request.getAllowRegexList()); + Assert.assertNull(request.getRestrictRegexList()); + Assert.assertNull(request.getTokenFormat()); + Assert.assertNull(request.getTransformations()); + Assert.assertEquals(false, request.getOutputProcessedImage()); + Assert.assertEquals(false, request.getOutputOcrText()); + Assert.assertNull(request.getMaskingMethod()); + Assert.assertNull(request.getPixelDensity()); + Assert.assertNull(request.getMaxResolution()); + Assert.assertEquals(false, request.getOutputProcessedAudio()); + Assert.assertNull(request.getOutputTranscription()); + Assert.assertNull(request.getBleep()); + Assert.assertNull(request.getOutputDirectory()); + Assert.assertNull(request.getWaitTime()); + } + + @Test + public void testGetDeidentifyImageRequest() { + File file = new File("test.jpg"); + List entities = Arrays.asList(DetectEntities.NAME, DetectEntities.DOB); + TokenFormat tokenFormat = TokenFormat.builder().entityOnly(entities).build(); + + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .entities(entities) + .tokenFormat(tokenFormat) + .outputProcessedImage(true) + .outputOcrText(true) + .build(); + + String vaultId = "vault123"; + String base64Content = "base64string"; + String format = "jpg"; + + DeidentifyImageRequest imageRequest = vaultClient.getDeidentifyImageRequest(request, vaultId, base64Content, format); + + Assert.assertEquals(vaultId, imageRequest.getVaultId()); + Assert.assertEquals(base64Content, imageRequest.getFile().getBase64()); + Assert.assertEquals(format.toUpperCase(), imageRequest.getFile().getDataFormat().name()); + } + + @Test + public void testGetDeidentifyPresentationRequest() { + File file = new File("test.pptx"); + List entities = Arrays.asList(DetectEntities.NAME); + TokenFormat tokenFormat = TokenFormat.builder().entityOnly(entities).build(); + + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .entities(entities) + .tokenFormat(tokenFormat) + .build(); + + String vaultId = "vault123"; + String base64Content = "base64string"; + String format = "pptx"; + + DeidentifyPresentationRequest presRequest = vaultClient.getDeidentifyPresentationRequest(request, vaultId, base64Content, format); + + Assert.assertEquals(vaultId, presRequest.getVaultId()); + Assert.assertEquals(base64Content, presRequest.getFile().getBase64()); + Assert.assertEquals(format.toUpperCase(), presRequest.getFile().getDataFormat().name()); + } + + @Test + public void testGetDeidentifySpreadsheetRequest() { + File file = new File("test.csv"); + List entities = Arrays.asList(DetectEntities.NAME); + TokenFormat tokenFormat = TokenFormat.builder().entityOnly(entities).build(); + + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .entities(entities) + .tokenFormat(tokenFormat) + .build(); + + String vaultId = "vault123"; + String base64Content = "base64string"; + String format = "csv"; + + DeidentifySpreadsheetRequest spreadsheetRequest = vaultClient.getDeidentifySpreadsheetRequest(request, vaultId, base64Content, format); + + Assert.assertEquals(vaultId, spreadsheetRequest.getVaultId()); + Assert.assertEquals(base64Content, spreadsheetRequest.getFile().getBase64()); + Assert.assertEquals(format.toUpperCase(), spreadsheetRequest.getFile().getDataFormat().name()); + } + + @Test + public void testGetDeidentifyStructuredTextRequest() { + File file = new File("test.json"); + List entities = Arrays.asList(DetectEntities.NAME); + TokenFormat tokenFormat = TokenFormat.builder().entityOnly(entities).build(); + + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .entities(entities) + .tokenFormat(tokenFormat) + .build(); + + String vaultId = "vault123"; + String base64Content = "base64string"; + String format = "json"; + + DeidentifyStructuredTextRequest structuredTextRequest = vaultClient.getDeidentifyStructuredTextRequest(request, vaultId, base64Content, format); + + Assert.assertEquals(vaultId, structuredTextRequest.getVaultId()); + Assert.assertEquals(base64Content, structuredTextRequest.getFile().getBase64()); + Assert.assertEquals(format.toUpperCase(), structuredTextRequest.getFile().getDataFormat().name()); + } + + @Test + public void testGetDeidentifyDocumentRequest() { + File file = new File("test.docx"); + List entities = Arrays.asList(DetectEntities.NAME); + TokenFormat tokenFormat = TokenFormat.builder().entityOnly(entities).build(); + + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .entities(entities) + .tokenFormat(tokenFormat) + .build(); + + String vaultId = "vault123"; + String base64Content = "base64string"; + String format = "docx"; + + DeidentifyDocumentRequest documentRequest = vaultClient.getDeidentifyDocumentRequest(request, vaultId, base64Content, format); + + Assert.assertEquals(vaultId, documentRequest.getVaultId()); + Assert.assertEquals(base64Content, documentRequest.getFile().getBase64()); + Assert.assertEquals(format.toUpperCase(), documentRequest.getFile().getDataFormat().name()); + } + + @Test + public void testGetDeidentifyPdfRequest() { + File file = new File("test.pdf"); + List entities = Arrays.asList(DetectEntities.NAME); + TokenFormat tokenFormat = TokenFormat.builder().entityOnly(entities).build(); + + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .entities(entities) + .tokenFormat(tokenFormat) + .pixelDensity(200) + .maxResolution(300) + .build(); + + String vaultId = "vault123"; + String base64Content = "base64string"; + + DeidentifyPdfRequest pdfRequest = vaultClient.getDeidentifyPdfRequest(request, vaultId, base64Content); + + Assert.assertEquals(vaultId, pdfRequest.getVaultId()); + Assert.assertEquals(base64Content, pdfRequest.getFile().getBase64()); + } + + @Test + public void testGetDeidentifyAudioRequest() { + File file = new File("test.mp3"); + List entities = Arrays.asList(DetectEntities.NAME); + TokenFormat tokenFormat = TokenFormat.builder().entityOnly(entities).build(); + AudioBleep bleep = AudioBleep.builder().frequency(1000.0).gain(10.0).startPadding(1.0).stopPadding(1.0).build(); + + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .entities(entities) + .tokenFormat(tokenFormat) + .bleep(bleep) + .outputProcessedAudio(true) + .outputTranscription(DetectOutputTranscriptions.TRANSCRIPTION) + .build(); + + String vaultId = "vault123"; + String base64Content = "base64string"; + String dataFormat = "MP_3"; + + DeidentifyAudioRequest audioRequest = vaultClient.getDeidentifyAudioRequest(request, vaultId, base64Content, dataFormat); + + Assert.assertEquals(vaultId, audioRequest.getVaultId()); + Assert.assertEquals(base64Content, audioRequest.getFile().getBase64()); + Assert.assertEquals(dataFormat, audioRequest.getFile().getDataFormat().name()); + } + + @Test + public void testGetDeidentifyTextFileRequest() { + File file = new File("test.txt"); + List entities = Arrays.asList(DetectEntities.NAME, DetectEntities.DOB); + TokenFormat tokenFormat = TokenFormat.builder().entityOnly(entities).build(); + + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .entities(entities) + .tokenFormat(tokenFormat) + .build(); + + String vaultId = "vault123"; + String base64Content = "base64string"; + + com.skyflow.generated.rest.resources.files.requests.DeidentifyTextRequest textRequest = + vaultClient.getDeidentifyTextFileRequest(request, vaultId, base64Content); + + Assert.assertEquals(vaultId, textRequest.getVaultId()); + Assert.assertEquals(base64Content, textRequest.getFile().getBase64()); + } } diff --git a/src/test/java/com/skyflow/vault/controller/DetectControllerFileTests.java b/src/test/java/com/skyflow/vault/controller/DetectControllerFileTests.java new file mode 100644 index 00000000..14b6d0bd --- /dev/null +++ b/src/test/java/com/skyflow/vault/controller/DetectControllerFileTests.java @@ -0,0 +1,237 @@ +package com.skyflow.vault.controller; + +import com.skyflow.config.Credentials; +import com.skyflow.config.VaultConfig; +import com.skyflow.errors.ErrorCode; +import com.skyflow.errors.SkyflowException; +import com.skyflow.vault.detect.AudioBleep; +import com.skyflow.vault.detect.DeidentifyFileRequest; +import com.skyflow.vault.detect.GetDetectRunRequest; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.util.ArrayList; + +public class DetectControllerFileTests { + private static final String EXCEPTION_NOT_THROWN = "Should have thrown an exception"; + private static String vaultID = null; + private static String clusterID = null; + private static VaultConfig vaultConfig = null; + private static DetectController detectController = null; + + @BeforeClass + public static void setup() { + vaultID = "vault123"; + clusterID = "cluster123"; + + Credentials credentials = new Credentials(); + credentials.setToken("valid-token"); + + vaultConfig = new VaultConfig(); + vaultConfig.setVaultId(vaultID); + vaultConfig.setClusterId(clusterID); + vaultConfig.setEnv(com.skyflow.enums.Env.DEV); + vaultConfig.setCredentials(credentials); + + detectController = new DetectController(vaultConfig, credentials); + } + + @Test + public void testNullFileInDeidentifyFileRequest() { + try { + DeidentifyFileRequest request = DeidentifyFileRequest.builder().build(); + detectController.deidentifyFile(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + } + + @Test + public void testUnreadableFileInDeidentifyFileRequest() { + try { + File file = new File("unreadable.txt") { + @Override + public boolean exists() { return true; } + @Override + public boolean isFile() { return true; } + @Override + public boolean canRead() { return false; } + }; + DeidentifyFileRequest request = DeidentifyFileRequest.builder().file(file).build(); + detectController.deidentifyFile(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (SkyflowException | RuntimeException e) { + // Depending on implementation, could be SkyflowException or RuntimeException + Assert.assertTrue(e.getMessage().contains("not readable") || e.getMessage().contains("unreadable.txt")); + } + } + + @Test + public void testNullEntitiesInDeidentifyFileRequest() { + try { + File file = File.createTempFile("test", ".txt"); + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .entities(new ArrayList<>()) + .build(); + detectController.deidentifyFile(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + } + + @Test + public void testNullRequest() { + try { + detectController.deidentifyFile(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + } + + @Test + public void testNonExistentFileInDeidentifyFileRequest() { + try { + File file = new File("nonexistent.txt"); + DeidentifyFileRequest request = DeidentifyFileRequest.builder().file(file).build(); + detectController.deidentifyFile(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + } + + @Test + public void testInvalidPixelDensity() throws Exception { + File file = File.createTempFile("test", ".txt"); + try { + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .pixelDensity(-1) + .build(); + detectController.deidentifyFile(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + file.delete(); + } + + @Test + public void testInvalidMaxResolution() throws Exception { + File file = File.createTempFile("test", ".txt"); + try { + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .maxResolution(-1) + .build(); + detectController.deidentifyFile(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + file.delete(); + } + + @Test + public void testInvalidBleepFrequency() throws Exception { + File file = File.createTempFile("test", ".txt"); + try { + AudioBleep bleep = AudioBleep.builder().build(); + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .bleep(bleep) + .build(); + detectController.deidentifyFile(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + file.delete(); + } + + @Test + public void testInvalidOutputDirectory() throws Exception { + File file = File.createTempFile("test", ".txt"); + try { + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .outputDirectory("not/a/real/dir") + .build(); + detectController.deidentifyFile(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + file.delete(); + } + + @Test + public void testInvalidWaitTime() throws Exception { + File file = File.createTempFile("test", ".txt"); + try { + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .waitTime(-1) + .build(); + detectController.deidentifyFile(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + file.delete(); + } + + @Test + public void testWaitTimeExceedsLimit() throws Exception { + File file = File.createTempFile("test", ".txt"); + try { + DeidentifyFileRequest request = DeidentifyFileRequest.builder() + .file(file) + .waitTime(100) + .build(); + detectController.deidentifyFile(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + file.delete(); + } + + @Test + public void testNullGetDetectRunRequest() { + try { + detectController.getDetectRun(null); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + } + + @Test + public void testEmptyRunIdInGetDetectRunRequest() { + try { + GetDetectRunRequest request = GetDetectRunRequest.builder().build(); + detectController.getDetectRun(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + } + + @Test + public void testNullRunIdInGetDetectRunRequest() { + try { + GetDetectRunRequest request = GetDetectRunRequest.builder().runId(null).build(); + detectController.getDetectRun(request); + Assert.fail(EXCEPTION_NOT_THROWN); + } catch (Exception e) { + Assert.assertEquals(ErrorCode.INVALID_INPUT.getCode(), 400); + } + } +} \ No newline at end of file