diff --git a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/dataset/DatasetResource.scala b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/dataset/DatasetResource.scala index 72ddd267a49..d5da3dc602b 100644 --- a/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/dataset/DatasetResource.scala +++ b/core/amber/src/main/scala/edu/uci/ics/texera/web/resource/dashboard/user/dataset/DatasetResource.scala @@ -41,8 +41,8 @@ import edu.uci.ics.texera.web.resource.dashboard.user.dataset.DatasetResource.{ ERR_DATASET_NAME_ALREADY_EXISTS, ERR_USER_HAS_NO_ACCESS_TO_DATASET_MESSAGE, ListDatasetsResponse, - calculateLatestDatasetVersionSize, calculateDatasetVersionSize, + calculateLatestDatasetVersionSize, context, createNewDatasetVersionFromFormData, getDashboardDataset, @@ -74,6 +74,7 @@ import java.nio.charset.StandardCharsets import java.nio.file.{Files, Paths} import java.util.zip.{ZipEntry, ZipOutputStream} import java.util +import java.util.Optional import java.util.concurrent.locks.ReentrantLock import javax.annotation.security.RolesAllowed import javax.ws.rs.{ @@ -1108,25 +1109,29 @@ class DatasetResource { /** * Retrieves a ZIP file for a specific dataset version or the latest version. * - * @param pathStr The dataset version path in the format: /ownerEmail/datasetName/versionName - * Example: /user@example.com/dataset/v1 - * @param getLatest When true, retrieves the latest version regardless of the provided path. - * @param did The dataset ID (used when getLatest is true). + * @param did The dataset ID (used when getLatest is true). + * @param dvid The dataset version ID, if given, retrieve this version; if not given, retrieve the latest version * @param user The session user. * @return A Response containing the dataset version as a ZIP file. */ @GET @Path("/version-zip") def retrieveDatasetVersionZip( - @QueryParam("path") pathStr: String, - @QueryParam("getLatest") getLatest: Boolean, @QueryParam("did") did: UInteger, + @QueryParam("dvid") dvid: Optional[Integer], @Auth user: SessionUser ): Response = { - val (dataset, version) = if (getLatest) { + if (!userHasReadAccess(context, did, user.getUid)) { + throw new ForbiddenException(ERR_USER_HAS_NO_ACCESS_TO_DATASET_MESSAGE) + } + val (dataset, version) = if (dvid.isEmpty) { + // dvid is not given, retrieve latest getLatestVersionInfo(did, user) } else { - resolveAndValidatePath(pathStr, user) + // dvid is given, retrieve certain version + withTransaction(context)(ctx => + (getDatasetByID(ctx, did), getDatasetVersionByID(ctx, UInteger.valueOf(dvid.get))) + ) } val targetDatasetPath = PathUtils.getDatasetPath(dataset.getDid) val fileNodes = GitVersionControlLocalFileStorage.retrieveRootFileNodesOfVersion( diff --git a/core/gui/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/user-dataset-explorer.component.ts b/core/gui/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/user-dataset-explorer.component.ts index b8f1d6d19d0..90c5ae05db6 100644 --- a/core/gui/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/user-dataset-explorer.component.ts +++ b/core/gui/src/app/dashboard/component/user/user-dataset/user-dataset-explorer/user-dataset-explorer.component.ts @@ -193,18 +193,11 @@ export class UserDatasetExplorerComponent implements OnInit { this.downloadService.downloadSingleFile(this.currentDisplayedFileName).pipe(untilDestroyed(this)).subscribe(); }; - extractVersionPath(currentDisplayedFileName: string): string { - const pathParts = currentDisplayedFileName.split("/"); - - return `/${pathParts[1]}/${pathParts[2]}/${pathParts[3]}`; - } - onClickDownloadVersionAsZip = (): void => { if (!this.did || !this.selectedVersion?.dvid) return; - const versionPath = this.extractVersionPath(this.currentDisplayedFileName); this.downloadService - .downloadDatasetVersion(versionPath, this.datasetName, this.selectedVersion.name) + .downloadDatasetVersion(this.did, this.selectedVersion.dvid, this.datasetName, this.selectedVersion.name) .pipe(untilDestroyed(this)) .subscribe(); }; diff --git a/core/gui/src/app/dashboard/service/user/dataset/dataset.service.ts b/core/gui/src/app/dashboard/service/user/dataset/dataset.service.ts index d97aefcaff6..2917ebb84cc 100644 --- a/core/gui/src/app/dashboard/service/user/dataset/dataset.service.ts +++ b/core/gui/src/app/dashboard/service/user/dataset/dataset.service.ts @@ -68,15 +68,11 @@ export class DatasetService { * - did: A number representing the dataset ID * @returns An Observable that emits a Blob containing the zip file */ - public retrieveDatasetZip(options: { path?: string; did?: number }): Observable { + public retrieveDatasetZip(options: { did: number; dvid?: number }): Observable { let params = new HttpParams(); - - if (options.path) { - params = params.set("path", encodeURIComponent(options.path)); - } - if (options.did) { - params = params.set("did", options.did.toString()); - params = params.set("getLatest", "true"); + params = params.set("did", options.did.toString()); + if (options.dvid) { + params = params.set("dvid", options.dvid.toString()); } return this.http.get(`${AppSettings.getApiEndpoint()}/${DATASET_BASE_URL}/version-zip`, { diff --git a/core/gui/src/app/dashboard/service/user/download/download.service.spec.ts b/core/gui/src/app/dashboard/service/user/download/download.service.spec.ts index 75bbf2e8f8f..47bdb764e12 100644 --- a/core/gui/src/app/dashboard/service/user/download/download.service.spec.ts +++ b/core/gui/src/app/dashboard/service/user/download/download.service.spec.ts @@ -134,18 +134,19 @@ describe("DownloadService", () => { }); it("should download a dataset version successfully", done => { - const versionPath = "path/to/version"; + const datasetId = 1; + const datasetVersionId = 1; const datasetName = "TestDataset"; const versionName = "v1.0"; const mockBlob = new Blob(["version content"], { type: "application/zip" }); datasetServiceSpy.retrieveDatasetZip.and.returnValue(of(mockBlob)); - downloadService.downloadDatasetVersion(versionPath, datasetName, versionName).subscribe({ + downloadService.downloadDatasetVersion(datasetId, datasetVersionId, datasetName, versionName).subscribe({ next: blob => { expect(blob).toBe(mockBlob); expect(notificationServiceSpy.info).toHaveBeenCalledWith("Starting to download version v1.0 as ZIP"); - expect(datasetServiceSpy.retrieveDatasetZip).toHaveBeenCalledWith({ path: versionPath }); + expect(datasetServiceSpy.retrieveDatasetZip).toHaveBeenCalledWith({ did: datasetId, dvid: datasetVersionId }); expect(fileSaverServiceSpy.saveAs).toHaveBeenCalledWith(mockBlob, "TestDataset-v1.0.zip"); expect(notificationServiceSpy.success).toHaveBeenCalledWith("Version v1.0 has been downloaded as ZIP"); done(); @@ -157,21 +158,22 @@ describe("DownloadService", () => { }); it("should handle dataset version download failure correctly", done => { - const versionPath = "path/to/version"; + const datasetId = 1; + const datasetVersionId = 1; const datasetName = "TestDataset"; const versionName = "v1.0"; const errorMessage = "Dataset version download failed"; datasetServiceSpy.retrieveDatasetZip.and.returnValue(throwError(() => new Error(errorMessage))); - downloadService.downloadDatasetVersion(versionPath, datasetName, versionName).subscribe({ + downloadService.downloadDatasetVersion(datasetId, datasetVersionId, datasetName, versionName).subscribe({ next: () => { fail("Should have thrown an error"); }, error: (error: unknown) => { expect(error).toBeTruthy(); expect(notificationServiceSpy.info).toHaveBeenCalledWith("Starting to download version v1.0 as ZIP"); - expect(datasetServiceSpy.retrieveDatasetZip).toHaveBeenCalledWith({ path: versionPath }); + expect(datasetServiceSpy.retrieveDatasetZip).toHaveBeenCalledWith({ did: datasetId, dvid: datasetVersionId }); expect(fileSaverServiceSpy.saveAs).not.toHaveBeenCalled(); expect(notificationServiceSpy.error).toHaveBeenCalledWith("Error downloading version 'v1.0' as ZIP"); done(); diff --git a/core/gui/src/app/dashboard/service/user/download/download.service.ts b/core/gui/src/app/dashboard/service/user/download/download.service.ts index 2ce5a309c72..d2682853735 100644 --- a/core/gui/src/app/dashboard/service/user/download/download.service.ts +++ b/core/gui/src/app/dashboard/service/user/download/download.service.ts @@ -46,9 +46,14 @@ export class DownloadService { ); } - downloadDatasetVersion(versionPath: string, datasetName: string, versionName: string): Observable { + downloadDatasetVersion( + datasetId: number, + datasetVersionId: number, + datasetName: string, + versionName: string + ): Observable { return this.downloadWithNotification( - () => this.datasetService.retrieveDatasetZip({ path: versionPath }), + () => this.datasetService.retrieveDatasetZip({ did: datasetId, dvid: datasetVersionId }), `${datasetName}-${versionName}.zip`, `Starting to download version ${versionName} as ZIP`, `Version ${versionName} has been downloaded as ZIP`,