diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f8e3f36fbb2a290f40f481524080e0ae040871f..a4a168b4dcf91e2fbe11ee264b4f69e949a74033 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ 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.4 - 01/06/2020 +## Added +- Created route to get modified dates of a form #76 (Richard Heise) +- Created methods to communicate with the DB + + ## 1.2.3 - 29/04/2020 ## Changed - Api to create a subform input without needing input ID from body #73 (Richard Heise) diff --git a/package.json b/package.json index 2029fc4a52bd07d6fba45e43a2bcf6b37b232ef3..c25e795b5f08f1abd50c473590510a91cf37871a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "form-creator-api", - "version": "1.2.3", + "version": "1.2.4", "description": "RESTful API used to manage and answer forms.", "main": "index.js", "scripts": { diff --git a/src/api/controllers/form.spec.ts b/src/api/controllers/form.spec.ts index 71bb21869573eee882df01ce9a3d580184c0d148..55ba967a1c36b8b800e9566386727b03329ad55e 100644 --- a/src/api/controllers/form.spec.ts +++ b/src/api/controllers/form.spec.ts @@ -37,7 +37,7 @@ import { Fixture } from "../../../test/fixture"; import { formScenario } from "../../../test/scenario"; before(function (done): void { - const fix: Fixture = new Fixture (); + const fix: Fixture = new Fixture(); waterfall([ (callback: (err: Error) => void) => { @@ -51,13 +51,13 @@ before(function (done): void { } ], (err) => { done(err); - }); + }); }); export let testToken: string; describe("Initial test User", () => { - it ("Should respond 200 when signing up a valid user", (done) => { + it("Should respond 200 when signing up a valid user", (done) => { request(server) .post("/user/signUp") .send({ @@ -73,7 +73,7 @@ describe("Initial test User", () => { }) .end(done); }); - + it("Should respond 200 when validating an user signIn", (done) => { request(server) .post("/user/signIn") @@ -88,12 +88,12 @@ describe("Initial test User", () => { expect(res.body.message).to.be.equal("Authentication successful."); testToken = res.body.token; }) - .end(done); + .end(done); }); }) -describe("API data controller - form", () => { +describe("API data controller - form", () => { it("should respond 200 when getting valid form", (done) => { request(server) @@ -103,7 +103,7 @@ describe("API data controller - form", () => { expect(res.body).to.be.an("object"); const form: Form = new Form(OptHandler.form(res.body)); - TestHandler.testForm(form, new Form( OptHandler.form(formScenario.validForm))); + TestHandler.testForm(form, new Form(OptHandler.form(formScenario.validForm))); }) .end(done); @@ -157,7 +157,7 @@ describe("API data controller - form", () => { }) .end(done); }); - + it("should respond 200 when putting valid form update swap inputs", (done) => { request(server) .put("/form/1") @@ -187,7 +187,7 @@ describe("API data controller - form", () => { .put("/form/3") .set("Authorization", "bearer " + testToken) .send(formScenario.formToRemoveInputs) - + .expect(200) .expect((res: any) => { expect(res.body.message).to.be.equal(formScenario.msg); @@ -200,7 +200,7 @@ describe("API data controller - form", () => { .put("/form/3") .set("Authorization", "bearer " + testToken) .send(formScenario.formToReenableInputs) - + .expect(200) .expect((res: any) => { expect(res.body.message).to.be.equal(formScenario.msg); @@ -214,7 +214,7 @@ describe("API data controller - form", () => { .put("/form/4") .set("Authorization", "bearer " + testToken) .send(formScenario.changeTitle) - + .expect(200) .expect((res: any) => { expect(res.body.message).to.be.equal(formScenario.msg); @@ -228,7 +228,7 @@ describe("API data controller - form", () => { .put("/form/4") .set("Authorization", "bearer " + testToken) .send(formScenario.undo) - + .expect(200) .expect((res: any) => { expect(res.body.message).to.be.equal(formScenario.msg); @@ -278,4 +278,27 @@ describe("API data controller - form", () => { }) .end(done); }); + + it("Should get all modified dates from a form", (done) => { + request(server) + .get("/formDate/1") + .expect(200) + .expect((res: any) => { + expect(res.body).to.be.an("array"); + expect(res.body.length).to.be.equal(1); + expect(res.body[0]).to.be.an("object"); + }) + .end(done); + }); + + it("Should get an empty array of modified dates from a form", (done) => { + request(server) + .get("/formDate/500") + .expect(200) + .expect((res: any) => { + expect(res.body).to.be.an("array"); + expect(res.body.length).to.be.equal(0); + }) + .end(done); + }); }); diff --git a/src/api/controllers/form.ts b/src/api/controllers/form.ts index 55a163da9eeffae5aa47f62d70ab0747debf1c69..2e677a1e619912c54e0737cf1c757216c7068672 100644 --- a/src/api/controllers/form.ts +++ b/src/api/controllers/form.ts @@ -22,7 +22,7 @@ import { waterfall } from "async"; import { OptHandler } from "../../utils/optHandler"; import { DiffHandler } from "../../utils/diffHandler"; -import { Form, FormOptions} from "../../core/form"; +import { Form, FormOptions } from "../../core/form"; import { FormUpdate, FormUpdateOptions } from "../../core/formUpdate"; import { Response, NextFunction } from "express"; import { Request } from "../apiTypes"; @@ -33,9 +33,9 @@ export class FormCtrl { public static read(req: Request, res: Response, next: NextFunction) { req.db.form.read(req.params.id, (err: Error, form?: Form) => { - if (err){ + if (err) { res.status(500).json({ - message: "Form with id: '" + req.params.id + "' not found. Some error has occurred. Check error property for details.", + message: "Form with id: '" + req.params.id + "' not found. Some error has occurred. Check error property for details.", error: err }); return; @@ -58,7 +58,7 @@ export class FormCtrl { }); return; } - waterfall ([ + waterfall([ (callback: (err: Error, result?: FormUpdate) => void) => { req.db.form.write(form, (err: Error, formResult: Form) => { if (err) { @@ -71,7 +71,7 @@ export class FormCtrl { , description: formResult.description , inputs: [] }; - const formUpdate: FormUpdate = DiffHandler.diff(formResult, new Form (formOpts)); + const formUpdate: FormUpdate = DiffHandler.diff(formResult, new Form(formOpts)); callback(null, formUpdate); }); @@ -121,7 +121,7 @@ export class FormCtrl { let newForm: Form; try { newForm = new Form(OptHandler.form(req.body)); - } catch(e) { + } catch (e) { res.status(500).json({ message: "Invalid Form. Check error property for details." , error: e.message @@ -135,7 +135,7 @@ export class FormCtrl { callback(err); return; } - + const e: Error = new Error("User dont own this form."); callback((forms.some((obj) => obj.id === Number(req.params.id))) ? null : e); }); @@ -198,4 +198,20 @@ export class FormCtrl { } }); } + + public static getDate(req: Request, res: Response, next: NextFunction) { + + req.db.form.readDate(req.params.id, (err: Error, dates?: Date[]) => { + if (err) { + res.status(500).json({ + message: "Some error has occurred. Check error property for details.", + error: err + }); + return; + } + + res.json(dates); + return; + }); + } } diff --git a/src/main.ts b/src/main.ts index bb6e5e6919407c20950c4f9a15ca1d19517f66ea..46dbd0b219b56cfe39365fa4f9bc6f35718bc7cf 100755 --- a/src/main.ts +++ b/src/main.ts @@ -56,6 +56,7 @@ app.use(express.json()); app.get("/form/:id", FormCtrl.read); app.put("/form/:id", tokenValidation(), FormCtrl.update); app.post("/form", tokenValidation(), FormCtrl.write); +app.get("/formDate/:id", FormCtrl.getDate); app.get("/answerNumber/:id", FormCtrl.answerNumber); app.post("/answer/:id", AnswerCtrl.write); app.get("/answer/:id", tokenValidation(), AnswerCtrl.read); diff --git a/src/utils/formQueryBuilder.ts b/src/utils/formQueryBuilder.ts index 7bf7f7416c9a0e15d564864b532f280b2aa8a0bb..dadaa3b278aabba303eda2a8a5d6c206797938d9 100644 --- a/src/utils/formQueryBuilder.ts +++ b/src/utils/formQueryBuilder.ts @@ -27,7 +27,7 @@ import { Input, InputOptions, Sugestion, Validation } from "../core/input"; import { InputUpdate, InputUpdateOptions } from "../core/inputUpdate"; import { SubForm } from "../core/subForm"; import { EnumHandler, InputType, UpdateType, ValidationType } from "./enumHandler"; -import { ErrorHandler} from "./errorHandler"; +import { ErrorHandler } from "./errorHandler"; import { OptHandler } from "./optHandler"; import { QueryBuilder, QueryOptions } from "./queryBuilder"; import { Sorter } from "./sorter"; @@ -60,7 +60,7 @@ export class FormQueryBuilder extends QueryBuilder { */ public list(userId: number, cb: (err: Error, forms?: Form[]) => void) { waterfall([ - (callback: (err: Error, result?: QueryResult) => void) => { + (callback: (err: Error, result?: QueryResult) => void) => { this.begin((error: Error, results?: QueryResult) => { callback(error); }); @@ -130,6 +130,65 @@ export class FormQueryBuilder extends QueryBuilder { }); } + /** + * Asynchronously lists all dates from a form from an user. + * @param formId - From ID that owns the modified dates. + * @param cb - Callback function which contains information about method's execution. + * @param cb.err - Error information when the method fails. + */ + public readDate(formId: number, cb: (err: Error, dates?: Date[]) => void) { + waterfall([ + (callback: (err: Error, result?: QueryResult) => void) => { + this.begin((error: Error, results?: QueryResult) => { + callback(error); + }); + }, + (callback: (err: Error, result?: Date[]) => void) => { + this.executeReadDate(formId, (error: Error, results?: Date[]) => { + callback(error, results); + }); + }, + (dates: Date[], callback: (err: Error, result?: Date[]) => void) => { + this.commit((error: Error, results?: QueryResult) => { + callback(error, dates); + }); + } + ], (err, dates?: Date[]) => { + if (err) { + this.rollback((error: Error, results?: QueryResult) => { + cb(err); + }); + return; + } + cb(null, dates); + return; + }); + } + + /** + * Asynchronously read a date from a modified form without transactions. + * @param id - Form identifier to be founded. + * @param cb - Callback function which contains the data read. + * @param cb.err - Error information when the method fails. + * @param cb.form - Date array or null if there's no date not exists. + */ + private executeReadDate(id: number, cb: (err: Error, dates?: Date[]) => void) { + const queryString: string = "SELECT update_date FROM form_update WHERE id_form=$1;"; + const query: QueryOptions = { + query: queryString + , parameters: [id] + }; + + this.executeQuery(query, (err: Error, result?: QueryResult) => { + if (err) { + cb(err); + return; + } + cb(null, result.rows); + }); + + } + /** * Asynchronously read a form from database. * @param id - Form identifier to be founded. @@ -140,7 +199,7 @@ export class FormQueryBuilder extends QueryBuilder { public read(id: number, cb: (err: Error, form?: Form) => void) { waterfall([ - (callback: (err: Error, result?: QueryResult) => void) => { + (callback: (err: Error, result?: QueryResult) => void) => { this.begin((error: Error, results?: QueryResult) => { callback(error); }); @@ -186,7 +245,7 @@ export class FormQueryBuilder extends QueryBuilder { return; } - const formTmp: Form = new Form ({ + const formTmp: Form = new Form({ id: result.rows[0]["id"] , title: result.rows[0]["title"] , description: result.rows[0]["description"] @@ -275,7 +334,7 @@ export class FormQueryBuilder extends QueryBuilder { let j: number = 0; let k: number = 0; while ((j < inputArrayTmp.length) && (k < validationArray.length)) { - if (inputArrayTmp[j].id === validationArray[k].inputId){ + if (inputArrayTmp[j].id === validationArray[k].inputId) { inputArrayTmp[j].validation.push(validationArray[k].validation); k++; } else { @@ -298,7 +357,7 @@ export class FormQueryBuilder extends QueryBuilder { let k: number = 0; while ((i < inputs.length) && (k < result.rows.length)) { if (inputs[i].id === result.rows[k]["id_input"]) { - inputs[i].sugestions.push({value: result.rows[k]["value"], placement: result.rows[k]["placement"]}); + inputs[i].sugestions.push({ value: result.rows[k]["value"], placement: result.rows[k]["placement"] }); k++; } else { i++; @@ -572,7 +631,7 @@ export class FormQueryBuilder extends QueryBuilder { }, (e) => { callback(e, formId); }); - } + } ], (err, id?: number) => { if (err) { cb(err); @@ -655,7 +714,7 @@ export class FormQueryBuilder extends QueryBuilder { const queryString: string = "SELECT id FROM form where id=$1;"; const query: QueryOptions = { query: queryString - , parameters: [ id ] + , parameters: [id] }; this.executeQuery(query, (error: Error, result?: QueryResult) => { @@ -877,7 +936,7 @@ export class FormQueryBuilder extends QueryBuilder { */ public update(formUpdate: FormUpdate, cb: (err: Error) => void) { waterfall([ - (callback: (err: Error, result?: QueryResult) => void) => { + (callback: (err: Error, result?: QueryResult) => void) => { this.begin((error: Error, results?: QueryResult) => { callback(error); }); @@ -1114,7 +1173,7 @@ export class FormQueryBuilder extends QueryBuilder { break; } default: { - callback(new Error ("Operation " + inputUpdate.inputOperation + " not recognized")); + callback(new Error("Operation " + inputUpdate.inputOperation + " not recognized")); break; } } @@ -1168,7 +1227,7 @@ export class FormQueryBuilder extends QueryBuilder { }; this.executeQuery(query, (err: Error, result?: QueryResult) => { cb(err); - }); + }); } /**