Skip to content

Commit

Permalink
RESCOI-447: Saves state of disclosures so user can return to the same…
Browse files Browse the repository at this point in the history
… place
  • Loading branch information
iambrandonn committed Dec 7, 2015
1 parent 7ac9ca9 commit 1c77869
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 15 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
V1.0.3
* Progress through a disclosure is now tracked.
If a user gets halfway through and stops, when they return
they will be brought back to where they were. The data has always been
saved. This will simply return them to that place in the process.

V1.0.2

* Updated documentation
Expand Down
3 changes: 3 additions & 0 deletions COIConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,8 @@ export let COIConstants = {
INFO: 0,
WARN: 1,
ERROR: 2
},
STATE_TYPE: {
ANNUAL_DISCLOSURE_STATE: 'annual_disclosure_state'
}
};
76 changes: 63 additions & 13 deletions client/scripts/stores/DisclosureStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,25 +171,70 @@ class _DisclosureStore extends AutoBindingStore {
this.refreshDisclosureSummaries();
}

loadDisclosureState(disclosureId) {
return new Promise((resolve, reject) => {
createRequest()
.get(`/api/coi/disclosures/${disclosureId}/state`)
.end(processResponse((err, state) => {
if (err) {
reject();
}

if (state.body) {
this.applicationState.currentDisclosureState.step = state.body.step;
this.applicationState.currentDisclosureState.question = state.body.question;
}

resolve();
}));
});
}

updateDisclosureState(disclosureId) {
createRequest()
.post(`/api/coi/disclosures/${disclosureId}/state`)
.send({
step: this.applicationState.currentDisclosureState.step,
question: this.applicationState.currentDisclosureState.question
})
.type('application/json')
.end();
}

loadArchivedConfig(configId) {
return new Promise((resolve, reject) => {
createRequest()
.get(`/api/coi/archived-config/${configId}`)
.end(processResponse((err, config) => {
if (err) {
reject();
}

resolve(config);
}));
});
}

loadDisclosureData(disclosureType) {
if (disclosureType === COIConstants.DISCLOSURE_TYPE.ANNUAL) {
createRequest()
.get('/api/coi/disclosures/annual')
.end(processResponse((err, disclosure) => {
if (!err) {
this.applicationState.currentDisclosureState.disclosure = disclosure.body;
this.entities = disclosure.body.entities;
this.declarations = disclosure.body.declarations;
this.files = disclosure.body.files;
createRequest()
.get(`/api/coi/archived-config/${disclosure.body.configId}`)
.end(processResponse((error, config) => {
if (!error) {
window.config = config.body;
ConfigActions.loadConfig(disclosure.body.configId);
this.emitChange();
}
}));
Promise.all([
this.loadDisclosureState(disclosure.body.id),
this.loadArchivedConfig(disclosure.body.configId)
])
.then(([, config]) => {
this.applicationState.currentDisclosureState.disclosure = disclosure.body;
this.entities = disclosure.body.entities;
this.declarations = disclosure.body.declarations;
this.files = disclosure.body.files;

window.config = config.body;
ConfigActions.loadConfig(disclosure.body.configId);
this.emitChange();
});
}
}));
}
Expand Down Expand Up @@ -307,6 +352,8 @@ class _DisclosureStore extends AutoBindingStore {
else {
this.applicationState.currentDisclosureState.question++;
}

this.updateDisclosureState(this.applicationState.currentDisclosureState.disclosure.id);
}

previousQuestion() {
Expand Down Expand Up @@ -341,6 +388,8 @@ class _DisclosureStore extends AutoBindingStore {
}
break;
}

this.updateDisclosureState(this.applicationState.currentDisclosureState.disclosure.id);
}

setCurrentQuestion(newQuestionId) {
Expand Down Expand Up @@ -437,6 +486,7 @@ class _DisclosureStore extends AutoBindingStore {
this.applicationState.currentDisclosureState.visitedSteps[COIConstants.DISCLOSURE_STEP.CERTIFY] = true;
break;
}
this.updateDisclosureState(this.applicationState.currentDisclosureState.disclosure.id);
}

newEntityInitiated() {
Expand Down
4 changes: 2 additions & 2 deletions db/migration/migrations/1.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>
*/

exports.up = function(knex, Promise) { //eslint-disable-line no-unused-vars
exports.up = function(knex) {
return knex.schema.createTable('disclosure_type', function(table) {
table.integer('type_cd').notNullable().primary();
table.string('description', 50).notNullable();
Expand Down Expand Up @@ -245,5 +245,5 @@ exports.up = function(knex, Promise) { //eslint-disable-line no-unused-vars
});
};

exports.down = function(knex, Promise) { //eslint-disable-line no-unused-vars
exports.down = function() {
};
31 changes: 31 additions & 0 deletions db/migration/migrations/2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
The Conflict of Interest (COI) module of Kuali Research
Copyright © 2015 Kuali, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/

exports.up = function(knex) {
return knex.schema.createTable('state', function(table) {
table.increments('id').notNullable();
table.string('key', 40).notNullable();
table.string('user_id', 40).notNullable();
table.text('state');
table.unique(['key', 'user_id']);
table.engine('InnoDB');
});
};

exports.down = function() {
};
31 changes: 31 additions & 0 deletions server/controllers/DisclosureController.js
Original file line number Diff line number Diff line change
Expand Up @@ -419,4 +419,35 @@ export let init = app => {
res.status(400).end();
}
});

/**
@Role: user
Can only retrieve state of their disclosure
*/
app.get('/api/coi/disclosures/:id/state', (req, res, next) => {
DisclosureDB.getCurrentState(req.dbInfo, req.userInfo, req.params.id)
.then(result => {
res.send(result);
})
.catch(err => {
Log.error(err);
next(err);
});
});

/**
@Role: user
Can only save the state of their disclosure
*/
app.post('/api/coi/disclosures/:id/state', (req, res, next) => {
res.status(202).end();

DisclosureDB.saveCurrentState(req.dbInfo, req.userInfo, req.params.id, req.body)
.then(() => {
})
.catch(err => {
Log.error(err);
next(err);
});
});
};
56 changes: 56 additions & 0 deletions server/db/DisclosureDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -984,3 +984,59 @@ export let deleteAnswers = (dbInfo, userInfo, disclosureId, answersToDelete) =>
});
});
};

export let getCurrentState = (dbInfo, userInfo, disclosureId) => {
return isDisclosureUsers(dbInfo, disclosureId, userInfo.schoolId)
.then(isSubmitter => {
if (!isSubmitter) {
throw Error(`Attempt by user id ${userInfo.schoolId} to retrieve state of disclosure ${disclosureId} which isnt theirs`);
}

let knex = getKnex(dbInfo);
return knex
.select('state')
.from('state')
.where({
key: COIConstants.STATE_TYPE.ANNUAL_DISCLOSURE_STATE,
user_id: userInfo.schoolId
})
.then(stateFound => {
if (stateFound.length === 0) {
return '';
}
return JSON.parse(stateFound[0].state);
});
});
};

export let saveCurrentState = (dbInfo, userInfo, disclosureId, state) => {
return getCurrentState(dbInfo, userInfo, disclosureId)
.then(currentState => {
let knex = getKnex(dbInfo);

if (currentState !== '') {
return knex('state')
.update({
state: JSON.stringify(state)
})
.where({
key: COIConstants.STATE_TYPE.ANNUAL_DISCLOSURE_STATE,
user_id: userInfo.schoolId
}).then(() => {
return;
});
}
else {
return knex('state')
.insert({
key: COIConstants.STATE_TYPE.ANNUAL_DISCLOSURE_STATE,
user_id: userInfo.schoolId,
state: JSON.stringify(state)
}, 'id').then(() => {
return;
});
}
});
};


0 comments on commit 1c77869

Please sign in to comment.