1
0
mirror of https://github.com/immich-app/immich.git synced 2025-04-23 13:09:00 +02:00

feat(server, web): Include partner's photos on map (#7065)

* feat(server): Include partner's photos on map - if included in timeline

* depend on query parameter withPartners

instead of partners.inTimeline

* web: map option to include partners images

* make open-api
This commit is contained in:
Torbjorn Tyridal 2024-02-14 16:07:00 +01:00 committed by GitHub
parent 7d59900662
commit 6adff50f0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 70 additions and 19 deletions

View File

@ -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) [[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** # **getMapMarkers**
> List<MapMarkerResponseDto> getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite) > List<MapMarkerResponseDto> 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 fileCreatedBefore = 2013-10-20T19:20:30+01:00; // DateTime |
final isArchived = true; // bool | final isArchived = true; // bool |
final isFavorite = true; // bool | final isFavorite = true; // bool |
final withPartners = true; // bool |
try { try {
final result = api_instance.getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite); final result = api_instance.getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners);
print(result); print(result);
} catch (e) { } catch (e) {
print('Exception when calling AssetApi->getMapMarkers: $e\n'); print('Exception when calling AssetApi->getMapMarkers: $e\n');
@ -703,6 +704,7 @@ Name | Type | Description | Notes
**fileCreatedBefore** | **DateTime**| | [optional] **fileCreatedBefore** | **DateTime**| | [optional]
**isArchived** | **bool**| | [optional] **isArchived** | **bool**| | [optional]
**isFavorite** | **bool**| | [optional] **isFavorite** | **bool**| | [optional]
**withPartners** | **bool**| | [optional]
### Return type ### Return type

View File

@ -652,7 +652,9 @@ class AssetApi {
/// * [bool] isArchived: /// * [bool] isArchived:
/// ///
/// * [bool] isFavorite: /// * [bool] isFavorite:
Future<Response> getMapMarkersWithHttpInfo({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, }) async { ///
/// * [bool] withPartners:
Future<Response> getMapMarkersWithHttpInfo({ DateTime? fileCreatedAfter, DateTime? fileCreatedBefore, bool? isArchived, bool? isFavorite, bool? withPartners, }) async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/asset/map-marker'; final path = r'/asset/map-marker';
@ -675,6 +677,9 @@ class AssetApi {
if (isFavorite != null) { if (isFavorite != null) {
queryParams.addAll(_queryParams('', 'isFavorite', isFavorite)); queryParams.addAll(_queryParams('', 'isFavorite', isFavorite));
} }
if (withPartners != null) {
queryParams.addAll(_queryParams('', 'withPartners', withPartners));
}
const contentTypes = <String>[]; const contentTypes = <String>[];
@ -699,8 +704,10 @@ class AssetApi {
/// * [bool] isArchived: /// * [bool] isArchived:
/// ///
/// * [bool] isFavorite: /// * [bool] isFavorite:
Future<List<MapMarkerResponseDto>?> 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<List<MapMarkerResponseDto>?> 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) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
} }

View File

@ -80,7 +80,7 @@ void main() {
// TODO // TODO
}); });
//Future<List<MapMarkerResponseDto>> getMapMarkers({ DateTime fileCreatedAfter, DateTime fileCreatedBefore, bool isArchived, bool isFavorite }) async //Future<List<MapMarkerResponseDto>> getMapMarkers({ DateTime fileCreatedAfter, DateTime fileCreatedBefore, bool isArchived, bool isFavorite, bool withPartners }) async
test('test getMapMarkers', () async { test('test getMapMarkers', () async {
// TODO // TODO
}); });

View File

@ -1397,6 +1397,14 @@
"schema": { "schema": {
"type": "boolean" "type": "boolean"
} }
},
{
"name": "withPartners",
"required": false,
"in": "query",
"schema": {
"type": "boolean"
}
} }
], ],
"responses": { "responses": {

View File

@ -7363,10 +7363,11 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
* @param {string} [fileCreatedBefore] * @param {string} [fileCreatedBefore]
* @param {boolean} [isArchived] * @param {boolean} [isArchived]
* @param {boolean} [isFavorite] * @param {boolean} [isFavorite]
* @param {boolean} [withPartners]
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
getMapMarkers: async (fileCreatedAfter?: string, fileCreatedBefore?: string, isArchived?: boolean, isFavorite?: boolean, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => { getMapMarkers: async (fileCreatedAfter?: string, fileCreatedBefore?: string, isArchived?: boolean, isFavorite?: boolean, withPartners?: boolean, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/asset/map-marker`; const localVarPath = `/asset/map-marker`;
// use dummy base URL string because the URL constructor only accepts absolute URLs. // use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
@ -7408,6 +7409,10 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
localVarQueryParameter['isFavorite'] = isFavorite; localVarQueryParameter['isFavorite'] = isFavorite;
} }
if (withPartners !== undefined) {
localVarQueryParameter['withPartners'] = withPartners;
}
setSearchParams(localVarUrlObj, localVarQueryParameter); setSearchParams(localVarUrlObj, localVarQueryParameter);
@ -8487,11 +8492,12 @@ export const AssetApiFp = function(configuration?: Configuration) {
* @param {string} [fileCreatedBefore] * @param {string} [fileCreatedBefore]
* @param {boolean} [isArchived] * @param {boolean} [isArchived]
* @param {boolean} [isFavorite] * @param {boolean} [isFavorite]
* @param {boolean} [withPartners]
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
async getMapMarkers(fileCreatedAfter?: string, fileCreatedBefore?: string, isArchived?: boolean, isFavorite?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<MapMarkerResponseDto>>> { async getMapMarkers(fileCreatedAfter?: string, fileCreatedBefore?: string, isArchived?: boolean, isFavorite?: boolean, withPartners?: boolean, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<MapMarkerResponseDto>>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, options); const localVarAxiosArgs = await localVarAxiosParamCreator.getMapMarkers(fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners, options);
const index = configuration?.serverIndex ?? 0; const index = configuration?.serverIndex ?? 0;
const operationBasePath = operationServerMap['AssetApi.getMapMarkers']?.[index]?.url; const operationBasePath = operationServerMap['AssetApi.getMapMarkers']?.[index]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath); return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, operationBasePath || basePath);
@ -8821,7 +8827,7 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
* @throws {RequiredError} * @throws {RequiredError}
*/ */
getMapMarkers(requestParameters: AssetApiGetMapMarkersRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise<Array<MapMarkerResponseDto>> { getMapMarkers(requestParameters: AssetApiGetMapMarkersRequest = {}, options?: RawAxiosRequestConfig): AxiosPromise<Array<MapMarkerResponseDto>> {
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));
}, },
/** /**
* *
@ -9155,6 +9161,13 @@ export interface AssetApiGetMapMarkersRequest {
* @memberof AssetApiGetMapMarkers * @memberof AssetApiGetMapMarkers
*/ */
readonly isFavorite?: boolean readonly isFavorite?: boolean
/**
*
* @type {boolean}
* @memberof AssetApiGetMapMarkers
*/
readonly withPartners?: boolean
} }
/** /**
@ -9997,7 +10010,7 @@ export class AssetApi extends BaseAPI {
* @memberof AssetApi * @memberof AssetApi
*/ */
public getMapMarkers(requestParameters: AssetApiGetMapMarkersRequest = {}, options?: RawAxiosRequestConfig) { 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));
} }
/** /**

View File

@ -1240,11 +1240,12 @@ export function runAssetJobs({ assetJobsDto }: {
body: assetJobsDto body: assetJobsDto
}))); })));
} }
export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite }: { export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived, isFavorite, withPartners }: {
fileCreatedAfter?: string; fileCreatedAfter?: string;
fileCreatedBefore?: string; fileCreatedBefore?: string;
isArchived?: boolean; isArchived?: boolean;
isFavorite?: boolean; isFavorite?: boolean;
withPartners?: boolean;
}, opts?: Oazapfts.RequestOpts) { }, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{ return oazapfts.ok(oazapfts.fetchJson<{
status: 200; status: 200;
@ -1253,7 +1254,8 @@ export function getMapMarkers({ fileCreatedAfter, fileCreatedBefore, isArchived,
fileCreatedAfter, fileCreatedAfter,
fileCreatedBefore, fileCreatedBefore,
isArchived, isArchived,
isFavorite isFavorite,
withPartners
}))}`, { }))}`, {
...opts ...opts
})); }));

View File

@ -286,6 +286,7 @@ describe(AssetService.name, () => {
describe('getMapMarkers', () => { describe('getMapMarkers', () => {
it('should get geo information of assets', async () => { it('should get geo information of assets', async () => {
partnerMock.getAll.mockResolvedValue([]);
assetMock.getMapMarkers.mockResolvedValue( assetMock.getMapMarkers.mockResolvedValue(
[assetStub.withLocation].map((asset) => ({ [assetStub.withLocation].map((asset) => ({
id: asset.id, id: asset.id,

View File

@ -157,8 +157,16 @@ export class AssetService {
return folder; return folder;
} }
getMapMarkers(auth: AuthDto, options: MapMarkerDto): Promise<MapMarkerResponseDto[]> { async getMapMarkers(auth: AuthDto, options: MapMarkerDto): Promise<MapMarkerResponseDto[]> {
return this.assetRepository.getMapMarkers(auth.user.id, options); 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<MemoryLaneResponseDto[]> { async getMemoryLane(auth: AuthDto, dto: MemoryLaneDto): Promise<MemoryLaneResponseDto[]> {

View File

@ -25,4 +25,10 @@ export class MapMarkerDto {
@IsDate() @IsDate()
@Type(() => Date) @Type(() => Date)
fileCreatedBefore?: Date; fileCreatedBefore?: Date;
@ApiProperty()
@Optional()
@IsBoolean()
@Transform(toBoolean)
withPartners?: boolean;
} }

View File

@ -140,7 +140,7 @@ export interface IAssetRepository {
softDeleteAll(ids: string[]): Promise<void>; softDeleteAll(ids: string[]): Promise<void>;
restoreAll(ids: string[]): Promise<void>; restoreAll(ids: string[]): Promise<void>;
findLivePhotoMatch(options: LivePhotoSearchOptions): Promise<AssetEntity | null>; findLivePhotoMatch(options: LivePhotoSearchOptions): Promise<AssetEntity | null>;
getMapMarkers(ownerId: string, options?: MapMarkerSearchOptions): Promise<MapMarker[]>; getMapMarkers(ownerIds: string[], options?: MapMarkerSearchOptions): Promise<MapMarker[]>;
getStatistics(ownerId: string, options: AssetStatsOptions): Promise<AssetStats>; getStatistics(ownerId: string, options: AssetStatsOptions): Promise<AssetStats>;
getTimeBuckets(options: TimeBucketOptions): Promise<TimeBucketItem[]>; getTimeBuckets(options: TimeBucketOptions): Promise<TimeBucketItem[]>;
getTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise<AssetEntity[]>; getTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise<AssetEntity[]>;

View File

@ -472,7 +472,7 @@ export class AssetRepository implements IAssetRepository {
}); });
} }
async getMapMarkers(ownerId: string, options: MapMarkerSearchOptions = {}): Promise<MapMarker[]> { async getMapMarkers(ownerIds: string[], options: MapMarkerSearchOptions = {}): Promise<MapMarker[]> {
const { isArchived, isFavorite, fileCreatedAfter, fileCreatedBefore } = options; const { isArchived, isFavorite, fileCreatedAfter, fileCreatedBefore } = options;
const assets = await this.repository.find({ const assets = await this.repository.find({
@ -484,7 +484,7 @@ export class AssetRepository implements IAssetRepository {
}, },
}, },
where: { where: {
ownerId, ownerId: In([...ownerIds]),
isVisible: true, isVisible: true,
isArchived, isArchived,
exifInfo: { exifInfo: {

View File

@ -33,6 +33,7 @@
<SettingSwitch title="Allow dark mode" bind:checked={settings.allowDarkMode} /> <SettingSwitch title="Allow dark mode" bind:checked={settings.allowDarkMode} />
<SettingSwitch title="Only favorites" bind:checked={settings.onlyFavorites} /> <SettingSwitch title="Only favorites" bind:checked={settings.onlyFavorites} />
<SettingSwitch title="Include archived" bind:checked={settings.includeArchived} /> <SettingSwitch title="Include archived" bind:checked={settings.includeArchived} />
<SettingSwitch title="Include shared with me" bind:checked={settings.withPartners} />
{#if customDateRange} {#if customDateRange}
<div in:fly={{ y: 10, duration: 200 }} class="flex flex-col gap-4"> <div in:fly={{ y: 10, duration: 200 }} class="flex flex-col gap-4">
<div class="flex items-center justify-between gap-8"> <div class="flex items-center justify-between gap-8">

View File

@ -46,6 +46,7 @@ export interface MapSettings {
allowDarkMode: boolean; allowDarkMode: boolean;
includeArchived: boolean; includeArchived: boolean;
onlyFavorites: boolean; onlyFavorites: boolean;
withPartners: boolean;
relativeDate: string; relativeDate: string;
dateAfter: string; dateAfter: string;
dateBefore: string; dateBefore: string;
@ -55,6 +56,7 @@ export const mapSettings = persisted<MapSettings>('map-settings', {
allowDarkMode: true, allowDarkMode: true,
includeArchived: false, includeArchived: false,
onlyFavorites: false, onlyFavorites: false,
withPartners: false,
relativeDate: '', relativeDate: '',
dateAfter: '', dateAfter: '',
dateBefore: '', dateBefore: '',

View File

@ -46,7 +46,7 @@
} }
abortController = new AbortController(); abortController = new AbortController();
const { includeArchived, onlyFavorites } = $mapSettings; const { includeArchived, onlyFavorites, withPartners } = $mapSettings;
const { fileCreatedAfter, fileCreatedBefore } = getFileCreatedDates(); const { fileCreatedAfter, fileCreatedBefore } = getFileCreatedDates();
return await getMapMarkers( return await getMapMarkers(
@ -55,6 +55,7 @@
isFavorite: onlyFavorites || undefined, isFavorite: onlyFavorites || undefined,
fileCreatedAfter: fileCreatedAfter || undefined, fileCreatedAfter: fileCreatedAfter || undefined,
fileCreatedBefore, fileCreatedBefore,
withPartners: withPartners || undefined,
}, },
{ {
signal: abortController.signal, signal: abortController.signal,