mirror of
https://gitlab.com/mobicoop/v3/service/auth.git
synced 2026-01-09 08:52:39 +00:00
add opa, refactor auth to authentication
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { RabbitSubscribe } from '@golevelup/nestjs-rabbitmq';
|
||||
import { Controller } from '@nestjs/common';
|
||||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { UpdateUsernameCommand } from '../../commands/update-username.command';
|
||||
import { Type } from '../../domain/dtos/type.enum';
|
||||
import { UpdateUsernameRequest } from '../../domain/dtos/update-username.request';
|
||||
import { DeleteAuthenticationRequest } from '../../domain/dtos/delete-authentication.request';
|
||||
import { DeleteAuthenticationCommand } from '../../commands/delete-authentication.command';
|
||||
|
||||
@Controller()
|
||||
export class AuthenticationMessagerController {
|
||||
constructor(private readonly _commandBus: CommandBus) {}
|
||||
|
||||
@RabbitSubscribe({
|
||||
exchange: 'user',
|
||||
routingKey: 'update',
|
||||
queue: 'auth-user-update',
|
||||
})
|
||||
public async userUpdatedHandler(message: string) {
|
||||
const updatedUser = JSON.parse(message);
|
||||
if (!updatedUser.hasOwnProperty('uuid')) throw new Error();
|
||||
if (updatedUser.hasOwnProperty('email') && updatedUser.email) {
|
||||
const updateUsernameRequest = new UpdateUsernameRequest();
|
||||
updateUsernameRequest.uuid = updatedUser.uuid;
|
||||
updateUsernameRequest.username = updatedUser.email;
|
||||
updateUsernameRequest.type = Type.EMAIL;
|
||||
await this._commandBus.execute(
|
||||
new UpdateUsernameCommand(updateUsernameRequest),
|
||||
);
|
||||
}
|
||||
if (updatedUser.hasOwnProperty('phone') && updatedUser.phone) {
|
||||
const updateUsernameRequest = new UpdateUsernameRequest();
|
||||
updateUsernameRequest.uuid = updatedUser.uuid;
|
||||
updateUsernameRequest.username = updatedUser.phone;
|
||||
updateUsernameRequest.type = Type.PHONE;
|
||||
await this._commandBus.execute(
|
||||
new UpdateUsernameCommand(updateUsernameRequest),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@RabbitSubscribe({
|
||||
exchange: 'user',
|
||||
routingKey: 'delete',
|
||||
queue: 'auth-user-delete',
|
||||
})
|
||||
public async userDeletedHandler(message: string) {
|
||||
const deletedUser = JSON.parse(message);
|
||||
if (!deletedUser.hasOwnProperty('uuid')) throw new Error();
|
||||
const deleteAuthRequest = new DeleteAuthenticationRequest();
|
||||
deleteAuthRequest.uuid = deletedUser.uuid;
|
||||
await this._commandBus.execute(
|
||||
new DeleteAuthenticationCommand(deleteAuthRequest),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
import { Mapper } from '@automapper/core';
|
||||
import { InjectMapper } from '@automapper/nestjs';
|
||||
import { Controller, UsePipes } from '@nestjs/common';
|
||||
import { CommandBus, QueryBus } from '@nestjs/cqrs';
|
||||
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { DatabaseException } from 'src/modules/database/src/exceptions/DatabaseException';
|
||||
import { AddUsernameCommand } from '../../commands/add-username.command';
|
||||
import { CreateAuthenticationCommand } from '../../commands/create-authentication.command';
|
||||
import { DeleteAuthenticationCommand } from '../../commands/delete-authentication.command';
|
||||
import { DeleteUsernameCommand } from '../../commands/delete-username.command';
|
||||
import { UpdatePasswordCommand } from '../../commands/update-password.command';
|
||||
import { UpdateUsernameCommand } from '../../commands/update-username.command';
|
||||
import { AddUsernameRequest } from '../../domain/dtos/add-username.request';
|
||||
import { CreateAuthenticationRequest } from '../../domain/dtos/create-authentication.request';
|
||||
import { DeleteAuthenticationRequest } from '../../domain/dtos/delete-authentication.request';
|
||||
import { DeleteUsernameRequest } from '../../domain/dtos/delete-username.request';
|
||||
import { UpdatePasswordRequest } from '../../domain/dtos/update-password.request';
|
||||
import { UpdateUsernameRequest } from '../../domain/dtos/update-username.request';
|
||||
import { ValidateAuthRequest } from '../../domain/dtos/validate-authentication.request';
|
||||
import { Authentication } from '../../domain/entities/authentication';
|
||||
import { Username } from '../../domain/entities/username';
|
||||
import { ValidateAuthenticationQuery } from '../../queries/validate-authentication.query';
|
||||
import { AuthenticationPresenter } from './authentication.presenter';
|
||||
import { RpcValidationPipe } from './rpc.validation-pipe';
|
||||
import { UsernamePresenter } from './username.presenter';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
whitelist: true,
|
||||
forbidUnknownValues: false,
|
||||
}),
|
||||
)
|
||||
@Controller()
|
||||
export class AuthenticationController {
|
||||
constructor(
|
||||
private readonly _commandBus: CommandBus,
|
||||
private readonly _queryBus: QueryBus,
|
||||
@InjectMapper() private readonly _mapper: Mapper,
|
||||
) {}
|
||||
|
||||
@GrpcMethod('AuthService', 'Validate')
|
||||
async validate(data: ValidateAuthRequest): Promise<AuthenticationPresenter> {
|
||||
try {
|
||||
const auth: Authentication = await this._queryBus.execute(
|
||||
new ValidateAuthenticationQuery(data.username, data.password),
|
||||
);
|
||||
return this._mapper.map(auth, Authentication, AuthenticationPresenter);
|
||||
} catch (e) {
|
||||
throw new RpcException({
|
||||
code: 7,
|
||||
message: 'Permission denied',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@GrpcMethod('AuthService', 'Create')
|
||||
async createUser(
|
||||
data: CreateAuthenticationRequest,
|
||||
): Promise<AuthenticationPresenter> {
|
||||
try {
|
||||
const auth: Authentication = await this._commandBus.execute(
|
||||
new CreateAuthenticationCommand(data),
|
||||
);
|
||||
return this._mapper.map(auth, Authentication, AuthenticationPresenter);
|
||||
} catch (e) {
|
||||
if (e instanceof DatabaseException) {
|
||||
if (e.message.includes('Already exists')) {
|
||||
throw new RpcException({
|
||||
code: 6,
|
||||
message: 'Auth already exists',
|
||||
});
|
||||
}
|
||||
}
|
||||
throw new RpcException({
|
||||
code: 7,
|
||||
message: 'Permission denied',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@GrpcMethod('AuthService', 'AddUsername')
|
||||
async addUsername(data: AddUsernameRequest): Promise<UsernamePresenter> {
|
||||
try {
|
||||
const username: Username = await this._commandBus.execute(
|
||||
new AddUsernameCommand(data),
|
||||
);
|
||||
|
||||
return this._mapper.map(username, Username, UsernamePresenter);
|
||||
} catch (e) {
|
||||
if (e instanceof DatabaseException) {
|
||||
if (e.message.includes('Already exists')) {
|
||||
throw new RpcException({
|
||||
code: 6,
|
||||
message: 'Username already exists',
|
||||
});
|
||||
}
|
||||
}
|
||||
throw new RpcException({
|
||||
code: 7,
|
||||
message: 'Permission denied',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@GrpcMethod('AuthService', 'UpdateUsername')
|
||||
async updateUsername(
|
||||
data: UpdateUsernameRequest,
|
||||
): Promise<UsernamePresenter> {
|
||||
try {
|
||||
const username: Username = await this._commandBus.execute(
|
||||
new UpdateUsernameCommand(data),
|
||||
);
|
||||
|
||||
return this._mapper.map(username, Username, UsernamePresenter);
|
||||
} catch (e) {
|
||||
if (e instanceof DatabaseException) {
|
||||
if (e.message.includes('Already exists')) {
|
||||
throw new RpcException({
|
||||
code: 6,
|
||||
message: 'Username already exists',
|
||||
});
|
||||
}
|
||||
}
|
||||
throw new RpcException({
|
||||
code: 7,
|
||||
message: 'Permission denied',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@GrpcMethod('AuthService', 'UpdatePassword')
|
||||
async updatePassword(
|
||||
data: UpdatePasswordRequest,
|
||||
): Promise<AuthenticationPresenter> {
|
||||
try {
|
||||
const auth: Authentication = await this._commandBus.execute(
|
||||
new UpdatePasswordCommand(data),
|
||||
);
|
||||
|
||||
return this._mapper.map(auth, Authentication, AuthenticationPresenter);
|
||||
} catch (e) {
|
||||
throw new RpcException({
|
||||
code: 7,
|
||||
message: 'Permission denied',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@GrpcMethod('AuthService', 'DeleteUsername')
|
||||
async deleteUsername(data: DeleteUsernameRequest) {
|
||||
try {
|
||||
return await this._commandBus.execute(new DeleteUsernameCommand(data));
|
||||
} catch (e) {
|
||||
throw new RpcException({
|
||||
code: 7,
|
||||
message: 'Permission denied',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@GrpcMethod('AuthService', 'Delete')
|
||||
async deleteAuth(data: DeleteAuthenticationRequest) {
|
||||
try {
|
||||
return await this._commandBus.execute(
|
||||
new DeleteAuthenticationCommand(data),
|
||||
);
|
||||
} catch (e) {
|
||||
throw new RpcException({
|
||||
code: 7,
|
||||
message: 'Permission denied',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { AutoMap } from '@automapper/classes';
|
||||
|
||||
export class AuthenticationPresenter {
|
||||
@AutoMap()
|
||||
uuid: string;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package authentication;
|
||||
|
||||
service AuthenticationService {
|
||||
rpc Validate(AuthenticationByUsernamePassword) returns (Uuid);
|
||||
rpc Create(Authentication) returns (Uuid);
|
||||
rpc AddUsername(Username) returns (Uuid);
|
||||
rpc UpdatePassword(Password) returns (Uuid);
|
||||
rpc UpdateUsername(Username) returns (Uuid);
|
||||
rpc DeleteUsername(Username) returns (Uuid);
|
||||
rpc Delete(Uuid) returns (Empty);
|
||||
}
|
||||
|
||||
message AuthenticationByUsernamePassword {
|
||||
string username = 1;
|
||||
string password = 2;
|
||||
}
|
||||
|
||||
enum Type {
|
||||
EMAIL = 0;
|
||||
PHONE = 1;
|
||||
}
|
||||
|
||||
message Authentication {
|
||||
string uuid = 1;
|
||||
string username = 2;
|
||||
string password = 3;
|
||||
Type type = 4;
|
||||
}
|
||||
|
||||
message Password {
|
||||
string uuid = 1;
|
||||
string password = 2;
|
||||
}
|
||||
|
||||
message Username {
|
||||
string uuid = 1;
|
||||
string username = 2;
|
||||
Type type = 3;
|
||||
}
|
||||
|
||||
message Uuid {
|
||||
string uuid = 1;
|
||||
}
|
||||
|
||||
message Empty {}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Injectable, ValidationPipe } from '@nestjs/common';
|
||||
import { RpcException } from '@nestjs/microservices';
|
||||
|
||||
@Injectable()
|
||||
export class RpcValidationPipe extends ValidationPipe {
|
||||
createExceptionFactory() {
|
||||
return (validationErrors = []) => {
|
||||
return new RpcException({
|
||||
code: 3,
|
||||
message: this.flattenValidationErrors(validationErrors),
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { AutoMap } from '@automapper/classes';
|
||||
|
||||
export class UsernamePresenter {
|
||||
@AutoMap()
|
||||
uuid: string;
|
||||
|
||||
@AutoMap()
|
||||
username: string;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { IMessageBroker } from '../../domain/interfaces/message-broker';
|
||||
|
||||
@Injectable()
|
||||
export class AuthenticationMessager extends IMessageBroker {
|
||||
constructor(private readonly _amqpConnection: AmqpConnection) {
|
||||
super('auth');
|
||||
}
|
||||
|
||||
publish(routingKey: string, message: string): void {
|
||||
this._amqpConnection.publish(this.exchange, routingKey, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthRepository } from '../../../database/src/domain/auth-repository';
|
||||
import { Authentication } from '../../domain/entities/authentication';
|
||||
|
||||
@Injectable()
|
||||
export class AuthenticationRepository extends AuthRepository<Authentication> {
|
||||
protected _model = 'auth';
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { IMessageBroker } from '../../domain/interfaces/message-broker';
|
||||
|
||||
@Injectable()
|
||||
export class LoggingMessager extends IMessageBroker {
|
||||
constructor(private readonly _amqpConnection: AmqpConnection) {
|
||||
super('logging');
|
||||
}
|
||||
|
||||
publish(routingKey: string, message: string): void {
|
||||
this._amqpConnection.publish(this.exchange, routingKey, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthRepository } from '../../../database/src/domain/auth-repository';
|
||||
import { Username } from '../../domain/entities/username';
|
||||
|
||||
@Injectable()
|
||||
export class UsernameRepository extends AuthRepository<Username> {
|
||||
protected _model = 'username';
|
||||
}
|
||||
Reference in New Issue
Block a user