diff --git a/mobile/openapi/doc/AssetApi.md b/mobile/openapi/doc/AssetApi.md index a7ea1c07c79a6..1aec7c0adda96 100644 --- a/mobile/openapi/doc/AssetApi.md +++ b/mobile/openapi/doc/AssetApi.md @@ -659,7 +659,7 @@ This endpoint does not need any parameter. [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) # **getMapMarkers** -> List getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite) +> List getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners) @@ -686,9 +686,10 @@ final fileCreatedAfter = 2013-10-20T19:20:30+01:00; // DateTime | final fileCreatedBefore = 2013-10-20T19:20:30+01:00; // DateTime | final isArchived = true; // bool | final isFavorite = true; // bool | +final withPartners = true; // bool | try { - final result = api_instance.getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite); + final result = api_instance.getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners); print(result); } catch (e) { print('Exception when calling AssetApi->getMapMarkers: $e\n'); @@ -703,6 +704,7 @@ Name | Type | Description | Notes **fileCreatedBefore** | **DateTime**| | [optional] **isArchived** | **bool**| | [optional] **isFavorite** | **bool**| | [optional] + **withPartners** | **bool**| | [optional] ### Return type diff --git a/mobile/openapi/lib/api/asset_api.dart b/mobile/openapi/lib/api/asset_api.dart index 7f4528c12f048..295e12a1d2a32 100644 --- a/mobile/openapi/lib/api/asset_api.dart +++ b/mobile/openapi/lib/api/asset_api.dart @@ -652,7 +652,9 @@ class AssetApi { /// * [bool] isArchived: /// /// * [bool] isFavorite: - Future getMapMarkersWithHttpInfo({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, }) async { + /// + /// * [bool] withPartners: + Future getMapMarkersWithHttpInfo({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, }) async { // ignore: prefer_const_declarations final path = r'/asset/map-marker'; @@ -675,6 +677,9 @@ class AssetApi { if (isFavorite != null) { queryParams.addAll(_queryParams('', 'isFavorite', isFavorite)); } + if (withPartners != null) { + queryParams.addAll(_queryParams('', 'withPartners', withPartners)); + } const contentTypes = []; @@ -699,8 +704,10 @@ class AssetApi { /// * [bool] isArchived: /// /// * [bool] isFavorite: - Future?> getMapMarkers({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, }) async { - final response = await getMapMarkersWithHttpInfo( fileCreatedAfter: fileCreatedAfter, fileCreatedBefore: fileCreatedBefore, isArchived: isArchived, isFavorite: isFavorite, ); + /// + /// * [bool] withPartners: + Future?> getMapMarkers({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, }) async { + final response = await getMapMarkersWithHttpInfo( fileCreatedAfter: fileCreatedAfter, fileCreatedBefore: fileCreatedBefore, isArchived: isArchived, isFavorite: isFavorite, withPartners: withPartners, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/test/asset_api_test.dart b/mobile/openapi/test/asset_api_test.dart index c34c85466c999..8ae9d4c955a50 100644 --- a/mobile/openapi/test/asset_api_test.dart +++ b/mobile/openapi/test/asset_api_test.dart @@ -80,7 +80,7 @@ void main() { // TODO }); - //Future> getMapMarkers({ DateTime fileCreatedAfter, DateTime fileCreatedBefore, bool isArchived, bool isFavorite }) async + //Future> getMapMarkers({ DateTime fileCreatedAfter, DateTime fileCreatedBefore, bool isArchived, bool isFavorite, bool withPartners }) async test('test getMapMarkers', () async { // TODO }); diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 4c6317c2c2dcb..4d31bd45f1797 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -1397,6 +1397,14 @@ "schema": { "type": "boolean" } + }, + { + "name": "withPartners", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } } ], "responses": { diff --git a/open-api/typescript-sdk/axios-client/api.ts b/open-api/typescript-sdk/axios-client/api.ts index 542fa0580ea98..2c2e3af55ae68 100644 --- a/open-api/typescript-sdk/axios-client/api.ts +++ b/open-api/typescript-sdk/axios-client/api.ts @@ -7340,10 +7340,11 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration * @param {string} [fileCreatedBefore] * @param {boolean} [isArchived] * @param {boolean} [isFavorite] + * @param {boolean} [withPartners] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - getMapMarkers: async (fileCreatedAfter?: string, fileCreatedBefore?: string, isArchived?: boolean, isFavorite?: boolean, options: RawAxiosRequestConfig = {}): Promise => { + getMapMarkers: async (fileCreatedAfter?: string, fileCreatedBefore?: string, isArchived?: boolean, isFavorite?: boolean, withPartners?: boolean, options: RawAxiosRequestConfig = {}): Promise => { const localVarPath = `/asset/map-marker`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -7385,6 +7386,10 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration localVarQueryParameter['isFavorite'] = isFavorite; } + if (withPartners !== undefined) { + localVarQueryParameter['withPartners'] = withPartners; + } + setSearchParams(localVarUrlObj, localVarQueryParameter); @@ -8458,11 +8463,12 @@ export const AssetApiFp = function(configuration?: Configuration) { * @param {string} [fileCreatedBefore] * @param {boolean} [isArchived] * @param {boolean} [isFavorite] + * @param {boolean} [withPartners] * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async getMapMarkers(fileCreatedAfter?: string, fileCreatedBefore?: string, isArchived?: boolean, isFavorite?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { - const localVarAxiosArgs = await localVarAxiosParamCreator.getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, options); + async getMapMarkers(fileCreatedAfter?: string, fileCreatedBefore?: string, isArchived?: boolean, isFavorite?: boolean, withPartners?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise>> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners, options); const index = configuration?.serverIndex ?? 0; const operationBasePath = operationServerMap['AssetApi.getMapMarkers']?.[index]?.url; return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); @@ -8790,7 +8796,7 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath * @throws {RequiredError} */ getMapMarkers(requestParameters: AssetApiGetMapMarkersRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise> { - return localVarFp.getMapMarkers(requestParameters.fileCreatedAfter, requestParameters.fileCreatedBefore, requestParameters.isArchived, requestParameters.isFavorite, options).then((request) => request(axios, basePath)); + return localVarFp.getMapMarkers(requestParameters.fileCreatedAfter, requestParameters.fileCreatedBefore, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.withPartners, options).then((request) => request(axios, basePath)); }, /** * @@ -9123,6 +9129,13 @@ export interface AssetApiGetMapMarkersRequest { * @memberof AssetApiGetMapMarkers */ readonly isFavorite?: boolean + + /** + * + * @type {boolean} + * @memberof AssetApiGetMapMarkers + */ + readonly withPartners?: boolean } /** @@ -9958,7 +9971,7 @@ export class AssetApi extends BaseAPI { * @memberof AssetApi */ public getMapMarkers(requestParameters: AssetApiGetMapMarkersRequest = {}, options?: RawAxiosRequestConfig) { - return AssetApiFp(this.configuration).getMapMarkers(requestParameters.fileCreatedAfter, requestParameters.fileCreatedBefore, requestParameters.isArchived, requestParameters.isFavorite, options).then((request) => request(this.axios, this.basePath)); + return AssetApiFp(this.configuration).getMapMarkers(requestParameters.fileCreatedAfter, requestParameters.fileCreatedBefore, requestParameters.isArchived, requestParameters.isFavorite, requestParameters.withPartners, options).then((request) => request(this.axios, this.basePath)); } /** diff --git a/open-api/typescript-sdk/fetch-client.ts b/open-api/typescript-sdk/fetch-client.ts index cb2c42f5dd871..35e152350984e 100644 --- a/open-api/typescript-sdk/fetch-client.ts +++ b/open-api/typescript-sdk/fetch-client.ts @@ -4,8 +4,8 @@ * DO NOT MODIFY - This file has been generated using oazapfts. * See https://www.npmjs.com/package/oazapfts */ -import * as Oazapfts from "oazapfts/lib/runtime"; -import * as QS from "oazapfts/lib/runtime/query"; +import * as Oazapfts from "@oazapfts/runtime"; +import * as QS from "@oazapfts/runtime/query"; export const defaults: Oazapfts.Defaults = { headers: {}, baseUrl: "/api", @@ -1266,11 +1266,12 @@ export function runAssetJobs({ assetJobsDto }: { body: assetJobsDto }))); } -export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite }: { +export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners }: { fileCreatedAfter?: string; fileCreatedBefore?: string; isArchived?: boolean; isFavorite?: boolean; + withPartners?: boolean; }, opts?: Oazapfts.RequestOpts) { return oazapfts.ok(oazapfts.fetchJson<{ status: 200; @@ -1279,7 +1280,8 @@ export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived, fileCreatedAfter, fileCreatedBefore, isArchived, - isFavorite + isFavorite, + withPartners }))}`, { ...opts })); diff --git a/server/src/domain/asset/asset.service.spec.ts b/server/src/domain/asset/asset.service.spec.ts index a6b2cde3e88eb..d8f24dec674be 100644 --- a/server/src/domain/asset/asset.service.spec.ts +++ b/server/src/domain/asset/asset.service.spec.ts @@ -286,6 +286,7 @@ describe(AssetService.name, () => { describe('getMapMarkers', () => { it('should get geo information of assets', async () => { + partnerMock.getAll.mockResolvedValue([]); assetMock.getMapMarkers.mockResolvedValue( [assetStub.withLocation].map((asset) => ({ id: asset.id, diff --git a/server/src/domain/asset/asset.service.ts b/server/src/domain/asset/asset.service.ts index e73858c31155b..33a00bb67a66f 100644 --- a/server/src/domain/asset/asset.service.ts +++ b/server/src/domain/asset/asset.service.ts @@ -187,8 +187,16 @@ export class AssetService { return folder; } - getMapMarkers(auth: AuthDto, options: MapMarkerDto): Promise { - return this.assetRepository.getMapMarkers(auth.user.id, options); + async getMapMarkers(auth: AuthDto, options: MapMarkerDto): Promise { + const userIds: string[] = [auth.user.id]; + if (options.withPartners) { + const partners = await this.partnerRepository.getAll(auth.user.id); + const partnersIds = partners + .filter((partner) => partner.sharedBy && partner.sharedWith && partner.sharedById != auth.user.id) + .map((partner) => partner.sharedById); + userIds.push(...partnersIds); + } + return this.assetRepository.getMapMarkers(userIds, options); } async getMemoryLane(auth: AuthDto, dto: MemoryLaneDto): Promise { diff --git a/server/src/domain/asset/dto/map-marker.dto.ts b/server/src/domain/asset/dto/map-marker.dto.ts index 79bb9fa385257..b703d6e73e297 100644 --- a/server/src/domain/asset/dto/map-marker.dto.ts +++ b/server/src/domain/asset/dto/map-marker.dto.ts @@ -25,4 +25,10 @@ export class MapMarkerDto { @IsDate() @Type(() => Date) fileCreatedBefore?: Date; + + @ApiProperty() + @Optional() + @IsBoolean() + @Transform(toBoolean) + withPartners?: boolean; } diff --git a/server/src/domain/repositories/asset.repository.ts b/server/src/domain/repositories/asset.repository.ts index 00a74f8293ad6..84a917932b7c8 100644 --- a/server/src/domain/repositories/asset.repository.ts +++ b/server/src/domain/repositories/asset.repository.ts @@ -198,7 +198,7 @@ export interface IAssetRepository { softDeleteAll(ids: string[]): Promise; restoreAll(ids: string[]): Promise; findLivePhotoMatch(options: LivePhotoSearchOptions): Promise; - getMapMarkers(ownerId: string, options?: MapMarkerSearchOptions): Promise; + getMapMarkers(ownerIds: string[], options?: MapMarkerSearchOptions): Promise; getStatistics(ownerId: string, options: AssetStatsOptions): Promise; getTimeBuckets(options: TimeBucketOptions): Promise; getTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise; diff --git a/server/src/infra/repositories/asset.repository.ts b/server/src/infra/repositories/asset.repository.ts index 95a227b693010..675c658678b73 100644 --- a/server/src/infra/repositories/asset.repository.ts +++ b/server/src/infra/repositories/asset.repository.ts @@ -633,7 +633,7 @@ export class AssetRepository implements IAssetRepository { }); } - async getMapMarkers(ownerId: string, options: MapMarkerSearchOptions = {}): Promise { + async getMapMarkers(ownerIds: string[], options: MapMarkerSearchOptions = {}): Promise { const { isArchived, isFavorite, fileCreatedAfter, fileCreatedBefore } = options; const assets = await this.repository.find({ @@ -645,7 +645,7 @@ export class AssetRepository implements IAssetRepository { }, }, where: { - ownerId, + ownerId: In([...ownerIds]), isVisible: true, isArchived, exifInfo: { diff --git a/web/src/lib/components/map-page/map-settings-modal.svelte b/web/src/lib/components/map-page/map-settings-modal.svelte index c2d8a5f6553d6..d6cbe5884f593 100644 --- a/web/src/lib/components/map-page/map-settings-modal.svelte +++ b/web/src/lib/components/map-page/map-settings-modal.svelte @@ -33,6 +33,7 @@ + {#if customDateRange}
diff --git a/web/src/lib/stores/preferences.store.ts b/web/src/lib/stores/preferences.store.ts index 09154f5b12257..7fe1f5e152e65 100644 --- a/web/src/lib/stores/preferences.store.ts +++ b/web/src/lib/stores/preferences.store.ts @@ -46,6 +46,7 @@ export interface MapSettings { allowDarkMode: boolean; includeArchived: boolean; onlyFavorites: boolean; + withPartners: boolean; relativeDate: string; dateAfter: string; dateBefore: string; @@ -55,6 +56,7 @@ export const mapSettings = persisted('map-settings', { allowDarkMode: true, includeArchived: false, onlyFavorites: false, + withPartners: false, relativeDate: '', dateAfter: '', dateBefore: '', diff --git a/web/src/routes/(user)/map/+page.svelte b/web/src/routes/(user)/map/+page.svelte index 3a5b53117c894..32af7b9f1ac28 100644 --- a/web/src/routes/(user)/map/+page.svelte +++ b/web/src/routes/(user)/map/+page.svelte @@ -42,7 +42,7 @@ } abortController = new AbortController(); - const { includeArchived, onlyFavorites } = $mapSettings; + const { includeArchived, onlyFavorites, withPartners } = $mapSettings; const { fileCreatedAfter, fileCreatedBefore } = getFileCreatedDates(); const { data } = await api.assetApi.getMapMarkers( @@ -51,6 +51,7 @@ isFavorite: onlyFavorites || undefined, fileCreatedAfter: fileCreatedAfter || undefined, fileCreatedBefore, + withPartners: withPartners || undefined, }, { signal: abortController.signal,