Skip to content

Commit

Permalink
Merge pull request #1 from leonardodimarchi/feat/password-reset
Browse files Browse the repository at this point in the history
Feat/password-reset
  • Loading branch information
leonardodimarchi committed Dec 24, 2023
2 parents 8f6b8ed + 6d54fa6 commit 4648182
Show file tree
Hide file tree
Showing 50 changed files with 977 additions and 68 deletions.
2 changes: 1 addition & 1 deletion src/modules/auth/domain/errors/incorrect-password.error.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DomainError } from '@shared/domain/domain.error';
import { DomainError } from '@shared/domain/errors/domain.error';

export class IncorrectPasswordError extends Error implements DomainError {
constructor() {
Expand Down
2 changes: 1 addition & 1 deletion src/modules/auth/domain/errors/user-not-found.error.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DomainError } from '@shared/domain/domain.error';
import { DomainError } from '@shared/domain/errors/domain.error';

export class UserNotFoundError extends Error implements DomainError {
constructor(email: string) {
Expand Down
2 changes: 1 addition & 1 deletion src/modules/auth/domain/usecases/login.usecase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { UserEntity } from '@modules/user/domain/entities/user/user.entity';
import { InvalidEmailError } from '@modules/user/domain/errors/invalid-email.error';
import { UserRepository } from '@modules/user/domain/repositories/user.repository';
import { PasswordEncryptionService } from '@modules/user/domain/services/password-encryption.service';
import { UseCase } from '@shared/domain/usecase';
import { Either, Left, Right } from '@shared/helpers/either';
import { IncorrectPasswordError } from '../errors/incorrect-password.error';
import { UserNotFoundError } from '../errors/user-not-found.error';
import { UseCase } from '@shared/domain/usecases/usecase';

export interface LoginUseCaseInput {
email: string;
Expand Down
5 changes: 4 additions & 1 deletion src/modules/course/domain/entities/course/course.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { UserEntity } from '@modules/user/domain/entities/user/user.entity';
import { BaseEntity, BaseEntityProps } from '@shared/domain/base.entity';
import {
BaseEntity,
BaseEntityProps,
} from '@shared/domain/entities/base.entity';
import { Either, Left, Right } from '@shared/helpers/either';
import { Replace } from '@shared/helpers/replace';
import { UUID } from 'crypto';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { UserEntity } from '@modules/user/domain/entities/user/user.entity';
import { BaseEntity, BaseEntityProps } from '@shared/domain/base.entity';
import {
BaseEntity,
BaseEntityProps,
} from '@shared/domain/entities/base.entity';
import { Either, Right } from '@shared/helpers/either';
import { Replace } from '@shared/helpers/replace';
import { UUID } from 'crypto';
Expand Down
10 changes: 5 additions & 5 deletions src/modules/course/domain/errors/course-not-found.error.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { DomainError } from '@shared/domain/domain.error'
import { DomainError } from '@shared/domain/errors/domain.error';

export class CourseNotFoundError extends Error implements DomainError {
public courseId: string
public courseId: string;

constructor(courseId: string) {
super(`Course not found: ${courseId}`)
super(`Course not found: ${courseId}`);

this.courseId = courseId
this.name = 'CourseNotFoundError'
this.courseId = courseId;
this.name = 'CourseNotFoundError';
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DomainError } from '@shared/domain/domain.error';
import { DomainError } from '@shared/domain/errors/domain.error';

export class InstructorNotFoundError extends Error implements DomainError {
public instructorId: string;
Expand Down
2 changes: 1 addition & 1 deletion src/modules/course/domain/errors/invalid-money.error.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DomainError } from "@shared/domain/domain.error";
import { DomainError } from '@shared/domain/errors/domain.error';

export class InvalidMoneyError extends Error implements DomainError {
constructor(money: number, currency: string) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { DomainError } from '@shared/domain/domain.error'
import { DomainError } from '@shared/domain/errors/domain.error';

export class StudentAlreadyEnrolledError extends Error implements DomainError {
public studentId: string
public courseId: string
public studentId: string;
public courseId: string;

constructor(studentId: string, courseId: string) {
super(`Enrollment already exists: ${studentId} at ${courseId}`)
super(`Enrollment already exists: ${studentId} at ${courseId}`);

this.studentId = studentId
this.courseId = courseId
this.name = 'StudentAlreadyEnrolledError'
this.studentId = studentId;
this.courseId = courseId;
this.name = 'StudentAlreadyEnrolledError';
}
}
10 changes: 5 additions & 5 deletions src/modules/course/domain/errors/student-not-found.error.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { DomainError } from '@shared/domain/domain.error'
import { DomainError } from '@shared/domain/errors/domain.error';

export class StudentNotFoundError extends Error implements DomainError {
public studentId: string
public studentId: string;

constructor(studentId: string) {
super(`Student not found: ${studentId}`)
super(`Student not found: ${studentId}`);

this.studentId = studentId
this.name = 'StudentNotFoundError'
this.studentId = studentId;
this.name = 'StudentNotFoundError';
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { UserRepository } from '@modules/user/domain/repositories/user.repository';
import { UseCase } from '@shared/domain/usecase';
import { Either, Left, Right } from '@shared/helpers/either';
import { UUID } from 'crypto';
import { CourseEntity } from '../entities/course/course.entity';
import { InstructorNotFoundError } from '../errors/instructor-not-found.error';
import { InvalidMoneyError } from '../errors/invalid-money.error';
import { CourseRepository } from '../repositories/course.repository';
import { UseCase } from '@shared/domain/usecases/usecase';

export interface CreateCourseUseCaseInput {
title: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { UserRepository } from '@modules/user/domain/repositories/user.repository';
import { UseCase } from '@shared/domain/usecase';
import { Either, Left, Right } from '@shared/helpers/either';
import { UUID } from 'crypto';
import { EnrollmentEntity } from '../entities/enrollment/enrollment.entity';
Expand All @@ -8,6 +7,7 @@ import { StudentAlreadyEnrolledError } from '../errors/student-already-enrolled.
import { StudentNotFoundError } from '../errors/student-not-found.error';
import { CourseRepository } from '../repositories/course.repository';
import { EnrollmentRepository } from '../repositories/enrollment.repository';
import { UseCase } from '@shared/domain/usecases/usecase';

export interface EnrollStudentInCourseUseCaseInput {
studentId: UUID;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { UseCase } from '@shared/domain/usecase';
import { Either, Right } from '@shared/helpers/either';
import { PaginatedEntitiesOptions } from '@shared/infra/database/interfaces/paginated-entities-options.interface.';
import { PaginatedEntities } from '@shared/infra/database/interfaces/paginated-entities.interface';
import { CourseEntity } from '../entities/course/course.entity';
import { CourseRepository } from '../repositories/course.repository';
import { UseCase } from '@shared/domain/usecases/usecase';

export interface GetAllCoursesUseCaseInput {
paginationOptions: PaginatedEntitiesOptions;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { UserEntity } from '@modules/user/domain/entities/user/user.entity';
import {
BaseEntity,
BaseEntityProps,
} from '@shared/domain/entities/base.entity';
import { Either, Right } from '@shared/helpers/either';
import { Replace } from '@shared/helpers/replace';
import { UUID } from 'node:crypto';

export interface PasswordResetEntityProps {
userId: UUID;
user?: UserEntity;
code: string;
validUntil: Date;
used: boolean;
}

export type PasswordResetEntityCreateProps = Replace<
PasswordResetEntityProps,
{
code?: string;
validUntil?: Date;
used?: boolean;
}
>;

export class PasswordResetEntity extends BaseEntity<PasswordResetEntityProps> {
private constructor(
props: PasswordResetEntityProps,
baseEntityProps?: BaseEntityProps,
) {
super(props, baseEntityProps);
Object.freeze(this);
}

static create(
{ userId, code, user, validUntil, used }: PasswordResetEntityCreateProps,
baseEntityProps?: BaseEntityProps,
): Either<Error, PasswordResetEntity> {
const day = 24 * 60 * 60 * 1000;
const tomorrow = new Date(+new Date() + day);

return new Right(
new PasswordResetEntity(
{
userId,
user,
code: code || this.generateCode(),
validUntil: validUntil || tomorrow,
used: used ?? false,
},
baseEntityProps,
),
);
}

static generateCode(): string {
const codeSize = 8;

return [...Array(codeSize)]
.map(() =>
Math.floor(Math.random() * 16)
.toString(16)
.toUpperCase(),
)
.join('');
}

public get userId(): UUID {
return this.props.userId;
}

public get user(): UserEntity | null {
return this.props.user || null;
}

public get code(): string {
return this.props.code;
}

public get validUntil(): Date {
return this.props.validUntil;
}

public get used(): boolean {
return this.props.used;
}

public setAsUsed(): void {
this.props.used = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { DomainError } from '@shared/domain/errors/domain.error';

export class IncorrectOldPasswordError extends Error implements DomainError {
constructor() {
super(`Old password confirmation failed`);

this.name = 'IncorrectOldPasswordError';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { DomainError } from '@shared/domain/errors/domain.error';

export class PasswordResetNotFoundError extends Error implements DomainError {
constructor() {
super(`PasswordReset not found`);

this.name = 'PasswordResetNotFoundError';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { UUID } from 'node:crypto';
import { PasswordResetEntity } from '../entities/password-reset.entity';

export abstract class PasswordResetRepository {
abstract save(entity: PasswordResetEntity): Promise<void>;
abstract getById(id: UUID): Promise<PasswordResetEntity | null>;
abstract getValidByUserId(userId: UUID): Promise<PasswordResetEntity | null>;
abstract getValidByCode(code: string): Promise<PasswordResetEntity | null>;
}
Loading

0 comments on commit 4648182

Please sign in to comment.