diff --git a/CHANGELOG.md b/CHANGELOG.md index a4a168b4dcf91e2fbe11ee264b4f69e949a74033..4134e78bc91275085d29f01c4d227988961ec726 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.2.5 - 02/06/2020 +## Changed +- Route to list forms now returns all the dates and answers of the forms #75 (Richard Heise) +- Added two extras steps on route waterfall using eachSeries. +- Tests weren't changed since the steps where tested by themselfs in other routes. + + ## 1.2.4 - 01/06/2020 ## Added - Created route to get modified dates of a form #76 (Richard Heise) diff --git a/package.json b/package.json index c25e795b5f08f1abd50c473590510a91cf37871a..d2fbbac0883245b366dee972b8d0275451b70529 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "form-creator-api", - "version": "1.2.4", + "version": "1.2.5", "description": "RESTful API used to manage and answer forms.", "main": "index.js", "scripts": { diff --git a/src/api/controllers/user.spec.ts b/src/api/controllers/user.spec.ts index b9d51024baf9f90bdca5d9514e940a3d663b0a8e..edfd30206a1a08a1208490f162ac9e481b9e01ae 100644 --- a/src/api/controllers/user.spec.ts +++ b/src/api/controllers/user.spec.ts @@ -24,11 +24,11 @@ import { expect } from "chai"; import * as server from "../../main"; import { testToken } from "./form.spec"; -describe ("API data controller", () => { - - it ("Should respond 500 when failing to sign up a hash-null user", (done) => { +describe("API data controller", () => { - request(server) + it("Should respond 500 when failing to sign up a hash-null user", (done) => { + + request(server) .post("/user/signUp") .send({ name: "Test_name" @@ -45,9 +45,9 @@ describe ("API data controller", () => { .end(done); }); - it ("Should respond 500 when failing sign up a name-null user", (done) => { + it("Should respond 500 when failing sign up a name-null user", (done) => { - request(server) + request(server) .post("/user/signUp") .send({ email: "test_email@test.com" @@ -60,15 +60,15 @@ describe ("API data controller", () => { expect(res.body.message).to.be.equal("Some error has ocurred. Check error property for details."); expect(res.body.error).to.be.equal("The dataType named 'name' was not found") }) - .end(done); + .end(done); }); - it ("Should respond 500 when failing sign up an email-null user", (done) => { + it("Should respond 500 when failing sign up an email-null user", (done) => { - request(server) + request(server) .post("/user/signUp") .send({ - name: "Test_name" + name: "Test_name" , hash: "Test_pw" }) .expect(500) @@ -78,16 +78,16 @@ describe ("API data controller", () => { expect(res.body.message).to.be.equal("Some error has ocurred. Check error property for details."); expect(res.body.error).to.be.equal("The dataType named 'email' was not found"); }) - .end(done); + .end(done); }); - - it ("Should respond 500 when failing sign up an user with an existing email in the DB", (done) => { - request(server) + it("Should respond 500 when failing sign up an user with an existing email in the DB", (done) => { + + request(server) .post("/user/signUp") .send({ name: "Test_name2" - , email: "test_email@test.com" + , email: "test_email@test.com" , hash: "Test_pw" }) .expect(500) @@ -97,9 +97,9 @@ describe ("API data controller", () => { expect(res.body.message).to.be.equal("Some error has ocurred. Check error property for details."); expect(res.body.error).to.be.equal("Email exists on the database."); }) - .end(done); + .end(done); }); - + it("Should respond 500 when failing to validate an user by wrong password", (done) => { request(server) @@ -176,12 +176,12 @@ describe ("API data controller", () => { }) .expect(200) - .expect((res: any) => { - expect(res.body).to.be.an("object"); - expect(res.body.message).to.be.an("string"); - expect(res.body.message).to.be.eql("Password changed with sucess."); - }) - .end(done); + .expect((res: any) => { + expect(res.body).to.be.an("object"); + expect(res.body.message).to.be.an("string"); + expect(res.body.message).to.be.eql("Password changed with sucess."); + }) + .end(done); }); it("Should respond 200 when listing forms from an user", (done) => { @@ -196,9 +196,9 @@ describe ("API data controller", () => { expect(i.id).to.be.eql(j++); } }) - .end(done); + .end(done); }); - + it("Should respond 200 when updating an user info", (done) => { request(server) @@ -214,7 +214,7 @@ describe ("API data controller", () => { expect(res.body.message).to.be.an("string"); expect(res.body.message).to.be.equal("Updated"); }) - .end(done); + .end(done); }); it("Should respond 500 when failing on updating an user info by email missing", (done) => { @@ -232,7 +232,7 @@ describe ("API data controller", () => { expect(res.body.message).to.be.equal("Invalid User. Check error property for details."); expect(res.body.error).to.be.equal("The dataType named 'email' was not found"); }) - .end(done); + .end(done); }); it("Should respond 500 when failing on updating an user info by email missing", (done) => { @@ -250,9 +250,9 @@ describe ("API data controller", () => { expect(res.body.message).to.be.equal("Invalid User. Check error property for details."); expect(res.body.error).to.be.equal("The dataType named 'name' was not found"); }) - .end(done); + .end(done); }); - + it("Should respond 200 when deleting an user from the database", (done) => { request(server) @@ -265,9 +265,9 @@ describe ("API data controller", () => { expect(res.body.message).to.be.an("string"); expect(res.body.message).to.be.equal("User data deleted."); }) - .end(done); + .end(done); }); - + it("Should respond 500 when failing to delete an user from the database", (done) => { request(server) @@ -275,15 +275,15 @@ describe ("API data controller", () => { .set("Authorization", "bearer " + testToken) .expect(500) - .expect((res: any) => { - expect(res.body).to.be.an("object"); - expect(res.body.message).to.be.an("string"); - expect(res.body.message).to.be.equal("Failed to delete user. Check error properties for details."); - expect(res.body.error).to.be.eql("Invalid ID, user doesn't exist."); - }) - .end(done); + .expect((res: any) => { + expect(res.body).to.be.an("object"); + expect(res.body.message).to.be.an("string"); + expect(res.body.message).to.be.equal("Failed to delete user. Check error properties for details."); + expect(res.body.error).to.be.eql("Invalid ID, user doesn't exist."); + }) + .end(done); }); - + it("Should respond 500 when failing to delete an user by incompatible ID", (done) => { request(server) @@ -296,25 +296,25 @@ describe ("API data controller", () => { expect(res.body.message).to.be.an("string"); expect(res.body.message).to.be.equal("Unauthorized action."); }) - .end(done); - }); + .end(done); + }); it("Should respond 500 when failing to change a password", (done) => { request(server) .put("/user/changePassword") - .set("Authorization", "bearer "+ testToken) + .set("Authorization", "bearer " + testToken) .send({ hash: "changed_pw_hashing" }) .expect(500) - .expect((res: any) => { - expect(res.body).to.be.an("object"); - expect(res.body.message).to.be.an("string"); - expect(res.body.message).to.be.eql("Some error has ocurred. Check error property for details.") - expect(res.body.error).to.be.eql("Bad amount of ids returned: found '0' should be 1"); - }) - .end(done); + .expect((res: any) => { + expect(res.body).to.be.an("object"); + expect(res.body.message).to.be.an("string"); + expect(res.body.message).to.be.eql("Some error has ocurred. Check error property for details.") + expect(res.body.error).to.be.eql("Bad amount of ids returned: found '0' should be 1"); + }) + .end(done); }); }); diff --git a/src/api/controllers/user.ts b/src/api/controllers/user.ts index b5322f806837c8c3bdf60487e45336a2002dfe52..e9e1778c1cf4e877ed3a11d5c66780774c308427 100644 --- a/src/api/controllers/user.ts +++ b/src/api/controllers/user.ts @@ -23,10 +23,11 @@ import { User } from "../../core/user"; import { Response, NextFunction } from "express"; import { Request } from "../apiTypes"; import { OptHandler } from "../../utils/optHandler"; -import { waterfall } from "async"; +import { eachSeries, map, waterfall } from "async"; import * as bcrypt from "bcrypt"; import * as jwt from "jsonwebtoken"; import { Form } from "../../core/form"; +import { FormAnswer, FormAnswerOptions } from "../../core/formAnswer"; export class UserCtrl { @@ -34,13 +35,13 @@ export class UserCtrl { let newUser: User; - waterfall ([ + waterfall([ (callback: (err: Error, user?: User) => void) => { bcrypt.hash(req.body.hash, 10, (err: Error, hashedPw: string) => { if (err) { callback(err); return; - } + } try { newUser = new User(OptHandler.User(req.body, hashedPw)); } catch (err) { @@ -53,7 +54,7 @@ export class UserCtrl { (user: User, callback: (err: Error) => void) => { req.db.user.write(user, (err: Error) => { if (err) { - callback(err); + callback(err); return; } else { res.json({ @@ -63,8 +64,8 @@ export class UserCtrl { return; } }); - } - + } + ], (error: Error) => { if (error) { res.status(500).json({ @@ -84,13 +85,13 @@ export class UserCtrl { if (id !== undefined) { callback(null, id); return; - } + } if (err) { callback(err); return; } - + callback(new Error("Auth Failed")); }); }, @@ -103,12 +104,12 @@ export class UserCtrl { callback(null, user); }); }, - (user: User, callback: (err: Error, user?: User) => void ) => { + (user: User, callback: (err: Error, user?: User) => void) => { bcrypt.compare(req.body.hash, user.hash, (err: Error, result?: boolean) => { if (err !== undefined) { callback(err); return; - } + } if (!result) { callback(new Error("Auth failed")); return; @@ -116,29 +117,29 @@ export class UserCtrl { callback(null, user); }); }, - (user: User, callback: (err: Error) => void ) => { + (user: User, callback: (err: Error) => void) => { jwt.sign( - { - email: user.email - , id: user.id - }, + { + email: user.email + , id: user.id + }, process.env.JWT_KEY - ,{ - expiresIn: "1h" - }, - (err: Error, encoded: string) => { - if (err) { - callback(err); - return; - } - res.json({ - message: "Authentication successful.", - token: encoded, - id: user.id - }); - callback(null); - }) - } + , { + expiresIn: "1h" + }, + (err: Error, encoded: string) => { + if (err) { + callback(err); + return; + } + res.json({ + message: "Authentication successful.", + token: encoded, + id: user.id + }); + callback(null); + }) + } ], (err: Error) => { if (err) { res.status(500).json({ @@ -150,7 +151,7 @@ export class UserCtrl { }); } - public static deleteData (req: Request, res: Response, next: NextFunction) { + public static deleteData(req: Request, res: Response, next: NextFunction) { if (Object(req.userData).id !== Number(req.params.id)) { res.status(500).json({ @@ -175,18 +176,18 @@ export class UserCtrl { }); } - public static changePassword (req: Request, res: Response, next: NextFunction) { + public static changePassword(req: Request, res: Response, next: NextFunction) { let newUser: User; - waterfall ([ + waterfall([ (callback: (err: Error, password?: string) => void) => { bcrypt.hash(req.body.hash, 10, (err: Error, hashedPw: string) => { if (err) { callback(err); return; - } - + } + callback(null, hashedPw); }); }, @@ -197,16 +198,16 @@ export class UserCtrl { callback(err); return; } - + newUser = new User(OptHandler.User(user, password)); - + callback(null, newUser); }); }, (user: User, callback: (err: Error) => void) => { req.db.user.update(user, Object(req.userData).id, (err: Error) => { if (err) { - callback(err); + callback(err); return; } else { res.json({ @@ -216,8 +217,8 @@ export class UserCtrl { return; } }); - } - + } + ], (error: Error) => { if (error) { res.status(500).json({ @@ -229,34 +230,87 @@ export class UserCtrl { }); } - public static listForms (req: Request, res: Response, next: NextFunction) { + public static listForms(req: Request, res: Response, next: NextFunction) { - req.db.form.list(req.params.id, (err: Error, forms?: Form[]) => { - if (err){ + waterfall([ + (callback: (err: Error, forms?: any[]) => void) => { + req.db.form.list(req.params.id, (err: Error, forms?: Form[]) => { + if (err) { + res.status(500).json({ + message: "Could not list forms. Some error has occurred. Check error property for details.", + error: err + }); + return; + } + + const mappedForms = forms.map(form => ({ + id: form.id + , title: form.title + , description: form.description + , answersNumber: 0 + , date: "" + })); + + callback(null, mappedForms); + }); + }, + (forms: any[], callback: (err: Error, result?: Object[]) => void) => { + eachSeries(forms, (form: any, innerCallback) => { + req.db.answer.readAll(form.id, (err: Error, resultAnswer?: FormAnswer[]) => { + if (err) { + innerCallback(err); + return; + } + let sum: number = 0; + for (const forms of resultAnswer) { + sum += Object.keys(forms.inputAnswers).length + } + + form.answersNumber = sum; + + innerCallback(null); + }); + }, (e) => { + callback(e, forms); + }); + }, + (forms: any[], callback: (err: Error, result?: Object[]) => void) => { + eachSeries(forms, (form: any, innerCallback) => { + req.db.form.readDate(form.id, (err: Error, dates?: any[]) => { + if (err) { + innerCallback(err); + return; + } + + if (dates.length) { + form.date = dates.sort().slice(-1)[0].update_date; + } + + innerCallback(null); + }); + }, (e) => { + callback(e, forms); + }); + }, + ], (error: Error, forms) => { + if (error) { res.status(500).json({ - message: "Could not list forms. Some error has occurred. Check error property for details.", - error: err + message: "Some error has ocurred. Check error property for details.", + error: error.message }); return; } - - const mappedForms = forms.map(form => ({ - id: form.id - , title: form.title - , description: form.description - })); - - res.json(mappedForms); - return; + res.json(forms); }); + } - public static update (req: Request, res: Response, next: NextFunction) { + public static update(req: Request, res: Response, next: NextFunction) { let newUser: User; try { newUser = new User(OptHandler.User(req.body)); - } catch(e) { + } catch (e) { res.status(500).json({ message: "Invalid User. Check error property for details." , error: e.message