Skip to content

Commit

Permalink
Merge branch 'main' into digital-research-hub
Browse files Browse the repository at this point in the history
  • Loading branch information
somathias committed Feb 1, 2024
2 parents 8731938 + 23c0daa commit 492cfdb
Show file tree
Hide file tree
Showing 52 changed files with 757 additions and 216 deletions.
8 changes: 7 additions & 1 deletion app/assets/javascripts/controlled_vocabs.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,20 @@ var SampleTypeControlledVocab = {
initialise_rich_text_editors(".rich-text-edit");
},

copyBlankModalForm: function() {
// first destroy any select2 elements, which won't survive being cloned. They will be initialised again when reset
$j('#cv-modal select[data-role="seek-objectsinput"]').select2('destroy');
SampleTypeControlledVocab.blankControlledVocabModelForm=$j('#cv-modal').clone();
},

//resets the modal
resetModalControlledVocabForm: function () {
$j('#cv-modal').remove();
$j('#modal-dialogues').append(SampleTypeControlledVocab.blankControlledVocabModelForm.clone());
CVTerms.init();
ObjectsInput.init();
SampleTypeControlledVocab.bindNewControlledVocabShowEvent();
SampleTypeControlledVocab.initialise_deferred_rich_editor_modal();

},

//selected CV item changed
Expand Down
7 changes: 6 additions & 1 deletion app/controllers/admin_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def index
respond_to do |format|
format.html
end
end
end

def update_admins
# Don't let admin remove themselves or they won't be able to manage roles
Expand Down Expand Up @@ -134,6 +134,11 @@ def update_features_enabled
Seek::Config.piwik_analytics_url = params[:piwik_analytics_url]
Seek::Config.piwik_analytics_tracking_notice = params[:piwik_analytics_tracking_notice]

Seek::Config.custom_analytics_snippet_enabled = string_to_boolean params[:custom_analytics_snippet_enabled]
Seek::Config.custom_analytics_snippet = params[:custom_analytics_snippet]
Seek::Config.custom_analytics_tracking_notice = params[:custom_analytics_tracking_notice]
Seek::Config.custom_analytics_name = params[:custom_analytics_name]

Seek::Config.doi_minting_enabled = string_to_boolean params[:doi_minting_enabled]
Seek::Config.datacite_username = params[:datacite_username]
Seek::Config.datacite_password = params[:datacite_password]
Expand Down
6 changes: 3 additions & 3 deletions app/controllers/assays_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def new
@permitted_params = assay_params if params[:assay]

# jump straight to experimental if modelling analysis is disabled
@assay_class ||= 'experimental' unless Seek::Config.modelling_analysis_enabled
@assay_class ||= 'EXP' unless Seek::Config.modelling_analysis_enabled

@assay.assay_class = AssayClass.for_type(@assay_class) unless @assay_class.nil?

Expand All @@ -82,7 +82,7 @@ def edit
end

def create
params[:assay_class_id] ||= AssayClass.for_type('experimental').id
params[:assay_class_id] ||= AssayClass.experimental.id
@assay = Assay.new(assay_params)

update_assay_organisms @assay, params
Expand Down Expand Up @@ -117,7 +117,7 @@ def fix_assay_linkage
return unless is_single_page_assay?
return unless @assay.has_linked_child_assay?

previous_assay_linked_st_id = @assay.previous_linked_assay_sample_type&.id
previous_assay_linked_st_id = @assay.previous_linked_sample_type&.id

next_assay = Assay.all.detect do |a|
a.sample_type&.sample_attributes&.first&.linked_sample_type_id == @assay.sample_type_id
Expand Down
35 changes: 27 additions & 8 deletions app/controllers/isa_assays_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ class IsaAssaysController < ApplicationController
before_action :find_requested_item, only: %i[edit update]

def new
@isa_assay = IsaAssay.new
if params[:is_assay_stream]
@isa_assay = IsaAssay.new({ assay: { assay_class_id: AssayClass.assay_stream.id } })
else
@isa_assay = IsaAssay.new({ assay: { assay_class_id: AssayClass.experimental.id } })
end
end

def create
@isa_assay = IsaAssay.new(isa_assay_params)
update_sharing_policies @isa_assay.assay
@isa_assay.assay.contributor = current_person
@isa_assay.sample_type.contributor = User.current_user.person
@isa_assay.sample_type.contributor = User.current_user.person if isa_assay_params[:sample_type]
if @isa_assay.save
redirect_to single_page_path(id: @isa_assay.assay.projects.first, item_type: 'assay',
item_id: @isa_assay.assay, notice: 'The ISA assay was created successfully!')
Expand All @@ -27,7 +31,11 @@ def create

def edit
# let edit the assay if the sample_type is not authorized
@isa_assay.sample_type = nil unless requested_item_authorized?(@isa_assay.sample_type)
if @isa_assay.assay.is_assay_stream?
@isa_assay.sample_type = nil
else
@isa_assay.sample_type = nil unless requested_item_authorized?(@isa_assay.sample_type)
end

respond_to do |format|
format.html
Expand All @@ -38,9 +46,11 @@ def update
@isa_assay.assay.attributes = isa_assay_params[:assay]

# update the sample_type
if requested_item_authorized?(@isa_assay.sample_type)
@isa_assay.sample_type.update(isa_assay_params[:sample_type])
@isa_assay.sample_type.resolve_inconsistencies
unless @isa_assay.assay.is_assay_stream?
if requested_item_authorized?(@isa_assay.sample_type)
@isa_assay.sample_type.update(isa_assay_params[:sample_type])
@isa_assay.sample_type.resolve_inconsistencies
end
end

if @isa_assay.save
Expand Down Expand Up @@ -87,10 +97,12 @@ def assay_params
{ data_files_attributes: %i[asset_id direction relationship_type_id] },
{ publication_ids: [] },
{ extended_metadata_attributes: determine_extended_metadata_keys(:assay) },
{ discussion_links_attributes: %i[id url label _destroy] }]
{ discussion_links_attributes: %i[id url label _destroy] }, :assay_stream_id]
end

def sample_type_params(params)
return [] unless params[:sample_type]

attributes = params[:sample_type][:sample_attributes]
if attributes
params[:sample_type][:sample_attributes_attributes] = []
Expand Down Expand Up @@ -128,9 +140,16 @@ def set_up_instance_variable
end

def find_requested_item
@isa_assay = IsaAssay.new
if params[:is_assay_stream]
@isa_assay = IsaAssay.new({ assay: { assay_class_id: AssayClass.assay_stream.id } })
else
@isa_assay = IsaAssay.new({ assay: { assay_class_id: AssayClass.experimental.id } })
end
@isa_assay.populate(params[:id])

# Should not deal with sample type if assay has assay_class assay stream
return if @isa_assay.assay.is_assay_stream?

if @isa_assay.sample_type.nil? || !requested_item_authorized?(@isa_assay.assay)
flash[:error] = "You are not authorized to edit this #{t('isa_assay')}"
flash[:error] = 'Resource not found.' if @isa_assay.sample_type.nil?
Expand Down
4 changes: 4 additions & 0 deletions app/controllers/workflow_classes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ def edit

def index
@workflow_classes = WorkflowClass.order(extractor: :desc).all
respond_to do |format|
format.html
format.jsonld { render json: @workflow_classes.map(&:ro_crate_metadata), adapter: :attributes }
end
end

private
Expand Down
30 changes: 19 additions & 11 deletions app/forms/isa_assay.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,31 @@ class IsaAssay

attr_accessor :assay, :sample_type, :input_sample_type_id

validates_presence_of :assay, :sample_type, :input_sample_type_id
validates_presence_of :assay
validate :validate_objects

def initialize(params = {})
@assay = Assay.new(params[:assay] || {})
@sample_type = SampleType.new((params[:sample_type] || {}).merge({ project_ids: @assay.project_ids }))
@sample_type.sample_attributes.build(is_title: true, required: true) unless params[:sample_type]
@assay.sample_type = @sample_type
@assay.assay_class = AssayClass.for_type('experimental')
unless @assay.is_assay_stream?
@sample_type = SampleType.new((params[:sample_type] || {}).merge({ project_ids: @assay.project_ids }))
@sample_type.sample_attributes.build(is_title: true, required: true) unless params[:sample_type]
@assay.sample_type = @sample_type
end

@input_sample_type_id = params[:input_sample_type_id]
end

def save
if valid?
if @assay.new_record?
if @assay.new_record? && !@assay.is_assay_stream?
# connect the sample type multi link attribute to the last sample type of the assay's study
input_attribute = @sample_type.sample_attributes.detect(&:seek_sample_multi?)
input_attribute.linked_sample_type_id = @input_sample_type_id
title = SampleType.find(@input_sample_type_id).sample_attributes.detect(&:is_title).title
input_attribute.title = "Input (#{title})"
end
@sample_type.save unless @assay.is_assay_stream?
@assay.save
@sample_type.save
else
false
end
Expand Down Expand Up @@ -54,6 +56,12 @@ def populate(id)
def validate_objects
@assay.errors.each { |e| errors.add(:base, "[Assay]: #{e.full_message}") } unless @assay.valid?

return if @assay.is_assay_stream?

errors.add(:base, '[Assay]: The assay is missing a sample type.') if @sample_type.nil?

return unless @sample_type

@sample_type.errors.full_messages.each { |e| errors.add(:base, "[Sample type]: #{e}") } unless @sample_type.valid?

unless @sample_type.sample_attributes.any?(&:seek_sample_multi?)
Expand All @@ -66,22 +74,22 @@ def validate_objects

unless @sample_type.sample_attributes.select { |a| a.title.include?('Input') && a.isa_tag.nil? }.one?
errors.add(:base,
"[Sample type]: Should have exactly one attribute with the title 'Input' <u><b>and</b></u> no ISA tag".html_safe)
"[Sample type]: Should have exactly one attribute with the title 'Input' <u><b>and</b></u> no ISA tag".html_safe)
end

if @sample_type.sample_attributes.select { |a| !a.title.include?('Input') && a.isa_tag.nil? }.any?
errors.add(:base,
"[Sample type]: All attributes should have an ISA Tag except for the <em>'Input'</em> attribute (hidden)".html_safe)
"[Sample type]: All attributes should have an ISA Tag except for the <em>'Input'</em> attribute (hidden)".html_safe)
end

assay_sample_or_datafile_attributes = @sample_type.sample_attributes.select do |a|
a.isa_tag&.isa_other_material? || a.isa_tag&.isa_data_file?
end

unless assay_sample_or_datafile_attributes.one?
errors.add(:base,
"[Sample type]: Should have exactly one attribute with the 'data_file' <u><b>or</b></u> 'other_material' ISA tag selected".html_safe)
"[Sample type]: Should have exactly one attribute with the 'data_file' <u><b>or</b></u> 'other_material' ISA tag selected".html_safe)
end

errors.add(:base, '[Input Assay]: Input Assay is not provided') if @input_sample_type_id.blank?
end
end
4 changes: 2 additions & 2 deletions app/helpers/images_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ def append_size_parameter(url, size)
url
end

def delete_icon(model_item, user, confirm_msg='Are you sure?')
item_name = text_for_resource model_item
def delete_icon(model_item, user, confirm_msg='Are you sure?', alternative_item_name=nil)
item_name = alternative_item_name.nil? ? (text_for_resource model_item) : alternative_item_name
if model_item.can_delete?(user)
fullURL = url_for(model_item)

Expand Down
40 changes: 31 additions & 9 deletions app/models/assay.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ class Assay < ApplicationRecord

belongs_to :sample_type

has_many :child_assays, class_name: 'Assay', foreign_key: 'assay_stream_id', dependent: :destroy
belongs_to :assay_stream, class_name: 'Assay', optional: true

belongs_to :assay_class
has_many :assay_organisms, dependent: :destroy, inverse_of: :assay
has_many :organisms, through: :assay_organisms, inverse_of: :assays
Expand Down Expand Up @@ -65,19 +68,38 @@ class Assay < ApplicationRecord

enforce_authorization_on_association :study, :view

def previous_linked_assay_sample_type
sample_type.sample_attributes.detect { |sa| sa.isa_tag.nil? && sa.title.include?('Input') }&.linked_sample_type
def is_assay_stream?
assay_class&.is_assay_stream?
end

def previous_linked_sample_type
return unless is_isa_json_compliant?

if is_assay_stream?
study.sample_types.second
else
sample_type.sample_attributes.detect { |sa| sa.isa_tag.nil? && sa.title.include?('Input') }&.linked_sample_type
end
end

def has_linked_child_assay?
sample_type&.linked_sample_attributes&.any?
return false unless is_isa_json_compliant?

if is_assay_stream?
child_assays.any?
else
sample_type&.linked_sample_attributes&.any?
end
end

# Fetches the assay which is linked through linked_sample_attributes (Single Page specific method)
def linked_assay
sample_type.linked_sample_attributes
.select { |lsa| lsa.isa_tag.nil? && lsa.title.include?('Input') }
.first&.sample_type&.assays&.first
def next_linked_child_assay
return unless has_linked_child_assay?

if is_assay_stream?
previous_linked_sample_type&.linked_sample_attributes&.detect { |sa| sa.isa_tag.nil? && sa.title.include?('Input') }&.sample_type&.assays&.first
else
sample_type.linked_sample_attributes.detect { |sa| sa.isa_tag.nil? && sa.title.include?('Input') }&.sample_type&.assays&.first
end
end

def default_contributor
Expand All @@ -95,7 +117,7 @@ def state_allows_delete?(*args)
end

def is_isa_json_compliant?
investigation.is_isa_json_compliant? && !sample_type.nil?
investigation.is_isa_json_compliant? && (!sample_type.nil? || is_assay_stream?)
end

# returns true if this is a modelling class of assay
Expand Down
29 changes: 19 additions & 10 deletions app/models/assay_class.rb
Original file line number Diff line number Diff line change
@@ -1,31 +1,40 @@
class AssayClass < ApplicationRecord

#this returns an instance of AssayClass according to one of the types "experimental" or "modelling"
#if there is not a match nil is returned
def self.for_type type
keys={"experimental"=>"EXP","modelling"=>"MODEL"}
return AssayClass.find_by(key: keys[type])
# this returns an instance of AssayClass according to one of the constants defined in seek/isa/assay_class.rb
# if there is not a match nil is returned
def self.for_type(type)
AssayClass.find_by(key: type)
end

def self.experimental
self.for_type('experimental')
for_type('EXP')
end

def self.modelling
self.for_type('modelling')
for_type('MODEL')

end

def self.assay_stream
for_type('STREAM')
end

def is_modelling?
key == "MODEL"
key == 'MODEL'
end

def is_experimental?
key == 'EXP'
end

def is_assay_stream?
key == 'STREAM'
end

LONG_KEYS = { 'EXP': 'Experimental Assay', 'MODEL': 'Modelling Analysis', 'STREAM': 'Assay Stream' }.freeze

# for cases where a longer more descriptive key is useful, but can't rely on the title
# which may have been changed over time
def long_key
{'EXP'=>'Experimental Assay','MODEL'=>'Modelling Analysis'}[key]
LONG_KEYS[key.to_sym]
end
end
4 changes: 4 additions & 0 deletions app/models/study.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ class Study < ApplicationRecord
has_many "related_#{type.pluralize}".to_sym, -> { distinct }, through: :assays, source: type.pluralize.to_sym
end

def assay_streams
assays.select(&:is_assay_stream?)
end

def assets
related_data_files + related_sops + related_models + related_publications + related_documents
end
Expand Down
Loading

0 comments on commit 492cfdb

Please sign in to comment.