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