diff --git a/Gemfile b/Gemfile index 3ee9804..dfc239e 100644 --- a/Gemfile +++ b/Gemfile @@ -192,7 +192,7 @@ gem 'activerecord-session_store' # JSON Schema validation -gem 'json_schemer' +gem 'json_schemer', '0.2.11' # JsonPath is a way of addressing elements within a JSON object. Similar to xpath of yore, JsonPath lets you traverse a json object and manipulate or access it. gem "jsonpath" diff --git a/Gemfile.lock b/Gemfile.lock index 74c4de1..7074a85 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -118,7 +118,7 @@ dragonfly-s3_data_store (1.3.0) dragonfly (~> 1.0) fog-aws - ecma-re-validator (0.2.0) + ecma-re-validator (0.2.1) regexp_parser (~> 1.2) erubi (1.9.0) erubis (2.7.0) @@ -188,7 +188,7 @@ guard (~> 2.1) guard-compat (~> 1.1) rspec (>= 2.99.0, < 4.0) - hana (1.3.5) + hana (1.3.6) hashdiff (1.0.0) hashie (3.6.0) highline (2.0.3) @@ -207,7 +207,7 @@ activesupport (>= 3.0.0) multi_json (>= 1.2) json (2.3.0) - json_schemer (0.2.10) + json_schemer (0.2.11) ecma-re-validator (~> 0.2) hana (~> 1.3) regexp_parser (~> 1.5) @@ -526,7 +526,7 @@ htmltoword (= 1.1.0) httparty jbuilder (~> 2.6.0) - json_schemer + json_schemer (= 0.2.11) jsonpath kaminari ledermann-rails-settings diff --git a/app/assets/stylesheets/dmpopidor.scss b/app/assets/stylesheets/dmpopidor.scss index 6e2282e..d50bd1c 100644 --- a/app/assets/stylesheets/dmpopidor.scss +++ b/app/assets/stylesheets/dmpopidor.scss @@ -12,6 +12,7 @@ $light-rust: #faefed; $yellow: #FFCC00; $light-yellow: #fff9e5; +$green: #2CAD5D; body { display: flex; @@ -1013,10 +1014,24 @@ display: flex; align-items: center; padding-top: 5px; - + justify-content: space-between; input { flex: 9; } + span { + text-align: center; + margin-left: 5px; + &.invalid { + color: $rust; + } + &.valid { + color: $green; + } + &.explanation { + color: $blue; + cursor: pointer; + } + } } fieldset.answer-fieldset { width: 100%; diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index d03fad6..07d5c90 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -4,7 +4,6 @@ class AnswersController < ApplicationController prepend Dmpopidor::Controllers::Answers - include DynamicFormHelper respond_to :html # POST /answers/create_or_update diff --git a/app/controllers/madmp_fragments_controller.rb b/app/controllers/madmp_fragments_controller.rb index 493ea78..9f75614 100644 --- a/app/controllers/madmp_fragments_controller.rb +++ b/app/controllers/madmp_fragments_controller.rb @@ -3,44 +3,83 @@ class MadmpFragmentsController < ApplicationController after_action :verify_authorized + include DynamicFormHelper def create_or_update p_params = permitted_params() schema = MadmpSchema.find(p_params[:schema_id]) classname = schema.classname - data = schema_params(schema) + data = data_reformater(schema.schema, schema_params(schema)) + @fragment = nil - # rubocop:disable BlockLength - MadmpFragment.transaction do - if p_params[:id].empty? - @fragment = MadmpFragment.new( - dmp_id: p_params[:dmp_id], - parent_id: p_params[:parent_id], - madmp_schema: schema, - data: data - ) - @fragment.classname = classname - authorize @fragment - @fragment.save! - else - @fragment = MadmpFragment.find_by!({ - id: p_params[:id], - dmp_id: p_params[:dmp_id] - }) - new_data = @fragment.data.merge(data) - authorize @fragment - @fragment.update( - data: new_data - ) + if params[:id].present? + # rubocop:disable BlockLength + Answer.transaction do + begin + @fragment = MadmpFragment.find_by!( + id: params[:id], + dmp_id: p_params[:dmp_id] + ) + data = @fragment.data.merge(data) + data = data.merge({ + "validations" => MadmpFragment.validate_data(data, schema.schema) + }) + @fragment.assign_attributes(data: data) + + authorize @fragment + unless p_params[:source] == "modal" + @fragment.answer.update!({ + lock_version: p_params[:answer][:lock_version], + is_common: p_params[:answer][:is_common], + user_id: current_user.id + }) + end + @fragment.save! + rescue ActiveRecord::StaleObjectError + @stale_fragment = @fragment + @fragment = MadmpFragment.find_by({ + id: params[:id], + dmp_id: p_params[:dmp_id] + }) + end end + else + @fragment = MadmpFragment.new( + dmp_id: p_params[:dmp_id], + parent_id: p_params[:parent_id], + madmp_schema: schema + ) + @fragment.classname = classname + data = data.merge({ + "validations" => MadmpFragment.validate_data(data, schema.schema) + }) + @fragment.assign_attributes(data: data) + + unless p_params[:source] == "modal" + @fragment.answer = Answer.create!({ + research_output_id: p_params[:answer][:research_output_id], + plan_id: p_params[:answer][:plan_id], + question_id: p_params[:answer][:question_id], + lock_version: p_params[:answer][:lock_version], + is_common: p_params[:answer][:is_common], + user_id: current_user.id + }) + end + authorize @fragment + @fragment.save! + end - + if @fragment.present? - render json: { - "fragment_id" => @fragment.parent_id, - "classname" => classname, - "html" => render_fragment_list(@fragment.dmp_id, @fragment.parent_id, schema.id) - } + if @fragment.answer.present? + render json: render_fragment_form(@fragment, @stale_fragment) + else + render json: { + "fragment_id" => @fragment.parent_id, + "classname" => classname, + "html" => render_fragment_list(@fragment.dmp_id, @fragment.parent_id, schema.id) + }.to_json + end end end @@ -141,6 +180,62 @@ end end + def render_fragment_form(fragment, stale_fragment = nil) + answer = fragment.answer + question = answer.question + research_output = answer.research_output + section = question.section + plan = answer.plan + + return { + "answer" => { + "id" => answer.id + }, + "question" => { + "id" => question.id, + "answer_lock_version" => answer.lock_version, + "locking" => stale_fragment ? + render_to_string(partial: "madmp_fragments/locking", locals: { + question: question, + answer: answer, + fragment: stale_fragment, + research_output: research_output, + user: answer.user + }, formats: [:html]) : + nil, + "form" => render_to_string(partial: "madmp_fragments/new_edit", locals: { + question: question, + answer: answer, + fragment: fragment , + research_output: research_output, + dmp_id: fragment.dmp_id, + parent_id: fragment.parent_id, + readonly: false + }, formats: [:html]), + "answer_status" => render_to_string(partial: "answers/status", locals: { + answer: answer + }, formats: [:html]) + }, + "section" => { + "id" => section.id, + "progress" => render_to_string(partial: "/org_admin/sections/progress", locals: { + section: section, + plan: plan + }, formats: [:html]) + }, + "plan" => { + "id" => plan.id, + "progress" => render_to_string(partial: "plans/progress", locals: { + plan: plan, + current_phase: section.phase + }, formats: [:html]) + }, + "research_output" => { + "id" => research_output.id + } + }.to_json + end + # Get the parameters conresponding to the schema def schema_params(schema, flat = false) s_params = schema.generate_strong_params(flat) @@ -148,7 +243,10 @@ end def permitted_params - permit_arr = [:id, :dmp_id, :parent_id, :schema_id] + permit_arr = [:id, :dmp_id, :parent_id, :schema_id, :source, + answer: [:id, :plan_id, :research_output_id, + :question_id, :lock_version, :is_common] + ] params.require(:madmp_fragment).permit(permit_arr) end end \ No newline at end of file diff --git a/app/helpers/dynamic_form_helper.rb b/app/helpers/dynamic_form_helper.rb index 940f391..14bfba8 100644 --- a/app/helpers/dynamic_form_helper.rb +++ b/app/helpers/dynamic_form_helper.rb @@ -1,6 +1,6 @@ module DynamicFormHelper - def create_text_field(form, value, name, label, html_class: nil, is_multiple: false, readonly: false, index: 0) + def create_text_field(form, value, name, label, validation: nil, html_class: nil, is_multiple: false, readonly: false, index: 0) render partial: 'shared/dynamic_form/fields/text_field', locals: { f: form, @@ -11,13 +11,14 @@ field_label: label, field_class: html_class, input_type: nil, - readonly: readonly + readonly: readonly, + validation: validation } end - def create_url_field(form, value, name, label, html_class: nil, is_multiple: false, readonly: false, index: 0) + def create_url_field(form, value, name, label, validation: nil, html_class: nil, is_multiple: false, readonly: false, index: 0) render partial: 'shared/dynamic_form/fields/text_field', locals: { f: form, @@ -28,13 +29,14 @@ field_label: label, field_class: html_class, input_type: 'url', - readonly: readonly + readonly: readonly, + validation: validation } end - def create_email_field(form, value, name, label, html_class: nil, is_multiple: false, readonly: false, index: 0) + def create_email_field(form, value, name, label, validation: nil, html_class: nil, is_multiple: false, readonly: false, index: 0) render partial: 'shared/dynamic_form/fields/text_field', locals: { f: form, @@ -45,13 +47,14 @@ field_label: label, field_class: html_class, input_type: 'email', - readonly: readonly + readonly: readonly, + validation: validation } end - def create_date_field(form, value, name, label, html_class: nil, is_multiple: false, readonly: false, index: 0) + def create_date_field(form, value, name, label, validation: nil, html_class: nil, is_multiple: false, readonly: false, index: 0) render partial: 'shared/dynamic_form/fields/text_field', locals: { f: form, @@ -62,13 +65,14 @@ field_label: label, field_class: html_class, input_type: 'date', - readonly: readonly + readonly: readonly, + validation: validation } end - def create_number_field(form, value, name, label, html_class: nil, is_multiple: false, readonly: false, index: 0) + def create_number_field(form, value, name, label, validation: nil, html_class: nil, is_multiple: false, readonly: false, index: 0) render partial: 'shared/dynamic_form/fields/number_field', locals: { f: form, @@ -78,24 +82,26 @@ field_name: name, field_label: label, field_class: html_class, - readonly: readonly + readonly: readonly, + validation: validation } end - def create_checkbox_field(form, value, name, label, html_class: nil, readonly: false) + def create_checkbox_field(form, value, name, label, validation: nil, html_class: nil, readonly: false) render partial: 'shared/dynamic_form/fields/checkbox_field', locals: { f: form, field_value: value, field_name: name, field_label: label, - readonly: readonly + readonly: readonly, + validation: validation } end - def create_select_field(form, value, name, label, select_values, html_class: nil, readonly: false) + def create_select_field(form, value, name, label, select_values, validation: nil, html_class: nil, readonly: false) render partial: 'shared/dynamic_form/fields/select_field', locals: { f: form, @@ -104,31 +110,52 @@ field_label: label, select_values: select_values, field_class: html_class, - readonly: readonly + readonly: readonly, + validation: validation } - end + end + def display_validation_message(validations) + message = "" + validations.each do |validation| + case validation + when "required" + message += d_('dmpopidor', 'This property is required.') + when "pattern" + message += d_('dmpopidor', 'This property has an invalid format.') + else + message += d_('dmpopidor', 'This property has an unknown problem : %{validation}') % { + validation: validation + } + end + end + message + end # Formats the data extract from the structured answer form to valid JSON data # This is useful because Rails converts all form data to strings and JSON needs the actual types def data_reformater(schema, data) schema["properties"].each do |key, prop| - case prop["type"] - when "integer", "number" - data[key] = data[key].to_i - when "boolean" - data[key] = data[key] == "1" - when "array" - data[key] = data[key].kind_of?(Array) ? data[key] : [data[key]] - when "object" - if prop['schema_id'].present? - sub_schema = MadmpSchema.find(prop['schema_id']) - data[key] = data_reformater(sub_schema.schema, data[key]) - end - # if value["dictionnary"] - # data[key] = JSON.parse(DictionnaryValue.where(id: data[key]).select(:id, :uri, :label).take.to_json) - # end - end + if data[key] == "" + data.delete(key) + else + case prop["type"] + when "integer", "number" + data[key] = data[key].to_i + when "boolean" + data[key] = data[key] == "1" + when "array" + data[key] = data[key].kind_of?(Array) ? data[key] : [data[key]] + when "object" + if prop['schema_id'].present? + sub_schema = MadmpSchema.find(prop['schema_id']) + data[key] = data_reformater(sub_schema.schema, data[key]) + end + # if value["dictionnary"] + # data[key] = JSON.parse(DictionnaryValue.where(id: data[key]).select(:id, :uri, :label).take.to_json) + # end + end + end end data end diff --git a/app/javascript/views/answers/edit.js b/app/javascript/views/answers/edit.js index ead84b5..287ea98 100644 --- a/app/javascript/views/answers/edit.js +++ b/app/javascript/views/answers/edit.js @@ -167,8 +167,10 @@ const detachEventHandlers = (jQueryForm) => { formHandlers({ jQuery: jQueryForm, attachment: 'off' }); const tinymceId = jQueryForm.find(`.${editorClass}`).attr('id'); - detachEditorHandlers(Tinymce.findEditorById(tinymceId)); - Tinymce.destroyEditorById(tinymceId); + if (tinymceId) { + detachEditorHandlers(Tinymce.findEditorById(tinymceId)); + Tinymce.destroyEditorById(tinymceId); + } }; /* Attaches events for a specific form including its tinymce editor @@ -177,8 +179,10 @@ const attachEventHandlers = (jQueryForm) => { formHandlers({ jQuery: jQueryForm, attachment: 'on' }); const tinymceId = jQueryForm.find(`.${editorClass}`).attr('id'); - Tinymce.init({ selector: `#${tinymceId}` }); - editorHandlers(Tinymce.findEditorById(tinymceId)); + if (tinymceId) { + Tinymce.init({ selector: `#${tinymceId}` }); + editorHandlers(Tinymce.findEditorById(tinymceId)); + } }; datePicker(); diff --git a/app/models/fragment/budget.rb b/app/models/fragment/budget.rb new file mode 100644 index 0000000..99fb4d3 --- /dev/null +++ b/app/models/fragment/budget.rb @@ -0,0 +1,32 @@ +# == Schema Information +# +# Table name: madmp_fragments +# +# id :integer not null, primary key +# data :json +# answer_id :integer +# madmp_schema_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# classname :string +# dmp_id :integer +# parent_id :integer +# +# Indexes +# +# index_madmp_fragments_on_answer_id (answer_id) +# index_madmp_fragments_on_madmp_schema_id (madmp_schema_id) +# + +class Fragment::Budget < MadmpFragment + + def research_output + self.parent + end + + + def self.sti_name + "cost" + end + +end diff --git a/app/models/fragment/data_collection.rb b/app/models/fragment/data_collection.rb index 29fe9d5..9763b8e 100644 --- a/app/models/fragment/data_collection.rb +++ b/app/models/fragment/data_collection.rb @@ -23,6 +23,10 @@ def research_output self.parent end + + def technical_resource_usage + Fragment::TechnicalResourceUsage.where(parent_id: id).first + end def self.sti_name "data_collection" diff --git a/app/models/fragment/data_processing.rb b/app/models/fragment/data_processing.rb new file mode 100644 index 0000000..1245ed4 --- /dev/null +++ b/app/models/fragment/data_processing.rb @@ -0,0 +1,35 @@ +# == Schema Information +# +# Table name: madmp_fragments +# +# id :integer not null, primary key +# data :json +# answer_id :integer +# madmp_schema_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# classname :string +# dmp_id :integer +# parent_id :integer +# +# Indexes +# +# index_madmp_fragments_on_answer_id (answer_id) +# index_madmp_fragments_on_madmp_schema_id (madmp_schema_id) +# + +class Fragment::DataProcessing < MadmpFragment + + def research_output + self.parent + end + + def technical_resource_usage + Fragment::TechnicalResourceUsage.where(parent_id: id).first + end + + def self.sti_name + "data_processing" + end + +end diff --git a/app/models/fragment/data_quality.rb b/app/models/fragment/data_quality.rb deleted file mode 100644 index 3a6d562..0000000 --- a/app/models/fragment/data_quality.rb +++ /dev/null @@ -1,31 +0,0 @@ -# == Schema Information -# -# Table name: madmp_fragments -# -# id :integer not null, primary key -# data :json -# answer_id :integer -# madmp_schema_id :integer -# created_at :datetime not null -# updated_at :datetime not null -# classname :string -# dmp_id :integer -# parent_id :integer -# -# Indexes -# -# index_madmp_fragments_on_answer_id (answer_id) -# index_madmp_fragments_on_madmp_schema_id (madmp_schema_id) -# - -class Fragment::DataQuality < MadmpFragment - - def research_output - self.parent - end - - def self.sti_name - "data_quality" - end - -end diff --git a/app/models/fragment/data_storage.rb b/app/models/fragment/data_storage.rb new file mode 100644 index 0000000..2373f71 --- /dev/null +++ b/app/models/fragment/data_storage.rb @@ -0,0 +1,35 @@ +# == Schema Information +# +# Table name: madmp_fragments +# +# id :integer not null, primary key +# data :json +# answer_id :integer +# madmp_schema_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# classname :string +# dmp_id :integer +# parent_id :integer +# +# Indexes +# +# index_madmp_fragments_on_answer_id (answer_id) +# index_madmp_fragments_on_madmp_schema_id (madmp_schema_id) +# + +class Fragment::DataStorage < MadmpFragment + + def research_output + self.parent + end + + def technical_resource_usage + Fragment::TechnicalResourceUsage.where(parent_id: id).first + end + + def self.sti_name + "data_storage" + end + +end diff --git a/app/models/fragment/documentation.rb b/app/models/fragment/documentation.rb deleted file mode 100644 index 9738ea3..0000000 --- a/app/models/fragment/documentation.rb +++ /dev/null @@ -1,40 +0,0 @@ -# == Schema Information -# -# Table name: madmp_fragments -# -# id :integer not null, primary key -# data :json -# answer_id :integer -# madmp_schema_id :integer -# created_at :datetime not null -# updated_at :datetime not null -# classname :string -# dmp_id :integer -# parent_id :integer -# -# Indexes -# -# index_madmp_fragments_on_answer_id (answer_id) -# index_madmp_fragments_on_madmp_schema_id (madmp_schema_id) -# - -class Fragment::Documentation < MadmpFragment - - def research_output - self.parent - end - - def documentation_administrator - Fragment::Person.where(id: data['documentation_administrator']['dbId']) - end - - def metadata_format - Fragment::MetadataFormat.where(id: data['metadata_format']['dbId']) - end - - - def self.sti_name - "documentation" - end - -end diff --git a/app/models/fragment/documentation_quality.rb b/app/models/fragment/documentation_quality.rb new file mode 100644 index 0000000..6c328a9 --- /dev/null +++ b/app/models/fragment/documentation_quality.rb @@ -0,0 +1,36 @@ +# == Schema Information +# +# Table name: madmp_fragments +# +# id :integer not null, primary key +# data :json +# answer_id :integer +# madmp_schema_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# classname :string +# dmp_id :integer +# parent_id :integer +# +# Indexes +# +# index_madmp_fragments_on_answer_id (answer_id) +# index_madmp_fragments_on_madmp_schema_id (madmp_schema_id) +# + +class Fragment::DocumentationQuality < MadmpFragment + + def research_output + self.parent + end + + def metadata_format + Fragment::MetadataFormat.where(id: data['metadata_format']['dbId']).first + end + + + def self.sti_name + "documentation" + end + +end diff --git a/app/models/fragment/funding.rb b/app/models/fragment/funding.rb index df5d41e..5dcef3f 100644 --- a/app/models/fragment/funding.rb +++ b/app/models/fragment/funding.rb @@ -21,7 +21,7 @@ class Fragment::Funding < MadmpFragment def project - Fragment::Project.where(id: data['project']['dbId']).first + self.parent end def funder diff --git a/app/models/fragment/metadata_format.rb b/app/models/fragment/metadata_format.rb deleted file mode 100644 index 9994278..0000000 --- a/app/models/fragment/metadata_format.rb +++ /dev/null @@ -1,32 +0,0 @@ -# == Schema Information -# -# Table name: madmp_fragments -# -# id :integer not null, primary key -# data :json -# answer_id :integer -# madmp_schema_id :integer -# created_at :datetime not null -# updated_at :datetime not null -# classname :string -# dmp_id :integer -# parent_id :integer -# -# Indexes -# -# index_madmp_fragments_on_answer_id (answer_id) -# index_madmp_fragments_on_madmp_schema_id (madmp_schema_id) -# - -class Fragment::MetadataFormat < MadmpFragment - - def documentation - Fragment::Documentation.where("(data->>'metadata_format'->>'dbId')::int = ?", id) - end - - - def self.sti_name - "metadata_format" - end - -end diff --git a/app/models/fragment/metadata_standard.rb b/app/models/fragment/metadata_standard.rb new file mode 100644 index 0000000..7ee2966 --- /dev/null +++ b/app/models/fragment/metadata_standard.rb @@ -0,0 +1,32 @@ +# == Schema Information +# +# Table name: madmp_fragments +# +# id :integer not null, primary key +# data :json +# answer_id :integer +# madmp_schema_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# classname :string +# dmp_id :integer +# parent_id :integer +# +# Indexes +# +# index_madmp_fragments_on_answer_id (answer_id) +# index_madmp_fragments_on_madmp_schema_id (madmp_schema_id) +# + +class Fragment::MetadataStandard < MadmpFragment + + def documentation + Fragment::Documentation.where("(data->>'metadata_format'->>'dbId')::int = ?", id) + end + + + def self.sti_name + "metadata_format" + end + +end diff --git a/app/models/fragment/partner.rb b/app/models/fragment/partner.rb index ef14870..f4a3eec 100644 --- a/app/models/fragment/partner.rb +++ b/app/models/fragment/partner.rb @@ -21,7 +21,7 @@ class Fragment::Partner < MadmpFragment def project - Fragment::Project.where(id: data['project']['dbId']).first + self.parent end diff --git a/app/models/fragment/preservation_issue.rb b/app/models/fragment/preservation_issue.rb index 3218e88..14a5a91 100644 --- a/app/models/fragment/preservation_issue.rb +++ b/app/models/fragment/preservation_issue.rb @@ -24,6 +24,10 @@ self.parent end + def technical_resource_usage + Fragment::TechnicalResourceUsage.where(parent_id: id).first + end + def self.sti_name "preservation_issue" diff --git a/app/models/fragment/research_output.rb b/app/models/fragment/research_output.rb index d4e20f6..9ce25c3 100644 --- a/app/models/fragment/research_output.rb +++ b/app/models/fragment/research_output.rb @@ -24,60 +24,48 @@ Fragment::Person.where(id: data['contact']['dbId']).first end + + def reuse_data + Fragment::ReuseData.where(parent_id: id).first + end + def data_collection Fragment::DataCollection.where(parent_id: id).first end + + def ethical_issues + Fragment::EthicalIssue.where(parent_id: id).first + end + + def personal_data_issues + Fragment::PersonalDataIssue.where(parent_id: id).first + end + + def legal_issues + Fragment::LegalIssue.where(parent_id: id).first + end - def data_quality - Fragment::DataQuality.where(parent_id: id).first + def data_processing + Fragment::DataProcessing.where(parent_id: id).first + end + + def data_storage + Fragment::DataStorage.where(parent_id: id).first end - def documentation - Fragment::Documentation.where(parent_id: id).first - end - - def preservation_issue - Fragment::PreservationIssue.where(parent_id: id).first + def documentation_quality + Fragment::DocumentationQuality.where(parent_id: id).first end def sharing Fragment::Sharing.where(parent_id: id).first end - - - def costs - Fragment::Cost.where(parent_id: id) - end - - def distributions - Fragment::Distribution.where(parent_id: id) - end - - def ethical_issues - Fragment::EthicalIssue.where(parent_id: id) - end - - def legal_issues - Fragment::LegalIssue.where(parent_id: id) + def preservation_issue + Fragment::PreservationIssue.where(parent_id: id).first end - def personal_data_issues - Fragment::PersonalDataIssue.where(parent_id: id) - end - - def reuse_datas - Fragment::ReuseData.where(parent_id: id) - end - - def staff_members - Fragment::StaffMember.where(parent_id: id) - end - - def technical_resource_usages - Fragment::TechnicalResourceUsage.where(parent_id: id) - end def self.sti_name diff --git a/app/models/fragment/sharing.rb b/app/models/fragment/sharing.rb index 0f22d4a..838cbb7 100644 --- a/app/models/fragment/sharing.rb +++ b/app/models/fragment/sharing.rb @@ -24,6 +24,16 @@ self.parent end + def technical_resource_usage + Fragment::TechnicalResourceUsage.where(parent_id: id).first + end + + + def distribution + Fragment::Distribution.where(parent_id: id).first + end + + def self.sti_name "sharing" diff --git a/app/models/fragment/staff_member.rb b/app/models/fragment/staff_member.rb deleted file mode 100644 index 149a0fd..0000000 --- a/app/models/fragment/staff_member.rb +++ /dev/null @@ -1,36 +0,0 @@ -# == Schema Information -# -# Table name: madmp_fragments -# -# id :integer not null, primary key -# data :json -# answer_id :integer -# madmp_schema_id :integer -# created_at :datetime not null -# updated_at :datetime not null -# classname :string -# dmp_id :integer -# parent_id :integer -# -# Indexes -# -# index_madmp_fragments_on_answer_id (answer_id) -# index_madmp_fragments_on_madmp_schema_id (madmp_schema_id) -# - -class Fragment::StaffMember < MadmpFragment - - def agent - Fragment::Person.where(id: data['agent']['dbId']) - end - - def research_output - self.parent - end - - - def self.sti_name - "staff_member" - end - -end diff --git a/app/models/madmp_fragment.rb b/app/models/madmp_fragment.rb index 0dab9e2..ccaaa18 100644 --- a/app/models/madmp_fragment.rb +++ b/app/models/madmp_fragment.rb @@ -44,17 +44,19 @@ # = Single Table Inheritence = # ================ self.inheritance_column = :classname + scope :budgets, -> { where(classname: 'budgets') } scope :costs, -> { where(classname: 'cost') } scope :data_collections, -> { where(classname: 'data_collection') } - scope :data_qualities, -> { where(classname: 'data_quality') } + scope :data_processings, -> { where(classname: 'data_processing') } + scope :data_storages, -> { where(classname: 'data_storage') } scope :distributions, -> { where(classname: 'distribution') } scope :dmps, -> { where(classname: 'dmp') } - scope :documentations, -> { where(classname: 'documentation') } + scope :documentation_qualities, -> { where(classname: 'documentation_quality') } scope :ethical_issues, -> { where(classname: 'ethical_issue') } scope :funders, -> { where(classname: 'funder') } scope :fundings, -> { where(classname: 'funding') } scope :metas, -> { where(classname: 'meta') } - scope :metadata_formats, -> { where(classname: 'metadata_format') } + scope :metadata_standards, -> { where(classname: 'metadata_standard') } scope :partners, -> { where(classname: 'partner') } scope :persons, -> { where(classname: 'person') } scope :personal_data_issues, -> { where(classname: 'personal_data_issue') } @@ -63,7 +65,6 @@ scope :research_outputs, -> { where(classname: 'research_output') } scope :reuse_datas, -> { where(classname: 'reuse_data') } scope :sharings, -> { where(classname: 'sharing') } - scope :staff_members, -> { where(classname: 'staff_member') } scope :technical_resource_usages, -> { where(classname: 'technical_resource_usage') } scope :technical_resources, -> { where(classname: 'technical_resource') } @@ -75,6 +76,11 @@ after_create :update_parent_references after_destroy :update_parent_references + # ===================== + # = Nested Attributes = + # ===================== + accepts_nested_attributes_for :answer, allow_destroy: true + # ================= # = Class methods = # ================= @@ -96,9 +102,8 @@ def get_sub_fragments sub_fragments = self.dmp.persons.group_by(&:madmp_schema_id) unless self.children.empty? - sub_fragments.merge(self.children.group_by(&:madmp_schema_id)) + sub_fragments = sub_fragments.merge(self.children.group_by(&:madmp_schema_id)) end - sub_fragments end @@ -155,10 +160,36 @@ sa.dmp_id = answer.plan.json_fragment().id sa.parent_id = parent_id end + data = data.merge({ + "validations" => self.validate_data(data, schema.schema) + }) s_answer.assign_attributes(data: data) s_answer.save end + + # Validate the fragment data with the linked schema + # and saves the result with the fragment data + def self.validate_data(data, schema) + schemer = JSONSchemer.schema(schema) + unformated = schemer.validate(data).to_a + validations = {} + unformated.each do |valid| + unless valid['type'] == "object" + key = valid['data_pointer'][1..-1] + if valid['type'] == "required" + required = JsonPath.on(valid, '$..missing_keys').flatten + required.each do |req| + validations[req] ? validations[req].push("required") : validations[req] = ["required"] + end + else + validations[key] ? validations[key].push(valid['type']) : validations[key] = [valid['type']] + end + end + end + validations + end + def self.find_sti_class(type_name) self end diff --git a/app/views/branded/answers/_new_edit.html.erb b/app/views/branded/answers/_new_edit.html.erb index dcd5013..56e3b38 100644 --- a/app/views/branded/answers/_new_edit.html.erb +++ b/app/views/branded/answers/_new_edit.html.erb @@ -58,27 +58,20 @@ <%= hidden_field_tag :standards, answer_hash['standards'].to_json %> <% end %> <% end %> - <% if question.question_format.structured %> -
- <% else %> - - <% end %> + <% if template.present? && template.org.present? %> <% question.example_answers([base_template_org.id, template.org.id]).each do |annotation| %> diff --git a/app/views/branded/madmp_fragments/_locking.html.erb b/app/views/branded/madmp_fragments/_locking.html.erb new file mode 100644 index 0000000..640291d --- /dev/null +++ b/app/views/branded/madmp_fragments/_locking.html.erb @@ -0,0 +1,18 @@ + +<%= _('The following answer cannot be saved') %>
+ <%# We do not need to re-show example answers in this lock conflict section so leave template nil %> + <%= render partial: '/madmp_fragments/new_edit', locals: { + template: nil, + question: question, + answer: answer, + fragment: fragment, + research_output: research_output, + dmp_id: fragment.dmp_id, + parent_id: fragment.parent_id, + readonly: true, locking: true + } %> +<%= _('since %{name} saved the answer below while you were editing. Please, combine your changes and then save the answer again.') % { name: user.name} %>
+