refactor: better types for getList and getDeletedAfter (#16926)
This commit is contained in:
@@ -29,6 +29,7 @@ import { SharedLinkRepository } from 'src/repositories/shared-link.repository';
|
||||
import { StackRepository } from 'src/repositories/stack.repository';
|
||||
import { StorageRepository } from 'src/repositories/storage.repository';
|
||||
import { SyncRepository } from 'src/repositories/sync.repository';
|
||||
import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository';
|
||||
import { TelemetryRepository } from 'src/repositories/telemetry.repository';
|
||||
import { TrashRepository } from 'src/repositories/trash.repository';
|
||||
import { UserRepository } from 'src/repositories/user.repository';
|
||||
@@ -205,6 +206,7 @@ export class TestContext {
|
||||
sharedLink: SharedLinkRepository;
|
||||
stack: StackRepository;
|
||||
storage: StorageRepository;
|
||||
systemMetadata: SystemMetadataRepository;
|
||||
sync: SyncRepository;
|
||||
telemetry: TelemetryRepository;
|
||||
trash: TrashRepository;
|
||||
@@ -241,6 +243,7 @@ export class TestContext {
|
||||
this.stack = new StackRepository(this.db);
|
||||
this.storage = new StorageRepository(logger);
|
||||
this.sync = new SyncRepository(this.db);
|
||||
this.systemMetadata = new SystemMetadataRepository(this.db);
|
||||
this.telemetry = newTelemetryRepositoryMock() as unknown as TelemetryRepository;
|
||||
this.trash = new TrashRepository(this.db);
|
||||
this.user = new UserRepository(this.db);
|
||||
|
||||
-5
@@ -47,11 +47,6 @@ export const systemConfigStub = {
|
||||
defaultStorageQuota: 1,
|
||||
},
|
||||
},
|
||||
deleteDelay30: {
|
||||
user: {
|
||||
deleteDelay: 30,
|
||||
},
|
||||
},
|
||||
libraryWatchEnabled: {
|
||||
library: {
|
||||
scan: {
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
import { Kysely } from 'kysely';
|
||||
import { DateTime } from 'luxon';
|
||||
import { DB } from 'src/db';
|
||||
import { JobName, JobStatus } from 'src/enum';
|
||||
import { UserService } from 'src/services/user.service';
|
||||
import { TestContext, TestFactory } from 'test/factory';
|
||||
import { getKyselyDB, newTestService } from 'test/utils';
|
||||
import { getKyselyDB, newTestService, ServiceMocks } from 'test/utils';
|
||||
|
||||
const setup = async (db: Kysely<DB>) => {
|
||||
const context = await TestContext.from(db).withUser({ isAdmin: true }).create();
|
||||
const { sut, mocks } = newTestService(UserService, context);
|
||||
|
||||
return { sut, mocks, context };
|
||||
};
|
||||
|
||||
describe.concurrent(UserService.name, () => {
|
||||
let sut: UserService;
|
||||
let context: TestContext;
|
||||
let mocks: ServiceMocks;
|
||||
|
||||
beforeAll(async () => {
|
||||
const db = await getKyselyDB();
|
||||
context = await TestContext.from(db).withUser({ isAdmin: true }).create();
|
||||
({ sut } = newTestService(UserService, context));
|
||||
({ sut, context, mocks } = await setup(await getKyselyDB()));
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
@@ -113,4 +123,50 @@ describe.concurrent(UserService.name, () => {
|
||||
expect(getResponse).toEqual(after);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleUserDeleteCheck', () => {
|
||||
it('should work when there are no deleted users', async () => {
|
||||
await expect(sut.handleUserDeleteCheck()).resolves.toEqual(JobStatus.SUCCESS);
|
||||
|
||||
expect(mocks.job.queueAll).toHaveBeenCalledWith([]);
|
||||
});
|
||||
|
||||
it('should work when there is a user to delete', async () => {
|
||||
const { sut, context, mocks } = await setup(await getKyselyDB());
|
||||
const user = TestFactory.user({ deletedAt: DateTime.now().minus({ days: 25 }).toJSDate() });
|
||||
|
||||
await context.createUser(user);
|
||||
|
||||
await expect(sut.handleUserDeleteCheck()).resolves.toEqual(JobStatus.SUCCESS);
|
||||
|
||||
expect(mocks.job.queueAll).toHaveBeenCalledWith([{ name: JobName.USER_DELETION, data: { id: user.id } }]);
|
||||
});
|
||||
|
||||
it('should skip a recently deleted user', async () => {
|
||||
const { sut, context, mocks } = await setup(await getKyselyDB());
|
||||
const user = TestFactory.user({ deletedAt: DateTime.now().minus({ days: 5 }).toJSDate() });
|
||||
|
||||
await context.createUser(user);
|
||||
|
||||
await expect(sut.handleUserDeleteCheck()).resolves.toEqual(JobStatus.SUCCESS);
|
||||
|
||||
expect(mocks.job.queueAll).toHaveBeenCalledWith([]);
|
||||
});
|
||||
|
||||
it('should respect a custom user delete delay', async () => {
|
||||
const db = await getKyselyDB();
|
||||
const { sut, context, mocks } = await setup(db);
|
||||
const user = TestFactory.user({ deletedAt: DateTime.now().minus({ days: 25 }).toJSDate() });
|
||||
await context.createUser(user);
|
||||
|
||||
const config = await sut.getConfig({ withCache: false });
|
||||
config.user.deleteDelay = 30;
|
||||
|
||||
await sut.updateConfig(config);
|
||||
|
||||
await expect(sut.handleUserDeleteCheck()).resolves.toEqual(JobStatus.SUCCESS);
|
||||
|
||||
expect(mocks.job.queueAll).toHaveBeenCalledWith([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { ApiKey, Asset, AuthApiKey, AuthUser, Library, Partner, User } from 'src/database';
|
||||
import { ApiKey, Asset, AuthApiKey, AuthUser, Library, Partner, User, UserAdmin } from 'src/database';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { OnThisDayData } from 'src/entities/memory.entity';
|
||||
import { AssetStatus, AssetType, MemoryType, Permission } from 'src/enum';
|
||||
import { AssetStatus, AssetType, MemoryType, Permission, UserStatus } from 'src/enum';
|
||||
import { ActivityItem, MemoryItem } from 'src/types';
|
||||
|
||||
export const newUuid = () => randomUUID() as string;
|
||||
@@ -85,6 +85,26 @@ const userFactory = (user: Partial<User> = {}) => ({
|
||||
...user,
|
||||
});
|
||||
|
||||
const userAdminFactory = (user: Partial<UserAdmin> = {}) => ({
|
||||
id: newUuid(),
|
||||
name: 'Test User',
|
||||
email: 'test@immich.cloud',
|
||||
profileImagePath: '',
|
||||
profileChangedAt: newDate(),
|
||||
storageLabel: null,
|
||||
shouldChangePassword: false,
|
||||
isAdmin: false,
|
||||
createdAt: newDate(),
|
||||
updatedAt: newDate(),
|
||||
deletedAt: null,
|
||||
oauthId: '',
|
||||
quotaSizeInBytes: null,
|
||||
quotaUsageInBytes: 0,
|
||||
status: UserStatus.ACTIVE,
|
||||
metadata: [],
|
||||
...user,
|
||||
});
|
||||
|
||||
const assetFactory = (asset: Partial<Asset> = {}) => ({
|
||||
id: newUuid(),
|
||||
createdAt: newDate(),
|
||||
@@ -198,5 +218,6 @@ export const factory = {
|
||||
session: sessionFactory,
|
||||
stack: stackFactory,
|
||||
user: userFactory,
|
||||
userAdmin: userAdminFactory,
|
||||
versionHistory: versionHistoryFactory,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user