mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-04 03:27:09 -05:00 
			
		
		
		
	chore(server): optional originalMimeType in asset response payload (#10272)
* chore(server): optional originalMimeType in asset response payload * lint * Update web/src/lib/utils/asset-utils.ts Co-authored-by: Jason Rasmussen <jrasm91@gmail.com> * fix permission of shared link * test * test * test * test server --------- Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
		
							parent
							
								
									df31eb1214
								
							
						
					
					
						commit
						e2a2c86a31
					
				
							
								
								
									
										19
									
								
								mobile/openapi/lib/model/asset_response_dto.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										19
									
								
								mobile/openapi/lib/model/asset_response_dto.dart
									
									
									
										generated
									
									
									
								
							@ -31,7 +31,7 @@ class AssetResponseDto {
 | 
				
			|||||||
    this.livePhotoVideoId,
 | 
					    this.livePhotoVideoId,
 | 
				
			||||||
    required this.localDateTime,
 | 
					    required this.localDateTime,
 | 
				
			||||||
    required this.originalFileName,
 | 
					    required this.originalFileName,
 | 
				
			||||||
    required this.originalMimeType,
 | 
					    this.originalMimeType,
 | 
				
			||||||
    required this.originalPath,
 | 
					    required this.originalPath,
 | 
				
			||||||
    this.owner,
 | 
					    this.owner,
 | 
				
			||||||
    required this.ownerId,
 | 
					    required this.ownerId,
 | 
				
			||||||
@ -92,7 +92,13 @@ class AssetResponseDto {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  String originalFileName;
 | 
					  String originalFileName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  String originalMimeType;
 | 
					  ///
 | 
				
			||||||
 | 
					  /// Please note: This property should have been non-nullable! Since the specification file
 | 
				
			||||||
 | 
					  /// does not include a default value (using the "default:" property), however, the generated
 | 
				
			||||||
 | 
					  /// source code must fall back to having a nullable type.
 | 
				
			||||||
 | 
					  /// Consider adding a "default:" property in the specification file to hide this note.
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  String? originalMimeType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  String originalPath;
 | 
					  String originalPath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -191,7 +197,7 @@ class AssetResponseDto {
 | 
				
			|||||||
    (livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
 | 
					    (livePhotoVideoId == null ? 0 : livePhotoVideoId!.hashCode) +
 | 
				
			||||||
    (localDateTime.hashCode) +
 | 
					    (localDateTime.hashCode) +
 | 
				
			||||||
    (originalFileName.hashCode) +
 | 
					    (originalFileName.hashCode) +
 | 
				
			||||||
    (originalMimeType.hashCode) +
 | 
					    (originalMimeType == null ? 0 : originalMimeType!.hashCode) +
 | 
				
			||||||
    (originalPath.hashCode) +
 | 
					    (originalPath.hashCode) +
 | 
				
			||||||
    (owner == null ? 0 : owner!.hashCode) +
 | 
					    (owner == null ? 0 : owner!.hashCode) +
 | 
				
			||||||
    (ownerId.hashCode) +
 | 
					    (ownerId.hashCode) +
 | 
				
			||||||
@ -246,7 +252,11 @@ class AssetResponseDto {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
      json[r'localDateTime'] = this.localDateTime.toUtc().toIso8601String();
 | 
					      json[r'localDateTime'] = this.localDateTime.toUtc().toIso8601String();
 | 
				
			||||||
      json[r'originalFileName'] = this.originalFileName;
 | 
					      json[r'originalFileName'] = this.originalFileName;
 | 
				
			||||||
 | 
					    if (this.originalMimeType != null) {
 | 
				
			||||||
      json[r'originalMimeType'] = this.originalMimeType;
 | 
					      json[r'originalMimeType'] = this.originalMimeType;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					    //  json[r'originalMimeType'] = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
      json[r'originalPath'] = this.originalPath;
 | 
					      json[r'originalPath'] = this.originalPath;
 | 
				
			||||||
    if (this.owner != null) {
 | 
					    if (this.owner != null) {
 | 
				
			||||||
      json[r'owner'] = this.owner;
 | 
					      json[r'owner'] = this.owner;
 | 
				
			||||||
@ -310,7 +320,7 @@ class AssetResponseDto {
 | 
				
			|||||||
        livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),
 | 
					        livePhotoVideoId: mapValueOfType<String>(json, r'livePhotoVideoId'),
 | 
				
			||||||
        localDateTime: mapDateTime(json, r'localDateTime', r'')!,
 | 
					        localDateTime: mapDateTime(json, r'localDateTime', r'')!,
 | 
				
			||||||
        originalFileName: mapValueOfType<String>(json, r'originalFileName')!,
 | 
					        originalFileName: mapValueOfType<String>(json, r'originalFileName')!,
 | 
				
			||||||
        originalMimeType: mapValueOfType<String>(json, r'originalMimeType')!,
 | 
					        originalMimeType: mapValueOfType<String>(json, r'originalMimeType'),
 | 
				
			||||||
        originalPath: mapValueOfType<String>(json, r'originalPath')!,
 | 
					        originalPath: mapValueOfType<String>(json, r'originalPath')!,
 | 
				
			||||||
        owner: UserResponseDto.fromJson(json[r'owner']),
 | 
					        owner: UserResponseDto.fromJson(json[r'owner']),
 | 
				
			||||||
        ownerId: mapValueOfType<String>(json, r'ownerId')!,
 | 
					        ownerId: mapValueOfType<String>(json, r'ownerId')!,
 | 
				
			||||||
@ -386,7 +396,6 @@ class AssetResponseDto {
 | 
				
			|||||||
    'isTrashed',
 | 
					    'isTrashed',
 | 
				
			||||||
    'localDateTime',
 | 
					    'localDateTime',
 | 
				
			||||||
    'originalFileName',
 | 
					    'originalFileName',
 | 
				
			||||||
    'originalMimeType',
 | 
					 | 
				
			||||||
    'originalPath',
 | 
					    'originalPath',
 | 
				
			||||||
    'ownerId',
 | 
					    'ownerId',
 | 
				
			||||||
    'resized',
 | 
					    'resized',
 | 
				
			||||||
 | 
				
			|||||||
@ -7785,7 +7785,6 @@
 | 
				
			|||||||
          "isTrashed",
 | 
					          "isTrashed",
 | 
				
			||||||
          "localDateTime",
 | 
					          "localDateTime",
 | 
				
			||||||
          "originalFileName",
 | 
					          "originalFileName",
 | 
				
			||||||
          "originalMimeType",
 | 
					 | 
				
			||||||
          "originalPath",
 | 
					          "originalPath",
 | 
				
			||||||
          "ownerId",
 | 
					          "ownerId",
 | 
				
			||||||
          "resized",
 | 
					          "resized",
 | 
				
			||||||
 | 
				
			|||||||
@ -182,7 +182,7 @@ export type AssetResponseDto = {
 | 
				
			|||||||
    livePhotoVideoId?: string | null;
 | 
					    livePhotoVideoId?: string | null;
 | 
				
			||||||
    localDateTime: string;
 | 
					    localDateTime: string;
 | 
				
			||||||
    originalFileName: string;
 | 
					    originalFileName: string;
 | 
				
			||||||
    originalMimeType: string;
 | 
					    originalMimeType?: string;
 | 
				
			||||||
    originalPath: string;
 | 
					    originalPath: string;
 | 
				
			||||||
    owner?: UserResponseDto;
 | 
					    owner?: UserResponseDto;
 | 
				
			||||||
    ownerId: string;
 | 
					    ownerId: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ export class SanitizedAssetResponseDto {
 | 
				
			|||||||
  @ApiProperty({ enumName: 'AssetTypeEnum', enum: AssetType })
 | 
					  @ApiProperty({ enumName: 'AssetTypeEnum', enum: AssetType })
 | 
				
			||||||
  type!: AssetType;
 | 
					  type!: AssetType;
 | 
				
			||||||
  thumbhash!: string | null;
 | 
					  thumbhash!: string | null;
 | 
				
			||||||
  originalMimeType!: string;
 | 
					  originalMimeType?: string;
 | 
				
			||||||
  resized!: boolean;
 | 
					  resized!: boolean;
 | 
				
			||||||
  localDateTime!: Date;
 | 
					  localDateTime!: Date;
 | 
				
			||||||
  duration!: string;
 | 
					  duration!: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -164,6 +164,36 @@ describe(SharedLinkService.name, () => {
 | 
				
			|||||||
        key: Buffer.from('random-bytes', 'utf8'),
 | 
					        key: Buffer.from('random-bytes', 'utf8'),
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it('should create a shared link with allowDownload set to false when showMetadata is false', async () => {
 | 
				
			||||||
 | 
					      accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set([assetStub.image.id]));
 | 
				
			||||||
 | 
					      shareMock.create.mockResolvedValue(sharedLinkStub.individual);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await sut.create(authStub.admin, {
 | 
				
			||||||
 | 
					        type: SharedLinkType.INDIVIDUAL,
 | 
				
			||||||
 | 
					        assetIds: [assetStub.image.id],
 | 
				
			||||||
 | 
					        showMetadata: false,
 | 
				
			||||||
 | 
					        allowDownload: true,
 | 
				
			||||||
 | 
					        allowUpload: true,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(accessMock.asset.checkOwnerAccess).toHaveBeenCalledWith(
 | 
				
			||||||
 | 
					        authStub.admin.user.id,
 | 
				
			||||||
 | 
					        new Set([assetStub.image.id]),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      expect(shareMock.create).toHaveBeenCalledWith({
 | 
				
			||||||
 | 
					        type: SharedLinkType.INDIVIDUAL,
 | 
				
			||||||
 | 
					        userId: authStub.admin.user.id,
 | 
				
			||||||
 | 
					        albumId: null,
 | 
				
			||||||
 | 
					        allowDownload: false,
 | 
				
			||||||
 | 
					        allowUpload: true,
 | 
				
			||||||
 | 
					        assets: [{ id: assetStub.image.id }],
 | 
				
			||||||
 | 
					        description: null,
 | 
				
			||||||
 | 
					        expiresAt: null,
 | 
				
			||||||
 | 
					        showExif: false,
 | 
				
			||||||
 | 
					        key: Buffer.from('random-bytes', 'utf8'),
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe('update', () => {
 | 
					  describe('update', () => {
 | 
				
			||||||
 | 
				
			|||||||
@ -84,7 +84,7 @@ export class SharedLinkService {
 | 
				
			|||||||
      password: dto.password,
 | 
					      password: dto.password,
 | 
				
			||||||
      expiresAt: dto.expiresAt || null,
 | 
					      expiresAt: dto.expiresAt || null,
 | 
				
			||||||
      allowUpload: dto.allowUpload ?? true,
 | 
					      allowUpload: dto.allowUpload ?? true,
 | 
				
			||||||
      allowDownload: dto.allowDownload ?? true,
 | 
					      allowDownload: dto.showMetadata === false ? false : dto.allowDownload ?? true,
 | 
				
			||||||
      showExif: dto.showMetadata ?? true,
 | 
					      showExif: dto.showMetadata ?? true,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -629,6 +629,7 @@
 | 
				
			|||||||
              {preloadAssets}
 | 
					              {preloadAssets}
 | 
				
			||||||
              on:close={closeViewer}
 | 
					              on:close={closeViewer}
 | 
				
			||||||
              haveFadeTransition={false}
 | 
					              haveFadeTransition={false}
 | 
				
			||||||
 | 
					              {sharedLink}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          {:else}
 | 
					          {:else}
 | 
				
			||||||
            <VideoViewer
 | 
					            <VideoViewer
 | 
				
			||||||
@ -667,7 +668,7 @@
 | 
				
			|||||||
                  .endsWith('.insp'))}
 | 
					                  .endsWith('.insp'))}
 | 
				
			||||||
              <PanoramaViewer {asset} />
 | 
					              <PanoramaViewer {asset} />
 | 
				
			||||||
            {:else}
 | 
					            {:else}
 | 
				
			||||||
              <PhotoViewer bind:zoomToggle bind:copyImage {asset} {preloadAssets} on:close={closeViewer} />
 | 
					              <PhotoViewer bind:zoomToggle bind:copyImage {asset} {preloadAssets} on:close={closeViewer} {sharedLink} />
 | 
				
			||||||
            {/if}
 | 
					            {/if}
 | 
				
			||||||
          {:else}
 | 
					          {:else}
 | 
				
			||||||
            <VideoViewer
 | 
					            <VideoViewer
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@ import PhotoViewer from '$lib/components/asset-viewer/photo-viewer.svelte';
 | 
				
			|||||||
import * as utils from '$lib/utils';
 | 
					import * as utils from '$lib/utils';
 | 
				
			||||||
import { AssetMediaSize } from '@immich/sdk';
 | 
					import { AssetMediaSize } from '@immich/sdk';
 | 
				
			||||||
import { assetFactory } from '@test-data/factories/asset-factory';
 | 
					import { assetFactory } from '@test-data/factories/asset-factory';
 | 
				
			||||||
 | 
					import { sharedLinkFactory } from '@test-data/factories/shared-link-factory';
 | 
				
			||||||
import { render } from '@testing-library/svelte';
 | 
					import { render } from '@testing-library/svelte';
 | 
				
			||||||
import type { MockInstance } from 'vitest';
 | 
					import type { MockInstance } from 'vitest';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -46,4 +47,41 @@ describe('PhotoViewer component', () => {
 | 
				
			|||||||
    expect(getAssetThumbnailUrlSpy).not.toBeCalled();
 | 
					    expect(getAssetThumbnailUrlSpy).not.toBeCalled();
 | 
				
			||||||
    expect(getAssetOriginalUrlSpy).toBeCalledWith({ id: asset.id, checksum: asset.checksum });
 | 
					    expect(getAssetOriginalUrlSpy).toBeCalledWith({ id: asset.id, checksum: asset.checksum });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('loads original for shared link when download permission is true and showMetadata permission is true', () => {
 | 
				
			||||||
 | 
					    const asset = assetFactory.build({ originalPath: 'image.gif', originalMimeType: 'image/gif' });
 | 
				
			||||||
 | 
					    const sharedLink = sharedLinkFactory.build({ allowDownload: true, showMetadata: true, assets: [asset] });
 | 
				
			||||||
 | 
					    render(PhotoViewer, { asset, sharedLink });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(getAssetThumbnailUrlSpy).not.toBeCalled();
 | 
				
			||||||
 | 
					    expect(getAssetOriginalUrlSpy).toBeCalledWith({ id: asset.id, checksum: asset.checksum });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('not loads original image when shared link download permission is false', () => {
 | 
				
			||||||
 | 
					    const asset = assetFactory.build({ originalPath: 'image.gif', originalMimeType: 'image/gif' });
 | 
				
			||||||
 | 
					    const sharedLink = sharedLinkFactory.build({ allowDownload: false, assets: [asset] });
 | 
				
			||||||
 | 
					    render(PhotoViewer, { asset, sharedLink });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(getAssetThumbnailUrlSpy).toBeCalledWith({
 | 
				
			||||||
 | 
					      id: asset.id,
 | 
				
			||||||
 | 
					      size: AssetMediaSize.Preview,
 | 
				
			||||||
 | 
					      checksum: asset.checksum,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(getAssetOriginalUrlSpy).not.toBeCalled();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('not loads original image when shared link showMetadata permission is false', () => {
 | 
				
			||||||
 | 
					    const asset = assetFactory.build({ originalPath: 'image.gif', originalMimeType: 'image/gif' });
 | 
				
			||||||
 | 
					    const sharedLink = sharedLinkFactory.build({ showMetadata: false, assets: [asset] });
 | 
				
			||||||
 | 
					    render(PhotoViewer, { asset, sharedLink });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(getAssetThumbnailUrlSpy).toBeCalledWith({
 | 
				
			||||||
 | 
					      id: asset.id,
 | 
				
			||||||
 | 
					      size: AssetMediaSize.Preview,
 | 
				
			||||||
 | 
					      checksum: asset.checksum,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(getAssetOriginalUrlSpy).not.toBeCalled();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,7 @@
 | 
				
			|||||||
  import { isWebCompatibleImage } from '$lib/utils/asset-utils';
 | 
					  import { isWebCompatibleImage } from '$lib/utils/asset-utils';
 | 
				
			||||||
  import { getBoundingBox } from '$lib/utils/people-utils';
 | 
					  import { getBoundingBox } from '$lib/utils/people-utils';
 | 
				
			||||||
  import { getAltText } from '$lib/utils/thumbnail-util';
 | 
					  import { getAltText } from '$lib/utils/thumbnail-util';
 | 
				
			||||||
  import { AssetTypeEnum, type AssetResponseDto, AssetMediaSize } from '@immich/sdk';
 | 
					  import { AssetTypeEnum, type AssetResponseDto, AssetMediaSize, type SharedLinkResponseDto } from '@immich/sdk';
 | 
				
			||||||
  import { zoomImageAction, zoomed } from '$lib/actions/zoom-image';
 | 
					  import { zoomImageAction, zoomed } from '$lib/actions/zoom-image';
 | 
				
			||||||
  import { canCopyImagesToClipboard, copyImageToClipboard } from 'copy-image-clipboard';
 | 
					  import { canCopyImagesToClipboard, copyImageToClipboard } from 'copy-image-clipboard';
 | 
				
			||||||
  import { onDestroy } from 'svelte';
 | 
					  import { onDestroy } from 'svelte';
 | 
				
			||||||
@ -23,7 +23,7 @@
 | 
				
			|||||||
  export let preloadAssets: AssetResponseDto[] | undefined = undefined;
 | 
					  export let preloadAssets: AssetResponseDto[] | undefined = undefined;
 | 
				
			||||||
  export let element: HTMLDivElement | undefined = undefined;
 | 
					  export let element: HTMLDivElement | undefined = undefined;
 | 
				
			||||||
  export let haveFadeTransition = true;
 | 
					  export let haveFadeTransition = true;
 | 
				
			||||||
 | 
					  export let sharedLink: SharedLinkResponseDto | undefined = undefined;
 | 
				
			||||||
  export let copyImage: (() => Promise<void>) | null = null;
 | 
					  export let copyImage: (() => Promise<void>) | null = null;
 | 
				
			||||||
  export let zoomToggle: (() => void) | null = null;
 | 
					  export let zoomToggle: (() => void) | null = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -67,6 +67,10 @@
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const getAssetUrl = (id: string, useOriginal: boolean, checksum: string) => {
 | 
					  const getAssetUrl = (id: string, useOriginal: boolean, checksum: string) => {
 | 
				
			||||||
 | 
					    if (sharedLink && (!sharedLink.allowDownload || !sharedLink.showMetadata)) {
 | 
				
			||||||
 | 
					      return getAssetThumbnailUrl({ id, size: AssetMediaSize.Preview, checksum });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return useOriginal
 | 
					    return useOriginal
 | 
				
			||||||
      ? getAssetOriginalUrl({ id, checksum })
 | 
					      ? getAssetOriginalUrl({ id, checksum })
 | 
				
			||||||
      : getAssetThumbnailUrl({ id, size: AssetMediaSize.Preview, checksum });
 | 
					      : getAssetThumbnailUrl({ id, size: AssetMediaSize.Preview, checksum });
 | 
				
			||||||
 | 
				
			|||||||
@ -51,7 +51,11 @@
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $: shareType = albumId ? SharedLinkType.Album : SharedLinkType.Individual;
 | 
					  $: shareType = albumId ? SharedLinkType.Album : SharedLinkType.Individual;
 | 
				
			||||||
 | 
					  $: {
 | 
				
			||||||
 | 
					    if (!showMetadata) {
 | 
				
			||||||
 | 
					      allowDownload = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if (editingLink) {
 | 
					  if (editingLink) {
 | 
				
			||||||
    if (editingLink.description) {
 | 
					    if (editingLink.description) {
 | 
				
			||||||
      description = editingLink.description;
 | 
					      description = editingLink.description;
 | 
				
			||||||
@ -227,7 +231,11 @@
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="my-3">
 | 
					        <div class="my-3">
 | 
				
			||||||
          <SettingSwitch bind:checked={allowDownload} title={'Allow public user to download'} />
 | 
					          <SettingSwitch
 | 
				
			||||||
 | 
					            bind:checked={allowDownload}
 | 
				
			||||||
 | 
					            title={'Allow public user to download'}
 | 
				
			||||||
 | 
					            disabled={!showMetadata}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="my-3">
 | 
					        <div class="my-3">
 | 
				
			||||||
 | 
				
			|||||||
@ -270,6 +270,10 @@ const supportedImageMimeTypes = new Set([
 | 
				
			|||||||
 * Returns true if the asset is an image supported by web browsers, false otherwise
 | 
					 * Returns true if the asset is an image supported by web browsers, false otherwise
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export function isWebCompatibleImage(asset: AssetResponseDto): boolean {
 | 
					export function isWebCompatibleImage(asset: AssetResponseDto): boolean {
 | 
				
			||||||
 | 
					  if (!asset.originalMimeType) {
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return supportedImageMimeTypes.has(asset.originalMimeType);
 | 
					  return supportedImageMimeTypes.has(asset.originalMimeType);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										19
									
								
								web/src/test-data/factories/shared-link-factory.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								web/src/test-data/factories/shared-link-factory.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import { faker } from '@faker-js/faker';
 | 
				
			||||||
 | 
					import { SharedLinkType, type SharedLinkResponseDto } from '@immich/sdk';
 | 
				
			||||||
 | 
					import { Sync } from 'factory.ts';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const sharedLinkFactory = Sync.makeFactory<SharedLinkResponseDto>({
 | 
				
			||||||
 | 
					  id: Sync.each(() => faker.string.uuid()),
 | 
				
			||||||
 | 
					  description: Sync.each(() => faker.word.sample()),
 | 
				
			||||||
 | 
					  password: Sync.each(() => faker.word.sample()),
 | 
				
			||||||
 | 
					  token: Sync.each(() => faker.word.sample()),
 | 
				
			||||||
 | 
					  userId: Sync.each(() => faker.string.uuid()),
 | 
				
			||||||
 | 
					  key: Sync.each(() => faker.word.sample()),
 | 
				
			||||||
 | 
					  type: Sync.each(() => faker.helpers.enumValue(SharedLinkType)),
 | 
				
			||||||
 | 
					  createdAt: Sync.each(() => faker.date.past().toISOString()),
 | 
				
			||||||
 | 
					  expiresAt: Sync.each(() => faker.date.past().toISOString()),
 | 
				
			||||||
 | 
					  assets: [],
 | 
				
			||||||
 | 
					  allowUpload: Sync.each(() => faker.datatype.boolean()),
 | 
				
			||||||
 | 
					  allowDownload: Sync.each(() => faker.datatype.boolean()),
 | 
				
			||||||
 | 
					  showMetadata: Sync.each(() => faker.datatype.boolean()),
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user