update packages, refactor
This commit is contained in:
parent
54c0718a5d
commit
79f42ae192
File diff suppressed because it is too large
Load Diff
92
package.json
92
package.json
|
@ -30,57 +30,57 @@
|
|||
"migrate:deploy": "npx prisma migrate deploy"
|
||||
},
|
||||
"dependencies": {
|
||||
"@golevelup/nestjs-rabbitmq": "^3.4.0",
|
||||
"@grpc/grpc-js": "^1.8.0",
|
||||
"@grpc/proto-loader": "^0.7.4",
|
||||
"@mobicoop/ddd-library": "^1.0.0",
|
||||
"@mobicoop/health-module": "^2.0.0",
|
||||
"@mobicoop/message-broker-module": "^1.2.0",
|
||||
"@nestjs/axios": "^1.0.1",
|
||||
"@nestjs/common": "^9.0.0",
|
||||
"@nestjs/config": "^2.2.0",
|
||||
"@nestjs/core": "^9.0.0",
|
||||
"@nestjs/cqrs": "^9.0.1",
|
||||
"@nestjs/event-emitter": "^2.0.0",
|
||||
"@nestjs/microservices": "^9.2.1",
|
||||
"@nestjs/platform-express": "^9.0.0",
|
||||
"@nestjs/terminus": "^9.2.2",
|
||||
"@prisma/client": "^4.7.1",
|
||||
"axios": "^1.2.2",
|
||||
"bcrypt": "^5.1.0",
|
||||
"@golevelup/nestjs-rabbitmq": "^4.0.0",
|
||||
"@grpc/grpc-js": "^1.9.5",
|
||||
"@grpc/proto-loader": "^0.7.10",
|
||||
"@mobicoop/ddd-library": "^2.0.0",
|
||||
"@mobicoop/health-module": "^2.3.1",
|
||||
"@mobicoop/message-broker-module": "^2.1.1",
|
||||
"@nestjs/axios": "^3.0.0",
|
||||
"@nestjs/common": "^10.2.7",
|
||||
"@nestjs/config": "^3.1.1",
|
||||
"@nestjs/core": "^10.2.7",
|
||||
"@nestjs/cqrs": "^10.2.6",
|
||||
"@nestjs/event-emitter": "^2.0.2",
|
||||
"@nestjs/microservices": "^10.2.7",
|
||||
"@nestjs/platform-express": "^10.2.7",
|
||||
"@nestjs/terminus": "^10.1.1",
|
||||
"@prisma/client": "^5.4.2",
|
||||
"axios": "^1.5.1",
|
||||
"bcrypt": "^5.1.1",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "^7.2.0"
|
||||
"rimraf": "^5.0.5",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^9.0.0",
|
||||
"@nestjs/schematics": "^9.0.0",
|
||||
"@nestjs/testing": "^9.0.0",
|
||||
"@nestjs/cli": "^10.1.18",
|
||||
"@nestjs/schematics": "^10.0.2",
|
||||
"@nestjs/testing": "^10.2.7",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/jest": "28.1.8",
|
||||
"@types/node": "^16.0.0",
|
||||
"@types/supertest": "^2.0.11",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"dotenv-cli": "^7.2.1",
|
||||
"eslint": "^8.0.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"jest": "28.1.3",
|
||||
"prettier": "^2.3.2",
|
||||
"prisma": "^4.7.1",
|
||||
"source-map-support": "^0.5.20",
|
||||
"supertest": "^6.1.3",
|
||||
"ts-jest": "28.0.8",
|
||||
"ts-loader": "^9.2.3",
|
||||
"ts-node": "^10.0.0",
|
||||
"tsconfig-paths": "4.1.0",
|
||||
"typescript": "^4.7.4",
|
||||
"uuid": "^9.0.0"
|
||||
"@types/express": "^4.17.19",
|
||||
"@types/jest": "29.5.5",
|
||||
"@types/node": "^20.8.6",
|
||||
"@types/supertest": "^2.0.14",
|
||||
"@types/uuid": "^9.0.5",
|
||||
"@typescript-eslint/eslint-plugin": "^6.8.0",
|
||||
"@typescript-eslint/parser": "^6.8.0",
|
||||
"dotenv-cli": "^7.3.0",
|
||||
"eslint": "^8.51.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.1",
|
||||
"jest": "29.7.0",
|
||||
"prettier": "^3.0.3",
|
||||
"prisma": "^5.4.2",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^6.3.3",
|
||||
"ts-jest": "29.1.1",
|
||||
"ts-loader": "^9.5.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "^5.2.2",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
|
@ -91,6 +91,7 @@
|
|||
"modulePathIgnorePatterns": [
|
||||
".module.ts",
|
||||
".dto.ts",
|
||||
".constants.ts",
|
||||
".di-tokens.ts",
|
||||
".response.ts",
|
||||
".port.ts",
|
||||
|
@ -108,6 +109,7 @@
|
|||
"coveragePathIgnorePatterns": [
|
||||
".module.ts",
|
||||
".dto.ts",
|
||||
".constants.ts",
|
||||
".di-tokens.ts",
|
||||
".response.ts",
|
||||
".port.ts",
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// service
|
||||
export const SERVICE_NAME = 'auth';
|
||||
|
||||
// grpc
|
||||
export const GRPC_AUTHENTICATION_PACKAGE_NAME = 'authentication';
|
||||
export const GRPC_AUTHORIZATION_PACKAGE_NAME = 'authorization';
|
||||
export const GRPC_AUTHENTICATION_SERVICE_NAME = 'AuthenticationService';
|
||||
export const GRPC_AUTHORIZATION_SERVICE_NAME = 'AuthorizationService';
|
||||
|
||||
// messaging
|
||||
export const USER_UPDATED_MESSAGE_HANDLER = 'userUpdated';
|
||||
export const USER_UPDATED_ROUTING_KEY = 'user.updated';
|
||||
export const USER_UPDATED_QUEUE = 'auth-user-updated';
|
||||
export const USER_DELETED_MESSAGE_HANDLER = 'userDeleted';
|
||||
export const USER_DELETED_ROUTING_KEY = 'user.deleted';
|
||||
export const USER_DELETED_QUEUE = 'auth-user-deleted';
|
||||
|
||||
// health
|
||||
export const GRPC_HEALTH_PACKAGE_NAME = 'health';
|
||||
export const HEALTH_AUTHENTICATION_REPOSITORY = 'AuthenticationRepository';
|
||||
export const HEALTH_USERNAME_REPOSITORY = 'UsernameRepository';
|
||||
export const HEALTH_CRITICAL_LOGGING_KEY = 'logging.auth.health.crit';
|
|
@ -15,6 +15,12 @@ import {
|
|||
import { MESSAGE_PUBLISHER } from './modules/messager/messager.di-tokens';
|
||||
import { MessagePublisherPort } from '@mobicoop/ddd-library';
|
||||
import { MessagerModule } from './modules/messager/messager.module';
|
||||
import {
|
||||
HEALTH_AUTHENTICATION_REPOSITORY,
|
||||
HEALTH_CRITICAL_LOGGING_KEY,
|
||||
HEALTH_USERNAME_REPOSITORY,
|
||||
SERVICE_NAME,
|
||||
} from './app.constants';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
@ -32,15 +38,15 @@ import { MessagerModule } from './modules/messager/messager.module';
|
|||
usernameRepository: HealthRepositoryPort,
|
||||
messagePublisher: MessagePublisherPort,
|
||||
): Promise<HealthModuleOptions> => ({
|
||||
serviceName: 'auth',
|
||||
criticalLoggingKey: 'logging.auth.health.crit',
|
||||
serviceName: SERVICE_NAME,
|
||||
criticalLoggingKey: HEALTH_CRITICAL_LOGGING_KEY,
|
||||
checkRepositories: [
|
||||
{
|
||||
name: 'AuthenticationRepository',
|
||||
name: HEALTH_AUTHENTICATION_REPOSITORY,
|
||||
repository: authenticationRepository,
|
||||
},
|
||||
{
|
||||
name: 'UsernameRepository',
|
||||
name: HEALTH_USERNAME_REPOSITORY,
|
||||
repository: usernameRepository,
|
||||
},
|
||||
],
|
||||
|
|
15
src/main.ts
15
src/main.ts
|
@ -2,6 +2,11 @@ import { NestFactory } from '@nestjs/core';
|
|||
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
|
||||
import { join } from 'path';
|
||||
import { AppModule } from './app.module';
|
||||
import {
|
||||
GRPC_AUTHENTICATION_PACKAGE_NAME,
|
||||
GRPC_AUTHORIZATION_PACKAGE_NAME,
|
||||
GRPC_HEALTH_PACKAGE_NAME,
|
||||
} from './app.constants';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
@ -11,7 +16,11 @@ async function bootstrap() {
|
|||
app.connectMicroservice<MicroserviceOptions>({
|
||||
transport: Transport.GRPC,
|
||||
options: {
|
||||
package: ['authentication', 'authorization', 'health'],
|
||||
package: [
|
||||
GRPC_AUTHENTICATION_PACKAGE_NAME,
|
||||
GRPC_AUTHORIZATION_PACKAGE_NAME,
|
||||
GRPC_HEALTH_PACKAGE_NAME,
|
||||
],
|
||||
protoPath: [
|
||||
join(
|
||||
__dirname,
|
||||
|
@ -23,11 +32,11 @@ async function bootstrap() {
|
|||
),
|
||||
join(__dirname, 'health.proto'),
|
||||
],
|
||||
url: process.env.SERVICE_URL + ':' + process.env.SERVICE_PORT,
|
||||
url: `${process.env.SERVICE_URL}:${process.env.SERVICE_PORT}`,
|
||||
loader: { keepCase: true, enums: String },
|
||||
},
|
||||
});
|
||||
await app.startAllMicroservices();
|
||||
await app.listen(process.env.HEALTH_SERVICE_PORT);
|
||||
await app.listen(process.env.HEALTH_SERVICE_PORT as unknown as number);
|
||||
}
|
||||
bootstrap();
|
||||
|
|
|
@ -31,14 +31,12 @@ export class AuthenticationMapper
|
|||
const record: AuthenticationWriteModel = {
|
||||
uuid: copy.id,
|
||||
password: copy.password,
|
||||
usernames: copy.usernames
|
||||
? {
|
||||
create: copy.usernames.map((username: UsernameProps) => ({
|
||||
username: username.name,
|
||||
type: username.type,
|
||||
})),
|
||||
}
|
||||
: undefined,
|
||||
usernames: {
|
||||
create: copy.usernames.map((username: UsernameProps) => ({
|
||||
username: username.name,
|
||||
type: username.type,
|
||||
})),
|
||||
},
|
||||
};
|
||||
return record;
|
||||
};
|
||||
|
@ -54,7 +52,7 @@ export class AuthenticationMapper
|
|||
usernames: record.usernames?.map((username: UsernameModel) => ({
|
||||
userId: record.uuid,
|
||||
name: username.username,
|
||||
type: Type[username.type],
|
||||
type: username.type as Type,
|
||||
})),
|
||||
},
|
||||
});
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
AuthenticationAlreadyExistsException,
|
||||
UsernameAlreadyExistsException,
|
||||
} from '@modules/authentication/core/domain/authentication.errors';
|
||||
import { Username } from '../../types/username';
|
||||
|
||||
@CommandHandler(CreateAuthenticationCommand)
|
||||
export class CreateAuthenticationService implements ICommandHandler {
|
||||
|
@ -26,7 +27,11 @@ export class CreateAuthenticationService implements ICommandHandler {
|
|||
await AuthenticationEntity.create({
|
||||
userId: command.userId,
|
||||
password: command.password,
|
||||
usernames: command.usernames,
|
||||
usernames: command.usernames.map((username: Username) => ({
|
||||
name: username.name,
|
||||
type: username.type,
|
||||
userId: command.userId,
|
||||
})),
|
||||
});
|
||||
try {
|
||||
await this.authenticationRepository.insert(authentication);
|
||||
|
|
|
@ -18,9 +18,8 @@ export class DeleteAuthenticationService implements ICommandHandler {
|
|||
usernames: true,
|
||||
});
|
||||
authentication.delete();
|
||||
const isDeleted: boolean = await this.authenticationRepository.delete(
|
||||
authentication,
|
||||
);
|
||||
const isDeleted: boolean =
|
||||
await this.authenticationRepository.delete(authentication);
|
||||
return isDeleted;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,9 +24,8 @@ export class DeleteUsernameService implements ICommandHandler {
|
|||
'Authentication must have at least one username',
|
||||
);
|
||||
username.delete();
|
||||
const isDeleted: boolean = await this.usernameRepository.deleteUsername(
|
||||
username,
|
||||
);
|
||||
const isDeleted: boolean =
|
||||
await this.usernameRepository.deleteUsername(username);
|
||||
return isDeleted;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { UsernameProps } from './username.types';
|
||||
import { NameProps } from './username.types';
|
||||
|
||||
// All properties that an Authentication has
|
||||
export interface AuthenticationProps {
|
||||
userId: string;
|
||||
password: string;
|
||||
usernames: UsernameProps[];
|
||||
usernames: NameProps[];
|
||||
}
|
||||
|
||||
// Properties that are needed for an Authentication creation
|
||||
export interface CreateAuthenticationProps {
|
||||
userId: string;
|
||||
password: string;
|
||||
usernames: UsernameProps[];
|
||||
usernames: NameProps[];
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ export class UsernameEntity extends AggregateRoot<UsernameProps> {
|
|||
const username = new UsernameEntity({
|
||||
id: props.name,
|
||||
props: {
|
||||
name: props.name,
|
||||
userId: props.userId,
|
||||
name: props.name,
|
||||
type: props.type,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
export interface UsernameProps {
|
||||
name: string;
|
||||
userId?: string;
|
||||
type: Type;
|
||||
export interface UsernameProps extends NameProps {
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export interface CreateUsernameProps {
|
||||
name: string;
|
||||
export interface CreateUsernameProps extends NameProps {
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export interface NameProps {
|
||||
name: string;
|
||||
type: Type;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
|
||||
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
@Injectable()
|
||||
|
@ -6,10 +6,4 @@ export class PrismaService extends PrismaClient implements OnModuleInit {
|
|||
async onModuleInit() {
|
||||
await this.$connect();
|
||||
}
|
||||
|
||||
async enableShutdownHooks(app: INestApplication) {
|
||||
this.$on('beforeExit', async () => {
|
||||
await app.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ type UsernameBaseModel = {
|
|||
};
|
||||
|
||||
export type UsernameReadModel = UsernameBaseModel & {
|
||||
createdAt?: Date;
|
||||
updatedAt?: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
|
||||
export type UsernameWriteModel = UsernameBaseModel;
|
||||
|
|
|
@ -10,6 +10,7 @@ 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-username/add-username.command';
|
||||
import { GRPC_AUTHENTICATION_SERVICE_NAME } from '@src/app.constants';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
|
@ -21,7 +22,7 @@ import { AddUsernameCommand } from '@modules/authentication/core/application/com
|
|||
export class AddUsernameGrpcController {
|
||||
constructor(private readonly commandBus: CommandBus) {}
|
||||
|
||||
@GrpcMethod('AuthenticationService', 'AddUsername')
|
||||
@GrpcMethod(GRPC_AUTHENTICATION_SERVICE_NAME, 'AddUsername')
|
||||
async addUsername(data: AddUsernameRequestDto): Promise<IdResponse> {
|
||||
try {
|
||||
const aggregateID: AggregateID = await this.commandBus.execute(
|
||||
|
|
|
@ -10,6 +10,7 @@ import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
|||
import { CreateAuthenticationRequestDto } from './dtos/create-authentication.request.dto';
|
||||
import { CreateAuthenticationCommand } from '@modules/authentication/core/application/commands/create-authentication/create-authentication.command';
|
||||
import { AuthenticationAlreadyExistsException } from '@modules/authentication/core/domain/authentication.errors';
|
||||
import { GRPC_AUTHENTICATION_SERVICE_NAME } from '@src/app.constants';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
|
@ -21,7 +22,7 @@ import { AuthenticationAlreadyExistsException } from '@modules/authentication/co
|
|||
export class CreateAuthenticationGrpcController {
|
||||
constructor(private readonly commandBus: CommandBus) {}
|
||||
|
||||
@GrpcMethod('AuthenticationService', 'Create')
|
||||
@GrpcMethod(GRPC_AUTHENTICATION_SERVICE_NAME, 'Create')
|
||||
async create(data: CreateAuthenticationRequestDto): Promise<IdResponse> {
|
||||
try {
|
||||
const aggregateID: AggregateID = await this.commandBus.execute(
|
||||
|
|
|
@ -9,6 +9,7 @@ import { CommandBus } from '@nestjs/cqrs';
|
|||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { DeleteAuthenticationCommand } from '@modules/authentication/core/application/commands/delete-authentication/delete-authentication.command';
|
||||
import { DeleteAuthenticationRequestDto } from './dtos/delete-authentication.request.dto';
|
||||
import { GRPC_AUTHENTICATION_SERVICE_NAME } from '@src/app.constants';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
|
@ -20,7 +21,7 @@ import { DeleteAuthenticationRequestDto } from './dtos/delete-authentication.req
|
|||
export class DeleteAuthenticationGrpcController {
|
||||
constructor(private readonly commandBus: CommandBus) {}
|
||||
|
||||
@GrpcMethod('AuthenticationService', 'Delete')
|
||||
@GrpcMethod(GRPC_AUTHENTICATION_SERVICE_NAME, 'Delete')
|
||||
async delete(data: DeleteAuthenticationRequestDto): Promise<void> {
|
||||
try {
|
||||
await this.commandBus.execute(new DeleteAuthenticationCommand(data));
|
||||
|
|
|
@ -9,6 +9,7 @@ import { CommandBus } from '@nestjs/cqrs';
|
|||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { DeleteUsernameRequestDto } from './dtos/delete-username.request.dto';
|
||||
import { DeleteUsernameCommand } from '@modules/authentication/core/application/commands/delete-username/delete-username.command';
|
||||
import { GRPC_AUTHENTICATION_SERVICE_NAME } from '@src/app.constants';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
|
@ -20,7 +21,7 @@ import { DeleteUsernameCommand } from '@modules/authentication/core/application/
|
|||
export class DeleteUsernameGrpcController {
|
||||
constructor(private readonly commandBus: CommandBus) {}
|
||||
|
||||
@GrpcMethod('AuthenticationService', 'DeleteUsername')
|
||||
@GrpcMethod(GRPC_AUTHENTICATION_SERVICE_NAME, 'DeleteUsername')
|
||||
async delete(data: DeleteUsernameRequestDto): Promise<void> {
|
||||
try {
|
||||
await this.commandBus.execute(new DeleteUsernameCommand(data));
|
||||
|
|
|
@ -16,7 +16,7 @@ export function IsValidUsername(validationOptions?: ValidationOptions) {
|
|||
options: validationOptions,
|
||||
validator: {
|
||||
validate(value: any, args: ValidationArguments) {
|
||||
const usernameType: Type = args.object['type'];
|
||||
const usernameType: Type = (args.object as any)['type'];
|
||||
switch (usernameType) {
|
||||
case Type.PHONE:
|
||||
return isPhoneNumber(value);
|
||||
|
|
|
@ -9,6 +9,7 @@ import { CommandBus } from '@nestjs/cqrs';
|
|||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { UpdatePasswordRequestDto } from './dtos/update-password.request.dto';
|
||||
import { UpdatePasswordCommand } from '@modules/authentication/core/application/commands/update-password/update-password.command';
|
||||
import { GRPC_AUTHENTICATION_SERVICE_NAME } from '@src/app.constants';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
|
@ -20,7 +21,7 @@ import { UpdatePasswordCommand } from '@modules/authentication/core/application/
|
|||
export class UpdatePasswordGrpcController {
|
||||
constructor(private readonly commandBus: CommandBus) {}
|
||||
|
||||
@GrpcMethod('AuthenticationService', 'UpdatePassword')
|
||||
@GrpcMethod(GRPC_AUTHENTICATION_SERVICE_NAME, 'UpdatePassword')
|
||||
async updatePassword(data: UpdatePasswordRequestDto): Promise<IdResponse> {
|
||||
try {
|
||||
const aggregateID: AggregateID = await this.commandBus.execute(
|
||||
|
|
|
@ -10,6 +10,7 @@ import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
|||
import { UsernameAlreadyExistsException } from '@modules/authentication/core/domain/authentication.errors';
|
||||
import { UpdateUsernameRequestDto } from './dtos/update-username.request.dto';
|
||||
import { UpdateUsernameCommand } from '@modules/authentication/core/application/commands/update-username/update-username.command';
|
||||
import { GRPC_AUTHENTICATION_SERVICE_NAME } from '@src/app.constants';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
|
@ -21,7 +22,7 @@ import { UpdateUsernameCommand } from '@modules/authentication/core/application/
|
|||
export class UpdateUsernameGrpcController {
|
||||
constructor(private readonly commandBus: CommandBus) {}
|
||||
|
||||
@GrpcMethod('AuthenticationService', 'UpdateUsername')
|
||||
@GrpcMethod(GRPC_AUTHENTICATION_SERVICE_NAME, 'UpdateUsername')
|
||||
async updateUsername(data: UpdateUsernameRequestDto): Promise<IdResponse> {
|
||||
try {
|
||||
const aggregateID: AggregateID = await this.commandBus.execute(
|
||||
|
|
|
@ -9,6 +9,7 @@ import { QueryBus } from '@nestjs/cqrs';
|
|||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { ValidateAuthenticationRequestDto } from './dtos/validate-authentication.request.dto';
|
||||
import { ValidateAuthenticationQuery } from '@modules/authentication/core/application/queries/validate-authentication/validate-authentication.query';
|
||||
import { GRPC_AUTHENTICATION_SERVICE_NAME } from '@src/app.constants';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
|
@ -20,7 +21,7 @@ import { ValidateAuthenticationQuery } from '@modules/authentication/core/applic
|
|||
export class ValidateAuthenticationGrpcController {
|
||||
constructor(private readonly queryBus: QueryBus) {}
|
||||
|
||||
@GrpcMethod('AuthenticationService', 'Validate')
|
||||
@GrpcMethod(GRPC_AUTHENTICATION_SERVICE_NAME, 'Validate')
|
||||
async validate(data: ValidateAuthenticationRequestDto): Promise<IdResponse> {
|
||||
try {
|
||||
const aggregateID: AggregateID = await this.queryBus.execute(
|
||||
|
|
|
@ -2,13 +2,14 @@ import { Injectable } from '@nestjs/common';
|
|||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { RabbitSubscribe } from '@mobicoop/message-broker-module';
|
||||
import { DeleteAuthenticationCommand } from '@modules/authentication/core/application/commands/delete-authentication/delete-authentication.command';
|
||||
import { USER_DELETED_MESSAGE_HANDLER } from '@src/app.constants';
|
||||
|
||||
@Injectable()
|
||||
export class UserDeletedMessageHandler {
|
||||
constructor(private readonly commandBus: CommandBus) {}
|
||||
|
||||
@RabbitSubscribe({
|
||||
name: 'userDeleted',
|
||||
name: USER_DELETED_MESSAGE_HANDLER,
|
||||
})
|
||||
public async userDeleted(message: string) {
|
||||
const deletedUser = JSON.parse(message);
|
||||
|
|
|
@ -3,13 +3,14 @@ import { CommandBus } from '@nestjs/cqrs';
|
|||
import { RabbitSubscribe } from '@mobicoop/message-broker-module';
|
||||
import { Type } from '@modules/authentication/core/domain/username.types';
|
||||
import { UpdateUsernameCommand } from '@modules/authentication/core/application/commands/update-username/update-username.command';
|
||||
import { USER_UPDATED_MESSAGE_HANDLER } from '@src/app.constants';
|
||||
|
||||
@Injectable()
|
||||
export class UserUpdatedMessageHandler {
|
||||
constructor(private readonly commandBus: CommandBus) {}
|
||||
|
||||
@RabbitSubscribe({
|
||||
name: 'userUpdated',
|
||||
name: USER_UPDATED_MESSAGE_HANDLER,
|
||||
})
|
||||
public async userUpdated(message: string) {
|
||||
const updatedUser = JSON.parse(message);
|
||||
|
|
|
@ -147,9 +147,9 @@ describe('AuthenticationRepository', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(updatedAuthentication.uuid).toBe(uuid);
|
||||
expect((updatedAuthentication as any).uuid).toBe(uuid);
|
||||
expect(authenticationToUpdate.updatedAt.getTime()).toBeLessThan(
|
||||
updatedAuthentication.updatedAt.getTime(),
|
||||
(updatedAuthentication as any).updatedAt.getTime(),
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -84,9 +84,8 @@ describe('UsernameRepository', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const username = await usernameRepository.findByName(
|
||||
'john.doe@email.com',
|
||||
);
|
||||
const username =
|
||||
await usernameRepository.findByName('john.doe@email.com');
|
||||
expect(username.id).toBe('john.doe@email.com');
|
||||
});
|
||||
|
||||
|
@ -103,9 +102,8 @@ describe('UsernameRepository', () => {
|
|||
it('should create a username', async () => {
|
||||
const beforeCount = await prismaService.username.count();
|
||||
|
||||
const usernameToCreate: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
const usernameToCreate: UsernameEntity =
|
||||
await UsernameEntity.create(createUsernameProps);
|
||||
await usernameRepository.insert(usernameToCreate);
|
||||
|
||||
const afterCount = await prismaService.username.count();
|
||||
|
@ -122,9 +120,8 @@ describe('UsernameRepository', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const usernameToCreate: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
const usernameToCreate: UsernameEntity =
|
||||
await UsernameEntity.create(createUsernameProps);
|
||||
await expect(
|
||||
usernameRepository.insert(usernameToCreate),
|
||||
).rejects.toBeInstanceOf(UniqueConstraintException);
|
||||
|
@ -141,9 +138,8 @@ describe('UsernameRepository', () => {
|
|||
},
|
||||
});
|
||||
|
||||
const toUpdate: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
const toUpdate: UsernameEntity =
|
||||
await UsernameEntity.create(createUsernameProps);
|
||||
await usernameRepository.updateUsername(
|
||||
usernameToUpdate.username,
|
||||
toUpdate,
|
||||
|
@ -155,16 +151,15 @@ describe('UsernameRepository', () => {
|
|||
},
|
||||
});
|
||||
|
||||
expect(updatedUsername.username).toBe('john.doe@email.com');
|
||||
expect((updatedUsername as any).username).toBe('john.doe@email.com');
|
||||
expect(usernameToUpdate.updatedAt.getTime()).toBeLessThan(
|
||||
updatedUsername.updatedAt.getTime(),
|
||||
(updatedUsername as any).updatedAt.getTime(),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw a DatabaseException if id is unknown', async () => {
|
||||
const toUpdate: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
const toUpdate: UsernameEntity =
|
||||
await UsernameEntity.create(createUsernameProps);
|
||||
|
||||
await expect(
|
||||
usernameRepository.updateUsername('jane.doe@email.com', toUpdate),
|
||||
|
@ -181,9 +176,8 @@ describe('UsernameRepository', () => {
|
|||
username: 'john.doe@email.com',
|
||||
},
|
||||
});
|
||||
const toDelete: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
const toDelete: UsernameEntity =
|
||||
await UsernameEntity.create(createUsernameProps);
|
||||
await usernameRepository.deleteUsername(toDelete);
|
||||
|
||||
const count = await prismaService.username.count();
|
||||
|
@ -191,9 +185,8 @@ describe('UsernameRepository', () => {
|
|||
});
|
||||
|
||||
it('should throw a DatabaseException if username does not exist', async () => {
|
||||
const toDelete: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
const toDelete: UsernameEntity =
|
||||
await UsernameEntity.create(createUsernameProps);
|
||||
await expect(usernameRepository.delete(toDelete)).rejects.toBeInstanceOf(
|
||||
DatabaseErrorException,
|
||||
);
|
||||
|
|
|
@ -82,9 +82,8 @@ describe('Add Username Service', () => {
|
|||
})),
|
||||
});
|
||||
it('should add a new username', async () => {
|
||||
const result: AggregateID = await addUsernameService.execute(
|
||||
addUsernameCommand,
|
||||
);
|
||||
const result: AggregateID =
|
||||
await addUsernameService.execute(addUsernameCommand);
|
||||
expect(result).toBe('john.doe@email.com');
|
||||
});
|
||||
it('should throw a dedicated exception if username already exists for this type', async () => {
|
||||
|
|
|
@ -80,17 +80,15 @@ describe('Authentication password validation', () => {
|
|||
it('should validate a valid password', async () => {
|
||||
const authenticationEntity: AuthenticationEntity =
|
||||
await AuthenticationEntity.create(createAuthenticationProps);
|
||||
const result: boolean = await authenticationEntity.authenticate(
|
||||
'somePassword',
|
||||
);
|
||||
const result: boolean =
|
||||
await authenticationEntity.authenticate('somePassword');
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
it('should not validate an invalid password', async () => {
|
||||
const authenticationEntity: AuthenticationEntity =
|
||||
await AuthenticationEntity.create(createAuthenticationProps);
|
||||
const result: boolean = await authenticationEntity.authenticate(
|
||||
'someWrongPassword',
|
||||
);
|
||||
const result: boolean =
|
||||
await authenticationEntity.authenticate('someWrongPassword');
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,18 +14,16 @@ const createUsernameProps: CreateUsernameProps = {
|
|||
|
||||
describe('Username entity create', () => {
|
||||
it('should create a new username entity', async () => {
|
||||
const usernameEntity: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
const usernameEntity: UsernameEntity =
|
||||
await UsernameEntity.create(createUsernameProps);
|
||||
expect(usernameEntity.id).toBe('john.doe@email.com');
|
||||
expect(usernameEntity.domainEvents.length).toBe(1);
|
||||
});
|
||||
});
|
||||
describe('Username entity update', () => {
|
||||
it('should update a username entity', async () => {
|
||||
const usernameEntity: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
const usernameEntity: UsernameEntity =
|
||||
await UsernameEntity.create(createUsernameProps);
|
||||
usernameEntity.update({
|
||||
name: 'new-john.doe@email.com',
|
||||
});
|
||||
|
@ -38,9 +36,8 @@ describe('Username entity update', () => {
|
|||
});
|
||||
describe('Username entity delete', () => {
|
||||
it('should delete a username entity', async () => {
|
||||
const usernameEntity: UsernameEntity = await UsernameEntity.create(
|
||||
createUsernameProps,
|
||||
);
|
||||
const usernameEntity: UsernameEntity =
|
||||
await UsernameEntity.create(createUsernameProps);
|
||||
usernameEntity.delete();
|
||||
expect(usernameEntity.domainEvents.length).toBe(2);
|
||||
expect(usernameEntity.domainEvents[1]).toBeInstanceOf(
|
||||
|
|
|
@ -85,9 +85,8 @@ describe('Username repository', () => {
|
|||
|
||||
it('should find a username by its name', async () => {
|
||||
jest.spyOn(usernameRepository, 'findOne');
|
||||
const username: UsernameEntity = await usernameRepository.findByName(
|
||||
'john.doe@email.com',
|
||||
);
|
||||
const username: UsernameEntity =
|
||||
await usernameRepository.findByName('john.doe@email.com');
|
||||
expect(usernameRepository.findOne).toHaveBeenCalledTimes(1);
|
||||
expect(usernameRepository.findOne).toHaveBeenCalledWith({
|
||||
username: 'john.doe@email.com',
|
||||
|
|
|
@ -55,9 +55,8 @@ describe('Add Username Grpc Controller', () => {
|
|||
|
||||
it('should add a new username', async () => {
|
||||
jest.spyOn(mockCommandBus, 'execute');
|
||||
const result: IdResponse = await addUsernameGrpcController.addUsername(
|
||||
addUsernameRequest,
|
||||
);
|
||||
const result: IdResponse =
|
||||
await addUsernameGrpcController.addUsername(addUsernameRequest);
|
||||
expect(result).toBeInstanceOf(IdResponse);
|
||||
expect(result.id).toBe('john.doe@email.com');
|
||||
expect(mockCommandBus.execute).toHaveBeenCalledTimes(1);
|
||||
|
|
|
@ -42,15 +42,13 @@ export class UsernameMapper
|
|||
updatedAt: new Date(record.updatedAt),
|
||||
props: {
|
||||
name: record.username,
|
||||
type: Type[record.type],
|
||||
type: record.type as Type,
|
||||
userId: record.authUuid,
|
||||
},
|
||||
});
|
||||
return entity;
|
||||
};
|
||||
|
||||
toResponse = (entity: UsernameEntity): UsernameResponseDto => {
|
||||
const response = new UsernameResponseDto(entity);
|
||||
return response;
|
||||
};
|
||||
toResponse = (entity: UsernameEntity): UsernameResponseDto =>
|
||||
new UsernameResponseDto(entity);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@ export abstract class DecisionMakerPort {
|
|||
abstract decide(
|
||||
domain: Domain,
|
||||
action: Action,
|
||||
context: ContextItem[],
|
||||
context?: ContextItem[],
|
||||
): Promise<boolean>;
|
||||
}
|
||||
|
|
|
@ -21,12 +21,14 @@ export class OpaDecisionMaker extends DecisionMakerPort {
|
|||
decide = async (
|
||||
domain: Domain,
|
||||
action: Action,
|
||||
context: ContextItem[],
|
||||
context?: ContextItem[],
|
||||
): Promise<boolean> => {
|
||||
const reducedContext = context.reduce(
|
||||
(obj, item) => Object.assign(obj, { [item.name]: item.value }),
|
||||
{},
|
||||
);
|
||||
const reducedContext = context
|
||||
? context.reduce(
|
||||
(obj, item) => Object.assign(obj, { [item.name]: item.value }),
|
||||
{},
|
||||
)
|
||||
: undefined;
|
||||
try {
|
||||
const { data } = await lastValueFrom(
|
||||
this.httpService.post<Decision>(
|
||||
|
|
|
@ -5,6 +5,7 @@ import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
|||
import { DecisionRequestDto } from './dtos/decision.request.dto';
|
||||
import { DecisionQuery } from '@modules/authorization/core/application/queries/decision/decision.query';
|
||||
import { DecisionResponseDto } from '../dtos/decision.response.dto';
|
||||
import { GRPC_AUTHORIZATION_SERVICE_NAME } from '@src/app.constants';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
|
@ -16,7 +17,7 @@ import { DecisionResponseDto } from '../dtos/decision.response.dto';
|
|||
export class DecideGrpcController {
|
||||
constructor(private readonly queryBus: QueryBus) {}
|
||||
|
||||
@GrpcMethod('AuthorizationService', 'Decide')
|
||||
@GrpcMethod(GRPC_AUTHORIZATION_SERVICE_NAME, 'Decide')
|
||||
async decide(data: DecisionRequestDto): Promise<DecisionResponseDto> {
|
||||
try {
|
||||
const allow: boolean = await this.queryBus.execute(
|
||||
|
|
|
@ -49,9 +49,8 @@ describe('Decision Query Handler', () => {
|
|||
value: '96d99d44-e0a6-458e-a656-de2a400d60a8',
|
||||
},
|
||||
]);
|
||||
const decision: boolean = await decisionQueryHandler.execute(
|
||||
decisionQuery,
|
||||
);
|
||||
const decision: boolean =
|
||||
await decisionQueryHandler.execute(decisionQuery);
|
||||
expect(decision).toBeTruthy();
|
||||
});
|
||||
it('should return a negative decision', async () => {
|
||||
|
@ -65,9 +64,8 @@ describe('Decision Query Handler', () => {
|
|||
value: '96d99d44-e0a6-458e-a656-de2a400d60a9',
|
||||
},
|
||||
]);
|
||||
const decision: boolean = await decisionQueryHandler.execute(
|
||||
decisionQuery,
|
||||
);
|
||||
const decision: boolean =
|
||||
await decisionQueryHandler.execute(decisionQuery);
|
||||
expect(decision).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,6 +6,15 @@ import {
|
|||
MessageBrokerPublisher,
|
||||
} from '@mobicoop/message-broker-module';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import {
|
||||
SERVICE_NAME,
|
||||
USER_DELETED_MESSAGE_HANDLER,
|
||||
USER_DELETED_QUEUE,
|
||||
USER_DELETED_ROUTING_KEY,
|
||||
USER_UPDATED_MESSAGE_HANDLER,
|
||||
USER_UPDATED_QUEUE,
|
||||
USER_UPDATED_ROUTING_KEY,
|
||||
} from '@src/app.constants';
|
||||
|
||||
const imports = [
|
||||
MessageBrokerModule.forRootAsync({
|
||||
|
@ -14,17 +23,22 @@ const imports = [
|
|||
useFactory: async (
|
||||
configService: ConfigService,
|
||||
): Promise<MessageBrokerModuleOptions> => ({
|
||||
uri: configService.get<string>('MESSAGE_BROKER_URI'),
|
||||
exchange: configService.get<string>('MESSAGE_BROKER_EXCHANGE'),
|
||||
name: 'auth',
|
||||
uri: configService.get<string>('MESSAGE_BROKER_URI') as string,
|
||||
exchange: {
|
||||
name: configService.get<string>('MESSAGE_BROKER_EXCHANGE') as string,
|
||||
durable: configService.get<boolean>(
|
||||
'MESSAGE_BROKER_EXCHANGE_DURABILITY',
|
||||
) as boolean,
|
||||
},
|
||||
name: SERVICE_NAME,
|
||||
handlers: {
|
||||
userUpdated: {
|
||||
routingKey: 'user.updated',
|
||||
queue: 'auth-user-updated',
|
||||
[USER_UPDATED_MESSAGE_HANDLER]: {
|
||||
routingKey: USER_UPDATED_ROUTING_KEY,
|
||||
queue: USER_UPDATED_QUEUE,
|
||||
},
|
||||
userDeleted: {
|
||||
routingKey: 'user.deleted',
|
||||
queue: 'auth-user-deleted',
|
||||
[USER_DELETED_MESSAGE_HANDLER]: {
|
||||
routingKey: USER_DELETED_ROUTING_KEY,
|
||||
queue: USER_DELETED_QUEUE,
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
|
|
@ -12,12 +12,13 @@
|
|||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
"strictNullChecks": true,
|
||||
"noImplicitAny": true,
|
||||
"strictBindCallApply": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"paths": {
|
||||
"@libs/*": ["src/libs/*"],
|
||||
"@modules/*": ["src/modules/*"],
|
||||
"@src/*": ["src/*"]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue