This is an automated email from the ASF dual-hosted git repository.

jsinovassin pushed a commit to branch UNOMI-986-oneshot-import-tenant-dir
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit 59a98f19ec73f815864dcc0852f3548ee1e7017f
Author: jsinovassin <[email protected]>
AuthorDate: Wed Sep 16 18:25:45 2026 +0200

    UNOMI-986: Write a one-shot import CSV to the directory of its tenant
    
    The endpoint that receives a one-shot CSV import and the Camel route that 
consumes it disagreed on
    the path. The endpoint wrote the file to the root of the upload directory. 
The route reads the tenant from the
    name of the directory holding the file, and the root directory is not a 
tenant. Every one-shot import
    uploaded through the endpoint was therefore dropped.
    
    The caller saw no failure. The upload answered 200, and the only trace was 
one warning:
    
      WARN ImportConfigByFileNameProcessor - Invalid or missing tenant ID in 
path:
           /opt/unomi/data/tmp/unomi_oneshot_import_configs/19d061b5-....csv
    
    The endpoint now resolves the current tenant, creates the directory named 
after it, and writes the
    file there. The route already reads sub-directories, because 
ProfileImportOneShotRouteBuilder
    declares recursive=true, so the per-tenant directory is what it expected 
all along.
    
    Measured on Apache Unomi 3.1.0-SNAPSHOT. The upload writes 
<uploadDir>/default/<importConfigId>.csv,
    the route reads it, and the profiles of the CSV are imported. An end to end 
test that drives the
    import through the user interface went from failing to passing.
    
    ExportConfigurationServiceEndPoint carries a /oneshot path as well. This 
commit does not cover the
    export side, which is worth checking for the same disagreement.
---
 .../rest/ImportConfigurationServiceEndPoint.java    | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git 
a/extensions/router/router-rest/src/main/java/org/apache/unomi/router/rest/ImportConfigurationServiceEndPoint.java
 
b/extensions/router/router-rest/src/main/java/org/apache/unomi/router/rest/ImportConfigurationServiceEndPoint.java
index e8d639df1..3dc1cb4d8 100644
--- 
a/extensions/router/router-rest/src/main/java/org/apache/unomi/router/rest/ImportConfigurationServiceEndPoint.java
+++ 
b/extensions/router/router-rest/src/main/java/org/apache/unomi/router/rest/ImportConfigurationServiceEndPoint.java
@@ -20,6 +20,7 @@ import org.apache.cxf.jaxrs.ext.multipart.Attachment;
 import org.apache.cxf.jaxrs.ext.multipart.Multipart;
 import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
 import org.apache.unomi.api.services.ConfigSharingService;
+import org.apache.unomi.api.services.ExecutionContextManager;
 import org.apache.unomi.router.api.ImportConfiguration;
 import org.apache.unomi.router.api.RouterConstants;
 import org.apache.unomi.router.api.services.ImportExportConfigurationService;
@@ -62,10 +63,17 @@ public class ImportConfigurationServiceEndPoint extends 
AbstractConfigurationSer
     @Reference
     protected ConfigSharingService configSharingService;
 
+    @Reference
+    protected ExecutionContextManager executionContextManager;
+
     public void setConfigSharingService(ConfigSharingService 
configSharingService) {
         this.configSharingService = configSharingService;
     }
 
+    public void setExecutionContextManager(ExecutionContextManager 
executionContextManager) {
+        this.executionContextManager = executionContextManager;
+    }
+
     public ImportConfigurationServiceEndPoint() throws KeyStoreException, 
NoSuchAlgorithmException, KeyManagementException {
         LOGGER.info("Initializing import configuration service endpoint...");
     }
@@ -131,8 +139,9 @@ public class ImportConfigurationServiceEndPoint extends 
AbstractConfigurationSer
     /**
      * Uploads a one-shot CSV file for an existing import configuration.
      * <p>
-     * The file is stored under the configured one-shot upload directory as 
{@code {importConfigId}.csv}
-     * for subsequent Camel processing.
+     * The file is stored under the configured one-shot upload directory, in a 
sub-directory named
+     * after the current tenant, as {@code {tenantId}/{importConfigId}.csv}. 
The Camel route reads the
+     * tenant from that directory name.
      *
      * @param importConfigId the import configuration id (multipart field)
      * @param file the CSV file upload (multipart field)
@@ -148,7 +157,13 @@ public class ImportConfigurationServiceEndPoint extends 
AbstractConfigurationSer
     public Response processOneshotImportConfigurationCSV(@Multipart(value = 
"importConfigId") @NotNull @Pattern(regexp = "^[a-zA-Z0-9_.\\-]{1,255}$") 
String importConfigId,
                                                          @Multipart(value = 
"file") Attachment file) {
         try {
-            java.nio.file.Path path = 
Paths.get(configSharingService.getProperty(RouterConstants.IMPORT_ONESHOT_UPLOAD_DIR)
 + importConfigId + ".csv");
+            // The Camel route reads the tenant from the directory holding the 
file, so the upload
+            // writes it there. Without that directory 
ImportConfigByFileNameProcessor answers
+            // "Invalid or missing tenant ID in path" and drops the file, and 
the import never runs.
+            String tenantId = 
executionContextManager.getCurrentContext().getTenantId();
+            java.nio.file.Path tenantDir = 
Paths.get(String.valueOf(configSharingService.getProperty(RouterConstants.IMPORT_ONESHOT_UPLOAD_DIR)),
 tenantId);
+            Files.createDirectories(tenantDir);
+            java.nio.file.Path path = tenantDir.resolve(importConfigId + 
".csv");
             Files.deleteIfExists(path);
             InputStream in = file.getObject(InputStream.class);
 

Reply via email to