Merge branch '18834-uploading-a-file-into-a-subdirectory-of-a-collection-does-not...
authorDaniel Kutyła <daniel.kutyla@contractors.roche.com>
Wed, 6 Apr 2022 20:15:08 +0000 (22:15 +0200)
committerDaniel Kutyła <daniel.kutyla@contractors.roche.com>
Wed, 6 Apr 2022 20:15:08 +0000 (22:15 +0200)
closes #18834

Arvados-DCO-1.1-Signed-off-by: Daniel Kutyła <daniel.kutyla@contractors.roche.com>

1  2 
src/services/collection-service/collection-service.test.ts
src/services/collection-service/collection-service.ts

index 610683694f626c7bd9157fabec99240f9f922835,88c5f725950f7031f9df2f7cdae0309a8cc180b2..817fdd5453bac324948d1d8d8170c8bec2d7168f
@@@ -4,8 -4,7 +4,8 @@@
  
  import axios, { AxiosInstance } from 'axios';
  import MockAdapter from 'axios-mock-adapter';
 -import { CollectionResource } from 'models/collection';
 +import { snakeCase } from 'lodash';
 +import { CollectionResource, defaultCollectionSelectedFields } from 'models/collection';
  import { AuthService } from '../auth-service/auth-service';
  import { CollectionService } from './collection-service';
  
@@@ -22,6 -21,7 +22,7 @@@ describe('collection-service', () => 
          axiosMock = new MockAdapter(serverApi);
          webdavClient = {
              delete: jest.fn(),
+             upload: jest.fn(),
          } as any;
          authService = {} as AuthService;
          actions = {
      });
  
      describe('get', () => {
 -        it('should make a list request with uuid filtering', async () => {
 +        it('should make a request with default selected fields', async () => {
              serverApi.get = jest.fn(() => Promise.resolve(
                  { data: { items: [{}] } }
              ));
              const uuid = 'zzzzz-4zz18-0123456789abcde'
              await collectionService.get(uuid);
              expect(serverApi.get).toHaveBeenCalledWith(
 -                '/collections', {
 +                `/collections/${uuid}`, {
                      params: {
 -                        filters: `[["uuid","=","zzzzz-4zz18-0123456789abcde"]]`,
 -                        include_old_versions: true,
 +                        select: JSON.stringify(defaultCollectionSelectedFields.map(snakeCase)),
                      },
                  }
              );
              const uuid = 'zzzzz-4zz18-0123456789abcde'
              await collectionService.get(uuid, undefined, ['manifestText']);
              expect(serverApi.get).toHaveBeenCalledWith(
 -                '/collections', {
 +                `/collections/${uuid}`, {
                      params: {
 -                        filters: `[["uuid","=","zzzzz-4zz18-0123456789abcde"]]`,
 -                        include_old_versions: true,
                          select: `["manifest_text"]`
                      },
                  }
          });
      });
  
+     describe('uploadFiles', () => {
+         it('should skip if no files to upload files', async () => {
+             // given
+             const files: File[] = [];
+             const collectionUUID = '';
+             // when
+             await collectionService.uploadFiles(collectionUUID, files);
+             // then
+             expect(webdavClient.upload).not.toHaveBeenCalled();
+         });
+         it('should upload files', async () => {
+             // given
+             const files: File[] = [{name: 'test-file1'} as File];
+             const collectionUUID = 'zzzzz-4zz18-0123456789abcde';
+             // when
+             await collectionService.uploadFiles(collectionUUID, files);
+             // then
+             expect(webdavClient.upload).toHaveBeenCalledTimes(1);
+             expect(webdavClient.upload.mock.calls[0][0]).toEqual("c=zzzzz-4zz18-0123456789abcde/test-file1");
+         });
+         it.only('should upload files with custom uplaod target', async () => {
+             // given
+             const files: File[] = [{name: 'test-file1'} as File];
+             const collectionUUID = 'zzzzz-4zz18-0123456789abcde';
+             const customTarget = 'zzzzz-4zz18-0123456789adddd/test-path/'
+             // when
+             await collectionService.uploadFiles(collectionUUID, files, undefined, customTarget);
+             // then
+             expect(webdavClient.upload).toHaveBeenCalledTimes(1);
+             expect(webdavClient.upload.mock.calls[0][0]).toEqual("c=zzzzz-4zz18-0123456789adddd/test-path/test-file1");
+         });
+     });
      describe('deleteFiles', () => {
          it('should remove no files', async () => {
              // given
index 857828c255ed2d5df521a39b078cb5ae973bc129,e5071d7e007af4ccea1f0df1ec894359ffc57618..92e4dfbae3e6d43f28f73b03dfce992da3f3fcfc
@@@ -2,7 -2,7 +2,7 @@@
  //
  // SPDX-License-Identifier: AGPL-3.0
  
 -import { CollectionResource } from "models/collection";
 +import { CollectionResource, defaultCollectionSelectedFields } from "models/collection";
  import { AxiosInstance } from "axios";
  import { CollectionFile, CollectionDirectory } from "models/collection-file";
  import { WebDAV } from "common/webdav";
@@@ -11,6 -11,8 +11,6 @@@ import { extractFilesData } from "./col
  import { TrashableResourceService } from "services/common-service/trashable-resource-service";
  import { ApiActions } from "services/api/api-actions";
  import { customEncodeURI } from "common/url";
 -import { FilterBuilder } from "services/api/filter-builder";
 -import { ListArguments } from "services/common-service/common-service";
  import { Session } from "models/session";
  
  export type UploadProgress = (fileId: number, loaded: number, total: number, currentTime: number) => void;
@@@ -31,8 -33,19 +31,8 @@@ export class CollectionService extends 
  
      async get(uuid: string, showErrors?: boolean, select?: string[], session?: Session) {
          super.validateUuid(uuid);
 -        // We use a filtered list request to avoid getting the manifest text
 -        const filters = new FilterBuilder().addEqual('uuid', uuid).getFilters();
 -        const listArgs: ListArguments = {filters, includeOldVersions: true};
 -        if (select) {
 -            listArgs.select = select;
 -        }
 -
 -        if (!session) {
 -            const lst = await super.list(listArgs, showErrors);
 -            return lst.items[0];
 -        } else {
 -            return super.get(uuid, showErrors, select, session);
 -        }
 +        const selectParam = select || defaultCollectionSelectedFields;
 +        return super.get(uuid, showErrors, selectParam, session);
      }
  
      create(data?: Partial<CollectionResource>) {
          await this.update(collectionUuid, { preserveVersion: true });
      }
  
-     async uploadFiles(collectionUuid: string, files: File[], onProgress?: UploadProgress) {
+     async uploadFiles(collectionUuid: string, files: File[], onProgress?: UploadProgress, targetLocation: string = '') {
          if (collectionUuid === "" || files.length === 0) { return; }
          // files have to be uploaded sequentially
          for (let idx = 0; idx < files.length; idx++) {
-             await this.uploadFile(collectionUuid, files[idx], idx, onProgress);
+             await this.uploadFile(collectionUuid, files[idx], idx, onProgress, targetLocation);
          }
          await this.update(collectionUuid, { preserveVersion: true });
      }
          };
      }
  
-     private async uploadFile(collectionUuid: string, file: File, fileId: number, onProgress: UploadProgress = () => { return; }) {
-         const fileURL = `c=${collectionUuid}/${file.name}`;
+     private async uploadFile(collectionUuid: string, file: File, fileId: number, onProgress: UploadProgress = () => { return; }, targetLocation: string = '') {
+         const fileURL = `c=${targetLocation !== '' ? targetLocation : collectionUuid}/${file.name}`.replace('//', '/');
          const requestConfig = {
              headers: {
                  'Content-Type': 'text/octet-stream'