mirror of
https://github.com/immich-app/immich.git
synced 2025-06-23 07:20:50 -04:00
refactor: memory stub (#16704)
This commit is contained in:
parent
b0bf4e4fff
commit
ce74f765b1
@ -1,5 +1,5 @@
|
|||||||
import { sql } from 'kysely';
|
import { sql } from 'kysely';
|
||||||
import { Permission } from 'src/enum';
|
import { AssetStatus, AssetType, Permission } from 'src/enum';
|
||||||
|
|
||||||
export type AuthUser = {
|
export type AuthUser = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -23,6 +23,38 @@ export type User = {
|
|||||||
profileChangedAt: Date;
|
profileChangedAt: Date;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Asset = {
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
deletedAt: Date | null;
|
||||||
|
id: string;
|
||||||
|
updateId: string;
|
||||||
|
status: AssetStatus;
|
||||||
|
checksum: Buffer<ArrayBufferLike>;
|
||||||
|
deviceAssetId: string;
|
||||||
|
deviceId: string;
|
||||||
|
duplicateId: string | null;
|
||||||
|
duration: string | null;
|
||||||
|
encodedVideoPath: string | null;
|
||||||
|
fileCreatedAt: Date | null;
|
||||||
|
fileModifiedAt: Date | null;
|
||||||
|
isArchived: boolean;
|
||||||
|
isExternal: boolean;
|
||||||
|
isFavorite: boolean;
|
||||||
|
isOffline: boolean;
|
||||||
|
isVisible: boolean;
|
||||||
|
libraryId: string | null;
|
||||||
|
livePhotoVideoId: string | null;
|
||||||
|
localDateTime: Date | null;
|
||||||
|
originalFileName: string;
|
||||||
|
originalPath: string;
|
||||||
|
ownerId: string;
|
||||||
|
sidecarPath: string | null;
|
||||||
|
stackId: string | null;
|
||||||
|
thumbhash: Buffer<ArrayBufferLike> | null;
|
||||||
|
type: AssetType;
|
||||||
|
};
|
||||||
|
|
||||||
export type AuthSharedLink = {
|
export type AuthSharedLink = {
|
||||||
id: string;
|
id: string;
|
||||||
expiresAt: Date | null;
|
expiresAt: Date | null;
|
||||||
|
7
server/src/db.d.ts
vendored
7
server/src/db.d.ts
vendored
@ -4,7 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { ColumnType } from 'kysely';
|
import type { ColumnType } from 'kysely';
|
||||||
import { AssetType, Permission, SyncEntityType } from 'src/enum';
|
import { OnThisDayData } from 'src/entities/memory.entity';
|
||||||
|
import { AssetType, MemoryType, Permission, SyncEntityType } from 'src/enum';
|
||||||
|
|
||||||
export type ArrayType<T> = ArrayTypeImpl<T> extends (infer U)[] ? U[] : ArrayTypeImpl<T>;
|
export type ArrayType<T> = ArrayTypeImpl<T> extends (infer U)[] ? U[] : ArrayTypeImpl<T>;
|
||||||
|
|
||||||
@ -231,7 +232,7 @@ export interface Libraries {
|
|||||||
|
|
||||||
export interface Memories {
|
export interface Memories {
|
||||||
createdAt: Generated<Timestamp>;
|
createdAt: Generated<Timestamp>;
|
||||||
data: Json;
|
data: OnThisDayData;
|
||||||
deletedAt: Timestamp | null;
|
deletedAt: Timestamp | null;
|
||||||
hideAt: Timestamp | null;
|
hideAt: Timestamp | null;
|
||||||
id: Generated<string>;
|
id: Generated<string>;
|
||||||
@ -240,7 +241,7 @@ export interface Memories {
|
|||||||
ownerId: string;
|
ownerId: string;
|
||||||
seenAt: Timestamp | null;
|
seenAt: Timestamp | null;
|
||||||
showAt: Timestamp | null;
|
showAt: Timestamp | null;
|
||||||
type: string;
|
type: MemoryType;
|
||||||
updatedAt: Generated<Timestamp>;
|
updatedAt: Generated<Timestamp>;
|
||||||
updateId: Generated<string>;
|
updateId: Generated<string>;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import { BadRequestException } from '@nestjs/common';
|
import { BadRequestException } from '@nestjs/common';
|
||||||
import { MemoryType } from 'src/enum';
|
|
||||||
import { MemoryService } from 'src/services/memory.service';
|
import { MemoryService } from 'src/services/memory.service';
|
||||||
import { authStub } from 'test/fixtures/auth.stub';
|
import { factory, newUuid, newUuids } from 'test/small.factory';
|
||||||
import { memoryStub } from 'test/fixtures/memory.stub';
|
|
||||||
import { userStub } from 'test/fixtures/user.stub';
|
|
||||||
import { newTestService, ServiceMocks } from 'test/utils';
|
import { newTestService, ServiceMocks } from 'test/utils';
|
||||||
|
|
||||||
describe(MemoryService.name, () => {
|
describe(MemoryService.name, () => {
|
||||||
@ -20,174 +17,227 @@ describe(MemoryService.name, () => {
|
|||||||
|
|
||||||
describe('search', () => {
|
describe('search', () => {
|
||||||
it('should search memories', async () => {
|
it('should search memories', async () => {
|
||||||
mocks.memory.search.mockResolvedValue([memoryStub.memory1, memoryStub.empty]);
|
const [userId] = newUuids();
|
||||||
await expect(sut.search(authStub.admin, {})).resolves.toEqual(
|
const asset = factory.asset();
|
||||||
|
const memory1 = factory.memory({ ownerId: userId, assets: [asset] });
|
||||||
|
const memory2 = factory.memory({ ownerId: userId });
|
||||||
|
|
||||||
|
mocks.memory.search.mockResolvedValue([memory1, memory2]);
|
||||||
|
|
||||||
|
await expect(sut.search(factory.auth({ id: userId }), {})).resolves.toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({ id: 'memory1', assets: expect.any(Array) }),
|
expect.objectContaining({ id: memory1.id, assets: [expect.objectContaining({ id: asset.id })] }),
|
||||||
expect.objectContaining({ id: 'memoryEmpty', assets: [] }),
|
expect.objectContaining({ id: memory2.id, assets: [] }),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should map ', async () => {
|
it('should map ', async () => {
|
||||||
await expect(sut.search(authStub.admin, {})).resolves.toEqual([]);
|
await expect(sut.search(factory.auth(), {})).resolves.toEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('get', () => {
|
describe('get', () => {
|
||||||
it('should throw an error when no access', async () => {
|
it('should throw an error when no access', async () => {
|
||||||
await expect(sut.get(authStub.admin, 'not-found')).rejects.toBeInstanceOf(BadRequestException);
|
await expect(sut.get(factory.auth(), 'not-found')).rejects.toBeInstanceOf(BadRequestException);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error when the memory is not found', async () => {
|
it('should throw an error when the memory is not found', async () => {
|
||||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['race-condition']));
|
const [memoryId] = newUuids();
|
||||||
await expect(sut.get(authStub.admin, 'race-condition')).rejects.toBeInstanceOf(BadRequestException);
|
|
||||||
|
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memoryId]));
|
||||||
|
|
||||||
|
await expect(sut.get(factory.auth(), memoryId)).rejects.toBeInstanceOf(BadRequestException);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get a memory by id', async () => {
|
it('should get a memory by id', async () => {
|
||||||
mocks.memory.get.mockResolvedValue(memoryStub.memory1);
|
const userId = newUuid();
|
||||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
const memory = factory.memory({ ownerId: userId });
|
||||||
await expect(sut.get(authStub.admin, 'memory1')).resolves.toMatchObject({ id: 'memory1' });
|
|
||||||
expect(mocks.memory.get).toHaveBeenCalledWith('memory1');
|
mocks.memory.get.mockResolvedValue(memory);
|
||||||
expect(mocks.access.memory.checkOwnerAccess).toHaveBeenCalledWith(userStub.admin.id, new Set(['memory1']));
|
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memory.id]));
|
||||||
|
|
||||||
|
await expect(sut.get(factory.auth({ id: userId }), memory.id)).resolves.toMatchObject({ id: memory.id });
|
||||||
|
|
||||||
|
expect(mocks.memory.get).toHaveBeenCalledWith(memory.id);
|
||||||
|
expect(mocks.access.memory.checkOwnerAccess).toHaveBeenCalledWith(memory.ownerId, new Set([memory.id]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('create', () => {
|
describe('create', () => {
|
||||||
it('should skip assets the user does not have access to', async () => {
|
it('should skip assets the user does not have access to', async () => {
|
||||||
mocks.memory.create.mockResolvedValue(memoryStub.empty);
|
const [assetId, userId] = newUuids();
|
||||||
|
const memory = factory.memory({ ownerId: userId });
|
||||||
|
|
||||||
|
mocks.memory.create.mockResolvedValue(memory);
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
sut.create(authStub.admin, {
|
sut.create(factory.auth({ id: userId }), {
|
||||||
type: MemoryType.ON_THIS_DAY,
|
type: memory.type,
|
||||||
data: { year: 2024 },
|
data: memory.data,
|
||||||
assetIds: ['not-mine'],
|
memoryAt: memory.memoryAt,
|
||||||
memoryAt: new Date(2024),
|
isSaved: memory.isSaved,
|
||||||
|
assetIds: [assetId],
|
||||||
}),
|
}),
|
||||||
).resolves.toMatchObject({ assets: [] });
|
).resolves.toMatchObject({ assets: [] });
|
||||||
|
|
||||||
expect(mocks.memory.create).toHaveBeenCalledWith(
|
expect(mocks.memory.create).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
ownerId: 'admin_id',
|
type: memory.type,
|
||||||
memoryAt: expect.any(Date),
|
data: memory.data,
|
||||||
type: MemoryType.ON_THIS_DAY,
|
ownerId: memory.ownerId,
|
||||||
isSaved: undefined,
|
memoryAt: memory.memoryAt,
|
||||||
sendAt: undefined,
|
isSaved: memory.isSaved,
|
||||||
data: { year: 2024 },
|
|
||||||
},
|
},
|
||||||
new Set(),
|
new Set(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a memory', async () => {
|
it('should create a memory', async () => {
|
||||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset1']));
|
const [assetId, userId] = newUuids();
|
||||||
mocks.memory.create.mockResolvedValue(memoryStub.memory1);
|
const asset = factory.asset({ id: assetId, ownerId: userId });
|
||||||
|
const memory = factory.memory({ assets: [asset] });
|
||||||
|
|
||||||
|
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set([asset.id]));
|
||||||
|
mocks.memory.create.mockResolvedValue(memory);
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
sut.create(authStub.admin, {
|
sut.create(factory.auth({ id: userId }), {
|
||||||
type: MemoryType.ON_THIS_DAY,
|
type: memory.type,
|
||||||
data: { year: 2024 },
|
data: memory.data,
|
||||||
assetIds: ['asset1'],
|
assetIds: memory.assets.map((asset) => asset.id),
|
||||||
memoryAt: new Date(2024, 0, 1),
|
memoryAt: memory.memoryAt,
|
||||||
}),
|
}),
|
||||||
).resolves.toBeDefined();
|
).resolves.toBeDefined();
|
||||||
|
|
||||||
expect(mocks.memory.create).toHaveBeenCalledWith(
|
expect(mocks.memory.create).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({ ownerId: userId }),
|
||||||
ownerId: userStub.admin.id,
|
new Set([assetId]),
|
||||||
}),
|
|
||||||
new Set(['asset1']),
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a memory without assets', async () => {
|
it('should create a memory without assets', async () => {
|
||||||
mocks.memory.create.mockResolvedValue(memoryStub.memory1);
|
const memory = factory.memory();
|
||||||
|
|
||||||
|
mocks.memory.create.mockResolvedValue(memory);
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
sut.create(authStub.admin, {
|
sut.create(factory.auth(), { type: memory.type, data: memory.data, memoryAt: memory.memoryAt }),
|
||||||
type: MemoryType.ON_THIS_DAY,
|
|
||||||
data: { year: 2024 },
|
|
||||||
memoryAt: new Date(2024),
|
|
||||||
}),
|
|
||||||
).resolves.toBeDefined();
|
).resolves.toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('update', () => {
|
describe('update', () => {
|
||||||
it('should require access', async () => {
|
it('should require access', async () => {
|
||||||
await expect(sut.update(authStub.admin, 'not-found', { isSaved: true })).rejects.toBeInstanceOf(
|
await expect(sut.update(factory.auth(), 'not-found', { isSaved: true })).rejects.toBeInstanceOf(
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(mocks.memory.update).not.toHaveBeenCalled();
|
expect(mocks.memory.update).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update a memory', async () => {
|
it('should update a memory', async () => {
|
||||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
const memory = factory.memory();
|
||||||
mocks.memory.update.mockResolvedValue(memoryStub.memory1);
|
|
||||||
await expect(sut.update(authStub.admin, 'memory1', { isSaved: true })).resolves.toBeDefined();
|
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memory.id]));
|
||||||
expect(mocks.memory.update).toHaveBeenCalledWith('memory1', expect.objectContaining({ isSaved: true }));
|
mocks.memory.update.mockResolvedValue(memory);
|
||||||
|
|
||||||
|
await expect(sut.update(factory.auth(), memory.id, { isSaved: true })).resolves.toBeDefined();
|
||||||
|
|
||||||
|
expect(mocks.memory.update).toHaveBeenCalledWith(memory.id, expect.objectContaining({ isSaved: true }));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('remove', () => {
|
describe('remove', () => {
|
||||||
it('should require access', async () => {
|
it('should require access', async () => {
|
||||||
await expect(sut.remove(authStub.admin, 'not-found')).rejects.toBeInstanceOf(BadRequestException);
|
await expect(sut.remove(factory.auth(), newUuid())).rejects.toBeInstanceOf(BadRequestException);
|
||||||
|
|
||||||
expect(mocks.memory.delete).not.toHaveBeenCalled();
|
expect(mocks.memory.delete).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should delete a memory', async () => {
|
it('should delete a memory', async () => {
|
||||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
const memoryId = newUuid();
|
||||||
await expect(sut.remove(authStub.admin, 'memory1')).resolves.toBeUndefined();
|
|
||||||
expect(mocks.memory.delete).toHaveBeenCalledWith('memory1');
|
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memoryId]));
|
||||||
|
|
||||||
|
await expect(sut.remove(factory.auth(), memoryId)).resolves.toBeUndefined();
|
||||||
|
|
||||||
|
expect(mocks.memory.delete).toHaveBeenCalledWith(memoryId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('addAssets', () => {
|
describe('addAssets', () => {
|
||||||
it('should require memory access', async () => {
|
it('should require memory access', async () => {
|
||||||
await expect(sut.addAssets(authStub.admin, 'not-found', { ids: ['asset1'] })).rejects.toBeInstanceOf(
|
const [memoryId, assetId] = newUuids();
|
||||||
|
|
||||||
|
await expect(sut.addAssets(factory.auth(), memoryId, { ids: [assetId] })).rejects.toBeInstanceOf(
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(mocks.memory.addAssetIds).not.toHaveBeenCalled();
|
expect(mocks.memory.addAssetIds).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should require asset access', async () => {
|
it('should require asset access', async () => {
|
||||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
const assetId = newUuid();
|
||||||
mocks.memory.get.mockResolvedValue(memoryStub.memory1);
|
const memory = factory.memory();
|
||||||
await expect(sut.addAssets(authStub.admin, 'memory1', { ids: ['not-found'] })).resolves.toEqual([
|
|
||||||
{ error: 'no_permission', id: 'not-found', success: false },
|
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memory.id]));
|
||||||
|
mocks.memory.get.mockResolvedValue(memory);
|
||||||
|
|
||||||
|
await expect(sut.addAssets(factory.auth(), memory.id, { ids: [assetId] })).resolves.toEqual([
|
||||||
|
{ error: 'no_permission', id: assetId, success: false },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(mocks.memory.addAssetIds).not.toHaveBeenCalled();
|
expect(mocks.memory.addAssetIds).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should skip assets already in the memory', async () => {
|
it('should skip assets already in the memory', async () => {
|
||||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
const asset = factory.asset();
|
||||||
mocks.memory.get.mockResolvedValue(memoryStub.memory1);
|
const memory = factory.memory({ assets: [asset] });
|
||||||
mocks.memory.getAssetIds.mockResolvedValue(new Set(['asset1']));
|
|
||||||
await expect(sut.addAssets(authStub.admin, 'memory1', { ids: ['asset1'] })).resolves.toEqual([
|
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memory.id]));
|
||||||
{ error: 'duplicate', id: 'asset1', success: false },
|
mocks.memory.get.mockResolvedValue(memory);
|
||||||
|
mocks.memory.getAssetIds.mockResolvedValue(new Set([asset.id]));
|
||||||
|
|
||||||
|
await expect(sut.addAssets(factory.auth(), memory.id, { ids: [asset.id] })).resolves.toEqual([
|
||||||
|
{ error: 'duplicate', id: asset.id, success: false },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(mocks.memory.addAssetIds).not.toHaveBeenCalled();
|
expect(mocks.memory.addAssetIds).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add assets', async () => {
|
it('should add assets', async () => {
|
||||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
const assetId = newUuid();
|
||||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset1']));
|
const memory = factory.memory();
|
||||||
mocks.memory.get.mockResolvedValue(memoryStub.memory1);
|
|
||||||
await expect(sut.addAssets(authStub.admin, 'memory1', { ids: ['asset1'] })).resolves.toEqual([
|
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set([memory.id]));
|
||||||
{ id: 'asset1', success: true },
|
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set([assetId]));
|
||||||
|
mocks.memory.get.mockResolvedValue(memory);
|
||||||
|
|
||||||
|
await expect(sut.addAssets(factory.auth(), memory.id, { ids: [assetId] })).resolves.toEqual([
|
||||||
|
{ id: assetId, success: true },
|
||||||
]);
|
]);
|
||||||
expect(mocks.memory.addAssetIds).toHaveBeenCalledWith('memory1', ['asset1']);
|
|
||||||
|
expect(mocks.memory.addAssetIds).toHaveBeenCalledWith(memory.id, [assetId]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('removeAssets', () => {
|
describe('removeAssets', () => {
|
||||||
it('should require memory access', async () => {
|
it('should require memory access', async () => {
|
||||||
await expect(sut.removeAssets(authStub.admin, 'not-found', { ids: ['asset1'] })).rejects.toBeInstanceOf(
|
await expect(sut.removeAssets(factory.auth(), 'not-found', { ids: ['asset1'] })).rejects.toBeInstanceOf(
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(mocks.memory.removeAssetIds).not.toHaveBeenCalled();
|
expect(mocks.memory.removeAssetIds).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should skip assets not in the memory', async () => {
|
it('should skip assets not in the memory', async () => {
|
||||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
||||||
await expect(sut.removeAssets(authStub.admin, 'memory1', { ids: ['not-found'] })).resolves.toEqual([
|
|
||||||
|
await expect(sut.removeAssets(factory.auth(), 'memory1', { ids: ['not-found'] })).resolves.toEqual([
|
||||||
{ error: 'not_found', id: 'not-found', success: false },
|
{ error: 'not_found', id: 'not-found', success: false },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(mocks.memory.removeAssetIds).not.toHaveBeenCalled();
|
expect(mocks.memory.removeAssetIds).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -195,9 +245,11 @@ describe(MemoryService.name, () => {
|
|||||||
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
mocks.access.memory.checkOwnerAccess.mockResolvedValue(new Set(['memory1']));
|
||||||
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset1']));
|
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset1']));
|
||||||
mocks.memory.getAssetIds.mockResolvedValue(new Set(['asset1']));
|
mocks.memory.getAssetIds.mockResolvedValue(new Set(['asset1']));
|
||||||
await expect(sut.removeAssets(authStub.admin, 'memory1', { ids: ['asset1'] })).resolves.toEqual([
|
|
||||||
|
await expect(sut.removeAssets(factory.auth(), 'memory1', { ids: ['asset1'] })).resolves.toEqual([
|
||||||
{ id: 'asset1', success: true },
|
{ id: 'asset1', success: true },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
expect(mocks.memory.removeAssetIds).toHaveBeenCalledWith('memory1', ['asset1']);
|
expect(mocks.memory.removeAssetIds).toHaveBeenCalledWith('memory1', ['asset1']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { JsonObject } from 'src/db';
|
|
||||||
import { OnJob } from 'src/decorators';
|
import { OnJob } from 'src/decorators';
|
||||||
import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
|
import { BulkIdResponseDto, BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
@ -97,7 +96,7 @@ export class MemoryService extends BaseService {
|
|||||||
{
|
{
|
||||||
ownerId: auth.user.id,
|
ownerId: auth.user.id,
|
||||||
type: dto.type,
|
type: dto.type,
|
||||||
data: dto.data as unknown as JsonObject,
|
data: dto.data,
|
||||||
isSaved: dto.isSaved,
|
isSaved: dto.isSaved,
|
||||||
memoryAt: dto.memoryAt,
|
memoryAt: dto.memoryAt,
|
||||||
seenAt: dto.seenAt,
|
seenAt: dto.seenAt,
|
||||||
|
34
server/test/fixtures/memory.stub.ts
vendored
34
server/test/fixtures/memory.stub.ts
vendored
@ -1,34 +0,0 @@
|
|||||||
import { MemoryType } from 'src/enum';
|
|
||||||
import { assetStub } from 'test/fixtures/asset.stub';
|
|
||||||
import { userStub } from 'test/fixtures/user.stub';
|
|
||||||
|
|
||||||
export const memoryStub = {
|
|
||||||
empty: {
|
|
||||||
id: 'memoryEmpty',
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date(),
|
|
||||||
memoryAt: new Date(2024),
|
|
||||||
ownerId: userStub.admin.id,
|
|
||||||
owner: userStub.admin,
|
|
||||||
type: MemoryType.ON_THIS_DAY,
|
|
||||||
data: { year: 2024 },
|
|
||||||
isSaved: false,
|
|
||||||
assets: [],
|
|
||||||
deletedAt: null,
|
|
||||||
seenAt: null,
|
|
||||||
} as unknown as any,
|
|
||||||
memory1: {
|
|
||||||
id: 'memory1',
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date(),
|
|
||||||
memoryAt: new Date(2024),
|
|
||||||
ownerId: userStub.admin.id,
|
|
||||||
owner: userStub.admin,
|
|
||||||
type: MemoryType.ON_THIS_DAY,
|
|
||||||
data: { year: 2024 },
|
|
||||||
isSaved: false,
|
|
||||||
assets: [assetStub.image1],
|
|
||||||
deletedAt: null,
|
|
||||||
seenAt: null,
|
|
||||||
} as unknown as any,
|
|
||||||
};
|
|
@ -1,6 +1,8 @@
|
|||||||
import { randomUUID } from 'node:crypto';
|
import { randomUUID } from 'node:crypto';
|
||||||
import { AuthUser, User } from 'src/database';
|
import { Asset, AuthUser, User } from 'src/database';
|
||||||
import { ActivityItem } from 'src/types';
|
import { OnThisDayData } from 'src/entities/memory.entity';
|
||||||
|
import { AssetStatus, AssetType, MemoryType } from 'src/enum';
|
||||||
|
import { ActivityItem, MemoryItem } from 'src/types';
|
||||||
|
|
||||||
export const newUuid = () => randomUUID() as string;
|
export const newUuid = () => randomUUID() as string;
|
||||||
export const newUuids = () =>
|
export const newUuids = () =>
|
||||||
@ -9,6 +11,7 @@ export const newUuids = () =>
|
|||||||
.map(() => newUuid());
|
.map(() => newUuid());
|
||||||
export const newDate = () => new Date();
|
export const newDate = () => new Date();
|
||||||
export const newUpdateId = () => 'uuid-v7';
|
export const newUpdateId = () => 'uuid-v7';
|
||||||
|
export const newSha1 = () => Buffer.from('this is a fake hash');
|
||||||
|
|
||||||
const authUser = (authUser: Partial<AuthUser>) => ({
|
const authUser = (authUser: Partial<AuthUser>) => ({
|
||||||
id: newUuid(),
|
id: newUuid(),
|
||||||
@ -35,6 +38,38 @@ export const factory = {
|
|||||||
}),
|
}),
|
||||||
authUser,
|
authUser,
|
||||||
user,
|
user,
|
||||||
|
asset: (asset: Partial<Asset> = {}) => ({
|
||||||
|
id: newUuid(),
|
||||||
|
createdAt: newDate(),
|
||||||
|
updatedAt: newDate(),
|
||||||
|
deletedAt: null,
|
||||||
|
updateId: newUpdateId(),
|
||||||
|
status: AssetStatus.ACTIVE,
|
||||||
|
checksum: newSha1(),
|
||||||
|
deviceAssetId: '',
|
||||||
|
deviceId: '',
|
||||||
|
duplicateId: null,
|
||||||
|
duration: null,
|
||||||
|
encodedVideoPath: null,
|
||||||
|
fileCreatedAt: newDate(),
|
||||||
|
fileModifiedAt: newDate(),
|
||||||
|
isArchived: false,
|
||||||
|
isExternal: false,
|
||||||
|
isFavorite: false,
|
||||||
|
isOffline: false,
|
||||||
|
isVisible: true,
|
||||||
|
libraryId: null,
|
||||||
|
livePhotoVideoId: null,
|
||||||
|
localDateTime: newDate(),
|
||||||
|
originalFileName: 'IMG_123.jpg',
|
||||||
|
originalPath: `upload/12/34/IMG_123.jpg`,
|
||||||
|
ownerId: newUuid(),
|
||||||
|
sidecarPath: null,
|
||||||
|
stackId: null,
|
||||||
|
thumbhash: null,
|
||||||
|
type: AssetType.IMAGE,
|
||||||
|
...asset,
|
||||||
|
}),
|
||||||
activity: (activity: Partial<ActivityItem> = {}) => {
|
activity: (activity: Partial<ActivityItem> = {}) => {
|
||||||
const userId = activity.userId || newUuid();
|
const userId = activity.userId || newUuid();
|
||||||
return {
|
return {
|
||||||
@ -51,4 +86,21 @@ export const factory = {
|
|||||||
...activity,
|
...activity,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
memory: (memory: Partial<MemoryItem> = {}) => ({
|
||||||
|
id: newUuid(),
|
||||||
|
createdAt: newDate(),
|
||||||
|
updatedAt: newDate(),
|
||||||
|
updateId: newUpdateId(),
|
||||||
|
deletedAt: null,
|
||||||
|
ownerId: newUuid(),
|
||||||
|
type: MemoryType.ON_THIS_DAY,
|
||||||
|
data: { year: 2024 } as OnThisDayData,
|
||||||
|
isSaved: false,
|
||||||
|
memoryAt: newDate(),
|
||||||
|
seenAt: null,
|
||||||
|
showAt: newDate(),
|
||||||
|
hideAt: newDate(),
|
||||||
|
assets: [],
|
||||||
|
...memory,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user