Node - Js Udemy
Node - Js Udemy
- 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 package.json 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 Node.js
o Crear archivo principal que es el que debes correr, ejemplo: main.js, app.js,
node.js, index.js etc…(incluso puede ser el nombre del proyecto).
o En el archivo package.json 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 ./index.js"
- },
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 ./index.js
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 package.json en el apartado
de scripts:
- "scripts": {
- "start": "node ./index.js",
- "server": "nodemon index.js"
- },
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 index.js
[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 index.js`
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 usuarioController.js
o Creamos el archivo usuarioController.js dentro de la carpeta
Controllers->usuarioController.js
o usuarioController: pondremos todas nuestras funciones y las exportamos
o ejemplo:
- const formularioLogin = (req, res) => {
- res.render('auth/login', {
- autenticado: false
- })
- }
-
- export {
- formularioLogin
- }
o Luego debemos importarla en index.js y llamarlas
- //importamos express
- import express from "express";
-
- //importamos formularioLogin
- import { formularioLogin } from "../controllers/usuarioController.js";
-
- //definimos router
- const router = express.Router();
-
- router.get('/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 package.json 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 Node.js 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
- app.use( express.static('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 tailwind.css
En la carpeta css creamos el archivo tailwind.css
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
postcss.config.cjs
tailwind.config.cjs
o En archivo tailwind.config.cjs debemos:
Decirle en que carpeta o archivos esta el archivo
css
Por defecto lo veremos asi:
- /** @type {import('tailwindcss').Config} */
- module.exports = {
- 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 package.json debemos agregar un
script:
- "scripts": {
- "start": "node ./index.js",
- "server": "nodemon index.js",
- "css": "postcss public/css/tailwind.css -o public/css/app.css"
- },
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/app.css 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 app.ccs para que se actualice
automáticamente:
- "css": "postcss public/css/tailwind.css -o public/css/app.css --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(req.body.password).withMessage("El password
debe ser igual al anterior").run(req);
//return res.json(resultado.array())
//verificar que el resultado este vacio
if(!resultado.isEmpty()) {
//errores
return res.render('auth/registro', {
pagina: 'Crear Cuenta',
errores: resultado.array(),
usuario: {
nombre: req.body.nombre,
email: req.body.email
}
})
}
o Para verificar si existe un usuario con el mismo email:
- //extraer los datos
- const { nombre, email, password } = req.body
-
- //verificar que el usuario no este duplicado
- const existeUsuario = await Usuario.findOne( { where : {
email } })
-
- if(existeUsuario) {
- return res.render('auth/registro', {
- pagina: 'Crear Cuenta',
- errores: [{msg: 'El usuario ya existe'}],
- usuario: {
- nombre: req.body.nombre,
- email: req.body.email
- }
- })
- }
-
- console.log(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: DataTypes.STRING,
- allowNull: false
- },
- token: DataTypes.STRING,
- confirmado: DataTypes.BOOLEAN
- },{
- hooks: {
- beforeCreate: async function(usuario) {
- const salt = await bcrypt.genSalt(10)
- usuario.password = await bcrypt.hash(usuario.password,
salt);
- }
- }
- })
o Almacenar datos a la base de datos:
- //almacenar un usuario
- await Usuario.create({
- 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 “tokens.js”
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 = () => Math.random().toString(32).substring(2) +
Date.now().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 “mensaje.pug”
En el mensaje ponemos nuestro template con un parrfo para mostrar el
mensaje:
- extends ../layout/index
- block contenido
- div.py-10
- h1.text-4xl.my-10.font-extrabold.text-center Bienes
- span.font-normal Raices
- h2.text-center.text-2xl.font-extrabold= pagina
-
-
- p.text-xl.font-bold.text-center.my-10= mensaje
Y en usuarioController agregamos esto al finalizar la creación del usuario:
- //Mostrar mensaje de confirmacion
- res.render('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 “routesusuarioRoutes.js” para cuando el
usuario confirme su cuenta nos redirija a una página de confirmación:
- router.get('/confirmar/:token', confirmar)
lo agregamos en la importacion
- //importamos formularioLogin
- import { formularioLogin, formularioRegistro, registrar, confirmar,
formularioOlvidePassword} from "../controllers/usuarioController.js";
en “.env” agregamos “BAKCEND_URL” donde se almacenara la url
- BACKEND_URL=http://localhost
En la función que enviara el correo desde “emails.js” debemos agregar la
ruta del link
- <a href="${process.env.BACKEND_URL}:${process.env.PORT ??
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 } = req.params;
- console.log(token)
- }
if(!usuario) {
return res.render('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
usuario.token = null;
usuario.confirmado = true;
await usuario.save();
res.render('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
- app.use(cookieParser())
-
- //habilitar csrf
- app.use( 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) => {
-
- res.render('auth/registro', {
- pagina: 'Registro',
- csrfToken: req.csrfToken()
- })
- }
-
- 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(req.body.password).withMessage("El
password debe ser igual al anterior").run(req);
-
- let resultado = validationResult(req)
-
- //return res.json(resultado.array())
- //verificar que el resultado este vacio
- if(!resultado.isEmpty()) {
- //errores
- return res.render('auth/registro', {
- pagina: 'Crear Cuenta',
- csrfToken: req.csrfToken(),
- errores: resultado.array(),
- usuario: {
- nombre: req.body.nombre,
- email: req.body.email
- }
- })
- }
-
- //extraer los datos
- const { nombre, email, password } = req.body
-
- //verificar que el usuario no este duplicado
- const existeUsuario = await Usuario.findOne( { where : { email }
})
-
- if(existeUsuario) {
- return res.render('auth/registro', {
- pagina: 'Crear Cuenta',
- csrfToken: req.csrfToken(),
- errores: [{msg: 'El usuario ya existe'}],
- usuario: {
- nombre: req.body.nombre,
- email: req.body.email
- }
- })
- }
- 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/emails.js'
luego creamos nuestras funciones de olvidar Password y también la de
reestablecer contraseña y las exportamos
- const formularioOlvidePassword = (req, res) => {
- res.render('auth/olvide-password', {
- pagina: 'Olvide mi password',
- csrfToken: req.csrfToken(),
- })
- }
-
- 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(!resultado.isEmpty()) {
- //errores
- return res.render('auth/olvide-password', {
- pagina: 'Recupera tu acceso a Bienes Raices',
- csrfToken: req.csrfToken(),
- errores: resultado.array()
- })
- }
- //buscar usuario
- const {email} = req.body
- const usuario = await Usuario.findOne({where:{email}})
- //si no existe usuario
- if(!usuario) {
- return res.render('auth/olvide-password', {
- pagina: 'Recupera tu acceso a Bienes Raices',
- csrfToken: req.csrfToken(),
- errores: [{msg: 'El Email no pertenece a ningún usuario'}]
- })
- }
- //Generar un token y enviar el email\
- usuario.token = generarId();
- await usuario.save();
- //enviar un email
- emailOlvidePassword({
- email,
- nombre: usuario.nombre,
- token: usuario.token
- })
- //renderizar un mensaje
- //Mostrar mensaje de confirmacion
- res.render('templates/mensaje', {
- pagina: 'restablece tu Password',
- mensaje: 'Hemos enviado un email con las instrucciones.'
- })
- }
-
- const comprobarToken = async (req,res) => {
- //recibimos el
- const {token} = req.params;
- // buscamos el usuario por el token
- const usuario = await Usuario.findOne({where:{token}})
- // verificar si existe usuario
- // si no existe
- if(!usuario) {
- return res.render('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
- res.render('auth/reset-password', {
- pagina: 'Reestablece tu Password',
- csrfToken: req.csrfToken(),
- })
- }
-
- 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(!resultado.isEmpty()) {
- //errores
- return res.render('auth/reset-password', {
- pagina: 'Reestablece tu Password',
- csrfToken: req.csrfToken(),
- errores: resultado.array()
- })
- }
- const {token} = req.params
- const {password} = req.body;
- //Identificar quien hace el cambio
- const usuario = await Usuario.findOne({where: {token}})
- //Hashear el nuevo password
- const salt = await bcrypt.genSalt(10)
- usuario.password = await bcrypt.hash(password, salt);
- usuario.token = null;
-
- await usuario.save();
-
- res.render('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 = nodemailer.createTransport({
- host: process.env.EMAIL_HOST,
- port: process.env.EMAIL_PORT,
- auth: {
- user: process.env.EMAIL_USER,
- pass: process.env.EMAIL_PASS
- }
- });
-
- const { email, nombre, token } = datos
-
- //enviar email
- await transport.sendMail({
- from: '[email protected]',
- to: email,
- subject: 'Restablece tu password en BienesRaices',
- text: 'Restablece tu password en BienesRaices',
- html: `
- <p>Hola ${nombre}, has solicitado reestablecer tu password
en bienesraices.com</p>
-
- <p>Sigue el siguiente enlace para generar un password
nuevo:
- <a href="${process.env.BACKEND_URL}:${process.env.PORT ??
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”
- router.post('/olvide-password', resetPassword)
-
- //Almacena el nuevo password
- router.get('/olvide-password/:token', comprobarToken);
- router.post('/olvide-password/:token', nuevoPassword);
luego debemos crear la vista en la carpeta outh “olvide-password”
- extends ../layout/index
- block contenido
- div.py-10
- h1.text-4xl.my-10.font-extrabold.text-center Bienes
- span.font-normal Raices
- h2.text-center.text-2xl.font-extrabold= pagina
- br
- p.text-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
- p.bg-red-600.text-white.uppercase.text-xs.text-
center.p-2.mb-1.font-bold= error.msg
-
- div.mt-8.mx-auto.max-w-md
- div.bg-white.py-8.px-4.shadow
- form.space-y-5(method="POST" action="/auth/olvide-
password" noValidate)
- input(type="hidden" name="_csrf" value=csrfToken)
- div
- label.block.text-sm.uppercase.text-gray-
500.mb-3.font-bold(for="email") Tu Email
- input#email.w-full.px-3.py-4.border.border-
gray-300.rounded-md.placeholder-gray-400(placeholder="Tu Email"
type="email" name="email")
-
- div.flex.items-center.justify-between
- a.text-gray-500.text-xs(href="/auth/registro")
No tienes cuenta? Registrarte
- a.text-gray-500.text-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
- div.py-10
- h1.text-4xl.my-10.font-extrabold.text-center Bienes
- span.font-normal Raices
- h2.text-center.text-2xl.font-extrabold= pagina
- br
- p.text-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
- p.bg-red-600.text-white.uppercase.text-xs.text-
center.p-2.mb-1.font-bold= error.msg
-
- div.mt-8.mx-auto.max-w-md
- div.bg-white.py-8.px-4.shadow
- form.space-y-5(method="POST" noValidate)
- input(type="hidden" name="_csrf" value=csrfToken)
- div
- label.block.text-sm.uppercase.text-gray-
500.mb-3.font-bold(for="password") Coloca tu nuevo Password
- input#password.w-full.px-3.py-4.border.border-
gray-300.rounded-md.placeholder-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" )