delete authentication, use custom logger
This commit is contained in:
parent
f33f679e12
commit
bbcd2cdb9e
|
@ -6,10 +6,10 @@ HEALTH_SERVICE_PORT=6002
|
||||||
# PRISMA
|
# PRISMA
|
||||||
DATABASE_URL="postgresql://mobicoop:mobicoop@v3-db:5432/mobicoop?schema=auth"
|
DATABASE_URL="postgresql://mobicoop:mobicoop@v3-db:5432/mobicoop?schema=auth"
|
||||||
|
|
||||||
# RABBIT MQ
|
# MESSAGE BROKER
|
||||||
RMQ_URI=amqp://v3-broker:5672
|
MESSAGE_BROKER_URI=amqp://v3-broker:5672
|
||||||
RMQ_EXCHANGE=mobicoop
|
MESSAGE_BROKER_EXCHANGE=mobicoop
|
||||||
|
|
||||||
# OPA
|
# OPA
|
||||||
OPA_IMAGE=openpolicyagent/opa:0.48.0-rootless
|
OPA_IMAGE=openpolicyagent/opa:0.54.0
|
||||||
OPA_URL=http://v3-auth-opa:8181/v1/data/
|
OPA_URL=http://v3-auth-opa:8181/v1/data/
|
||||||
|
|
|
@ -6,5 +6,5 @@ SERVICE_PORT=5002
|
||||||
DATABASE_URL="postgresql://mobicoop:mobicoop@localhost:5432/mobicoop-test?schema=auth"
|
DATABASE_URL="postgresql://mobicoop:mobicoop@localhost:5432/mobicoop-test?schema=auth"
|
||||||
|
|
||||||
# OPA
|
# OPA
|
||||||
OPA_IMAGE=openpolicyagent/opa:0.48.0-rootless
|
OPA_IMAGE=openpolicyagent/opa:0.54.0
|
||||||
OPA_URL=http://v3-auth-opa:8181/v1/data/
|
OPA_URL=http://v3-auth-opa:8181/v1/data/
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
"@grpc/grpc-js": "^1.8.0",
|
"@grpc/grpc-js": "^1.8.0",
|
||||||
"@grpc/proto-loader": "^0.7.4",
|
"@grpc/proto-loader": "^0.7.4",
|
||||||
"@mobicoop/ddd-library": "file:../../packages/dddlibrary",
|
"@mobicoop/ddd-library": "file:../../packages/dddlibrary",
|
||||||
|
"@mobicoop/message-broker-module": "^1.2.0",
|
||||||
"@nestjs/axios": "^1.0.1",
|
"@nestjs/axios": "^1.0.1",
|
||||||
"@nestjs/common": "^9.0.0",
|
"@nestjs/common": "^9.0.0",
|
||||||
"@nestjs/config": "^2.2.0",
|
"@nestjs/config": "^2.2.0",
|
||||||
|
@ -72,6 +73,24 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@acuminous/bitsyntax": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@acuminous/bitsyntax/-/bitsyntax-0.1.2.tgz",
|
||||||
|
"integrity": "sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-more-ints": "~1.0.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"safe-buffer": "~5.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@acuminous/bitsyntax/node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
|
||||||
|
@ -1500,6 +1519,33 @@
|
||||||
"reflect-metadata": "^0.1.12"
|
"reflect-metadata": "^0.1.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mobicoop/message-broker-module": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mobicoop/message-broker-module/-/message-broker-module-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-RoSHHK1GyQ/QVDmm3JS/wBfh171oChvyEp6YWmJd12krFLrPVn9MoEvZdyT3I5J31oBiUabMPle5Kdpw+Nrmww==",
|
||||||
|
"dependencies": {
|
||||||
|
"@golevelup/nestjs-rabbitmq": "^3.6.0",
|
||||||
|
"@types/amqplib": "^0.10.1",
|
||||||
|
"amqplib": "^0.10.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@nestjs/common": "^9.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@mobicoop/message-broker-module/node_modules/amqplib": {
|
||||||
|
"version": "0.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.3.tgz",
|
||||||
|
"integrity": "sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@acuminous/bitsyntax": "^0.1.2",
|
||||||
|
"buffer-more-ints": "~1.0.0",
|
||||||
|
"readable-stream": "1.x >=1.1.9",
|
||||||
|
"url-parse": "~1.5.10"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nestjs/axios": {
|
"node_modules/@nestjs/axios": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-1.0.1.tgz",
|
||||||
|
@ -2189,6 +2235,14 @@
|
||||||
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/amqplib": {
|
||||||
|
"version": "0.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.10.1.tgz",
|
||||||
|
"integrity": "sha512-j6ANKT79ncUDnAs/+9r9eDujxbeJoTjoVu33gHHcaPfmLQaMhvfbH2GqSe8KUM444epAp1Vl3peVOQfZk3UIqA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
"version": "7.20.1",
|
"version": "7.20.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz",
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
"@grpc/grpc-js": "^1.8.0",
|
"@grpc/grpc-js": "^1.8.0",
|
||||||
"@grpc/proto-loader": "^0.7.4",
|
"@grpc/proto-loader": "^0.7.4",
|
||||||
"@mobicoop/ddd-library": "file:../../packages/dddlibrary",
|
"@mobicoop/ddd-library": "file:../../packages/dddlibrary",
|
||||||
|
"@mobicoop/message-broker-module": "^1.2.0",
|
||||||
"@nestjs/axios": "^1.0.1",
|
"@nestjs/axios": "^1.0.1",
|
||||||
"@nestjs/common": "^9.0.0",
|
"@nestjs/common": "^9.0.0",
|
||||||
"@nestjs/config": "^2.2.0",
|
"@nestjs/config": "^2.2.0",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
|
binaryTargets = ["linux-musl", "debian-openssl-3.0.x"]
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export const MESSAGE_PUBLISHER = Symbol();
|
|
@ -1,20 +1,35 @@
|
||||||
import { classes } from '@automapper/classes';
|
// import { classes } from '@automapper/classes';
|
||||||
import { AutomapperModule } from '@automapper/nestjs';
|
// import { AutomapperModule } from '@automapper/nestjs';
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
import { AuthorizationModule } from './modules/authorization/authorization.module';
|
// import { AuthorizationModule } from './modules/authorization/authorization.module';
|
||||||
import { HealthModule } from './modules/health/health.module';
|
// import { HealthModule } from './modules/health/health.module';
|
||||||
import { AuthenticationModule } from '@modules/newauthentication/authentication.module';
|
import { AuthenticationModule } from '@modules/newauthentication/authentication.module';
|
||||||
import { EventEmitterModule } from '@nestjs/event-emitter';
|
import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||||
|
import {
|
||||||
|
MessageBrokerModule,
|
||||||
|
MessageBrokerModuleOptions,
|
||||||
|
} from '@mobicoop/message-broker-module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({ isGlobal: true }),
|
ConfigModule.forRoot({ isGlobal: true }),
|
||||||
EventEmitterModule.forRoot(),
|
EventEmitterModule.forRoot(),
|
||||||
AutomapperModule.forRoot({ strategyInitializer: classes() }),
|
MessageBrokerModule.forRootAsync({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
inject: [ConfigService],
|
||||||
|
useFactory: async (
|
||||||
|
configService: ConfigService,
|
||||||
|
): Promise<MessageBrokerModuleOptions> => ({
|
||||||
|
uri: configService.get<string>('MESSAGE_BROKER_URI'),
|
||||||
|
exchange: configService.get<string>('MESSAGE_BROKER_EXCHANGE'),
|
||||||
|
name: 'auth',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
// AutomapperModule.forRoot({ strategyInitializer: classes() }),
|
||||||
AuthenticationModule,
|
AuthenticationModule,
|
||||||
AuthorizationModule,
|
// AuthorizationModule,
|
||||||
HealthModule,
|
// HealthModule,
|
||||||
],
|
],
|
||||||
controllers: [],
|
controllers: [],
|
||||||
providers: [],
|
providers: [],
|
||||||
|
|
|
@ -49,6 +49,7 @@ export class AuthenticationMapper
|
||||||
createdAt: new Date(record.createdAt),
|
createdAt: new Date(record.createdAt),
|
||||||
updatedAt: new Date(record.updatedAt),
|
updatedAt: new Date(record.updatedAt),
|
||||||
props: {
|
props: {
|
||||||
|
userId: record.uuid,
|
||||||
password: record.password,
|
password: record.password,
|
||||||
usernames: record.usernames.map((username: UsernameModel) => ({
|
usernames: record.usernames.map((username: UsernameModel) => ({
|
||||||
name: username.username,
|
name: username.username,
|
||||||
|
|
|
@ -6,10 +6,20 @@ import { AUTHENTICATION_REPOSITORY } from './authentication.di-tokens';
|
||||||
import { AuthenticationRepository } from './infrastructure/authentication.repository';
|
import { AuthenticationRepository } from './infrastructure/authentication.repository';
|
||||||
import { PrismaService } from './infrastructure/prisma.service';
|
import { PrismaService } from './infrastructure/prisma.service';
|
||||||
import { CqrsModule } from '@nestjs/cqrs';
|
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];
|
const grpcControllers = [
|
||||||
|
CreateAuthenticationGrpcController,
|
||||||
|
DeleteAuthenticationGrpcController,
|
||||||
|
];
|
||||||
|
|
||||||
const commandHandlers: Provider[] = [CreateAuthenticationService];
|
const commandHandlers: Provider[] = [
|
||||||
|
CreateAuthenticationService,
|
||||||
|
DeleteAuthenticationService,
|
||||||
|
];
|
||||||
|
|
||||||
const mappers: Provider[] = [AuthenticationMapper];
|
const mappers: Provider[] = [AuthenticationMapper];
|
||||||
|
|
||||||
|
@ -20,12 +30,25 @@ const repositories: Provider[] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const messageBrokers: Provider[] = [
|
||||||
|
{
|
||||||
|
provide: MESSAGE_PUBLISHER,
|
||||||
|
useClass: MessageBrokerPublisher,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const orms: Provider[] = [PrismaService];
|
const orms: Provider[] = [PrismaService];
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [CqrsModule],
|
imports: [CqrsModule],
|
||||||
controllers: [...grpcControllers],
|
controllers: [...grpcControllers],
|
||||||
providers: [...commandHandlers, ...mappers, ...repositories, ...orms],
|
providers: [
|
||||||
|
...commandHandlers,
|
||||||
|
...mappers,
|
||||||
|
...repositories,
|
||||||
|
...messageBrokers,
|
||||||
|
...orms,
|
||||||
|
],
|
||||||
exports: [PrismaService, AuthenticationMapper, AUTHENTICATION_REPOSITORY],
|
exports: [PrismaService, AuthenticationMapper, AUTHENTICATION_REPOSITORY],
|
||||||
})
|
})
|
||||||
export class AuthenticationModule {}
|
export class AuthenticationModule {}
|
||||||
|
|
|
@ -2,11 +2,13 @@ import { Command, CommandProps } from '@mobicoop/ddd-library';
|
||||||
import { Username } from '../types/username';
|
import { Username } from '../types/username';
|
||||||
|
|
||||||
export class CreateAuthenticationCommand extends Command {
|
export class CreateAuthenticationCommand extends Command {
|
||||||
|
readonly userId: string;
|
||||||
readonly password: string;
|
readonly password: string;
|
||||||
readonly usernames: Username[];
|
readonly usernames: Username[];
|
||||||
|
|
||||||
constructor(props: CommandProps<CreateAuthenticationCommand>) {
|
constructor(props: CommandProps<CreateAuthenticationCommand>) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.userId = props.userId;
|
||||||
this.password = props.password;
|
this.password = props.password;
|
||||||
this.usernames = props.usernames;
|
this.usernames = props.usernames;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Inject } from '@nestjs/common';
|
||||||
import {
|
import {
|
||||||
AggregateID,
|
AggregateID,
|
||||||
ConflictException,
|
ConflictException,
|
||||||
UniqueConflictException,
|
UniqueConstraintException,
|
||||||
} from '@mobicoop/ddd-library';
|
} from '@mobicoop/ddd-library';
|
||||||
import { CreateAuthenticationCommand } from './create-authentication.command';
|
import { CreateAuthenticationCommand } from './create-authentication.command';
|
||||||
import { AUTHENTICATION_REPOSITORY } from '@modules/newauthentication/authentication.di-tokens';
|
import { AUTHENTICATION_REPOSITORY } from '@modules/newauthentication/authentication.di-tokens';
|
||||||
|
@ -22,21 +22,27 @@ export class CreateAuthenticationService implements ICommandHandler {
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(command: CreateAuthenticationCommand): Promise<AggregateID> {
|
async execute(command: CreateAuthenticationCommand): Promise<AggregateID> {
|
||||||
const authentication = await AuthenticationEntity.create({
|
const authentication: AuthenticationEntity =
|
||||||
password: command.password,
|
await AuthenticationEntity.create({
|
||||||
usernames: command.usernames,
|
userId: command.userId,
|
||||||
});
|
password: command.password,
|
||||||
|
usernames: command.usernames,
|
||||||
|
});
|
||||||
try {
|
try {
|
||||||
await this.repository.insert(authentication);
|
await this.repository.insert(authentication);
|
||||||
return authentication.id;
|
return authentication.getProps().userId;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log('error', error.cause);
|
|
||||||
if (error instanceof ConflictException) {
|
if (error instanceof ConflictException) {
|
||||||
throw new AuthenticationAlreadyExistsException(error);
|
throw new AuthenticationAlreadyExistsException(error);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
error instanceof UniqueConflictException &&
|
error instanceof UniqueConstraintException &&
|
||||||
|
error.message.includes('uuid')
|
||||||
|
) {
|
||||||
|
throw new AuthenticationAlreadyExistsException(error);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
error instanceof UniqueConstraintException &&
|
||||||
error.message.includes('username')
|
error.message.includes('username')
|
||||||
) {
|
) {
|
||||||
throw new UsernameAlreadyExistsException(error);
|
throw new UsernameAlreadyExistsException(error);
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Command, CommandProps } from '@mobicoop/ddd-library';
|
||||||
|
|
||||||
|
export class DeleteAuthenticationCommand extends Command {
|
||||||
|
readonly userId: string;
|
||||||
|
|
||||||
|
constructor(props: CommandProps<DeleteAuthenticationCommand>) {
|
||||||
|
super(props);
|
||||||
|
this.userId = props.userId;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
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';
|
||||||
|
|
||||||
|
@CommandHandler(DeleteAuthenticationCommand)
|
||||||
|
export class DeleteAuthenticationService implements ICommandHandler {
|
||||||
|
constructor(
|
||||||
|
@Inject(AUTHENTICATION_REPOSITORY)
|
||||||
|
private readonly authenticationRepository: AuthenticationRepositoryPort,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(command: DeleteAuthenticationCommand): Promise<boolean> {
|
||||||
|
const authentication: AuthenticationEntity =
|
||||||
|
await this.authenticationRepository.findOneById(command.userId, {
|
||||||
|
usernames: true,
|
||||||
|
});
|
||||||
|
authentication.delete();
|
||||||
|
const deleted: boolean = await this.authenticationRepository.delete(
|
||||||
|
authentication,
|
||||||
|
);
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
import { AggregateRoot, AggregateID } from '@mobicoop/ddd-library';
|
import { AggregateRoot, AggregateID } from '@mobicoop/ddd-library';
|
||||||
import { v4 } from 'uuid';
|
|
||||||
import * as bcrypt from 'bcrypt';
|
import * as bcrypt from 'bcrypt';
|
||||||
import {
|
import {
|
||||||
AuthenticationProps,
|
AuthenticationProps,
|
||||||
CreateAuthenticationProps,
|
CreateAuthenticationProps,
|
||||||
} from './authentication.types';
|
} from './authentication.types';
|
||||||
import { AuthenticationCreatedDomainEvent } from './events/authentication-created.domain-events';
|
import { AuthenticationCreatedDomainEvent } from './events/authentication-created.domain-events';
|
||||||
|
import { AuthenticationDeletedDomainEvent } from './events/authentication-deleted.domain-event';
|
||||||
|
|
||||||
export class AuthenticationEntity extends AggregateRoot<AuthenticationProps> {
|
export class AuthenticationEntity extends AggregateRoot<AuthenticationProps> {
|
||||||
protected readonly _id: AggregateID;
|
protected readonly _id: AggregateID;
|
||||||
|
@ -13,22 +13,30 @@ export class AuthenticationEntity extends AggregateRoot<AuthenticationProps> {
|
||||||
static create = async (
|
static create = async (
|
||||||
create: CreateAuthenticationProps,
|
create: CreateAuthenticationProps,
|
||||||
): Promise<AuthenticationEntity> => {
|
): Promise<AuthenticationEntity> => {
|
||||||
const id = v4();
|
|
||||||
const props: AuthenticationProps = { ...create };
|
const props: AuthenticationProps = { ...create };
|
||||||
const hash = await bcrypt.hash(props.password, 10);
|
const hash = await bcrypt.hash(props.password, 10);
|
||||||
const authentication = new AuthenticationEntity({
|
const authentication = new AuthenticationEntity({
|
||||||
id,
|
id: props.userId,
|
||||||
props: {
|
props: {
|
||||||
|
userId: props.userId,
|
||||||
password: hash,
|
password: hash,
|
||||||
usernames: props.usernames,
|
usernames: props.usernames,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
authentication.addEvent(
|
authentication.addEvent(
|
||||||
new AuthenticationCreatedDomainEvent({ aggregateId: id }),
|
new AuthenticationCreatedDomainEvent({ aggregateId: props.userId }),
|
||||||
);
|
);
|
||||||
return authentication;
|
return authentication;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
delete(): void {
|
||||||
|
this.addEvent(
|
||||||
|
new AuthenticationDeletedDomainEvent({
|
||||||
|
aggregateId: this.id,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
validate(): void {
|
validate(): void {
|
||||||
// entity business rules validation to protect it's invariant before saving entity to a database
|
// entity business rules validation to protect it's invariant before saving entity to a database
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,14 @@ import { UsernameProps } from './username.types';
|
||||||
|
|
||||||
// All properties that an Authentication has
|
// All properties that an Authentication has
|
||||||
export interface AuthenticationProps {
|
export interface AuthenticationProps {
|
||||||
|
userId: string;
|
||||||
password: string;
|
password: string;
|
||||||
usernames: UsernameProps[];
|
usernames: UsernameProps[];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Properties that are needed for an Authentication creation
|
// Properties that are needed for an Authentication creation
|
||||||
export interface CreateAuthenticationProps {
|
export interface CreateAuthenticationProps {
|
||||||
|
userId: string;
|
||||||
password: string;
|
password: string;
|
||||||
usernames: UsernameProps[];
|
usernames: UsernameProps[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { DomainEvent, DomainEventProps } from '@mobicoop/ddd-library';
|
||||||
|
|
||||||
|
export class AuthenticationDeletedDomainEvent extends DomainEvent {
|
||||||
|
constructor(props: DomainEventProps<AuthenticationDeletedDomainEvent>) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
import { Entity } from '@mobicoop/ddd-library';
|
|
||||||
import { UsernameProps } from './username.types';
|
|
||||||
|
|
||||||
export class UsernameEntity extends Entity<UsernameProps> {
|
|
||||||
protected _id: string;
|
|
||||||
validate(): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,12 +4,6 @@ export interface UsernameProps {
|
||||||
type: Type;
|
type: Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Properties that are needed for a Username creation
|
|
||||||
export interface CreateUsernameProps {
|
|
||||||
name: string;
|
|
||||||
type: Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum Type {
|
export enum Type {
|
||||||
EMAIL = 'EMAIL',
|
EMAIL = 'EMAIL',
|
||||||
PHONE = 'PHONE',
|
PHONE = 'PHONE',
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { PrismaRepositoryBase } from '@mobicoop/ddd-library';
|
import {
|
||||||
|
LoggerBase,
|
||||||
|
MessagePublisherPort,
|
||||||
|
PrismaRepositoryBase,
|
||||||
|
} from '@mobicoop/ddd-library';
|
||||||
import { AuthenticationEntity } from '../core/domain/authentication.entity';
|
import { AuthenticationEntity } from '../core/domain/authentication.entity';
|
||||||
import { AuthenticationRepositoryPort } from '../core/application/commands/ports/authentication.repository.port';
|
import { AuthenticationRepositoryPort } from '../core/application/commands/ports/authentication.repository.port';
|
||||||
import { PrismaService } from './prisma.service';
|
import { PrismaService } from './prisma.service';
|
||||||
import { AuthenticationMapper } from '../authentication.mapper';
|
import { AuthenticationMapper } from '../authentication.mapper';
|
||||||
|
import { MESSAGE_PUBLISHER } from '@src/app.di-tokens';
|
||||||
|
|
||||||
export type AuthenticationBaseModel = {
|
export type AuthenticationBaseModel = {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
@ -44,13 +49,20 @@ export class AuthenticationRepository
|
||||||
prisma: PrismaService,
|
prisma: PrismaService,
|
||||||
mapper: AuthenticationMapper,
|
mapper: AuthenticationMapper,
|
||||||
eventEmitter: EventEmitter2,
|
eventEmitter: EventEmitter2,
|
||||||
|
@Inject(MESSAGE_PUBLISHER)
|
||||||
|
protected readonly messagePublisher: MessagePublisherPort,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
prisma.auth,
|
prisma.auth,
|
||||||
prisma,
|
prisma,
|
||||||
mapper,
|
mapper,
|
||||||
eventEmitter,
|
eventEmitter,
|
||||||
new Logger(AuthenticationRepository.name),
|
new LoggerBase(
|
||||||
|
AuthenticationRepository.name,
|
||||||
|
'logging',
|
||||||
|
'auth',
|
||||||
|
messagePublisher,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ service AuthenticationService {
|
||||||
rpc UpdatePassword(Password) returns (Id);
|
rpc UpdatePassword(Password) returns (Id);
|
||||||
rpc UpdateUsername(Username) returns (Id);
|
rpc UpdateUsername(Username) returns (Id);
|
||||||
rpc DeleteUsername(Username) returns (Id);
|
rpc DeleteUsername(Username) returns (Id);
|
||||||
rpc Delete(Id) returns (Empty);
|
rpc Delete(UserId) returns (Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
message AuthenticationByUsernamePassword {
|
message AuthenticationByUsernamePassword {
|
||||||
|
@ -18,17 +18,18 @@ message AuthenticationByUsernamePassword {
|
||||||
}
|
}
|
||||||
|
|
||||||
message Authentication {
|
message Authentication {
|
||||||
repeated Username usernames = 1;
|
string userId = 1;
|
||||||
string password = 2;
|
repeated Username usernames = 2;
|
||||||
|
string password = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Password {
|
message Password {
|
||||||
string id = 1;
|
string userId = 1;
|
||||||
string password = 2;
|
string password = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Username {
|
message Username {
|
||||||
string id = 1;
|
string userId = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
string type = 3;
|
string type = 3;
|
||||||
}
|
}
|
||||||
|
@ -37,4 +38,8 @@ message Id {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message UserId {
|
||||||
|
string userId = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message Empty {}
|
message Empty {}
|
||||||
|
|
|
@ -22,7 +22,7 @@ export class CreateAuthenticationGrpcController {
|
||||||
constructor(private readonly commandBus: CommandBus) {}
|
constructor(private readonly commandBus: CommandBus) {}
|
||||||
|
|
||||||
@GrpcMethod('AuthenticationService', 'Create')
|
@GrpcMethod('AuthenticationService', 'Create')
|
||||||
async validate(data: CreateAuthenticationRequestDto): Promise<IdResponse> {
|
async create(data: CreateAuthenticationRequestDto): Promise<IdResponse> {
|
||||||
try {
|
try {
|
||||||
const aggregateID: AggregateID = await this.commandBus.execute(
|
const aggregateID: AggregateID = await this.commandBus.execute(
|
||||||
new CreateAuthenticationCommand(data),
|
new CreateAuthenticationCommand(data),
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import {
|
||||||
|
DatabaseErrorException,
|
||||||
|
NotFoundException,
|
||||||
|
RpcExceptionCode,
|
||||||
|
RpcValidationPipe,
|
||||||
|
} from '@mobicoop/ddd-library';
|
||||||
|
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 { DeleteAuthenticationRequestDto } from './dtos/delete-authentication.request.dto';
|
||||||
|
|
||||||
|
@UsePipes(
|
||||||
|
new RpcValidationPipe({
|
||||||
|
whitelist: true,
|
||||||
|
forbidUnknownValues: false,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
@Controller()
|
||||||
|
export class DeleteAuthenticationGrpcController {
|
||||||
|
constructor(private readonly commandBus: CommandBus) {}
|
||||||
|
|
||||||
|
@GrpcMethod('AuthenticationService', 'Delete')
|
||||||
|
async delete(data: DeleteAuthenticationRequestDto): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.commandBus.execute(new DeleteAuthenticationCommand(data));
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error instanceof NotFoundException)
|
||||||
|
throw new RpcException({
|
||||||
|
code: RpcExceptionCode.NOT_FOUND,
|
||||||
|
message: error.message,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error instanceof DatabaseErrorException)
|
||||||
|
throw new RpcException({
|
||||||
|
code: RpcExceptionCode.INTERNAL,
|
||||||
|
message: error.message,
|
||||||
|
});
|
||||||
|
throw new RpcException({
|
||||||
|
code: RpcExceptionCode.UNKNOWN,
|
||||||
|
message: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,10 @@ import {
|
||||||
import { UsernameDto } from './username.dto';
|
import { UsernameDto } from './username.dto';
|
||||||
|
|
||||||
export class CreateAuthenticationRequestDto {
|
export class CreateAuthenticationRequestDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
userId: string;
|
||||||
|
|
||||||
@Type(() => UsernameDto)
|
@Type(() => UsernameDto)
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@ArrayMinSize(1)
|
@ArrayMinSize(1)
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class DeleteAuthenticationRequestDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
userId: string;
|
||||||
|
}
|
Loading…
Reference in New Issue