Configuración Node.js y Express MVC
Configuración Node.js y Express MVC
- Instalar dependencias:
o Existen dos tipos de dependencias:
Dependencias de desarrollo: que solo usas mientras desarrollas el
proyecto. Ejemplo:
MySQL o gestor local de bases de datos
Dependencias que requiere el proyecto para funcionar correctamente.
Ejemplo:
Un sistema de pagos dentro de la aplicación.
o Instalar Express:
npm install express
Se nos creara una carpeta llamada node_modules, que es donde
estarán las librerias y dependencias que instalamos.
Y nuestro package-json que es donde veremos las dependencias
de las dependencias del proyecto.
En el archivo [Link] borramos todo “dependencies”
- "dependencies": {
- "express": "^4.18.1"
- }
o
Para instalar dependencias:
o npm i -D express
- "devDependencies": {
- "express": "^4.18.1"
- }
o Hace que el hosting ignore esas dependencias para que no
las instale automáticamente
o Pero en este caso express es una dependencia normal por
lo que regresamos a instalarlo normalmente.
o Para instalarlo nuevamente normal:
npm install express
- Como llamar el código de [Link]
o Crear archivo principal que es el que debes correr, ejemplo: [Link], [Link],
[Link], [Link] etc…(incluso puede ser el nombre del proyecto).
o En el archivo [Link] están los scripts los cuales son los que podemos
mandar a llamar.
o Por default el archivo estará asi
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
o Pero podemos cambiarlo asi por ejemplo para que corra nuestro archivo principal
- "scripts": {
- "start": "node ./[Link]"
- },
o Para mandar a llamar nuestro script:
npm run start
PS C:\Users\szott\Dropbox\Desarrollo\bienesraices_mvc> npm
run start
> [email protected] start
> node ./[Link]
hola mundo
al ver esto vemos que corre nuestro archivo principal
Tambien podemos llamarlo sin la palabra clave “run”
npm start
- Como Hacer para no estar llamando ese npm start (Instalar Nodemon)
o Instalar la dependencia
npm i -D nodemon
nos instalara el paquete:
- "devDependencies": {
- "nodemon": "^2.0.20"
- }
Para usar este script devemos agregarlo en el [Link] en el apartado
de scripts:
- "scripts": {
- "start": "node ./[Link]",
- "server": "nodemon [Link]"
- },
Y para correrlo ya solo ponemos en terminar
o npm run server
PS C:\Users\szott\Dropbox\Desarrollo\
bienesraices_mvc> npm run server
> [email protected] server
> nodemon [Link]
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node [Link]`
hola mundo
7
[nodemon] clean exit - waiting for changes before
restart
o Y con eso inicializamos nuestro servidor
- Template engines:
- Implementando Controllers:
o Vamos a crear una carpeta en la raíz llamada controllers
o En esta carpeta iran todos los controladores para cada modulo que creemos
o En este caso el controlador se llamara [Link]
o Creamos el archivo [Link] dentro de la carpeta
Controllers->[Link]
o usuarioController: pondremos todas nuestras funciones y las exportamos
o ejemplo:
- const formularioLogin = (req, res) => {
- [Link]('auth/login', {
- autenticado: false
- })
- }
-
- export {
- formularioLogin
- }
o Luego debemos importarla en [Link] y llamarlas
- //importamos express
- import express from "express";
-
- //importamos formularioLogin
- import { formularioLogin } from "../controllers/[Link]";
-
- //definimos router
- const router = [Link]();
-
- [Link]('/login', formularioLogin);
-
- //exportamos router
- export default router
o Tailwindcss:
Para instalar debemos escribier en la terminal:
npm i -D tailwindcss autoprefixer postcss postcss-cli
-D porque solo será una dependencia de desarrollo
En nuestro [Link] veremos las devDependencies y tenemos
que tener instaladas las 4 que escribimos en terminal:
- "devDependencies": {
- "autoprefixer": "^10.4.12",
- "nodemon": "^2.0.20",
- "postcss": "^8.4.16",
- "postcss-cli": "^10.0.0",
- "tailwindcss": "^3.1.8"
- }
En el archivo principal debemos decile a [Link] donde están los
archivos estáticos, en que parte va a encontrar las imágenes, css
etc.
En este caso creamos la carpeta public
- //carpeta publica
- [Link]( [Link]('public'));
en esta carpeta public Podemos tener todos los archivos estáticos
como css, imágenes, archivos JavaScript, etc.
Podemos crear dentro de la carpeta public carpetas para cada una
de ellas, ejemplo
o public/css
o public/img
o public/js
o etc…
Crear archivo [Link]
En la carpeta css creamos el archivo [Link]
Debemos llamar los componentes de tailwind dentro de este
archivo css Ejemplo:
- @tailwind base;
- @tailwind components;
- @tailwind utilities;
En terminal también debemos iniciar tailwindcss escribimos:
o npx tailwindcss init -p
nos creara dos archivos
[Link]
[Link]
o En archivo [Link] debemos:
Decirle en que carpeta o archivos esta el archivo
css
Por defecto lo veremos asi:
- /** @type {import('tailwindcss').Config} */
- [Link] = {
- content: [],
- theme: {
- extend: {},
- },
- plugins: [],
- }
En content vamos a escribir donde están esas
vistas:
- content: ['./views/**/*.pug'],
Podríamos hacer una línea por vista pero al
agregar los asteriscos (*) le decimos que en la
carpeta views cualquier archivo con
terminación .pug
o Luego debemos compilar tailwind
En el archivo [Link] debemos agregar un
script:
- "scripts": {
- "start": "node ./[Link]",
- "server": "nodemon [Link]",
- "css": "postcss public/css/[Link] -o public/css/[Link]"
- },
Luego comprobamos compilando en la terminal:
npm run css
y si tenemos clases que hemos usado en
nuestras vistas .pug, veremos en el
archivo public/css/[Link] que nos a
agregado las clases que hemos utilizado.
Este comando en terminal debemos
correrlo cada ves que agreguemos una
clase en nuestros .pug.
Agregar –watch a [Link] para que se actualice
automáticamente:
- "css": "postcss public/css/[Link] -o public/css/[Link] --watch"
//validacion
await check('nombre').notEmpty().withMessage('El campo nombre debe tener
un valor.').run(req)
await check('email').isEmail().withMessage('Eso no parece un
email.').run(req)
await check('password').isLength({ min: 6 }).withMessage('El password
debe ser de al menos 6 caracteres.').run(req)
await
check("repetir_password").equals([Link]).withMessage("El password
debe ser igual al anterior").run(req);
//return [Link]([Link]())
//verificar que el resultado este vacio
if(![Link]()) {
//errores
return [Link]('auth/registro', {
pagina: 'Crear Cuenta',
errores: [Link](),
usuario: {
nombre: [Link],
email: [Link]
}
})
}
o Para verificar si existe un usuario con el mismo email:
- //extraer los datos
- const { nombre, email, password } = [Link]
-
- //verificar que el usuario no este duplicado
- const existeUsuario = await [Link]( { where : {
email } })
-
- if(existeUsuario) {
- return [Link]('auth/registro', {
- pagina: 'Crear Cuenta',
- errores: [{msg: 'El usuario ya existe'}],
- usuario: {
- nombre: [Link],
- email: [Link]
- }
- })
- }
-
- [Link](existeUsuario)
o Hash de la Password en la base de datos
Debemos instalar bcrypt
npm i bcrypt
Y luego importarlo al modelo en uso en este caso Usuarios
- import bcrypt from 'bcrypt'
Ahora desde el modelo Ejemplo Usuario debemos hashear el Password en
este caso lo hace antes de guardar en la base de datos:
- password: {
- type: [Link],
- allowNull: false
- },
- token: [Link],
- confirmado: [Link]
- },{
- hooks: {
- beforeCreate: async function(usuario) {
- const salt = await [Link](10)
- [Link] = await [Link]([Link],
salt);
- }
- }
- })
o Almacenar datos a la base de datos:
- //almacenar un usuario
- await [Link]({
- nombre,
- email,
- password,
- token: 123
- })
o Generar token único
Creamos una carpeta “helpers” son funciones que podemos utilizar en
varios lugares.
Creamos dentro un archivo llamado “[Link]”
Dentro del archivo creamos una función que será igual a la forma en que
vamos a crear el id
Y luego la exportamos:
-
- const generarId = () => [Link]().toString(32).substring(2) +
[Link]().toString(32);
-
- export {
- generarId
- }
o Mostrar mensaje de confirmación al crear cuenta:
Creamos una carpeta en “views” llamada “templates”
Y dentro creamos un archivo llamado “[Link]”
En el mensaje ponemos nuestro template con un parrfo para mostrar el
mensaje:
- extends ../layout/index
- block contenido
- [Link]-10
- [Link]-center Bienes
- [Link]-normal Raices
- [Link]-extrabold= pagina
-
-
- [Link]-10= mensaje
Y en usuarioController agregamos esto al finalizar la creación del usuario:
- //Mostrar mensaje de confirmacion
- [Link]('templates/mensaje', {
- pagina: 'Cuenta Creada Correctamente',
- mensaje: 'Hemos enviado un email de confirmación a tu correo,
presiona en el enlace'
- })
o Agregar un token:
Agregamos una ruta en “routes[Link]” para cuando el
usuario confirme su cuenta nos redirija a una página de confirmación:
- [Link]('/confirmar/:token', confirmar)
lo agregamos en la importacion
- //importamos formularioLogin
- import { formularioLogin, formularioRegistro, registrar, confirmar,
formularioOlvidePassword} from "../controllers/[Link]";
en “.env” agregamos “BAKCEND_URL” donde se almacenara la url
- BACKEND_URL=[Link]
En la función que enviara el correo desde “[Link]” debemos agregar la
ruta del link
- <a href="${[Link].BACKEND_URL}:${[Link] ??
3000}/auth/confirmar/${token}"> Confirmar Cuenta</a>
Y en el controlador agregamos la funcion que confirmara el correo
- //funcion que comprueba una cuenta
- const confirmar = (req,res) => {
- const { token } = [Link];
- [Link](token)
- }
if(!usuario) {
return [Link]('auth/confirmar-cuenta', {
pagina: 'Error al confirmar tu cuenta',
mensaje: 'Hubo un error al confirmar tu cuenta, intenta de
nuevo',
error: true
})
}
//confirmar la cuenta
[Link] = null;
[Link] = true;
await [Link]();
[Link]('auth/confirmar-cuenta', {
pagina: 'Cuenta confirmada',
mensaje: 'La cuenta se confirmó correctamente'
})
}
- Habilitando Proteccion CSRF y cookie-parser:
o Sirve para verificar que los formularios si vienende de la aplicacion
o Intalar csurf: npm i csurf cookie-parser
o Debemos importarlo a nuestro archive principal
- import csrf from 'csurf'
- import cookieParser from 'cookie-parser';
y luego en el mismo archivo principar los debemos habilitar
- // habilitar cookie-parser
- [Link](cookieParser())
-
- //habilitar csrf
- [Link]( csrf({cookie: true}))
o luego en nuestra vista en el formulario luego de form debemos colocar el input
que llevara el valor de csrfToken
- input(type="hidden" name="_csrf" value=csrfToken)
o luego en nuestro controlador debemos poner la variable de csrfToken para llevarla
a la vista y al formulario en todas las funciones que requieran de ese formulario:
- const formularioRegistro = (req, res) => {
-
- [Link]('auth/registro', {
- pagina: 'Registro',
- csrfToken: [Link]()
- })
- }
-
- const registrar = async (req, res) => {
- //validacion
- await check('nombre').notEmpty().withMessage('El campo nombre debe
tener un valor.').run(req)
- await check('email').isEmail().withMessage('Eso no parece un
email.').run(req)
- await check('password').isLength({ min: 6 }).withMessage('El
password debe ser de al menos 6 caracteres.').run(req)
- await
check("repetir_password").equals([Link]).withMessage("El
password debe ser igual al anterior").run(req);
-
- let resultado = validationResult(req)
-
- //return [Link]([Link]())
- //verificar que el resultado este vacio
- if(![Link]()) {
- //errores
- return [Link]('auth/registro', {
- pagina: 'Crear Cuenta',
- csrfToken: [Link](),
- errores: [Link](),
- usuario: {
- nombre: [Link],
- email: [Link]
- }
- })
- }
-
- //extraer los datos
- const { nombre, email, password } = [Link]
-
- //verificar que el usuario no este duplicado
- const existeUsuario = await [Link]( { where : { email }
})
-
- if(existeUsuario) {
- return [Link]('auth/registro', {
- pagina: 'Crear Cuenta',
- csrfToken: [Link](),
- errores: [{msg: 'El usuario ya existe'}],
- usuario: {
- nombre: [Link],
- email: [Link]
- }
- })
- }
- Reestablecer contraseña
o
En el controlador debemos
Importar bcrypt
- import bcrypt from 'bcrypt'
agregar el nuevo archivo de correo desde helpers “emailOlvidePassword”
- import { emailRegistro, emailOlvidePassword } from
'../helpers/[Link]'
luego creamos nuestras funciones de olvidar Password y también la de
reestablecer contraseña y las exportamos
- const formularioOlvidePassword = (req, res) => {
- [Link]('auth/olvide-password', {
- pagina: 'Olvide mi password',
- csrfToken: [Link](),
- })
- }
-
- const resetPassword = async (req, res) => {
- //validacion
- await check('email').isEmail().withMessage('Eso no parece un
email.').run(req)
-
- let resultado = validationResult(req)
- //verificar que el resultado este vacio
- if(![Link]()) {
- //errores
- return [Link]('auth/olvide-password', {
- pagina: 'Recupera tu acceso a Bienes Raices',
- csrfToken: [Link](),
- errores: [Link]()
- })
- }
- //buscar usuario
- const {email} = [Link]
- const usuario = await [Link]({where:{email}})
- //si no existe usuario
- if(!usuario) {
- return [Link]('auth/olvide-password', {
- pagina: 'Recupera tu acceso a Bienes Raices',
- csrfToken: [Link](),
- errores: [{msg: 'El Email no pertenece a ningún usuario'}]
- })
- }
- //Generar un token y enviar el email\
- [Link] = generarId();
- await [Link]();
- //enviar un email
- emailOlvidePassword({
- email,
- nombre: [Link],
- token: [Link]
- })
- //renderizar un mensaje
- //Mostrar mensaje de confirmacion
- [Link]('templates/mensaje', {
- pagina: 'restablece tu Password',
- mensaje: 'Hemos enviado un email con las instrucciones.'
- })
- }
-
- const comprobarToken = async (req,res) => {
- //recibimos el
- const {token} = [Link];
- // buscamos el usuario por el token
- const usuario = await [Link]({where:{token}})
- // verificar si existe usuario
- // si no existe
- if(!usuario) {
- return [Link]('auth/confirmar-cuenta', {
- pagina: 'Restablece tu Password',
- mensaje: 'Hubo un error al validar tu informacion, intenta
de nuevo',
- error: true
- })
- }
- //si existe mostramos formulario de validacion
- [Link]('auth/reset-password', {
- pagina: 'Reestablece tu Password',
- csrfToken: [Link](),
- })
- }
-
- const nuevoPassword = async (req,res) => {
- // validar el password
- await check('password').isLength({ min: 6 }).withMessage('El
password debe ser de al menos 6 caracteres.').run(req)
- let resultado = validationResult(req)
- //verificar que el resultado este vacio
- if(![Link]()) {
- //errores
- return [Link]('auth/reset-password', {
- pagina: 'Reestablece tu Password',
- csrfToken: [Link](),
- errores: [Link]()
- })
- }
- const {token} = [Link]
- const {password} = [Link];
- //Identificar quien hace el cambio
- const usuario = await [Link]({where: {token}})
- //Hashear el nuevo password
- const salt = await [Link](10)
- [Link] = await [Link](password, salt);
- [Link] = null;
-
- await [Link]();
-
- [Link]('auth/confirmar-cuenta', {
- pagina: 'Password Reestablecido',
- mensaje: 'El Password se guardo correctamente'
- })
- }
-
- export {
- formularioLogin,
- formularioRegistro,
- registrar,
- confirmar,
- formularioOlvidePassword,
- resetPassword,
- comprobarToken,
- nuevoPassword
- }
En la carpeta helpers debemos agregar la función “emailOlvidePassword”
y exportarla para importarla en el controlador para enviar el correo al
usuario para que cambie su Password
- const emailOlvidePassword = async (datos) => {
- const transport = [Link]({
- host: [Link].EMAIL_HOST,
- port: [Link].EMAIL_PORT,
- auth: {
- user: [Link].EMAIL_USER,
- pass: [Link].EMAIL_PASS
- }
- });
-
- const { email, nombre, token } = datos
-
- //enviar email
- await [Link]({
- from: 'info@[Link]',
- to: email,
- subject: 'Restablece tu password en BienesRaices',
- text: 'Restablece tu password en BienesRaices',
- html: `
- <p>Hola ${nombre}, has solicitado reestablecer tu password
en [Link]</p>
-
- <p>Sigue el siguiente enlace para generar un password
nuevo:
- <a href="${[Link].BACKEND_URL}:${[Link] ??
3000}/auth/olvide-password/${token}"> Restablecer Password</a> </p>
-
- <p>Si tu no solicitaste el cambio de password, puedes
ignorar el mensaje.</p>
- `
- })
- }
-
- export {
- emailRegistro,
- emailOlvidePassword
- }
En usuarioRoutes debemos agregar las rutas “olvide-password”
- [Link]('/olvide-password', resetPassword)
-
- //Almacena el nuevo password
- [Link]('/olvide-password/:token', comprobarToken);
- [Link]('/olvide-password/:token', nuevoPassword);
luego debemos crear la vista en la carpeta outh “olvide-password”
- extends ../layout/index
- block contenido
- [Link]-10
- [Link]-center Bienes
- [Link]-normal Raices
- [Link]-extrabold= pagina
- br
- [Link]-center Escribe tu correo para recuperar acceso a tu
cuenta:
-
- if errores
- div(class="max-w-md mx-auto my-10")
- each error in errores
- [Link]-
[Link]-bold= [Link]
-
- [Link]-w-md
- [Link]
- [Link]-y-5(method="POST" action="/auth/olvide-
password" noValidate)
- input(type="hidden" name="_csrf" value=csrfToken)
- div
- [Link]-gray-
[Link]-bold(for="email") Tu Email
- input#[Link]-
[Link]-gray-400(placeholder="Tu Email"
type="email" name="email")
-
- [Link]-between
- [Link]-xs(href="/auth/registro")
No tienes cuenta? Registrarte
- [Link]-xs(href="/auth/login") Ya
tienes cuenta? Inicia Sesion
-
- input(class="w-full bg-indigo-600 hover:bg-indigo-
700 text-white text-center font-bold py-3 font-bold cursor-pointer"
type="submit" value="Enviar correo" )
Y la vista de “reset-password”
- extends ../layout/index
- block contenido
- [Link]-10
- [Link]-center Bienes
- [Link]-normal Raices
- [Link]-extrabold= pagina
- br
- [Link]-center Escribe tu correo para recuperar acceso a tu
cuenta:
-
- if errores
- div(class="max-w-md mx-auto my-10")
- each error in errores
- [Link]-
[Link]-bold= [Link]
-
- [Link]-w-md
- [Link]
- [Link]-y-5(method="POST" noValidate)
- input(type="hidden" name="_csrf" value=csrfToken)
- div
- [Link]-gray-
[Link]-bold(for="password") Coloca tu nuevo Password
- input#[Link]-
[Link]-gray-400(placeholder="Tu Nuevo
Password" type="password" name="password")
-
- input(class="w-full bg-indigo-600 hover:bg-indigo-
700 text-white text-center font-bold py-3 font-bold cursor-pointer"
type="submit" value="Cambiar Password" )