new authorization
This commit is contained in:
parent
bbcd2cdb9e
commit
470a93879e
24
package.json
24
package.json
|
@ -91,12 +91,12 @@
|
|||
"ts"
|
||||
],
|
||||
"modulePathIgnorePatterns": [
|
||||
".controller.ts",
|
||||
".module.ts",
|
||||
".request.ts",
|
||||
".presenter.ts",
|
||||
".profile.ts",
|
||||
".exception.ts",
|
||||
".dto.ts",
|
||||
".di-tokens.ts",
|
||||
".response.ts",
|
||||
".port.ts",
|
||||
"prisma.service.ts",
|
||||
"main.ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
|
@ -108,15 +108,19 @@
|
|||
"**/*.(t|j)s"
|
||||
],
|
||||
"coveragePathIgnorePatterns": [
|
||||
".controller.ts",
|
||||
".module.ts",
|
||||
".request.ts",
|
||||
".presenter.ts",
|
||||
".profile.ts",
|
||||
".exception.ts",
|
||||
".dto.ts",
|
||||
".di-tokens.ts",
|
||||
".response.ts",
|
||||
".port.ts",
|
||||
"prisma.service.ts",
|
||||
"main.ts"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"moduleNameMapper": {
|
||||
"^@modules(.*)": "<rootDir>/modules/$1",
|
||||
"^@src(.*)": "<rootDir>$1"
|
||||
},
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Module } from '@nestjs/common';
|
|||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
// import { AuthorizationModule } from './modules/authorization/authorization.module';
|
||||
// import { HealthModule } from './modules/health/health.module';
|
||||
import { AuthenticationModule } from '@modules/newauthentication/authentication.module';
|
||||
import { AuthenticationModule } from '@modules/authentication/authentication.module';
|
||||
import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||
import {
|
||||
MessageBrokerModule,
|
||||
|
|
|
@ -15,7 +15,7 @@ async function bootstrap() {
|
|||
protoPath: [
|
||||
join(
|
||||
__dirname,
|
||||
'modules/newauthentication/interface/grpc-controllers/authentication.proto',
|
||||
'modules/authentication/interface/grpc-controllers/authentication.proto',
|
||||
),
|
||||
join(
|
||||
__dirname,
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
export const AUTHENTICATION_REPOSITORY = Symbol('AUTHENTICATION_REPOSITORY');
|
||||
export const USERNAME_REPOSITORY = Symbol('USERNAME_REPOSITORY');
|
|
@ -52,6 +52,7 @@ export class AuthenticationMapper
|
|||
userId: record.uuid,
|
||||
password: record.password,
|
||||
usernames: record.usernames.map((username: UsernameModel) => ({
|
||||
userId: record.uuid,
|
||||
name: username.username,
|
||||
type: Type[username.type],
|
||||
})),
|
|
@ -1,66 +1,72 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { Module, Provider } from '@nestjs/common';
|
||||
import { CreateAuthenticationGrpcController } from './interface/grpc-controllers/create-authentication.grpc.controller';
|
||||
import { CreateAuthenticationService } from './core/application/commands/create-authentication/create-authentication.service';
|
||||
import { AuthenticationMapper } from './authentication.mapper';
|
||||
import {
|
||||
AUTHENTICATION_REPOSITORY,
|
||||
USERNAME_REPOSITORY,
|
||||
} from './authentication.di-tokens';
|
||||
import { AuthenticationRepository } from './infrastructure/authentication.repository';
|
||||
import { PrismaService } from './infrastructure/prisma.service';
|
||||
import { CqrsModule } from '@nestjs/cqrs';
|
||||
import { DatabaseModule } from '../database/database.module';
|
||||
import { AuthenticationController } from './adapters/primaries/authentication.controller';
|
||||
import { CreateAuthenticationUseCase } from './domain/usecases/create-authentication.usecase';
|
||||
import { ValidateAuthenticationUseCase } from './domain/usecases/validate-authentication.usecase';
|
||||
import { AuthenticationProfile } from './mappers/authentication.profile';
|
||||
import { AuthenticationRepository } from './adapters/secondaries/authentication.repository';
|
||||
import { UpdateUsernameUseCase } from './domain/usecases/update-username.usecase';
|
||||
import { UsernameProfile } from './mappers/username.profile';
|
||||
import { AddUsernameUseCase } from './domain/usecases/add-username.usecase';
|
||||
import { UpdatePasswordUseCase } from './domain/usecases/update-password.usecase';
|
||||
import { DeleteUsernameUseCase } from './domain/usecases/delete-username.usecase';
|
||||
import { DeleteAuthenticationUseCase } from './domain/usecases/delete-authentication.usecase';
|
||||
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { AuthenticationMessagerController } from './adapters/primaries/authentication-messager.controller';
|
||||
import { Messager } from './adapters/secondaries/messager';
|
||||
import { DeleteAuthenticationGrpcController } from './interface/grpc-controllers/delete-authentication.grpc.controller';
|
||||
import { DeleteAuthenticationService } from './core/application/commands/delete-authentication/delete-authentication.service';
|
||||
import { MESSAGE_PUBLISHER } from '@src/app.di-tokens';
|
||||
import { MessageBrokerPublisher } from '@mobicoop/message-broker-module';
|
||||
import { UsernameRepository } from './infrastructure/username.repository';
|
||||
import { UsernameMapper } from './username.mapper';
|
||||
import { AddUsernameGrpcController } from './interface/grpc-controllers/add-username.grpc.controller';
|
||||
import { AddUsernameService } from './core/application/commands/add-usernames/add-username.service';
|
||||
|
||||
const grpcControllers = [
|
||||
CreateAuthenticationGrpcController,
|
||||
DeleteAuthenticationGrpcController,
|
||||
AddUsernameGrpcController,
|
||||
];
|
||||
|
||||
const commandHandlers: Provider[] = [
|
||||
CreateAuthenticationService,
|
||||
DeleteAuthenticationService,
|
||||
AddUsernameService,
|
||||
];
|
||||
|
||||
const mappers: Provider[] = [AuthenticationMapper, UsernameMapper];
|
||||
|
||||
const repositories: Provider[] = [
|
||||
{
|
||||
provide: AUTHENTICATION_REPOSITORY,
|
||||
useClass: AuthenticationRepository,
|
||||
},
|
||||
{
|
||||
provide: USERNAME_REPOSITORY,
|
||||
useClass: UsernameRepository,
|
||||
},
|
||||
];
|
||||
|
||||
const messageBrokers: Provider[] = [
|
||||
{
|
||||
provide: MESSAGE_PUBLISHER,
|
||||
useClass: MessageBrokerPublisher,
|
||||
},
|
||||
];
|
||||
|
||||
const orms: Provider[] = [PrismaService];
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
DatabaseModule,
|
||||
CqrsModule,
|
||||
RabbitMQModule.forRootAsync(RabbitMQModule, {
|
||||
imports: [ConfigModule],
|
||||
useFactory: async (configService: ConfigService) => ({
|
||||
exchanges: [
|
||||
{
|
||||
name: configService.get<string>('RMQ_EXCHANGE'),
|
||||
type: 'topic',
|
||||
},
|
||||
],
|
||||
handlers: {
|
||||
userUpdate: {
|
||||
exchange: configService.get<string>('RMQ_EXCHANGE'),
|
||||
routingKey: 'user.update',
|
||||
},
|
||||
userDelete: {
|
||||
exchange: configService.get<string>('RMQ_EXCHANGE'),
|
||||
routingKey: 'user.delete',
|
||||
},
|
||||
},
|
||||
uri: configService.get<string>('RMQ_URI'),
|
||||
connectionInitOptions: { wait: false },
|
||||
enableControllerDiscovery: true,
|
||||
}),
|
||||
inject: [ConfigService],
|
||||
}),
|
||||
],
|
||||
controllers: [AuthenticationController, AuthenticationMessagerController],
|
||||
imports: [CqrsModule],
|
||||
controllers: [...grpcControllers],
|
||||
providers: [
|
||||
AuthenticationProfile,
|
||||
UsernameProfile,
|
||||
AuthenticationRepository,
|
||||
Messager,
|
||||
ValidateAuthenticationUseCase,
|
||||
CreateAuthenticationUseCase,
|
||||
AddUsernameUseCase,
|
||||
UpdateUsernameUseCase,
|
||||
UpdatePasswordUseCase,
|
||||
DeleteUsernameUseCase,
|
||||
DeleteAuthenticationUseCase,
|
||||
...commandHandlers,
|
||||
...mappers,
|
||||
...repositories,
|
||||
...messageBrokers,
|
||||
...orms,
|
||||
],
|
||||
exports: [
|
||||
PrismaService,
|
||||
AuthenticationMapper,
|
||||
AUTHENTICATION_REPOSITORY,
|
||||
USERNAME_REPOSITORY,
|
||||
],
|
||||
exports: [],
|
||||
})
|
||||
export class AuthenticationModule {}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import { Command, CommandProps } from '@mobicoop/ddd-library';
|
||||
import { Username } from '../../types/username';
|
||||
|
||||
export class AddUsernameCommand extends Command {
|
||||
readonly userId: string;
|
||||
readonly username: Username;
|
||||
|
||||
constructor(props: CommandProps<AddUsernameCommand>) {
|
||||
super(props);
|
||||
this.userId = props.userId;
|
||||
this.username = props.username;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
||||
import { Inject } from '@nestjs/common';
|
||||
import {
|
||||
AggregateID,
|
||||
ConflictException,
|
||||
UniqueConstraintException,
|
||||
} from '@mobicoop/ddd-library';
|
||||
import {
|
||||
AUTHENTICATION_REPOSITORY,
|
||||
USERNAME_REPOSITORY,
|
||||
} from '@modules/authentication/authentication.di-tokens';
|
||||
import { AuthenticationRepositoryPort } from '../../ports/authentication.repository.port';
|
||||
import { UsernameAlreadyExistsException } from '@modules/authentication/core/domain/authentication.errors';
|
||||
import { AddUsernameCommand } from './add-username.command';
|
||||
import { UsernameRepositoryPort } from '../../ports/username.repository.port';
|
||||
import { UsernameEntity } from '@modules/authentication/core/domain/username.entity';
|
||||
|
||||
@CommandHandler(AddUsernameCommand)
|
||||
export class AddUsernameService implements ICommandHandler {
|
||||
constructor(
|
||||
@Inject(AUTHENTICATION_REPOSITORY)
|
||||
private readonly authenticationRepository: AuthenticationRepositoryPort,
|
||||
@Inject(USERNAME_REPOSITORY)
|
||||
private readonly usernameRepository: UsernameRepositoryPort,
|
||||
) {}
|
||||
|
||||
async execute(command: AddUsernameCommand): Promise<AggregateID> {
|
||||
await this.authenticationRepository.findOneById(command.userId, {
|
||||
usernames: true,
|
||||
});
|
||||
try {
|
||||
const newUsername = await UsernameEntity.create({
|
||||
name: command.username.name,
|
||||
userId: command.userId,
|
||||
type: command.username.type,
|
||||
});
|
||||
await this.usernameRepository.insert(newUsername);
|
||||
return newUsername.id;
|
||||
} catch (error: any) {
|
||||
if (error instanceof ConflictException) {
|
||||
throw new UsernameAlreadyExistsException(error);
|
||||
}
|
||||
if (
|
||||
error instanceof UniqueConstraintException &&
|
||||
error.message.includes('username')
|
||||
) {
|
||||
throw new UsernameAlreadyExistsException(error);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { Command, CommandProps } from '@mobicoop/ddd-library';
|
||||
import { Username } from '../types/username';
|
||||
import { Username } from '../../types/username';
|
||||
|
||||
export class CreateAuthenticationCommand extends Command {
|
||||
readonly userId: string;
|
|
@ -6,19 +6,19 @@ import {
|
|||
UniqueConstraintException,
|
||||
} from '@mobicoop/ddd-library';
|
||||
import { CreateAuthenticationCommand } from './create-authentication.command';
|
||||
import { AUTHENTICATION_REPOSITORY } from '@modules/newauthentication/authentication.di-tokens';
|
||||
import { AuthenticationRepositoryPort } from '../ports/authentication.repository.port';
|
||||
import { AuthenticationEntity } from '@modules/newauthentication/core/domain/authentication.entity';
|
||||
import { AUTHENTICATION_REPOSITORY } from '@modules/authentication/authentication.di-tokens';
|
||||
import { AuthenticationRepositoryPort } from '../../ports/authentication.repository.port';
|
||||
import { AuthenticationEntity } from '@modules/authentication/core/domain/authentication.entity';
|
||||
import {
|
||||
AuthenticationAlreadyExistsException,
|
||||
UsernameAlreadyExistsException,
|
||||
} from '@modules/newauthentication/core/domain/authentication.errors';
|
||||
} from '@modules/authentication/core/domain/authentication.errors';
|
||||
|
||||
@CommandHandler(CreateAuthenticationCommand)
|
||||
export class CreateAuthenticationService implements ICommandHandler {
|
||||
constructor(
|
||||
@Inject(AUTHENTICATION_REPOSITORY)
|
||||
private readonly repository: AuthenticationRepositoryPort,
|
||||
private readonly authenticationRepository: AuthenticationRepositoryPort,
|
||||
) {}
|
||||
|
||||
async execute(command: CreateAuthenticationCommand): Promise<AggregateID> {
|
||||
|
@ -29,7 +29,7 @@ export class CreateAuthenticationService implements ICommandHandler {
|
|||
usernames: command.usernames,
|
||||
});
|
||||
try {
|
||||
await this.repository.insert(authentication);
|
||||
await this.authenticationRepository.insert(authentication);
|
||||
return authentication.getProps().userId;
|
||||
} catch (error: any) {
|
||||
if (error instanceof ConflictException) {
|
|
@ -1,9 +1,9 @@
|
|||
import { Inject } from '@nestjs/common';
|
||||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
|
||||
import { DeleteAuthenticationCommand } from './delete-authentication.command';
|
||||
import { AUTHENTICATION_REPOSITORY } from '@modules/newauthentication/authentication.di-tokens';
|
||||
import { AuthenticationRepositoryPort } from '../ports/authentication.repository.port';
|
||||
import { AuthenticationEntity } from '@modules/newauthentication/core/domain/authentication.entity';
|
||||
import { AUTHENTICATION_REPOSITORY } from '@modules/authentication/authentication.di-tokens';
|
||||
import { AuthenticationRepositoryPort } from '../../ports/authentication.repository.port';
|
||||
import { AuthenticationEntity } from '@modules/authentication/core/domain/authentication.entity';
|
||||
|
||||
@CommandHandler(DeleteAuthenticationCommand)
|
||||
export class DeleteAuthenticationService implements ICommandHandler {
|
||||
|
@ -18,9 +18,9 @@ export class DeleteAuthenticationService implements ICommandHandler {
|
|||
usernames: true,
|
||||
});
|
||||
authentication.delete();
|
||||
const deleted: boolean = await this.authenticationRepository.delete(
|
||||
const isDeleted: boolean = await this.authenticationRepository.delete(
|
||||
authentication,
|
||||
);
|
||||
return deleted;
|
||||
return isDeleted;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { RepositoryPort } from '@mobicoop/ddd-library';
|
||||
import { AuthenticationEntity } from '@modules/newauthentication/core/domain/authentication.entity';
|
||||
import { AuthenticationEntity } from '@modules/authentication/core/domain/authentication.entity';
|
||||
|
||||
export type AuthenticationRepositoryPort = RepositoryPort<AuthenticationEntity>;
|
|
@ -0,0 +1,4 @@
|
|||
import { RepositoryPort } from '@mobicoop/ddd-library';
|
||||
import { UsernameEntity } from '../../domain/username.entity';
|
||||
|
||||
export type UsernameRepositoryPort = RepositoryPort<UsernameEntity>;
|
|
@ -0,0 +1,6 @@
|
|||
import { Type } from '@modules/authentication/core/domain/username.types';
|
||||
|
||||
export type Username = {
|
||||
name: string;
|
||||
type: Type;
|
||||
};
|
|
@ -4,7 +4,7 @@ import {
|
|||
AuthenticationProps,
|
||||
CreateAuthenticationProps,
|
||||
} from './authentication.types';
|
||||
import { AuthenticationCreatedDomainEvent } from './events/authentication-created.domain-events';
|
||||
import { AuthenticationCreatedDomainEvent } from './events/authentication-created.domain-event';
|
||||
import { AuthenticationDeletedDomainEvent } from './events/authentication-deleted.domain-event';
|
||||
|
||||
export class AuthenticationEntity extends AggregateRoot<AuthenticationProps> {
|
|
@ -0,0 +1,7 @@
|
|||
import { DomainEvent, DomainEventProps } from '@mobicoop/ddd-library';
|
||||
|
||||
export class UsernameAddedDomainEvent extends DomainEvent {
|
||||
constructor(props: DomainEventProps<UsernameAddedDomainEvent>) {
|
||||
super(props);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import { AggregateID, AggregateRoot } from '@mobicoop/ddd-library';
|
||||
import { UsernameProps } from './username.types';
|
||||
import { UsernameAddedDomainEvent } from './events/username-added.domain-event';
|
||||
|
||||
export class UsernameEntity extends AggregateRoot<UsernameProps> {
|
||||
protected readonly _id: AggregateID;
|
||||
|
||||
static create = async (create: UsernameProps): Promise<UsernameEntity> => {
|
||||
const props: UsernameProps = { ...create };
|
||||
const username = new UsernameEntity({
|
||||
id: props.name,
|
||||
props: {
|
||||
name: props.name,
|
||||
userId: props.userId,
|
||||
type: props.type,
|
||||
},
|
||||
});
|
||||
username.addEvent(
|
||||
new UsernameAddedDomainEvent({ aggregateId: props.name }),
|
||||
);
|
||||
return username;
|
||||
};
|
||||
|
||||
validate(): void {
|
||||
// entity business rules validation to protect it's invariant before saving entity to a database
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
// All properties that a Username has
|
||||
export interface UsernameProps {
|
||||
name: string;
|
||||
userId?: string;
|
||||
type: Type;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
LoggerBase,
|
||||
|
@ -6,7 +6,7 @@ import {
|
|||
PrismaRepositoryBase,
|
||||
} from '@mobicoop/ddd-library';
|
||||
import { AuthenticationEntity } from '../core/domain/authentication.entity';
|
||||
import { AuthenticationRepositoryPort } from '../core/application/commands/ports/authentication.repository.port';
|
||||
import { AuthenticationRepositoryPort } from '../core/application/ports/authentication.repository.port';
|
||||
import { PrismaService } from './prisma.service';
|
||||
import { AuthenticationMapper } from '../authentication.mapper';
|
||||
import { MESSAGE_PUBLISHER } from '@src/app.di-tokens';
|
||||
|
@ -57,12 +57,11 @@ export class AuthenticationRepository
|
|||
prisma,
|
||||
mapper,
|
||||
eventEmitter,
|
||||
new LoggerBase(
|
||||
AuthenticationRepository.name,
|
||||
'logging',
|
||||
'auth',
|
||||
new LoggerBase({
|
||||
logger: new Logger(AuthenticationRepository.name),
|
||||
domain: 'auth',
|
||||
messagePublisher,
|
||||
),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
LoggerBase,
|
||||
MessagePublisherPort,
|
||||
PrismaRepositoryBase,
|
||||
} from '@mobicoop/ddd-library';
|
||||
import { PrismaService } from './prisma.service';
|
||||
import { MESSAGE_PUBLISHER } from '@src/app.di-tokens';
|
||||
import { UsernameEntity } from '../core/domain/username.entity';
|
||||
import { UsernameRepositoryPort } from '../core/application/ports/username.repository.port';
|
||||
import { UsernameMapper } from '../username.mapper';
|
||||
|
||||
export type UsernameModel = {
|
||||
username: string;
|
||||
authUuid: string;
|
||||
type: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
|
||||
/**
|
||||
* Repository is used for retrieving/saving domain entities
|
||||
* */
|
||||
@Injectable()
|
||||
export class UsernameRepository
|
||||
extends PrismaRepositoryBase<UsernameEntity, UsernameModel, UsernameModel>
|
||||
implements UsernameRepositoryPort
|
||||
{
|
||||
constructor(
|
||||
prisma: PrismaService,
|
||||
mapper: UsernameMapper,
|
||||
eventEmitter: EventEmitter2,
|
||||
@Inject(MESSAGE_PUBLISHER)
|
||||
protected readonly messagePublisher: MessagePublisherPort,
|
||||
) {
|
||||
super(
|
||||
prisma.username,
|
||||
prisma,
|
||||
mapper,
|
||||
eventEmitter,
|
||||
new LoggerBase({
|
||||
logger: new Logger(UsernameRepository.name),
|
||||
domain: 'auth',
|
||||
messagePublisher,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import { ResponseBase } from '@mobicoop/ddd-library';
|
||||
|
||||
export class UsernameResponseDto extends ResponseBase {}
|
|
@ -0,0 +1,49 @@
|
|||
import {
|
||||
AggregateID,
|
||||
IdResponse,
|
||||
RpcExceptionCode,
|
||||
RpcValidationPipe,
|
||||
} from '@mobicoop/ddd-library';
|
||||
import { Controller, UsePipes } from '@nestjs/common';
|
||||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { UsernameAlreadyExistsException } from '@modules/authentication/core/domain/authentication.errors';
|
||||
import { AddUsernameRequestDto } from './dtos/add-username.request.dto';
|
||||
import { AddUsernameCommand } from '@modules/authentication/core/application/commands/add-usernames/add-username.command';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
whitelist: true,
|
||||
forbidUnknownValues: false,
|
||||
}),
|
||||
)
|
||||
@Controller()
|
||||
export class AddUsernameGrpcController {
|
||||
constructor(private readonly commandBus: CommandBus) {}
|
||||
|
||||
@GrpcMethod('AuthenticationService', 'AddUsername')
|
||||
async addUsername(data: AddUsernameRequestDto): Promise<IdResponse> {
|
||||
try {
|
||||
const aggregateID: AggregateID = await this.commandBus.execute(
|
||||
new AddUsernameCommand({
|
||||
userId: data.userId,
|
||||
username: {
|
||||
name: data.name,
|
||||
type: data.type,
|
||||
},
|
||||
}),
|
||||
);
|
||||
return new IdResponse(aggregateID);
|
||||
} catch (error: any) {
|
||||
if (error instanceof UsernameAlreadyExistsException)
|
||||
throw new RpcException({
|
||||
code: RpcExceptionCode.ALREADY_EXISTS,
|
||||
message: error.message,
|
||||
});
|
||||
throw new RpcException({
|
||||
code: RpcExceptionCode.UNKNOWN,
|
||||
message: error.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,8 +8,8 @@ import { Controller, UsePipes } from '@nestjs/common';
|
|||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { CreateAuthenticationRequestDto } from './dtos/create-authentication.request.dto';
|
||||
import { CreateAuthenticationCommand } from '@modules/newauthentication/core/application/commands/create-authentication/create-authentication.command';
|
||||
import { AuthenticationAlreadyExistsException } from '@modules/newauthentication/core/domain/authentication.errors';
|
||||
import { CreateAuthenticationCommand } from '@modules/authentication/core/application/commands/create-authentication/create-authentication.command';
|
||||
import { AuthenticationAlreadyExistsException } from '@modules/authentication/core/domain/authentication.errors';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
|
@ -7,7 +7,7 @@ import {
|
|||
import { Controller, UsePipes } from '@nestjs/common';
|
||||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { DeleteAuthenticationCommand } from '@modules/newauthentication/core/application/commands/delete-authentication/delete-authentication.command';
|
||||
import { DeleteAuthenticationCommand } from '@modules/authentication/core/application/commands/delete-authentication/delete-authentication.command';
|
||||
import { DeleteAuthenticationRequestDto } from './dtos/delete-authentication.request.dto';
|
||||
|
||||
@UsePipes(
|
|
@ -0,0 +1,8 @@
|
|||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
import { UsernameDto } from './username.dto';
|
||||
|
||||
export class AddUsernameRequestDto extends UsernameDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
userId: string;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { Type } from '@modules/authentication/core/domain/username.types';
|
||||
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
|
||||
import { IsValidUsername } from './validators/decorators/is-valid-username.decorator';
|
||||
|
||||
export class UsernameDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@IsValidUsername({
|
||||
message: 'Invalid username',
|
||||
})
|
||||
name: string;
|
||||
|
||||
@IsEnum(Type)
|
||||
@IsNotEmpty()
|
||||
type: Type;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { Type } from '@modules/authentication/core/domain/username.types';
|
||||
import {
|
||||
registerDecorator,
|
||||
ValidationOptions,
|
||||
ValidationArguments,
|
||||
isEmail,
|
||||
isPhoneNumber,
|
||||
} from 'class-validator';
|
||||
|
||||
export function IsValidUsername(validationOptions?: ValidationOptions) {
|
||||
return function (object: any, propertyName: string) {
|
||||
registerDecorator({
|
||||
name: 'isValidUsername',
|
||||
target: object.constructor,
|
||||
propertyName: propertyName,
|
||||
options: validationOptions,
|
||||
validator: {
|
||||
validate(value: any, args: ValidationArguments) {
|
||||
const usernameType: Type = args.object['type'];
|
||||
switch (usernameType) {
|
||||
case Type.PHONE:
|
||||
return isPhoneNumber(value);
|
||||
case Type.EMAIL:
|
||||
return isEmail(value);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
import { IdResponse } from '@mobicoop/ddd-library';
|
||||
import { RpcExceptionCode } from '@mobicoop/ddd-library';
|
||||
import { UsernameAlreadyExistsException } from '@modules/authentication/core/domain/authentication.errors';
|
||||
import { Type } from '@modules/authentication/core/domain/username.types';
|
||||
import { AddUsernameGrpcController } from '@modules/authentication/interface/grpc-controllers/add-username.grpc.controller';
|
||||
import { AddUsernameRequestDto } from '@modules/authentication/interface/grpc-controllers/dtos/add-username.request.dto';
|
||||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { RpcException } from '@nestjs/microservices';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
const addUsernameRequest: AddUsernameRequestDto = {
|
||||
userId: '78153e03-4861-4f58-a705-88526efee53b',
|
||||
name: 'john.doe@email.com',
|
||||
type: Type.EMAIL,
|
||||
};
|
||||
|
||||
const mockCommandBus = {
|
||||
execute: jest
|
||||
.fn()
|
||||
.mockImplementationOnce(() => 'john.doe@email.com')
|
||||
.mockImplementationOnce(() => {
|
||||
throw new UsernameAlreadyExistsException();
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
throw new Error();
|
||||
}),
|
||||
};
|
||||
|
||||
describe('Add Username Grpc Controller', () => {
|
||||
let addUsernameGrpcController: AddUsernameGrpcController;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
{
|
||||
provide: CommandBus,
|
||||
useValue: mockCommandBus,
|
||||
},
|
||||
AddUsernameGrpcController,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
addUsernameGrpcController = module.get<AddUsernameGrpcController>(
|
||||
AddUsernameGrpcController,
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(addUsernameGrpcController).toBeDefined();
|
||||
});
|
||||
|
||||
it('should add a new username', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
const result: IdResponse = await addUsernameGrpcController.addUsername(
|
||||
addUsernameRequest,
|
||||
);
|
||||
expect(result).toBeInstanceOf(IdResponse);
|
||||
expect(result.id).toBe('john.doe@email.com');
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw a dedicated RpcException if username already exists', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
expect.assertions(3);
|
||||
try {
|
||||
await addUsernameGrpcController.addUsername(addUsernameRequest);
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(RpcException);
|
||||
expect(e.error.code).toBe(RpcExceptionCode.ALREADY_EXISTS);
|
||||
}
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw a generic RpcException', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
expect.assertions(3);
|
||||
try {
|
||||
await addUsernameGrpcController.addUsername(addUsernameRequest);
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(RpcException);
|
||||
expect(e.error.code).toBe(RpcExceptionCode.UNKNOWN);
|
||||
}
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,99 @@
|
|||
import { IdResponse } from '@mobicoop/ddd-library';
|
||||
import { RpcExceptionCode } from '@mobicoop/ddd-library';
|
||||
import { AuthenticationAlreadyExistsException } from '@modules/authentication/core/domain/authentication.errors';
|
||||
import { Type } from '@modules/authentication/core/domain/username.types';
|
||||
import { CreateAuthenticationGrpcController } from '@modules/authentication/interface/grpc-controllers/create-authentication.grpc.controller';
|
||||
import { CreateAuthenticationRequestDto } from '@modules/authentication/interface/grpc-controllers/dtos/create-authentication.request.dto';
|
||||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { RpcException } from '@nestjs/microservices';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
const createAuthenticationRequest: CreateAuthenticationRequestDto = {
|
||||
userId: '78153e03-4861-4f58-a705-88526efee53b',
|
||||
password: 'John123',
|
||||
usernames: [
|
||||
{
|
||||
name: 'john.doe@email.com',
|
||||
type: Type.EMAIL,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const mockCommandBus = {
|
||||
execute: jest
|
||||
.fn()
|
||||
.mockImplementationOnce(() => '78153e03-4861-4f58-a705-88526efee53b')
|
||||
.mockImplementationOnce(() => {
|
||||
throw new AuthenticationAlreadyExistsException();
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
throw new Error();
|
||||
}),
|
||||
};
|
||||
|
||||
describe('Create Authentication Grpc Controller', () => {
|
||||
let createAuthenticationGrpcController: CreateAuthenticationGrpcController;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
{
|
||||
provide: CommandBus,
|
||||
useValue: mockCommandBus,
|
||||
},
|
||||
CreateAuthenticationGrpcController,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
createAuthenticationGrpcController =
|
||||
module.get<CreateAuthenticationGrpcController>(
|
||||
CreateAuthenticationGrpcController,
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(createAuthenticationGrpcController).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create a new authentication', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
const result: IdResponse = await createAuthenticationGrpcController.create(
|
||||
createAuthenticationRequest,
|
||||
);
|
||||
expect(result).toBeInstanceOf(IdResponse);
|
||||
expect(result.id).toBe('78153e03-4861-4f58-a705-88526efee53b');
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw a dedicated RpcException if authentication already exists', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
expect.assertions(3);
|
||||
try {
|
||||
await createAuthenticationGrpcController.create(
|
||||
createAuthenticationRequest,
|
||||
);
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(RpcException);
|
||||
expect(e.error.code).toBe(RpcExceptionCode.ALREADY_EXISTS);
|
||||
}
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw a generic RpcException', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
expect.assertions(3);
|
||||
try {
|
||||
await createAuthenticationGrpcController.create(
|
||||
createAuthenticationRequest,
|
||||
);
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(RpcException);
|
||||
expect(e.error.code).toBe(RpcExceptionCode.UNKNOWN);
|
||||
}
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,108 @@
|
|||
import {
|
||||
DatabaseErrorException,
|
||||
NotFoundException,
|
||||
} from '@mobicoop/ddd-library';
|
||||
import { RpcExceptionCode } from '@mobicoop/ddd-library';
|
||||
import { DeleteAuthenticationGrpcController } from '@modules/authentication/interface/grpc-controllers/delete-authentication.grpc.controller';
|
||||
import { DeleteAuthenticationRequestDto } from '@modules/authentication/interface/grpc-controllers/dtos/delete-authentication.request.dto';
|
||||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { RpcException } from '@nestjs/microservices';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
const deleteAuthenticationRequest: DeleteAuthenticationRequestDto = {
|
||||
userId: '78153e03-4861-4f58-a705-88526efee53b',
|
||||
};
|
||||
|
||||
const mockCommandBus = {
|
||||
execute: jest
|
||||
.fn()
|
||||
.mockImplementationOnce(() => ({}))
|
||||
.mockImplementationOnce(() => {
|
||||
throw new NotFoundException();
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
throw new DatabaseErrorException();
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
throw new Error();
|
||||
}),
|
||||
};
|
||||
|
||||
describe('Delete Authentication Grpc Controller', () => {
|
||||
let deleteAuthenticationGrpcController: DeleteAuthenticationGrpcController;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
{
|
||||
provide: CommandBus,
|
||||
useValue: mockCommandBus,
|
||||
},
|
||||
DeleteAuthenticationGrpcController,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
deleteAuthenticationGrpcController =
|
||||
module.get<DeleteAuthenticationGrpcController>(
|
||||
DeleteAuthenticationGrpcController,
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(deleteAuthenticationGrpcController).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create a new authentication', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
await deleteAuthenticationGrpcController.delete(
|
||||
deleteAuthenticationRequest,
|
||||
);
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw a dedicated RpcException if authentication does not exist', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
expect.assertions(3);
|
||||
try {
|
||||
await deleteAuthenticationGrpcController.delete(
|
||||
deleteAuthenticationRequest,
|
||||
);
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(RpcException);
|
||||
expect(e.error.code).toBe(RpcExceptionCode.NOT_FOUND);
|
||||
}
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw a dedicated RpcException if a database error occurs', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
expect.assertions(3);
|
||||
try {
|
||||
await deleteAuthenticationGrpcController.delete(
|
||||
deleteAuthenticationRequest,
|
||||
);
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(RpcException);
|
||||
expect(e.error.code).toBe(RpcExceptionCode.INTERNAL);
|
||||
}
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should throw a generic RpcException', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
expect.assertions(3);
|
||||
try {
|
||||
await deleteAuthenticationGrpcController.delete(
|
||||
deleteAuthenticationRequest,
|
||||
);
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(RpcException);
|
||||
expect(e.error.code).toBe(RpcExceptionCode.UNKNOWN);
|
||||
}
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,57 @@
|
|||
import { Type } from '@modules/authentication/core/domain/username.types';
|
||||
import { IsValidUsername } from '@modules/authentication/interface/grpc-controllers/dtos/validators/decorators/is-valid-username.decorator';
|
||||
import { Validator } from 'class-validator';
|
||||
|
||||
describe('Username decorator', () => {
|
||||
class MyClass {
|
||||
@IsValidUsername({
|
||||
message: 'Invalid username',
|
||||
})
|
||||
name: string;
|
||||
|
||||
type: Type;
|
||||
}
|
||||
it('should return a property decorator has a function', () => {
|
||||
const isValidUsername = IsValidUsername();
|
||||
expect(typeof isValidUsername).toBe('function');
|
||||
});
|
||||
it('should validate a valid phone username', async () => {
|
||||
const myClassInstance = new MyClass();
|
||||
myClassInstance.name = '+33611223344';
|
||||
myClassInstance.type = Type.PHONE;
|
||||
const validator = new Validator();
|
||||
const validation = await validator.validate(myClassInstance);
|
||||
expect(validation.length).toBe(0);
|
||||
});
|
||||
it('should validate a valid email username', async () => {
|
||||
const myClassInstance = new MyClass();
|
||||
myClassInstance.name = 'john.doe@email.com';
|
||||
myClassInstance.type = Type.EMAIL;
|
||||
const validator = new Validator();
|
||||
const validation = await validator.validate(myClassInstance);
|
||||
expect(validation.length).toBe(0);
|
||||
});
|
||||
it('should not validate an invalid phone username', async () => {
|
||||
const myClassInstance = new MyClass();
|
||||
myClassInstance.name = '11223344';
|
||||
myClassInstance.type = Type.PHONE;
|
||||
const validator = new Validator();
|
||||
const validation = await validator.validate(myClassInstance);
|
||||
expect(validation.length).toBe(1);
|
||||
});
|
||||
it('should not validate an invalid email username', async () => {
|
||||
const myClassInstance = new MyClass();
|
||||
myClassInstance.name = 'john.doe.email.com';
|
||||
myClassInstance.type = Type.EMAIL;
|
||||
const validator = new Validator();
|
||||
const validation = await validator.validate(myClassInstance);
|
||||
expect(validation.length).toBe(1);
|
||||
});
|
||||
it('should not validate if type is not set', async () => {
|
||||
const myClassInstance = new MyClass();
|
||||
myClassInstance.name = 'john.doe@email.com';
|
||||
const validator = new Validator();
|
||||
const validation = await validator.validate(myClassInstance);
|
||||
expect(validation.length).toBe(1);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,49 @@
|
|||
import { Mapper } from '@mobicoop/ddd-library';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Type } from './core/domain/username.types';
|
||||
import { UsernameEntity } from './core/domain/username.entity';
|
||||
import { UsernameModel } from './infrastructure/username.repository';
|
||||
import { UsernameResponseDto } from './interface/dtos/username.response.dto';
|
||||
|
||||
/**
|
||||
* Mapper constructs objects that are used in different layers:
|
||||
* Record is an object that is stored in a database,
|
||||
* Entity is an object that is used in application domain layer,
|
||||
* and a ResponseDTO is an object returned to a user (usually as json).
|
||||
*/
|
||||
|
||||
@Injectable()
|
||||
export class UsernameMapper
|
||||
implements
|
||||
Mapper<UsernameEntity, UsernameModel, UsernameModel, UsernameResponseDto>
|
||||
{
|
||||
toPersistence = (entity: UsernameEntity): UsernameModel => {
|
||||
const copy = entity.getProps();
|
||||
const record: UsernameModel = {
|
||||
authUuid: copy.userId,
|
||||
username: copy.name,
|
||||
type: copy.type,
|
||||
createdAt: copy.createdAt,
|
||||
updatedAt: copy.updatedAt,
|
||||
};
|
||||
return record;
|
||||
};
|
||||
|
||||
toDomain = (record: UsernameModel): UsernameEntity => {
|
||||
const entity = new UsernameEntity({
|
||||
id: record.authUuid,
|
||||
createdAt: new Date(record.createdAt),
|
||||
updatedAt: new Date(record.updatedAt),
|
||||
props: {
|
||||
name: record.username,
|
||||
type: Type[record.type],
|
||||
},
|
||||
});
|
||||
return entity;
|
||||
};
|
||||
|
||||
toResponse = (entity: UsernameEntity): UsernameResponseDto => {
|
||||
const response = new UsernameResponseDto(entity);
|
||||
return response;
|
||||
};
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { AuthenticationRepository } from '../authentication/adapters/secondaries/authentication.repository';
|
||||
import { UsernameRepository } from '../authentication/adapters/secondaries/username.repository';
|
||||
import { AuthenticationRepository } from '../oldauthentication/adapters/secondaries/authentication.repository';
|
||||
import { UsernameRepository } from '../oldauthentication/adapters/secondaries/username.repository';
|
||||
import { PrismaService } from './adapters/secondaries/prisma-service';
|
||||
|
||||
@Module({
|
||||
|
|
|
@ -4,7 +4,7 @@ import {
|
|||
HealthIndicator,
|
||||
HealthIndicatorResult,
|
||||
} from '@nestjs/terminus';
|
||||
import { AuthenticationRepository } from '../../../authentication/adapters/secondaries/authentication.repository';
|
||||
import { AuthenticationRepository } from '../../../oldauthentication/adapters/secondaries/authentication.repository';
|
||||
|
||||
@Injectable()
|
||||
export class PrismaHealthIndicatorUseCase extends HealthIndicator {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { HealthServerController } from './adapters/primaries/health-server.controller';
|
||||
import { PrismaHealthIndicatorUseCase } from './domain/usecases/prisma.health-indicator.usecase';
|
||||
import { AuthenticationRepository } from '../authentication/adapters/secondaries/authentication.repository';
|
||||
import { AuthenticationRepository } from '../oldauthentication/adapters/secondaries/authentication.repository';
|
||||
import { DatabaseModule } from '../database/database.module';
|
||||
import { HealthController } from './adapters/primaries/health.controller';
|
||||
import { TerminusModule } from '@nestjs/terminus';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { PrismaHealthIndicatorUseCase } from '../../domain/usecases/prisma.health-indicator.usecase';
|
||||
import { AuthenticationRepository } from '../../../authentication/adapters/secondaries/authentication.repository';
|
||||
import { AuthenticationRepository } from '../../../oldauthentication/adapters/secondaries/authentication.repository';
|
||||
import { PrismaClientKnownRequestError } from '@prisma/client/runtime';
|
||||
import { HealthCheckError, HealthIndicatorResult } from '@nestjs/terminus';
|
||||
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
import { Module, Provider } from '@nestjs/common';
|
||||
import { CreateAuthenticationGrpcController } from './interface/grpc-controllers/create-authentication.grpc.controller';
|
||||
import { CreateAuthenticationService } from './core/application/commands/create-authentication/create-authentication.service';
|
||||
import { AuthenticationMapper } from './authentication.mapper';
|
||||
import { AUTHENTICATION_REPOSITORY } from './authentication.di-tokens';
|
||||
import { AuthenticationRepository } from './infrastructure/authentication.repository';
|
||||
import { PrismaService } from './infrastructure/prisma.service';
|
||||
import { CqrsModule } from '@nestjs/cqrs';
|
||||
import { DeleteAuthenticationGrpcController } from './interface/grpc-controllers/delete-authentication.grpc.controller';
|
||||
import { DeleteAuthenticationService } from './core/application/commands/delete-authentication/delete-authentication.service';
|
||||
import { MESSAGE_PUBLISHER } from '@src/app.di-tokens';
|
||||
import { MessageBrokerPublisher } from '@mobicoop/message-broker-module';
|
||||
|
||||
const grpcControllers = [
|
||||
CreateAuthenticationGrpcController,
|
||||
DeleteAuthenticationGrpcController,
|
||||
];
|
||||
|
||||
const commandHandlers: Provider[] = [
|
||||
CreateAuthenticationService,
|
||||
DeleteAuthenticationService,
|
||||
];
|
||||
|
||||
const mappers: Provider[] = [AuthenticationMapper];
|
||||
|
||||
const repositories: Provider[] = [
|
||||
{
|
||||
provide: AUTHENTICATION_REPOSITORY,
|
||||
useClass: AuthenticationRepository,
|
||||
},
|
||||
];
|
||||
|
||||
const messageBrokers: Provider[] = [
|
||||
{
|
||||
provide: MESSAGE_PUBLISHER,
|
||||
useClass: MessageBrokerPublisher,
|
||||
},
|
||||
];
|
||||
|
||||
const orms: Provider[] = [PrismaService];
|
||||
|
||||
@Module({
|
||||
imports: [CqrsModule],
|
||||
controllers: [...grpcControllers],
|
||||
providers: [
|
||||
...commandHandlers,
|
||||
...mappers,
|
||||
...repositories,
|
||||
...messageBrokers,
|
||||
...orms,
|
||||
],
|
||||
exports: [PrismaService, AuthenticationMapper, AUTHENTICATION_REPOSITORY],
|
||||
})
|
||||
export class AuthenticationModule {}
|
|
@ -1,6 +0,0 @@
|
|||
import { Type } from '@modules/newauthentication/core/domain/username.types';
|
||||
|
||||
export type Username = {
|
||||
name: string;
|
||||
type: Type;
|
||||
};
|
|
@ -1,11 +0,0 @@
|
|||
import { Type } from '@modules/newauthentication/core/domain/username.types';
|
||||
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class UsernameDto {
|
||||
@IsString()
|
||||
name: string;
|
||||
|
||||
@IsEnum(Type)
|
||||
@IsNotEmpty()
|
||||
type: Type;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { CqrsModule } from '@nestjs/cqrs';
|
||||
import { DatabaseModule } from '../database/database.module';
|
||||
import { AuthenticationController } from './adapters/primaries/authentication.controller';
|
||||
import { CreateAuthenticationUseCase } from './domain/usecases/create-authentication.usecase';
|
||||
import { ValidateAuthenticationUseCase } from './domain/usecases/validate-authentication.usecase';
|
||||
import { AuthenticationProfile } from './mappers/authentication.profile';
|
||||
import { AuthenticationRepository } from './adapters/secondaries/authentication.repository';
|
||||
import { UpdateUsernameUseCase } from './domain/usecases/update-username.usecase';
|
||||
import { UsernameProfile } from './mappers/username.profile';
|
||||
import { AddUsernameUseCase } from './domain/usecases/add-username.usecase';
|
||||
import { UpdatePasswordUseCase } from './domain/usecases/update-password.usecase';
|
||||
import { DeleteUsernameUseCase } from './domain/usecases/delete-username.usecase';
|
||||
import { DeleteAuthenticationUseCase } from './domain/usecases/delete-authentication.usecase';
|
||||
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { AuthenticationMessagerController } from './adapters/primaries/authentication-messager.controller';
|
||||
import { Messager } from './adapters/secondaries/messager';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
DatabaseModule,
|
||||
CqrsModule,
|
||||
RabbitMQModule.forRootAsync(RabbitMQModule, {
|
||||
imports: [ConfigModule],
|
||||
useFactory: async (configService: ConfigService) => ({
|
||||
exchanges: [
|
||||
{
|
||||
name: configService.get<string>('RMQ_EXCHANGE'),
|
||||
type: 'topic',
|
||||
},
|
||||
],
|
||||
handlers: {
|
||||
userUpdate: {
|
||||
exchange: configService.get<string>('RMQ_EXCHANGE'),
|
||||
routingKey: 'user.update',
|
||||
},
|
||||
userDelete: {
|
||||
exchange: configService.get<string>('RMQ_EXCHANGE'),
|
||||
routingKey: 'user.delete',
|
||||
},
|
||||
},
|
||||
uri: configService.get<string>('RMQ_URI'),
|
||||
connectionInitOptions: { wait: false },
|
||||
enableControllerDiscovery: true,
|
||||
}),
|
||||
inject: [ConfigService],
|
||||
}),
|
||||
],
|
||||
controllers: [AuthenticationController, AuthenticationMessagerController],
|
||||
providers: [
|
||||
AuthenticationProfile,
|
||||
UsernameProfile,
|
||||
AuthenticationRepository,
|
||||
Messager,
|
||||
ValidateAuthenticationUseCase,
|
||||
CreateAuthenticationUseCase,
|
||||
AddUsernameUseCase,
|
||||
UpdateUsernameUseCase,
|
||||
UpdatePasswordUseCase,
|
||||
DeleteUsernameUseCase,
|
||||
DeleteAuthenticationUseCase,
|
||||
],
|
||||
exports: [],
|
||||
})
|
||||
export class AuthenticationModule {}
|
|
@ -1,5 +1,5 @@
|
|||
import { ArgumentMetadata } from '@nestjs/common';
|
||||
import { ValidateAuthenticationRequest } from '../../../modules/authentication/domain/dtos/validate-authentication.request';
|
||||
import { ValidateAuthenticationRequest } from '../../../modules/oldauthentication/domain/dtos/validate-authentication.request';
|
||||
import { RpcValidationPipe } from '../../pipes/rpc.validation-pipe';
|
||||
|
||||
describe('RpcValidationPipe', () => {
|
||||
|
|
Loading…
Reference in New Issue