fix: shared check for server setup availability (#30311)

* fix: shared check for server setup availability

* chore: add medium test

* feat: require @Authenticated decorator everywhere

* fix: lints
This commit is contained in:
bo0tzz 2026-07-30 21:12:25 +02:00 committed by GitHub
parent 1f16fe16c2
commit a316ba35ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 249 additions and 66 deletions

View file

@ -35,7 +35,4 @@ export const errorDto = {
incorrectLogin: {
message: 'Incorrect email or password',
},
alreadyHasAdmin: {
message: 'The server already has an admin',
},
};

View file

@ -57,16 +57,6 @@ describe(AuthService.name, () => {
}),
);
});
it('should not allow a second admin to sign up', async () => {
const { sut, ctx } = setup();
await ctx.newUser({ isAdmin: true });
const dto = { name: 'Admin', email: 'admin@immich.cloud', password: 'password' };
const response = sut.adminSignUp(dto);
await expect(response).rejects.toThrow(BadRequestException);
await expect(response).rejects.toThrow('The server already has an admin');
});
});
describe('login', () => {

View file

@ -89,6 +89,7 @@ import { assert, Mock, Mocked, vitest } from 'vitest';
export type ControllerContext = {
authenticate: Mock;
requireSetupAvailable: Mock;
getHttpServer: () => any;
reset: () => void;
close: () => Promise<void>;
@ -124,7 +125,7 @@ export const controllerSetup = async (controller: new (...args: any[]) => unknow
{ provide: APP_GUARD, useClass: AuthGuard },
{ provide: LoggingRepository, useValue: LoggingRepository.create() },
{ provide: ClsService, useValue: { getId: vi.fn() } },
{ provide: AuthService, useValue: { authenticate: vi.fn() } },
{ provide: AuthService, useValue: { authenticate: vi.fn(), requireSetupAvailable: vi.fn() } },
...providers,
],
})
@ -137,13 +138,17 @@ export const controllerSetup = async (controller: new (...args: any[]) => unknow
await app.init();
// allow the AuthController to override the AuthService itself
const authenticate = app.get<Mocked<AuthService>>(AuthService).authenticate as Mock;
const resolvedAuthService = app.get<Mocked<AuthService>>(AuthService);
const authenticate = resolvedAuthService.authenticate as Mock;
const requireSetupAvailable = resolvedAuthService.requireSetupAvailable as Mock;
return {
authenticate,
requireSetupAvailable,
getHttpServer: () => app.getHttpServer(),
reset: () => {
authenticate.mockReset();
requireSetupAvailable.mockReset();
},
close: async () => {
await app.close();
@ -184,10 +189,12 @@ export const automock = <T>(
const mocks: Mock[] = [];
const instance = new Dependency(...args);
const propertyNames = new Set([
...Object.getOwnPropertyNames(Dependency.prototype),
...Object.getOwnPropertyNames(instance),
]);
const propertyNames = new Set(Object.getOwnPropertyNames(instance));
for (let proto = Dependency.prototype; proto && proto !== Object.prototype; proto = Object.getPrototypeOf(proto)) {
for (const property of Object.getOwnPropertyNames(proto)) {
propertyNames.add(property);
}
}
for (const property of propertyNames) {
if (property === 'constructor') {
continue;