Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: rate-me validation user refactor scenario #22

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions 3rdparty/rate-me/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module',
},
plugins: ['@typescript-eslint/eslint-plugin'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
root: true,
env: {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
},
};
56 changes: 56 additions & 0 deletions 3rdparty/rate-me/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# compiled output
dist
node_modules
build

# Logs
logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# OS
.DS_Store

# Tests
coverage
.nyc_output

# IDEs and editors
.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# temp directory
.temp
.tmp

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
4 changes: 4 additions & 0 deletions 3rdparty/rate-me/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "all"
}
44 changes: 44 additions & 0 deletions 3rdparty/rate-me/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## rate-me

Rate-me es una aplicación de evaluación de solvencia de ususarios.
Ofrece varios servicios para recuperar información financiera de personas a partir de su DNI / NIE:

- Validación de documento de identidad a partir de la foto
- Consulta de datos financieros a partir del número de documento de identidad
- Rating credicicio de una persona a partir de su documento de identidad

## Instalación

```bash
$ yarn install
```

## Ejecutando la aplicación

```bash
# development
$ yarn run start

# watch mode
$ yarn run start:dev

# production mode
$ yarn run start:prod
```

## Test

```bash
# unit tests
$ yarn run test

# e2e tests
$ yarn run test:e2e

# test coverage
$ yarn run test:cov
```


## Ejercicios propuestos
- [Validar usuarios](./src/validation/validateUser.md)
8 changes: 8 additions & 0 deletions 3rdparty/rate-me/nest-cli.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
}
}
72 changes: 72 additions & 0 deletions 3rdparty/rate-me/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"name": "rate-me",
"version": "0.0.1",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
"@types/node": "^20.3.1",
"@types/supertest": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.42.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.5.0",
"prettier": "^3.0.0",
"source-map-support": "^0.5.21",
"supertest": "^6.3.3",
"ts-jest": "^29.1.0",
"ts-loader": "^9.4.3",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.1.3"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"moduleNameMapper": {
"^~(.*)$": "<rootDir>/src/$1"
},
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
22 changes: 22 additions & 0 deletions 3rdparty/rate-me/src/app.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';

describe('AppController', () => {
let appController: AppController;

beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
controllers: [AppController],
providers: [AppService],
}).compile();

appController = app.get<AppController>(AppController);
});

describe('root', () => {
it('should return "Hello World!"', () => {
expect(appController.getHello()).toBe('Hello World!');
});
});
});
27 changes: 27 additions & 0 deletions 3rdparty/rate-me/src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Body, Controller, Get, Post } from '@nestjs/common';
import { AppService } from './app.service';
import { User } from './types/user';
import { validateUser } from './validation/validateUser';

@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}

@Get()
getHello(): string {
return this.appService.getHello();
}
@Post('user/add')
addUser(@Body() body: any) {
const newUser = { ...body } as User;
if (!validateUser(newUser)) {
throw new Error('Invalid user');
}
//TODO store user
return {
error: null,
success: true,
message: 'User saved',
};
}
}
10 changes: 10 additions & 0 deletions 3rdparty/rate-me/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
8 changes: 8 additions & 0 deletions 3rdparty/rate-me/src/app.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
8 changes: 8 additions & 0 deletions 3rdparty/rate-me/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
10 changes: 10 additions & 0 deletions 3rdparty/rate-me/src/types/user.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type User = {
id?: number;
email: string;
name: string;
surnames: string;
birthDate: string;
referal?: number;
tier: 'premium' | 'regular';
discount: number | null;
};
23 changes: 23 additions & 0 deletions 3rdparty/rate-me/src/utils/UserSequence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export class UserSequence {
private static instance: UserSequence;

private constructor(private next: number) {}

private initialSequence(initial: number) {
this.next = initial++;
}

public static getInstance(): UserSequence {
if (!UserSequence.instance) {
const currentMaxId = Math.random() * 1000;
UserSequence.instance = new UserSequence(currentMaxId + 1);
}
return UserSequence.instance;
}

public getNext(): number {
const next = this.next;
this.next++;
return next;
}
}
15 changes: 15 additions & 0 deletions 3rdparty/rate-me/src/validation/validateUser.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Validar usuarios

En un intento de mejorar nuestro código, contratamos a un freelance que nos salía muy barato para que nos ayudara en el proyecto.
Nos ha entregado una primera parte de lo pactado, la validación de usuarios, pero creemos que algo no está bien. En cambio, los test pasan...
Nuestro departamento interno de IT ha echado un ojo al código y dicen que es incomprensible y que está mal estructurado.
Estas son nuestras reglas de validación de usuarios:


- Todo usuario debe tener un email válido
- Hace poco hemos introducido los usuarios referidos. Vienen a ser usuarios recomendados por otras empresas. Para los usuarios referidos, en las comunicaciones, usamos el email del usuario que los ha recomendado. Entonces, no todos los usuarios deben tener email. Los referidos no tendrán.
- Todo usuario tiene que tener nombre y apellidos.
- Todo usuario tiene que tener una fecha de nacimiento válida.
- En la misma evolución en la que introdujimos usuarios referidos, decidimos que los usuarios que nos recomiendan a otros usuarios se merecían un descuento. Así que definimos dos capas de usuarios:
- Usuarios *regular*: cualquier usuario que no nos ha recomendado a nadie. No tendrá descuento.
- Usuarios *premium*: nos han recomendado otros usuarios, tienen que tener un descuento.
26 changes: 26 additions & 0 deletions 3rdparty/rate-me/src/validation/validateUser.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { User } from 'src/types/user';
import { validateUser } from './validateUser';

describe('validateUser', () => {
const sut = validateUser;
describe('when validating user', () => {

it('should return false if birthday is not valid', () => {
expect(sut({ birthDate: '1976/13/13' } as User)).toBeFalsy();
});

it('should return false if has no name', () => {
expect(sut({ birthDate: '1976/12/11' } as User)).toBeFalsy();
});

it('should return false if has no surnames', () => {
expect(sut({ birthDate: '1976/12/11'} as User)).toBeFalsy();
});

it('should return false if email is invalid', () => {
expect(sut({ birthDate: '1976/12/11', name: 'someName', surnames: 'surnames',
email: 'bad-email'
} as User)).toBeFalsy();
});
});
});
Loading
Loading