From dec217f311f12d8d12952fd5cbfb9d196aab7de1 Mon Sep 17 00:00:00 2001 From: Gregory Rushton Date: Tue, 10 Oct 2023 09:52:53 -0400 Subject: [PATCH] [DUOS-2675][risk=no] Manually validate study name in dataset submissions (#2347) * validate uniqueness for study names --- .../data_access_governance.spec.js | 3 ++- src/components/forms/formValidation.js | 8 ++++++- src/libs/ajax.js | 10 ++++++++ src/pages/DataSubmissionForm.js | 24 +++++++++++++++---- 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/cypress/component/DataSubmission/data_access_governance.spec.js b/cypress/component/DataSubmission/data_access_governance.spec.js index 8b68348be..771ecdc20 100644 --- a/cypress/component/DataSubmission/data_access_governance.spec.js +++ b/cypress/component/DataSubmission/data_access_governance.spec.js @@ -1,6 +1,6 @@ /* eslint-disable no-undef */ import React from 'react'; -import { DAC, User, Institution, Schema } from '../../../src/libs/ajax'; +import { DAC, User, Institution, Schema, Study } from '../../../src/libs/ajax'; import DataSubmissionForm from '../../../src/pages/DataSubmissionForm'; import { mount } from 'cypress/react'; @@ -22,6 +22,7 @@ beforeEach(() => { cy.stub(User, 'getMe').returns(user); cy.stub(Institution, 'list').returns([{name: 'Test Institution'}]); cy.stub(Schema, 'datasetRegistrationV1').returns({}); + cy.stub(Study, 'getStudyNames').returns([]); }); describe('Data Access Governance', function () { diff --git a/src/components/forms/formValidation.js b/src/components/forms/formValidation.js index c4e689a8d..9b5e0e441 100644 --- a/src/components/forms/formValidation.js +++ b/src/components/forms/formValidation.js @@ -30,7 +30,13 @@ export const dateValidator = { msg: 'Please enter a date (YYYY-MM-DD), e.g. 2018-11-13', }; -const validators = [requiredValidator, urlValidator, emailValidator, dateValidator]; +export const uniqueValidator = { + id: 'unique', + isValid: (val, list) => !list.includes(val), + msg: 'Please enter a unique value that doesn\'t exist in the system' +}; + +const validators = [requiredValidator, urlValidator, emailValidator, dateValidator, uniqueValidator]; /** * Validates the form value diff --git a/src/libs/ajax.js b/src/libs/ajax.js index 0d1d4a92e..7ecf91f0e 100644 --- a/src/libs/ajax.js +++ b/src/libs/ajax.js @@ -384,6 +384,16 @@ export const DataSet = { }, }; +export const Study = { + + getStudyNames: async () => { + const url = `${await getApiUrl()}/api/dataset/studyNames`; + const res = await fetchOk(url, Config.authOpts()); + return await res.json(); + } + +}; + export const DatasetAssociation = { createDatasetAssociations: async (objectId, usersIdList) => { diff --git a/src/pages/DataSubmissionForm.js b/src/pages/DataSubmissionForm.js index 7f6b895a3..38c2c7f12 100644 --- a/src/pages/DataSubmissionForm.js +++ b/src/pages/DataSubmissionForm.js @@ -3,7 +3,7 @@ import { validateForm } from '../utils/JsonSchemaUtils'; import { cloneDeep, isNil } from 'lodash/fp'; import { useState, useEffect } from 'react'; -import { Institution, DataSet } from '../libs/ajax'; +import { Institution, DataSet, Study } from '../libs/ajax'; import { Notifications } from '../libs/utils'; import lockIcon from '../images/lock-icon.png'; @@ -14,9 +14,11 @@ import DataSubmissionStudyInformation from '../components/data_submission/ds_stu import NIHAdministrativeInformation from '../components/data_submission/NIHAdministrativeInformation'; import NIHDataManagement from '../components/data_submission/NIHDataManagement'; import NihAnvilUse from '../components/data_submission/NihAnvilUse'; -// schema validation is auto-generated from pre-compiled code - if the backend -// schama changes, then run `npm run genschemas` to regenerate this code +// Schema validation was previously auto-generated from pre-compiled code +// If any validation changes, it needs to be manually updated in both DataRegistrationV1Validation +// and JsonSchemaUtils import validateSchema from '../assets/schemas/DataRegistrationV1Validation'; +import {uniqueValidator} from '../components/forms/formValidation'; import { set } from 'lodash'; import UsgOmbText from '../components/UsgOmbText'; @@ -26,6 +28,7 @@ export const DataSubmissionForm = (props) => { } = props; const [institutions, setInstitutions] = useState([]); + const [studyNames, setStudyNames] = useState([]); const [failedInit, setFailedInit] = useState(false); const [allConsentGroupsSaved, setAllConsentGroupsSaved] = useState(false); @@ -37,9 +40,15 @@ export const DataSubmissionForm = (props) => { setInstitutions(institutions); }; + const getAllStudies = async() => { + const studyNames = await Study.getStudyNames(); + setStudyNames(studyNames); + }; + const init = async () => { try { - getAllInstitutions(); + await getAllInstitutions(); + await getAllStudies(); } catch (error) { setFailedInit(true); Notifications.showError({ @@ -100,6 +109,13 @@ export const DataSubmissionForm = (props) => { // check against json schema to see if there are uncaught validation issues let [valid, validation] = validateForm(validateSchema, registration); + if (!uniqueValidator.isValid(registration.studyName, studyNames)) { + validation.studyName = { + failed: ['unique'], + valid: false + }; + } + if (formData.alternativeDataSharingPlan === true) { if (isNil(formFiles.alternativeDataSharingPlanFile)) { validation.alternativeDataSharingPlanFile = {