feat: initialize the server e2e tests

This commit is contained in:
Ahmed Bouhuolia
2024-12-15 00:49:10 +02:00
parent 05f4b49b58
commit 2ba31148ca
10 changed files with 43 additions and 278 deletions

View File

@@ -1,29 +1,4 @@
import { AuthForgetPasswordService } from './AuthForgetPassword.service';
import { AuthSendResetPasswordService } from './AuthResetPassword.service';
import { AuthSigninService } from './AuthSignin.service';
import { AuthSignupService } from './AuthSignup.service';
export class AuthApplication {
constructor(
private readonly authSigninService: AuthSigninService,
private readonly authSignupService: AuthSignupService,
private readonly authResetPasswordService: AuthSendResetPasswordService,
private readonly authForgetPasswordService: AuthForgetPasswordService,
) {}
async signin(email: string, password: string) {
return this.authSigninService.signIn(email, password);
}
async signup(data: any) {
return this.authSignupService.signup(data);
}
async resetPassword(data: any) {
return this.authResetPasswordService.resetPassword(data);
}
async forgetPassword(data: any) {
return this.authForgetPasswordService.execute(data);
}
}

View File

@@ -1 +0,0 @@
export class AuthForgetPasswordService {}

View File

@@ -1,132 +0,0 @@
import { Injectable, Inject } from '@nestjs/common';
import uniqid from 'uniqid';
import moment from 'moment';
import config from '@/config';
import {
IAuthResetedPasswordEventPayload,
IAuthSendedResetPassword,
IAuthSendingResetPassword,
IPasswordReset,
ISystemUser,
} from '@/interfaces';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import events from '@/subscribers/events';
import { PasswordReset } from '@/system/models';
import { ERRORS } from './_constants';
import { ServiceError } from '@/exceptions';
import { hashPassword } from '@/utils';
@Injectable()
export class AuthSendResetPasswordService {
constructor(
private readonly eventPublisher: EventPublisher,
@Inject('SystemUserRepository') private readonly systemUserRepository: any,
@Inject('PasswordResetModel')
private readonly passwordResetModel: typeof PasswordReset,
) {}
/**
* Generates and retrieve password reset token for the given user email.
* @param {string} email
* @return {<Promise<IPasswordReset>}
*/
public async sendResetPassword(email: string): Promise<PasswordReset> {
const user = await this.validateEmailExistance(email);
const token: string = uniqid();
// Triggers sending reset password event.
await this.eventPublisher.emitAsync(events.auth.sendingResetPassword, {
user,
token,
} as IAuthSendingResetPassword);
// Delete all stored tokens of reset password that associate to the give email.
this.deletePasswordResetToken(email);
// Creates a new password reset row with unique token.
const passwordReset = await this.passwordResetModel
.query()
.insert({ email, token });
// Triggers sent reset password event.
await this.eventPublisher.emitAsync(events.auth.sendResetPassword, {
user,
token,
} as IAuthSendedResetPassword);
return passwordReset;
}
/**
* Resets a user password from given token.
* @param {string} token - Password reset token.
* @param {string} password - New Password.
* @return {Promise<void>}
*/
public async resetPassword(token: string, password: string): Promise<void> {
// Finds the password reset token.
const tokenModel: IPasswordReset = await this.passwordResetModel
.query()
.findOne('token', token);
// In case the password reset token not found throw token invalid error..
if (!tokenModel) {
throw new ServiceError(ERRORS.TOKEN_INVALID);
}
// Different between token creation datetime and current time.
if (
moment().diff(tokenModel.createdAt, 'seconds') >
config.resetPasswordSeconds
) {
// Deletes the expired token by expired token email.
await this.deletePasswordResetToken(tokenModel.email);
throw new ServiceError(ERRORS.TOKEN_EXPIRED);
}
const user = await this.systemUserRepository.findOneByEmail(
tokenModel.email,
);
if (!user) {
throw new ServiceError(ERRORS.USER_NOT_FOUND);
}
const hashedPassword = await hashPassword(password);
await this.systemUserRepository.update(
{ password: hashedPassword },
{ id: user.id },
);
// Deletes the used token.
await this.deletePasswordResetToken(tokenModel.email);
// Triggers `onResetPassword` event.
await this.eventPublisher.emitAsync(events.auth.resetPassword, {
user,
token,
password,
} as IAuthResetedPasswordEventPayload);
}
/**
* Deletes the password reset token by the given email.
* @param {string} email
* @returns {Promise}
*/
private async deletePasswordResetToken(email: string) {
return this.passwordResetModel.query().where('email', email).delete();
}
/**
* Validates the given email existance on the storage.
* @throws {ServiceError}
* @param {string} email - email address.
*/
private async validateEmailExistance(email: string): Promise<ISystemUser> {
const userByEmail = await this.systemUserRepository.findOneByEmail(email);
if (!userByEmail) {
throw new ServiceError(ERRORS.EMAIL_NOT_FOUND);
}
return userByEmail;
}
}

View File

@@ -1,88 +0,0 @@
import { Inject, Injectable } from '@nestjs/common';
import { cloneDeep } from 'lodash';
import { SystemUser } from '../System/models/SystemUser';
import { TenantModel } from '../System/models/TenantModel';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { events } from '@/common/events/events';
import { ServiceError } from '../Items/ServiceError';
import { ERRORS } from '../Items/Items.constants';
import {
IAuthSignedInEventPayload,
IAuthSigningInEventPayload,
IAuthSignInPOJO,
} from './Auth.interfaces';
@Injectable()
export class AuthSigninService {
constructor(
private readonly eventEmitter: EventEmitter2,
@Inject(SystemUser.name)
private readonly systemUserModel: typeof SystemUser,
@Inject(TenantModel.name)
private readonly tenantModel: typeof TenantModel,
) {}
/**
* Validates the given email and password.
* @param {ISystemUser} user
*/
public async validateSignIn(user: SystemUser) {
// Validate if the given user is inactive.
if (!user.active) {
throw new ServiceError(ERRORS.USER_INACTIVE);
}
}
/**
* sign-in and generates JWT token.
* @param {string} email - Email address.
* @param {string} password - Password.
* @return {Promise<{user: IUser, token: string}>}
*/
public async signIn(
email: string,
password: string,
): Promise<IAuthSignInPOJO> {
// Finds the user of the given email address.
const user = await SystemUser.query()
.findOne('email', email)
.modify('inviteAccepted');
// Validate the given email and password.
await this.validateSignIn(user);
// Triggers on signing-in event.
await this.eventEmitter.emitAsync(events.auth.signingIn, {
email,
password,
user,
} as IAuthSigningInEventPayload);
const token = generateToken(user);
// Update the last login at of the user.
// await systemUserRepository.patchLastLoginAt(user.id);
// Triggers `onSignIn` event.
await this.eventEmitter.emitAsync(events.auth.signIn, {
email,
password,
user,
} as IAuthSignedInEventPayload);
const tenant = await this.tenantModel
.query()
.findById(user.tenantId)
.withGraphFetched('metadata');
// Keep the user object immutable.
const outputUser = cloneDeep(user);
// Remove password property from user object.
Reflect.deleteProperty(outputUser, 'password');
return { user: outputUser, token, tenant };
}
}

View File

@@ -1 +0,0 @@
export class AuthSignupService {}