mirror of
https://github.com/immich-app/immich.git
synced 2026-05-28 02:22:34 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b15a90618 |
@@ -75,7 +75,7 @@ export class SearchService extends BaseService {
|
||||
|
||||
const page = dto.page ?? 1;
|
||||
const size = dto.size || 250;
|
||||
const userIds = await this.getUserIdsToSearch(auth, dto.visibility);
|
||||
const userIds = await this.getUserIdsToSearch(auth);
|
||||
const { hasNextPage, items } = await this.searchRepository.searchMetadata(
|
||||
{ page, size },
|
||||
{
|
||||
@@ -103,7 +103,7 @@ export class SearchService extends BaseService {
|
||||
requireElevatedPermission(auth);
|
||||
}
|
||||
|
||||
const userIds = await this.getUserIdsToSearch(auth, dto.visibility);
|
||||
const userIds = await this.getUserIdsToSearch(auth);
|
||||
const items = await this.searchRepository.searchRandom(dto.size || 250, { ...dto, userIds });
|
||||
return items.map((item) => mapAsset(item, { auth }));
|
||||
}
|
||||
@@ -113,7 +113,7 @@ export class SearchService extends BaseService {
|
||||
requireElevatedPermission(auth);
|
||||
}
|
||||
|
||||
const userIds = await this.getUserIdsToSearch(auth, dto.visibility);
|
||||
const userIds = await this.getUserIdsToSearch(auth);
|
||||
const items = await this.searchRepository.searchLargeAssets(dto.size || 250, { ...dto, userIds });
|
||||
return items.map((item) => mapAsset(item, { auth }));
|
||||
}
|
||||
@@ -128,7 +128,7 @@ export class SearchService extends BaseService {
|
||||
throw new BadRequestException('Smart search is not enabled');
|
||||
}
|
||||
|
||||
const userIds = this.getUserIdsToSearch(auth, dto.visibility);
|
||||
const userIds = this.getUserIdsToSearch(auth);
|
||||
let embedding;
|
||||
if (dto.query) {
|
||||
const key = machineLearning.clip.modelName + dto.query + dto.language;
|
||||
@@ -202,11 +202,7 @@ export class SearchService extends BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
private async getUserIdsToSearch(auth: AuthDto, visibility?: AssetVisibility): Promise<string[]> {
|
||||
// Locked assets are personal. Never include partner IDs, regardless of A's elevated session.
|
||||
if (visibility === AssetVisibility.Locked) {
|
||||
return [auth.user.id];
|
||||
}
|
||||
private async getUserIdsToSearch(auth: AuthDto): Promise<string[]> {
|
||||
const partnerIds = await getMyPartnerIds({
|
||||
userId: auth.user.id,
|
||||
repository: this.partnerRepository,
|
||||
|
||||
@@ -204,16 +204,5 @@ describe(TimelineService.name, () => {
|
||||
}),
|
||||
).rejects.toThrow(BadRequestException);
|
||||
});
|
||||
|
||||
it('should throw an error if withPartners is true and visibility is locked', async () => {
|
||||
await expect(
|
||||
sut.getTimeBucket(authStub.adminWithElevatedPermission, {
|
||||
timeBucket: 'bucket',
|
||||
visibility: AssetVisibility.Locked,
|
||||
withPartners: true,
|
||||
userId: authStub.adminWithElevatedPermission.user.id,
|
||||
}),
|
||||
).rejects.toThrow(BadRequestException);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -71,14 +71,13 @@ export class TimelineService extends BaseService {
|
||||
}
|
||||
|
||||
if (dto.withPartners) {
|
||||
const requestedLocked = dto.visibility === AssetVisibility.Locked;
|
||||
const requestedArchived = dto.visibility === AssetVisibility.Archive || dto.visibility === undefined;
|
||||
const requestedFavorite = dto.isFavorite === true || dto.isFavorite === false;
|
||||
const requestedTrash = dto.isTrashed === true;
|
||||
|
||||
if (requestedLocked || requestedArchived || requestedFavorite || requestedTrash) {
|
||||
if (requestedArchived || requestedFavorite || requestedTrash) {
|
||||
throw new BadRequestException(
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited, non-locked assets',
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited assets',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
-7
@@ -41,13 +41,6 @@ export const authStub = {
|
||||
id: 'token-id',
|
||||
} as AuthSession,
|
||||
}),
|
||||
adminWithElevatedPermission: Object.freeze<AuthDto>({
|
||||
user: authUser.admin,
|
||||
session: {
|
||||
id: 'token-id-elevated',
|
||||
hasElevatedPermission: true,
|
||||
} as AuthSession,
|
||||
}),
|
||||
adminSharedLink: Object.freeze({
|
||||
user: authUser.admin,
|
||||
sharedLink: {
|
||||
|
||||
@@ -51,13 +51,13 @@ describe(TimelineService.name, () => {
|
||||
const response1 = sut.getTimeBuckets(auth, { withPartners: true, visibility: AssetVisibility.Archive });
|
||||
await expect(response1).rejects.toBeInstanceOf(BadRequestException);
|
||||
await expect(response1).rejects.toThrow(
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited, non-locked assets',
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited assets',
|
||||
);
|
||||
|
||||
const response2 = sut.getTimeBuckets(auth, { withPartners: true });
|
||||
await expect(response2).rejects.toBeInstanceOf(BadRequestException);
|
||||
await expect(response2).rejects.toThrow(
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited, non-locked assets',
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited assets',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -67,13 +67,13 @@ describe(TimelineService.name, () => {
|
||||
const response1 = sut.getTimeBuckets(auth, { withPartners: true, isFavorite: false });
|
||||
await expect(response1).rejects.toBeInstanceOf(BadRequestException);
|
||||
await expect(response1).rejects.toThrow(
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited, non-locked assets',
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited assets',
|
||||
);
|
||||
|
||||
const response2 = sut.getTimeBuckets(auth, { withPartners: true, isFavorite: true });
|
||||
await expect(response2).rejects.toBeInstanceOf(BadRequestException);
|
||||
await expect(response2).rejects.toThrow(
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited, non-locked assets',
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited assets',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -83,7 +83,7 @@ describe(TimelineService.name, () => {
|
||||
const response = sut.getTimeBuckets(auth, { withPartners: true, isTrashed: true });
|
||||
await expect(response).rejects.toBeInstanceOf(BadRequestException);
|
||||
await expect(response).rejects.toThrow(
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited, non-locked assets',
|
||||
'withPartners is only supported for non-archived, non-trashed, non-favorited assets',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -67,3 +67,11 @@ export function calculateViewerAssetViewportProximity(
|
||||
timelineManager.visibleWindow.bottom + headerHeight,
|
||||
);
|
||||
}
|
||||
|
||||
export function calculateViewerAssetIsInOrNearViewport(
|
||||
timelineManager: TimelineManager,
|
||||
positionTop: number,
|
||||
positionHeight: number,
|
||||
) {
|
||||
return isInOrNearViewport(calculateViewerAssetViewportProximity(timelineManager, positionTop, positionHeight));
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ import type { AssetDescriptor, Direction, MoveAsset, TimelineAsset } from './typ
|
||||
import { ViewerAsset } from './viewer-asset.svelte';
|
||||
|
||||
export class TimelineMonth {
|
||||
#viewportProximity: ViewportProximity = $state(ViewportProximity.FarFromViewport);
|
||||
#isInOrNearViewport = $state(false);
|
||||
#isInViewport = $state(false);
|
||||
isLoaded: boolean = $state(false);
|
||||
timelineDays: TimelineDay[] = $state([]);
|
||||
readonly timelineManager: TimelineManager;
|
||||
@@ -85,24 +86,28 @@ export class TimelineMonth {
|
||||
}
|
||||
|
||||
set viewportProximity(newValue: ViewportProximity) {
|
||||
const old = this.#viewportProximity;
|
||||
if (old === newValue) {
|
||||
return;
|
||||
const isInOrNearViewport = isInOrNearViewportUtil(newValue);
|
||||
if (this.#isInOrNearViewport !== isInOrNearViewport) {
|
||||
this.#isInOrNearViewport = isInOrNearViewport;
|
||||
if (isInOrNearViewport) {
|
||||
void this.timelineManager.loadTimelineMonth(this.yearMonth);
|
||||
} else {
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
this.#viewportProximity = newValue;
|
||||
if (isInOrNearViewportUtil(newValue)) {
|
||||
void this.timelineManager.loadTimelineMonth(this.yearMonth);
|
||||
} else {
|
||||
this.cancel();
|
||||
|
||||
const isInViewport = isInViewportUtil(newValue);
|
||||
if (this.#isInViewport !== isInViewport) {
|
||||
this.#isInViewport = isInViewport;
|
||||
}
|
||||
}
|
||||
|
||||
get isInOrNearViewport() {
|
||||
return isInOrNearViewportUtil(this.#viewportProximity);
|
||||
return this.#isInOrNearViewport;
|
||||
}
|
||||
|
||||
get isInViewport() {
|
||||
return isInViewportUtil(this.#viewportProximity);
|
||||
return this.#isInViewport;
|
||||
}
|
||||
|
||||
get lastTimelineDay() {
|
||||
|
||||
@@ -1,28 +1,24 @@
|
||||
import type { CommonPosition } from '$lib/utils/layout-utils';
|
||||
import {
|
||||
ViewportProximity,
|
||||
calculateViewerAssetViewportProximity,
|
||||
isInOrNearViewport,
|
||||
} from './internal/intersection-support.svelte';
|
||||
import { calculateViewerAssetIsInOrNearViewport } from './internal/intersection-support.svelte';
|
||||
import type { TimelineDay } from './timeline-day.svelte';
|
||||
import type { TimelineAsset } from './types';
|
||||
|
||||
export class ViewerAsset {
|
||||
readonly #group: TimelineDay;
|
||||
|
||||
#viewportProximity = $derived.by(() => {
|
||||
#isInOrNearViewport = $derived.by(() => {
|
||||
if (!this.position) {
|
||||
return ViewportProximity.FarFromViewport;
|
||||
return false;
|
||||
}
|
||||
|
||||
const store = this.#group.timelineMonth.timelineManager;
|
||||
const positionTop = this.#group.absoluteTimelineDayTop + this.position.top;
|
||||
|
||||
return calculateViewerAssetViewportProximity(store, positionTop, this.position.height);
|
||||
return calculateViewerAssetIsInOrNearViewport(store, positionTop, this.position.height);
|
||||
});
|
||||
|
||||
get isInOrNearViewport() {
|
||||
return isInOrNearViewport(this.#viewportProximity);
|
||||
return this.#isInOrNearViewport;
|
||||
}
|
||||
|
||||
position: CommonPosition | undefined = $state.raw();
|
||||
|
||||
Reference in New Issue
Block a user