Skip to content

Commit

Permalink
feat(server): deterministic download order (#7658)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrasm91 committed Mar 5, 2024
1 parent 8df63b7 commit 972d5a3
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 3 deletions.
33 changes: 31 additions & 2 deletions server/src/domain/download/download.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ describe(DownloadService.name, () => {
};

accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
assetMock.getByIds.mockResolvedValue([assetStub.noResizePath, assetStub.noWebpPath]);
assetMock.getByIds.mockResolvedValue([
{ ...assetStub.noResizePath, id: 'asset-1' },
{ ...assetStub.noWebpPath, id: 'asset-2' },
]);
storageMock.createZipStream.mockReturnValue(archiveMock);

await expect(sut.downloadArchive(authStub.admin, { assetIds: ['asset-1', 'asset-2'] })).resolves.toEqual({
Expand All @@ -110,7 +113,33 @@ describe(DownloadService.name, () => {
};

accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
assetMock.getByIds.mockResolvedValue([assetStub.noResizePath, assetStub.noResizePath]);
assetMock.getByIds.mockResolvedValue([
{ ...assetStub.noResizePath, id: 'asset-1' },
{ ...assetStub.noResizePath, id: 'asset-2' },
]);
storageMock.createZipStream.mockReturnValue(archiveMock);

await expect(sut.downloadArchive(authStub.admin, { assetIds: ['asset-1', 'asset-2'] })).resolves.toEqual({
stream: archiveMock.stream,
});

expect(archiveMock.addFile).toHaveBeenCalledTimes(2);
expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, 'upload/library/IMG_123.jpg', 'IMG_123.jpg');
expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, 'upload/library/IMG_123.jpg', 'IMG_123+1.jpg');
});

it('should be deterministic', async () => {
const archiveMock = {
addFile: jest.fn(),
finalize: jest.fn(),
stream: new Readable(),
};

accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
assetMock.getByIds.mockResolvedValue([
{ ...assetStub.noResizePath, id: 'asset-2' },
{ ...assetStub.noResizePath, id: 'asset-1' },
]);
storageMock.createZipStream.mockReturnValue(archiveMock);

await expect(sut.downloadArchive(authStub.admin, { assetIds: ['asset-1', 'asset-2'] })).resolves.toEqual({
Expand Down
9 changes: 8 additions & 1 deletion server/src/domain/download/download.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,16 @@ export class DownloadService {

const zip = this.storageRepository.createZipStream();
const assets = await this.assetRepository.getByIds(dto.assetIds);
const assetMap = new Map(assets.map((asset) => [asset.id, asset]));
const paths: Record<string, number> = {};

for (const { originalPath, originalFileName } of assets) {
for (const assetId of dto.assetIds) {
const asset = assetMap.get(assetId);
if (!asset) {
continue;
}

const { originalPath, originalFileName } = asset;
const extension = extname(originalPath);
let filename = `${originalFileName}${extension}`;
const count = paths[filename] || 0;
Expand Down

0 comments on commit 972d5a3

Please sign in to comment.