From ec66f3ad843c4fd2bf02bab6fb15b450216a0401 Mon Sep 17 00:00:00 2001 From: Nauel Date: Sat, 12 Sep 2020 14:44:15 -0400 Subject: [PATCH 01/11] controlador y servicio de exam y question --- config/enum/typeOfQuestion.js | 8 + .../20200830010510-create-question.js | 3 +- .../20200830010511-create-answer.js | 3 +- src/api/routes/answers.js | 16 +- src/api/routes/exams.js | 12 + src/api/routes/index.js | 4 +- src/api/routes/questions.js | 10 + src/controllers/answerController.js | 113 +++++---- src/controllers/examController.js | 42 ++++ src/controllers/questionController.js | 36 +++ src/models/answer.js | 3 +- src/models/question.js | 3 +- src/services/answerService.js | 223 +++++++++++------- src/services/examService.js | 126 ++++++++++ src/services/questionService.js | 207 ++++++++++++++++ tests/rest/answer-controller.js | 105 +++++++++ 16 files changed, 766 insertions(+), 148 deletions(-) create mode 100644 config/enum/typeOfQuestion.js create mode 100644 src/api/routes/exams.js create mode 100644 src/api/routes/questions.js create mode 100644 src/controllers/examController.js create mode 100644 src/controllers/questionController.js create mode 100644 src/services/examService.js create mode 100644 src/services/questionService.js create mode 100644 tests/rest/answer-controller.js diff --git a/config/enum/typeOfQuestion.js b/config/enum/typeOfQuestion.js new file mode 100644 index 00000000..e26bd1f6 --- /dev/null +++ b/config/enum/typeOfQuestion.js @@ -0,0 +1,8 @@ +const typeQuestion = { + QUESTIONABIERTA: 1, + QUESTIONCERRADA: 2, + QUESTIONMULTIPLE: 3, + QUESTIONNUMERICA: 4, +}; + +module.exports = typeQuestion; \ No newline at end of file diff --git a/database/migrations/20200830010510-create-question.js b/database/migrations/20200830010510-create-question.js index ae9094ae..b47e2add 100644 --- a/database/migrations/20200830010510-create-question.js +++ b/database/migrations/20200830010510-create-question.js @@ -23,7 +23,8 @@ module.exports = { allowNull: false, }, content: { - type: Sequelize.STRING + type: Sequelize.STRING, + allowNull: false, }, minimum: { type: Sequelize.INTEGER diff --git a/database/migrations/20200830010511-create-answer.js b/database/migrations/20200830010511-create-answer.js index 6bae127b..6b0c118f 100644 --- a/database/migrations/20200830010511-create-answer.js +++ b/database/migrations/20200830010511-create-answer.js @@ -18,8 +18,7 @@ module.exports = { references: { model: 'questions', key: 'id' } }, content: { - type: Sequelize.STRING, - allowNull: false, + type: Sequelize.STRING }, isTrue: { type: Sequelize.BOOLEAN, diff --git a/src/api/routes/answers.js b/src/api/routes/answers.js index 038b1d36..b5005b5c 100644 --- a/src/api/routes/answers.js +++ b/src/api/routes/answers.js @@ -1,14 +1,14 @@ const express = require("express"); const router = express.Router(); const answerController = require("../../controllers/answerController"); -const { validator } = require('../middlewares/validator'); -const AnswerService = require("../../services/answerService") +const { validator } = require("../middlewares/validator"); +const AnswerService = require("../../services/answerService"); router.post("/", validator(AnswerService.validate()), answerController.createAnswer); -router.get("/listOne/:id", answerController.getAnswer); -router.get("/question/:question_id", answerController.getAnswerQuestion); -router.delete('/:id', answerController.deleteAnswer); -router.put('/:id', answerController.updateAnswer); -router.get('/', answerController.listAll); +router.get("/:id", answerController.getAnswer); +router.get("/question/:question_id", answerController.getByQuestion); +router.delete("/:id", answerController.deleteAnswer); +router.put("/:id", answerController.updateAnswer); +router.get("/", answerController.listAll); -module.exports = router; +module.exports = router; \ No newline at end of file diff --git a/src/api/routes/exams.js b/src/api/routes/exams.js new file mode 100644 index 00000000..8f620d11 --- /dev/null +++ b/src/api/routes/exams.js @@ -0,0 +1,12 @@ +const express = require("express"); +const router = express.Router(); +const examController = require("../../controllers/examController"); +const ExamService = require("../../services/examService"); +const { validator } = require("../middlewares/validator"); + +router.post("/", validator(ExamService.validate()), examController.createExam); +router.get("/:id", examController.getExamComplet); + +module.exports = router; + +// con un parametro para completo o cabecera \ No newline at end of file diff --git a/src/api/routes/index.js b/src/api/routes/index.js index 02d5505d..56374bd9 100644 --- a/src/api/routes/index.js +++ b/src/api/routes/index.js @@ -5,13 +5,15 @@ module.exports = function(app) { const API_BASE_URL = "/api/v1"; - const routes = [ + const routes = [ { path: "/students", file: "./students" }, { path: "/professors", file: "./professors" }, { path: "/courses", file: "./courses" }, { path: "/login", file: "./login" }, { path: "/category", file: "./category" }, { path: "/answer", file: "./answers" }, + { path: "/question", file: "./questions" }, + { path: "/exam", file: "./exams" }, ]; routes.forEach(route => { diff --git a/src/api/routes/questions.js b/src/api/routes/questions.js new file mode 100644 index 00000000..09e1e009 --- /dev/null +++ b/src/api/routes/questions.js @@ -0,0 +1,10 @@ +const express = require("express"); +const router = express.Router(); +const QuestionController = require("../../controllers/questionController"); +const QuestionService = require("../../services/questionService"); +const { validator } = require("../middlewares/validator"); + +router.post("/", validator(QuestionService.validate()), QuestionController.createQuestion); +router.get("/:id", QuestionController.getQuestion); + +module.exports = router; \ No newline at end of file diff --git a/src/controllers/answerController.js b/src/controllers/answerController.js index aa35e666..731cf730 100644 --- a/src/controllers/answerController.js +++ b/src/controllers/answerController.js @@ -1,62 +1,77 @@ -const AnswerService = require('../services/answerService'); +const AnswerService = require("../services/answerService"); +const questionService = require("../services/questionService"); +const questionController = require("./questionController"); +const typeQuestion = require("../../config/enum/typeOfQuestion"); -class answerController{ +class answerController { - static async listAll(req,res){ - try{ - const allanswers = await AnswerService.findAllAnswer() - return res.status(200).json({ok:true,allanswers}) - }catch(err){ - return res.status(500).json({ ok: false, err }); - } - } - static async createAnswer(req,res){ - try{ - const answers = await AnswerService.createAnswer(req.body) - return res.status(200).json({ok:true,message:'Created Sucessfull',data:answers}) - }catch(err){ - return res.status(500).json({ ok: false, err }); + static async listAll(req, res) { + try { + const data = await AnswerService.show(); + return res.status(200).json({ message: "Ejecution Sucessfull", data }); + } catch (err) { + return res.status(500).json({ err }); } } - static async getAnswer(req,res){ - try{ - const {id} = req.params - const answers = await AnswerService.searchAnswer(id) - return res.status(200).json({ok:true,data:answers}) - }catch(err){ - return res.status(500).json({ ok: false, err }); - } + + static createAnswer(req, res) { + let existeQuestion = {}; + return questionService.exist(req.body.question_id) + .then(respuesta => { + existeQuestion = respuesta; + return AnswerService.validateParameters(respuesta, req.body); + }) + .then(data => { + const consulta = (existeQuestion.type_question_id === typeQuestion.QUESTIONABIERTA ? { where: { question_id: req.body.question_id } } : { where: { question_id: req.body.question_id, content: req.body.content } }); + return AnswerService.findOneBy(consulta); + }) + .then(data => { + if (data) return Promise.reject({ err: "The answer already exists. " + data.content }); + else return AnswerService.create(req.body); + }) + .then((data) => res.status(200).json({ message: "Successfully created", data })) + .catch((err) => res.status(500).json({ err })); } - static async getAnswerQuestion(req,res){ - try{ - const {question_id} = req.params - const getanswer = await AnswerService.getAnswerQuestion(question_id) - return res.status(200).json({ok:true,data:getanswer}) - }catch(err){ - return res.status(500).json({ ok: false, err }); + + static async getAnswer(req, res) { + try { + const { id } = req.params; + const answers = await AnswerService.findById(id); + return res.status(200).json({ message: "Sucessfull Ejecution", data: answers }); + } catch (err) { + return res.status(500).json({ err }); } } - static async updateAnswer(req,res){ - try{ - const {id} = req.params - const updateanswer = await AnswerService.updateAnswer(req.body,id) - return res.status(200).json({ok:true,message:'Update Sucessfull',data:updateanswer}) - }catch(err){ - return res.status(500).json({ ok: false, err }); + + static async getByQuestion(req, res) { + try { + const { question_id } = req.params; + const consulta = { where: { question_id: question_id } }; + const getanswer = await AnswerService.findAllBy(consulta); + return res.status(200).json({ message: "Sucessfull Ejecution", data: getanswer }); + } catch (err) { + return res.status(500).json({ err }); } } - //delete course ... - static async deleteAnswer (req,res){ - try{ - const {id} = req.params - const deleteanswer = await AnswerService.deleteAnswerQuestion(id) - return res.status(200).json(deleteanswer) - }catch(err){ - return res.status(500).json({ ok: false, err }); + + static async updateAnswer(req, res) { + try { + const { id } = req.params; + const updateanswer = await AnswerService.update(req.body, id); + return res.status(200).json({ message: "Sucessfull Ejecution", data: updateanswer }); + } catch (err) { + return res.status(500).json({ err }); } } + static async deleteAnswer(req, res) { + try { + const { id } = req.params; + const deleteanswer = await AnswerService.delete(id); + return res.status(200).json({ message: "Delete Sucessfull", data: deleteanswer }); + } catch (err) { + return res.status(500).json({ err }); + } + } } -module.exports = answerController - - +module.exports = answerController; \ No newline at end of file diff --git a/src/controllers/examController.js b/src/controllers/examController.js new file mode 100644 index 00000000..0d578e63 --- /dev/null +++ b/src/controllers/examController.js @@ -0,0 +1,42 @@ +const ExamService = require("../services/examService"); + +class examController { + + static getExamComplet(req, res) { + return ExamService.findAllById(req.params.id) + .then((data) => { + if (data.length > 0) { + return res.status(200).json({ message: "Query executed correctly", data }); + } else { + return res.status(404).json({ err: "Exam not found" }); + } + }) + .catch((err) => res.status(500).json({ err })); + } + + static getExam(req, res) { + return ExamService.findById(req.body.id) + .then((data) => { + if (data) { + return res.status(200).json({ message: "Query executed correctly", data }); + } else { + return res.status(404).json({ err: "Exam not found" }); + } + }) + .catch((err) => res.status(500).json({ err })); + } + + static createExam(req, res) { + const exam = { + module_id: req.body.module_id, + type: req.body.type, + name_exam: req.body.name_exam + }; + return ExamService.findExist(exam) + .then(data => ExamService.create(exam)) + .then((data) => res.status(200).json({ message: "Create successfully", data })) + .catch((err) => res.status(500).json({ err })); + } + +} +module.exports = examController; \ No newline at end of file diff --git a/src/controllers/questionController.js b/src/controllers/questionController.js new file mode 100644 index 00000000..80647258 --- /dev/null +++ b/src/controllers/questionController.js @@ -0,0 +1,36 @@ +const QuestionService = require("../services/questionService"); + +class questionController { + + static getQuestion(req, res) { + return QuestionService.findById(req.params.id) + .then((data) => { + if (data) { + return res.status(200).json({ message: "Consulta successfully", data }); + } else { + return res.status(404).json({ err: "No existe question" }); + } + }) + .catch((err) => res.status(500).json({ err })); + } + + static createQuestion(req, res) { + const question = { + exam_id: req.body.exam_id, + type_question_id: req.body.type_question_id, + code: req.body.code, + content: req.body.content, + minimum: req.body.minimum, + tope: req.body.tope, + length: req.body.length, + help: req.body.help + } //= req.body; + return QuestionService.validarParameter(question) + .then(data => QuestionService.findExist(question)) + .then(data => QuestionService.create(question)) + .then((data) => res.status(200).json({ message: "Create successfully", data })) + .catch((err) => res.status(500).json({ err })); + } +} + +module.exports = questionController; \ No newline at end of file diff --git a/src/models/answer.js b/src/models/answer.js index ee074790..180b4731 100644 --- a/src/models/answer.js +++ b/src/models/answer.js @@ -18,8 +18,7 @@ const Answer = sequelize.define('answers', { references: { model: 'questions', key: 'id' } }, content: { - type: Sequelize.STRING, - allowNull: false, + type: Sequelize.STRING }, isTrue: { type: Sequelize.BOOLEAN, diff --git a/src/models/question.js b/src/models/question.js index 63227f8d..83316798 100644 --- a/src/models/question.js +++ b/src/models/question.js @@ -23,7 +23,8 @@ const Question = sequelize.define('questions', { allowNull: false, }, content: { - type: Sequelize.STRING + type: Sequelize.STRING, + allowNull: false, }, minimum: { type: Sequelize.INTEGER diff --git a/src/services/answerService.js b/src/services/answerService.js index a61fdf75..f6cf5ae0 100644 --- a/src/services/answerService.js +++ b/src/services/answerService.js @@ -1,99 +1,154 @@ const Answer = require("../models/answer"); -const { check } = require("express-validator"); +const { check } = require("express-validator"); +const typeQuestion = require("../../config/enum/typeOfQuestion"); class AnswerService { - - static validate(){ - return [ - check('code', 'code is required').not().isEmpty(), - check('question_id', 'question_id is required').not().isEmpty(), - check('content', 'content is required').not().isEmpty(), - check('isTrue', 'isTrue is required').not().isEmpty(), - check('score', 'score is required').not().isEmpty(), - ]; -} + static validate() { + return [ + check("code", "code is required").not().isEmpty().isAlphanumeric().isLength({ min: 2, max: 15 }), + check("question_id", "question_id is required").not().isEmpty().isNumeric(), + check("isTrue", "isTrue is required").isNumeric().isLength({ min: 1, max: 1 }), + check("score", "score is required").isNumeric(), + ]; + } + + static async show() { + try { + const answers = await Answer.findAll(); + if (answers) { + return answers; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + static async create(data) { + try { + const { code, question_id, content, isTrue, score } = data; + const answerCreated = await Answer.create({ + code, + question_id, + content, + isTrue, + score, + }); + return answerCreated; + } catch (err) { + return new Error("An error has ocurred"); + } + } - static async findAllAnswer() { - try { - const answers = await Answer.findAll(); - if (answers) { - return answers; - } - } catch (err) { - return new Error("An error has ocurred"); + static async findById(id) { + try { + const foundAnswer = await Answer.findByPk(id); + if (foundAnswer) { + return foundAnswer; + } else { + return "Don't exists id"; + } + } catch (err) { + return new Error("An error has ocurred"); + } } - } - static async createAnswer(data) { - try { - const { code, question_id, content, isTrue, score } = data; - const answerscourse = await Answer.create({ - code, - question_id, - content, - isTrue, - score, - }); - return answerscourse; - } catch (err) { - return new Error("An error has ocurred"); + + static async findOneBy(consulta) { + try { + const answerExiste = await Answer.findOne(consulta); + if (answerExiste) { + return answerExiste; + } + } catch (err) { + return new Error("An error has ocurred"); + } } - } - static async searchAnswer(id) { - try { - const answersearch = await Answer.findByPk(id); - if (answersearch) { - return answersearch; - }else{ - return "Don't exists id" - } - } catch (err) { - return new Error("An error has ocurred"); + + static async finAllBy(consulta) { + try { + const allAnswer = await Answer.findAll(consulta); + if (allAnswer) { + return allAnswer; + } + } catch (err) { + return new Error("An error has ocurred"); + } } - } - static async getAnswerQuestion(question_id) { - try { - const answerquestion = await Answer.findAll({ - where: { question_id: question_id }, - }); - if (answerquestion) { - return answerquestion; - } - } catch (err) { - return new Error("An error has ocurred"); + static async delete(id) { + try { + const answer = await Answer.findByPk(id); + if (answer) { + await answer.destroy(); + return answer; + } + } catch (err) { + return new Error("An error has ocurred"); + } } - } - static async deleteAnswerQuestion(id){ - try{ - const answerdelete= await Answer.findByPk(id); - if(answerdelete){ - await answerdelete.destroy() - return answerdelete + + static async update(data, id) { + try { + const { code, question_id, content, isTrue, score } = data; + const foundAnswer = await Answer.findByPk(id); + if (foundAnswer) { + foundAnswer.update({ + code, + question_id, + content, + isTrue, + score, + }); + return foundAnswer; + } + } catch (err) { + return new Error("An error has ocurred"); } - }catch(err){ - return new Error("An error has ocurred"); - } - } + } - static async updateAnswer(data, id) { - try { - const { code, question_id, content, isTrue, score } = data; - const answerquestion = await Answer.findByPk(id); - if (answerquestion) { - answerquestion.update({ - code, - question_id, - content, - isTrue, - score, - }) - return answerquestion; - } - } catch (err) { - return new Error("An error has ocurred"); + + /*********************** + * question abierta y numerica solo puede tener una respuesta o graba una vez y despues modifica + * !answer.isTrue no ingresa cuando vale 0 + * en las preguntas abiertas no deberia guardar en content + **/ + static validateParameters(question, answer) { + return new Promise((resolve, reject) => { // !answer.question_id || !question.content || + console.log("question", question.type_question_id); + switch (question.type_question_id) { + case typeQuestion.QUESTIONABIERTA: + if (!answer.code || !answer.score) { // || !answer.isTrue + reject("Faltan Parametros obligatorios"); + } else { + resolve("Parametros correctos"); + } + break; + default: + if (!answer.code || !answer.content || !answer.score) { //!answer.isTrue || + reject("Faltan parametros obligatorios"); + } else { + resolve("Parametros correctos"); + } + break; + } + }); } - } + + /****************** + * 1. ver si exsite la misma respuesta + * 2. si es abierta o numerica debe tener solo una respuesta para cada question + **/ + static async getExisteAnswer(question, req, res) { + try { + const { id } = req.params; + let consulta = {}; + consulta = (question.type_question_id === typeQuestion.QUESTIONABIERTA ? { where: { question_id: req.body.question_id } } : { where: { question_id: req.body.question_id, content: req.body.content } }); + const existeAnswer = await AnswerService.findOneBy(consulta); + return res.status(200).json(existeAnswer); + } catch (err) { + return res.status(500).json({ err }); + } + } + } -module.exports = AnswerService; +module.exports = AnswerService; \ No newline at end of file diff --git a/src/services/examService.js b/src/services/examService.js new file mode 100644 index 00000000..9fb124b2 --- /dev/null +++ b/src/services/examService.js @@ -0,0 +1,126 @@ +const Exam = require("../models/exam"); +const { check } = require("express-validator"); +const models = require("../../config/db/mysql"); + +let sequelize; +sequelize = models.sequelize; + +class ExamService { + + static validate() { + return [ + check("module_id", "module_id is required").not().isEmpty().isAlphanumeric().isLength({ min: 1, max: 15 }), + check("name_exam", "name_exam is required").not().isEmpty().isLength({ min: 2, max: 500 }), + ]; + } + + static async show() { + try { + const hereExam = await Exam.findAll(); + if (hereExam) { + return hereExam; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static async create(data) { + try { + const { module_id, type, name_exam } = data; + const hereExam = await Exam.create({ + module_id, + type, + name_exam + }); + return hereExam; + } catch (err) { + return new Error("An error has ocurred"); + } + } + static async findById(id) { + try { + const hereExam = await Exam.findByPk(id); + if (hereExam) { + return hereExam; + } else { + return "Don't exists id"; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static async delete(id) { + // si un estudiante no hizo el examen se borra.. el profesor puede borrar con alumnos borrado logico + try { + const hereExam = await Exam.findByPk(id); + if (hereExam) { + await hereExam.destroy(); + return hereExam; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static async update(data, id) { + try { + const { module_id, type, name_exam } = data; + const hereExam = await Exam.findByPk(id); + if (hereExam) { + hereExam.update({ + module_id, + type, + name_exam + }); + return hereExam; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static async findOneBy(consulta) { + try { + const hereExam = await Exam.findOne(consulta); + if (hereExam) { + return hereExam; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static findAllById(id) { + let query = ` + SELECT * + FROM exams e + inner join questions as q on q.exam_id = e.id + INNER JOIN answers AS a ON a.question_id = q.id + where e.id =:id;`; + return sequelize.query(query, { replacements: { id: id }, type: sequelize.QueryTypes.SELECT }); + } + + /** + * Search record if it exists in the database + * @param {object} exam containing info about a post + * @returns {Promise} message error if it exists + */ + static findExist(exam) { + return Exam.findOne({ where: { module_id: exam.module_id, name_exam: exam.name_exam } }) + .then((data) => { + if (data) { + const err = "The record exists"; + return Promise.reject(err); + } else { + return Promise.resolve({ message: "The record does not exist" }); + } + }) + .catch((err) => { + return Promise.reject(err); + }); + } + +} +module.exports = ExamService; \ No newline at end of file diff --git a/src/services/questionService.js b/src/services/questionService.js new file mode 100644 index 00000000..6cc43ec5 --- /dev/null +++ b/src/services/questionService.js @@ -0,0 +1,207 @@ +/* eslint-disable indent */ +const Question = require("../models/question"); +const exam = require("./examService") +const { check } = require("express-validator"); +const typeQuestion = require("../../config/enum/typeOfQuestion"); + +class QuestionService { + + static validate() { + + return [ + check("exam_id", "exam_id is required").not().isEmpty(), + check("type_question_id", "type_question_id is required").not().isEmpty().isNumeric().custom((val, { req }) => { + if (!val || val < 0 || val > parseInt(typeQuestion.QUESTIONNUMERICA, 10) + 1) { + throw new Error("Mandatory parameters are missing or out of range"); + } else return true; + }), + check("code", "code is required").not().isEmpty().isAlphanumeric().isLength({ min: 2, max: 15 }), + check("content", "content is required").not().isEmpty().isLength({ min: 2, max: 500 }), + check("help", "help is optional").optional().isLength({ min: 2, max: 500 }), + check("minimum").custom((minimum, { req }) => { + if (!req.body.type_question_id || req.body.type_question_id < 1 || req.body.type_question_id > parseInt(typeQuestion.QUESTIONNUMERICA, 10) + 1) return true; + switch (req.body.type_question_id) { + case typeQuestion.QUESTIONABIERTA: + if (!minimum || minimum < 1) throw new Error("Mandatory parameters are missing"); + break; + case typeQuestion.QUESTIONNUMERICA: + if (!minimum || minimum === 0) throw new Error("Mandatory parameters are missing"); + break; + default: + if (!minimum) return true; + else throw new Error("Parameter NOT required"); + } + return true; + }), + check("tope").custom((val, { req }) => { + if (!req.body.type_question_id || req.body.type_question_id < 1 || req.body.type_question_id > parseInt(typeQuestion.QUESTIONNUMERICA, 10) + 1) return true; + switch (req.body.type_question_id) { + case typeQuestion.QUESTIONNUMERICA: + if (!val || val === 0) throw new Error("Mandatory parameters are missing"); + break; + default: + if (!val) return true; + else throw new Error("Parameter NOT required"); + } + return true; + }), + check("length").custom((val, { req }) => { + if (!req.body.type_question_id || req.body.type_question_id < 1 || req.body.type_question_id > parseInt(typeQuestion.QUESTIONNUMERICA, 10) + 1) return true; + switch (req.body.type_question_id) { + case typeQuestion.QUESTIONABIERTA: + if (!val || val < 1 || val > 500) throw new Error("Mandatory parameters are missing"); + break; + default: + if (!val) { return true; } else { throw new Error("Parameter NOT required"); } + } + return true; + }) + ]; + } + + static async show() { + try { + const questions = await Question.findAll(); + if (questions) { + return questions; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static async create(data) { + try { + const { exam_id, type_question_id, code, content, minimum, tope, length, help } = data; + const question = await Question.create({ + exam_id, + type_question_id, + code, + content, + minimum, + tope, + length, + help + }); + return question; + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static async findById(id) { + try { + const questionSearch = await Question.findByPk(id); + if (questionSearch) { + return questionSearch; + } else { + return "Question does not exist"; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static async delete(id) { + try { + const question = await Question.findByPk(id); + if (question) { + await question.destroy(); + return question; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static async update(data, id) { + try { + const { code, question_id, content, isTrue, score } = data; + const question = await Question.findByPk(id); + if (question) { + question.update({ + code, + question_id, + content, + isTrue, + score, + }); + return question; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static async findOneBy(consulta) { + try { + const questionExiste = await Question.findOne(consulta); + if (questionExiste) { + return questionExiste; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static findExist(question) { + return QuestionService.findOneBy({ where: { exam_id: question.exam_id, content: question.content } }) + .then((data) => { + if (data) { + const err = { error: "The Question already exists" }; + err.data = data; + return Promise.reject(err); + } else { + return Promise.resolve("There is no Question"); + } + }) + .catch((err) => Promise.reject(err)); + } + + /* question abierta y numerica solo puede tener una respuesta o graba una vez y despues modifica + !Question.isTrue no ingresa cuando vale 0 + en las preguntas abiertas no deberia guardar en content + */ + static validarParameter(question) { + return new Promise((resolve, reject) => { + if (!question.exam_id || !question.type_question_id || !question.code || !question.content) { + reject("Required parameters are missing"); + } else { + switch (question.type_question_id) { + case typeQuestion.QUESTIONABIERTA: + if (!question.length || question.length == 0) { + console.log("Required parameters are missing"); + reject("Required parameters are missing"); + } else { + resolve("Correct parameters"); + } + break; + case typeQuestion.QUESTIONNUMERICA: + if (!question.minimum || !question.top || question.minimum == 0 || question.top == 0) { + reject("Required parameters are missing: minimum or top"); + } else { + resolve("Correct parameters"); + } + break; + default: + resolve("Correct parameters"); + } + } + }); + } + + static exist(id) { + + return Question.findByPk(id) + .then((data) => { + if (data) { + return Promise.resolve(data); + } else { + const err = { statusCode: 404, message: "there is no question" }; + return Promise.reject(err); + } + }) + .catch((err) => Promise.reject(err)); + } +} +module.exports = QuestionService; \ No newline at end of file diff --git a/tests/rest/answer-controller.js b/tests/rest/answer-controller.js new file mode 100644 index 00000000..375a6f31 --- /dev/null +++ b/tests/rest/answer-controller.js @@ -0,0 +1,105 @@ +const chai = require("chai"); +const chaiHttp = require("chai-http"); + +const app = require("../../src/index"); + +const { expect } = chai; + +chai.use(chaiHttp); + +describe("Answer tests", () => { + + describe("Create a answer of Exam", () => { + it("should return a answer created", (done) => { + + chai.request(app) + .post("/api/v1/answer") + .send({ + "code": "r11", + "question_id": 3, + "content": "naranja_99", + "isTrue": 1, + "score": 10 + }) + .end(function(err, res) { + + if (err) done(err); + //console.log(res) + + expect(res).to.have.status(200); + expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + done(); + }); + }) + + it("should return an error if content is empty and type of question is open", (done) => { + + chai.request(app) + .post("/api/v1/answer") + .send({ + "code": "r11", + "question_id": 1, + "isTrue": 1, + "score": 10 + }) + .end(function(err, res) { + + if (err) done(err); + //console.log(res) + + expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + expect(res).to.have.status(200); + + done(); + + }); + }) + + it("should return an error if content is empty and type of question is not open", (done) => { + + chai.request(app) + .post("/api/v1/answer") + .send({ + "code": "r12", + "question_id": 3, + "isTrue": 1, + "score": 10 + }) + .end(function(err, res) { + + if (err) done(err); + //console.log(res) + + expect(JSON.parse(res.text)).to.have.all.keys("err"); + expect(res).to.have.status(500); + + done(); + + }); + }) + + it("should return an error if question_id is empty", (done) => { + + chai.request(app) + .post("/api/v1/answer") + .send({ + "code": "r11", + "content": "naranja", + "isTrue": 1, + "score": 10 + }) + .end(function(err, res) { + + if (err) done(err); + //console.log(res) + + expect(JSON.parse(res.text)).to.have.all.keys("errors"); + expect(res).to.have.status(400); // 404 + + done(); + }); + }); + }); + + +}) \ No newline at end of file From 32d23d58f0dd74af92464b6a3cd15a45b30db120 Mon Sep 17 00:00:00 2001 From: Nauel Date: Sun, 13 Sep 2020 12:40:35 -0400 Subject: [PATCH 02/11] fix:correction of services for creation --- src/controllers/answerController.js | 23 +++++++----- src/controllers/examController.js | 2 +- src/controllers/questionController.js | 13 +++++-- src/services/answerService.js | 54 +++++++++------------------ src/services/examService.js | 4 +- src/services/questionService.js | 37 ++++++++---------- 6 files changed, 59 insertions(+), 74 deletions(-) diff --git a/src/controllers/answerController.js b/src/controllers/answerController.js index 731cf730..05f32dbd 100644 --- a/src/controllers/answerController.js +++ b/src/controllers/answerController.js @@ -1,6 +1,5 @@ const AnswerService = require("../services/answerService"); const questionService = require("../services/questionService"); -const questionController = require("./questionController"); const typeQuestion = require("../../config/enum/typeOfQuestion"); class answerController { @@ -15,18 +14,24 @@ class answerController { } static createAnswer(req, res) { - let existeQuestion = {}; - return questionService.exist(req.body.question_id) - .then(respuesta => { - existeQuestion = respuesta; - return AnswerService.validateParameters(respuesta, req.body); + let existsQuestion = {}; + return questionService.findById(req.body.question_id) + .then(data => { + if (data) { + existsQuestion = data; + const answerVerify = req.body; + answerVerify.type_question_id = data.type_question_id; + return AnswerService.validateParameters(answerVerify); + } else { + return Promise.reject({ err: "The question not exists. " }); + } }) .then(data => { - const consulta = (existeQuestion.type_question_id === typeQuestion.QUESTIONABIERTA ? { where: { question_id: req.body.question_id } } : { where: { question_id: req.body.question_id, content: req.body.content } }); - return AnswerService.findOneBy(consulta); + const query = ((existsQuestion.type_question_id === typeQuestion.QUESTIONABIERTA || existsQuestion.type_question_id === typeQuestion.QUESTIONNUMERICA) ? { where: { question_id: req.body.question_id } } : { where: { question_id: req.body.question_id, content: req.body.content } }); + return AnswerService.findOneBy(query); }) .then(data => { - if (data) return Promise.reject({ err: "The answer already exists. " + data.content }); + if (data) return Promise.reject({ err: "The answer already exists. " }); else return AnswerService.create(req.body); }) .then((data) => res.status(200).json({ message: "Successfully created", data })) diff --git a/src/controllers/examController.js b/src/controllers/examController.js index 0d578e63..0648e0f2 100644 --- a/src/controllers/examController.js +++ b/src/controllers/examController.js @@ -32,7 +32,7 @@ class examController { type: req.body.type, name_exam: req.body.name_exam }; - return ExamService.findExist(exam) + return ExamService.findExists(exam) .then(data => ExamService.create(exam)) .then((data) => res.status(200).json({ message: "Create successfully", data })) .catch((err) => res.status(500).json({ err })); diff --git a/src/controllers/questionController.js b/src/controllers/questionController.js index 80647258..16c2b8a7 100644 --- a/src/controllers/questionController.js +++ b/src/controllers/questionController.js @@ -1,5 +1,5 @@ const QuestionService = require("../services/questionService"); - +const examService = require("../services/examService"); class questionController { static getQuestion(req, res) { @@ -25,8 +25,15 @@ class questionController { length: req.body.length, help: req.body.help } //= req.body; - return QuestionService.validarParameter(question) - .then(data => QuestionService.findExist(question)) + return QuestionService.validateParameters(question) + .then(data => examService.findById(question.exam_id)) + .then(data => { + if (data) { + return QuestionService.findExist(question); + } else { + return res.status(500).json({ err: "Exam does not exist" }); + } + }) .then(data => QuestionService.create(question)) .then((data) => res.status(200).json({ message: "Create successfully", data })) .catch((err) => res.status(500).json({ err })); diff --git a/src/services/answerService.js b/src/services/answerService.js index f6cf5ae0..67188b87 100644 --- a/src/services/answerService.js +++ b/src/services/answerService.js @@ -8,8 +8,8 @@ class AnswerService { return [ check("code", "code is required").not().isEmpty().isAlphanumeric().isLength({ min: 2, max: 15 }), check("question_id", "question_id is required").not().isEmpty().isNumeric(), - check("isTrue", "isTrue is required").isNumeric().isLength({ min: 1, max: 1 }), - check("score", "score is required").isNumeric(), + check("isTrue", "isTrue is required").not().isEmpty().isIn([1, 0]), + check("score", "score is required").optional().isNumeric(), ]; } @@ -105,50 +105,32 @@ class AnswerService { } } - - /*********************** - * question abierta y numerica solo puede tener una respuesta o graba una vez y despues modifica - * !answer.isTrue no ingresa cuando vale 0 - * en las preguntas abiertas no deberia guardar en content - **/ - static validateParameters(question, answer) { - return new Promise((resolve, reject) => { // !answer.question_id || !question.content || - console.log("question", question.type_question_id); - switch (question.type_question_id) { + /** + * Verification of data to add + * @param {Object} answer post data to add + * @returns {Promise.resolve} message for correct data + * @returns {Promise.reject} alert message, if data is missing + */ + static validateParameters(answer) { + return new Promise((resolve, reject) => { + console.log("question", answer.type_question_id); + switch (answer.type_question_id) { case typeQuestion.QUESTIONABIERTA: - if (!answer.code || !answer.score) { // || !answer.isTrue - reject("Faltan Parametros obligatorios"); + if (!answer.code || !answer.score) { + reject("Mandatory parameters are missing"); } else { - resolve("Parametros correctos"); + resolve("Correct parameters"); } break; default: - if (!answer.code || !answer.content || !answer.score) { //!answer.isTrue || - reject("Faltan parametros obligatorios"); + if (!answer.code || !answer.content || !answer.score) { + reject("Mandatory parameters are missing"); } else { - resolve("Parametros correctos"); + resolve("Correct parameters"); } break; } }); } - - /****************** - * 1. ver si exsite la misma respuesta - * 2. si es abierta o numerica debe tener solo una respuesta para cada question - **/ - static async getExisteAnswer(question, req, res) { - try { - const { id } = req.params; - let consulta = {}; - consulta = (question.type_question_id === typeQuestion.QUESTIONABIERTA ? { where: { question_id: req.body.question_id } } : { where: { question_id: req.body.question_id, content: req.body.content } }); - const existeAnswer = await AnswerService.findOneBy(consulta); - return res.status(200).json(existeAnswer); - } catch (err) { - return res.status(500).json({ err }); - } - } - - } module.exports = AnswerService; \ No newline at end of file diff --git a/src/services/examService.js b/src/services/examService.js index 9fb124b2..b1c8a665 100644 --- a/src/services/examService.js +++ b/src/services/examService.js @@ -43,8 +43,6 @@ class ExamService { const hereExam = await Exam.findByPk(id); if (hereExam) { return hereExam; - } else { - return "Don't exists id"; } } catch (err) { return new Error("An error has ocurred"); @@ -107,7 +105,7 @@ class ExamService { * @param {object} exam containing info about a post * @returns {Promise} message error if it exists */ - static findExist(exam) { + static findExists(exam) { return Exam.findOne({ where: { module_id: exam.module_id, name_exam: exam.name_exam } }) .then((data) => { if (data) { diff --git a/src/services/questionService.js b/src/services/questionService.js index 6cc43ec5..80c481f4 100644 --- a/src/services/questionService.js +++ b/src/services/questionService.js @@ -94,8 +94,6 @@ class QuestionService { const questionSearch = await Question.findByPk(id); if (questionSearch) { return questionSearch; - } else { - return "Question does not exist"; } } catch (err) { return new Error("An error has ocurred"); @@ -144,7 +142,13 @@ class QuestionService { } } - static findExist(question) { + /** + * Verify that the question does not exist in the exam before adding + * @param {object} question to add + * @returns {Promise} resolve, when the question does not exist in the exam + * @returns {Promise} reject, when the question exists in the exam + */ + static findExists(question) { return QuestionService.findOneBy({ where: { exam_id: question.exam_id, content: question.content } }) .then((data) => { if (data) { @@ -158,11 +162,14 @@ class QuestionService { .catch((err) => Promise.reject(err)); } - /* question abierta y numerica solo puede tener una respuesta o graba una vez y despues modifica - !Question.isTrue no ingresa cuando vale 0 - en las preguntas abiertas no deberia guardar en content - */ - static validarParameter(question) { + /** + * Valida los parametros del post para guardar la question, comprueba que los paratros no sean nulos y + * los verifica segun el tipo de pregunta + * @param {object} question datos del post + * @returns {Promise.resolve} message, cuando los parametros son correctos + * @returns {Promise.reject} message, cuando algunos de los parametros faltan validateParameters + */ + static validateParameters(question) { return new Promise((resolve, reject) => { if (!question.exam_id || !question.type_question_id || !question.code || !question.content) { reject("Required parameters are missing"); @@ -189,19 +196,5 @@ class QuestionService { } }); } - - static exist(id) { - - return Question.findByPk(id) - .then((data) => { - if (data) { - return Promise.resolve(data); - } else { - const err = { statusCode: 404, message: "there is no question" }; - return Promise.reject(err); - } - }) - .catch((err) => Promise.reject(err)); - } } module.exports = QuestionService; \ No newline at end of file From f8939e5175216856f955c1bd6818cdef75031dd8 Mon Sep 17 00:00:00 2001 From: Nauel Date: Sun, 13 Sep 2020 23:55:24 -0400 Subject: [PATCH 03/11] fix:service name and parameter validation --- src/controllers/questionController.js | 2 +- src/services/answerService.js | 17 +++++++++++++---- src/services/examService.js | 2 +- src/services/questionService.js | 6 +++--- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/controllers/questionController.js b/src/controllers/questionController.js index 16c2b8a7..e02f4755 100644 --- a/src/controllers/questionController.js +++ b/src/controllers/questionController.js @@ -29,7 +29,7 @@ class questionController { .then(data => examService.findById(question.exam_id)) .then(data => { if (data) { - return QuestionService.findExist(question); + return QuestionService.findExists(question); } else { return res.status(500).json({ err: "Exam does not exist" }); } diff --git a/src/services/answerService.js b/src/services/answerService.js index 67188b87..c58bb762 100644 --- a/src/services/answerService.js +++ b/src/services/answerService.js @@ -6,10 +6,19 @@ class AnswerService { static validate() { return [ - check("code", "code is required").not().isEmpty().isAlphanumeric().isLength({ min: 2, max: 15 }), + check("code", "code is required").not().isEmpty().isLength({ min: 2, max: 15 }).withMessage("Allowable range 2-15"), check("question_id", "question_id is required").not().isEmpty().isNumeric(), check("isTrue", "isTrue is required").not().isEmpty().isIn([1, 0]), - check("score", "score is required").optional().isNumeric(), + check("score", "score is required").custom((val, { req }) => { + if (!val && req.body.isTrue == 1) { + throw new Error("Score is required"); + } else if (val && req.body.isTrue == 0) { + throw new Error("Score not required, because isTrue = false"); + } else if (val && req.body.isTrue == 1 && (val < 0 || val > 100)) { + throw new Error("Allowable range 0-100"); + } + return true; + }) ]; } @@ -116,14 +125,14 @@ class AnswerService { console.log("question", answer.type_question_id); switch (answer.type_question_id) { case typeQuestion.QUESTIONABIERTA: - if (!answer.code || !answer.score) { + if (!answer.code) { reject("Mandatory parameters are missing"); } else { resolve("Correct parameters"); } break; default: - if (!answer.code || !answer.content || !answer.score) { + if (!answer.code || !answer.content) { reject("Mandatory parameters are missing"); } else { resolve("Correct parameters"); diff --git a/src/services/examService.js b/src/services/examService.js index b1c8a665..f9637181 100644 --- a/src/services/examService.js +++ b/src/services/examService.js @@ -9,7 +9,7 @@ class ExamService { static validate() { return [ - check("module_id", "module_id is required").not().isEmpty().isAlphanumeric().isLength({ min: 1, max: 15 }), + check("module_id", "module_id is required").not().isEmpty().isNumeric().isLength({ min: 1, max: 15 }), check("name_exam", "name_exam is required").not().isEmpty().isLength({ min: 2, max: 500 }), ]; } diff --git a/src/services/questionService.js b/src/services/questionService.js index 80c481f4..0e09ede7 100644 --- a/src/services/questionService.js +++ b/src/services/questionService.js @@ -15,7 +15,7 @@ class QuestionService { throw new Error("Mandatory parameters are missing or out of range"); } else return true; }), - check("code", "code is required").not().isEmpty().isAlphanumeric().isLength({ min: 2, max: 15 }), + check("code", "code is required").not().isEmpty().isLength({ min: 2, max: 15 }), check("content", "content is required").not().isEmpty().isLength({ min: 2, max: 500 }), check("help", "help is optional").optional().isLength({ min: 2, max: 500 }), check("minimum").custom((minimum, { req }) => { @@ -184,8 +184,8 @@ class QuestionService { } break; case typeQuestion.QUESTIONNUMERICA: - if (!question.minimum || !question.top || question.minimum == 0 || question.top == 0) { - reject("Required parameters are missing: minimum or top"); + if (!question.minimum || !question.tope || question.minimum == 0 || question.tope == 0) { + reject("Required parameters are missing: minimum or tope"); } else { resolve("Correct parameters"); } From d3a2804c59dc2a1eeb8aa1e8f19019184dec92ec Mon Sep 17 00:00:00 2001 From: Nauel Date: Tue, 15 Sep 2020 14:58:23 -0400 Subject: [PATCH 04/11] fix:use of unnecessary switch and message correction in unit test --- src/services/answerService.js | 32 ++++++++++++++------------------ src/services/questionService.js | 27 ++++++++++++--------------- tests/rest/answer-controller.js | 2 +- 3 files changed, 27 insertions(+), 34 deletions(-) diff --git a/src/services/answerService.js b/src/services/answerService.js index c58bb762..93b2ce9a 100644 --- a/src/services/answerService.js +++ b/src/services/answerService.js @@ -16,8 +16,16 @@ class AnswerService { throw new Error("Score not required, because isTrue = false"); } else if (val && req.body.isTrue == 1 && (val < 0 || val > 100)) { throw new Error("Allowable range 0-100"); + } else { + let cadena = val.toString(); + let expresion = /[0-9]{3}|[0-9]{2}/gi; + let hallado = cadena.match(expresion); + if (hallado && hallado.length == 1 && (cadena.length > 1 && cadena.length < 4)) { + return true; + } else { + throw new Error("Only numbers allowed"); + } } - return true; }) ]; } @@ -122,23 +130,11 @@ class AnswerService { */ static validateParameters(answer) { return new Promise((resolve, reject) => { - console.log("question", answer.type_question_id); - switch (answer.type_question_id) { - case typeQuestion.QUESTIONABIERTA: - if (!answer.code) { - reject("Mandatory parameters are missing"); - } else { - resolve("Correct parameters"); - } - break; - default: - if (!answer.code || !answer.content) { - reject("Mandatory parameters are missing"); - } else { - resolve("Correct parameters"); - } - break; - } + if (answer.type_question_id == typeQuestion.QUESTIONABIERTA && answer.content) { + reject("Parameter CONTENT no required "); + } else if (answer.type_question_id != typeQuestion.QUESTIONABIERTA && !answer.content) { + reject("Mandatory parameters are missing"); + } else return resolve(1); }); } } diff --git a/src/services/questionService.js b/src/services/questionService.js index 0e09ede7..6305c2f2 100644 --- a/src/services/questionService.js +++ b/src/services/questionService.js @@ -35,26 +35,23 @@ class QuestionService { }), check("tope").custom((val, { req }) => { if (!req.body.type_question_id || req.body.type_question_id < 1 || req.body.type_question_id > parseInt(typeQuestion.QUESTIONNUMERICA, 10) + 1) return true; - switch (req.body.type_question_id) { - case typeQuestion.QUESTIONNUMERICA: - if (!val || val === 0) throw new Error("Mandatory parameters are missing"); - break; - default: - if (!val) return true; - else throw new Error("Parameter NOT required"); + if (req.body.type_question_id == typeQuestion.QUESTIONNUMERICA && (!val || val === 0)) { + throw new Error("Mandatory parameters are missing"); + } else if (req.body.type_question_id != typeQuestion.QUESTIONNUMERICA && !val) { + return true; + } else if (req.body.type_question_id != typeQuestion.QUESTIONNUMERICA && val) { + throw new Error("Parameter NOT required"); } - return true; }), check("length").custom((val, { req }) => { if (!req.body.type_question_id || req.body.type_question_id < 1 || req.body.type_question_id > parseInt(typeQuestion.QUESTIONNUMERICA, 10) + 1) return true; - switch (req.body.type_question_id) { - case typeQuestion.QUESTIONABIERTA: - if (!val || val < 1 || val > 500) throw new Error("Mandatory parameters are missing"); - break; - default: - if (!val) { return true; } else { throw new Error("Parameter NOT required"); } + if (req.body.type_question_id == typeQuestion.QUESTIONABIERTA && (!val || val < 1 || val > 500)) { + throw new Error("Mandatory parameters are missing"); + } else if (req.body.type_question_id != typeQuestion.QUESTIONABIERTA && !val) { + return true; + } else if (req.body.type_question_id != typeQuestion.QUESTIONABIERTA && val) { + throw new Error("Parameter NOT required"); } - return true; }) ]; } diff --git a/tests/rest/answer-controller.js b/tests/rest/answer-controller.js index 375a6f31..fd36f2ad 100644 --- a/tests/rest/answer-controller.js +++ b/tests/rest/answer-controller.js @@ -32,7 +32,7 @@ describe("Answer tests", () => { }); }) - it("should return an error if content is empty and type of question is open", (done) => { + it("should return a answer created, if content is empty and type of question is open", (done) => { chai.request(app) .post("/api/v1/answer") From 0f19f12d17e16ad4fa6efee2f71255e7adee4167 Mon Sep 17 00:00:00 2001 From: Nauel Date: Thu, 17 Sep 2020 11:06:24 -0400 Subject: [PATCH 05/11] fix: clearing the unit test record --- tests/rest/answer-controller.js | 78 ++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 17 deletions(-) diff --git a/tests/rest/answer-controller.js b/tests/rest/answer-controller.js index fd36f2ad..27537f5f 100644 --- a/tests/rest/answer-controller.js +++ b/tests/rest/answer-controller.js @@ -1,59 +1,104 @@ const chai = require("chai"); const chaiHttp = require("chai-http"); - +const faker = require("faker"); const app = require("../../src/index"); - +const Answer = require("../../src/models/answer"); const { expect } = chai; chai.use(chaiHttp); describe("Answer tests", () => { + let num; + let res1; + let res2; + + before(() => { + num = faker.random.number(); + }) - describe("Create a answer of Exam", () => { - it("should return a answer created", (done) => { + after(async() => { + + try { + const answer1 = await Answer.findByPk(res1.body.data.id); + if (answer1) await answer1.destroy(); + const answer2 = await Answer.findByPk(res2.body.data.id); + if (answer2) await answer2.destroy(); + } catch (err) { + return new Error("An error has ocurred"); + } + + }); + + describe("Create a answer of question open", () => { + + it("should return a answer created, if content is empty", (done) => { chai.request(app) .post("/api/v1/answer") .send({ "code": "r11", - "question_id": 3, - "content": "naranja_99", + "question_id": 1, "isTrue": 1, "score": 10 }) .end(function(err, res) { if (err) done(err); - //console.log(res) - expect(res).to.have.status(200); + res1 = res; expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + expect(res).to.have.status(200); + done(); + }); }) + }) + + describe("Create a answer of closed question multiple choice", () => { - it("should return a answer created, if content is empty and type of question is open", (done) => { + it("Should return a Answer Created", (done) => { chai.request(app) .post("/api/v1/answer") .send({ - "code": "r11", - "question_id": 1, + "code": "r3." + num, + "question_id": 5, + "content": "naranja" + num, "isTrue": 1, "score": 10 }) .end(function(err, res) { if (err) done(err); - //console.log(res) - expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + res2 = res; expect(res).to.have.status(200); - + expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); done(); + }); + }); + + it("Should return a Error, the content is the same as the previous answer", (done) => { + + chai.request(app) + .post("/api/v1/answer") + .send({ + "code": "r3." + num, + "question_id": 5, + "content": "naranja" + num, + "isTrue": 1, + "score": 10 + }) + .end(function(err, res) { + if (err) done(err); + + expect(res).to.have.status(500); + expect(JSON.parse(res.text)).to.have.all.keys("err"); + done(); }); - }) + }); it("should return an error if content is empty and type of question is not open", (done) => { @@ -76,7 +121,7 @@ describe("Answer tests", () => { done(); }); - }) + }); it("should return an error if question_id is empty", (done) => { @@ -101,5 +146,4 @@ describe("Answer tests", () => { }); }); - }) \ No newline at end of file From 4c865f0b9743bdcf41609106ab6a152d6197d204 Mon Sep 17 00:00:00 2001 From: Nauel Date: Fri, 18 Sep 2020 19:53:59 -0400 Subject: [PATCH 06/11] fix:variable names and classes --- config/enum/typeOfQuestion.js | 8 +-- .../migrations/20200830010509-create-exam.js | 2 +- .../20200830010510-create-question.js | 4 +- .../20200830010511-create-answer.js | 2 +- .../20200830010512-create-student_exam.js | 4 +- .../20200830010514-create-student-answer.js | 8 +-- database/seeders/20200828135836-exams.js | 8 +-- database/seeders/20200830142733-questions.js | 16 ++--- database/seeders/20200830142801-answers.js | 28 ++++---- .../seeders/20200830142900-student_answers.js | 16 ++--- .../seeders/20200830142910-student_exams.js | 8 +-- src/api/routes/answers.js | 14 ++-- src/api/routes/exams.js | 6 +- src/controllers/answerController.js | 30 ++++---- src/controllers/examController.js | 6 +- src/controllers/questionController.js | 13 ++-- src/models/answer.js | 2 +- src/models/exam.js | 2 +- src/models/question.js | 4 +- src/models/student_answer.js | 8 +-- src/models/student_exam.js | 4 +- src/services/answerService.js | 48 ++++++++----- src/services/examService.js | 20 +++--- src/services/questionService.js | 68 +++++++++---------- tests/rest/answer-controller.js | 10 +-- 25 files changed, 176 insertions(+), 163 deletions(-) diff --git a/config/enum/typeOfQuestion.js b/config/enum/typeOfQuestion.js index e26bd1f6..9528d9bc 100644 --- a/config/enum/typeOfQuestion.js +++ b/config/enum/typeOfQuestion.js @@ -1,8 +1,8 @@ const typeQuestion = { - QUESTIONABIERTA: 1, - QUESTIONCERRADA: 2, - QUESTIONMULTIPLE: 3, - QUESTIONNUMERICA: 4, + OPENQUESTION: 1, + CLOSEDQUESTION: 2, + MULTIPLEQUESTION: 3, + NUMERICALQUESTION: 4, }; module.exports = typeQuestion; \ No newline at end of file diff --git a/database/migrations/20200830010509-create-exam.js b/database/migrations/20200830010509-create-exam.js index d394e7dc..2cf55a3a 100644 --- a/database/migrations/20200830010509-create-exam.js +++ b/database/migrations/20200830010509-create-exam.js @@ -8,7 +8,7 @@ module.exports = { autoIncrement: true, primaryKey: true, }, - module_id: { + moduleId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'modules', key: 'id' } diff --git a/database/migrations/20200830010510-create-question.js b/database/migrations/20200830010510-create-question.js index b47e2add..1d249094 100644 --- a/database/migrations/20200830010510-create-question.js +++ b/database/migrations/20200830010510-create-question.js @@ -8,12 +8,12 @@ module.exports = { autoIncrement: true, primaryKey: true, }, - exam_id: { + examId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'exams', key: 'id' } }, - type_question_id: { + typeQuestionId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'type_questions', key: 'id' } diff --git a/database/migrations/20200830010511-create-answer.js b/database/migrations/20200830010511-create-answer.js index 6b0c118f..bd64e53a 100644 --- a/database/migrations/20200830010511-create-answer.js +++ b/database/migrations/20200830010511-create-answer.js @@ -12,7 +12,7 @@ module.exports = { type: Sequelize.STRING, allowNull: false, }, - question_id: { + questionId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'questions', key: 'id' } diff --git a/database/migrations/20200830010512-create-student_exam.js b/database/migrations/20200830010512-create-student_exam.js index d79592c8..dcf3fc54 100644 --- a/database/migrations/20200830010512-create-student_exam.js +++ b/database/migrations/20200830010512-create-student_exam.js @@ -8,12 +8,12 @@ module.exports = { primaryKey: true, type: Sequelize.INTEGER }, - student_id: { + studentId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'students', key: 'id' } }, - exam_id: { + examId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'exams', key: 'id' } diff --git a/database/migrations/20200830010514-create-student-answer.js b/database/migrations/20200830010514-create-student-answer.js index ee2712ee..36dad460 100644 --- a/database/migrations/20200830010514-create-student-answer.js +++ b/database/migrations/20200830010514-create-student-answer.js @@ -8,22 +8,22 @@ module.exports = { primaryKey: true, type: Sequelize.INTEGER }, - exam_id: { + examId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'exams', key: 'id' } }, - question_id: { + questionId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'questions', key: 'id' } }, - type_question_id: { + typeQuestionId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'type_questions', key: 'id' } }, - student_id: { + studentId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'students', key: 'id' } diff --git a/database/seeders/20200828135836-exams.js b/database/seeders/20200828135836-exams.js index c25cfd27..b5b538ea 100644 --- a/database/seeders/20200828135836-exams.js +++ b/database/seeders/20200828135836-exams.js @@ -5,10 +5,10 @@ module.exports = { up: async(queryInterface, Sequelize) => { let obj = [ - { module_id: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { module_id: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { module_id: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { module_id: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { moduleId: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { moduleId: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { moduleId: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { moduleId: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, ]; await queryInterface.bulkInsert('exams', obj, {}); }, diff --git a/database/seeders/20200830142733-questions.js b/database/seeders/20200830142733-questions.js index 991154e5..086ada8a 100644 --- a/database/seeders/20200830142733-questions.js +++ b/database/seeders/20200830142733-questions.js @@ -3,14 +3,14 @@ const faker = require('faker'); module.exports = { up: async(queryInterface, Sequelize) => { let obj = [ - { exam_id: 1, type_question_id: 1, code: 'p1', content: faker.name.findName(), minimum: 9, length: 100, createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, type_question_id: 1, code: 'p2', content: faker.name.findName(), minimum: 1, length: 100, createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, type_question_id: 2, code: 'p3', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, type_question_id: 2, code: 'p4', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, type_question_id: 3, code: 'p5', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, type_question_id: 3, code: 'p6', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, type_question_id: 4, code: 'p7', content: faker.name.findName(), minimum: 1, tope: 100, createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, type_question_id: 4, code: 'p8', content: faker.name.findName(), minimum: 1, tope: 100, createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 1, code: 'p1', content: faker.name.findName(), minimum: 9, length: 100, createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 1, code: 'p2', content: faker.name.findName(), minimum: 1, length: 100, createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 2, code: 'p3', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 2, code: 'p4', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 3, code: 'p5', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 3, code: 'p6', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 4, code: 'p7', content: faker.name.findName(), minimum: 1, tope: 100, createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 4, code: 'p8', content: faker.name.findName(), minimum: 1, tope: 100, createdAt: new Date(), updatedAt: new Date() }, ]; await queryInterface.bulkInsert('questions', obj, {}); }, diff --git a/database/seeders/20200830142801-answers.js b/database/seeders/20200830142801-answers.js index 7168f617..9f717bea 100644 --- a/database/seeders/20200830142801-answers.js +++ b/database/seeders/20200830142801-answers.js @@ -4,20 +4,20 @@ const faker = require('faker'); module.exports = { up: async(queryInterface, Sequelize) => { let obj = [ - { code: 'rta31', question_id: 3, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta32', question_id: 3, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta33', question_id: 3, content: faker.name.findName(), isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta41', question_id: 4, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta42', question_id: 4, content: faker.name.findName(), isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta43', question_id: 4, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta51', question_id: 5, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta52', question_id: 5, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta53', question_id: 5, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta61', question_id: 6, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta62', question_id: 6, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta63', question_id: 6, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta7', question_id: 7, content: '70', isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta8', question_id: 8, content: '17', isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta31', questionId: 3, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta32', questionId: 3, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta33', questionId: 3, content: faker.name.findName(), isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta41', questionId: 4, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta42', questionId: 4, content: faker.name.findName(), isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta43', questionId: 4, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta51', questionId: 5, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta52', questionId: 5, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta53', questionId: 5, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta61', questionId: 6, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta62', questionId: 6, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta63', questionId: 6, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta7', questionId: 7, content: '70', isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, + { code: 'rta8', questionId: 8, content: '17', isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, ]; await queryInterface.bulkInsert('answers', obj, {}); }, diff --git a/database/seeders/20200830142900-student_answers.js b/database/seeders/20200830142900-student_answers.js index e1dc7ca8..94e42f46 100644 --- a/database/seeders/20200830142900-student_answers.js +++ b/database/seeders/20200830142900-student_answers.js @@ -5,14 +5,14 @@ module.exports = { up: async(queryInterface, Sequelize) => { let obj = [ - { exam_id: 1, question_id: 1, type_question_id: 1, student_id: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, question_id: 2, type_question_id: 1, student_id: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, question_id: 3, type_question_id: 2, student_id: 1, date_of_answer: new Date(), code_answer: 'id1,cod1', student_answer: 'content 1', createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, question_id: 4, type_question_id: 2, student_id: 1, date_of_answer: new Date(), code_answer: 'id2,cod2', student_answer: 'content 2', createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, question_id: 5, type_question_id: 3, student_id: 1, date_of_answer: new Date(), code_answer: 'id1,cod1;id2,cod2', student_answer: 'content 1;content 2', createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, question_id: 6, type_question_id: 3, student_id: 1, date_of_answer: new Date(), code_answer: 'id1,cod1;id2,cod2', student_answer: 'content 1;content 2', createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, question_id: 7, type_question_id: 4, student_id: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.random.number(), createdAt: new Date(), updatedAt: new Date() }, - { exam_id: 1, question_id: 8, type_question_id: 4, student_id: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.random.number(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 1, typeQuestionId: 1, studentId: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 2, typeQuestionId: 1, studentId: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 3, typeQuestionId: 2, studentId: 1, date_of_answer: new Date(), code_answer: 'id1,cod1', student_answer: 'content 1', createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 4, typeQuestionId: 2, studentId: 1, date_of_answer: new Date(), code_answer: 'id2,cod2', student_answer: 'content 2', createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 5, typeQuestionId: 3, studentId: 1, date_of_answer: new Date(), code_answer: 'id1,cod1;id2,cod2', student_answer: 'content 1;content 2', createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 6, typeQuestionId: 3, studentId: 1, date_of_answer: new Date(), code_answer: 'id1,cod1;id2,cod2', student_answer: 'content 1;content 2', createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 7, typeQuestionId: 4, studentId: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.random.number(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 8, typeQuestionId: 4, studentId: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.random.number(), createdAt: new Date(), updatedAt: new Date() }, ]; await queryInterface.bulkInsert('student_answers', obj, {}); }, diff --git a/database/seeders/20200830142910-student_exams.js b/database/seeders/20200830142910-student_exams.js index 8393ae89..ece01a3d 100644 --- a/database/seeders/20200830142910-student_exams.js +++ b/database/seeders/20200830142910-student_exams.js @@ -3,10 +3,10 @@ module.exports = { up: async(queryInterface, Sequelize) => { let obj = [ - { student_id: 1, exam_id: 1, createdAt: new Date(), updatedAt: new Date() }, - { student_id: 1, exam_id: 2, createdAt: new Date(), updatedAt: new Date() }, - { student_id: 1, exam_id: 3, createdAt: new Date(), updatedAt: new Date() }, - { student_id: 1, exam_id: 4, createdAt: new Date(), updatedAt: new Date() }, + { studentId: 1, examId: 1, createdAt: new Date(), updatedAt: new Date() }, + { studentId: 1, examId: 2, createdAt: new Date(), updatedAt: new Date() }, + { studentId: 1, examId: 3, createdAt: new Date(), updatedAt: new Date() }, + { studentId: 1, examId: 4, createdAt: new Date(), updatedAt: new Date() }, ]; await queryInterface.bulkInsert('student_exams', obj, {}); }, diff --git a/src/api/routes/answers.js b/src/api/routes/answers.js index b5005b5c..0dfadba6 100644 --- a/src/api/routes/answers.js +++ b/src/api/routes/answers.js @@ -1,14 +1,14 @@ const express = require("express"); const router = express.Router(); -const answerController = require("../../controllers/answerController"); +const AnswerController = require("../../controllers/answerController"); const { validator } = require("../middlewares/validator"); const AnswerService = require("../../services/answerService"); -router.post("/", validator(AnswerService.validate()), answerController.createAnswer); -router.get("/:id", answerController.getAnswer); -router.get("/question/:question_id", answerController.getByQuestion); -router.delete("/:id", answerController.deleteAnswer); -router.put("/:id", answerController.updateAnswer); -router.get("/", answerController.listAll); +router.post("/", validator(AnswerService.validate()), AnswerController.createAnswer); +router.get("/:id", AnswerController.getAnswer); +router.get("/question/:questionId", AnswerController.getByQuestion); +router.delete("/:id", AnswerController.deleteAnswer); +router.put("/:id", AnswerController.updateAnswer); +router.get("/", AnswerController.listAll); module.exports = router; \ No newline at end of file diff --git a/src/api/routes/exams.js b/src/api/routes/exams.js index 8f620d11..8741db80 100644 --- a/src/api/routes/exams.js +++ b/src/api/routes/exams.js @@ -1,11 +1,11 @@ const express = require("express"); const router = express.Router(); -const examController = require("../../controllers/examController"); +const ExamController = require("../../controllers/examController"); const ExamService = require("../../services/examService"); const { validator } = require("../middlewares/validator"); -router.post("/", validator(ExamService.validate()), examController.createExam); -router.get("/:id", examController.getExamComplet); +router.post("/", validator(ExamService.validate()), ExamController.createExam); +router.get("/:id", ExamController.getExamComplet); module.exports = router; diff --git a/src/controllers/answerController.js b/src/controllers/answerController.js index 05f32dbd..b4534cc9 100644 --- a/src/controllers/answerController.js +++ b/src/controllers/answerController.js @@ -1,8 +1,8 @@ const AnswerService = require("../services/answerService"); -const questionService = require("../services/questionService"); +const QuestionService = require("../services/questionService"); const typeQuestion = require("../../config/enum/typeOfQuestion"); -class answerController { +class AnswerController { static async listAll(req, res) { try { @@ -15,19 +15,19 @@ class answerController { static createAnswer(req, res) { let existsQuestion = {}; - return questionService.findById(req.body.question_id) + const answerVerify = req.body; + return QuestionService.findById(req.body.questionId) .then(data => { if (data) { existsQuestion = data; - const answerVerify = req.body; - answerVerify.type_question_id = data.type_question_id; + answerVerify.typeQuestionId = data.typeQuestionId; return AnswerService.validateParameters(answerVerify); } else { return Promise.reject({ err: "The question not exists. " }); } }) .then(data => { - const query = ((existsQuestion.type_question_id === typeQuestion.QUESTIONABIERTA || existsQuestion.type_question_id === typeQuestion.QUESTIONNUMERICA) ? { where: { question_id: req.body.question_id } } : { where: { question_id: req.body.question_id, content: req.body.content } }); + const query = ((existsQuestion.typeQuestionId === typeQuestion.OPENQUESTION || existsQuestion.typeQuestionId === typeQuestion.NUMERICALQUESTION) ? { where: { questionId: req.body.questionId } } : { where: { questionId: req.body.questionId, content: req.body.content } }); return AnswerService.findOneBy(query); }) .then(data => { @@ -50,10 +50,10 @@ class answerController { static async getByQuestion(req, res) { try { - const { question_id } = req.params; - const consulta = { where: { question_id: question_id } }; - const getanswer = await AnswerService.findAllBy(consulta); - return res.status(200).json({ message: "Sucessfull Ejecution", data: getanswer }); + const { questionId } = req.params; + const query = { where: { questionId: questionId } }; + const answer = await AnswerService.findAllBy(query); + return res.status(200).json({ message: "Sucessfull Ejecution", data: answer }); } catch (err) { return res.status(500).json({ err }); } @@ -62,8 +62,8 @@ class answerController { static async updateAnswer(req, res) { try { const { id } = req.params; - const updateanswer = await AnswerService.update(req.body, id); - return res.status(200).json({ message: "Sucessfull Ejecution", data: updateanswer }); + const answer = await AnswerService.update(req.body, id); + return res.status(200).json({ message: "Sucessfull Ejecution", data: answer }); } catch (err) { return res.status(500).json({ err }); } @@ -72,11 +72,11 @@ class answerController { static async deleteAnswer(req, res) { try { const { id } = req.params; - const deleteanswer = await AnswerService.delete(id); - return res.status(200).json({ message: "Delete Sucessfull", data: deleteanswer }); + const answer = await AnswerService.delete(id); + return res.status(200).json({ message: "Delete Sucessfull", data: answer }); } catch (err) { return res.status(500).json({ err }); } } } -module.exports = answerController; \ No newline at end of file +module.exports = AnswerController; \ No newline at end of file diff --git a/src/controllers/examController.js b/src/controllers/examController.js index 0648e0f2..219a01e3 100644 --- a/src/controllers/examController.js +++ b/src/controllers/examController.js @@ -1,6 +1,6 @@ const ExamService = require("../services/examService"); -class examController { +class ExamController { static getExamComplet(req, res) { return ExamService.findAllById(req.params.id) @@ -28,7 +28,7 @@ class examController { static createExam(req, res) { const exam = { - module_id: req.body.module_id, + moduleId: req.body.moduleId, type: req.body.type, name_exam: req.body.name_exam }; @@ -39,4 +39,4 @@ class examController { } } -module.exports = examController; \ No newline at end of file +module.exports = ExamController; \ No newline at end of file diff --git a/src/controllers/questionController.js b/src/controllers/questionController.js index e02f4755..0c699a0b 100644 --- a/src/controllers/questionController.js +++ b/src/controllers/questionController.js @@ -1,6 +1,7 @@ const QuestionService = require("../services/questionService"); -const examService = require("../services/examService"); -class questionController { +const ExamService = require("../services/examService"); + +class QuestionController { static getQuestion(req, res) { return QuestionService.findById(req.params.id) @@ -16,8 +17,8 @@ class questionController { static createQuestion(req, res) { const question = { - exam_id: req.body.exam_id, - type_question_id: req.body.type_question_id, + examId: req.body.examId, + typeQuestionId: req.body.typeQuestionId, code: req.body.code, content: req.body.content, minimum: req.body.minimum, @@ -26,7 +27,7 @@ class questionController { help: req.body.help } //= req.body; return QuestionService.validateParameters(question) - .then(data => examService.findById(question.exam_id)) + .then(data => ExamService.findById(question.examId)) .then(data => { if (data) { return QuestionService.findExists(question); @@ -40,4 +41,4 @@ class questionController { } } -module.exports = questionController; \ No newline at end of file +module.exports = QuestionController; \ No newline at end of file diff --git a/src/models/answer.js b/src/models/answer.js index 180b4731..3c7a0146 100644 --- a/src/models/answer.js +++ b/src/models/answer.js @@ -12,7 +12,7 @@ const Answer = sequelize.define('answers', { type: Sequelize.STRING, allowNull: false, }, - question_id: { + questionId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'questions', key: 'id' } diff --git a/src/models/exam.js b/src/models/exam.js index c4122e18..eef83643 100644 --- a/src/models/exam.js +++ b/src/models/exam.js @@ -8,7 +8,7 @@ const Exam = sequelize.define('exams', { autoIncrement: true, primaryKey: true, }, - module_id: { + moduleId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'modules', key: 'id' } diff --git a/src/models/question.js b/src/models/question.js index 83316798..8c8b7eab 100644 --- a/src/models/question.js +++ b/src/models/question.js @@ -8,12 +8,12 @@ const Question = sequelize.define('questions', { autoIncrement: true, primaryKey: true, }, - exam_id: { + examId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'exams', key: 'id' } }, - type_question_id: { + typeQuestionId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'type_questions', key: 'id' } diff --git a/src/models/student_answer.js b/src/models/student_answer.js index a0cb1c2a..72e94386 100644 --- a/src/models/student_answer.js +++ b/src/models/student_answer.js @@ -8,22 +8,22 @@ const Student_Answer = sequelize.define('student_answers', { primaryKey: true, type: Sequelize.INTEGER }, - exam_id: { + examId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'exams', key: 'id' } }, - question_id: { + questionId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'questions', key: 'id' } }, - type_question_id: { + typeQuestionId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'type_questions', key: 'id' } }, - student_id: { + studentId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'students', key: 'id' } diff --git a/src/models/student_exam.js b/src/models/student_exam.js index 6bd78dec..c1ae7bfd 100644 --- a/src/models/student_exam.js +++ b/src/models/student_exam.js @@ -8,12 +8,12 @@ const Student_Exam = sequelize.define('student_exams', { primaryKey: true, type: Sequelize.INTEGER }, - student_id: { + studentId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'students', key: 'id' } }, - exam_id: { + examId: { type: Sequelize.INTEGER, allowNull: false, references: { model: 'exams', key: 'id' } diff --git a/src/services/answerService.js b/src/services/answerService.js index 93b2ce9a..14a1a194 100644 --- a/src/services/answerService.js +++ b/src/services/answerService.js @@ -1,4 +1,6 @@ const Answer = require("../models/answer"); +const ExamService = require("./examService"); +const QuestionService = require("./questionService"); const { check } = require("express-validator"); const typeQuestion = require("../../config/enum/typeOfQuestion"); @@ -7,7 +9,7 @@ class AnswerService { static validate() { return [ check("code", "code is required").not().isEmpty().isLength({ min: 2, max: 15 }).withMessage("Allowable range 2-15"), - check("question_id", "question_id is required").not().isEmpty().isNumeric(), + check("questionId", "questionId is required").not().isEmpty().isNumeric(), check("isTrue", "isTrue is required").not().isEmpty().isIn([1, 0]), check("score", "score is required").custom((val, { req }) => { if (!val && req.body.isTrue == 1) { @@ -17,10 +19,10 @@ class AnswerService { } else if (val && req.body.isTrue == 1 && (val < 0 || val > 100)) { throw new Error("Allowable range 0-100"); } else { - let cadena = val.toString(); - let expresion = /[0-9]{3}|[0-9]{2}/gi; - let hallado = cadena.match(expresion); - if (hallado && hallado.length == 1 && (cadena.length > 1 && cadena.length < 4)) { + let chain = val.toString(); + let expression = /[0-9]{3}|[0-9]{2}/gi; + let found = chain.match(expression); + if (found && found.length == 1 && (chain.length > 1 && chain.length < 4)) { return true; } else { throw new Error("Only numbers allowed"); @@ -43,10 +45,10 @@ class AnswerService { static async create(data) { try { - const { code, question_id, content, isTrue, score } = data; + const { code, questionId, content, isTrue, score } = data; const answerCreated = await Answer.create({ code, - question_id, + questionId, content, isTrue, score, @@ -70,20 +72,20 @@ class AnswerService { } } - static async findOneBy(consulta) { + static async findOneBy(query) { try { - const answerExiste = await Answer.findOne(consulta); - if (answerExiste) { - return answerExiste; + const answerExists = await Answer.findOne(query); + if (answerExists) { + return answerExists; } } catch (err) { return new Error("An error has ocurred"); } } - static async finAllBy(consulta) { + static async finAllBy(query) { try { - const allAnswer = await Answer.findAll(consulta); + const allAnswer = await Answer.findAll(query); if (allAnswer) { return allAnswer; } @@ -103,14 +105,26 @@ class AnswerService { } } + static async findExam(query) { + try { + const data = await QuestionService.findOneBy({ where: { id: query.questionId } }); + if (data) { + const answerExists = await ExamService.findOneBy({ where: { id: data.examId } }); + return answerExists; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + static async update(data, id) { try { - const { code, question_id, content, isTrue, score } = data; + const { code, questionId, content, isTrue, score } = data; const foundAnswer = await Answer.findByPk(id); if (foundAnswer) { foundAnswer.update({ code, - question_id, + questionId, content, isTrue, score, @@ -130,9 +144,9 @@ class AnswerService { */ static validateParameters(answer) { return new Promise((resolve, reject) => { - if (answer.type_question_id == typeQuestion.QUESTIONABIERTA && answer.content) { + if (answer.typeQuestionId == typeQuestion.OPENQUESTION && answer.content) { reject("Parameter CONTENT no required "); - } else if (answer.type_question_id != typeQuestion.QUESTIONABIERTA && !answer.content) { + } else if (answer.typeQuestionId != typeQuestion.OPENQUESTION && !answer.content) { reject("Mandatory parameters are missing"); } else return resolve(1); }); diff --git a/src/services/examService.js b/src/services/examService.js index f9637181..7b83af16 100644 --- a/src/services/examService.js +++ b/src/services/examService.js @@ -9,7 +9,7 @@ class ExamService { static validate() { return [ - check("module_id", "module_id is required").not().isEmpty().isNumeric().isLength({ min: 1, max: 15 }), + check("moduleId", "moduleId is required").not().isEmpty().isNumeric().isLength({ min: 1, max: 15 }), check("name_exam", "name_exam is required").not().isEmpty().isLength({ min: 2, max: 500 }), ]; } @@ -27,9 +27,9 @@ class ExamService { static async create(data) { try { - const { module_id, type, name_exam } = data; + const { moduleId, type, name_exam } = data; const hereExam = await Exam.create({ - module_id, + moduleId, type, name_exam }); @@ -64,11 +64,11 @@ class ExamService { static async update(data, id) { try { - const { module_id, type, name_exam } = data; + const { moduleId, type, name_exam } = data; const hereExam = await Exam.findByPk(id); if (hereExam) { hereExam.update({ - module_id, + moduleId, type, name_exam }); @@ -79,9 +79,9 @@ class ExamService { } } - static async findOneBy(consulta) { + static async findOneBy(query) { try { - const hereExam = await Exam.findOne(consulta); + const hereExam = await Exam.findOne(query); if (hereExam) { return hereExam; } @@ -94,8 +94,8 @@ class ExamService { let query = ` SELECT * FROM exams e - inner join questions as q on q.exam_id = e.id - INNER JOIN answers AS a ON a.question_id = q.id + inner join questions as q on q.examId = e.id + INNER JOIN answers AS a ON a.questionId = q.id where e.id =:id;`; return sequelize.query(query, { replacements: { id: id }, type: sequelize.QueryTypes.SELECT }); } @@ -106,7 +106,7 @@ class ExamService { * @returns {Promise} message error if it exists */ static findExists(exam) { - return Exam.findOne({ where: { module_id: exam.module_id, name_exam: exam.name_exam } }) + return Exam.findOne({ where: { moduleId: exam.moduleId, name_exam: exam.name_exam } }) .then((data) => { if (data) { const err = "The record exists"; diff --git a/src/services/questionService.js b/src/services/questionService.js index 6305c2f2..d0954f65 100644 --- a/src/services/questionService.js +++ b/src/services/questionService.js @@ -1,6 +1,5 @@ /* eslint-disable indent */ const Question = require("../models/question"); -const exam = require("./examService") const { check } = require("express-validator"); const typeQuestion = require("../../config/enum/typeOfQuestion"); @@ -9,9 +8,9 @@ class QuestionService { static validate() { return [ - check("exam_id", "exam_id is required").not().isEmpty(), - check("type_question_id", "type_question_id is required").not().isEmpty().isNumeric().custom((val, { req }) => { - if (!val || val < 0 || val > parseInt(typeQuestion.QUESTIONNUMERICA, 10) + 1) { + check("examId", "examId is required").not().isEmpty(), + check("typeQuestionId", "typeQuestionId is required").not().isEmpty().isNumeric().custom((val, { req }) => { + if (!val || val < 0 || val > parseInt(typeQuestion.NUMERICALQUESTION, 10) + 1) { throw new Error("Mandatory parameters are missing or out of range"); } else return true; }), @@ -19,12 +18,12 @@ class QuestionService { check("content", "content is required").not().isEmpty().isLength({ min: 2, max: 500 }), check("help", "help is optional").optional().isLength({ min: 2, max: 500 }), check("minimum").custom((minimum, { req }) => { - if (!req.body.type_question_id || req.body.type_question_id < 1 || req.body.type_question_id > parseInt(typeQuestion.QUESTIONNUMERICA, 10) + 1) return true; - switch (req.body.type_question_id) { - case typeQuestion.QUESTIONABIERTA: + if (!req.body.typeQuestionId || req.body.typeQuestionId < 1 || req.body.typeQuestionId > parseInt(typeQuestion.NUMERICALQUESTION, 10) + 1) return true; + switch (req.body.typeQuestionId) { + case typeQuestion.OPENQUESTION: if (!minimum || minimum < 1) throw new Error("Mandatory parameters are missing"); break; - case typeQuestion.QUESTIONNUMERICA: + case typeQuestion.NUMERICALQUESTION: if (!minimum || minimum === 0) throw new Error("Mandatory parameters are missing"); break; default: @@ -34,22 +33,22 @@ class QuestionService { return true; }), check("tope").custom((val, { req }) => { - if (!req.body.type_question_id || req.body.type_question_id < 1 || req.body.type_question_id > parseInt(typeQuestion.QUESTIONNUMERICA, 10) + 1) return true; - if (req.body.type_question_id == typeQuestion.QUESTIONNUMERICA && (!val || val === 0)) { + if (!req.body.typeQuestionId || req.body.typeQuestionId < 1 || req.body.typeQuestionId > parseInt(typeQuestion.NUMERICALQUESTION, 10) + 1) return true; + if (req.body.typeQuestionId == typeQuestion.NUMERICALQUESTION && (!val || val === 0)) { throw new Error("Mandatory parameters are missing"); - } else if (req.body.type_question_id != typeQuestion.QUESTIONNUMERICA && !val) { + } else if (req.body.typeQuestionId != typeQuestion.NUMERICALQUESTION && !val) { return true; - } else if (req.body.type_question_id != typeQuestion.QUESTIONNUMERICA && val) { + } else if (req.body.typeQuestionId != typeQuestion.NUMERICALQUESTION && val) { throw new Error("Parameter NOT required"); } }), check("length").custom((val, { req }) => { - if (!req.body.type_question_id || req.body.type_question_id < 1 || req.body.type_question_id > parseInt(typeQuestion.QUESTIONNUMERICA, 10) + 1) return true; - if (req.body.type_question_id == typeQuestion.QUESTIONABIERTA && (!val || val < 1 || val > 500)) { + if (!req.body.typeQuestionId || req.body.typeQuestionId < 1 || req.body.typeQuestionId > parseInt(typeQuestion.NUMERICALQUESTION, 10) + 1) return true; + if (req.body.typeQuestionId == typeQuestion.OPENQUESTION && (!val || val < 1 || val > 500)) { throw new Error("Mandatory parameters are missing"); - } else if (req.body.type_question_id != typeQuestion.QUESTIONABIERTA && !val) { + } else if (req.body.typeQuestionId != typeQuestion.OPENQUESTION && !val) { return true; - } else if (req.body.type_question_id != typeQuestion.QUESTIONABIERTA && val) { + } else if (req.body.typeQuestionId != typeQuestion.OPENQUESTION && val) { throw new Error("Parameter NOT required"); } }) @@ -69,10 +68,10 @@ class QuestionService { static async create(data) { try { - const { exam_id, type_question_id, code, content, minimum, tope, length, help } = data; + const { examId, typeQuestionId, code, content, minimum, tope, length, help } = data; const question = await Question.create({ - exam_id, - type_question_id, + examId, + typeQuestionId, code, content, minimum, @@ -111,12 +110,12 @@ class QuestionService { static async update(data, id) { try { - const { code, question_id, content, isTrue, score } = data; + const { code, questionId, content, isTrue, score } = data; const question = await Question.findByPk(id); if (question) { question.update({ code, - question_id, + questionId, content, isTrue, score, @@ -128,11 +127,11 @@ class QuestionService { } } - static async findOneBy(consulta) { + static async findOneBy(query) { try { - const questionExiste = await Question.findOne(consulta); - if (questionExiste) { - return questionExiste; + const questionExists = await Question.findOne(query); + if (questionExists) { + return questionExists; } } catch (err) { return new Error("An error has ocurred"); @@ -146,7 +145,7 @@ class QuestionService { * @returns {Promise} reject, when the question exists in the exam */ static findExists(question) { - return QuestionService.findOneBy({ where: { exam_id: question.exam_id, content: question.content } }) + return QuestionService.findOneBy({ where: { examId: question.examId, content: question.content } }) .then((data) => { if (data) { const err = { error: "The Question already exists" }; @@ -160,19 +159,18 @@ class QuestionService { } /** - * Valida los parametros del post para guardar la question, comprueba que los paratros no sean nulos y - * los verifica segun el tipo de pregunta - * @param {object} question datos del post - * @returns {Promise.resolve} message, cuando los parametros son correctos - * @returns {Promise.reject} message, cuando algunos de los parametros faltan validateParameters + * Validate the parameters of the post, check that they are not null according to the type of question + * @param {object} question post data + * @returns {Promise.resolve} message, when the parameters are correct + * @returns {Promise.reject} message, when some of the parameters are missing */ static validateParameters(question) { return new Promise((resolve, reject) => { - if (!question.exam_id || !question.type_question_id || !question.code || !question.content) { + if (!question.examId || !question.typeQuestionId || !question.code || !question.content) { reject("Required parameters are missing"); } else { - switch (question.type_question_id) { - case typeQuestion.QUESTIONABIERTA: + switch (question.typeQuestionId) { + case typeQuestion.OPENQUESTION: if (!question.length || question.length == 0) { console.log("Required parameters are missing"); reject("Required parameters are missing"); @@ -180,7 +178,7 @@ class QuestionService { resolve("Correct parameters"); } break; - case typeQuestion.QUESTIONNUMERICA: + case typeQuestion.NUMERICALQUESTION: if (!question.minimum || !question.tope || question.minimum == 0 || question.tope == 0) { reject("Required parameters are missing: minimum or tope"); } else { diff --git a/tests/rest/answer-controller.js b/tests/rest/answer-controller.js index 27537f5f..44ccf8e8 100644 --- a/tests/rest/answer-controller.js +++ b/tests/rest/answer-controller.js @@ -37,7 +37,7 @@ describe("Answer tests", () => { .post("/api/v1/answer") .send({ "code": "r11", - "question_id": 1, + "questionId": 1, "isTrue": 1, "score": 10 }) @@ -63,7 +63,7 @@ describe("Answer tests", () => { .post("/api/v1/answer") .send({ "code": "r3." + num, - "question_id": 5, + "questionId": 5, "content": "naranja" + num, "isTrue": 1, "score": 10 @@ -85,7 +85,7 @@ describe("Answer tests", () => { .post("/api/v1/answer") .send({ "code": "r3." + num, - "question_id": 5, + "questionId": 5, "content": "naranja" + num, "isTrue": 1, "score": 10 @@ -106,7 +106,7 @@ describe("Answer tests", () => { .post("/api/v1/answer") .send({ "code": "r12", - "question_id": 3, + "questionId": 3, "isTrue": 1, "score": 10 }) @@ -123,7 +123,7 @@ describe("Answer tests", () => { }); }); - it("should return an error if question_id is empty", (done) => { + it("should return an error if questionId is empty", (done) => { chai.request(app) .post("/api/v1/answer") From f8de91704aed0162dc0553c1508a0a830cfb0ad1 Mon Sep 17 00:00:00 2001 From: Nauel Date: Sat, 3 Oct 2020 20:11:25 -0400 Subject: [PATCH 07/11] fix: update method of question, answer and exam --- .../migrations/20200830010509-create-exam.js | 6 +- database/seeders/20200828135836-exams.js | 8 +- database/seeders/20200830142733-questions.js | 21 +- database/seeders/20200830142801-answers.js | 29 +- .../seeders/20200830142900-student_answers.js | 20 +- .../seeders/20200830142910-student_exams.js | 6 +- src/api/routes/answers.js | 2 +- src/api/routes/exams.js | 4 +- src/api/routes/questions.js | 1 + src/controllers/answerController.js | 37 ++- src/controllers/examController.js | 36 ++- src/controllers/questionController.js | 42 ++- src/models/exam.js | 6 +- src/services/answerService.js | 65 +++- src/services/examService.js | 90 ++++-- src/services/questionService.js | 80 ++++- tests/rest/answer-controller.js | 251 +++++++++++++--- tests/rest/exams.js | 109 +++++++ tests/rest/question.js | 283 ++++++++++++++++++ 19 files changed, 930 insertions(+), 166 deletions(-) create mode 100644 tests/rest/exams.js create mode 100644 tests/rest/question.js diff --git a/database/migrations/20200830010509-create-exam.js b/database/migrations/20200830010509-create-exam.js index 2cf55a3a..e7df0dca 100644 --- a/database/migrations/20200830010509-create-exam.js +++ b/database/migrations/20200830010509-create-exam.js @@ -16,10 +16,14 @@ module.exports = { type: { type: Sequelize.STRING }, - name_exam: { + name: { type: Sequelize.STRING, allowNull: false, }, + publishedAt: { + allowNull: true, + type: Sequelize.DATE + }, createdAt: { allowNull: false, type: Sequelize.DATE diff --git a/database/seeders/20200828135836-exams.js b/database/seeders/20200828135836-exams.js index b5b538ea..37fcdd09 100644 --- a/database/seeders/20200828135836-exams.js +++ b/database/seeders/20200828135836-exams.js @@ -5,10 +5,10 @@ module.exports = { up: async(queryInterface, Sequelize) => { let obj = [ - { moduleId: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { moduleId: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { moduleId: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { moduleId: 1, type: '1', name_exam: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { id: 1, moduleId: 1, type: '1', name: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { id: 2, moduleId: 1, type: '1', name: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { id: 3, moduleId: 1, type: '1', name: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { id: 4, moduleId: 1, type: '1', name: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, ]; await queryInterface.bulkInsert('exams', obj, {}); }, diff --git a/database/seeders/20200830142733-questions.js b/database/seeders/20200830142733-questions.js index 086ada8a..22abd405 100644 --- a/database/seeders/20200830142733-questions.js +++ b/database/seeders/20200830142733-questions.js @@ -1,21 +1,18 @@ -'use strict'; -const faker = require('faker'); +"use strict"; +const faker = require("faker"); module.exports = { up: async(queryInterface, Sequelize) => { let obj = [ - { examId: 1, typeQuestionId: 1, code: 'p1', content: faker.name.findName(), minimum: 9, length: 100, createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, typeQuestionId: 1, code: 'p2', content: faker.name.findName(), minimum: 1, length: 100, createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, typeQuestionId: 2, code: 'p3', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, typeQuestionId: 2, code: 'p4', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, typeQuestionId: 3, code: 'p5', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, typeQuestionId: 3, code: 'p6', content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, typeQuestionId: 4, code: 'p7', content: faker.name.findName(), minimum: 1, tope: 100, createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, typeQuestionId: 4, code: 'p8', content: faker.name.findName(), minimum: 1, tope: 100, createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 1, code: "p1", content: faker.name.findName(), minimum: 10, length: 100, createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 2, code: "p2", content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 3, code: "p3", content: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 4, code: "p4", content: faker.name.findName(), minimum: 10, tope: 100, createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, typeQuestionId: 4, code: "p5", content: faker.name.findName(), minimum: 10, tope: 100, createdAt: new Date(), updatedAt: new Date() }, ]; - await queryInterface.bulkInsert('questions', obj, {}); + await queryInterface.bulkInsert("questions", obj, {}); }, down: async(queryInterface, Sequelize) => { - await queryInterface.bulkDelete('questions', null, {}); + await queryInterface.bulkDelete("questions", null, {}); } }; \ No newline at end of file diff --git a/database/seeders/20200830142801-answers.js b/database/seeders/20200830142801-answers.js index 9f717bea..710e51c1 100644 --- a/database/seeders/20200830142801-answers.js +++ b/database/seeders/20200830142801-answers.js @@ -1,28 +1,21 @@ -'use strict'; -const faker = require('faker'); +"use strict"; +const faker = require("faker"); module.exports = { up: async(queryInterface, Sequelize) => { let obj = [ - { code: 'rta31', questionId: 3, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta32', questionId: 3, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta33', questionId: 3, content: faker.name.findName(), isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta41', questionId: 4, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta42', questionId: 4, content: faker.name.findName(), isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta43', questionId: 4, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta51', questionId: 5, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta52', questionId: 5, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta53', questionId: 5, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta61', questionId: 6, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta62', questionId: 6, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta63', questionId: 6, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta7', questionId: 7, content: '70', isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, - { code: 'rta8', questionId: 8, content: '17', isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, + { code: "rta21", questionId: 2, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, + { code: "rta22", questionId: 2, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, + { code: "rta23", questionId: 2, content: faker.name.findName(), isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, + { code: "rta31", questionId: 3, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, + { code: "rta32", questionId: 3, content: faker.name.findName(), isTrue: 0, score: 0, createdAt: new Date(), updatedAt: new Date() }, + { code: "rta33", questionId: 3, content: faker.name.findName(), isTrue: 1, score: 5, createdAt: new Date(), updatedAt: new Date() }, + { code: "rta42", questionId: 5, content: "70", isTrue: 1, score: 10, createdAt: new Date(), updatedAt: new Date() }, ]; - await queryInterface.bulkInsert('answers', obj, {}); + await queryInterface.bulkInsert("answers", obj, {}); }, down: async(queryInterface, Sequelize) => { - await queryInterface.bulkDelete('answers', null, {}); + await queryInterface.bulkDelete("answers", null, {}); } }; \ No newline at end of file diff --git a/database/seeders/20200830142900-student_answers.js b/database/seeders/20200830142900-student_answers.js index 94e42f46..8704eda1 100644 --- a/database/seeders/20200830142900-student_answers.js +++ b/database/seeders/20200830142900-student_answers.js @@ -1,23 +1,19 @@ -'use strict'; -const faker = require('faker'); +"use strict"; +const faker = require("faker"); module.exports = { up: async(queryInterface, Sequelize) => { let obj = [ - { examId: 1, questionId: 1, typeQuestionId: 1, studentId: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, questionId: 2, typeQuestionId: 1, studentId: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, questionId: 3, typeQuestionId: 2, studentId: 1, date_of_answer: new Date(), code_answer: 'id1,cod1', student_answer: 'content 1', createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, questionId: 4, typeQuestionId: 2, studentId: 1, date_of_answer: new Date(), code_answer: 'id2,cod2', student_answer: 'content 2', createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, questionId: 5, typeQuestionId: 3, studentId: 1, date_of_answer: new Date(), code_answer: 'id1,cod1;id2,cod2', student_answer: 'content 1;content 2', createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, questionId: 6, typeQuestionId: 3, studentId: 1, date_of_answer: new Date(), code_answer: 'id1,cod1;id2,cod2', student_answer: 'content 1;content 2', createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, questionId: 7, typeQuestionId: 4, studentId: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.random.number(), createdAt: new Date(), updatedAt: new Date() }, - { examId: 1, questionId: 8, typeQuestionId: 4, studentId: 1, date_of_answer: new Date(), code_answer: '0', student_answer: faker.random.number(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 1, typeQuestionId: 1, studentId: 1, date_of_answer: new Date(), code_answer: "0", student_answer: faker.name.findName(), createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 2, typeQuestionId: 2, studentId: 1, date_of_answer: new Date(), code_answer: "id2,cod2", student_answer: "content 2", createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 3, typeQuestionId: 3, studentId: 1, date_of_answer: new Date(), code_answer: "id1,cod1;id2,cod2", student_answer: "content 1;content 2", createdAt: new Date(), updatedAt: new Date() }, + { examId: 1, questionId: 4, typeQuestionId: 4, studentId: 1, date_of_answer: new Date(), code_answer: "0", student_answer: faker.random.number(), createdAt: new Date(), updatedAt: new Date() }, ]; - await queryInterface.bulkInsert('student_answers', obj, {}); + await queryInterface.bulkInsert("student_answers", obj, {}); }, down: async(queryInterface, Sequelize) => { - await queryInterface.bulkDelete('student_answers', null, {}); + await queryInterface.bulkDelete("student_answers", null, {}); } }; \ No newline at end of file diff --git a/database/seeders/20200830142910-student_exams.js b/database/seeders/20200830142910-student_exams.js index ece01a3d..40d15535 100644 --- a/database/seeders/20200830142910-student_exams.js +++ b/database/seeders/20200830142910-student_exams.js @@ -1,4 +1,4 @@ -'use strict'; +"use strict"; module.exports = { up: async(queryInterface, Sequelize) => { @@ -8,10 +8,10 @@ module.exports = { { studentId: 1, examId: 3, createdAt: new Date(), updatedAt: new Date() }, { studentId: 1, examId: 4, createdAt: new Date(), updatedAt: new Date() }, ]; - await queryInterface.bulkInsert('student_exams', obj, {}); + await queryInterface.bulkInsert("student_exams", obj, {}); }, down: async(queryInterface, Sequelize) => { - await queryInterface.bulkDelete('student_exams', null, {}); + await queryInterface.bulkDelete("student_exams", null, {}); } }; \ No newline at end of file diff --git a/src/api/routes/answers.js b/src/api/routes/answers.js index 0dfadba6..9419ea60 100644 --- a/src/api/routes/answers.js +++ b/src/api/routes/answers.js @@ -8,7 +8,7 @@ router.post("/", validator(AnswerService.validate()), AnswerController.createAns router.get("/:id", AnswerController.getAnswer); router.get("/question/:questionId", AnswerController.getByQuestion); router.delete("/:id", AnswerController.deleteAnswer); -router.put("/:id", AnswerController.updateAnswer); +router.put("/:id", validator(AnswerService.validate()), AnswerController.updateNormal); router.get("/", AnswerController.listAll); module.exports = router; \ No newline at end of file diff --git a/src/api/routes/exams.js b/src/api/routes/exams.js index 8741db80..e79d432e 100644 --- a/src/api/routes/exams.js +++ b/src/api/routes/exams.js @@ -5,7 +5,9 @@ const ExamService = require("../../services/examService"); const { validator } = require("../middlewares/validator"); router.post("/", validator(ExamService.validate()), ExamController.createExam); -router.get("/:id", ExamController.getExamComplet); +router.get("/:id", ExamController.getExam); //.getExamComplet); +router.put("/:id", ExamController.updateNormal); +router.patch("/close/:id", ExamController.close); module.exports = router; diff --git a/src/api/routes/questions.js b/src/api/routes/questions.js index 09e1e009..38b06240 100644 --- a/src/api/routes/questions.js +++ b/src/api/routes/questions.js @@ -6,5 +6,6 @@ const { validator } = require("../middlewares/validator"); router.post("/", validator(QuestionService.validate()), QuestionController.createQuestion); router.get("/:id", QuestionController.getQuestion); +router.put("/:id", validator(QuestionService.validate()), QuestionController.updateQuestion); module.exports = router; \ No newline at end of file diff --git a/src/controllers/answerController.js b/src/controllers/answerController.js index b4534cc9..5a18a79c 100644 --- a/src/controllers/answerController.js +++ b/src/controllers/answerController.js @@ -16,22 +16,23 @@ class AnswerController { static createAnswer(req, res) { let existsQuestion = {}; const answerVerify = req.body; - return QuestionService.findById(req.body.questionId) + // return QuestionService.findById(req.body.questionId) + return QuestionService.findByIdActiva(req.body.questionId) .then(data => { + // console.log('data ', JSON.stringify(data)) if (data) { existsQuestion = data; answerVerify.typeQuestionId = data.typeQuestionId; return AnswerService.validateParameters(answerVerify); - } else { - return Promise.reject({ err: "The question not exists. " }); } + return Promise.reject("The question not exists. "); }) .then(data => { const query = ((existsQuestion.typeQuestionId === typeQuestion.OPENQUESTION || existsQuestion.typeQuestionId === typeQuestion.NUMERICALQUESTION) ? { where: { questionId: req.body.questionId } } : { where: { questionId: req.body.questionId, content: req.body.content } }); return AnswerService.findOneBy(query); }) .then(data => { - if (data) return Promise.reject({ err: "The answer already exists. " }); + if (data) return Promise.reject("The answer already exists. "); else return AnswerService.create(req.body); }) .then((data) => res.status(200).json({ message: "Successfully created", data })) @@ -69,6 +70,34 @@ class AnswerController { } } + /** + * The complete registration must be sent, to validate + * + */ + static async updateNormal(req, res) { + const { id } = req.params; + let answerVerify = Object.assign({}, req.body); + // delete answerVerify.questionId; + return AnswerService.findExam(id, answerVerify.questionId) + .then(exam => { + if (exam && exam.publishedAt === null && exam.question) { + // answerVerify.questionId = exam.question.id; + answerVerify.typeQuestionId = exam.question.typeQuestionId; + return AnswerService.validateParameters(answerVerify); + } + return res.status(500).json({ err: "Exam not found" }); + }) + .then((data) => { + if (data) return AnswerService.updateRestricted(req.body, id); + return res.status(500).json({ err: "error in validate" }); + }) + .then(answer => { + if (answer) return res.status(200).json({ message: "Sucessfull Ejecution", data: answer }); + return res.status(500).json({ err: "error en update of answer" }); + }) + .catch(err => res.status(500).json({ err })); + } + static async deleteAnswer(req, res) { try { const { id } = req.params; diff --git a/src/controllers/examController.js b/src/controllers/examController.js index 219a01e3..6df5f363 100644 --- a/src/controllers/examController.js +++ b/src/controllers/examController.js @@ -30,13 +30,43 @@ class ExamController { const exam = { moduleId: req.body.moduleId, type: req.body.type, - name_exam: req.body.name_exam + name: req.body.name }; - return ExamService.findExists(exam) + return ExamService.exists(exam) .then(data => ExamService.create(exam)) - .then((data) => res.status(200).json({ message: "Create successfully", data })) + .then(examCreate => { + if (examCreate) { + return res.status(200).json({ message: "Create successfully", data: examCreate }); + } + return res.status(404).json({ err: "Registry creation error" }); + }) .catch((err) => res.status(500).json({ err })); } + static async updateNormal(req, res) { + try { + const { id } = req.params; + const exam = await ExamService.updateNormal(req.body, id); + if (exam) { + return res.status(200).json({ message: "Sucessfull Ejecution", data: exam }); + } else return res.status(404).json({ err: "Exam not found" }); + } catch (err) { + return res.status(500).json({ err }); + } + } + + static async close(req, res) { + try { + const { id } = req.params; + const parametros = { publishedAt: new Date() }; + const exam = await ExamService.updateRestringuido(parametros, id); + if (exam) { + return res.status(200).json({ message: "Sucessfull Ejecution", data: exam }); + } else return res.status(404).json({ err: "Exam not found" }); + } catch (err) { + return res.status(500).json({ err }); + } + } + } module.exports = ExamController; \ No newline at end of file diff --git a/src/controllers/questionController.js b/src/controllers/questionController.js index 0c699a0b..7f595808 100644 --- a/src/controllers/questionController.js +++ b/src/controllers/questionController.js @@ -9,7 +9,7 @@ class QuestionController { if (data) { return res.status(200).json({ message: "Consulta successfully", data }); } else { - return res.status(404).json({ err: "No existe question" }); + return res.status(404).json({ err: "There is no question" }); } }) .catch((err) => res.status(500).json({ err })); @@ -26,19 +26,41 @@ class QuestionController { length: req.body.length, help: req.body.help } //= req.body; - return QuestionService.validateParameters(question) - .then(data => ExamService.findById(question.examId)) - .then(data => { - if (data) { - return QuestionService.findExists(question); - } else { - return res.status(500).json({ err: "Exam does not exist" }); + return Promise.all([ExamService.findById(question.examId), QuestionService.findExists(question), QuestionService.validateParameters(question)]) + .then(exam => { + if (exam[0] && exam[0].publishedAt === null && exam[1]) { + return QuestionService.create(question); } + return Promise.reject("Exam does not exist"); + }) + .then((data) => { + if (data) return res.status(200).json({ message: "Create successfully", data }); + return res.status(500).json({ err: "Registry creation error" }); }) - .then(data => QuestionService.create(question)) - .then((data) => res.status(200).json({ message: "Create successfully", data })) .catch((err) => res.status(500).json({ err })); } + + static async updateQuestion(req, res) { + const { id } = req.params; + let change = req.body; + return Promise.all([ExamService.findById(req.body.examId), QuestionService.findById(id)]) + .then(examQuestion => { + if (examQuestion[0] && examQuestion[0].publishedAt === null && examQuestion[1]) { + return QuestionService.changeType(change, examQuestion[1]); + } + return Promise.reject("Exam or Questin does not exist"); + //return res.status(500).json({ err: "Exam not found" }); + }) + .then(data => { + if (data) return QuestionService.update(req.body, id); + return res.status(500).json({ err: "There is an error in the parameters" }); + }) + .then(question => { + if (question) return res.status(200).json({ message: "Sucessfull Ejecution", data: question }); + return res.status(500).json({ err: "Error in update" }); + }) + .catch(err => res.status(500).json({ err })); + } } module.exports = QuestionController; \ No newline at end of file diff --git a/src/models/exam.js b/src/models/exam.js index eef83643..7bdca85f 100644 --- a/src/models/exam.js +++ b/src/models/exam.js @@ -16,10 +16,14 @@ const Exam = sequelize.define('exams', { type: { type: Sequelize.STRING }, - name_exam: { + name: { type: Sequelize.STRING, allowNull: false, }, + publishedAt: { + allowNull: true, + type: Sequelize.DATE + }, createdAt: { allowNull: false, type: Sequelize.DATE diff --git a/src/services/answerService.js b/src/services/answerService.js index 14a1a194..426bca72 100644 --- a/src/services/answerService.js +++ b/src/services/answerService.js @@ -8,12 +8,14 @@ class AnswerService { static validate() { return [ - check("code", "code is required").not().isEmpty().isLength({ min: 2, max: 15 }).withMessage("Allowable range 2-15"), - check("questionId", "questionId is required").not().isEmpty().isNumeric(), - check("isTrue", "isTrue is required").not().isEmpty().isIn([1, 0]), + check("code", "code is required").notEmpty().isLength({ min: 2, max: 15 }).withMessage("Allowable range 2-15"), + check("questionId", "questionId is required").notEmpty().isNumeric(), + check("isTrue", "isTrue is required").notEmpty().isIn([1, 0]), check("score", "score is required").custom((val, { req }) => { if (!val && req.body.isTrue == 1) { throw new Error("Score is required"); + } else if (!val && req.body.isTrue == 0) { + return true; } else if (val && req.body.isTrue == 0) { throw new Error("Score not required, because isTrue = false"); } else if (val && req.body.isTrue == 1 && (val < 0 || val > 100)) { @@ -105,19 +107,53 @@ class AnswerService { } } - static async findExam(query) { + static async findExam(idAnswer, questionId) { + let respuesta = {}; + return Answer.findByPk(idAnswer) + .then(data => { + if (data) { + respuesta.answer = data; + return QuestionService.findById(questionId); + } + return Promise.reject("No existe answer") + }) + .then(data => { + if (data) { + respuesta.question = data; + return ExamService.findById(data.examId); + } + return Promise.reject("No existe question") + }) + .then(data => { + if (data && data.publisheAt === null) { + respuesta.exam = data; + return Promise.resolve(respuesta); + } + return Promise.reject("No existe exam o esta close") + }) + .catch(err => Promise.reject(err)) + } + + // questionId can be not changed + static async updateNormal(data, id) { try { - const data = await QuestionService.findOneBy({ where: { id: query.questionId } }); - if (data) { - const answerExists = await ExamService.findOneBy({ where: { id: data.examId } }); - return answerExists; + const { code, content, isTrue, score } = data; + const foundAnswer = await Answer.findByPk(id); + if (foundAnswer) { + foundAnswer.update({ + code, + content: content || null, + isTrue, + score: score || 0, + }); + return foundAnswer; } } catch (err) { return new Error("An error has ocurred"); } } - static async update(data, id) { + static async updateRestricted(data, id) { try { const { code, questionId, content, isTrue, score } = data; const foundAnswer = await Answer.findByPk(id); @@ -125,9 +161,9 @@ class AnswerService { foundAnswer.update({ code, questionId, - content, + content: content || null, isTrue, - score, + score: score || 0, }); return foundAnswer; } @@ -137,17 +173,18 @@ class AnswerService { } /** - * Verification of data to add + * Verification of consistency of the data to add * @param {Object} answer post data to add * @returns {Promise.resolve} message for correct data * @returns {Promise.reject} alert message, if data is missing */ static validateParameters(answer) { + // console.log('data ', JSON.stringify(answer)) return new Promise((resolve, reject) => { if (answer.typeQuestionId == typeQuestion.OPENQUESTION && answer.content) { - reject("Parameter CONTENT no required "); + reject("CONTENT parameter is not necessary for open questions"); } else if (answer.typeQuestionId != typeQuestion.OPENQUESTION && !answer.content) { - reject("Mandatory parameters are missing"); + reject("Parameter content is mandatory"); } else return resolve(1); }); } diff --git a/src/services/examService.js b/src/services/examService.js index 7b83af16..ad1b465a 100644 --- a/src/services/examService.js +++ b/src/services/examService.js @@ -1,16 +1,14 @@ const Exam = require("../models/exam"); const { check } = require("express-validator"); -const models = require("../../config/db/mysql"); - -let sequelize; -sequelize = models.sequelize; +const { sequelize } = require("../../config/db/mysql"); +const Module = require("../models/module"); class ExamService { static validate() { return [ - check("moduleId", "moduleId is required").not().isEmpty().isNumeric().isLength({ min: 1, max: 15 }), - check("name_exam", "name_exam is required").not().isEmpty().isLength({ min: 2, max: 500 }), + check("moduleId", "moduleId is required").notEmpty().isNumeric().isLength({ min: 1, max: 15 }), + check("name", "name is required").notEmpty().isLength({ min: 2, max: 500 }), ]; } @@ -27,17 +25,18 @@ class ExamService { static async create(data) { try { - const { moduleId, type, name_exam } = data; + const { moduleId, type, name } = data; const hereExam = await Exam.create({ moduleId, type, - name_exam + name }); return hereExam; } catch (err) { return new Error("An error has ocurred"); } } + static async findById(id) { try { const hereExam = await Exam.findByPk(id); @@ -62,15 +61,66 @@ class ExamService { } } - static async update(data, id) { + static async deleteNormal(id) { + try { + const hereExam = await Exam.findByPk(id); + if (hereExam && hereExam.publishedAt === null) { + await hereExam.destroy(); + return hereExam; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static async deleteRestringuido(id) { + try { + const hereExam = await Exam.findByPk(id); + if (hereExam) { + await hereExam.destroy(); + return hereExam; + } + } catch (err) { + return new Error("An error has ocurred"); + } + } + + static updateNormal(data, id) { + const { moduleId, type, name } = data; + return Module.findByPk(moduleId) + .then(theModule => { + if (theModule) { + return Exam.findByPk(id); + } + return Promise.reject("no existe el modulo"); + }) + .then(hereExam => { + if (hereExam && hereExam.publishedAt === null) { + return hereExam.update({ + moduleId, + type, + name + }); + } + return Promise.reject("no existe el examen"); + }) + .then(data => { + // console.log('data ', data) + return Promise.resolve(data); + }) + .catch(err => Promise.reject(err)); + } + + static async updateRestringuido(data, id) { try { - const { moduleId, type, name_exam } = data; + const { moduleId, type, name, publishedAt } = data; const hereExam = await Exam.findByPk(id); if (hereExam) { hereExam.update({ moduleId, type, - name_exam + name, + publishedAt }); return hereExam; } @@ -105,15 +155,19 @@ class ExamService { * @param {object} exam containing info about a post * @returns {Promise} message error if it exists */ - static findExists(exam) { - return Exam.findOne({ where: { moduleId: exam.moduleId, name_exam: exam.name_exam } }) - .then((data) => { + static exists(exam) { + return Module.findByPk(exam.moduleId) + .then(theModule => { + if (theModule) { + return Exam.findOne({ where: { moduleId: exam.moduleId, name: exam.name } }); + } + return Promise.reject("no existe el modulo"); + }) + .then(data => { if (data) { - const err = "The record exists"; - return Promise.reject(err); - } else { - return Promise.resolve({ message: "The record does not exist" }); + return Promise.reject("Exists the record the exam"); } + return Promise.resolve(1); }) .catch((err) => { return Promise.reject(err); diff --git a/src/services/questionService.js b/src/services/questionService.js index d0954f65..35a183b5 100644 --- a/src/services/questionService.js +++ b/src/services/questionService.js @@ -1,5 +1,7 @@ /* eslint-disable indent */ const Question = require("../models/question"); +const Answer = require("../models/answer"); +const Exam = require("../models/exam"); const { check } = require("express-validator"); const typeQuestion = require("../../config/enum/typeOfQuestion"); @@ -8,23 +10,23 @@ class QuestionService { static validate() { return [ - check("examId", "examId is required").not().isEmpty(), - check("typeQuestionId", "typeQuestionId is required").not().isEmpty().isNumeric().custom((val, { req }) => { - if (!val || val < 0 || val > parseInt(typeQuestion.NUMERICALQUESTION, 10) + 1) { - throw new Error("Mandatory parameters are missing or out of range"); + check("examId", "examId is required").notEmpty(), + check("typeQuestionId", "typeQuestionId is required").notEmpty().bail().custom((val, { req }) => { + if (!val || !parseInt(val, 10) || val < 0 || val > parseInt(typeQuestion.NUMERICALQUESTION, 10) + 1) { + throw new Error("Question type value is out of range"); } else return true; }), - check("code", "code is required").not().isEmpty().isLength({ min: 2, max: 15 }), - check("content", "content is required").not().isEmpty().isLength({ min: 2, max: 500 }), + check("code", "code is required").notEmpty().isLength({ min: 2, max: 15 }), + check("content", "content is required").notEmpty().isLength({ min: 2, max: 500 }), check("help", "help is optional").optional().isLength({ min: 2, max: 500 }), check("minimum").custom((minimum, { req }) => { if (!req.body.typeQuestionId || req.body.typeQuestionId < 1 || req.body.typeQuestionId > parseInt(typeQuestion.NUMERICALQUESTION, 10) + 1) return true; switch (req.body.typeQuestionId) { case typeQuestion.OPENQUESTION: - if (!minimum || minimum < 1) throw new Error("Mandatory parameters are missing"); + if (!minimum || !parseInt(minimum, 10) || minimum < 1) throw new Error("Mandatory parameters are missing"); break; case typeQuestion.NUMERICALQUESTION: - if (!minimum || minimum === 0) throw new Error("Mandatory parameters are missing"); + if (!minimum || !parseInt(minimum, 10) || minimum === 0) throw new Error("Mandatory parameters are missing"); break; default: if (!minimum) return true; @@ -40,16 +42,18 @@ class QuestionService { return true; } else if (req.body.typeQuestionId != typeQuestion.NUMERICALQUESTION && val) { throw new Error("Parameter NOT required"); - } + } else return true; }), check("length").custom((val, { req }) => { if (!req.body.typeQuestionId || req.body.typeQuestionId < 1 || req.body.typeQuestionId > parseInt(typeQuestion.NUMERICALQUESTION, 10) + 1) return true; - if (req.body.typeQuestionId == typeQuestion.OPENQUESTION && (!val || val < 1 || val > 500)) { + if (req.body.typeQuestionId == typeQuestion.OPENQUESTION && (!val || parseInt(val, 10) < 1 || parseInt(val, 10) > 500)) { throw new Error("Mandatory parameters are missing"); } else if (req.body.typeQuestionId != typeQuestion.OPENQUESTION && !val) { return true; } else if (req.body.typeQuestionId != typeQuestion.OPENQUESTION && val) { throw new Error("Parameter NOT required"); + } else if (req.body.typeQuestionId == typeQuestion.OPENQUESTION && val && parseInt(val, 10) > 1 && parseInt(val, 10) < 500) { + return true; } }) ]; @@ -96,6 +100,29 @@ class QuestionService { } } + /** + * Find question the un exam sin ejecutar + * @param {Integer} id identificador the question + */ + static async findByIdActiva(id) { + let respuesta = {}; + return Question.findByPk(id) + .then(data => { + if (data) { + respuesta.question = data; + return Exam.findByPk(data.examId); + } + return Promise.reject("No existe la question"); + }) + .then(data => { + if (data && data.publishedAt === null) { + return Promise.resolve(respuesta.question); + } + return Promise.reject("examen no existe o cerrado"); + }) + .catch(err => Promise.reject(err)); + } + static async delete(id) { try { const question = await Question.findByPk(id); @@ -110,15 +137,18 @@ class QuestionService { static async update(data, id) { try { - const { code, questionId, content, isTrue, score } = data; + const { examId, typeQuestionId, code, content, minimum, tope, length, help } = data; const question = await Question.findByPk(id); if (question) { question.update({ + examId, + typeQuestionId, code, - questionId, content, - isTrue, - score, + minimum: minimum || null, + tope: tope || null, + length: length || null, + help: help || null }); return question; } @@ -172,7 +202,6 @@ class QuestionService { switch (question.typeQuestionId) { case typeQuestion.OPENQUESTION: if (!question.length || question.length == 0) { - console.log("Required parameters are missing"); reject("Required parameters are missing"); } else { resolve("Correct parameters"); @@ -191,5 +220,26 @@ class QuestionService { } }); } + + /** + * validar the update, parameter and logica + * if change of type the question then change the answers + * + */ + static async changeType(now, before) { + try { + if (now.typeQuestionId != before.typeQuestionId) { + const answer1 = await Answer.findAll({ where: { questionId: before.id } }); + if (answer1) { + let vector = Object.values(answer1); + vector.forEach(answer => answer.destroy()); + } + return 1; + } + return 1; + } catch (err) { + return new Error("An error has ocurred"); + } + } } module.exports = QuestionService; \ No newline at end of file diff --git a/tests/rest/answer-controller.js b/tests/rest/answer-controller.js index 44ccf8e8..559afa63 100644 --- a/tests/rest/answer-controller.js +++ b/tests/rest/answer-controller.js @@ -1,42 +1,160 @@ const chai = require("chai"); const chaiHttp = require("chai-http"); -const faker = require("faker"); const app = require("../../src/index"); const Answer = require("../../src/models/answer"); const { expect } = chai; -chai.use(chaiHttp); - -describe("Answer tests", () => { - let num; - let res1; - let res2; +const User = require("../../src/models/user"); +const Professor = require("../../src/models/professor"); +const Category = require("../../src/models/category"); +const Course = require("../../src/models/course"); +const Module = require("../../src/models/module"); +const Exam = require("../../src/models/exam"); +const Question = require("../../src/models/question"); +const Type_question = require("../../src/models/type_question.js"); - before(() => { - num = faker.random.number(); - }) - after(async() => { - - try { - const answer1 = await Answer.findByPk(res1.body.data.id); - if (answer1) await answer1.destroy(); - const answer2 = await Answer.findByPk(res2.body.data.id); - if (answer2) await answer2.destroy(); - } catch (err) { - return new Error("An error has ocurred"); +chai.use(chaiHttp); +before(async() => { + try { + // ** METODO 1 + + await Type_question.create({ id: 1, type_question: 1, content: "abierta" }); + await Type_question.create({ id: 2, type_question: 2, content: "cerrada" }); + await Type_question.create({ id: 3, type_question: 3, content: "multiple" }); + await Type_question.create({ id: 4, type_question: 4, content: "numerica" }); + + await User.create({ id: "1", firstname: "ana", lastname: "aa", email: "aaa@ddd.com", password: "sss" }); + await Category.create({ id: "1", name: "alto", slug: "1" }); + await Professor.create({ id: "1", userId: "1", valuation: "11" }); + await Course.create({ id: "1", professorId: "1", categoryId: "1", title: "nodejs", description: "ssss", isPrivate: "0", invitationCode: "adfsdfs" }); + await Module.create({ id: "1", courseId: "1", title: "safsd", description: "sdfs" }); + + await Exam.create({ id: "1", moduleId: "1", name: "sdfs" }); + await Question.create({ id: 1, examId: 1, typeQuestionId: 1, code: "q1", content: "pregunta abierta", minimum: 20, length: 100 }); + await Question.create({ id: 2, examId: 1, typeQuestionId: 2, code: "q2", content: "pregunta cerrada" }); + await Question.create({ id: 3, examId: 1, typeQuestionId: 3, code: "q3", content: "pregunta multi opcion" }); + await Question.create({ id: 4, examId: 1, typeQuestionId: 4, code: "q4", content: "pregunta numerica", minimum: 10, tope: 100 }); + + //** METODO 2 */ + /* let usuarios = await User.findByPk(1); + if (usuarios == undefined) { + await User.create({ id: "1", firstname: "persona 1", lastname: "lopez perez", email: "aaa@ddd.com", password: "s89ss" }); } - }); + let categories = await Category.findByPk(1); + if (categories === undefined) { await Category.create({ id: "1", name: "alto", slug: "1" }); } + + let professors = await Professor.findByPk(1); + if (professors == undefined || professors == null) { await Professor.create({ id: "1", userId: "1", valuation: "11" }); } - describe("Create a answer of question open", () => { + let courses = await Course.findByPk(1); + if (courses === undefined || courses === null) { + await Course.create({ id: "1", professorId: "1", categoryId: "1", title: "alto", description: "ssss", isPrivate: "0", invitationCode: "adf5$5sdfs" }); + } - it("should return a answer created, if content is empty", (done) => { + let modules = await Module.findByPk(1); + if (modules == undefined || modules == null) { await Module.create({ id: "1", courseId: "1", title: "safsd", description: "sdfs" }); } + + await Type_question.create({ id: 1, type_question: 1, content: "abierta" }); + await Type_question.create({ id: 2, type_question: 2, content: "cerrada" }); + await Type_question.create({ id: 3, type_question: 3, content: "multiple" }); + await Type_question.create({ id: 4, type_question: 4, content: "numerica" }); + + + await Exam.create({ id: "1", moduleId: "1", name: "sdfs" }); + await Question.create({ id: 1, examId: 1, typeQuestionId: 1, code: "q1", content: "pregunta abierta", minimum: 20, length: 100 }); + await Question.create({ id: 2, examId: 1, typeQuestionId: 2, code: "q2", content: "pregunta cerrada" }); + await Question.create({ id: 3, examId: 1, typeQuestionId: 3, code: "q3", content: "pregunta multi opcion" }); + await Question.create({ id: 4, examId: 1, typeQuestionId: 4, code: "q4", content: "pregunta numerica", minimum: 10, tope: 100 }); +*/ + + } catch (err) { + return new Error("An error has ocurred"); + } +}); + +after(async() => { + try { + let data; + let vector; + + + + await Answer.destroy({ force: true }); + await Question.destroy({ force: true }); + await Exam.destroy({ force: true }); + await Module.destroy({ force: true }); + await Type_question.destroy({ force: true }); + /* + data = await Answer.findAll(); + if (data) { + vector = Object.values(data); + vector.forEach(item => (item.destroy({ force: true }))); + } + + let data1 = await Question.findAll(); + if (data1) { + let vector1 = Object.values(data1); + await vector1.forEach(item => item.destroy({ force: true })); + } + + let data2 = await Exam.findAll(); + if (data2) { + let vector2 = Object.values(data2); + vector2.forEach(item => item.destroy({ force: true })); + } + let data4 = await Type_question.findAll(); + if (data4) { + let vector4 = Object.values(data4); + vector4.forEach(item => item.destroy({ force: true })); + } + + let data5 = await Module.findAll(); + if (data5) { + let vector5 = Object.values(data5); + await vector5.forEach(item => item.destroy({ force: true })); + } + + let data6 = await Course.findAll(); + if (data6) { + let vector5 = Object.values(data6); + await vector5.forEach(item => item.destroy({ force: true })); + } + + let data7 = await Professor.findAll(); + if (data7) { + let vector5 = Object.values(data7); + await vector5.forEach(item => item.destroy({ force: true })); + } + + let data8 = await Category.findAll(); + if (data8) { + let vector5 = Object.values(data8); + await vector5.forEach(item => item.destroy({ force: true })); + } + + let data9 = await User.findAll(); + if (data9) { + let vector5 = Object.values(data9); + await vector5.forEach(item => item.destroy({ force: true })); + } + */ + + } catch (err) { + return new Error("An error has ocurred"); + } +}); +describe("Answer Tests", () => { + + describe("Create an answer of Question Open", () => { + + it("Should return an answer created, if content is empty", (done) => { chai.request(app) .post("/api/v1/answer") .send({ - "code": "r11", + "code": "r1.1", "questionId": 1, "isTrue": 1, "score": 10 @@ -45,34 +163,30 @@ describe("Answer tests", () => { if (err) done(err); - res1 = res; expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); expect(res).to.have.status(200); - done(); - }); - }) - }) + }); + }); - describe("Create a answer of closed question multiple choice", () => { + describe("Create an answer of Question Multiple choice", () => { it("Should return a Answer Created", (done) => { chai.request(app) .post("/api/v1/answer") .send({ - "code": "r3." + num, - "questionId": 5, - "content": "naranja" + num, + "code": "r3.1", + "questionId": 3, + "content": "red", "isTrue": 1, - "score": 10 + "score": 15 }) .end(function(err, res) { if (err) done(err); - res2 = res; expect(res).to.have.status(200); expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); done(); @@ -84,9 +198,9 @@ describe("Answer tests", () => { chai.request(app) .post("/api/v1/answer") .send({ - "code": "r3." + num, - "questionId": 5, - "content": "naranja" + num, + "code": "r3.2", + "questionId": 3, + "content": "red", "isTrue": 1, "score": 10 }) @@ -100,12 +214,12 @@ describe("Answer tests", () => { }); }); - it("should return an error if content is empty and type of question is not open", (done) => { + it("Should return an Error, if content is empty and type of question is not open", (done) => { chai.request(app) .post("/api/v1/answer") .send({ - "code": "r12", + "code": "r3.3", "questionId": 3, "isTrue": 1, "score": 10 @@ -113,37 +227,76 @@ describe("Answer tests", () => { .end(function(err, res) { if (err) done(err); - //console.log(res) expect(JSON.parse(res.text)).to.have.all.keys("err"); expect(res).to.have.status(500); - done(); - }); }); - it("should return an error if questionId is empty", (done) => { + it("Should return an Error, if questionId is empty", (done) => { chai.request(app) .post("/api/v1/answer") .send({ - "code": "r11", - "content": "naranja", + "code": "r3.4", + "content": "yellow", "isTrue": 1, - "score": 10 + "score": 15 }) .end(function(err, res) { if (err) done(err); - //console.log(res) expect(JSON.parse(res.text)).to.have.all.keys("errors"); expect(res).to.have.status(400); // 404 - done(); }); }); }); -}) \ No newline at end of file + describe("Create an answer of Question Numerical", () => { + + it("Should return an answer created", (done) => { + + chai.request(app) + .post("/api/v1/answer") + .send({ + "code": "r4.1", + "questionId": 4, + "content": 70, + "isTrue": 1, + "score": 10 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + expect(res).to.have.status(200); + done(); + }); + }); + + it("Should return an Error, if add other answer", (done) => { + + chai.request(app) + .post("/api/v1/answer") + .send({ + "code": "r4.2", + "questionId": 4, + "content": 80, + "isTrue": 1, + "score": 10 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(JSON.parse(res.text)).to.have.all.keys("err"); + expect(res).to.have.status(500); + done(); + }); + }); + }); +}); \ No newline at end of file diff --git a/tests/rest/exams.js b/tests/rest/exams.js new file mode 100644 index 00000000..defd14f2 --- /dev/null +++ b/tests/rest/exams.js @@ -0,0 +1,109 @@ +const chai = require("chai"); +const chaiHttp = require("chai-http"); +const app = require("../../src/index"); + +const User = require("../../src/models/user"); +const Professor = require("../../src/models/professor"); +const Category = require("../../src/models/category"); +const Course = require("../../src/models/course"); +const Module = require("../../src/models/module"); +const Type_question = require("../../src/models/type_question.js"); + +const { expect } = chai; + +chai.use(chaiHttp); +before(async() => { + try { + await Type_question.create({ id: 1, type_question: 1, content: "abierta" }); + await Type_question.create({ id: 2, type_question: 2, content: "cerrada" }); + await Type_question.create({ id: 3, type_question: 3, content: "multiple" }); + await Type_question.create({ id: 4, type_question: 4, content: "numerica" }); + await User.create({ id: "1", firstname: "ana", lastname: "aa", email: "aaa@ddd.com", password: "sss" }); + await Category.create({ id: "1", name: "alto", slug: "1" }); + await Professor.create({ id: "1", userId: "1", valuation: "11" }); + await Course.create({ id: "1", professorId: "1", categoryId: "1", title: "alto", description: "ssss", isPrivate: "0", invitationCode: "adfsdf677s" }); + await Module.create({ id: 1, courseId: 1, title: "safsd", description: "sdfs" }); + + } catch (err) { + return new Error("An error has ocurred"); + } +}); + + + +describe("Exam Test", () => { + + it("Should return an Exam Created", (done) => { + + chai.request(app) + .post("/api/v1/exam") + .send({ + "moduleId": "1", + "type": 1, + "name": "Introduction to Vue" + }) + .end(function(err, res) { + + if (err) done(err); + + expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + expect(res).to.have.status(200); + done(); + }); + }); + + it("Should return an Error, when the exam name is empty", (done) => { + + chai.request(app) + .post("/api/v1/exam") + .send({ + "moduleId": "1", + "type": 1 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(400); + expect(JSON.parse(res.text)).to.have.all.keys("errors"); + done(); + }); + }); + + it("Should return an Error, when moduleId is empty", (done) => { + + chai.request(app) + .post("/api/v1/exam") + .send({ + "type": 1, + "name": "Introduction to Ionic" + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(400); + expect(JSON.parse(res.text)).to.have.all.keys("errors"); + done(); + }); + }); + + it("Should return an Error, when name and moduleId exists in the base", (done) => { + + chai.request(app) + .post("/api/v1/exam") + .send({ + "moduleId": "1", + "type": 1, + "name": "Introduction to Vue" + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(500); + expect(JSON.parse(res.text)).to.have.all.keys("err"); + done(); + }); + }); +}) \ No newline at end of file diff --git a/tests/rest/question.js b/tests/rest/question.js new file mode 100644 index 00000000..b8f5a533 --- /dev/null +++ b/tests/rest/question.js @@ -0,0 +1,283 @@ +const chai = require("chai"); +const chaiHttp = require("chai-http"); +const app = require("../../src/index"); +const { expect } = chai; + +const User = require("../../src/models/user"); +const Professor = require("../../src/models/professor"); +const Category = require("../../src/models/category"); +const Course = require("../../src/models/course"); +const Module = require("../../src/models/module"); +const Exam = require("../../src/models/exam"); + +chai.use(chaiHttp); + +describe("Question Tests", () => { + + before(async() => { + try { + await User.create({ id: "1", firstname: "ana", lastname: "aa", email: "aaa@ddd.com", password: "sss" }); + await Category.create({ id: "1", name: "alto", slug: "1" }); + await Professor.create({ id: "1", userId: "1", valuation: "11" }); + await Course.create({ id: "1", professorId: "1", categoryId: "1", title: "alto", description: "ssss", isPrivate: "0", invitationCode: "adfsdfs" }); + await Module.create({ id: "1", courseId: "1", title: "safsd", description: "sdfs" }); + await Exam.create({ id: "1", moduleId: "1", name: "sdfs" }); + + } catch (err) { + return new Error("An error has ocurred"); + } + }); + + describe("Creation of OPEN Question", () => { + + it("should return an question created", (done) => { + + chai.request(app) + .post("/api/v1/question") + .send({ + "id": 1, + "examId": 1, + "typeQuestionId": 1, + "code": "E1.q1.1", + "content": "What is Git?", + "minimum": 2, + "length": 100 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + expect(res).to.have.status(200); + done(); + }); + }); + + it("Should return an Error, when the tope exists and it is not necessary", (done) => { + + chai.request(app) + .post("/api/v1/question") + .send({ + "examId": 1, + "typeQuestionId": 1, + "code": "E1.q1.2", + "content": "What does the method return Object.values()?", + "minimum": 2, + "tope": 100, + "length": 100 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(400); + expect(JSON.parse(res.text)).to.have.all.keys("errors"); + done(); + }); + }); + + it("Should return an Error, when examId is empty", (done) => { + + chai.request(app) + .post("/api/v1/question") + .send({ + "typeQuestionId": 1, + "code": "E1.q1.3", + "content": "colores primarios", + "minimum": 2, + "length": 100 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(400); + expect(JSON.parse(res.text)).to.have.all.keys("errors"); + done(); + }); + }); + + it("Should return an Error, when examId and content exists in the base", (done) => { + + chai.request(app) + .post("/api/v1/question") + .send({ + "examId": 1, + "typeQuestionId": 1, + "code": "E1.q1.4", + "content": "What is Git?", + "minimum": 2, + "length": 100 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(500); + expect(JSON.parse(res.text)).to.have.all.keys("err"); + done(); + }); + }); + }); + + describe("Close question creation", () => { + + it("Should return an question created", (done) => { + + chai.request(app) + .post("/api/v1/question") + .send({ + "id": 2, + "examId": 1, + "typeQuestionId": 2, + "code": "E1.q2.1", + "content": "What does the method return Object.values()?" + }) + .end(function(err, res) { + + if (err) done(err); + + expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + expect(res).to.have.status(200); + done(); + }); + }); + }); + + describe("Multi-choice question creation", () => { + + it("Should return an question created", (done) => { + + chai.request(app) + .post("/api/v1/question") + .send({ + "id": 3, + "examId": 1, + "typeQuestionId": 3, + "code": "E1.q3.1", + "content": "What are the primary colors?" + }) + .end(function(err, res) { + + if (err) done(err); + + expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + expect(res).to.have.status(200); + done(); + }); + }); + + it("Should return an Error, because there are no required parameters", (done) => { + + chai.request(app) + .post("/api/v1/question") + .send({ + "examId": 1, + "typeQuestionId": 3, + "code": "E1.q3.2", + "content": "What is Git?", + "minimum": 2, + "tope": 100, + "length": 100 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(400); + expect(JSON.parse(res.text)).to.have.all.keys("errors"); + done(); + }); + }); + + it("Should return an Error, because examId is empty", (done) => { + + chai.request(app) + .post("/api/v1/question") + .send({ + "typeQuestionId": 3, + "code": "E1.q3.3", + "content": "What is Git?", + "minimum": 2, + "tope": 100, + "length": 100 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(400); + expect(JSON.parse(res.text)).to.have.all.keys("errors"); + done(); + }); + }); + }); + + describe("Creation of NUMERICAL question", () => { + + it("should return an question created", (done) => { + + chai.request(app) + .post("/api/v1/question") + .send({ + "id": 4, + "examId": 1, + "typeQuestionId": 4, + "code": "E1.q4.1", + "content": "Escriba el numero", + "minimum": 2, + "tope": 100 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + expect(res).to.have.status(200); + done(); + }); + }); + + it("Should return an Error, because tope is empty", (done) => { + + chai.request(app) + .post("/api/v1/question") + .send({ + "examId": 1, + "typeQuestionId": 4, + "code": "E1.q4.2", + "content": "Otro numero" + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(400); + expect(JSON.parse(res.text)).to.have.all.keys("errors"); + done(); + }); + }); + + it("Should return an Error, because the question exists in the exam", (done) => { + + chai.request(app) + .post("/api/v1/question") + .send({ + "examId": 1, + "typeQuestionId": 4, + "code": "E1.q4.3", + "content": "Escriba el numero", + "minimum": 2, + "tope": 100 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(500); + expect(JSON.parse(res.text)).to.have.all.keys("err"); + done(); + }); + }); + }); +}); \ No newline at end of file From 8b806a18bdcccac6a2e89b00801749d29219385c Mon Sep 17 00:00:00 2001 From: Nauel Date: Sun, 4 Oct 2020 14:55:01 -0400 Subject: [PATCH 08/11] fix:removed dependency from table module with exam --- .../migrations/20200830010509-create-exam.js | 1 - src/api/routes/answers.js | 4 - src/api/routes/exams.js | 6 +- src/api/routes/questions.js | 3 - src/models/exam.js | 1 - src/services/examService.js | 19 +- tests/rest/answer-controller.js | 183 +++++------------- tests/rest/exams.js | 38 ++-- tests/rest/question.js | 50 +++-- 9 files changed, 110 insertions(+), 195 deletions(-) diff --git a/database/migrations/20200830010509-create-exam.js b/database/migrations/20200830010509-create-exam.js index e7df0dca..0227e767 100644 --- a/database/migrations/20200830010509-create-exam.js +++ b/database/migrations/20200830010509-create-exam.js @@ -11,7 +11,6 @@ module.exports = { moduleId: { type: Sequelize.INTEGER, allowNull: false, - references: { model: 'modules', key: 'id' } }, type: { type: Sequelize.STRING diff --git a/src/api/routes/answers.js b/src/api/routes/answers.js index 60666055..9419ea60 100644 --- a/src/api/routes/answers.js +++ b/src/api/routes/answers.js @@ -8,11 +8,7 @@ router.post("/", validator(AnswerService.validate()), AnswerController.createAns router.get("/:id", AnswerController.getAnswer); router.get("/question/:questionId", AnswerController.getByQuestion); router.delete("/:id", AnswerController.deleteAnswer); -<<<<<<< HEAD router.put("/:id", validator(AnswerService.validate()), AnswerController.updateNormal); -======= -router.put("/:id", AnswerController.updateAnswer); ->>>>>>> ee693a9f76585cfafffae1d7281a57c985144e93 router.get("/", AnswerController.listAll); module.exports = router; \ No newline at end of file diff --git a/src/api/routes/exams.js b/src/api/routes/exams.js index 4afa58f8..d2d28fb7 100644 --- a/src/api/routes/exams.js +++ b/src/api/routes/exams.js @@ -5,13 +5,9 @@ const ExamService = require("../../services/examService"); const { validator } = require("../middlewares/validator"); router.post("/", validator(ExamService.validate()), ExamController.createExam); -<<<<<<< HEAD -router.get("/:id", ExamController.getExam); //.getExamComplet); +router.get("/:id", ExamController.getExamComplet); router.put("/:id", ExamController.updateNormal); router.patch("/close/:id", ExamController.close); -======= -router.get("/:id", ExamController.getExamComplet); ->>>>>>> ee693a9f76585cfafffae1d7281a57c985144e93 module.exports = router; diff --git a/src/api/routes/questions.js b/src/api/routes/questions.js index 6679c7e6..38b06240 100644 --- a/src/api/routes/questions.js +++ b/src/api/routes/questions.js @@ -6,9 +6,6 @@ const { validator } = require("../middlewares/validator"); router.post("/", validator(QuestionService.validate()), QuestionController.createQuestion); router.get("/:id", QuestionController.getQuestion); -<<<<<<< HEAD router.put("/:id", validator(QuestionService.validate()), QuestionController.updateQuestion); -======= ->>>>>>> ee693a9f76585cfafffae1d7281a57c985144e93 module.exports = router; \ No newline at end of file diff --git a/src/models/exam.js b/src/models/exam.js index 7bdca85f..22a88ebe 100644 --- a/src/models/exam.js +++ b/src/models/exam.js @@ -11,7 +11,6 @@ const Exam = sequelize.define('exams', { moduleId: { type: Sequelize.INTEGER, allowNull: false, - references: { model: 'modules', key: 'id' } }, type: { type: Sequelize.STRING diff --git a/src/services/examService.js b/src/services/examService.js index ad1b465a..e2b6b1bd 100644 --- a/src/services/examService.js +++ b/src/services/examService.js @@ -1,7 +1,6 @@ const Exam = require("../models/exam"); const { check } = require("express-validator"); const { sequelize } = require("../../config/db/mysql"); -const Module = require("../models/module"); class ExamService { @@ -87,13 +86,7 @@ class ExamService { static updateNormal(data, id) { const { moduleId, type, name } = data; - return Module.findByPk(moduleId) - .then(theModule => { - if (theModule) { - return Exam.findByPk(id); - } - return Promise.reject("no existe el modulo"); - }) + return Exam.findByPk(id) .then(hereExam => { if (hereExam && hereExam.publishedAt === null) { return hereExam.update({ @@ -102,7 +95,7 @@ class ExamService { name }); } - return Promise.reject("no existe el examen"); + return Promise.reject("Not exists exam"); }) .then(data => { // console.log('data ', data) @@ -156,13 +149,7 @@ class ExamService { * @returns {Promise} message error if it exists */ static exists(exam) { - return Module.findByPk(exam.moduleId) - .then(theModule => { - if (theModule) { - return Exam.findOne({ where: { moduleId: exam.moduleId, name: exam.name } }); - } - return Promise.reject("no existe el modulo"); - }) + return Exam.findOne({ where: { moduleId: exam.moduleId, name: exam.name } }) .then(data => { if (data) { return Promise.reject("Exists the record the exam"); diff --git a/tests/rest/answer-controller.js b/tests/rest/answer-controller.js index 559afa63..0d501ba4 100644 --- a/tests/rest/answer-controller.js +++ b/tests/rest/answer-controller.js @@ -4,148 +4,69 @@ const app = require("../../src/index"); const Answer = require("../../src/models/answer"); const { expect } = chai; -const User = require("../../src/models/user"); -const Professor = require("../../src/models/professor"); -const Category = require("../../src/models/category"); -const Course = require("../../src/models/course"); -const Module = require("../../src/models/module"); const Exam = require("../../src/models/exam"); const Question = require("../../src/models/question"); const Type_question = require("../../src/models/type_question.js"); chai.use(chaiHttp); -before(async() => { - try { - // ** METODO 1 - - await Type_question.create({ id: 1, type_question: 1, content: "abierta" }); - await Type_question.create({ id: 2, type_question: 2, content: "cerrada" }); - await Type_question.create({ id: 3, type_question: 3, content: "multiple" }); - await Type_question.create({ id: 4, type_question: 4, content: "numerica" }); - - await User.create({ id: "1", firstname: "ana", lastname: "aa", email: "aaa@ddd.com", password: "sss" }); - await Category.create({ id: "1", name: "alto", slug: "1" }); - await Professor.create({ id: "1", userId: "1", valuation: "11" }); - await Course.create({ id: "1", professorId: "1", categoryId: "1", title: "nodejs", description: "ssss", isPrivate: "0", invitationCode: "adfsdfs" }); - await Module.create({ id: "1", courseId: "1", title: "safsd", description: "sdfs" }); - - await Exam.create({ id: "1", moduleId: "1", name: "sdfs" }); - await Question.create({ id: 1, examId: 1, typeQuestionId: 1, code: "q1", content: "pregunta abierta", minimum: 20, length: 100 }); - await Question.create({ id: 2, examId: 1, typeQuestionId: 2, code: "q2", content: "pregunta cerrada" }); - await Question.create({ id: 3, examId: 1, typeQuestionId: 3, code: "q3", content: "pregunta multi opcion" }); - await Question.create({ id: 4, examId: 1, typeQuestionId: 4, code: "q4", content: "pregunta numerica", minimum: 10, tope: 100 }); - - //** METODO 2 */ - /* let usuarios = await User.findByPk(1); - if (usuarios == undefined) { - await User.create({ id: "1", firstname: "persona 1", lastname: "lopez perez", email: "aaa@ddd.com", password: "s89ss" }); - } - let categories = await Category.findByPk(1); - if (categories === undefined) { await Category.create({ id: "1", name: "alto", slug: "1" }); } +describe("Answer Tests", () => { + + before(async() => { + try { + + await Type_question.create({ id: 1, type_question: 1, content: "abierta" }); + await Type_question.create({ id: 2, type_question: 2, content: "cerrada" }); + await Type_question.create({ id: 3, type_question: 3, content: "multiple" }); + await Type_question.create({ id: 4, type_question: 4, content: "numerica" }); - let professors = await Professor.findByPk(1); - if (professors == undefined || professors == null) { await Professor.create({ id: "1", userId: "1", valuation: "11" }); } + await Exam.create({ id: "1", moduleId: "1", name: "sdfs" }); + await Question.create({ id: 1, examId: 1, typeQuestionId: 1, code: "q1", content: "pregunta abierta", minimum: 20, length: 100 }); + await Question.create({ id: 2, examId: 1, typeQuestionId: 2, code: "q2", content: "pregunta cerrada" }); + await Question.create({ id: 3, examId: 1, typeQuestionId: 3, code: "q3", content: "pregunta multi opcion" }); + await Question.create({ id: 4, examId: 1, typeQuestionId: 4, code: "q4", content: "pregunta numerica", minimum: 10, tope: 100 }); - let courses = await Course.findByPk(1); - if (courses === undefined || courses === null) { - await Course.create({ id: "1", professorId: "1", categoryId: "1", title: "alto", description: "ssss", isPrivate: "0", invitationCode: "adf5$5sdfs" }); + } catch (err) { + return new Error("An error has ocurred"); } + }); - let modules = await Module.findByPk(1); - if (modules == undefined || modules == null) { await Module.create({ id: "1", courseId: "1", title: "safsd", description: "sdfs" }); } - - await Type_question.create({ id: 1, type_question: 1, content: "abierta" }); - await Type_question.create({ id: 2, type_question: 2, content: "cerrada" }); - await Type_question.create({ id: 3, type_question: 3, content: "multiple" }); - await Type_question.create({ id: 4, type_question: 4, content: "numerica" }); - - - await Exam.create({ id: "1", moduleId: "1", name: "sdfs" }); - await Question.create({ id: 1, examId: 1, typeQuestionId: 1, code: "q1", content: "pregunta abierta", minimum: 20, length: 100 }); - await Question.create({ id: 2, examId: 1, typeQuestionId: 2, code: "q2", content: "pregunta cerrada" }); - await Question.create({ id: 3, examId: 1, typeQuestionId: 3, code: "q3", content: "pregunta multi opcion" }); - await Question.create({ id: 4, examId: 1, typeQuestionId: 4, code: "q4", content: "pregunta numerica", minimum: 10, tope: 100 }); -*/ - - } catch (err) { - return new Error("An error has ocurred"); - } -}); - -after(async() => { - try { - let data; - let vector; - - - - await Answer.destroy({ force: true }); - await Question.destroy({ force: true }); - await Exam.destroy({ force: true }); - await Module.destroy({ force: true }); - await Type_question.destroy({ force: true }); - /* - data = await Answer.findAll(); - if (data) { - vector = Object.values(data); - vector.forEach(item => (item.destroy({ force: true }))); - } - - let data1 = await Question.findAll(); - if (data1) { - let vector1 = Object.values(data1); - await vector1.forEach(item => item.destroy({ force: true })); - } - - let data2 = await Exam.findAll(); - if (data2) { - let vector2 = Object.values(data2); - vector2.forEach(item => item.destroy({ force: true })); - } - let data4 = await Type_question.findAll(); - if (data4) { - let vector4 = Object.values(data4); - vector4.forEach(item => item.destroy({ force: true })); - } - - let data5 = await Module.findAll(); - if (data5) { - let vector5 = Object.values(data5); - await vector5.forEach(item => item.destroy({ force: true })); - } - - let data6 = await Course.findAll(); - if (data6) { - let vector5 = Object.values(data6); - await vector5.forEach(item => item.destroy({ force: true })); - } - - let data7 = await Professor.findAll(); - if (data7) { - let vector5 = Object.values(data7); - await vector5.forEach(item => item.destroy({ force: true })); - } - - let data8 = await Category.findAll(); - if (data8) { - let vector5 = Object.values(data8); - await vector5.forEach(item => item.destroy({ force: true })); - } - - let data9 = await User.findAll(); - if (data9) { - let vector5 = Object.values(data9); - await vector5.forEach(item => item.destroy({ force: true })); - } - */ - - } catch (err) { - return new Error("An error has ocurred"); - } -}); -describe("Answer Tests", () => { + after(async() => { + try { + /* + await Answer.destroy({ force: true }); + await Question.destroy({ force: true }); + await Exam.destroy({ force: true }); + await Type_question.destroy({ force: true }); + */ + let data = await Answer.findAll(); + if (data) { + let vector1 = Object.values(data); + vector1.forEach(item => item.destroy({ force: true })); + } + + let data1 = await Question.findAll(); + if (data1) { + let vector1 = Object.values(data1); + vector1.forEach(item => item.destroy({ force: true })); + } + + let data2 = await Exam.findAll(); + if (data2) { + let vector2 = Object.values(data2); + vector2.forEach(item => item.destroy({ force: true })); + } + let data4 = await Type_question.findAll(); + if (data4) { + let vector4 = Object.values(data4); + vector4.forEach(item => item.destroy({ force: true })); + } + + } catch (err) { + return new Error("An error has ocurred"); + } + }); describe("Create an answer of Question Open", () => { diff --git a/tests/rest/exams.js b/tests/rest/exams.js index defd14f2..9d1e14fb 100644 --- a/tests/rest/exams.js +++ b/tests/rest/exams.js @@ -2,37 +2,29 @@ const chai = require("chai"); const chaiHttp = require("chai-http"); const app = require("../../src/index"); -const User = require("../../src/models/user"); -const Professor = require("../../src/models/professor"); -const Category = require("../../src/models/category"); -const Course = require("../../src/models/course"); -const Module = require("../../src/models/module"); -const Type_question = require("../../src/models/type_question.js"); - const { expect } = chai; +const Exam = require("../../src/models/exam"); chai.use(chaiHttp); -before(async() => { - try { - await Type_question.create({ id: 1, type_question: 1, content: "abierta" }); - await Type_question.create({ id: 2, type_question: 2, content: "cerrada" }); - await Type_question.create({ id: 3, type_question: 3, content: "multiple" }); - await Type_question.create({ id: 4, type_question: 4, content: "numerica" }); - await User.create({ id: "1", firstname: "ana", lastname: "aa", email: "aaa@ddd.com", password: "sss" }); - await Category.create({ id: "1", name: "alto", slug: "1" }); - await Professor.create({ id: "1", userId: "1", valuation: "11" }); - await Course.create({ id: "1", professorId: "1", categoryId: "1", title: "alto", description: "ssss", isPrivate: "0", invitationCode: "adfsdf677s" }); - await Module.create({ id: 1, courseId: 1, title: "safsd", description: "sdfs" }); - } catch (err) { - return new Error("An error has ocurred"); - } -}); +describe("Exam Test", () => { + after(async() => { + try { + // await Exam.destroy({ force: true }); + let data2 = await Exam.findAll(); + if (data2) { + let vector2 = Object.values(data2); + vector2.forEach(item => item.destroy({ force: true })); + } -describe("Exam Test", () => { + } catch (err) { + console.log("Error: ", err); + // return new Error("An error has ocurred"); + } + }); it("Should return an Exam Created", (done) => { chai.request(app) diff --git a/tests/rest/question.js b/tests/rest/question.js index b8f5a533..cb48eb62 100644 --- a/tests/rest/question.js +++ b/tests/rest/question.js @@ -3,12 +3,10 @@ const chaiHttp = require("chai-http"); const app = require("../../src/index"); const { expect } = chai; -const User = require("../../src/models/user"); -const Professor = require("../../src/models/professor"); -const Category = require("../../src/models/category"); -const Course = require("../../src/models/course"); -const Module = require("../../src/models/module"); +const Type_question = require("../../src/models/type_question.js"); const Exam = require("../../src/models/exam"); +const Question = require("../../src/models/question"); + chai.use(chaiHttp); @@ -16,11 +14,11 @@ describe("Question Tests", () => { before(async() => { try { - await User.create({ id: "1", firstname: "ana", lastname: "aa", email: "aaa@ddd.com", password: "sss" }); - await Category.create({ id: "1", name: "alto", slug: "1" }); - await Professor.create({ id: "1", userId: "1", valuation: "11" }); - await Course.create({ id: "1", professorId: "1", categoryId: "1", title: "alto", description: "ssss", isPrivate: "0", invitationCode: "adfsdfs" }); - await Module.create({ id: "1", courseId: "1", title: "safsd", description: "sdfs" }); + await Type_question.create({ id: 1, type_question: 1, content: "abierta" }); + await Type_question.create({ id: 2, type_question: 2, content: "cerrada" }); + await Type_question.create({ id: 3, type_question: 3, content: "multiple" }); + await Type_question.create({ id: 4, type_question: 4, content: "numerica" }); + await Exam.create({ id: "1", moduleId: "1", name: "sdfs" }); } catch (err) { @@ -28,6 +26,37 @@ describe("Question Tests", () => { } }); + after(async() => { + try { + /* + await Question.destroy({ force: true }); + await Exam.destroy({ force: true }); + await Type_question.destroy({ force: true }); + + */ + + let data1 = await Question.findAll(); + if (data1) { + let vector1 = Object.values(data1); + vector1.forEach(item => item.destroy({ force: true })); + } + + let data2 = await Exam.findAll(); + if (data2) { + let vector2 = Object.values(data2); + vector2.forEach(item => item.destroy({ force: true })); + } + let data4 = await Type_question.findAll(); + if (data4) { + let vector4 = Object.values(data4); + vector4.forEach(item => item.destroy({ force: true })); + } + + } catch (err) { + return new Error("An error has ocurred"); + } + }); + describe("Creation of OPEN Question", () => { it("should return an question created", (done) => { @@ -35,7 +64,6 @@ describe("Question Tests", () => { chai.request(app) .post("/api/v1/question") .send({ - "id": 1, "examId": 1, "typeQuestionId": 1, "code": "E1.q1.1", From a1df999d64727b0cca33da6eadc228491a9ba1f7 Mon Sep 17 00:00:00 2001 From: Nauel Date: Wed, 7 Oct 2020 14:31:22 -0400 Subject: [PATCH 09/11] fix:associations of table question, answer, exam ans type_question --- src/conexiones.js | 9 ++++++++ src/controllers/examController.js | 2 +- src/index.js | 14 ++++++------ src/models/answer.js | 1 - src/models/question.js | 2 -- src/services/examService.js | 37 +++++++++++++++++++++---------- 6 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 src/conexiones.js diff --git a/src/conexiones.js b/src/conexiones.js new file mode 100644 index 00000000..72cf0823 --- /dev/null +++ b/src/conexiones.js @@ -0,0 +1,9 @@ +const Type_question = require("../src/models/type_question"); +const Exam = require("../src/models/exam"); +const Question = require("../src/models/question"); +const Answer = require("../src/models/answer"); + +// **** relation of exam ******************** +Question.belongsTo(Type_question); +Question.hasMany(Answer); +Exam.hasMany(Question); \ No newline at end of file diff --git a/src/controllers/examController.js b/src/controllers/examController.js index 6df5f363..6a9c582b 100644 --- a/src/controllers/examController.js +++ b/src/controllers/examController.js @@ -5,7 +5,7 @@ class ExamController { static getExamComplet(req, res) { return ExamService.findAllById(req.params.id) .then((data) => { - if (data.length > 0) { + if (data && data.length > 0) { return res.status(200).json({ message: "Query executed correctly", data }); } else { return res.status(404).json({ err: "Exam not found" }); diff --git a/src/index.js b/src/index.js index a48b4a90..1635d5df 100644 --- a/src/index.js +++ b/src/index.js @@ -9,17 +9,17 @@ const path = require('path'); //creation of the service const app = express(); - +require("./conexiones") app.set("view engine", "hbs"); -app.engine(".hbs",exphbs({ - layoutsDir: path.join(__dirname,"../views/layouts"), - defaultLayout:'main', +app.engine(".hbs", exphbs({ + layoutsDir: path.join(__dirname, "../views/layouts"), + defaultLayout: 'main', extname: ".hbs", - partialsDir: path.join(__dirname,"../views/partials"), + partialsDir: path.join(__dirname, "../views/partials"), })); -app.set('views', path.join(__dirname,'../views')); +app.set('views', path.join(__dirname, '../views')); app.use(express.static(path.join(__dirname, '/public'))); @@ -53,4 +53,4 @@ const server = app.listen(port, "0.0.0.0", () => { console.log(`listening in port: ${port}`); }); -module.exports = server; +module.exports = server; \ No newline at end of file diff --git a/src/models/answer.js b/src/models/answer.js index 3c7a0146..974b52cb 100644 --- a/src/models/answer.js +++ b/src/models/answer.js @@ -15,7 +15,6 @@ const Answer = sequelize.define('answers', { questionId: { type: Sequelize.INTEGER, allowNull: false, - references: { model: 'questions', key: 'id' } }, content: { type: Sequelize.STRING diff --git a/src/models/question.js b/src/models/question.js index 8c8b7eab..07813f92 100644 --- a/src/models/question.js +++ b/src/models/question.js @@ -11,12 +11,10 @@ const Question = sequelize.define('questions', { examId: { type: Sequelize.INTEGER, allowNull: false, - references: { model: 'exams', key: 'id' } }, typeQuestionId: { type: Sequelize.INTEGER, allowNull: false, - references: { model: 'type_questions', key: 'id' } }, code: { type: Sequelize.STRING, diff --git a/src/services/examService.js b/src/services/examService.js index e2b6b1bd..8a20a370 100644 --- a/src/services/examService.js +++ b/src/services/examService.js @@ -1,6 +1,9 @@ const Exam = require("../models/exam"); const { check } = require("express-validator"); -const { sequelize } = require("../../config/db/mysql"); + +const Question = require("../models/question"); +const Answer = require("../models/answer"); +const Type_question = require("../models/type_question"); class ExamService { @@ -98,7 +101,7 @@ class ExamService { return Promise.reject("Not exists exam"); }) .then(data => { - // console.log('data ', data) + // console.log("data ", data) return Promise.resolve(data); }) .catch(err => Promise.reject(err)); @@ -134,13 +137,25 @@ class ExamService { } static findAllById(id) { - let query = ` - SELECT * - FROM exams e - inner join questions as q on q.examId = e.id - INNER JOIN answers AS a ON a.questionId = q.id - where e.id =:id;`; - return sequelize.query(query, { replacements: { id: id }, type: sequelize.QueryTypes.SELECT }); + let query = { + include: [{ + model: Question, + attributes: { exclude: ["publishedAt", "createdAt", "updatedAt", "deletedAt"] }, + include: [{ + model: Type_question, + attributes: ["content"], + }, { + model: Answer, + attributes: { exclude: ["publishedAt", "createdAt", "updatedAt", "deletedAt"] }, + }], + }], + attributes: { exclude: ["publishedAt", "createdAt", "updatedAt", "deletedAt"] }, + where: { id: id } + }; + + return Exam.findAll(query) + .then(data => Promise.resolve(data)) + .catch(err => Promise.reject(err)); } /** @@ -156,9 +171,7 @@ class ExamService { } return Promise.resolve(1); }) - .catch((err) => { - return Promise.reject(err); - }); + .catch((err) => Promise.reject(err)); } } From b03f3c29c109b07b0e395a65fb3fad5404df77dd Mon Sep 17 00:00:00 2001 From: Nauel Date: Thu, 8 Oct 2020 16:30:47 -0400 Subject: [PATCH 10/11] fix:changing location of table associations --- src/conexiones.js | 9 -- src/index.js | 2 +- src/models/associations.js | 9 ++ src/services/examService.js | 1 + tests/rest/answer-controller.js | 35 +++---- tests/rest/exams.js | 179 ++++++++++++++++++-------------- tests/rest/question.js | 39 ++++--- 7 files changed, 147 insertions(+), 127 deletions(-) delete mode 100644 src/conexiones.js create mode 100644 src/models/associations.js diff --git a/src/conexiones.js b/src/conexiones.js deleted file mode 100644 index 72cf0823..00000000 --- a/src/conexiones.js +++ /dev/null @@ -1,9 +0,0 @@ -const Type_question = require("../src/models/type_question"); -const Exam = require("../src/models/exam"); -const Question = require("../src/models/question"); -const Answer = require("../src/models/answer"); - -// **** relation of exam ******************** -Question.belongsTo(Type_question); -Question.hasMany(Answer); -Exam.hasMany(Question); \ No newline at end of file diff --git a/src/index.js b/src/index.js index 1635d5df..92dd5b7e 100644 --- a/src/index.js +++ b/src/index.js @@ -9,7 +9,7 @@ const path = require('path'); //creation of the service const app = express(); -require("./conexiones") + app.set("view engine", "hbs"); app.engine(".hbs", exphbs({ diff --git a/src/models/associations.js b/src/models/associations.js new file mode 100644 index 00000000..42e870d7 --- /dev/null +++ b/src/models/associations.js @@ -0,0 +1,9 @@ +const Type_question = require("./type_question"); +const Exam = require("./exam"); +const Question = require("./question"); +const Answer = require("./answer"); + +// **** associations of exam ******************** +Question.belongsTo(Type_question); +Question.hasMany(Answer); +Exam.hasMany(Question); \ No newline at end of file diff --git a/src/services/examService.js b/src/services/examService.js index 8a20a370..09fd02e4 100644 --- a/src/services/examService.js +++ b/src/services/examService.js @@ -5,6 +5,7 @@ const Question = require("../models/question"); const Answer = require("../models/answer"); const Type_question = require("../models/type_question"); +require("../models/associations"); class ExamService { static validate() { diff --git a/tests/rest/answer-controller.js b/tests/rest/answer-controller.js index 0d501ba4..c6ac4d3d 100644 --- a/tests/rest/answer-controller.js +++ b/tests/rest/answer-controller.js @@ -8,9 +8,17 @@ const Exam = require("../../src/models/exam"); const Question = require("../../src/models/question"); const Type_question = require("../../src/models/type_question.js"); - chai.use(chaiHttp); +const deleteRegister = async(data) => { + let vector = await Object.values(data); + for (const item of vector) { + const erased = await item.destroy({ force: true }); + // console.log('erased ', JSON.stringify(erased)) + } + return 1; +}; + describe("Answer Tests", () => { before(async() => { @@ -21,7 +29,7 @@ describe("Answer Tests", () => { await Type_question.create({ id: 3, type_question: 3, content: "multiple" }); await Type_question.create({ id: 4, type_question: 4, content: "numerica" }); - await Exam.create({ id: "1", moduleId: "1", name: "sdfs" }); + await Exam.create({ id: "1", moduleId: "1", name: "exam de answer" }); await Question.create({ id: 1, examId: 1, typeQuestionId: 1, code: "q1", content: "pregunta abierta", minimum: 20, length: 100 }); await Question.create({ id: 2, examId: 1, typeQuestionId: 2, code: "q2", content: "pregunta cerrada" }); await Question.create({ id: 3, examId: 1, typeQuestionId: 3, code: "q3", content: "pregunta multi opcion" }); @@ -41,27 +49,16 @@ describe("Answer Tests", () => { await Type_question.destroy({ force: true }); */ let data = await Answer.findAll(); - if (data) { - let vector1 = Object.values(data); - vector1.forEach(item => item.destroy({ force: true })); - } + await deleteRegister(data) let data1 = await Question.findAll(); - if (data1) { - let vector1 = Object.values(data1); - vector1.forEach(item => item.destroy({ force: true })); - } + await deleteRegister(data1) let data2 = await Exam.findAll(); - if (data2) { - let vector2 = Object.values(data2); - vector2.forEach(item => item.destroy({ force: true })); - } + await deleteRegister(data2) + let data4 = await Type_question.findAll(); - if (data4) { - let vector4 = Object.values(data4); - vector4.forEach(item => item.destroy({ force: true })); - } + await deleteRegister(data4); } catch (err) { return new Error("An error has ocurred"); @@ -199,7 +196,7 @@ describe("Answer Tests", () => { }); }); - it("Should return an Error, if add other answer", (done) => { + it("Should return an Error, if you add another answer to the same question", (done) => { chai.request(app) .post("/api/v1/answer") diff --git a/tests/rest/exams.js b/tests/rest/exams.js index 9d1e14fb..40acc816 100644 --- a/tests/rest/exams.js +++ b/tests/rest/exams.js @@ -6,6 +6,15 @@ const { expect } = chai; const Exam = require("../../src/models/exam"); chai.use(chaiHttp); +let examCreado; + +const deleteRegister = async(data) => { + let vector = await Object.values(data); + for (const item of vector) { + const erased = await item.destroy({ force: true }); + // console.log('erased ', JSON.stringify(erased)) + } +}; describe("Exam Test", () => { @@ -14,10 +23,7 @@ describe("Exam Test", () => { // await Exam.destroy({ force: true }); let data2 = await Exam.findAll(); - if (data2) { - let vector2 = Object.values(data2); - vector2.forEach(item => item.destroy({ force: true })); - } + await deleteRegister(data2); } catch (err) { console.log("Error: ", err); @@ -25,77 +31,96 @@ describe("Exam Test", () => { } }); - it("Should return an Exam Created", (done) => { - - chai.request(app) - .post("/api/v1/exam") - .send({ - "moduleId": "1", - "type": 1, - "name": "Introduction to Vue" - }) - .end(function(err, res) { - - if (err) done(err); - - expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); - expect(res).to.have.status(200); - done(); - }); - }); - - it("Should return an Error, when the exam name is empty", (done) => { - - chai.request(app) - .post("/api/v1/exam") - .send({ - "moduleId": "1", - "type": 1 - }) - .end(function(err, res) { - - if (err) done(err); - - expect(res).to.have.status(400); - expect(JSON.parse(res.text)).to.have.all.keys("errors"); - done(); - }); - }); - - it("Should return an Error, when moduleId is empty", (done) => { - - chai.request(app) - .post("/api/v1/exam") - .send({ - "type": 1, - "name": "Introduction to Ionic" - }) - .end(function(err, res) { - - if (err) done(err); - - expect(res).to.have.status(400); - expect(JSON.parse(res.text)).to.have.all.keys("errors"); - done(); - }); - }); - - it("Should return an Error, when name and moduleId exists in the base", (done) => { - - chai.request(app) - .post("/api/v1/exam") - .send({ - "moduleId": "1", - "type": 1, - "name": "Introduction to Vue" - }) - .end(function(err, res) { - - if (err) done(err); - - expect(res).to.have.status(500); - expect(JSON.parse(res.text)).to.have.all.keys("err"); - done(); - }); - }); + describe("Exam Test", () => { + it("Should return an Exam Created", (done) => { + + chai.request(app) + .post("/api/v1/exam") + .send({ + "moduleId": "1", + "type": 1, + "name": "Introduction to Vue" + }) + .end(function(err, res) { + + if (err) done(err); + // console.log('created ', res, JSON.stringify(res)) + + expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + expect(res).to.have.status(200); + let otro = JSON.parse(res.text); + examCreado = otro.data.id; + done(); + }); + }); + + it("Should return as Exam list", (done) => { + + chai.request(app) + .get("/api/v1/exam/" + examCreado) + .end(function(err, res) { + + if (err) done(err); + + expect(JSON.parse(res.text)).to.have.all.keys("message", "data"); + expect(res).to.have.status(200); + done(); + }); + }); + + it("Should return an Error, when the exam name is empty", (done) => { + + chai.request(app) + .post("/api/v1/exam") + .send({ + "moduleId": "1", + "type": 1 + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(400); + expect(JSON.parse(res.text)).to.have.all.keys("errors"); + done(); + }); + }); + + it("Should return an Error, when moduleId is empty", (done) => { + + chai.request(app) + .post("/api/v1/exam") + .send({ + "type": 1, + "name": "Introduction to Ionic" + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(400); + expect(JSON.parse(res.text)).to.have.all.keys("errors"); + done(); + }); + }); + + it("Should return an Error, when name and moduleId exists in the base", (done) => { + + chai.request(app) + .post("/api/v1/exam") + .send({ + "moduleId": "1", + "type": 1, + "name": "Introduction to Vue" + }) + .end(function(err, res) { + + if (err) done(err); + + expect(res).to.have.status(500); + expect(JSON.parse(res.text)).to.have.all.keys("err"); + done(); + }); + }); + }) }) \ No newline at end of file diff --git a/tests/rest/question.js b/tests/rest/question.js index cb48eb62..62db9643 100644 --- a/tests/rest/question.js +++ b/tests/rest/question.js @@ -2,14 +2,21 @@ const chai = require("chai"); const chaiHttp = require("chai-http"); const app = require("../../src/index"); const { expect } = chai; - const Type_question = require("../../src/models/type_question.js"); const Exam = require("../../src/models/exam"); const Question = require("../../src/models/question"); - chai.use(chaiHttp); +const clearRegistry = async(data) => { + let vector = await Object.values(data); + for (const item of vector) { + const erased = await item.destroy({ force: true }); + // console.log('erased ', JSON.stringify(erased)) + } + return 1; +}; + describe("Question Tests", () => { before(async() => { @@ -19,7 +26,7 @@ describe("Question Tests", () => { await Type_question.create({ id: 3, type_question: 3, content: "multiple" }); await Type_question.create({ id: 4, type_question: 4, content: "numerica" }); - await Exam.create({ id: "1", moduleId: "1", name: "sdfs" }); + await Exam.create({ id: "1", moduleId: "1", name: "exam de question" }); } catch (err) { return new Error("An error has ocurred"); @@ -29,28 +36,18 @@ describe("Question Tests", () => { after(async() => { try { /* - await Question.destroy({ force: true }); - await Exam.destroy({ force: true }); - await Type_question.destroy({ force: true }); - - */ - + await Question.destroy({ force: true }); + await Exam.destroy({ force: true }); + await Type_question.destroy({ force: true }); + */ let data1 = await Question.findAll(); - if (data1) { - let vector1 = Object.values(data1); - vector1.forEach(item => item.destroy({ force: true })); - } + await clearRegistry(data1); let data2 = await Exam.findAll(); - if (data2) { - let vector2 = Object.values(data2); - vector2.forEach(item => item.destroy({ force: true })); - } + await clearRegistry(data2); + let data4 = await Type_question.findAll(); - if (data4) { - let vector4 = Object.values(data4); - vector4.forEach(item => item.destroy({ force: true })); - } + await clearRegistry(data4); } catch (err) { return new Error("An error has ocurred"); From af6f25646b47f39011e35bcf82464c0afc9df665 Mon Sep 17 00:00:00 2001 From: Nauel Date: Sun, 1 Nov 2020 16:19:03 -0400 Subject: [PATCH 11/11] fix:addition of the delete method --- _exam.http | 115 ++++++++++++++++++ .../20200830010511-create-answer.js | 9 +- .../seeders/20200830142608-type_questions.js | 8 +- src/api/routes/exams.js | 2 + src/api/routes/questions.js | 2 + src/controllers/answerController.js | 8 +- src/controllers/examController.js | 14 ++- src/controllers/questionController.js | 23 ++++ src/models/associations.js | 4 +- src/services/answerService.js | 42 ++++--- src/services/examService.js | 45 +++---- src/services/questionService.js | 28 +++-- 12 files changed, 235 insertions(+), 65 deletions(-) create mode 100644 _exam.http diff --git a/_exam.http b/_exam.http new file mode 100644 index 00000000..c048e6f1 --- /dev/null +++ b/_exam.http @@ -0,0 +1,115 @@ +POST http://localhost:3000/api/v1/exam HTTP/1.1 +content-type: application/json + +{ + "moduleId": 1, + "name": "JS X" +} + +### +GET http://localhost:3000/api/v1/exam HTTP/1.1 +content-type: application/json + +### +GET http://localhost:3000/api/v1/exam/6 HTTP/1.1 +content-type: application/json + +### +PUT http://localhost:3000/api/v1/exam/6 HTTP/1.1 +content-type: application/json + +{ + "moduleId": 1, + "name": "js VI" +} + +### Exam closed for editing because it is running +PATCH http://localhost:3000/api/v1/exam/close/6 HTTP/1.1 +content-type: application/json + +### Exam closed for editing because it is running +DELETE http://localhost:3000/api/v1/exam/6 HTTP/1.1 +content-type: application/json + +### ######################### QUESTION ######################### +### +POST http://localhost:3000/api/v1/question HTTP/1.1 +content-type: application/json + +{ + "examId": 6, + "typeQuestionId": 2, + "code":"q1.1", + "content": "pregunta 41" +} +### +POST http://localhost:3000/api/v1/question HTTP/1.1 +content-type: application/json + +{ + "examId": 6, + "typeQuestionId": 4, + "code":"q1.1", + "content": "pregunta 2", + "minimum": 2, + "tope":50 +} +### +GET http://localhost:3000/api/v1/question HTTP/1.1 +content-type: application/json + +### +GET http://localhost:3000/api/v1/question/107 HTTP/1.1 +content-type: application/json + +### +PUT http://localhost:3000/api/v1/question/5 HTTP/1.1 +content-type: application/json + +{ + "examId": 3, + "typeQuestionId": 4, + "code":"q1.1", + "content": "Pregunta 2da.", + "minimum": 2, + "tope":50 +} + +### +DELETE http://localhost:3000/api/v1/question/5 HTTP/1.1 +content-type: application/json + +### ######################### ANSWER ######################### +### +POST http://localhost:3000/api/v1/answer HTTP/1.1 +content-type: application/json + +{ + "questionId": 22, + "content": "red q1", + "code":"a1.1", + "isTrue": 1, + "score": 20 +} + +### +GET http://localhost:3000/api/v1/answer HTTP/1.1 +content-type: application/json + +### +GET http://localhost:3000/api/v1/answer/1 HTTP/1.1 +content-type: application/json + +### +PUT http://localhost:3000/api/v1/answer/1 HTTP/1.1 +content-type: application/json + +{ + "questionId": 3, + "content": "blue", + "code":"a1.1", + "isTrue": 0 +} +### +DELETE http://localhost:3000/api/v1/answer/1 HTTP/1.1 +content-type: application/json diff --git a/database/migrations/20200830010511-create-answer.js b/database/migrations/20200830010511-create-answer.js index bd64e53a..6aaded7f 100644 --- a/database/migrations/20200830010511-create-answer.js +++ b/database/migrations/20200830010511-create-answer.js @@ -1,7 +1,7 @@ -'use strict'; +"use strict"; module.exports = { up: async(queryInterface, Sequelize) => { - await queryInterface.createTable('answers', { + await queryInterface.createTable("answers", { id: { type: Sequelize.INTEGER, allowNull: false, @@ -15,7 +15,8 @@ module.exports = { questionId: { type: Sequelize.INTEGER, allowNull: false, - references: { model: 'questions', key: 'id' } + onDelete: "CASCADE", + references: { model: "questions", key: "id" } }, content: { type: Sequelize.STRING @@ -45,6 +46,6 @@ module.exports = { }); }, down: async(queryInterface, Sequelize) => { - await queryInterface.dropTable('answers'); + await queryInterface.dropTable("answers"); } }; \ No newline at end of file diff --git a/database/seeders/20200830142608-type_questions.js b/database/seeders/20200830142608-type_questions.js index 9ada31c6..85170a11 100644 --- a/database/seeders/20200830142608-type_questions.js +++ b/database/seeders/20200830142608-type_questions.js @@ -3,10 +3,10 @@ const faker = require('faker'); module.exports = { up: async(queryInterface, Sequelize) => { let data = [ - { type_question: '1', content: 'abierta', createdAt: new Date(), updatedAt: new Date() }, - { type_question: '2', content: 'cerrada', createdAt: new Date(), updatedAt: new Date() }, - { type_question: '3', content: 'multiple', createdAt: new Date(), updatedAt: new Date() }, - { type_question: '4', content: 'numerica', createdAt: new Date(), updatedAt: new Date() }, + { id: 1, type_question: '1', content: 'abierta', createdAt: new Date(), updatedAt: new Date() }, + { id: 2, type_question: '2', content: 'cerrada', createdAt: new Date(), updatedAt: new Date() }, + { id: 3, type_question: '3', content: 'multiple', createdAt: new Date(), updatedAt: new Date() }, + { id: 4, type_question: '4', content: 'numerica', createdAt: new Date(), updatedAt: new Date() }, ]; await queryInterface.bulkInsert('type_questions', data, {}); diff --git a/src/api/routes/exams.js b/src/api/routes/exams.js index d2d28fb7..d20a51cb 100644 --- a/src/api/routes/exams.js +++ b/src/api/routes/exams.js @@ -5,9 +5,11 @@ const ExamService = require("../../services/examService"); const { validator } = require("../middlewares/validator"); router.post("/", validator(ExamService.validate()), ExamController.createExam); +router.get("/", ExamController.getAll); router.get("/:id", ExamController.getExamComplet); router.put("/:id", ExamController.updateNormal); router.patch("/close/:id", ExamController.close); +router.delete("/:id", ExamController.delete); module.exports = router; diff --git a/src/api/routes/questions.js b/src/api/routes/questions.js index 38b06240..b6230473 100644 --- a/src/api/routes/questions.js +++ b/src/api/routes/questions.js @@ -5,7 +5,9 @@ const QuestionService = require("../../services/questionService"); const { validator } = require("../middlewares/validator"); router.post("/", validator(QuestionService.validate()), QuestionController.createQuestion); +router.get("/", QuestionController.getAll); router.get("/:id", QuestionController.getQuestion); router.put("/:id", validator(QuestionService.validate()), QuestionController.updateQuestion); +router.delete("/:id", QuestionController.delete); module.exports = router; \ No newline at end of file diff --git a/src/controllers/answerController.js b/src/controllers/answerController.js index 5a18a79c..0fe9de40 100644 --- a/src/controllers/answerController.js +++ b/src/controllers/answerController.js @@ -72,17 +72,17 @@ class AnswerController { /** * The complete registration must be sent, to validate - * + * You can change the relationship with the question, questionId */ static async updateNormal(req, res) { const { id } = req.params; let answerVerify = Object.assign({}, req.body); // delete answerVerify.questionId; return AnswerService.findExam(id, answerVerify.questionId) - .then(exam => { - if (exam && exam.publishedAt === null && exam.question) { + .then(data => { + if (data.exam && data.exam[0].questions[0]) { // answerVerify.questionId = exam.question.id; - answerVerify.typeQuestionId = exam.question.typeQuestionId; + answerVerify.typeQuestionId = data.exam[0].questions[0].typeQuestionId; return AnswerService.validateParameters(answerVerify); } return res.status(500).json({ err: "Exam not found" }); diff --git a/src/controllers/examController.js b/src/controllers/examController.js index 6a9c582b..e7a68856 100644 --- a/src/controllers/examController.js +++ b/src/controllers/examController.js @@ -14,8 +14,8 @@ class ExamController { .catch((err) => res.status(500).json({ err })); } - static getExam(req, res) { - return ExamService.findById(req.body.id) + static getAll(req, res) { + return ExamService.show() .then((data) => { if (data) { return res.status(200).json({ message: "Query executed correctly", data }); @@ -68,5 +68,15 @@ class ExamController { } } + static async delete(req, res) { + try { + const { id } = req.params; + const exam = await ExamService.deleteNormal(id); + return res.status(200).json({ message: "Delete Sucessfull", data: exam }); + } catch (err) { + return res.status(500).json({ err }); + } + } + } module.exports = ExamController; \ No newline at end of file diff --git a/src/controllers/questionController.js b/src/controllers/questionController.js index 7f595808..094b8b7b 100644 --- a/src/controllers/questionController.js +++ b/src/controllers/questionController.js @@ -15,6 +15,18 @@ class QuestionController { .catch((err) => res.status(500).json({ err })); } + static getAll(req, res) { + return QuestionService.show(req.body.id) + .then((data) => { + if (data && data.length > 0) { + return res.status(200).json({ message: "Query executed correctly", data }); + } else { + return res.status(404).json({ err: "Question not found" }); + } + }) + .catch((err) => res.status(500).json({ err })); + } + static createQuestion(req, res) { const question = { examId: req.body.examId, @@ -45,6 +57,7 @@ class QuestionController { let change = req.body; return Promise.all([ExamService.findById(req.body.examId), QuestionService.findById(id)]) .then(examQuestion => { + console.log('sss ', examQuestion) if (examQuestion[0] && examQuestion[0].publishedAt === null && examQuestion[1]) { return QuestionService.changeType(change, examQuestion[1]); } @@ -61,6 +74,16 @@ class QuestionController { }) .catch(err => res.status(500).json({ err })); } + + static async delete(req, res) { + try { + const { id } = req.params; + const question = await QuestionService.delete(id); + return res.status(200).json({ message: "Delete Sucessfull", data: question }); + } catch (err) { + return res.status(500).json({ err }); + } + } } module.exports = QuestionController; \ No newline at end of file diff --git a/src/models/associations.js b/src/models/associations.js index 42e870d7..51feb470 100644 --- a/src/models/associations.js +++ b/src/models/associations.js @@ -5,5 +5,7 @@ const Answer = require("./answer"); // **** associations of exam ******************** Question.belongsTo(Type_question); -Question.hasMany(Answer); +//Answer.belongsTo(Question, { onDelete: "CASCADE", hooks: true }); +Answer.belongsTo(Question, { foreignKey: { name: "questionId", allowNull: false }, onDelete: "CASCADE" }); +Question.hasMany(Answer, { foreignKey: { name: "questionId", allowNull: false } }); Exam.hasMany(Question); \ No newline at end of file diff --git a/src/services/answerService.js b/src/services/answerService.js index 6c9fab55..985b2725 100644 --- a/src/services/answerService.js +++ b/src/services/answerService.js @@ -1,6 +1,7 @@ const Answer = require("../models/answer"); -const ExamService = require("./examService"); -const QuestionService = require("./questionService"); +const Question = require("../models/question"); +const Exam = require("../models/exam"); + const { check } = require("express-validator"); const typeQuestion = require("../../config/enum/typeOfQuestion"); @@ -95,6 +96,7 @@ class AnswerService { return new Error("An error has ocurred"); } } + static async delete(id) { try { const answer = await Answer.findByPk(id); @@ -107,31 +109,41 @@ class AnswerService { } } + /** ***** + * Find out if the answer exists and the question can be another or old, + * always checking that the exam is not published + * @param {Integer} idAnswer identifier of the answer to update + * @param {Integer} questionId identificador of question + */ static async findExam(idAnswer, questionId) { let respuesta = {}; - return Answer.findByPk(idAnswer) + let query = { + include: [{ + model: Question, + attributes: { exclude: ["createdAt", "updatedAt", "deletedAt"] }, + where: { id: questionId } + }], + attributes: { exclude: ["createdAt", "updatedAt", "deletedAt"] }, + where: { + publishedAt: null + } + }; + return await Answer.findByPk(idAnswer) .then(data => { if (data) { respuesta.answer = data; - return QuestionService.findById(questionId); - } - return Promise.reject("No existe answer") - }) - .then(data => { - if (data) { - respuesta.question = data; - return ExamService.findById(data.examId); + return Exam.findAll(query); // return QuestionService.findById(questionId); } - return Promise.reject("No existe question") + return Promise.reject("There is NO answer"); }) .then(data => { - if (data && data.publisheAt === null) { + if (data.length > 0) { respuesta.exam = data; return Promise.resolve(respuesta); } - return Promise.reject("No existe exam o esta close") + return Promise.reject("There is NO exam or is it published"); }) - .catch(err => Promise.reject(err)) + .catch(err => Promise.reject(err)); } // questionId can be not changed diff --git a/src/services/examService.js b/src/services/examService.js index 09fd02e4..5543b1e4 100644 --- a/src/services/examService.js +++ b/src/services/examService.js @@ -21,8 +21,9 @@ class ExamService { if (hereExam) { return hereExam; } + return Promise.reject("Not exists Exam"); } catch (err) { - return new Error("An error has ocurred"); + return Promise.reject("An error has ocurred"); } } @@ -52,7 +53,7 @@ class ExamService { } static async delete(id) { - // si un estudiante no hizo el examen se borra.. el profesor puede borrar con alumnos borrado logico + // the teacher can delete an exam with enrolled students try { const hereExam = await Exam.findByPk(id); if (hereExam) { @@ -64,28 +65,20 @@ class ExamService { } } - static async deleteNormal(id) { - try { - const hereExam = await Exam.findByPk(id); - if (hereExam && hereExam.publishedAt === null) { - await hereExam.destroy(); - return hereExam; - } - } catch (err) { - return new Error("An error has ocurred"); - } - } - - static async deleteRestringuido(id) { - try { - const hereExam = await Exam.findByPk(id); - if (hereExam) { - await hereExam.destroy(); - return hereExam; - } - } catch (err) { - return new Error("An error has ocurred"); - } + /** + * the exam is logically deleted if it is not published and does not have a related question + * @param {integer} id identificator of exam + */ + static deleteNormal(id) { + return Promise.all([Exam.findByPk(id), Question.findOne({ where: { examId: id } })]) + .then(exam => { + if (exam[0] && exam[0].publishedAt === null && !exam[1]) { + exam[0].destroy(); + return exam[0]; + } + return Promise.reject("Exam is running or There is related question"); + }) + .catch(err => Promise.reject(err)); } static updateNormal(data, id) { @@ -141,13 +134,13 @@ class ExamService { let query = { include: [{ model: Question, - attributes: { exclude: ["publishedAt", "createdAt", "updatedAt", "deletedAt"] }, + attributes: { exclude: ["createdAt", "updatedAt", "deletedAt"] }, include: [{ model: Type_question, attributes: ["content"], }, { model: Answer, - attributes: { exclude: ["publishedAt", "createdAt", "updatedAt", "deletedAt"] }, + attributes: { exclude: ["createdAt", "updatedAt", "deletedAt"] }, }], }], attributes: { exclude: ["publishedAt", "createdAt", "updatedAt", "deletedAt"] }, diff --git a/src/services/questionService.js b/src/services/questionService.js index 35a183b5..f1ccfe28 100644 --- a/src/services/questionService.js +++ b/src/services/questionService.js @@ -30,7 +30,7 @@ class QuestionService { break; default: if (!minimum) return true; - else throw new Error("Parameter NOT required"); + else throw new Error("Parameter NOT required for the type of question"); } return true; }), @@ -41,7 +41,7 @@ class QuestionService { } else if (req.body.typeQuestionId != typeQuestion.NUMERICALQUESTION && !val) { return true; } else if (req.body.typeQuestionId != typeQuestion.NUMERICALQUESTION && val) { - throw new Error("Parameter NOT required"); + throw new Error("Parameter NOT required for the type of question"); } else return true; }), check("length").custom((val, { req }) => { @@ -51,7 +51,7 @@ class QuestionService { } else if (req.body.typeQuestionId != typeQuestion.OPENQUESTION && !val) { return true; } else if (req.body.typeQuestionId != typeQuestion.OPENQUESTION && val) { - throw new Error("Parameter NOT required"); + throw new Error("Parameter NOT required for the type of question"); } else if (req.body.typeQuestionId == typeQuestion.OPENQUESTION && val && parseInt(val, 10) > 1 && parseInt(val, 10) < 500) { return true; } @@ -85,7 +85,7 @@ class QuestionService { }); return question; } catch (err) { - return new Error("An error has ocurred"); + return Promise.reject("An error has ocurred"); } } @@ -124,6 +124,18 @@ class QuestionService { } static async delete(id) { + return Promise.all([Question.findByPk(id), Answer.findOne({ where: { questionId: id } })]) + .then(questionAnswer => { + if (questionAnswer[0] && !questionAnswer[1]) { + questionAnswer[0].destroy(); + return questionAnswer[0]; + } + return Promise.reject("There is related answer"); + }) + .catch(err => Promise.reject(err)); + } + + static async deleteOrigin(id) { try { const question = await Question.findByPk(id); if (question) { @@ -175,12 +187,11 @@ class QuestionService { * @returns {Promise} reject, when the question exists in the exam */ static findExists(question) { - return QuestionService.findOneBy({ where: { examId: question.examId, content: question.content } }) + return Question.findOne({ where: { examId: question.examId, content: question.content } }) .then((data) => { + // console.log('findExists ', data) if (data) { - const err = { error: "The Question already exists" }; - err.data = data; - return Promise.reject(err); + return Promise.reject("The Question already exists"); } else { return Promise.resolve("There is no Question"); } @@ -222,7 +233,6 @@ class QuestionService { } /** - * validar the update, parameter and logica * if change of type the question then change the answers * */