|
| 1 | +/** |
| 2 | + * Legacy Challenge Service |
| 3 | + * Interacts with InformixDB |
| 4 | + * Note: this is built to work for topgear challenges and iterative review phases |
| 5 | + */ |
| 6 | +const _ = require('lodash') |
| 7 | +const logger = require('../common/logger') |
| 8 | +const util = require('util') |
| 9 | +const helper = require('../common/helper') |
| 10 | +const IDGenerator = require('../common/idGenerator') |
| 11 | +const reviewIdGen = new IDGenerator('review_id_seq') |
| 12 | +const reviewItemIdGen = new IDGenerator('review_item_id_seq') |
| 13 | + |
| 14 | +const ITERATIVE_REVIEWER_RESOURCE_ROLE_ID = 21 |
| 15 | +const QUERY_GET_ITERATIVE_REVIEW_RESOURCE_FOR_CHALLENGE = `SELECT limit 1 resource_id as resourceid FROM resource WHERE project_id = %d AND resource_role_id = ${ITERATIVE_REVIEWER_RESOURCE_ROLE_ID}` |
| 16 | + |
| 17 | +const QUERY_CREATE_REVIEW = 'INSERT INTO review (review_id, resource_id, submission_id, project_phase_id, scorecard_id, committed, score, initial_score, create_user, create_date, modify_user, modify_date) values (?,?,?,?,?,?,?,?,?,CURRENT,?,CURRENT)' |
| 18 | + |
| 19 | +/** |
| 20 | +review_id is a new ID using idGenerator |
| 21 | +resource_id, as near as I can tell, should be the universal Id of the resource, not the challenge or project specific IDs used for roles and resources. |
| 22 | +submission_id, the most important item, which you should have. |
| 23 | +project_phase_id, try null, or any phase that overlaps in time with the challenge phase the reviews are submitted for. I can't find any logic or constraints for this field. |
| 24 | +scorecard_id, the second most important item, which you should have. |
| 25 | +committed, in the case of a TopGear batch review submission should be true. |
| 26 | +score and initial_score are usually aggregated by OR and AP, but you could aggregate them yourself, according to the scorecard weights. Try having AP do it for you. |
| 27 | +create_user should be some generic API user name that tells us it was a TopGear batch upload. |
| 28 | +create_date should be now (use CURRENT for Informix SQL if you want). |
| 29 | +modify_user and modify_date can be null (or just don't include those in the field list). |
| 30 | +The ? are just placeholders for your values. I believe Informix uses a single quote for strings. |
| 31 | + */ |
| 32 | + |
| 33 | +const QUERY_CREATE_REVIEW_ITEM = 'INSERT INTO review_item (review_item_id, review_id, scorecard_question_id, upload_id, answer, sort, create_user, create_date, modify_user, modify_date) values (?,?,?,?,?,?,?,CURRENT,?,CURRENT)' |
| 34 | + |
| 35 | +/* |
| 36 | +review_item_id, use your idGenerator ID. |
| 37 | +review_id, the review ID from the previous query. |
| 38 | +scorecard_question_id, the most important field, which you should have. |
| 39 | +upload_id, this is specific to the submission_id, although you could have multiple uploads and you will want the upload_id, which TopGear should have if someone answered a question about a submission, because the submission must have been downloaded from somewhere. |
| 40 | +answer, usually a number. |
| 41 | +sort, use a constant here if you wish. From what I can tell, this would be used to display certain comments at the top for review appeals. It may have a default sort from the scorecard definition, but it's probably not important since people won't be looking at individual reviews much, I'm guessing. |
| 42 | +Same as above for create_user, etc. |
| 43 | +*/ |
| 44 | + |
| 45 | +const QUERY_GET_SUBMISSION = 'SELECT FIRST 1 * FROM submission s INNER JOIN upload u on s.upload_id = u.upload_id WHERE u.project_id = %d AND upload_status_id = 1 AND submission_status_id = 1 ORDER BY u.CREATE_DATE ASC' |
| 46 | + |
| 47 | +const QUERY_GET_PROJECT_PHASE = 'select pc.parameter scorecard_id, pp.project_phase_id project_phase_id from project_phase pp inner join phase_criteria pc on pc.project_phase_id = pp.project_phase_id where pp.project_id = %d and pp.phase_type_id = 18 and phase_criteria_type_id = 1' |
| 48 | + |
| 49 | +/** |
| 50 | + * Prepare Informix statement |
| 51 | + * @param {Object} connection the Informix connection |
| 52 | + * @param {String} sql the sql |
| 53 | + * @return {Object} Informix statement |
| 54 | + */ |
| 55 | +async function prepare (connection, sql) { |
| 56 | + // logger.debug(`Preparing SQL ${sql}`) |
| 57 | + const stmt = await connection.prepareAsync(sql) |
| 58 | + return Promise.promisifyAll(stmt) |
| 59 | +} |
| 60 | + |
| 61 | +/** |
| 62 | + * Insert review in IFX |
| 63 | + * @param {Number} challengeLegacyId the legacy challenge ID |
| 64 | + * @param {Number} createdBy the scorecard ID |
| 65 | + * @param {Number} score the review score |
| 66 | + * @param {Array} responses the review responses |
| 67 | + * @param {Number} createdBy the creator user ID |
| 68 | + */ |
| 69 | +async function insertReview (challengeLegacyId, scorecardId, score, responses, createdBy) { |
| 70 | + const connection = await helper.getInformixConnection() |
| 71 | + let result = null |
| 72 | + let reviewId |
| 73 | + try { |
| 74 | + const resourceId = await getIterativeReviewerResourceId(connection, challengeLegacyId) |
| 75 | + if (!resourceId) throw new Error('Cannot find Iterative Reviewer') |
| 76 | + const submissionId = await getSubmissionId(connection, challengeLegacyId) |
| 77 | + if (!submissionId) throw new Error('Cannot find Submission') |
| 78 | + const projectPhaseId = await getProjectPhaseId(connection, challengeLegacyId) |
| 79 | + if (!projectPhaseId) throw new Error('Cannot find Project Phase Id') |
| 80 | + reviewId = await reviewIdGen.getNextId() |
| 81 | + await connection.beginTransactionAsync() |
| 82 | + const query = await prepare(connection, QUERY_CREATE_REVIEW) |
| 83 | + result = await query.executeAsync([reviewId, resourceId, submissionId, projectPhaseId, scorecardId, 1, score, score, createdBy, createdBy]) |
| 84 | + for (let i = 0; i < responses.length; i += 1) { |
| 85 | + await insertReviewItem(connection, reviewId, responses[i], i, createdBy) |
| 86 | + } |
| 87 | + await connection.commitTransactionAsync() |
| 88 | + } catch (e) { |
| 89 | + logger.error(`Error in 'insertReview' ${e}, rolling back transaction`) |
| 90 | + await connection.rollbackTransactionAsync() |
| 91 | + throw e |
| 92 | + } finally { |
| 93 | + logger.info(`Review ${challengeLegacyId} has been created`) |
| 94 | + await connection.closeAsync() |
| 95 | + } |
| 96 | + return result |
| 97 | +} |
| 98 | + |
| 99 | +/** |
| 100 | + * Insert review item in IFX |
| 101 | + * @param {Object} connection |
| 102 | + * @param {Number} reviewId the review ID |
| 103 | + * @param {Object} response the response |
| 104 | + * @param {Number} sort the sort |
| 105 | + * @param {Number} createdBy the creator user ID |
| 106 | + */ |
| 107 | +async function insertReviewItem (connection, reviewId, response, sort, createdBy) { |
| 108 | + let result = null |
| 109 | + const reviewItemId = await reviewItemIdGen.getNextId() |
| 110 | + await connection.beginTransactionAsync() |
| 111 | + const query = await prepare(connection, QUERY_CREATE_REVIEW_ITEM) |
| 112 | + result = await query.executeAsync([reviewItemId, reviewId, response.questionId, null, response.answer, sort, createdBy, createdBy]) |
| 113 | + return result |
| 114 | +} |
| 115 | + |
| 116 | +/** |
| 117 | + * Gets the iterative reviewer resource id |
| 118 | + * @param {Object} connection |
| 119 | + * @param {Number} challengeLegacyId |
| 120 | + */ |
| 121 | +async function getIterativeReviewerResourceId (connection, challengeLegacyId) { |
| 122 | + const result = await connection.queryAsync(util.format(QUERY_GET_ITERATIVE_REVIEW_RESOURCE_FOR_CHALLENGE, challengeLegacyId)) |
| 123 | + return _.get(result, '[0].resourceid', null) |
| 124 | +} |
| 125 | + |
| 126 | +/** |
| 127 | + * Gets the submission id |
| 128 | + * @param {Object} connection |
| 129 | + * @param {Number} challengeLegacyId |
| 130 | + */ |
| 131 | +async function getSubmissionId (connection, challengeLegacyId) { |
| 132 | + const result = await connection.queryAsync(util.format(QUERY_GET_SUBMISSION, challengeLegacyId)) |
| 133 | + return _.get(result, '[0].submission_id', null) |
| 134 | +} |
| 135 | + |
| 136 | +/** |
| 137 | + * Gets the submission id |
| 138 | + * @param {Object} connection |
| 139 | + * @param {Number} challengeLegacyId |
| 140 | + */ |
| 141 | +async function getProjectPhaseId (connection, challengeLegacyId) { |
| 142 | + const result = await connection.queryAsync(util.format(QUERY_GET_PROJECT_PHASE, challengeLegacyId)) |
| 143 | + return _.get(result, '[0].project_phase_id', null) |
| 144 | +} |
| 145 | + |
| 146 | +module.exports = { |
| 147 | + insertReview |
| 148 | +} |
0 commit comments