Introducci贸n

1

Qu茅 necesitas para este curso y qu茅 aprender谩s sobre Node.js con Hapi

2

Conceptos principales de hapi y creaci贸n de nuestro primer servidor

3

Breve historia y estado actual

Creando un sitio b谩sico con Hapi

4

El objeto h, response y sus herramientas

5

Uso de plugins - Contenido est谩tico

6

Plantillas con Handlebars

7

Renderizado de vistas - Layout y template del home

8

Recibiendo par谩metros en una ruta POST - Creaci贸n del registro

9

Definir una mejor estructura con buenas pr谩cticas en Hapi

10

Validando la informaci贸n - Implementando Joi

11

Introducci贸n a Firebase

12

Creando un modelo y guardando en firebase

13

Implementando el login y validaci贸n del usuario

14

Autenticaci贸n de usuarios - Cookies y estado

15

Manejando errores

16

Visualizaci贸n de errores

17

Controlar el error 404 en inert y el error de validaci贸n

18

Repaso - Creaci贸n del modelo y controlador para preguntas

19

Repaso - Creaci贸n de las rutas para crear preguntas

20

Listar las 煤ltimas preguntas en el home

Aplicacion de conceptos avanzados

21

Enrutamiento avanzado - visualizando una pregunta

22

Enrutamiento avanzado - respondiendo una pregunta

23

Generando la l贸gica de la plantilla seg煤n si es creador o contribuidor

24

M茅todos de servidor - respuesta correcta

25

Usando m茅todos de servidor

26

Manejo del cach茅 - Agregando el home al cach茅

27

Procesamiento de archivos - Aceptando im谩genes

28

Logging con Good - Monitoreando el servidor

29

Creaci贸n de plugins - Teor铆a

30

Creaci贸n de plugins - Implementando un API REST

31

Estrateg铆as de autenticaci贸n - Asegurando el API REST

32

Seguridad b谩sica - Asegurando el servidor contra CSRF

33

Seguridad b谩sica - Asegurando el servidor contra XSS

Herramientas de desarrollo

34

Depuraci贸n del proyecto

35

Ecosistema de Hapi

A煤n no tienes acceso a esta clase

Crea una cuenta y contin煤a viendo este curso

Enrutamiento avanzado - respondiendo una pregunta

22/35
Recursos

Para crear la funcionalidad de respuesta, creamos un m茅todo nuevo en el modelo de preguntas llamado answer. Este m茅todo nos permitir谩 insertar con push el objeto con la respuesta individual para una pregunta que ser谩 almacenada en un arreglo child llamado answers.

Luego definimos el m茅todo respectivo en el controlador de las preguntas y creamos la ruta que manejar谩 el env铆o de las respuestas desde el formulario.

Es importante tener en cuenta que el ID de la pregunta que estamos respondiendo, corresponde a un input de tipo hidden en la vista, por lo que debemos asignar apropiadamente su valor a partir del key recibido en la ruta.

Finalmente, actualizamos la vista de detalles de pregunta, recordando que las respuestas son un arreglo en la base de datos de Firebase, por lo que deberemos recorrerlo igualmente con la instrucci贸n {#each ... } ... {/each} de handlebars.

Para el conteo de las respuestas crearemos un helper personalizado de handlebars y lo registraremos en el index.js con el m茅todo .registerHelper( 鈥<nombre helper>鈥, <funci贸n helper> ). Los helpers son funciones de JavaScript que est谩n disponibles globalmente en la aplicaci贸n para ser inclu铆das en cualquiera de las vistas.

Aportes 12

Preguntas 0

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesi贸n.

En el helper del conteo, pudi茅ramos validar si el arreglo de respuestas viene en null para devolver 0, y as铆 no tendr铆amos que incluir el tag #if en la plantilla.

no ser铆a mejor crear un modelo para 鈥渁nswer鈥 ?

Para evitar el if dentro del archivo index.hbs podemos poner el siguiente c贸digo en el index.js

handlerbars.registerHelper('answerNumber', (answers) => {
  if (!answers) return 0;
  const keys = Object.keys(answers).length;
  return keys;
});

en el archivo index.hbs solo agregamos esto

{{answerNumber question.answers}}

馃槉鉁

A la funcion answerQuestion agregu茅 un if() que eval煤a si el usuario est谩 o no est谩 logueado. Si no lo esta, lo redirecciona al login.

async function answerQuestion (req, h) {
  if (!req.state.user) {
    return h.redirect('/login')
  }
  let result
  try {
    result = await questions.answer(req.payload, req.state.user)
    console.log('Respuesta creada' + result);
  } catch (error) {
    console.error(error);
  }

  return h.redirect('/question/' + req.payload.id)
}```

Me sigue gustando m谩s como se ve con pug鈥
El punto es que pug acepta bloques de c贸digo dentro de la vista

extends ./layout/layout

block content
  main.container-fluid(role="main")
    .jumbotron.bg-white
      .container
        h1.display-3 FAQ
        p
          | The best place to learn and for those who are learning, ask a question
          | to clarify your doubts and share your knowledge if you know the answer

    .container
      h2.mb-4 Last Questions
      if questions 
        each q, key in questions
          .card.bg-white.mb-3
            .card-body
              .row
                .col-2.text-center
                  a.text-dark(href="#")
                    -
                      let numAns = 0;
                      if(q.answers){
                       numAns = Object.keys(q.answers).length
                      }
                    h3=numAns
                    | Answers
                .col-10.d-flex.align-items-stretch
                  h4.mt-3
                    a.text-dark(href="/question/"+key)= q.title
          hr
      else 
        .card.bg-white.mb-3
          .card-body
            .row
              .col-2.text-center
                h3 
              .col-10.d-flex.align-items-stretch
                h4.mt-3= error

block footer
  include ./partials/footer
block scripts
  include ./partials/scripts

controller.question.js

'use strict'

const questions = require('../models/index').questions

async function createQuestion(req, h) {
    let result

    try {
        result = await questions.create(req.payload, req.state.user)
        console.log(`Pregunta creada con el ID: ${result}`)
        return h.response(`Pregunta creada con el ID: ${result}`)
    } catch (error) {
        console.error(`Ocurrio un error: ${error}`)

        return h.view('ask', {
            title: 'Crear pregunta',
            error: 'Problemas creado la pregunta'
        }).code(500).takeover()
    }
}

async function answerQuestion(req, h) {
    let result
    try {
        result = questions.answer(req.payload, req.state.user)
        console.log(`Respuesta creada: ${result}`)
    } catch (error) {
        console.error(error)
    }

    return h.redirect(`/question/${req.payload.id}`)
}

module.exports = {
    createQuestion: createQuestion,
    answerQuestion: answerQuestion
}

models.questions.js

'use strict'

class Quiestions {
    constructor(db) {
        this.db = db
        this.ref = this.db.ref('/')
        this.collection = this.ref.child('questions')
    }

    async create (data, user) {
        const ask = {
            ...data
        }
        ask.owner = user
        const question = this.collection.push()
        question.set(ask)

        return question.key
    }

    async getLast(amount) {
        const query = await this.collection.limitToLast(amount).once('value')
        const data = query.val()
        return data
    }

    async getOne (id) {
        const query = await this.collection.child(id).once('value')
        const data = query.val()
        return data
    }

    async answer (data, user) {
        const answers = await this.collection.child(data.id).child('answers').push()
        answers.set({
            text: data.answer, 
            user: user
        })
        return answers
    }
}

module.exports = Quiestions

no es malo tener el id en el input vacio , ya que se puede ver en inspeccionar > elementos ?, o si hay ?

Modifique un poco el c贸digo y quedo as铆:
index.js

handlebars.registerHelper('answerNumber', (answers) => {
  if (answers === undefined) {
    return 0;
  }
  const keys = Object.keys(answers);
  return keys.length;
});

index.hbs

<h3>
  {{answerNumber question.answers}}
</h3>

me agrado la funcion que tiene handlerbars, me gustaria aplicar esa parte con express js

En el modelo de questions, en la funcion getOne, pueden modificar data.answers para que quede ordenado, siguiendo el ejemplo de un compa帽ero de la clase anterior quedar铆a as铆.

  async getOne(id){
    const query = await this.collection.child(id).once('value');
    const data = query.val();
    const orderedAnswers = {};
    Object.keys(data.answers).reverse().map(key => orderedAnswers[key] = data.answers[key]);
    return {
      ...data,
      answers: orderedAnswers,
    };
  }```