From 389ee7ea43148e7e35a9f1a17b6e6e1a428366ba Mon Sep 17 00:00:00 2001 From: zmagod Date: Fri, 22 Jul 2016 14:31:09 +0200 Subject: [PATCH 1/8] start fixing modules --- app/helpers/permission_helper.rb | 22 +++++------ app/models/experiment.rb | 5 +++ app/models/my_module.rb | 10 +++-- app/models/project.rb | 68 ++++++++++++++++++-------------- 4 files changed, 61 insertions(+), 44 deletions(-) diff --git a/app/helpers/permission_helper.rb b/app/helpers/permission_helper.rb index a09d00756..251675e15 100644 --- a/app/helpers/permission_helper.rb +++ b/app/helpers/permission_helper.rb @@ -122,7 +122,7 @@ module PermissionHelper ] do |proxy, *args, &block| if args[0] my_module = args[0] - if my_module.active? and my_module.project.active? + if my_module.active? and my_module.experiment.project.active? proxy.call(*args, &block) else false @@ -334,11 +334,11 @@ module PermissionHelper end def can_view_module(my_module) - can_view_project(my_module.project) + can_view_project(my_module.experiment.project) end def can_edit_module(my_module) - is_user_or_higher_of_project(my_module.project) + is_user_or_higher_of_project(my_module.experiment.project) end def can_archive_module(my_module) @@ -350,7 +350,7 @@ module PermissionHelper end def can_edit_tags_for_module(my_module) - is_user_or_higher_of_project(my_module.project) + is_user_or_higher_of_project(my_module.experiment.project) end def can_add_tag_to_module(my_module) @@ -362,11 +362,11 @@ module PermissionHelper end def can_view_module_info(my_module) - can_view_project(my_module.project) + can_view_project(my_module.experiment.project) end def can_view_module_users(my_module) - can_view_project(my_module.project) + can_view_project(my_module.experiment.project) end def can_edit_users_on_module(my_module) @@ -386,24 +386,24 @@ module PermissionHelper end def can_view_module_activities(my_module) - is_member_of_project(my_module.project) + is_member_of_project(my_module.experiment.project) end def can_view_module_comments(my_module) - can_view_project(my_module.project) + can_view_project(my_module.experiment.project) end def can_add_comment_to_module(my_module) - is_technician_or_higher_of_project(my_module.project) + is_technician_or_higher_of_project(my_module.experiment.project) end def can_view_module_samples(my_module) can_view_module(my_module) and - can_view_samples(my_module.project.organization) + can_view_samples(my_module.experiment.project.organization) end def can_view_module_archive(my_module) - is_user_or_higher_of_project(my_module.project) + is_user_or_higher_of_project(my_module.experiment.project) end # ---- RESULTS PERMISSIONS ---- diff --git a/app/models/experiment.rb b/app/models/experiment.rb index 5b9b06e20..70d5f91ff 100644 --- a/app/models/experiment.rb +++ b/app/models/experiment.rb @@ -22,4 +22,9 @@ class Experiment < ActiveRecord::Base experiment.validates :archived_by, presence: true experiment.validates :archived_on, presence: true end + + def modules_without_group + MyModule.where(experiment_id: id).where(my_module_group: nil) + .where(archived: false) + end end diff --git a/app/models/my_module.rb b/app/models/my_module.rb index 6bac4d9b1..0cac4e052 100644 --- a/app/models/my_module.rb +++ b/app/models/my_module.rb @@ -52,12 +52,14 @@ class MyModule < ActiveRecord::Base if include_archived new_query = MyModule .distinct - .where("my_modules.project_id IN (?)", project_ids) + .joins(:experiment) + .where("experiment.project_id IN (?)", project_ids) .where_attributes_like([:name, :description], a_query) else new_query = MyModule .distinct - .where("my_modules.project_id IN (?)", project_ids) + .joins(:experiment) + .where("experiment.project_id IN (?)", project_ids) .where("my_modules.archived = ?", false) .where_attributes_like([:name, :description], a_query) end @@ -285,7 +287,7 @@ class MyModule < ActiveRecord::Base # Copy the module clone = MyModule.new( name: self.name, - project: self.project, + experiment: self.experiment, description: self.description, x: self.x, y: self.y) @@ -318,7 +320,7 @@ class MyModule < ActiveRecord::Base # Find an empty position for the restored module. It's # basically a first empty row with x=0. def get_new_position - if project.blank? + if project.experiment.blank? return { x: 0, y: 0 } end diff --git a/app/models/project.rb b/app/models/project.rb index de59771f6..1793e739e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -89,12 +89,24 @@ class Project < ActiveRecord::Base .limit(per_page) end + def project_my_modules + experiments.map{ |exp| exp.my_modules.take} + end + def active_modules - self.my_modules.where(:archived => false) + experiments.map do |exp| + exp.my_modules + .where(:archived => false) + .take + end end def archived_modules - self.my_modules.where(:archived => true) + experiments.map do |exp| + exp.my_modules + .where(:archived => true) + .take + end end def unassigned_users @@ -110,9 +122,9 @@ class Project < ActiveRecord::Base if role.blank? return MyModule.none elsif role == "owner" - return self.my_modules.where(archived: false) + return self.active_modules else - return self.my_modules.where(archived: false) + return self.active_modules .joins(:user_my_modules) .where("user_my_modules.user_id IN (?)", user.id) .distinct @@ -127,19 +139,17 @@ class Project < ActiveRecord::Base return (self.user_projects.select { |up| up.user == user }).first.role end - def modules_without_group - MyModule.where(project_id: id).where(my_module_group: nil) - .where(archived: false) - end - def active_module_groups - self.my_module_groups.joins(:my_modules) + self.experiments.each do |exp| + exp.my_module_groups.joins(:my_modules) .where('my_modules.archived = ?', false) .distinct + .take + end end def assigned_samples - Sample.joins(:my_modules).where(my_modules: {id: my_modules} ) + Sample.joins(:my_modules).where(my_modules: {id: project_my_modules} ) end def unassigned_samples(assigned_samples) @@ -148,7 +158,7 @@ class Project < ActiveRecord::Base def space_taken st = 0 - my_modules.find_each do |my_module| + project_my_modules.find_each do |my_module| st += my_module.space_taken end st @@ -254,23 +264,23 @@ class Project < ActiveRecord::Base # Archive all modules. Receives an array of module integer IDs. def archive_modules(module_ids) module_ids.each do |m_id| - my_module = my_modules.find_by_id(m_id) + my_module = project_my_modules.find_by_id(m_id) unless my_module.blank? my_module.archive! end end - my_modules.reload + project_my_modules.reload end # Archive all modules. Receives an array of module integer IDs and current user. def archive_modules(module_ids, current_user) module_ids.each do |m_id| - my_module = my_modules.find_by_id(m_id) + my_module = project_my_modules.find_by_id(m_id) unless my_module.blank? my_module.archive!(current_user) end end - my_modules.reload + project_my_modules.reload end # Add modules, and returns a map of "virtual" IDs with @@ -333,7 +343,7 @@ class Project < ActiveRecord::Base dg = RGL::DirectedAdjacencyGraph.new connections.each do |a,b| # Check if both vertices exist - if (my_modules.find_all {|m| [a.to_i, b.to_i].include? m.id }).count == 2 + if (project_my_modules.find_all {|m| [a.to_i, b.to_i].include? m.id }).count == 2 dg.add_edge(a, b) end end @@ -348,13 +358,13 @@ class Project < ActiveRecord::Base # but keep a copy of previous state previous_sources = {} previous_sources.default = [] - my_modules.each do |m| + project_my_modules.each do |m| previous_sources[m.id] = [] m.inputs.each do |c| previous_sources[m.id] << c.from end end - my_modules.each do |m| + project_my_modules.each do |m| unless m.outputs.destroy_all raise ActiveRecord::ActiveRecordError end @@ -374,8 +384,8 @@ class Project < ActiveRecord::Base visited = [] # Assign samples to all new downstream modules filtered_edges.each do |a, b| - source = my_modules.find(a.to_i) - target = my_modules.find(b.to_i) + source = project_my_modules.find(a.to_i) + target = project_my_modules.find(b.to_i) # Do this only for new edges if previous_sources[target.id].exclude?(source) # Go as high upstream as new edges take us @@ -386,7 +396,7 @@ class Project < ActiveRecord::Base # Save topological order of modules (for modules without workflow, # leave them unordered) - my_modules.each do |m| + project_my_modules.each do |m| if topsort.include? m.id.to_s m.workflow_order = topsort.find_index(m.id.to_s) else @@ -396,14 +406,14 @@ class Project < ActiveRecord::Base end # Make sure to reload my modules, which now have updated connections and samples - my_modules.reload + project_my_modules.reload true end # When connections are deleted, unassign samples that # are not inherited anymore def unassign_samples_from_old_downstream_modules(sources) - my_modules.each do |my_module| + project_my_modules.each do |my_module| sources[my_module.id].each do |s| # Only do this for newly deleted connections if s.outputs.map{|i| i.to}.exclude? my_module @@ -456,17 +466,17 @@ class Project < ActiveRecord::Base raise ActiveRecord::ActiveRecordError end end - my_modules.reload + project_my_modules.reload end # Normalize module positions in this project. def normalize_module_positions # This method normalizes module positions so x-s and y-s # are all positive - x_diff = (my_modules.collect { |m| m.x }).min - y_diff = (my_modules.collect { |m| m.y }).min + x_diff = (project_my_modules.collect { |m| m.x }).min + y_diff = (project_my_modules.collect { |m| m.y }).min - my_modules.each do |m| + project_my_modules.each do |m| unless m.update_attribute(:x, m.x - x_diff) and m.update_attribute(:y, m.y - y_diff) @@ -484,7 +494,7 @@ class Project < ActiveRecord::Base dg = RGL::DirectedAdjacencyGraph[] group_ids = Set.new - my_modules.where(archived: :false).each do |m| + active_modules.each do |m| unless m.my_module_group.blank? group_ids << m.my_module_group.id end From 7c9a0bc2bb821bcd584c644501542ba30aebcd35 Mon Sep 17 00:00:00 2001 From: zmagod Date: Fri, 22 Jul 2016 15:36:48 +0200 Subject: [PATCH 2/8] fixed models --- app/models/experiment.rb | 5 ----- app/models/my_module.rb | 4 ++++ app/models/my_module_group.rb | 3 ++- app/models/organization.rb | 2 +- app/models/project.rb | 8 +++++++- app/models/step.rb | 2 +- app/models/user_project.rb | 2 +- 7 files changed, 16 insertions(+), 10 deletions(-) diff --git a/app/models/experiment.rb b/app/models/experiment.rb index 70d5f91ff..5b9b06e20 100644 --- a/app/models/experiment.rb +++ b/app/models/experiment.rb @@ -22,9 +22,4 @@ class Experiment < ActiveRecord::Base experiment.validates :archived_by, presence: true experiment.validates :archived_on, presence: true end - - def modules_without_group - MyModule.where(experiment_id: id).where(my_module_group: nil) - .where(archived: false) - end end diff --git a/app/models/my_module.rb b/app/models/my_module.rb index 0cac4e052..9d4a01048 100644 --- a/app/models/my_module.rb +++ b/app/models/my_module.rb @@ -311,6 +311,10 @@ class MyModule < ActiveRecord::Base project.log(final) end + # Check if the model has a group + def self.without_group(exp) + where(my_module_group: nil, archived: false, experiment_id: exp.id) + end private def create_blank_protocol diff --git a/app/models/my_module_group.rb b/app/models/my_module_group.rb index 4e62db544..311aa813f 100644 --- a/app/models/my_module_group.rb +++ b/app/models/my_module_group.rb @@ -29,7 +29,8 @@ class MyModuleGroup < ActiveRecord::Base new_query = MyModuleGroup .distinct - .where("my_module_groups.project_id IN (?)", project_ids) + .joins(:experiment) + .where("experiment.project_id IN (?)", project_ids) .where_attributes_like(:name, a_query) # Show all results if needed diff --git a/app/models/organization.rb b/app/models/organization.rb index 6637710d4..b09720a12 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -257,7 +257,7 @@ class Organization < ActiveRecord::Base projects.includes( my_modules: { protocols: { steps: :assets }, results: { result_asset: :asset } } ).find_each do |project| - project.my_modules.find_each do |my_module| + project.project_my_modules.find_each do |my_module| my_module.protocol.steps.find_each do |step| step.assets.find_each { |asset| st += asset.estimated_size } end diff --git a/app/models/project.rb b/app/models/project.rb index 1793e739e..e039ba6ba 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -117,6 +117,12 @@ class Project < ActiveRecord::Base .where("users.id NOT IN (?)", UserProject.where(project: self).select(:id).distinct) end + def modules_without_group + self.experiments.map do |exp| + MyModule.where(experiment_id: exp.id).where(my_module_group: nil).where(archived: false) + end + end + def assigned_modules(user) role = self.user_role(user) if role.blank? @@ -140,7 +146,7 @@ class Project < ActiveRecord::Base end def active_module_groups - self.experiments.each do |exp| + experiments.map do |exp| exp.my_module_groups.joins(:my_modules) .where('my_modules.archived = ?', false) .distinct diff --git a/app/models/step.rb b/app/models/step.rb index eca511b0f..51b83b498 100644 --- a/app/models/step.rb +++ b/app/models/step.rb @@ -124,7 +124,7 @@ class Step < ActiveRecord::Base if (protocol.my_module.present?) then Activity.create( type_of: :destroy_step, - project: protocol.my_module.project, + project: protocol.my_module.experiment.project, my_module: protocol.my_module, user: @current_user, message: I18n.t( diff --git a/app/models/user_project.rb b/app/models/user_project.rb index e839a92c9..b462e48f2 100644 --- a/app/models/user_project.rb +++ b/app/models/user_project.rb @@ -17,7 +17,7 @@ class UserProject < ActiveRecord::Base def destroy_associations # Destroy the user from all project's modules - project.my_modules.each do |my_module| + project.project_my_modules.each do |my_module| um2 = (my_module.user_my_modules.select { |um| um.user == self.user }).first if um2.present? um2.destroy From b3c61cfa41ba86d011d4d04f03396a56634021da Mon Sep 17 00:00:00 2001 From: zmagod Date: Mon, 25 Jul 2016 09:13:04 +0200 Subject: [PATCH 3/8] fixed project_my_modules method --- app/models/my_module.rb | 7 +++---- app/models/project.rb | 15 +++------------ 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/app/models/my_module.rb b/app/models/my_module.rb index 9d4a01048..426f35bdc 100644 --- a/app/models/my_module.rb +++ b/app/models/my_module.rb @@ -53,15 +53,14 @@ class MyModule < ActiveRecord::Base new_query = MyModule .distinct .joins(:experiment) - .where("experiment.project_id IN (?)", project_ids) + .where('"experiments"."project_id" IN (?)', project_ids) .where_attributes_like([:name, :description], a_query) else new_query = MyModule .distinct .joins(:experiment) - .where("experiment.project_id IN (?)", project_ids) - .where("my_modules.archived = ?", false) - .where_attributes_like([:name, :description], a_query) + .where( '"experiments"."project_id" IN (?) AND "my_modules"."archived" = ?', project_ids, false) + .where_attributes_like('"my_modules"."name"', '"my_modules"."description"') end # Show all results if needed diff --git a/app/models/project.rb b/app/models/project.rb index e039ba6ba..828cb7044 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -27,7 +27,6 @@ class Project < ActiveRecord::Base def self.search(user, include_archived, query = nil, page = 1) - if query a_query = query.strip .gsub("_","\\_") @@ -90,23 +89,15 @@ class Project < ActiveRecord::Base end def project_my_modules - experiments.map{ |exp| exp.my_modules.take} + experiments.collect{ |exp| exp.my_modules }.first end def active_modules - experiments.map do |exp| - exp.my_modules - .where(:archived => false) - .take - end + project_my_modules.where(:archived => false) end def archived_modules - experiments.map do |exp| - exp.my_modules - .where(:archived => true) - .take - end + project_my_modules.where(:archived => true) end def unassigned_users From 426bce48b2675fa9a6b9dd4288c92b8f7ee61d7a Mon Sep 17 00:00:00 2001 From: zmagod Date: Mon, 25 Jul 2016 09:31:40 +0200 Subject: [PATCH 4/8] fixed permission_helper --- app/helpers/permission_helper.rb | 80 ++++++++++++++++---------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/app/helpers/permission_helper.rb b/app/helpers/permission_helper.rb index 251675e15..4b520e359 100644 --- a/app/helpers/permission_helper.rb +++ b/app/helpers/permission_helper.rb @@ -370,15 +370,15 @@ module PermissionHelper end def can_edit_users_on_module(my_module) - is_owner_of_project(my_module.project) + is_owner_of_project(my_module.experiment.project) end def can_add_user_to_module(my_module) - is_owner_of_project(my_module.project) + is_owner_of_project(my_module.experiment.project) end def can_remove_user_from_module(my_module) - is_owner_of_project(my_module.project) + is_owner_of_project(my_module.experiment.project) end def can_view_module_protocols(my_module) @@ -409,61 +409,61 @@ module PermissionHelper # ---- RESULTS PERMISSIONS ---- def can_view_results_in_module(my_module) - can_view_project(my_module.project) + can_view_project(my_module.experiment.project) end def can_view_or_download_result_assets(my_module) - is_member_of_project(my_module.project) || can_view_project(my_module.project) + is_member_of_project(my_module.experiment.project) || can_view_project(my_module.experiment.project) end def can_view_result_comments(my_module) - can_view_project(my_module.project) + can_view_project(my_module.experiment.project) end def can_add_result_comment_in_module(my_module) - is_technician_or_higher_of_project(my_module.project) + is_technician_or_higher_of_project(my_module.experiment.project) end # ---- RESULT TEXT PERMISSIONS ---- def can_create_result_text_in_module(my_module) - is_user_or_higher_of_project(my_module.project) + is_user_or_higher_of_project(my_module.experiment.project) end def can_edit_result_text_in_module(my_module) - is_user_or_higher_of_project(my_module.project) + is_user_or_higher_of_project(my_module.experiment.project) end def can_archive_result_text_in_module(my_module) - is_owner_of_project(my_module.project) + is_owner_of_project(my_module.experiment.project) end # ---- RESULT TABLE PERMISSIONS ---- def can_create_result_table_in_module(my_module) - is_user_or_higher_of_project(my_module.project) + is_user_or_higher_of_project(my_module.experiment.project) end def can_edit_result_table_in_module(my_module) - is_user_or_higher_of_project(my_module.project) + is_user_or_higher_of_project(my_module.experiment.project) end def can_archive_result_table_in_module(my_module) - is_owner_of_project(my_module.project) + is_owner_of_project(my_module.experiment.project) end # ---- RESULT ASSET PERMISSIONS ---- def can_create_result_asset_in_module(my_module) - is_user_or_higher_of_project(my_module.project) + is_user_or_higher_of_project(my_module.experiment.project) end def can_edit_result_asset_in_module(my_module) - is_user_or_higher_of_project(my_module.project) + is_user_or_higher_of_project(my_module.experiment.project) end def can_archive_result_asset_in_module(my_module) - is_owner_of_project(my_module.project) + is_owner_of_project(my_module.experiment.project) end # ---- REPORTS PERMISSIONS ---- @@ -507,11 +507,11 @@ module PermissionHelper end def can_add_samples_to_module(my_module) - is_technician_or_higher_of_project(my_module.project) + is_technician_or_higher_of_project(my_module.experiment.project) end def can_delete_samples_from_module(my_module) - is_technician_or_higher_of_project(my_module.project) + is_technician_or_higher_of_project(my_module.experiment.project) end # ---- SAMPLE TYPES PERMISSIONS ---- @@ -562,7 +562,7 @@ module PermissionHelper protocol.added_by == current_user elsif protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and can_view_module(my_module) + my_module.active? and my_module.experiment.project.active? and can_view_module(my_module) else false end @@ -619,7 +619,7 @@ module PermissionHelper def can_revert_protocol(protocol) if protocol.linked? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_user_or_higher_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) else false end @@ -628,7 +628,7 @@ module PermissionHelper def can_update_protocol_from_parent(protocol) if protocol.linked? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_user_or_higher_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) else false end @@ -637,7 +637,7 @@ module PermissionHelper def can_load_protocol_from_repository(protocol, source) if can_view_protocol(source) my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_user_or_higher_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) else false end @@ -649,9 +649,9 @@ module PermissionHelper parent = protocol.parent my_module.active? and - my_module.project.active? and + my_module.experiment.project.active? and is_normal_user_or_admin_of_organization(parent.organization) and - is_user_or_higher_of_project(my_module.project) and + is_user_or_higher_of_project(my_module.experiment.project) and (parent.in_repository_public? or parent.in_repository_private?) and parent.added_by == current_user else @@ -662,7 +662,7 @@ module PermissionHelper # ---- STEPS PERMISSIONS ---- def can_load_protocol_into_module(my_module) - is_user_or_higher_of_project(my_module.project) + is_user_or_higher_of_project(my_module.experiment.project) end def can_export_protocol_from_module(my_module) @@ -670,18 +670,18 @@ module PermissionHelper end def can_copy_protocol_to_repository(my_module) - is_normal_user_or_admin_of_organization(my_module.project.organization) + is_normal_user_or_admin_of_organization(my_module.experiment.project.organization) end def can_link_copied_protocol_in_repository(protocol) can_copy_protocol_to_repository(protocol.my_module) and - is_user_or_higher_of_project(protocol.my_module.project) + is_user_or_higher_of_project(protocol.my_module.experiment.project) end def can_view_steps_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and can_view_module(my_module) + my_module.active? and my_module.experiment.project.active? and can_view_module(my_module) elsif protocol.in_repository? protocol.in_repository_active? and can_view_protocol(protocol) else @@ -692,7 +692,7 @@ module PermissionHelper def can_create_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_user_or_higher_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) elsif protocol.in_repository? protocol.in_repository_active? and can_edit_protocol(protocol) else @@ -703,7 +703,7 @@ module PermissionHelper def can_reorder_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_user_or_higher_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) elsif protocol.in_repository? protocol.in_repository_active? and can_edit_protocol(protocol) else @@ -720,7 +720,7 @@ module PermissionHelper def can_edit_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_user_or_higher_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) elsif protocol.in_repository? protocol.in_repository_active? and can_edit_protocol(protocol) else @@ -731,7 +731,7 @@ module PermissionHelper def can_delete_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_owner_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_owner_of_project(my_module.experiment.project) elsif protocol.in_repository? protocol.in_repository_active? and can_edit_protocol(protocol) else @@ -742,7 +742,7 @@ module PermissionHelper def can_view_step_comments(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and can_view_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and can_view_project(my_module.experiment.project) else # In repository, comments are disabled false @@ -752,7 +752,7 @@ module PermissionHelper def can_add_step_comment_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_technician_or_higher_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_technician_or_higher_of_project(my_module.experiment.project) else # In repository, user cannot complete steps false @@ -762,8 +762,8 @@ module PermissionHelper def can_view_or_download_step_assets(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and - (is_member_of_project(my_module.project) || can_view_project(my_module.project)) + my_module.active? and my_module.experiment.project.active? and + (is_member_of_project(my_module.experiment.project) || can_view_project(my_module.experiment.project)) elsif protocol.in_repository? protocol.in_repository_active? and can_view_protocol(protocol) else @@ -774,7 +774,7 @@ module PermissionHelper def can_complete_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_technician_or_higher_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_technician_or_higher_of_project(my_module.experiment.project) else # In repository, user cannot complete steps false @@ -784,7 +784,7 @@ module PermissionHelper def can_uncomplete_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_user_or_higher_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) else # In repository, user cannot complete steps false @@ -794,7 +794,7 @@ module PermissionHelper def can_check_checkbox(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_technician_or_higher_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_technician_or_higher_of_project(my_module.experiment.project) else # In repository, user cannot check checkboxes false @@ -804,7 +804,7 @@ module PermissionHelper def can_uncheck_checkbox(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_user_or_higher_of_project(my_module.project) + my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) else # In repository, user cannot check checkboxes false From 18d66ece56784c54b02aef7cb2bb2d07607fa44c Mon Sep 17 00:00:00 2001 From: zmagod Date: Mon, 25 Jul 2016 11:25:10 +0200 Subject: [PATCH 5/8] migrated model related functions to experiment.rb [fixes: SCI-31] --- app/models/experiment.rb | 436 ++++++++++++++++++++++++++++++++++++++ app/models/my_module.rb | 27 ++- app/models/project.rb | 443 +-------------------------------------- 3 files changed, 450 insertions(+), 456 deletions(-) diff --git a/app/models/experiment.rb b/app/models/experiment.rb index 5b9b06e20..468dfcf21 100644 --- a/app/models/experiment.rb +++ b/app/models/experiment.rb @@ -22,4 +22,440 @@ class Experiment < ActiveRecord::Base experiment.validates :archived_by, presence: true experiment.validates :archived_on, presence: true end + + def modules_without_group + MyModule.where(experiment_id: id).where(my_module_group: nil) + .where(archived: false) + end + + def active_module_groups + self.my_module_groups.joins(:my_modules) + .where('my_modules.archived = ?', false) + .distinct + end + + def assigned_modules(user) + role = self.project.user_role(user) + if role.blank? + return MyModule.none + elsif role == "owner" + return self.active_modules + else + return self.active_modules + .joins(:user_my_modules) + .where("user_my_modules.user_id IN (?)", user.id) + .distinct + end + end + + def active_modules + my_modules.where(:archived => false) + end + + def archived_modules + my_modules.where(:archived => true) + end + + def assigned_samples + Sample.joins(:my_modules).where(my_modules: {id: my_modules} ) + end + + def unassigned_samples(assigned_samples) + Sample.where(organization_id: organization).where.not(id: assigned_samples) + end + + def update_canvas( + to_archive, + to_add, + to_rename, + to_clone, + connections, + positions, + current_user, + module_groups + ) + cloned_modules = [] + begin + Experiment.transaction do + # First, add new modules + new_ids, cloned_pairs, originals = add_modules( + to_add, to_clone, current_user) + cloned_modules = cloned_pairs.collect { |mn, _| mn } + + # Rename modules + rename_modules(to_rename) + + # Add activities that modules were created + originals.each do |m| + Activity.create( + type_of: :create_module, + user: current_user, + project: selfproject, + my_module: m, + message: I18n.t( + "activities.create_module", + user: current_user.full_name, + module: m.name + ) + ) + end + + # Add activities that modules were cloned + cloned_pairs.each do |mn, mo| + Activity.create( + type_of: :clone_module, + project: mn.experiment.project, + my_module: mn, + user: current_user, + message: I18n.t( + "activities.clone_module", + user: current_user.full_name, + module_new: mn.name, + module_original: mo.name + ) + ) + end + + # Then, archive modules that need to be archived + archive_modules(to_archive, current_user) + + # Update connections, positions & module group variables + # with actual IDs retrieved from the new modules creation + updated_connections = [] + connections.each do |a,b| + updated_connections << [new_ids.fetch(a, a), new_ids.fetch(b, b)] + end + updated_positions = Hash.new + positions.each do |id, pos| + updated_positions[new_ids.fetch(id, id)] = pos + end + updated_module_groups = {} + module_groups.each do |id, name| + updated_module_groups[new_ids.fetch(id, id)] = name + end + + # Update connections + update_module_connections(updated_connections) + + # Update module positions (no validation needed here) + update_module_positions(updated_positions) + + # Normalize module positions + normalize_module_positions + + # Finally, update module groups + update_module_groups(updated_module_groups, current_user) + end + rescue ActiveRecord::ActiveRecordError, ArgumentError, ActiveRecord::RecordNotSaved + return false + end + + return true + end + + private + + # Archive all modules. Receives an array of module integer IDs. + def archive_modules(module_ids) + module_ids.each do |m_id| + my_module = self.my_modules.find_by_id(m_id) + unless my_module.blank? + my_module.archive! + end + end + modules.reload + end + + # Archive all modules. Receives an array of module integer IDs and current user. + def archive_modules(module_ids, current_user) + module_ids.each do |m_id| + my_module = self.my_modules.find_by_id(m_id) + unless my_module.blank? + my_module.archive!(current_user) + end + end + my_modules.reload + end + + # Add modules, and returns a map of "virtual" IDs with + # actual IDs of saved modules. + # to_add is an array of hashes, each containing 'name', + # 'x', 'y' and 'id'. + # to_clone is a hash, storing new cloned modules as keys, + # and original modules as values. + def add_modules(to_add, to_clone, current_user) + originals = [] + cloned_pairs = {} + ids_map = Hash.new + to_add.each do |m| + original = MyModule.find_by_id(to_clone.fetch(m[:id], nil)) + if original.present? then + my_module = original.deep_clone(current_user) + cloned_pairs[my_module] = original + else + my_module = MyModule.new( + experiment: self) + originals << my_module + end + + my_module.name = m[:name] + my_module.x = m[:x] + my_module.y = m[:y] + my_module.created_by = current_user + my_module.last_modified_by = current_user + my_module.save! + + ids_map[m[:id]] = my_module.id.to_s + end + my_modules.reload + return ids_map, cloned_pairs, originals + end + + # Rename modules; this method accepts a map where keys + # represent IDs of modules, and values new names for + # such modules. If a module with given ID doesn't exist, + # it's obviously not updated. + def rename_modules(to_rename) + to_rename.each do |id, new_name| + my_module = MyModule.find_by_id(id) + if my_module.present? + my_module.name = new_name + my_module.save! + end + end + end + + # Update connections for all modules in this project. + # Input is an array of arrays, where first element represents + # source node, and second element represents target node. + # Example input: [ [1, 2], [2, 3], [4, 5], [2, 5] ] + def update_module_connections(connections) + require 'rgl/base' + require 'rgl/adjacency' + require 'rgl/topsort' + + dg = RGL::DirectedAdjacencyGraph.new + connections.each do |a,b| + # Check if both vertices exist + if (my_modules.find_all {|m| [a.to_i, b.to_i].include? m.id }).count == 2 + dg.add_edge(a, b) + end + end + + # Check if cycles exist! + topsort = dg.topsort_iterator.to_a + if topsort.length == 0 and dg.edges.size > 1 + raise ArgumentError, "Cycles exist." + end + + # First, delete existing connections + # but keep a copy of previous state + previous_sources = {} + previous_sources.default = [] + my_modules.each do |m| + previous_sources[m.id] = [] + m.inputs.each do |c| + previous_sources[m.id] << c.from + end + end + self.my_modules.each do |m| + unless m.outputs.destroy_all + raise ActiveRecord::ActiveRecordError + end + end + + + # Add new connections + filtered_edges = dg.edges.collect { |e| [e.source, e.target] } + filtered_edges.each do |a, b| + Connection.create!(:input_id => b, :output_id => a) + end + + # Unassign samples from former downstream modules + # for all destroyed connections + unassign_samples_from_old_downstream_modules(previous_sources) + + visited = [] + # Assign samples to all new downstream modules + filtered_edges.each do |a, b| + source = self.my_modules.find(a.to_i) + target = self.my_modules.find(b.to_i) + # Do this only for new edges + if previous_sources[target.id].exclude?(source) + # Go as high upstream as new edges take us + # and then assign samples to all downsteam samples + assign_samples_to_new_downstream_modules(previous_sources, visited, source) + end + end + + # Save topological order of modules (for modules without workflow, + # leave them unordered) + self.my_modules.each do |m| + if topsort.include? m.id.to_s + m.workflow_order = topsort.find_index(m.id.to_s) + else + m.workflow_order = -1 + end + m.save! + end + + # Make sure to reload my modules, which now have updated connections and samples + self.my_modules.reload + true + end + + # When connections are deleted, unassign samples that + # are not inherited anymore + def unassign_samples_from_old_downstream_modules(sources) + self.my_modules.each do |my_module| + sources[my_module.id].each do |s| + # Only do this for newly deleted connections + if s.outputs.map{|i| i.to}.exclude? my_module + my_module.get_downstream_modules.each do |dm| + # Get unique samples for all upstream modules + um = dm.get_upstream_modules + um.shift # remove current module + ums = um.map{|m| m.samples}.flatten.uniq + s.samples.each do |sample| + dm.samples.delete(sample) if ums.exclude? sample + end + end + end + end + end + end + + # Assign samples to new connections recursively + def assign_samples_to_new_downstream_modules(sources, visited, my_module) + # If samples are already assigned for this module, stop going upstream + if visited.include? (my_module) + return + end + visited << my_module + # Edge case, when module is source or it doesn't have any new input connections + if my_module.inputs.blank? or ( + my_module.inputs.map{|c| c.from} - + sources[my_module.id] + ).empty? + my_module.get_downstream_modules.each do |dm| + new_samples = my_module.samples.select { |el| dm.samples.exclude?(el) } + dm.samples.push(*new_samples) + end + else + my_module.inputs.each do |input| + # Go upstream for new in connections + if sources[my_module.id].exclude?(input.from) + assign_samples_to_new_downstream_modules(input.from) + end + end + end + end + + # Updates positions of modules. + # Input is a map where keys are module IDs, and values are + # hashes like { x: , y: }. + def update_module_positions(positions) + positions.each do |id, pos| + unless MyModule.update(id, x: pos[:x], y: pos[:y]) + raise ActiveRecord::ActiveRecordError + end + end + self.my_modules.reload + end + + # Normalize module positions in this project. + def normalize_module_positions + # This method normalizes module positions so x-s and y-s + # are all positive + x_diff = (self.my_modules.collect { |m| m.x }).min + y_diff = (self.my_modules.collect { |m| m.y }).min + + self.my_modules.each do |m| + unless + m.update_attribute(:x, m.x - x_diff) and + m.update_attribute(:y, m.y - y_diff) + raise ActiveRecord::ActiveRecordError + end + end + end + + # Recalculate module groups in this project. Input is + # a hash of module ids and their corresponding module names. + def update_module_groups(module_groups, current_user) + require 'rgl/base' + require 'rgl/adjacency' + require 'rgl/connected_components' + + dg = RGL::DirectedAdjacencyGraph[] + group_ids = Set.new + active_modules.each do |m| + unless m.my_module_group.blank? + group_ids << m.my_module_group.id + end + unless dg.has_vertex? m.id + dg.add_vertex m.id + end + m.outputs.each do |o| + dg.add_edge m.id, o.to.id + end + end + workflows = [] + dg.to_undirected.each_connected_component { |w| workflows << w } + + # Retrieve maximum allowed module group name + max_length = (MyModuleGroup.validators_on(:name).select { |v| v.class == ActiveModel::Validations::LengthValidator }).first.options[:maximum] + # For each workflow, generate new names + new_index = 1 + wf_names = [] + suffix = I18n.t("my_module_groups.new.suffix") + cut_index = -(suffix.length + 1) + workflows.each do |w| + modules = MyModule.find(w) + + # Get an array of module names + names = [] + modules.each do |m| + names << module_groups.fetch(m.id.to_s, "") + end + names = names.uniq + name = (names.select { |v| v != "" }).join(", ") + + if w.length <= 1 + name = nil + elsif name.blank? + name = I18n.t("my_module_groups.new.name", index: new_index) + new_index += 1 + while MyModuleGroup.find_by(name: name).present? + name = I18n.t("my_module_groups.new.name", index: new_index) + new_index += 1 + end + elsif name.length > max_length + # If length is too long, shorten it + name = name[0..(max_length + cut_index)] + suffix + end + + wf_names << name + end + + # Remove any existing module groups from modules + unless MyModuleGroup.destroy_all(:id => group_ids.to_a) + raise ActiveRecord::ActiveRecordError + end + + # Second, create new groups + workflows.each_with_index do |w, i| + # Single modules are not considered part of any workflow + if w.length > 1 + group = MyModuleGroup.new( + name: wf_names[i], + project: self, + my_modules: MyModule.find(w)) + group.created_by = current_user + group.save! + end + end + + my_module_groups.reload + true + end end diff --git a/app/models/my_module.rb b/app/models/my_module.rb index 426f35bdc..28eeee962 100644 --- a/app/models/my_module.rb +++ b/app/models/my_module.rb @@ -52,15 +52,14 @@ class MyModule < ActiveRecord::Base if include_archived new_query = MyModule .distinct - .joins(:experiment) - .where('"experiments"."project_id" IN (?)', project_ids) + .where("my_modules.project_id IN (?)", project_ids) .where_attributes_like([:name, :description], a_query) else new_query = MyModule .distinct - .joins(:experiment) - .where( '"experiments"."project_id" IN (?) AND "my_modules"."archived" = ?', project_ids, false) - .where_attributes_like('"my_modules"."name"', '"my_modules"."description"') + .where("my_modules.project_id IN (?)", project_ids) + .where("my_modules.archived = ?", false) + .where_attributes_like([:name, :description], a_query) end # Show all results if needed @@ -118,20 +117,22 @@ class MyModule < ActiveRecord::Base User.find_by_sql( "SELECT DISTINCT users.id, users.full_name FROM users " + "INNER JOIN user_projects ON users.id = user_projects.user_id " + - "WHERE user_projects.project_id = #{project_id.to_s}" + + "INNER JOIN experiments ON experiments.project_id = user_projects.project_id " + + "WHERE experiments.id = #{experiment_id.to_s}" + " AND users.id NOT IN " + "(SELECT DISTINCT user_id FROM user_my_modules WHERE user_my_modules.my_module_id = #{id.to_s})" ) end def unassigned_samples - Sample.where(organization_id: project.organization).where.not(id: samples) + Sample.where(organization_id: experiment.project.organization).where.not(id: samples) end def unassigned_tags Tag.find_by_sql( "SELECT DISTINCT tags.id, tags.name, tags.color FROM tags " + - "WHERE tags.project_id = #{project_id.to_s} AND tags.id NOT IN " + + "INNER JOIN experiments ON experiments.project_id = tags.project_id " + + "WHERE experiments.id = #{experiment_id.to_s} AND tags.id NOT IN " + "(SELECT DISTINCT tag_id FROM my_module_tags WHERE my_module_tags.my_module_id = #{id.to_s})" ) end @@ -307,13 +308,9 @@ class MyModule < ActiveRecord::Base # Writes to user log. def log(message) final = "[%s] %s" % [name, message] - project.log(final) + experiment.project.log(final) end - # Check if the model has a group - def self.without_group(exp) - where(my_module_group: nil, archived: false, experiment_id: exp.id) - end private def create_blank_protocol @@ -323,12 +320,12 @@ class MyModule < ActiveRecord::Base # Find an empty position for the restored module. It's # basically a first empty row with x=0. def get_new_position - if project.experiment.blank? + if experiment.blank? return { x: 0, y: 0 } end new_y = 0 - positions = project.active_modules.collect{ |m| [m.x, m.y] } + positions = experiment.active_modules.collect{ |m| [m.x, m.y] } (0..10000).each do |n| unless positions.include? [0, n] new_y = n diff --git a/app/models/project.rb b/app/models/project.rb index 828cb7044..45600b7b1 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -88,18 +88,6 @@ class Project < ActiveRecord::Base .limit(per_page) end - def project_my_modules - experiments.collect{ |exp| exp.my_modules }.first - end - - def active_modules - project_my_modules.where(:archived => false) - end - - def archived_modules - project_my_modules.where(:archived => true) - end - def unassigned_users User .joins("INNER JOIN user_organizations ON users.id = user_organizations.user_id ") @@ -108,26 +96,6 @@ class Project < ActiveRecord::Base .where("users.id NOT IN (?)", UserProject.where(project: self).select(:id).distinct) end - def modules_without_group - self.experiments.map do |exp| - MyModule.where(experiment_id: exp.id).where(my_module_group: nil).where(archived: false) - end - end - - def assigned_modules(user) - role = self.user_role(user) - if role.blank? - return MyModule.none - elsif role == "owner" - return self.active_modules - else - return self.active_modules - .joins(:user_my_modules) - .where("user_my_modules.user_id IN (?)", user.id) - .distinct - end - end - def user_role(user) unless self.users.include? user return nil @@ -136,21 +104,8 @@ class Project < ActiveRecord::Base return (self.user_projects.select { |up| up.user == user }).first.role end - def active_module_groups - experiments.map do |exp| - exp.my_module_groups.joins(:my_modules) - .where('my_modules.archived = ?', false) - .distinct - .take - end - end - - def assigned_samples - Sample.joins(:my_modules).where(my_modules: {id: project_my_modules} ) - end - - def unassigned_samples(assigned_samples) - Sample.where(organization_id: organization).where.not(id: assigned_samples) + def project_my_modules + experiments.collect{ |exp| exp.my_modules }.first end def space_taken @@ -161,404 +116,10 @@ class Project < ActiveRecord::Base st end - def update_canvas( - to_archive, - to_add, - to_rename, - to_clone, - connections, - positions, - current_user, - module_groups - ) - cloned_modules = [] - begin - Project.transaction do - # First, add new modules - new_ids, cloned_pairs, originals = add_modules( - to_add, to_clone, current_user) - cloned_modules = cloned_pairs.collect { |mn, _| mn } - - # Rename modules - rename_modules(to_rename) - - # Add activities that modules were created - originals.each do |m| - Activity.create( - type_of: :create_module, - user: current_user, - project: self, - my_module: m, - message: I18n.t( - "activities.create_module", - user: current_user.full_name, - module: m.name - ) - ) - end - - # Add activities that modules were cloned - cloned_pairs.each do |mn, mo| - Activity.create( - type_of: :clone_module, - project: mn.project, - my_module: mn, - user: current_user, - message: I18n.t( - "activities.clone_module", - user: current_user.full_name, - module_new: mn.name, - module_original: mo.name - ) - ) - end - - # Then, archive modules that need to be archived - archive_modules(to_archive, current_user) - - # Update connections, positions & module group variables - # with actual IDs retrieved from the new modules creation - updated_connections = [] - connections.each do |a,b| - updated_connections << [new_ids.fetch(a, a), new_ids.fetch(b, b)] - end - updated_positions = Hash.new - positions.each do |id, pos| - updated_positions[new_ids.fetch(id, id)] = pos - end - updated_module_groups = {} - module_groups.each do |id, name| - updated_module_groups[new_ids.fetch(id, id)] = name - end - - # Update connections - update_module_connections(updated_connections) - - # Update module positions (no validation needed here) - update_module_positions(updated_positions) - - # Normalize module positions - normalize_module_positions - - # Finally, update module groups - update_module_groups(updated_module_groups, current_user) - end - rescue ActiveRecord::ActiveRecordError, ArgumentError, ActiveRecord::RecordNotSaved - return false - end - - return true - end - # Writes to user log. def log(message) final = "[%s] %s" % [name, message] organization.log(final) end - private - - # Archive all modules. Receives an array of module integer IDs. - def archive_modules(module_ids) - module_ids.each do |m_id| - my_module = project_my_modules.find_by_id(m_id) - unless my_module.blank? - my_module.archive! - end - end - project_my_modules.reload - end - - # Archive all modules. Receives an array of module integer IDs and current user. - def archive_modules(module_ids, current_user) - module_ids.each do |m_id| - my_module = project_my_modules.find_by_id(m_id) - unless my_module.blank? - my_module.archive!(current_user) - end - end - project_my_modules.reload - end - - # Add modules, and returns a map of "virtual" IDs with - # actual IDs of saved modules. - # to_add is an array of hashes, each containing 'name', - # 'x', 'y' and 'id'. - # to_clone is a hash, storing new cloned modules as keys, - # and original modules as values. - def add_modules(to_add, to_clone, current_user) - originals = [] - cloned_pairs = {} - ids_map = Hash.new - to_add.each do |m| - original = MyModule.find_by_id(to_clone.fetch(m[:id], nil)) - if original.present? then - my_module = original.deep_clone(current_user) - cloned_pairs[my_module] = original - else - my_module = MyModule.new( - project: self) - originals << my_module - end - - my_module.name = m[:name] - my_module.x = m[:x] - my_module.y = m[:y] - my_module.created_by = current_user - my_module.last_modified_by = current_user - my_module.save! - - ids_map[m[:id]] = my_module.id.to_s - end - my_modules.reload - return ids_map, cloned_pairs, originals - end - - # Rename modules; this method accepts a map where keys - # represent IDs of modules, and values new names for - # such modules. If a module with given ID doesn't exist, - # it's obviously not updated. - def rename_modules(to_rename) - to_rename.each do |id, new_name| - my_module = MyModule.find_by_id(id) - if my_module.present? - my_module.name = new_name - my_module.save! - end - end - end - - # Update connections for all modules in this project. - # Input is an array of arrays, where first element represents - # source node, and second element represents target node. - # Example input: [ [1, 2], [2, 3], [4, 5], [2, 5] ] - def update_module_connections(connections) - require 'rgl/base' - require 'rgl/adjacency' - require 'rgl/topsort' - - dg = RGL::DirectedAdjacencyGraph.new - connections.each do |a,b| - # Check if both vertices exist - if (project_my_modules.find_all {|m| [a.to_i, b.to_i].include? m.id }).count == 2 - dg.add_edge(a, b) - end - end - - # Check if cycles exist! - topsort = dg.topsort_iterator.to_a - if topsort.length == 0 and dg.edges.size > 1 - raise ArgumentError, "Cycles exist." - end - - # First, delete existing connections - # but keep a copy of previous state - previous_sources = {} - previous_sources.default = [] - project_my_modules.each do |m| - previous_sources[m.id] = [] - m.inputs.each do |c| - previous_sources[m.id] << c.from - end - end - project_my_modules.each do |m| - unless m.outputs.destroy_all - raise ActiveRecord::ActiveRecordError - end - end - - - # Add new connections - filtered_edges = dg.edges.collect { |e| [e.source, e.target] } - filtered_edges.each do |a, b| - Connection.create!(:input_id => b, :output_id => a) - end - - # Unassign samples from former downstream modules - # for all destroyed connections - unassign_samples_from_old_downstream_modules(previous_sources) - - visited = [] - # Assign samples to all new downstream modules - filtered_edges.each do |a, b| - source = project_my_modules.find(a.to_i) - target = project_my_modules.find(b.to_i) - # Do this only for new edges - if previous_sources[target.id].exclude?(source) - # Go as high upstream as new edges take us - # and then assign samples to all downsteam samples - assign_samples_to_new_downstream_modules(previous_sources, visited, source) - end - end - - # Save topological order of modules (for modules without workflow, - # leave them unordered) - project_my_modules.each do |m| - if topsort.include? m.id.to_s - m.workflow_order = topsort.find_index(m.id.to_s) - else - m.workflow_order = -1 - end - m.save! - end - - # Make sure to reload my modules, which now have updated connections and samples - project_my_modules.reload - true - end - - # When connections are deleted, unassign samples that - # are not inherited anymore - def unassign_samples_from_old_downstream_modules(sources) - project_my_modules.each do |my_module| - sources[my_module.id].each do |s| - # Only do this for newly deleted connections - if s.outputs.map{|i| i.to}.exclude? my_module - my_module.get_downstream_modules.each do |dm| - # Get unique samples for all upstream modules - um = dm.get_upstream_modules - um.shift # remove current module - ums = um.map{|m| m.samples}.flatten.uniq - s.samples.each do |sample| - dm.samples.delete(sample) if ums.exclude? sample - end - end - end - end - end - end - - # Assign samples to new connections recursively - def assign_samples_to_new_downstream_modules(sources, visited, my_module) - # If samples are already assigned for this module, stop going upstream - if visited.include? (my_module) - return - end - visited << my_module - # Edge case, when module is source or it doesn't have any new input connections - if my_module.inputs.blank? or ( - my_module.inputs.map{|c| c.from} - - sources[my_module.id] - ).empty? - my_module.get_downstream_modules.each do |dm| - new_samples = my_module.samples.select { |el| dm.samples.exclude?(el) } - dm.samples.push(*new_samples) - end - else - my_module.inputs.each do |input| - # Go upstream for new in connections - if sources[my_module.id].exclude?(input.from) - assign_samples_to_new_downstream_modules(input.from) - end - end - end - end - - # Updates positions of modules. - # Input is a map where keys are module IDs, and values are - # hashes like { x: , y: }. - def update_module_positions(positions) - positions.each do |id, pos| - unless MyModule.update(id, x: pos[:x], y: pos[:y]) - raise ActiveRecord::ActiveRecordError - end - end - project_my_modules.reload - end - - # Normalize module positions in this project. - def normalize_module_positions - # This method normalizes module positions so x-s and y-s - # are all positive - x_diff = (project_my_modules.collect { |m| m.x }).min - y_diff = (project_my_modules.collect { |m| m.y }).min - - project_my_modules.each do |m| - unless - m.update_attribute(:x, m.x - x_diff) and - m.update_attribute(:y, m.y - y_diff) - raise ActiveRecord::ActiveRecordError - end - end - end - - # Recalculate module groups in this project. Input is - # a hash of module ids and their corresponding module names. - def update_module_groups(module_groups, current_user) - require 'rgl/base' - require 'rgl/adjacency' - require 'rgl/connected_components' - - dg = RGL::DirectedAdjacencyGraph[] - group_ids = Set.new - active_modules.each do |m| - unless m.my_module_group.blank? - group_ids << m.my_module_group.id - end - unless dg.has_vertex? m.id - dg.add_vertex m.id - end - m.outputs.each do |o| - dg.add_edge m.id, o.to.id - end - end - workflows = [] - dg.to_undirected.each_connected_component { |w| workflows << w } - - # Retrieve maximum allowed module group name - max_length = (MyModuleGroup.validators_on(:name).select { |v| v.class == ActiveModel::Validations::LengthValidator }).first.options[:maximum] - # For each workflow, generate new names - new_index = 1 - wf_names = [] - suffix = I18n.t("my_module_groups.new.suffix") - cut_index = -(suffix.length + 1) - workflows.each do |w| - modules = MyModule.find(w) - - # Get an array of module names - names = [] - modules.each do |m| - names << module_groups.fetch(m.id.to_s, "") - end - names = names.uniq - name = (names.select { |v| v != "" }).join(", ") - - if w.length <= 1 - name = nil - elsif name.blank? - name = I18n.t("my_module_groups.new.name", index: new_index) - new_index += 1 - while MyModuleGroup.find_by(name: name).present? - name = I18n.t("my_module_groups.new.name", index: new_index) - new_index += 1 - end - elsif name.length > max_length - # If length is too long, shorten it - name = name[0..(max_length + cut_index)] + suffix - end - - wf_names << name - end - - # Remove any existing module groups from modules - unless MyModuleGroup.destroy_all(:id => group_ids.to_a) - raise ActiveRecord::ActiveRecordError - end - - # Second, create new groups - workflows.each_with_index do |w, i| - # Single modules are not considered part of any workflow - if w.length > 1 - group = MyModuleGroup.new( - name: wf_names[i], - project: self, - my_modules: MyModule.find(w)) - group.created_by = current_user - group.save! - end - end - - my_module_groups.reload - true - end end From 6053c782f991cef2b0c7b7b1cea574f35099052b Mon Sep 17 00:00:00 2001 From: zmagod Date: Mon, 25 Jul 2016 12:07:10 +0200 Subject: [PATCH 6/8] fixed permission_helper [fixes SCI-34] --- app/helpers/permission_helper.rb | 99 ++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 23 deletions(-) diff --git a/app/helpers/permission_helper.rb b/app/helpers/permission_helper.rb index 4b520e359..5b8b23d4d 100644 --- a/app/helpers/permission_helper.rb +++ b/app/helpers/permission_helper.rb @@ -122,7 +122,9 @@ module PermissionHelper ] do |proxy, *args, &block| if args[0] my_module = args[0] - if my_module.active? and my_module.experiment.project.active? + if my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? proxy.call(*args, &block) else false @@ -562,7 +564,10 @@ module PermissionHelper protocol.added_by == current_user elsif protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and can_view_module(my_module) + my_module.active? && + my_module.experiment.project.active? && + can_view_module(my_module) && + my_module.experiment.active? else false end @@ -610,7 +615,10 @@ module PermissionHelper def can_unlink_protocol(protocol) if protocol.linked? my_module = protocol.my_module - my_module.active? and my_module.project.active? and is_user_or_higher_of_project(my_module.project) + my_module.active? && + my_module.project.active? && + is_user_or_higher_of_project(my_module.project) && + my_module.experiment.active? else false end @@ -619,7 +627,10 @@ module PermissionHelper def can_revert_protocol(protocol) if protocol.linked? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + is_user_or_higher_of_project(my_module.experiment.project) && + my_module.experiment.active? else false end @@ -628,7 +639,10 @@ module PermissionHelper def can_update_protocol_from_parent(protocol) if protocol.linked? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + is_user_or_higher_of_project(my_module.experiment.project) && + my_module.experiment.active? else false end @@ -637,7 +651,10 @@ module PermissionHelper def can_load_protocol_from_repository(protocol, source) if can_view_protocol(source) my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + is_user_or_higher_of_project(my_module.experiment.project) && + my_module.experiment.active? else false end @@ -648,11 +665,12 @@ module PermissionHelper my_module = protocol.my_module parent = protocol.parent - my_module.active? and - my_module.experiment.project.active? and - is_normal_user_or_admin_of_organization(parent.organization) and - is_user_or_higher_of_project(my_module.experiment.project) and - (parent.in_repository_public? or parent.in_repository_private?) and + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + is_normal_user_or_admin_of_organization(parent.organization) && + is_user_or_higher_of_project(my_module.experiment.project) && + (parent.in_repository_public? or parent.in_repository_private?) && parent.added_by == current_user else false @@ -681,7 +699,10 @@ module PermissionHelper def can_view_steps_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and can_view_module(my_module) + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + can_view_module(my_module) elsif protocol.in_repository? protocol.in_repository_active? and can_view_protocol(protocol) else @@ -692,7 +713,10 @@ module PermissionHelper def can_create_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + is_user_or_higher_of_project(my_module.experiment.project) elsif protocol.in_repository? protocol.in_repository_active? and can_edit_protocol(protocol) else @@ -703,7 +727,10 @@ module PermissionHelper def can_reorder_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + is_user_or_higher_of_project(my_module.experiment.project) elsif protocol.in_repository? protocol.in_repository_active? and can_edit_protocol(protocol) else @@ -720,7 +747,10 @@ module PermissionHelper def can_edit_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + is_user_or_higher_of_project(my_module.experiment.project) elsif protocol.in_repository? protocol.in_repository_active? and can_edit_protocol(protocol) else @@ -731,7 +761,10 @@ module PermissionHelper def can_delete_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_owner_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + is_owner_of_project(my_module.experiment.project) elsif protocol.in_repository? protocol.in_repository_active? and can_edit_protocol(protocol) else @@ -742,7 +775,10 @@ module PermissionHelper def can_view_step_comments(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and can_view_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + can_view_project(my_module.experiment.project) else # In repository, comments are disabled false @@ -752,7 +788,10 @@ module PermissionHelper def can_add_step_comment_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_technician_or_higher_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + is_technician_or_higher_of_project(my_module.experiment.project) else # In repository, user cannot complete steps false @@ -762,7 +801,9 @@ module PermissionHelper def can_view_or_download_step_assets(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && (is_member_of_project(my_module.experiment.project) || can_view_project(my_module.experiment.project)) elsif protocol.in_repository? protocol.in_repository_active? and can_view_protocol(protocol) @@ -774,7 +815,10 @@ module PermissionHelper def can_complete_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_technician_or_higher_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + is_technician_or_higher_of_project(my_module.experiment.project) else # In repository, user cannot complete steps false @@ -784,7 +828,10 @@ module PermissionHelper def can_uncomplete_step_in_protocol(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + is_user_or_higher_of_project(my_module.experiment.project) else # In repository, user cannot complete steps false @@ -794,7 +841,10 @@ module PermissionHelper def can_check_checkbox(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_technician_or_higher_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + is_technician_or_higher_of_project(my_module.experiment.project) else # In repository, user cannot check checkboxes false @@ -804,7 +854,10 @@ module PermissionHelper def can_uncheck_checkbox(protocol) if protocol.in_module? my_module = protocol.my_module - my_module.active? and my_module.experiment.project.active? and is_user_or_higher_of_project(my_module.experiment.project) + my_module.active? && + my_module.experiment.project.active? && + my_module.experiment.active? && + is_user_or_higher_of_project(my_module.experiment.project) else # In repository, user cannot check checkboxes false From c27ffa9fbf41b49547c0e4b91e6654861ed973f9 Mon Sep 17 00:00:00 2001 From: zmagod Date: Tue, 26 Jul 2016 08:44:09 +0200 Subject: [PATCH 7/8] fixed project_my_module method --- app/models/project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index 45600b7b1..90afb25d3 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -105,7 +105,7 @@ class Project < ActiveRecord::Base end def project_my_modules - experiments.collect{ |exp| exp.my_modules }.first + MyModule.where('"experiment_id" IN (?)', experiments.select(:id)) end def space_taken From 346bffe08f6910dd283509fa0aa8f82224efa079 Mon Sep 17 00:00:00 2001 From: zmagod Date: Tue, 26 Jul 2016 09:17:24 +0200 Subject: [PATCH 8/8] fixed protocol.rb --- app/models/protocol.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/protocol.rb b/app/models/protocol.rb index 408f234e7..2b30bc5b4 100644 --- a/app/models/protocol.rb +++ b/app/models/protocol.rb @@ -148,7 +148,7 @@ class Protocol < ActiveRecord::Base def self.new_blank_for_module(my_module) Protocol.new( - organization: my_module.project.organization, + organization: my_module.experiment.project.organization, protocol_type: :unlinked, my_module: my_module ) @@ -611,4 +611,4 @@ class Protocol < ActiveRecord::Base self.parent.decrement!(:nr_of_linked_children) if self.parent.present? end -end \ No newline at end of file +end