diff --git a/mobile/openapi/.openapi-generator/FILES b/mobile/openapi/.openapi-generator/FILES
index d68e7e9b3..62b938b3a 100644
--- a/mobile/openapi/.openapi-generator/FILES
+++ b/mobile/openapi/.openapi-generator/FILES
@@ -31,6 +31,7 @@ doc/CheckExistingAssetsDto.md
doc/CheckExistingAssetsResponseDto.md
doc/CreateAlbumDto.md
doc/CreateAlbumShareLinkDto.md
+doc/CreateAssetsShareLinkDto.md
doc/CreateProfileImageResponseDto.md
doc/CreateTagDto.md
doc/CreateUserDto.md
@@ -86,6 +87,7 @@ doc/ThumbnailFormat.md
doc/TimeGroupEnum.md
doc/UpdateAlbumDto.md
doc/UpdateAssetDto.md
+doc/UpdateAssetsToSharedLinkDto.md
doc/UpdateTagDto.md
doc/UpdateUserDto.md
doc/UpsertDeviceInfoDto.md
@@ -140,6 +142,7 @@ lib/model/check_existing_assets_dto.dart
lib/model/check_existing_assets_response_dto.dart
lib/model/create_album_dto.dart
lib/model/create_album_share_link_dto.dart
+lib/model/create_assets_share_link_dto.dart
lib/model/create_profile_image_response_dto.dart
lib/model/create_tag_dto.dart
lib/model/create_user_dto.dart
@@ -188,6 +191,7 @@ lib/model/thumbnail_format.dart
lib/model/time_group_enum.dart
lib/model/update_album_dto.dart
lib/model/update_asset_dto.dart
+lib/model/update_assets_to_shared_link_dto.dart
lib/model/update_tag_dto.dart
lib/model/update_user_dto.dart
lib/model/upsert_device_info_dto.dart
@@ -224,6 +228,7 @@ test/check_existing_assets_dto_test.dart
test/check_existing_assets_response_dto_test.dart
test/create_album_dto_test.dart
test/create_album_share_link_dto_test.dart
+test/create_assets_share_link_dto_test.dart
test/create_profile_image_response_dto_test.dart
test/create_tag_dto_test.dart
test/create_user_dto_test.dart
@@ -279,6 +284,7 @@ test/thumbnail_format_test.dart
test/time_group_enum_test.dart
test/update_album_dto_test.dart
test/update_asset_dto_test.dart
+test/update_assets_to_shared_link_dto_test.dart
test/update_tag_dto_test.dart
test/update_user_dto_test.dart
test/upsert_device_info_dto_test.dart
diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md
index 5ff0099b0..46a36d839 100644
Binary files a/mobile/openapi/README.md and b/mobile/openapi/README.md differ
diff --git a/mobile/openapi/doc/APIKeyApi.md b/mobile/openapi/doc/APIKeyApi.md
index c715cedd8..4918e6161 100644
Binary files a/mobile/openapi/doc/APIKeyApi.md and b/mobile/openapi/doc/APIKeyApi.md differ
diff --git a/mobile/openapi/doc/AlbumApi.md b/mobile/openapi/doc/AlbumApi.md
index 7f57c201a..02405ec98 100644
Binary files a/mobile/openapi/doc/AlbumApi.md and b/mobile/openapi/doc/AlbumApi.md differ
diff --git a/mobile/openapi/doc/AssetApi.md b/mobile/openapi/doc/AssetApi.md
index f8fafd51d..547005353 100644
Binary files a/mobile/openapi/doc/AssetApi.md and b/mobile/openapi/doc/AssetApi.md differ
diff --git a/mobile/openapi/doc/AuthenticationApi.md b/mobile/openapi/doc/AuthenticationApi.md
index ffcece086..8c9b0e2d4 100644
Binary files a/mobile/openapi/doc/AuthenticationApi.md and b/mobile/openapi/doc/AuthenticationApi.md differ
diff --git a/mobile/openapi/doc/CreateAssetsShareLinkDto.md b/mobile/openapi/doc/CreateAssetsShareLinkDto.md
new file mode 100644
index 000000000..2ceffddee
Binary files /dev/null and b/mobile/openapi/doc/CreateAssetsShareLinkDto.md differ
diff --git a/mobile/openapi/doc/DeviceInfoApi.md b/mobile/openapi/doc/DeviceInfoApi.md
index b4dcdb255..1ee91414a 100644
Binary files a/mobile/openapi/doc/DeviceInfoApi.md and b/mobile/openapi/doc/DeviceInfoApi.md differ
diff --git a/mobile/openapi/doc/JobApi.md b/mobile/openapi/doc/JobApi.md
index 124e3d214..b2f2b4f7a 100644
Binary files a/mobile/openapi/doc/JobApi.md and b/mobile/openapi/doc/JobApi.md differ
diff --git a/mobile/openapi/doc/OAuthApi.md b/mobile/openapi/doc/OAuthApi.md
index 836cd8455..d1bcec668 100644
Binary files a/mobile/openapi/doc/OAuthApi.md and b/mobile/openapi/doc/OAuthApi.md differ
diff --git a/mobile/openapi/doc/ServerInfoApi.md b/mobile/openapi/doc/ServerInfoApi.md
index 0e1ff6649..4089a3baf 100644
Binary files a/mobile/openapi/doc/ServerInfoApi.md and b/mobile/openapi/doc/ServerInfoApi.md differ
diff --git a/mobile/openapi/doc/ShareApi.md b/mobile/openapi/doc/ShareApi.md
index 419f115fb..045793b75 100644
Binary files a/mobile/openapi/doc/ShareApi.md and b/mobile/openapi/doc/ShareApi.md differ
diff --git a/mobile/openapi/doc/SystemConfigApi.md b/mobile/openapi/doc/SystemConfigApi.md
index ae8d234cc..74cf32606 100644
Binary files a/mobile/openapi/doc/SystemConfigApi.md and b/mobile/openapi/doc/SystemConfigApi.md differ
diff --git a/mobile/openapi/doc/TagApi.md b/mobile/openapi/doc/TagApi.md
index 2603525e1..7e3996c10 100644
Binary files a/mobile/openapi/doc/TagApi.md and b/mobile/openapi/doc/TagApi.md differ
diff --git a/mobile/openapi/doc/UpdateAssetsToSharedLinkDto.md b/mobile/openapi/doc/UpdateAssetsToSharedLinkDto.md
new file mode 100644
index 000000000..3f7d70c7e
Binary files /dev/null and b/mobile/openapi/doc/UpdateAssetsToSharedLinkDto.md differ
diff --git a/mobile/openapi/doc/UserApi.md b/mobile/openapi/doc/UserApi.md
index 752fb7945..01b6bd1ad 100644
Binary files a/mobile/openapi/doc/UserApi.md and b/mobile/openapi/doc/UserApi.md differ
diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart
index 595ca69b5..70ff81ddf 100644
Binary files a/mobile/openapi/lib/api.dart and b/mobile/openapi/lib/api.dart differ
diff --git a/mobile/openapi/lib/api/album_api.dart b/mobile/openapi/lib/api/album_api.dart
index 614aad807..f3e2b96d9 100644
Binary files a/mobile/openapi/lib/api/album_api.dart and b/mobile/openapi/lib/api/album_api.dart differ
diff --git a/mobile/openapi/lib/api/api_key_api.dart b/mobile/openapi/lib/api/api_key_api.dart
index 26223bf89..7cc9a3589 100644
Binary files a/mobile/openapi/lib/api/api_key_api.dart and b/mobile/openapi/lib/api/api_key_api.dart differ
diff --git a/mobile/openapi/lib/api/asset_api.dart b/mobile/openapi/lib/api/asset_api.dart
index fb0e2b719..5f4f278d2 100644
Binary files a/mobile/openapi/lib/api/asset_api.dart and b/mobile/openapi/lib/api/asset_api.dart differ
diff --git a/mobile/openapi/lib/api/authentication_api.dart b/mobile/openapi/lib/api/authentication_api.dart
index 39888550d..628ee2f1f 100644
Binary files a/mobile/openapi/lib/api/authentication_api.dart and b/mobile/openapi/lib/api/authentication_api.dart differ
diff --git a/mobile/openapi/lib/api/device_info_api.dart b/mobile/openapi/lib/api/device_info_api.dart
index 2aa2ff7c5..4cde7c5e4 100644
Binary files a/mobile/openapi/lib/api/device_info_api.dart and b/mobile/openapi/lib/api/device_info_api.dart differ
diff --git a/mobile/openapi/lib/api/job_api.dart b/mobile/openapi/lib/api/job_api.dart
index b64a67c35..2fafd44d3 100644
Binary files a/mobile/openapi/lib/api/job_api.dart and b/mobile/openapi/lib/api/job_api.dart differ
diff --git a/mobile/openapi/lib/api/o_auth_api.dart b/mobile/openapi/lib/api/o_auth_api.dart
index b8778596a..61165c9a2 100644
Binary files a/mobile/openapi/lib/api/o_auth_api.dart and b/mobile/openapi/lib/api/o_auth_api.dart differ
diff --git a/mobile/openapi/lib/api/server_info_api.dart b/mobile/openapi/lib/api/server_info_api.dart
index 8cc3460c9..a939f885e 100644
Binary files a/mobile/openapi/lib/api/server_info_api.dart and b/mobile/openapi/lib/api/server_info_api.dart differ
diff --git a/mobile/openapi/lib/api/share_api.dart b/mobile/openapi/lib/api/share_api.dart
index 6695e6aa0..d574023ff 100644
Binary files a/mobile/openapi/lib/api/share_api.dart and b/mobile/openapi/lib/api/share_api.dart differ
diff --git a/mobile/openapi/lib/api/system_config_api.dart b/mobile/openapi/lib/api/system_config_api.dart
index d2d0ac5ba..328a1fc3b 100644
Binary files a/mobile/openapi/lib/api/system_config_api.dart and b/mobile/openapi/lib/api/system_config_api.dart differ
diff --git a/mobile/openapi/lib/api/tag_api.dart b/mobile/openapi/lib/api/tag_api.dart
index 3591cf11c..1869e0ade 100644
Binary files a/mobile/openapi/lib/api/tag_api.dart and b/mobile/openapi/lib/api/tag_api.dart differ
diff --git a/mobile/openapi/lib/api/user_api.dart b/mobile/openapi/lib/api/user_api.dart
index f187652ac..51bd6180f 100644
Binary files a/mobile/openapi/lib/api/user_api.dart and b/mobile/openapi/lib/api/user_api.dart differ
diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart
index 3a916af67..38bf12fb8 100644
Binary files a/mobile/openapi/lib/api_client.dart and b/mobile/openapi/lib/api_client.dart differ
diff --git a/mobile/openapi/lib/model/create_assets_share_link_dto.dart b/mobile/openapi/lib/model/create_assets_share_link_dto.dart
new file mode 100644
index 000000000..12fc7fb64
Binary files /dev/null and b/mobile/openapi/lib/model/create_assets_share_link_dto.dart differ
diff --git a/mobile/openapi/lib/model/update_assets_to_shared_link_dto.dart b/mobile/openapi/lib/model/update_assets_to_shared_link_dto.dart
new file mode 100644
index 000000000..fb8a4c780
Binary files /dev/null and b/mobile/openapi/lib/model/update_assets_to_shared_link_dto.dart differ
diff --git a/mobile/openapi/test/album_api_test.dart b/mobile/openapi/test/album_api_test.dart
index f120d01bd..8d22634b4 100644
Binary files a/mobile/openapi/test/album_api_test.dart and b/mobile/openapi/test/album_api_test.dart differ
diff --git a/mobile/openapi/test/api_key_api_test.dart b/mobile/openapi/test/api_key_api_test.dart
index 588a6f4c2..df8272065 100644
Binary files a/mobile/openapi/test/api_key_api_test.dart and b/mobile/openapi/test/api_key_api_test.dart differ
diff --git a/mobile/openapi/test/asset_api_test.dart b/mobile/openapi/test/asset_api_test.dart
index c7f356dac..930893b39 100644
Binary files a/mobile/openapi/test/asset_api_test.dart and b/mobile/openapi/test/asset_api_test.dart differ
diff --git a/mobile/openapi/test/authentication_api_test.dart b/mobile/openapi/test/authentication_api_test.dart
index f855d3239..45f283f8a 100644
Binary files a/mobile/openapi/test/authentication_api_test.dart and b/mobile/openapi/test/authentication_api_test.dart differ
diff --git a/mobile/openapi/test/create_assets_share_link_dto_test.dart b/mobile/openapi/test/create_assets_share_link_dto_test.dart
new file mode 100644
index 000000000..813e6bced
Binary files /dev/null and b/mobile/openapi/test/create_assets_share_link_dto_test.dart differ
diff --git a/mobile/openapi/test/device_info_api_test.dart b/mobile/openapi/test/device_info_api_test.dart
index f7271b8dc..5bfbb4c32 100644
Binary files a/mobile/openapi/test/device_info_api_test.dart and b/mobile/openapi/test/device_info_api_test.dart differ
diff --git a/mobile/openapi/test/job_api_test.dart b/mobile/openapi/test/job_api_test.dart
index ece525212..5ff6fd774 100644
Binary files a/mobile/openapi/test/job_api_test.dart and b/mobile/openapi/test/job_api_test.dart differ
diff --git a/mobile/openapi/test/o_auth_api_test.dart b/mobile/openapi/test/o_auth_api_test.dart
index bc8b5f381..db5e6c0a2 100644
Binary files a/mobile/openapi/test/o_auth_api_test.dart and b/mobile/openapi/test/o_auth_api_test.dart differ
diff --git a/mobile/openapi/test/server_info_api_test.dart b/mobile/openapi/test/server_info_api_test.dart
index b662587ee..e2222244e 100644
Binary files a/mobile/openapi/test/server_info_api_test.dart and b/mobile/openapi/test/server_info_api_test.dart differ
diff --git a/mobile/openapi/test/share_api_test.dart b/mobile/openapi/test/share_api_test.dart
index fcc988cdf..3fb8f8955 100644
Binary files a/mobile/openapi/test/share_api_test.dart and b/mobile/openapi/test/share_api_test.dart differ
diff --git a/mobile/openapi/test/system_config_api_test.dart b/mobile/openapi/test/system_config_api_test.dart
index 6cb7aa79d..28a3b0ed2 100644
Binary files a/mobile/openapi/test/system_config_api_test.dart and b/mobile/openapi/test/system_config_api_test.dart differ
diff --git a/mobile/openapi/test/tag_api_test.dart b/mobile/openapi/test/tag_api_test.dart
index a504aedfa..ffb6c70a4 100644
Binary files a/mobile/openapi/test/tag_api_test.dart and b/mobile/openapi/test/tag_api_test.dart differ
diff --git a/mobile/openapi/test/update_assets_to_shared_link_dto_test.dart b/mobile/openapi/test/update_assets_to_shared_link_dto_test.dart
new file mode 100644
index 000000000..9b0fb4d1d
Binary files /dev/null and b/mobile/openapi/test/update_assets_to_shared_link_dto_test.dart differ
diff --git a/mobile/openapi/test/user_api_test.dart b/mobile/openapi/test/user_api_test.dart
index 5163a1500..d24f36590 100644
Binary files a/mobile/openapi/test/user_api_test.dart and b/mobile/openapi/test/user_api_test.dart differ
diff --git a/server/apps/immich/src/api-v1/asset/asset.controller.ts b/server/apps/immich/src/api-v1/asset/asset.controller.ts
index a2f9a7f7f..4f2d24a7c 100644
--- a/server/apps/immich/src/api-v1/asset/asset.controller.ts
+++ b/server/apps/immich/src/api-v1/asset/asset.controller.ts
@@ -14,6 +14,7 @@ import {
Header,
Put,
UploadedFiles,
+ Patch,
} from '@nestjs/common';
import { Authenticated } from '../../decorators/authenticated.decorator';
import { AssetService } from './asset.service';
@@ -50,6 +51,9 @@ import {
IMMICH_CONTENT_LENGTH_HINT,
} from '../../constants/download.constant';
import { DownloadFilesDto } from './dto/download-files.dto';
+import { CreateAssetsShareLinkDto } from './dto/create-asset-shared-link.dto';
+import { SharedLinkResponseDto } from '../share/response-dto/shared-link-response.dto';
+import { UpdateAssetsToSharedLinkDto } from './dto/add-assets-to-shared-link.dto';
@ApiBearerAuth()
@ApiTags('Asset')
@@ -321,4 +325,22 @@ export class AssetController {
): Promise {
return await this.assetService.checkExistingAssets(authUser, checkExistingAssetsDto);
}
+
+ @Authenticated()
+ @Post('/shared-link')
+ async createAssetsSharedLink(
+ @GetAuthUser() authUser: AuthUserDto,
+ @Body(ValidationPipe) dto: CreateAssetsShareLinkDto,
+ ): Promise {
+ return await this.assetService.createAssetsSharedLink(authUser, dto);
+ }
+
+ @Authenticated({ isShared: true })
+ @Patch('/shared-link')
+ async updateAssetsInSharedLink(
+ @GetAuthUser() authUser: AuthUserDto,
+ @Body(ValidationPipe) dto: UpdateAssetsToSharedLinkDto,
+ ): Promise {
+ return await this.assetService.updateAssetsInSharedLink(authUser, dto);
+ }
}
diff --git a/server/apps/immich/src/api-v1/asset/asset.service.ts b/server/apps/immich/src/api-v1/asset/asset.service.ts
index aeae60da9..6f2138ea5 100644
--- a/server/apps/immich/src/api-v1/asset/asset.service.ts
+++ b/server/apps/immich/src/api-v1/asset/asset.service.ts
@@ -13,7 +13,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { createHash, randomUUID } from 'node:crypto';
import { QueryFailedError, Repository } from 'typeorm';
import { AuthUserDto } from '../../decorators/auth-user.decorator';
-import { AssetEntity, AssetType } from '@app/infra';
+import { AssetEntity, AssetType, SharedLinkType } from '@app/infra';
import { constants, createReadStream, ReadStream, stat } from 'fs';
import { ServeFileDto } from './dto/serve-file.dto';
import { Response as Res } from 'express';
@@ -59,6 +59,9 @@ import { StorageService } from '@app/storage';
import { ShareCore } from '../share/share.core';
import { ISharedLinkRepository } from '../share/shared-link.repository';
import { DownloadFilesDto } from './dto/download-files.dto';
+import { CreateAssetsShareLinkDto } from './dto/create-asset-shared-link.dto';
+import { mapSharedLinkToResponseDto, SharedLinkResponseDto } from '../share/response-dto/shared-link-response.dto';
+import { UpdateAssetsToSharedLinkDto } from './dto/add-assets-to-shared-link.dto';
const fileInfo = promisify(stat);
@@ -699,6 +702,42 @@ export class AssetService {
throw new ForbiddenException();
}
}
+
+ async createAssetsSharedLink(authUser: AuthUserDto, dto: CreateAssetsShareLinkDto): Promise {
+ const assets = [];
+
+ await this.checkAssetsAccess(authUser, dto.assetIds);
+ for (const assetId of dto.assetIds) {
+ const asset = await this._assetRepository.getById(assetId);
+ assets.push(asset);
+ }
+
+ const sharedLink = await this.shareCore.createSharedLink(authUser.id, {
+ sharedType: SharedLinkType.INDIVIDUAL,
+ expiredAt: dto.expiredAt,
+ allowUpload: dto.allowUpload,
+ assets: assets,
+ description: dto.description,
+ });
+
+ return mapSharedLinkToResponseDto(sharedLink);
+ }
+
+ async updateAssetsInSharedLink(
+ authUser: AuthUserDto,
+ dto: UpdateAssetsToSharedLinkDto,
+ ): Promise {
+ if (!authUser.sharedLinkId) throw new ForbiddenException();
+ const assets = [];
+
+ for (const assetId of dto.assetIds) {
+ const asset = await this._assetRepository.getById(assetId);
+ assets.push(asset);
+ }
+
+ const updatedLink = await this.shareCore.updateAssetsInSharedLink(authUser.sharedLinkId, assets);
+ return mapSharedLinkToResponseDto(updatedLink);
+ }
}
async function processETag(path: string, res: Res, headers: Record): Promise {
diff --git a/server/apps/immich/src/api-v1/asset/dto/add-assets-to-shared-link.dto.ts b/server/apps/immich/src/api-v1/asset/dto/add-assets-to-shared-link.dto.ts
new file mode 100644
index 000000000..2eb451d3d
--- /dev/null
+++ b/server/apps/immich/src/api-v1/asset/dto/add-assets-to-shared-link.dto.ts
@@ -0,0 +1,6 @@
+import { IsNotEmpty } from 'class-validator';
+
+export class UpdateAssetsToSharedLinkDto {
+ @IsNotEmpty()
+ assetIds!: string[];
+}
diff --git a/server/apps/immich/src/api-v1/asset/dto/create-asset-shared-link.dto.ts b/server/apps/immich/src/api-v1/asset/dto/create-asset-shared-link.dto.ts
new file mode 100644
index 000000000..7a2f72be9
--- /dev/null
+++ b/server/apps/immich/src/api-v1/asset/dto/create-asset-shared-link.dto.ts
@@ -0,0 +1,31 @@
+import { ApiProperty } from '@nestjs/swagger';
+import { IsArray, IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator';
+
+export class CreateAssetsShareLinkDto {
+ @IsArray()
+ @IsString({ each: true })
+ @IsNotEmpty({ each: true })
+ @ApiProperty({
+ isArray: true,
+ type: String,
+ title: 'Array asset IDs to be shared',
+ example: [
+ 'bf973405-3f2a-48d2-a687-2ed4167164be',
+ 'dd41870b-5d00-46d2-924e-1d8489a0aa0f',
+ 'fad77c3f-deef-4e7e-9608-14c1aa4e559a',
+ ],
+ })
+ assetIds!: string[];
+
+ @IsString()
+ @IsOptional()
+ expiredAt?: string;
+
+ @IsBoolean()
+ @IsOptional()
+ allowUpload?: boolean;
+
+ @IsString()
+ @IsOptional()
+ description?: string;
+}
diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json
index cf77df1ca..82f2a501d 100644
--- a/server/immich-openapi-specs.json
+++ b/server/immich-openapi-specs.json
@@ -1258,6 +1258,78 @@
]
}
},
+ "/asset/shared-link": {
+ "post": {
+ "operationId": "createAssetsSharedLink",
+ "description": "",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateAssetsShareLinkDto"
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SharedLinkResponseDto"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "Asset"
+ ],
+ "security": [
+ {
+ "bearer": []
+ }
+ ]
+ },
+ "patch": {
+ "operationId": "updateAssetsInSharedLink",
+ "description": "",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdateAssetsToSharedLinkDto"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SharedLinkResponseDto"
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "Asset"
+ ],
+ "security": [
+ {
+ "bearer": []
+ }
+ ]
+ }
+ },
"/share": {
"get": {
"operationId": "getAllSharedLinks",
@@ -3548,6 +3620,35 @@
"existingIds"
]
},
+ "CreateAssetsShareLinkDto": {
+ "type": "object",
+ "properties": {
+ "assetIds": {
+ "title": "Array asset IDs to be shared",
+ "example": [
+ "bf973405-3f2a-48d2-a687-2ed4167164be",
+ "dd41870b-5d00-46d2-924e-1d8489a0aa0f",
+ "fad77c3f-deef-4e7e-9608-14c1aa4e559a"
+ ],
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "expiredAt": {
+ "type": "string"
+ },
+ "allowUpload": {
+ "type": "boolean"
+ },
+ "description": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "assetIds"
+ ]
+ },
"SharedLinkType": {
"type": "string",
"enum": [
@@ -3654,6 +3755,20 @@
"allowUpload"
]
},
+ "UpdateAssetsToSharedLinkDto": {
+ "type": "object",
+ "properties": {
+ "assetIds": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "assetIds"
+ ]
+ },
"EditSharedLinkDto": {
"type": "object",
"properties": {
diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts
index 4627973a4..5af6cb396 100644
--- a/web/src/api/open-api/api.ts
+++ b/web/src/api/open-api/api.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.40.0
+ * The version of the OpenAPI document: 1.41.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
@@ -702,6 +702,37 @@ export interface CreateAlbumShareLinkDto {
*/
'description'?: string;
}
+/**
+ *
+ * @export
+ * @interface CreateAssetsShareLinkDto
+ */
+export interface CreateAssetsShareLinkDto {
+ /**
+ *
+ * @type {Array}
+ * @memberof CreateAssetsShareLinkDto
+ */
+ 'assetIds': Array;
+ /**
+ *
+ * @type {string}
+ * @memberof CreateAssetsShareLinkDto
+ */
+ 'expiredAt'?: string;
+ /**
+ *
+ * @type {boolean}
+ * @memberof CreateAssetsShareLinkDto
+ */
+ 'allowUpload'?: boolean;
+ /**
+ *
+ * @type {string}
+ * @memberof CreateAssetsShareLinkDto
+ */
+ 'description'?: string;
+}
/**
*
* @export
@@ -2029,6 +2060,19 @@ export interface UpdateAssetDto {
*/
'isFavorite'?: boolean;
}
+/**
+ *
+ * @export
+ * @interface UpdateAssetsToSharedLinkDto
+ */
+export interface UpdateAssetsToSharedLinkDto {
+ /**
+ *
+ * @type {Array}
+ * @memberof UpdateAssetsToSharedLinkDto
+ */
+ 'assetIds': Array;
+}
/**
*
* @export
@@ -3599,6 +3643,45 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
options: localVarRequestOptions,
};
},
+ /**
+ *
+ * @param {CreateAssetsShareLinkDto} createAssetsShareLinkDto
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ createAssetsSharedLink: async (createAssetsShareLinkDto: CreateAssetsShareLinkDto, options: AxiosRequestConfig = {}): Promise => {
+ // verify required parameter 'createAssetsShareLinkDto' is not null or undefined
+ assertParamExists('createAssetsSharedLink', 'createAssetsShareLinkDto', createAssetsShareLinkDto)
+ const localVarPath = `/asset/shared-link`;
+ // use dummy base URL string because the URL constructor only accepts absolute URLs.
+ const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
+ let baseOptions;
+ if (configuration) {
+ baseOptions = configuration.baseOptions;
+ }
+
+ const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
+ const localVarHeaderParameter = {} as any;
+ const localVarQueryParameter = {} as any;
+
+ // authentication bearer required
+ // http bearer authentication required
+ await setBearerAuthToObject(localVarHeaderParameter, configuration)
+
+
+
+ localVarHeaderParameter['Content-Type'] = 'application/json';
+
+ setSearchParams(localVarUrlObj, localVarQueryParameter);
+ let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+ localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+ localVarRequestOptions.data = serializeDataIfNeeded(createAssetsShareLinkDto, localVarRequestOptions, configuration)
+
+ return {
+ url: toPathString(localVarUrlObj),
+ options: localVarRequestOptions,
+ };
+ },
/**
*
* @param {DeleteAssetDto} deleteAssetDto
@@ -4255,6 +4338,45 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
options: localVarRequestOptions,
};
},
+ /**
+ *
+ * @param {UpdateAssetsToSharedLinkDto} updateAssetsToSharedLinkDto
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ updateAssetsInSharedLink: async (updateAssetsToSharedLinkDto: UpdateAssetsToSharedLinkDto, options: AxiosRequestConfig = {}): Promise => {
+ // verify required parameter 'updateAssetsToSharedLinkDto' is not null or undefined
+ assertParamExists('updateAssetsInSharedLink', 'updateAssetsToSharedLinkDto', updateAssetsToSharedLinkDto)
+ const localVarPath = `/asset/shared-link`;
+ // use dummy base URL string because the URL constructor only accepts absolute URLs.
+ const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
+ let baseOptions;
+ if (configuration) {
+ baseOptions = configuration.baseOptions;
+ }
+
+ const localVarRequestOptions = { method: 'PATCH', ...baseOptions, ...options};
+ const localVarHeaderParameter = {} as any;
+ const localVarQueryParameter = {} as any;
+
+ // authentication bearer required
+ // http bearer authentication required
+ await setBearerAuthToObject(localVarHeaderParameter, configuration)
+
+
+
+ localVarHeaderParameter['Content-Type'] = 'application/json';
+
+ setSearchParams(localVarUrlObj, localVarQueryParameter);
+ let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+ localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+ localVarRequestOptions.data = serializeDataIfNeeded(updateAssetsToSharedLinkDto, localVarRequestOptions, configuration)
+
+ return {
+ url: toPathString(localVarUrlObj),
+ options: localVarRequestOptions,
+ };
+ },
/**
*
* @param {any} assetData
@@ -4329,6 +4451,16 @@ export const AssetApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.checkExistingAssets(checkExistingAssetsDto, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
+ /**
+ *
+ * @param {CreateAssetsShareLinkDto} createAssetsShareLinkDto
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ async createAssetsSharedLink(createAssetsShareLinkDto: CreateAssetsShareLinkDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
+ const localVarAxiosArgs = await localVarAxiosParamCreator.createAssetsSharedLink(createAssetsShareLinkDto, options);
+ return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
+ },
/**
*
* @param {DeleteAssetDto} deleteAssetDto
@@ -4501,6 +4633,16 @@ export const AssetApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.updateAsset(assetId, updateAssetDto, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
+ /**
+ *
+ * @param {UpdateAssetsToSharedLinkDto} updateAssetsToSharedLinkDto
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ async updateAssetsInSharedLink(updateAssetsToSharedLinkDto: UpdateAssetsToSharedLinkDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
+ const localVarAxiosArgs = await localVarAxiosParamCreator.updateAssetsInSharedLink(updateAssetsToSharedLinkDto, options);
+ return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
+ },
/**
*
* @param {any} assetData
@@ -4539,6 +4681,15 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
checkExistingAssets(checkExistingAssetsDto: CheckExistingAssetsDto, options?: any): AxiosPromise {
return localVarFp.checkExistingAssets(checkExistingAssetsDto, options).then((request) => request(axios, basePath));
},
+ /**
+ *
+ * @param {CreateAssetsShareLinkDto} createAssetsShareLinkDto
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ createAssetsSharedLink(createAssetsShareLinkDto: CreateAssetsShareLinkDto, options?: any): AxiosPromise {
+ return localVarFp.createAssetsSharedLink(createAssetsShareLinkDto, options).then((request) => request(axios, basePath));
+ },
/**
*
* @param {DeleteAssetDto} deleteAssetDto
@@ -4694,6 +4845,15 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
updateAsset(assetId: string, updateAssetDto: UpdateAssetDto, options?: any): AxiosPromise {
return localVarFp.updateAsset(assetId, updateAssetDto, options).then((request) => request(axios, basePath));
},
+ /**
+ *
+ * @param {UpdateAssetsToSharedLinkDto} updateAssetsToSharedLinkDto
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ updateAssetsInSharedLink(updateAssetsToSharedLinkDto: UpdateAssetsToSharedLinkDto, options?: any): AxiosPromise {
+ return localVarFp.updateAssetsInSharedLink(updateAssetsToSharedLinkDto, options).then((request) => request(axios, basePath));
+ },
/**
*
* @param {any} assetData
@@ -4735,6 +4895,17 @@ export class AssetApi extends BaseAPI {
return AssetApiFp(this.configuration).checkExistingAssets(checkExistingAssetsDto, options).then((request) => request(this.axios, this.basePath));
}
+ /**
+ *
+ * @param {CreateAssetsShareLinkDto} createAssetsShareLinkDto
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof AssetApi
+ */
+ public createAssetsSharedLink(createAssetsShareLinkDto: CreateAssetsShareLinkDto, options?: AxiosRequestConfig) {
+ return AssetApiFp(this.configuration).createAssetsSharedLink(createAssetsShareLinkDto, options).then((request) => request(this.axios, this.basePath));
+ }
+
/**
*
* @param {DeleteAssetDto} deleteAssetDto
@@ -4924,6 +5095,17 @@ export class AssetApi extends BaseAPI {
return AssetApiFp(this.configuration).updateAsset(assetId, updateAssetDto, options).then((request) => request(this.axios, this.basePath));
}
+ /**
+ *
+ * @param {UpdateAssetsToSharedLinkDto} updateAssetsToSharedLinkDto
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof AssetApi
+ */
+ public updateAssetsInSharedLink(updateAssetsToSharedLinkDto: UpdateAssetsToSharedLinkDto, options?: AxiosRequestConfig) {
+ return AssetApiFp(this.configuration).updateAssetsInSharedLink(updateAssetsToSharedLinkDto, options).then((request) => request(this.axios, this.basePath));
+ }
+
/**
*
* @param {any} assetData
@@ -5300,6 +5482,7 @@ export const DeviceInfoApiAxiosParamCreator = function (configuration?: Configur
* @deprecated
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
+ * @deprecated
* @throws {RequiredError}
*/
createDeviceInfo: async (upsertDeviceInfoDto: UpsertDeviceInfoDto, options: AxiosRequestConfig = {}): Promise => {
@@ -5339,6 +5522,7 @@ export const DeviceInfoApiAxiosParamCreator = function (configuration?: Configur
* @deprecated
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
+ * @deprecated
* @throws {RequiredError}
*/
updateDeviceInfo: async (upsertDeviceInfoDto: UpsertDeviceInfoDto, options: AxiosRequestConfig = {}): Promise => {
@@ -5427,6 +5611,7 @@ export const DeviceInfoApiFp = function(configuration?: Configuration) {
* @deprecated
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
+ * @deprecated
* @throws {RequiredError}
*/
async createDeviceInfo(upsertDeviceInfoDto: UpsertDeviceInfoDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
@@ -5437,6 +5622,7 @@ export const DeviceInfoApiFp = function(configuration?: Configuration) {
* @deprecated
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
+ * @deprecated
* @throws {RequiredError}
*/
async updateDeviceInfo(upsertDeviceInfoDto: UpsertDeviceInfoDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
@@ -5467,6 +5653,7 @@ export const DeviceInfoApiFactory = function (configuration?: Configuration, bas
* @deprecated
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
+ * @deprecated
* @throws {RequiredError}
*/
createDeviceInfo(upsertDeviceInfoDto: UpsertDeviceInfoDto, options?: any): AxiosPromise {
@@ -5476,6 +5663,7 @@ export const DeviceInfoApiFactory = function (configuration?: Configuration, bas
* @deprecated
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
+ * @deprecated
* @throws {RequiredError}
*/
updateDeviceInfo(upsertDeviceInfoDto: UpsertDeviceInfoDto, options?: any): AxiosPromise {
@@ -5504,6 +5692,7 @@ export class DeviceInfoApi extends BaseAPI {
* @deprecated
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
+ * @deprecated
* @throws {RequiredError}
* @memberof DeviceInfoApi
*/
@@ -5515,6 +5704,7 @@ export class DeviceInfoApi extends BaseAPI {
* @deprecated
* @param {UpsertDeviceInfoDto} upsertDeviceInfoDto
* @param {*} [options] Override http request option.
+ * @deprecated
* @throws {RequiredError}
* @memberof DeviceInfoApi
*/
diff --git a/web/src/api/open-api/base.ts b/web/src/api/open-api/base.ts
index 4d4ced151..2d8f7a0a4 100644
--- a/web/src/api/open-api/base.ts
+++ b/web/src/api/open-api/base.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.40.0
+ * The version of the OpenAPI document: 1.41.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/web/src/api/open-api/common.ts b/web/src/api/open-api/common.ts
index d51fd5cd2..acd18acb2 100644
--- a/web/src/api/open-api/common.ts
+++ b/web/src/api/open-api/common.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.40.0
+ * The version of the OpenAPI document: 1.41.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/web/src/api/open-api/configuration.ts b/web/src/api/open-api/configuration.ts
index 14b5a1c7a..65556da1f 100644
--- a/web/src/api/open-api/configuration.ts
+++ b/web/src/api/open-api/configuration.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.40.0
+ * The version of the OpenAPI document: 1.41.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/web/src/api/open-api/index.ts b/web/src/api/open-api/index.ts
index 0ce2e4a1f..ea27b5ef1 100644
--- a/web/src/api/open-api/index.ts
+++ b/web/src/api/open-api/index.ts
@@ -4,7 +4,7 @@
* Immich
* Immich API
*
- * The version of the OpenAPI document: 1.40.0
+ * The version of the OpenAPI document: 1.41.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte
index 2b78aa6f1..501d68d5a 100644
--- a/web/src/lib/components/album-page/album-viewer.svelte
+++ b/web/src/lib/components/album-page/album-viewer.svelte
@@ -1,13 +1,11 @@
+
+
+ {#if isMultiSelectionMode}
+
+
+
+ Selected {selectedAssets.size}
+
+
+
+ downloadAssets(false)}
+ logo={CloudDownloadOutline}
+ />
+ {#if isOwned}
+
+ {/if}
+
+
+ {:else}
+ goto('/photos')}
+ backIcon={ArrowLeft}
+ showBackButton={false}
+ >
+
+
+
+
+ IMMICH
+
+
+
+
+
+ {#if sharedLink?.allowUpload}
+
+ {/if}
+
+ downloadAssets(true)}
+ logo={FolderDownloadOutline}
+ />
+
+
+ {/if}
+
+
diff --git a/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte b/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte
index c98d65244..5b3eabb6d 100644
--- a/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte
+++ b/web/src/lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte
@@ -2,7 +2,13 @@
import { createEventDispatcher, onMount } from 'svelte';
import BaseModal from '../base-modal.svelte';
import Link from 'svelte-material-icons/Link.svelte';
- import { AlbumResponseDto, api, SharedLinkResponseDto, SharedLinkType } from '@api';
+ import {
+ AlbumResponseDto,
+ api,
+ AssetResponseDto,
+ SharedLinkResponseDto,
+ SharedLinkType
+ } from '@api';
import { notificationController, NotificationType } from '../notification/notification';
import { ImmichDropDownOption } from '../dropdown-button.svelte';
import SettingSwitch from '$lib/components/admin-page/settings/setting-switch.svelte';
@@ -10,9 +16,11 @@
import SettingInputField, {
SettingInputFieldType
} from '$lib/components/admin-page/settings/setting-input-field.svelte';
+ import { handleError } from '$lib/utils/handle-error';
export let shareType: SharedLinkType;
- export let album: AlbumResponseDto | undefined;
+ export let sharedAssets: AssetResponseDto[] = [];
+ export let album: AlbumResponseDto | undefined = undefined;
export let editingLink: SharedLinkResponseDto | undefined = undefined;
let isShowSharedLink = false;
@@ -37,32 +45,36 @@
}
});
- const createAlbumSharedLink = async () => {
- if (album) {
- try {
- const expirationTime = getExpirationTimeInMillisecond();
- const currentTime = new Date().getTime();
- const expirationDate = expirationTime
- ? new Date(currentTime + expirationTime).toISOString()
- : undefined;
+ const handleCreateSharedLink = async () => {
+ const expirationTime = getExpirationTimeInMillisecond();
+ const currentTime = new Date().getTime();
+ const expirationDate = expirationTime
+ ? new Date(currentTime + expirationTime).toISOString()
+ : undefined;
+ try {
+ if (shareType === SharedLinkType.Album && album) {
const { data } = await api.albumApi.createAlbumSharedLink({
albumId: album.id,
expiredAt: expirationDate,
allowUpload: isAllowUpload,
description: description
});
-
buildSharedLink(data);
- isShowSharedLink = true;
- } catch (e) {
- console.error('[createAlbumSharedLink] Error: ', e);
- notificationController.show({
- type: NotificationType.Error,
- message: 'Failed to create shared link'
+ } else {
+ const { data } = await api.assetApi.createAssetsSharedLink({
+ assetIds: sharedAssets.map((a) => a.id),
+ expiredAt: expirationDate,
+ allowUpload: isAllowUpload,
+ description: description
});
+ buildSharedLink(data);
}
+ } catch (e) {
+ handleError(e, 'Failed to create shared link');
}
+
+ isShowSharedLink = true;
};
const buildSharedLink = (createdLink: SharedLinkResponseDto) => {
@@ -76,8 +88,11 @@
message: 'Copied to clipboard!',
type: NotificationType.Info
});
- } catch (error) {
- console.error('Error', error);
+ } catch (e) {
+ handleError(
+ e,
+ 'Cannot copy to clipboard, make sure you are accessing the page through https'
+ );
}
};
@@ -127,11 +142,7 @@
dispatch('close');
} catch (e) {
- console.error('[handleEditLink]', e);
- notificationController.show({
- type: NotificationType.Error,
- message: 'Failed to edit shared link'
- });
+ handleError(e, 'Failed to edit shared link');
}
}
};
@@ -162,6 +173,18 @@
{/if}
{/if}
+ {#if shareType == SharedLinkType.Individual}
+ {#if !editingLink}
+ Let anyone with the link see the selected photo(s)
+ {:else}
+
+ Individual shared | {editingLink.description}
+
+ {/if}
+ {/if}
+
@@ -215,7 +238,7 @@
{:else}
-
+
{@html notificationInfo.message}
diff --git a/web/src/lib/utils/file-uploader.ts b/web/src/lib/utils/file-uploader.ts
index 671534f25..5c6949c22 100644
--- a/web/src/lib/utils/file-uploader.ts
+++ b/web/src/lib/utils/file-uploader.ts
@@ -12,7 +12,7 @@ import { addAssetsToAlbum } from '$lib/utils/asset-utils';
export const openFileUploadDialog = (
albumId: string | undefined = undefined,
sharedKey: string | undefined = undefined,
- callback?: () => void
+ onDone?: (id: string) => void
) => {
try {
const fileSelector = document.createElement('input');
@@ -28,8 +28,7 @@ export const openFileUploadDialog = (
}
const files = Array.from(target.files);
- await fileUploadHandler(files, albumId, sharedKey);
- callback && callback();
+ await fileUploadHandler(files, albumId, sharedKey, onDone);
};
fileSelector.click();
@@ -41,7 +40,8 @@ export const openFileUploadDialog = (
export const fileUploadHandler = async (
files: File[],
albumId: string | undefined = undefined,
- sharedKey: string | undefined = undefined
+ sharedKey: string | undefined = undefined,
+ onDone?: (id: string) => void
) => {
if (files.length > 50) {
notificationController.show({
@@ -54,13 +54,13 @@ export const fileUploadHandler = async (
return;
}
- console.log('fileUploadHandler');
+
const acceptedFile = files.filter(
(e) => e.type.split('/')[0] === 'video' || e.type.split('/')[0] === 'image'
);
for (const asset of acceptedFile) {
- await fileUploader(asset, albumId, sharedKey);
+ await fileUploader(asset, albumId, sharedKey, onDone);
}
};
@@ -68,7 +68,8 @@ export const fileUploadHandler = async (
async function fileUploader(
asset: File,
albumId: string | undefined = undefined,
- sharedKey: string | undefined = undefined
+ sharedKey: string | undefined = undefined,
+ onDone?: (id: string) => void
) {
const assetType = asset.type.split('/')[0].toUpperCase();
const temp = asset.name.split('.');
@@ -135,6 +136,7 @@ async function fileUploader(
if (albumId && dataId) {
addAssetsToAlbum(albumId, [dataId]);
}
+ onDone && dataId && onDone(dataId);
return;
}
}
@@ -154,10 +156,9 @@ async function fileUploader(
request.upload.onload = () => {
setTimeout(() => {
uploadAssetsStore.removeUploadAsset(deviceAssetId);
-
+ const res: AssetFileUploadResponseDto = JSON.parse(request.response || '{}');
if (albumId) {
try {
- const res: AssetFileUploadResponseDto = JSON.parse(request.response || '{}');
if (res.id) {
addAssetsToAlbum(albumId, [res.id], sharedKey);
}
@@ -165,6 +166,7 @@ async function fileUploader(
console.error('ERROR parsing data JSON in upload onload');
}
}
+ onDone && onDone(res.id);
}, 1000);
};
diff --git a/web/src/routes/photos/+page.svelte b/web/src/routes/photos/+page.svelte
index dccba87cf..43208f38e 100644
--- a/web/src/routes/photos/+page.svelte
+++ b/web/src/routes/photos/+page.svelte
@@ -6,9 +6,8 @@
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import AlbumSelectionModal from '$lib/components/shared-components/album-selection-modal.svelte';
import { goto } from '$app/navigation';
-
import type { PageData } from './$types';
-
+ import ShareVariantOutline from 'svelte-material-icons/ShareVariantOutline.svelte';
import { openFileUploadDialog } from '$lib/utils/file-uploader';
import {
assetInteractionStore,
@@ -21,16 +20,17 @@
import CircleIconButton from '$lib/components/shared-components/circle-icon-button.svelte';
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
import Plus from 'svelte-material-icons/Plus.svelte';
- import { AlbumResponseDto, api } from '@api';
+ import { AlbumResponseDto, api, SharedLinkType } from '@api';
import {
notificationController,
NotificationType
} from '$lib/components/shared-components/notification/notification';
import { assetStore } from '$lib/stores/assets.store';
import { addAssetsToAlbum, bulkDownload } from '$lib/utils/asset-utils';
+ import CreateSharedLinkModal from '$lib/components/shared-components/create-share-link-modal/create-shared-link-modal.svelte';
export let data: PageData;
-
+ let isShowCreateSharedLinkModal = false;
const deleteSelectedAssetHandler = async () => {
try {
if (
@@ -114,6 +114,15 @@
assetInteractionStore.clearMultiselect();
});
};
+
+ const handleCreateSharedLink = async () => {
+ isShowCreateSharedLinkModal = true;
+ };
+
+ const handleCloseSharedLinkModal = () => {
+ assetInteractionStore.clearMultiselect();
+ isShowCreateSharedLinkModal = false;
+ };
+
(isShowAlbumPicker = false)}
/>
{/if}
+
+ {#if isShowCreateSharedLinkModal}
+
+ {/if}
{
+export const load: PageServerLoad = async ({ params, parent }) => {
+ const { user } = await parent();
+
const { key } = params;
try {
@@ -22,7 +24,8 @@ export const load: PageServerLoad = async ({ params }) => {
imageUrl: assetId
? getThumbnailUrl(assetId, ThumbnailFormat.Webp, sharedLink.key)
: 'feature-panel.png'
- }
+ },
+ user
};
} catch (e) {
throw error(404, {
diff --git a/web/src/routes/share/[key]/+page.svelte b/web/src/routes/share/[key]/+page.svelte
index d436e61b9..554216eff 100644
--- a/web/src/routes/share/[key]/+page.svelte
+++ b/web/src/routes/share/[key]/+page.svelte
@@ -1,6 +1,7 @@
-{#if album}
+{#if sharedLink.type == SharedLinkType.Album && album}
{/if}
+
+{#if sharedLink.type == SharedLinkType.Individual}
+
+
+
+{/if}