diff --git a/src/app/controllers/encrypt-submissions.server.controller.js b/src/app/controllers/encrypt-submissions.server.controller.js index d364e21bfe..413867c43d 100644 --- a/src/app/controllers/encrypt-submissions.server.controller.js +++ b/src/app/controllers/encrypt-submissions.server.controller.js @@ -25,6 +25,8 @@ const { getProcessedResponses, } = require('../modules/submission/submission.service') +const HttpStatus = require('http-status-codes') + /** * Extracts relevant fields, injects questions, verifies visibility of field and validates answers * to produce req.body.parsedResponses @@ -223,15 +225,47 @@ exports.saveResponseToDb = function (req, res, next) { */ exports.getMetadata = function (req, res) { let pageSize = 10 - let { page } = req.query || {} + let { page, submissionId } = req.query || {} let numToSkip = parseInt(page - 1 || 0) * pageSize + let matchClause = { + form: req.form._id, + submissionType: 'encryptSubmission', + } + + if (submissionId) { + if (mongoose.Types.ObjectId.isValid(submissionId)) { + matchClause._id = mongoose.Types.ObjectId(submissionId) + // Reading from primary to avoid any contention issues with bulk queries on secondary servers + Submission.findOne(matchClause, { created: 1 }) + .read('primary') + .exec((err, result) => { + if (err) { + logger.error(getRequestIp(req), req.url, req.headers, err) + return res.status(HttpStatus.INTERNAL_SERVER_ERROR).send({ + message: errorHandler.getMongoErrorMessage(err), + }) + } + if (!result) { + return res.status(HttpStatus.OK).send({ metadata: [], count: 0 }) + } + let entry = { + number: 1, + refNo: result._id, + submissionTime: moment(result.created) + .tz('Asia/Singapore') + .format('Do MMM YYYY, h:mm:ss a'), + } + return res.status(HttpStatus.OK).send({ metadata: [entry], count: 1 }) + }) + } else { + return res.status(HttpStatus.OK).send({ metadata: [], count: 0 }) + } + } + Submission.aggregate([ { - $match: { - form: req.form._id, - submissionType: 'encryptSubmission', - }, + $match: matchClause, }, { $sort: { created: -1 }, diff --git a/src/public/modules/forms/admin/controllers/view-responses.client.controller.js b/src/public/modules/forms/admin/controllers/view-responses.client.controller.js index eceab09d5d..ab0d81f37c 100644 --- a/src/public/modules/forms/admin/controllers/view-responses.client.controller.js +++ b/src/public/modules/forms/admin/controllers/view-responses.client.controller.js @@ -40,7 +40,12 @@ function ViewResponsesController( vm.isEncryptResponseMode = vm.myform.responseMode === responseModeEnum.ENCRYPT vm.encryptionKey = null // will be set to an instance of EncryptionKey when form is unlocked successfully vm.csvDownloading = false // whether CSV export is in progress + vm.attachmentDownloadUrls = new Map() + vm.filterBySubmissionRefId = '' // whether to filter submissions by a specific ID + vm.filterBySubmissionRefIdTextbox = '' + vm.filterBySubmissionRefIdMatcher = /^[0-9A-Fa-f]{24}$/ + vm.filterBySubmissionShowFilterBox = false // Three views: // 1 - Unlock view for verifying form password @@ -318,12 +323,29 @@ function ViewResponsesController( } }) + vm.filterBySubmissionChanged = function () { + // We only reload the table if the text box has changed. This prevents excessive + // requests being sent by users clicking on the "Filter" button repeatedly. + if ( + vm.filterBySubmissionRefIdTextbox !== '' && + vm.filterBySubmissionRefId !== vm.filterBySubmissionRefIdTextbox + ) { + vm.filterBySubmissionRefId = vm.filterBySubmissionRefIdTextbox + vm.tableParams.reload() + } + } + + vm.filterBySubmissionReset = function () { + vm.filterBySubmissionShowFilterBox = false + vm.filterBySubmissionRefId = '' + vm.filterBySubmissionRefIdTextbox = '' + vm.tableParams.reload() + } + // Called by child directive unlockResponsesForm after key is verified to get responses - vm.loadResponses = function (formPassword) { - vm.formPassword = formPassword + vm.loadResponses = function () { vm.currentView = 2 vm.loading = true - vm.tableParams = new NgTableParams( { page: 1, // show first page @@ -334,6 +356,7 @@ function ViewResponsesController( let { page } = params.url() return Submissions.getMetadata({ formId: vm.myform._id, + filterBySubmissionRefId: vm.filterBySubmissionRefId, page, }) .then((data) => { diff --git a/src/public/modules/forms/admin/css/export-button.css b/src/public/modules/forms/admin/css/export-button.css index 602f23432c..942afd499f 100644 --- a/src/public/modules/forms/admin/css/export-button.css +++ b/src/public/modules/forms/admin/css/export-button.css @@ -7,7 +7,6 @@ display: flex; justify-content: center; align-items: center; - min-width: 164px; margin-left: auto; } diff --git a/src/public/modules/forms/admin/css/view-responses.css b/src/public/modules/forms/admin/css/view-responses.css index 662eebac1a..20836838fe 100644 --- a/src/public/modules/forms/admin/css/view-responses.css +++ b/src/public/modules/forms/admin/css/view-responses.css @@ -101,7 +101,8 @@ } #responses-tab .response-stats { - width: 100%; + white-space: nowrap; + min-width: 240px; } #responses-tab .datepicker-export-container { @@ -715,3 +716,22 @@ padding-left: 16px !important; border: solid 1px #ccc; } + +#filter-by-submission-reset-link { + padding-top: 13px; + padding-left: 13px; + white-space: nowrap; + cursor: pointer; +} + +#filter-by-submission-filter-link { + padding-top: 13px; + padding-left: 5px; + white-space: nowrap; + cursor: pointer; +} + +#filter-by-submission-filter-textbox-container { + display: flex; + min-width: 240px; +} diff --git a/src/public/modules/forms/admin/views/view-responses.client.view.html b/src/public/modules/forms/admin/views/view-responses.client.view.html index 5e9671e07c..f6f3081780 100644 --- a/src/public/modules/forms/admin/views/view-responses.client.view.html +++ b/src/public/modules/forms/admin/views/view-responses.client.view.html @@ -31,7 +31,9 @@
-
+
-
+
-
+
{{vm.responsesCount}} response(s) to date + + + + +
+
+ + + View All
-
+
+
+
+
-
+
+
+
+ +
No results found
+
+ Did you enter the right reference number? We can't seem to find + the response. +
+
+