diff --git a/app/serializers/extended_metadata_type_serializer.rb b/app/serializers/extended_metadata_type_serializer.rb index d749ec2c61..70a99543fa 100644 --- a/app/serializers/extended_metadata_type_serializer.rb +++ b/app/serializers/extended_metadata_type_serializer.rb @@ -18,6 +18,7 @@ def get_extended_metadata_attribute(attribute) "sample_attribute_type": get_sample_attribute_type(attribute), "required": attribute.required, "pos": attribute.pos, + "allow_cv_free_text": attribute.allow_cv_free_text, "sample_controlled_vocab_id": attribute.sample_controlled_vocab_id&.to_s, "linked_extended_metadata_type_id": attribute.linked_extended_metadata_type_id&.to_s } diff --git a/lib/seek/extended_metadata_type/extended_metadata_type_extractor.rb b/lib/seek/extended_metadata_type/extended_metadata_type_extractor.rb index 968e0e556e..df51611fe1 100644 --- a/lib/seek/extended_metadata_type/extended_metadata_type_extractor.rb +++ b/lib/seek/extended_metadata_type/extended_metadata_type_extractor.rb @@ -62,7 +62,8 @@ def self.create_extended_metadata_type_from_json(data) sample_attribute_type: sample_attribute_type, sample_controlled_vocab: sample_controlled_vocab, linked_extended_metadata_type: linked_extended_metadata_type, - required: attr['required'].present? ? attr['required'] : false, + required: attr.key?('required') ? attr['required'] : false, + allow_cv_free_text: attr.key?('allow_cv_free_text') ? attr['allow_cv_free_text'] : false, pid: attr['pid'].present? ? attr['pid'] : nil ) end @@ -70,4 +71,4 @@ def self.create_extended_metadata_type_from_json(data) end end end -end \ No newline at end of file +end diff --git a/lib/seek/extended_metadata_type/extended_metadata_type_schema.json b/lib/seek/extended_metadata_type/extended_metadata_type_schema.json index 2cd91251ce..4cc8b81521 100644 --- a/lib/seek/extended_metadata_type/extended_metadata_type_schema.json +++ b/lib/seek/extended_metadata_type/extended_metadata_type_schema.json @@ -31,6 +31,9 @@ "description": { "type": ["string", "null"] }, + "allow_cv_free_text": { + "type": "boolean" + }, "label": { "type": "string" }, @@ -64,6 +67,9 @@ "description": { "type": ["string", "null"] }, + "allow_cv_free_text": { + "type": "boolean" + }, "label": { "type": "string" }, @@ -86,4 +92,4 @@ }, "required": ["title", "supported_type", "enabled", "attributes"], "additionalProperties": false -} \ No newline at end of file +} diff --git a/public/api/definitions/_schemas.yml b/public/api/definitions/_schemas.yml index 34c7510acf..8cb0c16dad 100644 --- a/public/api/definitions/_schemas.yml +++ b/public/api/definitions/_schemas.yml @@ -4840,6 +4840,8 @@ extendedMetadataTypeExtendedMetadataAttributeResponse: type: boolean pos: $ref: "#/components/schemas/nullableInteger" + allow_cv_free_text: + type: boolean sample_controlled_vocab_id: $ref: "#/components/schemas/nullableNonEmptyString" linked_extended_metadata_type_id: diff --git a/test/factories/extended_metadata_types.rb b/test/factories/extended_metadata_types.rb index 8bb909c326..ae809d3f47 100644 --- a/test/factories/extended_metadata_types.rb +++ b/test/factories/extended_metadata_types.rb @@ -57,10 +57,10 @@ after(:build) do |a| a.extended_metadata_attributes << FactoryBot.create(:name_extended_metadata_attribute, title:'apple name') cv_list_attribute = ExtendedMetadataAttribute.new(title: 'apple list', sample_attribute_type: FactoryBot.create(:cv_list_attribute_type), - sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), description: "apple samples list", label: "apple samples list") + sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), description: "apple samples list", label: "apple samples list", allow_cv_free_text: true) a.extended_metadata_attributes << cv_list_attribute cv_attribute = ExtendedMetadataAttribute.new(title: 'apple controlled vocab', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), - sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), description: "apple samples controlled vocab", label: "apple samples controlled vocab") + sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), description: "apple samples controlled vocab", label: "apple samples controlled vocab", allow_cv_free_text: false) a.extended_metadata_attributes << cv_attribute end end diff --git a/test/fixtures/files/extended_metadata_type/valid_emt_with_cv_with_ontologies.json b/test/fixtures/files/extended_metadata_type/valid_emt_with_cv_with_ontologies.json index d63828a35f..7806f70c6b 100644 --- a/test/fixtures/files/extended_metadata_type/valid_emt_with_cv_with_ontologies.json +++ b/test/fixtures/files/extended_metadata_type/valid_emt_with_cv_with_ontologies.json @@ -8,6 +8,7 @@ "description": "Topics, used for annotating. Describes the domain, field of interest, of study, application, work, data, or technology. Initially seeded from the EDAM ontology.", "type": "Controlled Vocabulary", "required": true, + "allow_cv_free_text": true, "pos": 1, "pid": "http://edamontology.org/topic_0003", "ID": "CV_TOPICS_ID" diff --git a/test/functional/studies_controller_test.rb b/test/functional/studies_controller_test.rb index 0bd8b82f97..e978276c48 100644 --- a/test/functional/studies_controller_test.rb +++ b/test/functional/studies_controller_test.rb @@ -337,8 +337,8 @@ def test_should_show_investigation_tab test 'edit study with selected projects scope policy' do proj = User.current_user.person.projects.first study = FactoryBot.create(:study, contributor: User.current_user.person, - investigation: FactoryBot.create(:investigation, contributor: User.current_user.person), - policy: FactoryBot.create(:policy, + investigation: FactoryBot.create(:investigation, contributor: User.current_user.person), + policy: FactoryBot.create(:policy, access_type: Policy::NO_ACCESS, permissions: [FactoryBot.create(:permission, contributor: proj, access_type: Policy::EDITING)])) get :edit, params: { id: study.id } @@ -360,7 +360,7 @@ def test_should_show_investigation_tab person = User.current_user.person inv = FactoryBot.create :investigation, policy: FactoryBot.create(:public_policy), contributor:person study = FactoryBot.create :study, title: 'the study', policy: FactoryBot.create(:public_policy), - investigation: inv, contributor:person + investigation: inv, contributor:person get :new_object_based_on_existing_one, params: { id: study.id } assert_response :success assert_select '#study_title[value=?]', 'the study' @@ -698,10 +698,10 @@ def test_should_show_investigation_tab assert_difference('Study.count') do investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } - cm_attributes = {extended_metadata_attributes:{ extended_metadata_type_id: cmt.id, - data:{ - "name":'fred', - "age":22}}} + cm_attributes = {extended_metadata_attributes: { extended_metadata_type_id: cmt.id, + data: { + "name": 'fred', + "age": 22}}} post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } end @@ -718,8 +718,8 @@ def test_should_show_investigation_tab assert_no_difference('Study.count') do assert_no_difference('ExtendedMetadata.count') do put :update, params: { id: study.id, study: { title: "new title", - extended_metadata_attributes: { extended_metadata_type_id: cmt.id, id: cm.id, - data: { + extended_metadata_attributes: { extended_metadata_type_id: cmt.id, id: cm.id, + data: { "name": 'max', "age": 20 } } } @@ -743,10 +743,10 @@ def test_should_show_investigation_tab assert_no_difference('ExtendedMetadata.count') do investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } - cm_attributes = {extended_metadata_attributes:{ extended_metadata_type_id: cmt.id, - data:{ - "name":'fred', - "age":22}}} + cm_attributes = {extended_metadata_attributes: { extended_metadata_type_id: cmt.id, + data: { + "name": 'fred', + "age": 22}}} post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } end @@ -840,10 +840,10 @@ def test_should_show_investigation_tab assert_difference('Study.count') do investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } - cm_attributes = {extended_metadata_attributes:{extended_metadata_type_id: cmt.id, - data:{ - "full name":'Paul Jones', - "full address":'London, UK'}}} + cm_attributes = {extended_metadata_attributes: {extended_metadata_type_id: cmt.id, + data: { + "full name": 'Paul Jones', + "full address": 'London, UK'}}} put :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } end @@ -866,11 +866,11 @@ def test_should_show_investigation_tab assert_difference('Study.count') do investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } - cm_attributes = {extended_metadata_attributes:{extended_metadata_type_id: cmt.id, - data:{ - "full name":'full name', - "Full name":'Full name', - "full name":'full name'}}} + cm_attributes = {extended_metadata_attributes: {extended_metadata_type_id: cmt.id, + data: { + "full name": 'full name', + "Full name": 'Full name', + "full name": 'full name'}}} put :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } end @@ -894,12 +894,12 @@ def test_should_show_investigation_tab assert_difference('Study.count') do investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } - cm_attributes = {extended_metadata_attributes:{extended_metadata_type_id: cmt.id, - data:{ - "+name":'+name', - "-name":'-name', - "&name":'&name', - "name(name)":'name(name)' + cm_attributes = {extended_metadata_attributes: {extended_metadata_type_id: cmt.id, + data: { + "+name": '+name', + "-name": '-name', + "&name": '&name', + "name(name)": 'name(name)' }}} put :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } @@ -924,10 +924,10 @@ def test_should_show_investigation_tab assert_difference('Study.count') do investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } - cm_attributes = {extended_metadata_attributes:{extended_metadata_type_id: cmt.id, - data:{ - "apple name":"Newton's Apple", - "apple list":['Granny Smith','Bramley'], + cm_attributes = {extended_metadata_attributes: {extended_metadata_type_id: cmt.id, + data: { + "apple name": "Newton's Apple", + "apple list": ['Granny Smith','Bramley','random apple'], "apple controlled vocab": ['Granny Smith']}}} post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } @@ -940,12 +940,30 @@ def test_should_show_investigation_tab assert_equal cmt, cm.extended_metadata_type assert_equal "Newton's Apple",cm.get_attribute_value('apple name') assert_equal 'Granny Smith',cm.get_attribute_value('apple controlled vocab') - assert_equal ['Granny Smith','Bramley'],cm.get_attribute_value('apple list') + assert_equal ['Granny Smith','Bramley','random apple'],cm.get_attribute_value('apple list') get :show, params: { id: study } assert_response :success assert_select 'div.extended_metadata',text:/Granny Smith/, count:2 + + assert_no_difference('Study.count') do + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + study_attributes = { title: 'test', investigation_id: investigation.id } + cm_attributes = {extended_metadata_attributes: {extended_metadata_type_id: cmt.id, + data: { + "apple name": "Newton's Apple", + "apple list": ['Granny Smith','Bramley'], + "apple controlled vocab": ['random apple']}}} + + post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } + end + + + + assert study=assigns(:study) + refute study.valid? + end test 'should create and update study with linked extended metadata type' do @@ -960,10 +978,10 @@ def test_should_show_investigation_tab study_attributes = { title: 'Alice in Wonderland', investigation_id: investigation.id } cm_attributes = { extended_metadata_attributes: { extended_metadata_type_id: cmt.id, data: { - "role_email":"alice@email.com", - "role_phone":"0012345", + "role_email": "alice@email.com", + "role_phone": "0012345", "role_name": { - "first_name":"alice", + "first_name": "alice", "last_name": "liddell" } } @@ -993,9 +1011,9 @@ def test_should_show_investigation_tab put :update, params: { id: study.id, study: { title: "Alice Through the Looking Glass", extended_metadata_attributes: { extended_metadata_type_id: cmt.id, id:cm.id, data: { - "role_email":"rabbit@email.com", + "role_email": "rabbit@email.com", "role_name": { - "first_name":"rabbit" + "first_name": "rabbit" } } } @@ -1020,9 +1038,9 @@ def test_should_show_investigation_tab study_attributes = { title: 'Family', investigation_id: investigation.id } cm_attributes = { extended_metadata_attributes: { extended_metadata_type_id: cmt.id, data: { - "dad":{"first_name":"john", "last_name":"liddell"}, - "mom":{"first_name":"lily", "last_name":"liddell"}, - "child":{"0":{"first_name":"alice", "last_name":"liddell"}} + "dad": {"first_name":"john", "last_name":"liddell"}, + "mom": {"first_name":"lily", "last_name":"liddell"}, + "child": {"0":{"first_name":"alice", "last_name":"liddell"}} } } } @@ -1050,8 +1068,8 @@ def test_should_show_investigation_tab put :update, params: { id: study.id, study: { title: "Alice Through the Looking Glass", extended_metadata_attributes: { extended_metadata_type_id: cmt.id, id:cm.id, data: { - "dad":{"first_name":"tom", "last_name":"liddell"}, - "child":{"0":{"first_name":"rabbit", "last_name":"wonderland"},"1":{"first_name":"mad", "last_name":"hatter"}} + "dad": {"first_name":"tom", "last_name":"liddell"}, + "child": {"0":{"first_name":"rabbit", "last_name":"wonderland"},"1":{"first_name":"mad", "last_name":"hatter"}} } } } @@ -1113,8 +1131,8 @@ def test_should_show_investigation_tab study_attributes = { title: 'Alice in Wonderland', investigation_id: investigation.id } cm_attributes = { extended_metadata_attributes: { extended_metadata_type_id: cmt.id, data: { - "role_email":"alice@email.com", - "role_phone":"0012345", + "role_email": "alice@email.com", + "role_phone": "0012345", "role_name": {"first_name":"alice", "last_name": "liddell"}, "role_address": {"street":"wonder","city": "land" } } @@ -1145,9 +1163,9 @@ def test_should_show_investigation_tab put :update, params: { id: study.id, study: { title: "Alice Through the Looking Glass", extended_metadata_attributes: { extended_metadata_type_id: cmt.id, id:cm.id, data: { - "role_email":"rabbit@email.com", - "role_name":{ - "first_name":"rabbit" + "role_email": "rabbit@email.com", + "role_name": { + "first_name": "rabbit" } } } @@ -1178,38 +1196,38 @@ def test_should_show_investigation_tab cm_attributes = { extended_metadata_attributes: { extended_metadata_type_id: cmt.id, data: { - "study_title":"happy study", - "study_sites":{ - "0":{ - "study_site_name":"site1", - "study_site_location":"fairyland", - "participants":{ - "0":{ - "participant_name":{ - "first_name":"alice", - "last_name":"liddell" + "study_title": "happy study", + "study_sites": { + "0": { + "study_site_name": "site1", + "study_site_location": "fairyland", + "participants": { + "0": { + "participant_name": { + "first_name": "alice", + "last_name": "liddell" }, - "participant_age":"7" + "participant_age": "7" }, - "1":{ - "participant_name":{ - "first_name":"pippi", - "last_name":"langstrumpf" + "1": { + "participant_name": { + "first_name": "pippi", + "last_name": "langstrumpf" }, - "participant_age":"9" + "participant_age": "9" } } }, - "1":{ - "study_site_name":"site2", - "study_site_location":"space", - "participants":{ - "0":{ - "participant_name":{ - "first_name":"arthur", - "last_name":"Dent" + "1": { + "study_site_name": "site2", + "study_site_location": "space", + "participants": { + "0": { + "participant_name": { + "first_name": "arthur", + "last_name": "Dent" }, - "participant_age":"40" + "participant_age": "40" } } } @@ -1247,28 +1265,28 @@ def test_should_show_investigation_tab study: { title: 'Updated Study', extended_metadata_attributes: { - id:cm.id, + id: cm.id, extended_metadata_type_id: cmt.id, data: { - "study_title":"happy study new", - "study_sites":{ - "0":{ - "study_site_name":"site1", - "study_site_location":"better fairyland", - "participants":{ - "0":{ - "participant_name":{ - "first_name":"mad", - "last_name":"hatter" + "study_title": "happy study new", + "study_sites": { + "0": { + "study_site_name": "site1", + "study_site_location": "better fairyland", + "participants": { + "0": { + "participant_name": { + "first_name": "mad", + "last_name": "hatter" }, - "participant_age":"unknown" + "participant_age": "unknown" }, - "1":{ - "participant_name":{ - "first_name":"pippi", - "last_name":"langstrumpf" + "1": { + "participant_name": { + "first_name": "pippi", + "last_name": "langstrumpf" }, - "participant_age":"9" + "participant_age": "9" } } } @@ -1305,10 +1323,10 @@ def test_should_show_investigation_tab cm_attributes = { extended_metadata_attributes: { extended_metadata_type_id: cmt.id, data: { - "role_affiliation_name":"HITS", - "role_affiliation_identifiers":{ - "0":{"identifier":"01f7bcy98", "scheme":"ROR"}, - "1":{"identifier":"grid.424699.4", "scheme":"GRID"} + "role_affiliation_name": "HITS", + "role_affiliation_identifiers": { + "0": {"identifier":"01f7bcy98", "scheme":"ROR"}, + "1": {"identifier":"grid.424699.4", "scheme":"GRID"} } } } @@ -1347,10 +1365,10 @@ def test_should_show_investigation_tab cm_attributes = { extended_metadata_attributes: { extended_metadata_type_id: cmt.id, data: { - "role_affiliation_name":"HITS", - "role_affiliation_identifiers":{ - "0":{ "identifier":"01f7bcy98", "scheme":"ROR"}, - "1":{"identifier":"grid.424699.4", "scheme":"GRID"} + "role_affiliation_name": "HITS", + "role_affiliation_identifiers": { + "0": { "identifier":"01f7bcy98", "scheme":"ROR"}, + "1": {"identifier":"grid.424699.4", "scheme":"GRID"} } } } @@ -1387,7 +1405,7 @@ def test_should_show_investigation_tab study: { title: 'Updated Study', extended_metadata_attributes: { - id:cm.id, + id: cm.id, extended_metadata_type_id: cmt.id, data: { "role_affiliation_name": "University of Manchester", @@ -1424,7 +1442,7 @@ def test_should_show_investigation_tab study: { title: 'Updated Study', extended_metadata_attributes: { - id:cm.id, + id: cm.id, extended_metadata_type_id: cmt.id, data: { "role_affiliation_name": "University of Manchester", @@ -1467,7 +1485,7 @@ def test_should_show_investigation_tab study: { title: 'Updated Study', extended_metadata_attributes: { - id:cm.id, + id: cm.id, extended_metadata_type_id: cmt.id, data: { "role_affiliation_name": "University of Manchester", @@ -1516,10 +1534,10 @@ def test_should_show_investigation_tab cm_attributes = { extended_metadata_attributes: { extended_metadata_type_id: cmt.id, data: { - "role_affiliation_name":"HITS", - "role_affiliation_identifiers":{ - "0":{"identifier":"01f7bcy98", "scheme":"ROR"}, - "1":{"identifier":"grid.424699.4", "scheme":"GRID"} + "role_affiliation_name": "HITS", + "role_affiliation_identifiers": { + "0": {"identifier":"01f7bcy98", "scheme":"ROR"}, + "1": {"identifier":"grid.424699.4", "scheme":"GRID"} } } } @@ -1561,10 +1579,10 @@ def test_should_show_investigation_tab cm_attributes = { extended_metadata_attributes: { extended_metadata_type_id: cmt.id, data: { - "role_affiliation_name":"HITS", - "role_affiliation_identifiers":{ - "0":{"identifier":"", "scheme":"ROR"}, - "1":{"identifier":"grid.424699.4", "scheme":""} + "role_affiliation_name": "HITS", + "role_affiliation_identifiers": { + "0": {"identifier":"", "scheme":"ROR"}, + "1": {"identifier":"grid.424699.4", "scheme":""} } } } @@ -1609,10 +1627,10 @@ def test_should_show_investigation_tab cm_attributes = { extended_metadata_attributes: { extended_metadata_type_id: cmt.id, data: { - "role_affiliation_name":"HITS", - "role_affiliation_identifiers":{ - "0":{"identifier":"01f7bcy98", "scheme":"ROR"}, - "1":{"identifier":"grid.424699.4", "scheme":"GRID"} + "role_affiliation_name": "HITS", + "role_affiliation_identifiers": { + "0": {"identifier":"01f7bcy98", "scheme":"ROR"}, + "1": {"identifier":"grid.424699.4", "scheme":"GRID"} } } } @@ -1634,7 +1652,7 @@ def test_should_show_investigation_tab title: 'my new study title', investigation_id: nil, extended_metadata_attributes: { - id:cm.id, + id: cm.id, extended_metadata_type_id: cmt.id, data: { "role_affiliation_name": "University of Manchester", @@ -1701,10 +1719,10 @@ def test_should_show_investigation_tab cm_attributes = { extended_metadata_attributes: { extended_metadata_type_id: cmt.id, data: { - "role_affiliation_name":"HITS", - "role_affiliation_identifiers":{ - "0":{"identifier":"01f7bcy98", "scheme":"ROR"}, - "1":{"identifier":"grid.424699.4", "scheme":"GRID"} + "role_affiliation_name": "HITS", + "role_affiliation_identifiers": { + "0": {"identifier":"01f7bcy98", "scheme":"ROR"}, + "1": {"identifier":"grid.424699.4", "scheme":"GRID"} } } } @@ -1724,7 +1742,7 @@ def test_should_show_investigation_tab study: { title: 'my new study title', extended_metadata_attributes: { - id:cm.id, + id: cm.id, extended_metadata_type_id: cmt.id, data: { "role_affiliation_name": "University of Manchester", @@ -2050,7 +2068,7 @@ def test_should_show_investigation_tab study_sample_sample_type = FactoryBot.create :isa_sample_collection_sample_type, linked_sample_type: study_source_sample_type, contributor: person study = FactoryBot.create(:study, investigation: investigation , - policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission,contributor: person, access_type:Policy::EDITING)]), + policy: FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission,contributor: person, access_type:Policy::EDITING)]), sample_types: [study_source_sample_type, study_sample_sample_type], contributor: person) diff --git a/test/unit/extended_metadatas/emt_extractor_test.rb b/test/unit/extended_metadatas/emt_extractor_test.rb index 791b4867e6..35afc7cf9e 100644 --- a/test/unit/extended_metadatas/emt_extractor_test.rb +++ b/test/unit/extended_metadatas/emt_extractor_test.rb @@ -89,6 +89,7 @@ class EmtExtractorTest < ActiveSupport::TestCase assert_equal SampleAttributeType.find_by(title: 'Controlled Vocabulary'), topics_attr.sample_attribute_type assert topics_attr.required assert_equal 'http://edamontology.org/topic_0003', topics_attr.pid + assert topics_attr.allow_cv_free_text assert_equal topic_cv, topics_attr.sample_controlled_vocab assert_equal 4, topics_attr.sample_controlled_vocab.sample_controlled_vocab_terms.count @@ -153,4 +154,3 @@ def update_id(emt_file_name, person_emt, replaced) end -