diff --git a/app/services/team_importer.rb b/app/services/team_importer.rb index 0eb484b8c..0535f98eb 100644 --- a/app/services/team_importer.rb +++ b/app/services/team_importer.rb @@ -168,6 +168,11 @@ class TeamImporter ActiveRecord::Base.no_touching do experiment = create_experiment(experiment_json, project, user_id) + experiment.my_modules.each do |my_module| + my_module.nr_of_assigned_samples = 0 + my_module.save(touch: false) + end + # Create connections for modules experiment_json['my_modules'].each do |my_module_json| create_task_connections(my_module_json['outputs']) diff --git a/spec/services/model_importers/team_importer_spec.rb b/spec/services/model_importers/team_importer_spec.rb index 28b2517d9..e0d85c506 100644 --- a/spec/services/model_importers/team_importer_spec.rb +++ b/spec/services/model_importers/team_importer_spec.rb @@ -3,40 +3,43 @@ require 'rails_helper' describe TeamImporter do - - def check_module(json_module, db_module) - it { expect(my_module.dig('my_module', 'name')).to be_a(String) } - end describe '#import_template_experiment_from_dir' do context 'successful import of all different elements with given json' do - + # Constants TEMPLATE_DIR = "#{Rails.root}/spec/services/model_importers/" \ "test_experiment_data" + USER_ID = 2 + PROJECT_ID = 2 + before :all do time = Time.new(2015, 8, 1, 14, 35, 0) - create :user, email: Faker::Internet.email + + # Create 2 users and 2 projects to check for a different ID (id = 2) + # when importing to avoid any defaults + create :user @user = create :user @team = create :team - create :project, name: 'Project 1', visibility: 1, team: @team, - archived: false, created_at: time + create :project, name: 'Placeholder project', visibility: 1, + team: @team, archived: false, created_at: time @project = create :project, name: 'Project', visibility: 1, team: @team, archived: false, created_at: time - @json = @team_importer = TeamImporter.new - @exp = @team_importer - .import_template_experiment_from_dir(TEMPLATE_DIR, 2, 2) + @team_importer = TeamImporter.new + @exp = @team_importer.import_experiment_template_from_dir(TEMPLATE_DIR, + PROJECT_ID, + USER_ID) end describe 'Experiment variables' do it { expect(@exp.id).to eq 1 } - it { expect(@exp.project.id).to eq 2 } + it { expect(@exp.project.id).to eq PROJECT_ID } it { expect(@exp.name).to eq 'Experiment export' } it { expect(@exp.description).to eq 'My description' } - it { expect(@exp.created_at).to eq '2019-01-21T13:27:53.342Z' } - it { expect(@exp.created_by.id).to eq 2 } - it { expect(@exp.last_modified_by.id).to eq 2 } + it { expect(@exp.created_at).to eq '2019-01-21T13:27:53.342Z'.to_time } + it { expect(@exp.created_by.id).to eq USER_ID } + it { expect(@exp.last_modified_by.id).to eq USER_ID } it { expect(@exp.archived).to eq false } it { expect(@exp.archived_by_id).to be_nil } @@ -45,33 +48,347 @@ describe TeamImporter do it { expect(@exp.restored_by_id).to be_nil } it { expect(@exp.restored_on).to be_nil } - it { expect(@exp.workflowimg_updated_at).to eq '2019-01-21T13:31:04.682Z' } + it do + expect(@exp.workflowimg_updated_at).to eq( + '2019-01-21T13:31:04.682Z'.to_time + ) + end it { expect(@exp.workflowimg_file_size).to eq 4581 } end describe 'Module groups' do # Module groups it { expect(@exp.my_module_groups.count).to eq 2 } - it { expect(@exp.my_module_groups.pluck(:created_by_id)).to all eq 2 } - it { expect(@exp.my_module_groups.pluck(:created_at)).to( - match_array(['2019-01-21T13:32:46.449Z'.to_time, - '2019-01-21T13:32:46.460Z'.to_time])) } - it { expect(@exp.my_module_groups.pluck(:updated_at)).to( - match_array(['2019-01-21T13:32:46.449Z'.to_time, - '2019-01-21T13:32:46.460Z'.to_time])) } - it { expect(@exp.modules_without_group.count).to( - eq 1) } - it { expect(@exp.my_modules.where(my_module_group: nil).count).to( - eq 2) } - it { expect(@exp.archived_modules.count).to( - eq 1) } + it do + expect(@exp.my_module_groups.pluck(:created_by_id)).to all eq( + USER_ID + ) + end + it do + expect(@exp.my_module_groups.pluck(:created_at)).to( + match_array(['2019-01-21T13:32:46.449Z'.to_time, + '2019-01-21T13:32:46.460Z'.to_time]) + ) + end + it do + expect(@exp.my_module_groups.pluck(:updated_at)).to( + match_array(['2019-01-21T13:32:46.449Z'.to_time, + '2019-01-21T13:32:46.460Z'.to_time]) + ) + end + it do + expect(@exp.my_modules.where(my_module_group: nil).count).to eq 2 + end + it { expect(@exp.archived_modules.count).to eq 1 } + end + + describe 'Connections' do + it 'creates all connections between modules' do + expect(Connection.all.count).to eq 3 + + # Load known modules + exp_design = @exp.my_modules.find_by(name: 'Experiment design') + rna = @exp.my_modules.find_by( + name: 'RNA quality & quantity - BIOANALYSER' + ) + reverse = @exp.my_modules.find_by( + name: 'Reverse transcription' + ) + + task1 = @exp.my_modules.find_by(name: 'Workflow 2 - task 1') + task2 = @exp.my_modules.find_by(name: 'Workflow 2 - task 2') + + # Check connections + expect(exp_design.outputs.first.input_id).to eq( + rna.id + ) + expect(rna.outputs.first.input_id).to eq( + reverse.id + ) + expect(task1.outputs.first.input_id).to eq( + task2.id + ) + + # Others should be empty + expect(task2.outputs).to be_empty + expect(reverse.outputs).to be_empty + end end describe 'Modules' do - @json = JSON.parse(File.read("#{TEMPLATE_DIR}" \ - "/experiment_export.json")) - @json['my_modules'].each do |my_module| - check_module(my_module, '') + it 'imports all the modules' do + team_json = JSON.parse(File.read("#{TEMPLATE_DIR}/experiment.json")) + team_json['my_modules'].each do |my_module| + json_module = my_module.dig('my_module') + + # Find DB mapped module + name = json_module.dig('name') + db_module = @exp.my_modules.find_by(name: name) + + expect(db_module.description).to eq json_module['description'] + expect(db_module.created_at).to eq json_module['created_at'].to_time + expect(db_module.created_by_id).to eq USER_ID + + expect(db_module.updated_at).to eq json_module['updated_at'].to_time + expect(db_module.last_modified_by_id).to eq USER_ID + + expect(db_module.archived).to eq json_module['archived'] + + expect(db_module.state).to eq json_module['state'] + if json_module['completed_on'] + expect(db_module.completed_on).to eq( + json_module['completed_on'].to_time + ) + end + + if json_module['due_date'] + expect(db_module.due_date).to eq( + json_module['due_date'].to_time + ) + end + + # Coordinates and workflow + expect(db_module.x).to eq json_module['x'] + expect(db_module.y).to eq json_module['y'] + expect(db_module.workflow_order).to eq( + json_module['workflow_order'] + ) + + # Check for lonely tasks + if json_module['my_module_group_id'].nil? + expect(db_module.my_module_group_id).to be_nil + end + + expect(db_module.nr_of_assigned_samples).to be_zero + + # Check if callbacks for protocols are turned off + expect(db_module.protocols.count).to eq 1 + + # Although rows are present in JSON, they shouldn't be imported + expect(db_module.repository_rows.count).to be_zero + + # No tags should be imported + expect(db_module.tags.count).to be_zero + + ########### + # Protocols + ########### + db_protocol = db_module.protocols.first + json_protocol = my_module['protocols'][0]['protocol'] + + # Protocol object + expect(db_protocol.name).to eq json_protocol['name'] + expect(db_protocol.description).to eq json_protocol['description'] + expect(db_protocol.created_at).to eq( + json_protocol['created_at'].to_time + ) + expect(db_protocol.updated_at).to eq( + json_protocol['updated_at'].to_time + ) + expect(db_protocol.added_by_id).to eq( + json_protocol.dig('added_by_id') + ) + expect(db_protocol.archived_by_id).to be_nil + expect(db_protocol.archived_on).to be_nil + expect(db_protocol.restored_by_id).to be_nil + expect(db_protocol.restored_on).to be_nil + expect(db_protocol.authors).to eq json_protocol['authors'] + expect(db_protocol.parent_id).to eq json_protocol['parent_id'] + expect(db_protocol.parent_updated_at).to eq( + json_protocol['parent_updated_at'] + ) + expect(db_protocol.protocol_type).to eq( + json_protocol['protocol_type'] + ) + expect(db_protocol.team_id).to eq @team.id + expect(db_protocol.nr_of_linked_children).to eq( + json_protocol.dig('nr_of_linked_children') + ) + + ####### + # STEPS + ####### + json_steps = my_module.dig('protocols')[0].dig('steps') + json_steps.each do |json_step| + json_step_obj = json_step.dig('step') + db_step = db_protocol.steps.find_by(name: json_step_obj['name']) + + # Step object + expect(db_step.description).to eq json_step_obj['description'] + expect(db_step.updated_at).to eq( + json_step_obj['updated_at'].to_time + ) + expect(db_step.position).to eq json_step_obj['position'] + expect(db_step.last_modified_by_id).to eq USER_ID + expect(db_step.completed).to eq json_step_obj['completed'] + + if json_step_obj['completed'] + expect(db_step.completed_on).to eq( + json_step_obj['completed_on'].to_time + ) + end + + # Checklists + expect(db_step.checklists.count).to eq( + json_step['checklists'].count + ) + json_step['checklists'].each do |checklist| + json_checklist = checklist['checklist'] + json_items = checklist['checklist_items'] + db_checklist = db_step.checklists.find_by( + name: json_checklist['name'] + ) + + # Checklist object + expect(db_checklist.created_at).to eq( + json_checklist['created_at'].to_time + ) + expect(db_checklist.updated_at).to eq( + json_checklist['updated_at'].to_time + ) + expect(db_checklist.created_by_id).to eq USER_ID + expect(db_checklist.last_modified_by_id).to eq USER_ID + + expect(db_checklist.checklist_items.count).to eq( + json_items.count + ) + + # Checklist items + json_items.each do |json_item| + db_item = db_checklist.checklist_items.find_by( + text: json_item['text'] + ) + expect(db_item.checked).to eq(json_item['checked']) + expect(db_item.position).to eq(json_item['position']) + expect(db_item.created_at).to eq( + json_item['created_at'].to_time + ) + expect(db_item.updated_at).to eq( + json_item['updated_at'].to_time + ) + expect(db_item.created_by_id).to eq USER_ID + expect(db_item.last_modified_by_id).to eq USER_ID + end + end + + # Step assets + expect(db_step.assets.count).to eq( + json_step['assets'].count + ) + + expect(db_step.step_assets.count).to eq( + json_step['step_assets'].count + ) + + json_step['assets'].each do |json_asset| + db_asset = db_step.assets.find_by( + file_file_name: json_asset['file_file_name'] + ) + + # Basic fields + expect(db_asset.created_at).to eq( + json_asset['created_at'].to_time + ) + expect(db_asset.created_by_id).to eq USER_ID + expect(db_asset.last_modified_by_id).to eq USER_ID + expect(db_asset.team_id). to eq @team.id + + # Other fields + expect(db_asset.estimated_size).to eq( + json_asset['estimated_size'] + ) + expect(db_asset.file_content_type).to eq( + json_asset['file_content_type'] + ) + expect(db_asset.file_file_size).to eq( + json_asset['file_file_size'] + ) + expect(db_asset.file_updated_at).to be_within(10.seconds) + .of(Time.now) + expect(db_asset.lock).to eq( + json_asset['lock'] + ) + expect(db_asset.lock_ttl).to eq( + json_asset['lock_ttl'] + ) + expect(db_asset.version).to eq( + json_asset['version'] + ) + end + + # Tables + expect(db_step.step_tables.count).to eq( + json_step['step_tables'].count + ) + expect(db_step.tables.count).to eq( + json_step['tables'].count + ) + + json_step['tables'].each do |json_table| + db_table = db_step.tables.find_by( + contents: Base64.decode64(json_table['contents']) + ) + + # Basic fields + expect(db_table.created_at).to eq( + json_table['created_at'].to_time + ) + expect(db_table.updated_at).to eq( + json_table['updated_at'].to_time + ) + expect(db_table.created_by_id).to eq USER_ID + expect(db_table.last_modified_by_id).to eq USER_ID + expect(db_table.team_id). to eq @team.id + + # Other fields + expect(db_table.name).to eq(json_table['name']) + expect(db_table.data_vector).to eq( + Base64.decode64(json_table['data_vector']) + ) + end + + # Step comments + expect(db_step.step_comments.count).to eq( + json_step['step_comments'].count + ) + json_step['step_comments'].each do |json_comment| + db_comment = db_step.step_comments.find_by( + message: json_comment['message'] + ) + + expect(db_comment.created_at).to eq( + json_comment['created_at'].to_time + ) + expect(db_comment.updated_at).to eq( + json_comment['updated_at'].to_time + ) + expect(db_comment.last_modified_by_id).to eq USER_ID + end + end + + # Task comments + expect(db_module.task_comments.count).to eq( + my_module['task_comments'].count + ) + my_module['task_comments'].each do |json_comment| + db_comment = db_module.task_comments.find_by( + message: json_comment['message'] + ) + + expect(db_comment.created_at).to eq( + json_comment['created_at'].to_time + ) + expect(db_comment.updated_at).to eq( + json_comment['updated_at'].to_time + ) + expect(db_comment.last_modified_by_id).to eq USER_ID + end + # + # User assigns to the the module + unless my_module['user_my_modules'].empty? + expect(db_module.user_my_modules.first.user_id).to eq USER_ID + end + end end end end diff --git a/spec/services/model_importers/test_experiment_data/experiment_export.json b/spec/services/model_importers/test_experiment_data/experiment_export.json deleted file mode 100644 index 1f85e2c00..000000000 --- a/spec/services/model_importers/test_experiment_data/experiment_export.json +++ /dev/null @@ -1,1170 +0,0 @@ -{ - "experiment": { - "archived": false, - "archived_by_id": null, - "archived_on": null, - "created_at": "2019-01-21T13:27:53.342Z", - "created_by_id": 1, - "description": "My description", - "id": 3, - "last_modified_by_id": 1, - "name": "Experiment export", - "project_id": 1, - "restored_by_id": null, - "restored_on": null, - "updated_at": "2019-01-21T13:32:46.473Z", - "workflowimg_content_type": "image/png", - "workflowimg_file_name": "wimg20190121-1-111oj8z.png", - "workflowimg_file_size": 4581, - "workflowimg_updated_at": "2019-01-21T13:31:04.682Z" - }, - "my_module_groups": [ - { - "created_at": "2019-01-21T13:32:46.449Z", - "created_by_id": 1, - "experiment_id": 3, - "id": 13, - "updated_at": "2019-01-21T13:32:46.449Z" - }, - { - "created_at": "2019-01-21T13:32:46.460Z", - "created_by_id": 1, - "experiment_id": 3, - "id": 14, - "updated_at": "2019-01-21T13:32:46.460Z" - } - ], - "my_modules": [ - { - "my_module": { - "archived": true, - "archived_by_id": 1, - "archived_on": "2019-01-21T13:32:46.000Z", - "completed_on": null, - "created_at": "2019-01-17T09:42:11.511Z", - "created_by_id": 1, - "description": null, - "due_date": "2019-01-28T12:44:56.555Z", - "experiment_id": 3, - "id": 9, - "last_modified_by_id": 1, - "my_module_group_id": null, - "name": "Data analysis - Pfaffl method", - "nr_of_assigned_samples": 0, - "restored_by_id": 1, - "restored_on": "2019-01-21T13:31:37.000Z", - "state": "uncompleted", - "updated_at": "2019-01-21T13:32:46.278Z", - "workflow_order": -1, - "x": 64, - "y": 46 - }, - "my_module_repository_rows": [], - "my_module_tags": [], - "outputs": [], - "protocols": [ - { - "protocol": { - "added_by_id": null, - "archived_by_id": null, - "archived_on": null, - "authors": null, - "created_at": "2019-01-21T12:44:56.564Z", - "description": null, - "id": 9, - "my_module_id": 9, - "name": null, - "nr_of_linked_children": 0, - "parent_id": null, - "parent_updated_at": null, - "protocol_type": "unlinked", - "published_on": null, - "restored_by_id": null, - "restored_on": null, - "team_id": 1, - "updated_at": "2019-01-21T13:31:55.946Z" - }, - "protocol_protocol_keywords": [], - "steps": [ - { - "assets": [], - "checklists": [], - "step": { - "completed": false, - "completed_on": null, - "created_at": "2019-01-21T13:31:55.921Z", - "description": "", - "id": 21, - "last_modified_by_id": 1, - "name": "Temp step", - "position": 0, - "protocol_id": 9, - "updated_at": "2019-01-21T13:31:55.921Z", - "user_id": 1 - }, - "step_assets": [], - "step_comments": [], - "step_tables": [], - "tables": [] - } - ] - } - ], - "results": [], - "task_comments": [], - "user_my_modules": [ - { - "assigned_by_id": 1, - "created_at": "2019-01-17T09:42:54.874Z", - "id": 9, - "my_module_id": 9, - "updated_at": "2019-01-21T12:44:56.591Z", - "user_id": 1 - } - ] - }, - { - "my_module": { - "archived": false, - "archived_by_id": null, - "archived_on": null, - "completed_on": null, - "created_at": "2019-01-21T13:01:34.508Z", - "created_by_id": 1, - "description": null, - "due_date": null, - "experiment_id": 3, - "id": 12, - "last_modified_by_id": 1, - "my_module_group_id": null, - "name": "Lonely task", - "nr_of_assigned_samples": 0, - "restored_by_id": null, - "restored_on": null, - "state": "uncompleted", - "updated_at": "2019-01-21T13:28:43.805Z", - "workflow_order": -1, - "x": 64, - "y": 46 - }, - "my_module_repository_rows": [], - "my_module_tags": [], - "outputs": [], - "protocols": [ - { - "protocol": { - "added_by_id": null, - "archived_by_id": null, - "archived_on": null, - "authors": null, - "created_at": "2019-01-21T13:01:34.544Z", - "description": null, - "id": 12, - "my_module_id": 12, - "name": null, - "nr_of_linked_children": 0, - "parent_id": null, - "parent_updated_at": null, - "protocol_type": "unlinked", - "published_on": null, - "restored_by_id": null, - "restored_on": null, - "team_id": 1, - "updated_at": "2019-01-21T13:04:30.641Z" - }, - "protocol_protocol_keywords": [], - "steps": [ - { - "assets": [], - "checklists": [ - { - "checklist": { - "created_at": "2019-01-21T13:04:30.562Z", - "created_by_id": null, - "id": 2, - "last_modified_by_id": null, - "name": "Guide", - "step_id": 18, - "updated_at": "2019-01-21T13:04:30.562Z" - }, - "checklist_items": [ - { - "checked": false, - "checklist_id": 2, - "created_at": "2019-01-21T13:04:30.565Z", - "created_by_id": null, - "id": 8, - "last_modified_by_id": null, - "position": 0, - "text": "Wolf", - "updated_at": "2019-01-21T13:04:30.565Z" - }, - { - "checked": true, - "checklist_id": 2, - "created_at": "2019-01-21T13:04:30.568Z", - "created_by_id": null, - "id": 9, - "last_modified_by_id": null, - "position": 1, - "text": "Cat", - "updated_at": "2019-01-21T13:04:32.708Z" - }, - { - "checked": false, - "checklist_id": 2, - "created_at": "2019-01-21T13:04:30.570Z", - "created_by_id": null, - "id": 10, - "last_modified_by_id": null, - "position": 2, - "text": "Bull", - "updated_at": "2019-01-21T13:04:30.570Z" - } - ] - } - ], - "step": { - "completed": false, - "completed_on": null, - "created_at": "2019-01-21T13:04:30.558Z", - "description": "", - "id": 18, - "last_modified_by_id": 1, - "name": "Lonelier step", - "position": 0, - "protocol_id": 12, - "updated_at": "2019-01-21T13:04:30.564Z", - "user_id": 1 - }, - "step_assets": [], - "step_comments": [], - "step_tables": [], - "tables": [] - } - ] - } - ], - "results": [], - "task_comments": [], - "user_my_modules": [] - }, - { - "my_module": { - "archived": false, - "archived_by_id": null, - "archived_on": null, - "completed_on": null, - "created_at": "2019-01-21T13:01:34.493Z", - "created_by_id": 1, - "description": null, - "due_date": null, - "experiment_id": 3, - "id": 11, - "last_modified_by_id": 1, - "my_module_group_id": 13, - "name": "Workflow 2 - task 2", - "nr_of_assigned_samples": 0, - "restored_by_id": null, - "restored_on": null, - "state": "uncompleted", - "updated_at": "2019-01-21T13:32:46.452Z", - "workflow_order": 1, - "x": 0, - "y": 46 - }, - "my_module_repository_rows": [], - "my_module_tags": [], - "outputs": [], - "protocols": [ - { - "protocol": { - "added_by_id": null, - "archived_by_id": null, - "archived_on": null, - "authors": null, - "created_at": "2019-01-21T13:01:34.502Z", - "description": null, - "id": 11, - "my_module_id": 11, - "name": null, - "nr_of_linked_children": 0, - "parent_id": null, - "parent_updated_at": null, - "protocol_type": "unlinked", - "published_on": null, - "restored_by_id": null, - "restored_on": null, - "team_id": 1, - "updated_at": "2019-01-21T13:09:36.370Z" - }, - "protocol_protocol_keywords": [], - "steps": [ - { - "assets": [ - { - "created_at": "2019-01-21T13:09:35.615Z", - "created_by_id": 1, - "estimated_size": 17799, - "file_content_type": "image/png", - "file_file_name": "100gen_line_bending.png", - "file_file_size": 16181, - "file_present": true, - "file_processing": false, - "file_updated_at": "2019-01-21T13:10:05.392Z", - "id": 21, - "last_modified_by_id": null, - "lock": null, - "lock_ttl": null, - "team_id": 1, - "updated_at": "2019-01-21T13:10:06.290Z", - "version": 1 - } - ], - "checklists": [], - "step": { - "completed": false, - "completed_on": null, - "created_at": "2019-01-21T13:09:35.466Z", - "description": "", - "id": 20, - "last_modified_by_id": 1, - "name": "Workflow 2 step", - "position": 0, - "protocol_id": 11, - "updated_at": "2019-01-21T13:10:06.292Z", - "user_id": 1 - }, - "step_assets": [ - { - "asset_id": 21, - "id": 9, - "step_id": 20 - } - ], - "step_comments": [], - "step_tables": [], - "tables": [] - } - ] - } - ], - "results": [], - "task_comments": [], - "user_my_modules": [] - }, - { - "my_module": { - "archived": false, - "archived_by_id": null, - "archived_on": null, - "completed_on": null, - "created_at": "2019-01-21T13:01:34.470Z", - "created_by_id": 1, - "description": null, - "due_date": null, - "experiment_id": 3, - "id": 10, - "last_modified_by_id": 1, - "my_module_group_id": 13, - "name": "Workflow 2 - task 1", - "nr_of_assigned_samples": 0, - "restored_by_id": null, - "restored_on": null, - "state": "uncompleted", - "updated_at": "2019-01-21T13:32:46.456Z", - "workflow_order": 0, - "x": 0, - "y": 29 - }, - "my_module_repository_rows": [], - "my_module_tags": [], - "outputs": [ - { - "id": 34, - "input_id": 11, - "output_id": 10 - } - ], - "protocols": [ - { - "protocol": { - "added_by_id": null, - "archived_by_id": null, - "archived_on": null, - "authors": null, - "created_at": "2019-01-21T13:01:34.485Z", - "description": null, - "id": 10, - "my_module_id": 10, - "name": null, - "nr_of_linked_children": 0, - "parent_id": null, - "parent_updated_at": null, - "protocol_type": "unlinked", - "published_on": null, - "restored_by_id": null, - "restored_on": null, - "team_id": 1, - "updated_at": "2019-01-21T13:05:20.594Z" - }, - "protocol_protocol_keywords": [], - "steps": [ - { - "assets": [], - "checklists": [], - "step": { - "completed": false, - "completed_on": null, - "created_at": "2019-01-21T13:05:20.547Z", - "description": "", - "id": 19, - "last_modified_by_id": 1, - "name": "USB step", - "position": 0, - "protocol_id": 10, - "updated_at": "2019-01-21T13:05:36.010Z", - "user_id": 1 - }, - "step_assets": [], - "step_comments": [ - { - "associated_id": 19, - "created_at": "2019-01-21T13:05:36.007Z", - "id": 10, - "last_modified_by_id": null, - "message": "Comment 12", - "updated_at": "2019-01-21T13:05:36.007Z", - "user_id": 1 - } - ], - "step_tables": [ - { - "id": 2, - "step_id": 19, - "table_id": 5 - } - ], - "tables": [ - { - "contents": "eyJkYXRhIjpbWyIxIixudWxsLG51bGwsbnVsbCxudWxsXSxbbnVsbCwiMiIs\nbnVsbCxudWxsLG51bGxdLFtudWxsLG51bGwsIjMiLG51bGwsbnVsbF0sW251\nbGwsbnVsbCxudWxsLCI0IixudWxsXSxbbnVsbCxudWxsLG51bGwsbnVsbCwi\nNSJdXX0=\n", - "created_at": "2019-01-21T13:05:20.550Z", - "created_by_id": 1, - "data_vector": "JzEnOjEgJzInOjcgJzMnOjEzICc0JzoxOSAnNSc6MjUgJ251bGwnOjIsMyw0\nLDUsNiw4LDksMTAsMTEsMTIsMTQsMTUsMTYsMTcsMTgsMjAsMjEsMjIsMjMs\nMjQ=\n", - "id": 5, - "last_modified_by_id": null, - "name": "USB table", - "team_id": 1, - "updated_at": "2019-01-21T13:05:20.550Z" - } - ] - } - ] - } - ], - "results": [], - "task_comments": [], - "user_my_modules": [] - }, - { - "my_module": { - "archived": false, - "archived_by_id": null, - "archived_on": null, - "completed_on": null, - "created_at": "2019-01-19T07:51:02.803Z", - "created_by_id": 1, - "description": null, - "due_date": "2019-01-28T12:44:56.002Z", - "experiment_id": 3, - "id": 1, - "last_modified_by_id": null, - "my_module_group_id": 14, - "name": "Experiment design", - "nr_of_assigned_samples": 0, - "restored_by_id": null, - "restored_on": null, - "state": "uncompleted", - "updated_at": "2019-01-21T13:32:46.464Z", - "workflow_order": 2, - "x": 0, - "y": 0 - }, - "my_module_repository_rows": [], - "my_module_tags": [ - { - "created_by_id": null, - "id": 1, - "my_module_id": 1, - "tag_id": 1 - } - ], - "outputs": [ - { - "id": 32, - "input_id": 4, - "output_id": 1 - } - ], - "protocols": [ - { - "protocol": { - "added_by_id": null, - "archived_by_id": null, - "archived_on": null, - "authors": null, - "created_at": "2019-01-21T12:44:56.065Z", - "description": null, - "id": 1, - "my_module_id": 1, - "name": null, - "nr_of_linked_children": 0, - "parent_id": null, - "parent_updated_at": null, - "protocol_type": "unlinked", - "published_on": null, - "restored_by_id": null, - "restored_on": null, - "team_id": 1, - "updated_at": "2019-01-21T12:44:56.065Z" - }, - "protocol_protocol_keywords": [], - "steps": [ - { - "assets": [], - "checklists": [], - "step": { - "completed": true, - "completed_on": "2019-01-19T10:56:48.558Z", - "created_at": "2019-01-19T08:52:33.490Z", - "description": "Compare response of PVYNTN, cab4 and PR1 genes in mock/virus inoculated potatoes & in time", - "id": 1, - "last_modified_by_id": null, - "name": "Gene expression", - "position": 0, - "protocol_id": 1, - "updated_at": "2019-01-21T12:59:03.007Z", - "user_id": 1 - }, - "step_assets": [], - "step_comments": [ - { - "associated_id": 1, - "created_at": "2019-01-21T12:59:03.005Z", - "id": 9, - "last_modified_by_id": null, - "message": "Very nice job!", - "updated_at": "2019-01-21T12:59:03.005Z", - "user_id": 1 - } - ], - "step_tables": [], - "tables": [] - } - ] - } - ], - "results": [ - { - "asset": null, - "result": { - "archived": false, - "archived_by_id": null, - "archived_on": null, - "created_at": "2019-01-20T00:57:52.635Z", - "id": 1, - "last_modified_by_id": null, - "my_module_id": 1, - "name": "Experimental design", - "restored_by_id": null, - "restored_on": null, - "updated_at": "2019-01-21T12:44:58.101Z", - "user_id": 1 - }, - "result_comments": [], - "result_text": null, - "table": { - "contents": "eyJkYXRhIjpbWyIiLCIiLCIiLG51bGwsbnVsbF0sWyIiLCIiLCIiLG51bGws\nbnVsbF0sWyJncm91cC90aW1lIiwiMSBkcGkiLCI2IGRwaSIsIiIsIiJdLFsi\nUFZZTlROIiwiMSIsIjEiLCIiLCIiXSxbIm1vY2siLCIxIiwiMSIsIiIsIiJd\nLFtudWxsLG51bGwsbnVsbCxudWxsLG51bGxdXX0=\n", - "created_at": "2019-01-21T12:44:58.086Z", - "created_by_id": 1, - "data_vector": "JzEnOjYsMTEsMTIsMTQsMTUgJzYnOjggJ2RwaSc6Nyw5ICdncm91cC90aW1l\nJzo1ICdtb2NrJzoxMyAnbnVsbCc6MSwyLDMsNCwxNiwxNywxOCwxOSwyMCAn\ncHZ5bnRuJzoxMA==\n", - "id": 1, - "last_modified_by_id": null, - "name": "", - "team_id": 1, - "updated_at": "2019-01-21T12:44:58.093Z" - } - }, - { - "asset": { - "created_at": "2019-01-21T12:45:29.138Z", - "created_by_id": 1, - "estimated_size": 232, - "file_content_type": "text/plain", - "file_file_name": "samples.txt", - "file_file_size": 69, - "file_present": true, - "file_processing": false, - "file_updated_at": "2019-01-21T12:45:28.889Z", - "id": 1, - "last_modified_by_id": 1, - "lock": null, - "lock_ttl": null, - "team_id": 1, - "updated_at": "2019-01-21T13:06:01.610Z", - "version": 1 - }, - "result": { - "archived": true, - "archived_by_id": 1, - "archived_on": "2019-01-21T13:15:54.000Z", - "created_at": "2019-01-20T18:09:01.268Z", - "id": 6, - "last_modified_by_id": 1, - "my_module_id": 1, - "name": "sF", - "restored_by_id": null, - "restored_on": null, - "updated_at": "2019-01-21T13:15:54.487Z", - "user_id": 1 - }, - "result_comments": [], - "result_text": null, - "table": {} - } - ], - "task_comments": [ - { - "associated_id": 1, - "created_at": "2019-01-20T01:27:40.727Z", - "id": 2, - "last_modified_by_id": null, - "message": "We should have a meeting to discuss sampling parametrs soon.", - "updated_at": "2019-01-21T12:44:57.607Z", - "user_id": 1 - }, - { - "associated_id": 1, - "created_at": "2019-01-19T11:47:29.757Z", - "id": 3, - "last_modified_by_id": null, - "message": "I agree.", - "updated_at": "2019-01-21T12:44:57.620Z", - "user_id": 1 - } - ], - "user_my_modules": [ - { - "assigned_by_id": 1, - "created_at": "2019-01-19T07:52:25.851Z", - "id": 1, - "my_module_id": 1, - "updated_at": "2019-01-21T12:44:56.118Z", - "user_id": 1 - } - ] - }, - { - "my_module": { - "archived": false, - "archived_by_id": null, - "archived_on": null, - "completed_on": null, - "created_at": "2019-01-17T08:25:30.434Z", - "created_by_id": 1, - "description": null, - "due_date": "2019-03-25T12:44:56.326Z", - "experiment_id": 3, - "id": 5, - "last_modified_by_id": null, - "my_module_group_id": 14, - "name": "Reverse transcription", - "nr_of_assigned_samples": 4, - "restored_by_id": null, - "restored_on": null, - "state": "uncompleted", - "updated_at": "2019-01-21T13:32:46.467Z", - "workflow_order": 4, - "x": 33, - "y": 16 - }, - "my_module_repository_rows": [ - { - "assigned_by_id": 1, - "created_at": "2019-01-21T12:44:57.146Z", - "id": 16, - "my_module_id": 5, - "repository_row_id": 1, - "updated_at": "2019-01-21T12:44:57.146Z" - }, - { - "assigned_by_id": 1, - "created_at": "2019-01-21T12:44:57.169Z", - "id": 17, - "my_module_id": 5, - "repository_row_id": 2, - "updated_at": "2019-01-21T12:44:57.169Z" - }, - { - "assigned_by_id": 1, - "created_at": "2019-01-21T12:44:57.184Z", - "id": 18, - "my_module_id": 5, - "repository_row_id": 3, - "updated_at": "2019-01-21T12:44:57.184Z" - }, - { - "assigned_by_id": 1, - "created_at": "2019-01-21T12:44:57.201Z", - "id": 19, - "my_module_id": 5, - "repository_row_id": 4, - "updated_at": "2019-01-21T12:44:57.201Z" - }, - { - "assigned_by_id": 1, - "created_at": "2019-01-21T12:44:57.217Z", - "id": 20, - "my_module_id": 5, - "repository_row_id": 5, - "updated_at": "2019-01-21T12:44:57.217Z" - } - ], - "my_module_tags": [ - { - "created_by_id": null, - "id": 5, - "my_module_id": 5, - "tag_id": 2 - } - ], - "outputs": [], - "protocols": [ - { - "protocol": { - "added_by_id": null, - "archived_by_id": null, - "archived_on": null, - "authors": null, - "created_at": "2019-01-21T12:44:56.334Z", - "description": null, - "id": 5, - "my_module_id": 5, - "name": null, - "nr_of_linked_children": 0, - "parent_id": null, - "parent_updated_at": null, - "protocol_type": "unlinked", - "published_on": null, - "restored_by_id": null, - "restored_on": null, - "team_id": 1, - "updated_at": "2019-01-21T12:57:52.015Z" - }, - "protocol_protocol_keywords": [], - "steps": [ - { - "assets": [], - "checklists": [ - { - "checklist": { - "created_at": "2019-01-21T12:44:58.537Z", - "created_by_id": null, - "id": 1, - "last_modified_by_id": null, - "name": "Mastermix", - "step_id": 9, - "updated_at": "2019-01-21T12:44:58.537Z" - }, - "checklist_items": [ - { - "checked": true, - "checklist_id": 1, - "created_at": "2019-01-21T12:44:58.540Z", - "created_by_id": null, - "id": 1, - "last_modified_by_id": null, - "position": null, - "text": "RT buffer", - "updated_at": "2019-01-21T12:50:40.690Z" - }, - { - "checked": true, - "checklist_id": 1, - "created_at": "2019-01-21T12:44:58.542Z", - "created_by_id": null, - "id": 2, - "last_modified_by_id": null, - "position": null, - "text": "dNTP mix", - "updated_at": "2019-01-21T12:50:41.287Z" - }, - { - "checked": false, - "checklist_id": 1, - "created_at": "2019-01-21T12:44:58.543Z", - "created_by_id": null, - "id": 3, - "last_modified_by_id": null, - "position": null, - "text": "Random Primers", - "updated_at": "2019-01-21T12:44:58.543Z" - }, - { - "checked": false, - "checklist_id": 1, - "created_at": "2019-01-21T12:44:58.545Z", - "created_by_id": null, - "id": 4, - "last_modified_by_id": null, - "position": null, - "text": "RNase inhibitor", - "updated_at": "2019-01-21T12:44:58.545Z" - }, - { - "checked": false, - "checklist_id": 1, - "created_at": "2019-01-21T12:44:58.547Z", - "created_by_id": null, - "id": 5, - "last_modified_by_id": null, - "position": null, - "text": "Reverse transcriptase", - "updated_at": "2019-01-21T12:44:58.547Z" - }, - { - "checked": false, - "checklist_id": 1, - "created_at": "2019-01-21T12:44:58.548Z", - "created_by_id": null, - "id": 6, - "last_modified_by_id": null, - "position": null, - "text": "Optional: Luciferase mRNA (denatured)", - "updated_at": "2019-01-21T12:44:58.548Z" - }, - { - "checked": false, - "checklist_id": 1, - "created_at": "2019-01-21T12:44:58.550Z", - "created_by_id": null, - "id": 7, - "last_modified_by_id": null, - "position": null, - "text": "H2O to 12.5 ul", - "updated_at": "2019-01-21T12:44:58.550Z" - } - ] - } - ], - "step": { - "completed": true, - "completed_on": "2019-01-17T13:52:32.426Z", - "created_at": "2019-01-17T13:15:20.691Z", - "description": "High Capacity cDNA Reverse Transcription Kit (Applied Biosystems)", - "id": 9, - "last_modified_by_id": null, - "name": "Prepare mastermix for RT", - "position": 1, - "protocol_id": 5, - "updated_at": "2019-01-21T12:44:58.539Z", - "user_id": 1 - }, - "step_assets": [], - "step_comments": [], - "step_tables": [], - "tables": [] - }, - { - "assets": [], - "checklists": [], - "step": { - "completed": false, - "completed_on": null, - "created_at": "2019-01-17T12:58:06.802Z", - "description": "25\u00b0C for 10 min 37\u00b0C for 2 h", - "id": 10, - "last_modified_by_id": null, - "name": "RT reaction", - "position": 2, - "protocol_id": 5, - "updated_at": "2019-01-21T12:44:58.483Z", - "user_id": 1 - }, - "step_assets": [], - "step_comments": [], - "step_tables": [], - "tables": [] - }, - { - "assets": [], - "checklists": [], - "step": { - "completed": true, - "completed_on": "2019-01-17T17:37:06.427Z", - "created_at": "2019-01-17T09:35:43.770Z", - "description": "\n
1 ug of RNA denature at 80\u00b0C for 5 min --> ice
", - "id": 8, - "last_modified_by_id": 1, - "name": "RNA denaturation", - "position": 0, - "protocol_id": 5, - "updated_at": "2019-01-21T12:57:51.929Z", - "user_id": 1 - }, - "step_assets": [], - "step_comments": [], - "step_tables": [ - { - "id": 1, - "step_id": 8, - "table_id": 4 - } - ], - "tables": [ - { - "contents": "eyJkYXRhIjpbWyIxMSIsIjIyIiwiMzMiLCI0NCIsIjU1Il0sW251bGwsbnVs\nbCxudWxsLG51bGwsbnVsbF0sW251bGwsbnVsbCxudWxsLG51bGwsbnVsbF0s\nW251bGwsbnVsbCxudWxsLG51bGwsbnVsbF0sW251bGwsbnVsbCxudWxsLG51\nbGwsIjY3OCJdXX0=\n", - "created_at": "2019-01-21T12:57:51.923Z", - "created_by_id": 1, - "data_vector": "JzExJzoxICcyMic6MiAnMzMnOjMgJzQ0Jzo0ICc1NSc6NSAnNjc4JzoyNSAn\nbnVsbCc6Niw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywxOCwxOSwy\nMCwyMSwyMiwyMywyNA==\n", - "id": 4, - "last_modified_by_id": null, - "name": "", - "team_id": 1, - "updated_at": "2019-01-21T12:57:51.923Z" - } - ] - } - ] - } - ], - "results": [], - "task_comments": [ - { - "associated_id": 5, - "created_at": "2019-01-17T18:29:15.198Z", - "id": 6, - "last_modified_by_id": null, - "message": "Please show Steve the RT procedure.", - "updated_at": "2019-01-21T12:44:57.665Z", - "user_id": 1 - } - ], - "user_my_modules": [ - { - "assigned_by_id": 1, - "created_at": "2019-01-17T08:27:25.032Z", - "id": 5, - "my_module_id": 5, - "updated_at": "2019-01-21T12:44:56.361Z", - "user_id": 1 - } - ] - }, - { - "my_module": { - "archived": false, - "archived_by_id": null, - "archived_on": null, - "completed_on": null, - "created_at": "2019-01-18T16:17:06.765Z", - "created_by_id": 1, - "description": null, - "due_date": "2019-03-11T12:44:56.265Z", - "experiment_id": 3, - "id": 4, - "last_modified_by_id": null, - "my_module_group_id": 14, - "name": "RNA quality & quantity - BIOANALYSER", - "nr_of_assigned_samples": 4, - "restored_by_id": null, - "restored_on": null, - "state": "uncompleted", - "updated_at": "2019-01-21T13:32:46.471Z", - "workflow_order": 3, - "x": 33, - "y": 0 - }, - "my_module_repository_rows": [ - { - "assigned_by_id": 1, - "created_at": "2019-01-21T12:44:57.027Z", - "id": 11, - "my_module_id": 4, - "repository_row_id": 1, - "updated_at": "2019-01-21T12:44:57.027Z" - }, - { - "assigned_by_id": 1, - "created_at": "2019-01-21T12:44:57.047Z", - "id": 12, - "my_module_id": 4, - "repository_row_id": 2, - "updated_at": "2019-01-21T12:44:57.047Z" - }, - { - "assigned_by_id": 1, - "created_at": "2019-01-21T12:44:57.062Z", - "id": 13, - "my_module_id": 4, - "repository_row_id": 3, - "updated_at": "2019-01-21T12:44:57.062Z" - }, - { - "assigned_by_id": 1, - "created_at": "2019-01-21T12:44:57.078Z", - "id": 14, - "my_module_id": 4, - "repository_row_id": 4, - "updated_at": "2019-01-21T12:44:57.078Z" - }, - { - "assigned_by_id": 1, - "created_at": "2019-01-21T12:44:57.093Z", - "id": 15, - "my_module_id": 4, - "repository_row_id": 5, - "updated_at": "2019-01-21T12:44:57.093Z" - } - ], - "my_module_tags": [ - { - "created_by_id": null, - "id": 4, - "my_module_id": 4, - "tag_id": 2 - } - ], - "outputs": [ - { - "id": 33, - "input_id": 5, - "output_id": 4 - } - ], - "protocols": [ - { - "protocol": { - "added_by_id": null, - "archived_by_id": null, - "archived_on": null, - "authors": null, - "created_at": "2019-01-21T12:44:56.272Z", - "description": null, - "id": 4, - "my_module_id": 4, - "name": null, - "nr_of_linked_children": 0, - "parent_id": null, - "parent_updated_at": null, - "protocol_type": "unlinked", - "published_on": null, - "restored_by_id": null, - "restored_on": null, - "team_id": 1, - "updated_at": "2019-01-21T12:44:56.272Z" - }, - "protocol_protocol_keywords": [], - "steps": [ - { - "assets": [ - { - "created_at": "2019-01-21T12:45:32.296Z", - "created_by_id": 1, - "estimated_size": 1129370, - "file_content_type": "application/pdf", - "file_file_name": "G2938-90034_KitRNA6000Nano_ebook.pdf", - "file_file_size": 974068, - "file_present": true, - "file_processing": false, - "file_updated_at": "2019-01-21T12:45:32.237Z", - "id": 8, - "last_modified_by_id": 1, - "lock": null, - "lock_ttl": null, - "team_id": 1, - "updated_at": "2019-01-21T13:06:04.590Z", - "version": 1 - } - ], - "checklists": [], - "step": { - "completed": false, - "completed_on": null, - "created_at": "2019-01-18T16:27:28.209Z", - "description": null, - "id": 7, - "last_modified_by_id": null, - "name": "Use Nano chip for testing RNA integrity", - "position": 0, - "protocol_id": 4, - "updated_at": "2019-01-21T13:06:04.592Z", - "user_id": 1 - }, - "step_assets": [ - { - "asset_id": 8, - "id": 3, - "step_id": 7 - } - ], - "step_comments": [], - "step_tables": [], - "tables": [] - } - ] - } - ], - "results": [ - { - "asset": { - "created_at": "2019-01-21T12:45:32.847Z", - "created_by_id": 1, - "estimated_size": 46131, - "file_content_type": "image/jpeg", - "file_file_name": "Bioanalyser_result.JPG", - "file_file_size": 41938, - "file_present": true, - "file_processing": false, - "file_updated_at": "2019-01-21T12:45:43.655Z", - "id": 9, - "last_modified_by_id": 1, - "lock": null, - "lock_ttl": null, - "team_id": 1, - "updated_at": "2019-01-21T12:45:44.269Z", - "version": 1 - }, - "result": { - "archived": true, - "archived_by_id": 1, - "archived_on": "2019-01-21T13:16:01.000Z", - "created_at": "2019-01-20T13:55:26.927Z", - "id": 11, - "last_modified_by_id": 1, - "my_module_id": 4, - "name": "Result of RNA integrity", - "restored_by_id": null, - "restored_on": null, - "updated_at": "2019-01-21T13:16:01.326Z", - "user_id": 1 - }, - "result_comments": [], - "result_text": null, - "table": {} - } - ], - "task_comments": [], - "user_my_modules": [ - { - "assigned_by_id": 1, - "created_at": "2019-01-18T16:18:49.946Z", - "id": 4, - "my_module_id": 4, - "updated_at": "2019-01-21T12:44:56.301Z", - "user_id": 1 - } - ] - } - ] -}