From 7ccc0b7da80048005f6b295800df07ba026bb3dc Mon Sep 17 00:00:00 2001 From: Aliaksandr Stsiapanay Date: Tue, 28 Jan 2025 17:37:03 +0300 Subject: [PATCH 1/2] fix: Publish request fails for quick apps #653 --- .../server/service/PublicationService.java | 22 +--------------- .../core/server/service/PublicationUtil.java | 25 +++++++++++++++++++ .../server/service/PublicationUtilTest.java | 19 ++++++++++++++ 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/server/src/main/java/com/epam/aidial/core/server/service/PublicationService.java b/server/src/main/java/com/epam/aidial/core/server/service/PublicationService.java index 0edf46c14..6ae4b1af3 100644 --- a/server/src/main/java/com/epam/aidial/core/server/service/PublicationService.java +++ b/server/src/main/java/com/epam/aidial/core/server/service/PublicationService.java @@ -378,26 +378,6 @@ private void prepareAndValidatePublicationRequest(ProxyContext context, Publicat validateRules(publication); } - /** - * Builds the target folder path for custom application files. - * - * @param resource the publication resource containing the target URL - * @return the constructed target folder path for custom application files - */ - private static String buildTargetFolderForCustomAppFiles(Publication.Resource resource) { - String targetUrl = resource.getTargetUrl(); - // Find the index of the end of a bucket segment (the second slash in the target URL) - int indexOfBucketEndSlash = targetUrl.indexOf(ResourceDescriptor.PATH_SEPARATOR, targetUrl.indexOf(ResourceDescriptor.PATH_SEPARATOR) + 1); - // Find the index of the start of a file name (the last slash in the target URL) - int indexOfFileNameStartSlash = targetUrl.lastIndexOf(ResourceDescriptor.PATH_SEPARATOR); - // Extract the application path from the target URL - String appPath = targetUrl.substring(indexOfBucketEndSlash + 1, indexOfFileNameStartSlash); - // Extract the application name from the target URL - String appName = targetUrl.substring(indexOfFileNameStartSlash + 1); - // Construct and return the target folder path - return appPath + ResourceDescriptor.PATH_SEPARATOR + "." + appName + ResourceDescriptor.PATH_SEPARATOR; - } - private void addCustomApplicationRelatedFiles(ProxyContext context, Publication publication) { List existingUrls = publication.getResources().stream() .map(Publication.Resource::getSourceUrl) @@ -416,7 +396,7 @@ private void addCustomApplicationRelatedFiles(ProxyContext context, Publication if (application.getApplicationTypeSchemaId() == null) { return Stream.empty(); } - String targetFolder = buildTargetFolderForCustomAppFiles(resource); + String targetFolder = PublicationUtil.buildTargetFolderForCustomAppFiles(resource.getTargetUrl(), encryption); return ApplicationTypeSchemaUtils.getFiles(context.getConfig(), application, encryption, resourceService) .stream() .filter(sourceDescriptor -> !existingUrls.contains(sourceDescriptor.getUrl()) && !sourceDescriptor.isPublic()) diff --git a/server/src/main/java/com/epam/aidial/core/server/service/PublicationUtil.java b/server/src/main/java/com/epam/aidial/core/server/service/PublicationUtil.java index 241c903d1..76eb2dac5 100644 --- a/server/src/main/java/com/epam/aidial/core/server/service/PublicationUtil.java +++ b/server/src/main/java/com/epam/aidial/core/server/service/PublicationUtil.java @@ -1,12 +1,15 @@ package com.epam.aidial.core.server.service; +import com.epam.aidial.core.server.security.EncryptionService; import com.epam.aidial.core.server.util.ProxyUtil; +import com.epam.aidial.core.server.util.ResourceDescriptorFactory; import com.epam.aidial.core.storage.resource.ResourceDescriptor; import com.epam.aidial.core.storage.util.UrlUtil; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import lombok.experimental.UtilityClass; +import java.util.List; import java.util.Map; @UtilityClass @@ -96,4 +99,26 @@ private JsonObject replaceConversationIdentity(String conversationBody, Resource conversation.put("folderId", folderUrl); return conversation; } + + + /** + * Builds the target folder path for custom application files. + * + * @param targetUrl the target URL of the application being published + * @return the constructed target folder path for custom application files + */ + static String buildTargetFolderForCustomAppFiles(String targetUrl, EncryptionService encryptionService) { + ResourceDescriptor descriptor = ResourceDescriptorFactory.fromAnyUrl(targetUrl, encryptionService); + if (descriptor.isFolder()) { + throw new IllegalArgumentException("target url must be a file"); + } + String appName = descriptor.getName(); + List folders = descriptor.getParentFolders(); + if (folders.isEmpty()) { + return "." + appName + ResourceDescriptor.PATH_SEPARATOR; + } else { + String appPath = String.join(ResourceDescriptor.PATH_SEPARATOR, folders); + return appPath + ResourceDescriptor.PATH_SEPARATOR + "." + appName + ResourceDescriptor.PATH_SEPARATOR; + } + } } diff --git a/server/src/test/java/com/epam/aidial/core/server/service/PublicationUtilTest.java b/server/src/test/java/com/epam/aidial/core/server/service/PublicationUtilTest.java index 50e73c756..3640c7e80 100644 --- a/server/src/test/java/com/epam/aidial/core/server/service/PublicationUtilTest.java +++ b/server/src/test/java/com/epam/aidial/core/server/service/PublicationUtilTest.java @@ -2,18 +2,37 @@ import com.epam.aidial.core.server.ResourceBaseTest; import com.epam.aidial.core.server.data.ResourceTypes; +import com.epam.aidial.core.server.security.EncryptionService; import com.epam.aidial.core.server.util.ProxyUtil; import com.epam.aidial.core.server.util.ResourceDescriptorFactory; import com.epam.aidial.core.storage.resource.ResourceDescriptor; import com.fasterxml.jackson.core.JsonProcessingException; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +@ExtendWith(MockitoExtension.class) public class PublicationUtilTest { + @Mock + private EncryptionService encryptionService; + + @Test + public void testBuildTargetFolderForCustomAppFiles() { + when(encryptionService.decrypt(any(String.class))).thenReturn("location/"); + assertEquals("folder/.appA/", PublicationUtil.buildTargetFolderForCustomAppFiles("applications/asdfoiefjio/folder/appA", encryptionService)); + assertEquals(".appA/", PublicationUtil.buildTargetFolderForCustomAppFiles("applications/asdfoiefjio/appA", encryptionService)); + assertThrows(IllegalArgumentException.class, () -> PublicationUtil.buildTargetFolderForCustomAppFiles("applications/asdfoiefjio/appA/", encryptionService)); + } + @Test void testConversationIdReplacement() { ResourceDescriptor targetResource1 = ResourceDescriptorFactory.fromDecoded(ResourceTypes.CONVERSATION, "bucketName", "bucket/location/", "conversation"); From 5ce566b007050f361e90cd3911077579e8e7d45e Mon Sep 17 00:00:00 2001 From: Aliaksandr Stsiapanay Date: Tue, 28 Jan 2025 18:01:21 +0300 Subject: [PATCH 2/2] fix: resolve PR comments --- .../com/epam/aidial/core/server/service/PublicationUtil.java | 4 ++++ .../epam/aidial/core/server/service/PublicationUtilTest.java | 1 + 2 files changed, 5 insertions(+) diff --git a/server/src/main/java/com/epam/aidial/core/server/service/PublicationUtil.java b/server/src/main/java/com/epam/aidial/core/server/service/PublicationUtil.java index 76eb2dac5..4c3e5b781 100644 --- a/server/src/main/java/com/epam/aidial/core/server/service/PublicationUtil.java +++ b/server/src/main/java/com/epam/aidial/core/server/service/PublicationUtil.java @@ -1,5 +1,6 @@ package com.epam.aidial.core.server.service; +import com.epam.aidial.core.server.data.ResourceTypes; import com.epam.aidial.core.server.security.EncryptionService; import com.epam.aidial.core.server.util.ProxyUtil; import com.epam.aidial.core.server.util.ResourceDescriptorFactory; @@ -112,6 +113,9 @@ static String buildTargetFolderForCustomAppFiles(String targetUrl, EncryptionSer if (descriptor.isFolder()) { throw new IllegalArgumentException("target url must be a file"); } + if (descriptor.getType() != ResourceTypes.APPLICATION) { + throw new IllegalArgumentException("target url must be an application type"); + } String appName = descriptor.getName(); List folders = descriptor.getParentFolders(); if (folders.isEmpty()) { diff --git a/server/src/test/java/com/epam/aidial/core/server/service/PublicationUtilTest.java b/server/src/test/java/com/epam/aidial/core/server/service/PublicationUtilTest.java index 3640c7e80..5e5e8f240 100644 --- a/server/src/test/java/com/epam/aidial/core/server/service/PublicationUtilTest.java +++ b/server/src/test/java/com/epam/aidial/core/server/service/PublicationUtilTest.java @@ -31,6 +31,7 @@ public void testBuildTargetFolderForCustomAppFiles() { assertEquals("folder/.appA/", PublicationUtil.buildTargetFolderForCustomAppFiles("applications/asdfoiefjio/folder/appA", encryptionService)); assertEquals(".appA/", PublicationUtil.buildTargetFolderForCustomAppFiles("applications/asdfoiefjio/appA", encryptionService)); assertThrows(IllegalArgumentException.class, () -> PublicationUtil.buildTargetFolderForCustomAppFiles("applications/asdfoiefjio/appA/", encryptionService)); + assertThrows(IllegalArgumentException.class, () -> PublicationUtil.buildTargetFolderForCustomAppFiles("prompts/asdfoiefjio/appA", encryptionService)); } @Test