refactor
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { vi } from 'vitest';
|
||||
import { Mock, vi } from 'vitest';
|
||||
import { AuthController } from './AuthController';
|
||||
import { AuthService } from './AuthService';
|
||||
import { SignupParams, LoginParams, AuthSessionDTO } from './dtos/AuthDto';
|
||||
import { AuthSessionDTO, LoginParams, SignupParams } from './dtos/AuthDto';
|
||||
import type { CommandResultDTO } from './presenters/CommandResultPresenter';
|
||||
|
||||
describe('AuthController', () => {
|
||||
let controller: AuthController;
|
||||
@@ -36,7 +37,7 @@ describe('AuthController', () => {
|
||||
displayName: 'Test User',
|
||||
},
|
||||
};
|
||||
(service.signupWithEmail as jest.Mock).mockResolvedValue(session);
|
||||
(service.signupWithEmail as Mock).mockResolvedValue(session);
|
||||
|
||||
const result = await controller.signup(params);
|
||||
|
||||
@@ -59,7 +60,7 @@ describe('AuthController', () => {
|
||||
displayName: 'Test User',
|
||||
},
|
||||
};
|
||||
(service.loginWithEmail as jest.Mock).mockResolvedValue(session);
|
||||
(service.loginWithEmail as Mock).mockResolvedValue(session);
|
||||
|
||||
const result = await controller.login(params);
|
||||
|
||||
@@ -78,7 +79,7 @@ describe('AuthController', () => {
|
||||
displayName: 'Test User',
|
||||
},
|
||||
};
|
||||
(service.getCurrentSession as jest.Mock).mockResolvedValue(session);
|
||||
(service.getCurrentSession as Mock).mockResolvedValue(session);
|
||||
|
||||
const result = await controller.getSession();
|
||||
|
||||
@@ -87,7 +88,7 @@ describe('AuthController', () => {
|
||||
});
|
||||
|
||||
it('should return null if no session', async () => {
|
||||
(service.getCurrentSession as jest.Mock).mockResolvedValue(null);
|
||||
(service.getCurrentSession as Mock).mockResolvedValue(null);
|
||||
|
||||
const result = await controller.getSession();
|
||||
|
||||
@@ -97,8 +98,8 @@ describe('AuthController', () => {
|
||||
|
||||
describe('logout', () => {
|
||||
it('should call service.logout and return DTO', async () => {
|
||||
const dto = { success: true };
|
||||
(service.logout as jest.Mock).mockResolvedValue(dto);
|
||||
const dto: CommandResultDTO = { success: true };
|
||||
(service.logout as Mock).mockResolvedValue(dto);
|
||||
|
||||
const result = await controller.logout();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Controller, Get, Post, Body } from '@nestjs/common';
|
||||
import { AuthService } from './AuthService';
|
||||
import { LoginParams, SignupParams, AuthSessionDTO } from './dtos/AuthDto';
|
||||
import type { CommandResultDTO } from './presenters/CommandResultPresenter';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
@@ -22,7 +23,7 @@ export class AuthController {
|
||||
}
|
||||
|
||||
@Post('logout')
|
||||
async logout(): Promise<{ success: boolean }> {
|
||||
async logout(): Promise<CommandResultDTO> {
|
||||
return this.authService.logout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ export const IDENTITY_SESSION_PORT_TOKEN = 'IdentitySessionPort';
|
||||
export const LOGIN_USE_CASE_TOKEN = 'LoginUseCase';
|
||||
export const SIGNUP_USE_CASE_TOKEN = 'SignupUseCase';
|
||||
export const LOGOUT_USE_CASE_TOKEN = 'LogoutUseCase';
|
||||
export const AUTH_SESSION_PRESENTER_TOKEN = 'AuthSessionPresenter';
|
||||
export const COMMAND_RESULT_PRESENTER_TOKEN = 'CommandResultPresenter';
|
||||
|
||||
export const AuthProviders: Provider[] = [
|
||||
{
|
||||
@@ -73,20 +75,28 @@ export const AuthProviders: Provider[] = [
|
||||
},
|
||||
{
|
||||
provide: LOGIN_USE_CASE_TOKEN,
|
||||
useFactory: (authRepo: IAuthRepository, passwordHashing: IPasswordHashingService, logger: Logger) =>
|
||||
new LoginUseCase(authRepo, passwordHashing, logger),
|
||||
inject: [AUTH_REPOSITORY_TOKEN, PASSWORD_HASHING_SERVICE_TOKEN, LOGGER_TOKEN],
|
||||
useFactory: (authRepo: IAuthRepository, passwordHashing: IPasswordHashingService, logger: Logger, presenter: AuthSessionPresenter) =>
|
||||
new LoginUseCase(authRepo, passwordHashing, logger, presenter),
|
||||
inject: [AUTH_REPOSITORY_TOKEN, PASSWORD_HASHING_SERVICE_TOKEN, LOGGER_TOKEN, AUTH_SESSION_PRESENTER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: SIGNUP_USE_CASE_TOKEN,
|
||||
useFactory: (authRepo: IAuthRepository, passwordHashing: IPasswordHashingService, logger: Logger) =>
|
||||
new SignupUseCase(authRepo, passwordHashing, logger),
|
||||
inject: [AUTH_REPOSITORY_TOKEN, PASSWORD_HASHING_SERVICE_TOKEN, LOGGER_TOKEN],
|
||||
useFactory: (authRepo: IAuthRepository, passwordHashing: IPasswordHashingService, logger: Logger, presenter: AuthSessionPresenter) =>
|
||||
new SignupUseCase(authRepo, passwordHashing, logger, presenter),
|
||||
inject: [AUTH_REPOSITORY_TOKEN, PASSWORD_HASHING_SERVICE_TOKEN, LOGGER_TOKEN, AUTH_SESSION_PRESENTER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: LOGOUT_USE_CASE_TOKEN,
|
||||
useFactory: (sessionPort: IdentitySessionPort, logger: Logger) =>
|
||||
new LogoutUseCase(sessionPort, logger),
|
||||
inject: [IDENTITY_SESSION_PORT_TOKEN, LOGGER_TOKEN],
|
||||
useFactory: (sessionPort: IdentitySessionPort, logger: Logger, presenter: CommandResultPresenter) =>
|
||||
new LogoutUseCase(sessionPort, logger, presenter),
|
||||
inject: [IDENTITY_SESSION_PORT_TOKEN, LOGGER_TOKEN, COMMAND_RESULT_PRESENTER_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: AUTH_SESSION_PRESENTER_TOKEN,
|
||||
useClass: AuthSessionPresenter,
|
||||
},
|
||||
{
|
||||
provide: COMMAND_RESULT_PRESENTER_TOKEN,
|
||||
useClass: CommandResultPresenter,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Inject } from '@nestjs/common';
|
||||
|
||||
// Core Use Cases
|
||||
import { LoginUseCase, type LoginInput } from '@core/identity/application/use-cases/LoginUseCase';
|
||||
@@ -11,12 +11,10 @@ import { User } from '@core/identity/domain/entities/User';
|
||||
import type { IUserRepository } from '@core/identity/domain/repositories/IUserRepository';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
import { IDENTITY_SESSION_PORT_TOKEN, LOGGER_TOKEN, LOGIN_USE_CASE_TOKEN, LOGOUT_USE_CASE_TOKEN, SIGNUP_USE_CASE_TOKEN, USER_REPOSITORY_TOKEN } from './AuthProviders';
|
||||
import { AuthenticatedUserDTO, AuthSessionDTO, LoginParams, SignupParams } from './dtos/AuthDto';
|
||||
import { AuthSessionDTO, LoginParams, SignupParams } from './dtos/AuthDto';
|
||||
import { AuthSessionPresenter } from './presenters/AuthSessionPresenter';
|
||||
import type { CommandResultDTO } from './presenters/CommandResultPresenter';
|
||||
import { CommandResultPresenter } from './presenters/CommandResultPresenter';
|
||||
import { CommandResultPresenter, type CommandResultDTO } from './presenters/CommandResultPresenter';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(
|
||||
@Inject(LOGGER_TOKEN) private logger: Logger,
|
||||
@@ -25,31 +23,10 @@ export class AuthService {
|
||||
@Inject(LOGIN_USE_CASE_TOKEN) private readonly loginUseCase: LoginUseCase,
|
||||
@Inject(SIGNUP_USE_CASE_TOKEN) private readonly signupUseCase: SignupUseCase,
|
||||
@Inject(LOGOUT_USE_CASE_TOKEN) private readonly logoutUseCase: LogoutUseCase,
|
||||
private readonly authSessionPresenter: AuthSessionPresenter,
|
||||
private readonly commandResultPresenter: CommandResultPresenter,
|
||||
) {}
|
||||
|
||||
private mapUserToAuthenticatedUserDTO(user: User): AuthenticatedUserDTO {
|
||||
return {
|
||||
userId: user.getId().value,
|
||||
email: user.getEmail() ?? '',
|
||||
displayName: user.getDisplayName() ?? '',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private buildAuthSessionDTO(token: string, user: AuthenticatedUserDTO): AuthSessionDTO {
|
||||
return {
|
||||
token,
|
||||
user: {
|
||||
userId: user.userId,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async getCurrentSession(): Promise<AuthSessionDTO | null> {
|
||||
// TODO this must call a use case
|
||||
this.logger.debug('[AuthService] Attempting to get current session.');
|
||||
const coreSession = await this.identitySessionPort.getCurrentSession();
|
||||
if (!coreSession) {
|
||||
@@ -87,7 +64,8 @@ export class AuthService {
|
||||
throw new Error(error.details?.message ?? 'Signup failed');
|
||||
}
|
||||
|
||||
const userDTO = this.authSessionPresenter.getResponseModel();
|
||||
const authSessionPresenter = new AuthSessionPresenter();
|
||||
const userDTO = authSessionPresenter.getResponseModel();
|
||||
const coreUserDTO = {
|
||||
id: userDTO.userId,
|
||||
displayName: userDTO.displayName,
|
||||
@@ -116,7 +94,8 @@ export class AuthService {
|
||||
throw new Error(error.details?.message ?? 'Login failed');
|
||||
}
|
||||
|
||||
const userDTO = this.authSessionPresenter.getResponseModel();
|
||||
const authSessionPresenter = new AuthSessionPresenter();
|
||||
const userDTO = authSessionPresenter.getResponseModel();
|
||||
const coreUserDTO = {
|
||||
id: userDTO.userId,
|
||||
displayName: userDTO.displayName,
|
||||
@@ -133,6 +112,7 @@ export class AuthService {
|
||||
async logout(): Promise<CommandResultDTO> {
|
||||
this.logger.debug('[AuthService] Attempting logout.');
|
||||
|
||||
const commandResultPresenter = new CommandResultPresenter();
|
||||
const result = await this.logoutUseCase.execute();
|
||||
|
||||
if (result.isErr()) {
|
||||
@@ -140,6 +120,6 @@ export class AuthService {
|
||||
throw new Error(error.details?.message ?? 'Logout failed');
|
||||
}
|
||||
|
||||
return this.commandResultPresenter.getResponseModel();
|
||||
return commandResultPresenter.getResponseModel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,16 +5,12 @@ import { UserId } from '@core/identity/domain/value-objects/UserId';
|
||||
|
||||
describe('AuthSessionPresenter', () => {
|
||||
let presenter: AuthSessionPresenter;
|
||||
let mockIdentitySessionPort: any;
|
||||
|
||||
beforeEach(() => {
|
||||
mockIdentitySessionPort = {
|
||||
createSession: vi.fn(),
|
||||
};
|
||||
presenter = new AuthSessionPresenter(mockIdentitySessionPort);
|
||||
presenter = new AuthSessionPresenter();
|
||||
});
|
||||
|
||||
it('maps successful result into response model', async () => {
|
||||
it('maps successful result into response model', () => {
|
||||
const user = User.create({
|
||||
id: UserId.fromString('user-1'),
|
||||
displayName: 'Test User',
|
||||
@@ -22,20 +18,15 @@ describe('AuthSessionPresenter', () => {
|
||||
passwordHash: { value: 'hash' } as any,
|
||||
});
|
||||
|
||||
const expectedSession = {
|
||||
token: 'token-123',
|
||||
user: {
|
||||
userId: 'user-1',
|
||||
email: 'user@example.com',
|
||||
displayName: 'Test User',
|
||||
},
|
||||
const expectedUser = {
|
||||
userId: 'user-1',
|
||||
email: 'user@example.com',
|
||||
displayName: 'Test User',
|
||||
};
|
||||
|
||||
mockIdentitySessionPort.createSession.mockResolvedValue(expectedSession);
|
||||
presenter.present({ user });
|
||||
|
||||
await presenter.present({ user });
|
||||
|
||||
expect(presenter.getResponseModel()).toEqual(expectedSession);
|
||||
expect(presenter.getResponseModel()).toEqual(expectedUser);
|
||||
});
|
||||
|
||||
it('getResponseModel throws when not presented', () => {
|
||||
|
||||
Reference in New Issue
Block a user