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/20200830010509-create-exam.js b/database/migrations/20200830010509-create-exam.js index 2cf55a3a..0227e767 100644 --- a/database/migrations/20200830010509-create-exam.js +++ b/database/migrations/20200830010509-create-exam.js @@ -11,15 +11,18 @@ module.exports = { moduleId: { type: Sequelize.INTEGER, allowNull: false, - references: { model: 'modules', key: 'id' } }, 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/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/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/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/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..d20a51cb 100644 --- a/src/api/routes/exams.js +++ b/src/api/routes/exams.js @@ -5,7 +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 09e1e009..b6230473 100644 --- a/src/api/routes/questions.js +++ b/src/api/routes/questions.js @@ -5,6 +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 b4534cc9..0fe9de40 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 + * 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(data => { + if (data.exam && data.exam[0].questions[0]) { + // answerVerify.questionId = exam.question.id; + answerVerify.typeQuestionId = data.exam[0].questions[0].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..e7a68856 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" }); @@ -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 }); @@ -30,13 +30,53 @@ 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 }); + } + } + + 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 0c699a0b..094b8b7b 100644 --- a/src/controllers/questionController.js +++ b/src/controllers/questionController.js @@ -9,7 +9,19 @@ 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 })); + } + + 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 })); @@ -26,19 +38,52 @@ 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 => { + console.log('sss ', 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 })); + } + + 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/index.js b/src/index.js index a48b4a90..92dd5b7e 100644 --- a/src/index.js +++ b/src/index.js @@ -12,14 +12,14 @@ const app = express(); 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/associations.js b/src/models/associations.js new file mode 100644 index 00000000..51feb470 --- /dev/null +++ b/src/models/associations.js @@ -0,0 +1,11 @@ +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); +//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/models/exam.js b/src/models/exam.js index eef83643..22a88ebe 100644 --- a/src/models/exam.js +++ b/src/models/exam.js @@ -11,15 +11,18 @@ const Exam = sequelize.define('exams', { moduleId: { type: Sequelize.INTEGER, allowNull: false, - references: { model: 'modules', key: 'id' } }, 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/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/answerService.js b/src/services/answerService.js index 14a1a194..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"); @@ -8,12 +9,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)) { @@ -93,6 +96,7 @@ class AnswerService { return new Error("An error has ocurred"); } } + static async delete(id) { try { const answer = await Answer.findByPk(id); @@ -105,19 +109,63 @@ class AnswerService { } } - static async findExam(query) { + /** ***** + * 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 = {}; + 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 Exam.findAll(query); // return QuestionService.findById(questionId); + } + return Promise.reject("There is NO answer"); + }) + .then(data => { + if (data.length > 0) { + respuesta.exam = data; + return Promise.resolve(respuesta); + } + return Promise.reject("There is NO exam or is it published"); + }) + .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 +173,9 @@ class AnswerService { foundAnswer.update({ code, questionId, - content, + content: content || null, isTrue, - score, + score: score || 0, }); return foundAnswer; } @@ -137,7 +185,7 @@ 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 @@ -145,9 +193,9 @@ class AnswerService { static validateParameters(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..5543b1e4 100644 --- a/src/services/examService.js +++ b/src/services/examService.js @@ -1,16 +1,17 @@ const Exam = require("../models/exam"); const { check } = require("express-validator"); -const models = require("../../config/db/mysql"); -let sequelize; -sequelize = models.sequelize; +const Question = require("../models/question"); +const Answer = require("../models/answer"); +const Type_question = require("../models/type_question"); +require("../models/associations"); 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 }), ]; } @@ -20,24 +21,26 @@ 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"); } } 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); @@ -50,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) { @@ -62,15 +65,52 @@ class ExamService { } } - static async update(data, id) { + /** + * 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) { + const { moduleId, type, name } = data; + return Exam.findByPk(id) + .then(hereExam => { + if (hereExam && hereExam.publishedAt === null) { + return hereExam.update({ + moduleId, + type, + name + }); + } + return Promise.reject("Not exists exam"); + }) + .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; } @@ -91,13 +131,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: ["createdAt", "updatedAt", "deletedAt"] }, + include: [{ + model: Type_question, + attributes: ["content"], + }, { + model: Answer, + attributes: { exclude: ["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)); } /** @@ -105,19 +157,15 @@ 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 Exam.findOne({ where: { moduleId: exam.moduleId, name: exam.name } }) + .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); - }); + .catch((err) => Promise.reject(err)); } } diff --git a/src/services/questionService.js b/src/services/questionService.js index d0954f65..f1ccfe28 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,27 +10,27 @@ 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; - else throw new Error("Parameter NOT required"); + else throw new Error("Parameter NOT required for the type of question"); } return true; }), @@ -39,17 +41,19 @@ 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 }) => { 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"); + 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; } }) ]; @@ -81,7 +85,7 @@ class QuestionService { }); return question; } catch (err) { - return new Error("An error has ocurred"); + return Promise.reject("An error has ocurred"); } } @@ -96,7 +100,42 @@ 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) { + 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) { @@ -110,15 +149,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; } @@ -145,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"); } @@ -172,7 +213,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 +231,25 @@ class QuestionService { } }); } + + /** + * 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..c6ac4d3d 100644 --- a/tests/rest/answer-controller.js +++ b/tests/rest/answer-controller.js @@ -1,42 +1,78 @@ 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); +const Exam = require("../../src/models/exam"); +const Question = require("../../src/models/question"); +const Type_question = require("../../src/models/type_question.js"); -describe("Answer tests", () => { - let num; - let res1; - let res2; +chai.use(chaiHttp); - before(() => { - num = faker.random.number(); - }) +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; +}; - after(async() => { +describe("Answer Tests", () => { + before(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(); + + 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: "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" }); + 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 { + /* + 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(); + await deleteRegister(data) + + let data1 = await Question.findAll(); + await deleteRegister(data1) + + let data2 = await Exam.findAll(); + await deleteRegister(data2) + let data4 = await Type_question.findAll(); + await deleteRegister(data4); + + } catch (err) { + return new Error("An error has ocurred"); + } }); - describe("Create a answer of question open", () => { + describe("Create an answer of Question Open", () => { - it("should return a answer created, if content is empty", (done) => { + 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 +81,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 +116,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 +132,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 +145,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 you add another answer to the same question", (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..40acc816 --- /dev/null +++ b/tests/rest/exams.js @@ -0,0 +1,126 @@ +const chai = require("chai"); +const chaiHttp = require("chai-http"); +const app = require("../../src/index"); + +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", () => { + + after(async() => { + try { + // await Exam.destroy({ force: true }); + + let data2 = await Exam.findAll(); + await deleteRegister(data2); + + } catch (err) { + console.log("Error: ", 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); + // 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 new file mode 100644 index 00000000..62db9643 --- /dev/null +++ b/tests/rest/question.js @@ -0,0 +1,308 @@ +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() => { + 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 Exam.create({ id: "1", moduleId: "1", name: "exam de question" }); + + } catch (err) { + return new Error("An error has ocurred"); + } + }); + + after(async() => { + try { + /* + await Question.destroy({ force: true }); + await Exam.destroy({ force: true }); + await Type_question.destroy({ force: true }); + */ + let data1 = await Question.findAll(); + await clearRegistry(data1); + + let data2 = await Exam.findAll(); + await clearRegistry(data2); + + let data4 = await Type_question.findAll(); + await clearRegistry(data4); + + } 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({ + "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