diff --git a/app/assets/javascripts/protocols/import_export/eln_table.js b/app/assets/javascripts/protocols/import_export/eln_table.js
index a17b87f90..d8fff26b0 100644
--- a/app/assets/javascripts/protocols/import_export/eln_table.js
+++ b/app/assets/javascripts/protocols/import_export/eln_table.js
@@ -73,4 +73,4 @@ function generateElnTable(id, content) {
}
var html = html_s + tr + html_e;
return $.parseHTML(html);
-}
\ No newline at end of file
+}
diff --git a/app/assets/javascripts/protocols/import_export/import.js b/app/assets/javascripts/protocols/import_export/import.js
index 212a262f3..c9d8ee579 100644
--- a/app/assets/javascripts/protocols/import_export/import.js
+++ b/app/assets/javascripts/protocols/import_export/import.js
@@ -80,6 +80,10 @@ function importProtocolFromFile(
element.find("[data-toggle='" + name + "']").hide();
}
+ function showPartOfElement(element, name) {
+ element.find("[data-toggle='" + name + "']").show();
+ }
+
function newAssetElement(folder, stepGuid, fileRef, fileName, fileType) {
var html = '
';
var assetBytes;
@@ -214,20 +218,7 @@ function importProtocolFromFile(
tableNodes = node.find('elnTables > elnTable');
if (tableNodes.length > 0) {
tableNodes.each(function() {
- var tableId = $(this).attr('id');
- var tableName = $(this).children('name').text();
- var tableContent = $(this).children('contents').text();
-
- // Generate table element
- var tableEl = newPreviewElement(
- 'table',
- { name: tableName }
- );
- var elnTableEl = generateElnTable(tableId, tableContent);
- addChildToPreviewElement(tableEl, 'table', elnTableEl);
-
- // Now, append table element to step
- addChildToPreviewElement(stepEl, 'tables', tableEl);
+ addTablePreview(stepEl, this);
});
} else {
hidePartOfElement(stepEl, 'tables');
@@ -237,41 +228,99 @@ function importProtocolFromFile(
checklistNodes = node.find('checklists > checklist');
if (checklistNodes.length > 0) {
checklistNodes.each(function() {
- var checklistId = $(this).attr('id');
- var checklistName = $(this).children('name').text();
-
- var checklistEl = newPreviewElement(
- 'checklist',
- { name: checklistName }
- );
-
- // Iterate through checklist items
- $(this).find('items > item').each(function() {
- var itemId = $(this).attr('id');
- var itemText = $(this).children('text').text();
-
- var itemEl = newPreviewElement(
- 'checklist-item',
- { text: itemText }
- );
- addChildToPreviewElement(checklistEl, 'checklist-items', itemEl);
- });
-
- // Now, add checklist item to step
- addChildToPreviewElement(stepEl, 'checklists', checklistEl);
+ addChecklistPreview(stepEl, this);
});
}
+ // Parse step elements
+ $(this).find('stepElements > stepElement').each(function() {
+ $element = $(this);
+ switch ($(this).attr('type')) {
+ case 'Checklist':
+ addChecklistPreview(stepEl, $(this).find('checklist'));
+ showPartOfElement(stepEl, 'checklists');
+ break;
+ case 'StepTable':
+ addTablePreview(stepEl, $(this).find('elnTable'));
+ showPartOfElement(stepEl, 'tables');
+ break;
+ case 'StepText':
+ addStepTextPreview(stepEl, $(this).find('stepText'), protocolFolders[position], stepGuid);
+ showPartOfElement(stepEl, 'step-texts');
+ break;
+ default:
+ // nothing to do
+ break;
+ }
+ });
+
// Append step element to preview container
previewContainer.append(stepEl);
});
}
+ function addTablePreview(stepEl, tableNode) {
+ var tableId = $(tableNode).attr('id');
+ var tableName = $(tableNode).children('name').text();
+ var tableContent = $(tableNode).children('contents').text();
+
+ // Generate table element
+ var tableEl = newPreviewElement(
+ 'table',
+ { name: tableName }
+ );
+ var elnTableEl = generateElnTable(tableId, tableContent);
+ addChildToPreviewElement(tableEl, 'table', elnTableEl);
+
+ // Now, append table element to step
+ addChildToPreviewElement(stepEl, 'tables', tableEl);
+ }
+
+ function addChecklistPreview(stepEl, checklistNode) {
+ var checklistId = $(checklistNode).attr('id');
+ var checklistName = $(checklistNode).children('name').text();
+
+ var checklistEl = newPreviewElement(
+ 'checklist',
+ { name: checklistName }
+ );
+
+ // Iterate through checklist items
+ $(checklistNode).find('items > item').each(function() {
+ var itemId = $(this).attr('id');
+ var itemText = $(this).children('text').text();
+
+ var itemEl = newPreviewElement(
+ 'checklist-item',
+ { text: itemText }
+ );
+ addChildToPreviewElement(checklistEl, 'checklist-items', itemEl);
+ });
+
+ // Now, add checklist item to step
+ addChildToPreviewElement(stepEl, 'checklists', checklistEl);
+ }
+
+ function addStepTextPreview(stepEl, stepTextNode, folder, stepGuid) {
+ var itemId = $(stepTextNode).attr('id');
+
+ var itemText = displayTinyMceAssetInDescription(stepTextNode, folder, stepGuid);
+
+ var textEl = newPreviewElement(
+ 'step-text',
+ { text: itemText }
+ );
+
+ addChildToPreviewElement(stepEl, 'step-texts', textEl);
+ }
+
// display tiny_mce_assets in step description
function displayTinyMceAssetInDescription(node, folder, stepGuid) {
- var description;
+ var description = node.children('description').html() || node.children('contents').html();
+
+ if (!description) return '';
+
if (node.children('descriptionAssets').length === 0) {
- description = node.children('description').html();
return $('').html(
description.replace(/\[~tiny_mce_id:([0-9a-zA-Z]+)\]/,
'Can\'t import image')
@@ -281,7 +330,7 @@ function importProtocolFromFile(
.replace(' ]]>', '')
).html();
}
- description = node.children('description').html();
+
description = description.replace('', '')
@@ -518,6 +567,76 @@ function importProtocolFromFile(
return result;
}
+ function stepTextJson(stepTextNode, folderIndex, stepGuid) {
+ var json = {};
+
+ json.contents = $('').html(
+ stepTextNode.children('contents')
+ .html()
+ .replace('', '')
+ .replace(']]>', '')
+ ).html();
+
+ json.descriptionAssets = prepareTinyMceAssets(stepTextNode, folderIndex, stepGuid);
+
+ return json;
+ }
+
+ function stepTableJson(tableNode) {
+ var json = {};
+ var contents = tableNode.children('contents').text();
+ json.id = tableNode.attr('id');
+ json.name = tableNode.children('name').text();
+ contents = hex2a(contents);
+ contents = window.btoa(contents);
+ json.contents = contents;
+
+ return json;
+ }
+
+ function checklistJson(checklistNode) {
+ var json = {};
+ var itemsJson = [];
+ json.id = checklistNode.attr('id');
+ json.name = checklistNode.children('name').text();
+
+ // Iterate through checklist items
+ checklistNode.find('items > item').each(function() {
+ var itemJson = {};
+ itemJson.id = $(this).attr('id');
+ itemJson.position = $(this).attr('position');
+ itemJson.text = $(this).children('text').text();
+ itemsJson.push(itemJson);
+ });
+ json.items = itemsJson;
+
+ return json;
+ }
+
+ function stepElementJson(stepElementNode, folderIndex, stepGuid) {
+ var json = {
+ type: stepElementNode.attr('type')
+ };
+
+ switch (json.type) {
+ case 'Checklist':
+ json.checklist = checklistJson(stepElementNode.find('checklist'));
+ break;
+ case 'StepTable':
+ json.elnTable = stepTableJson(stepElementNode.find('elnTable'));
+ break;
+ case 'StepText':
+ json.stepText = stepTextJson(stepElementNode.find('stepText'), folderIndex, stepGuid);
+ break;
+ default:
+ // nothing to do
+ break;
+ }
+
+ return json;
+ }
+
function importSingleProtocol(index, replaceVals, resultCallback) {
// Retrieve general protocol info
var name;
@@ -551,6 +670,7 @@ function importProtocolFromFile(
// Allright, let's construct the huge,
// messy-pot of a protocol JSON
+ protocolJson.elnVersion = $(protocolXmls[index]).attr('version');
protocolJson.name = name;
protocolJson.description = protocolDescription;
protocolJson.authors = authors;
@@ -571,14 +691,16 @@ function importProtocolFromFile(
stepJson.position = $(this).attr('position');
stepJson.name = $(this).children('name').text();
// I know is crazy but is the only way I found to pass valid HTML
- stepJson.description = $('').html($(this)
- .children('description')
- .html()
- .replace('', '')
- .replace(']]>', ''))
- .html();
- // Iterage throug tiny_mce_assets
+ if ($(this).children('description').html()) {
+ stepJson.description = $('').html($(this)
+ .children('description')
+ .html()
+ .replace('', '')
+ .replace(']]>', ''))
+ .html();
+ }
+ // Iterate through tiny_mce_assets
stepJson.descriptionAssets = prepareTinyMceAssets(this, index, stepGuid);
// Iterate through assets
@@ -608,39 +730,23 @@ function importProtocolFromFile(
// Iterate through step tables
$(this).find('elnTables > elnTable').each(function() {
- var stepTableJson = {};
- var contents = $(this).children('contents').text();
- stepTableJson.id = $(this).attr('id');
- stepTableJson.name = $(this).children('name').text();
- contents = hex2a(contents);
- contents = window.btoa(contents);
- stepTableJson.contents = contents;
-
- stepTablesJson.push(stepTableJson);
+ stepTablesJson.push(stepTableJson($(this)));
});
stepJson.tables = stepTablesJson;
// Iterate through checklists
$(this).find('checklists > checklist').each(function() {
- var stepChecklistJson = {};
- var itemsJson = [];
- stepChecklistJson.id = $(this).attr('id');
- stepChecklistJson.name = $(this).children('name').text();
-
- // Iterate through checklist items
- $(this).find('items > item').each(function() {
- var itemJson = {};
- itemJson.id = $(this).attr('id');
- itemJson.position = $(this).attr('position');
- itemJson.text = $(this).children('text').text();
- itemsJson.push(itemJson);
- });
- stepChecklistJson.items = itemsJson;
-
- stepChecklistsJson.push(stepChecklistJson);
+ stepChecklistsJson.push(checklistJson($(this)));
});
stepJson.checklists = stepChecklistsJson;
+ // Parse step elements
+ stepJson.stepElements = [];
+
+ $(this).find('stepElements > stepElement').each(function() {
+ stepJson.stepElements.push(stepElementJson($(this), index, stepGuid));
+ });
+
stepsJson.push(stepJson);
});
protocolJson.steps = stepsJson;
diff --git a/app/controllers/protocols_controller.rb b/app/controllers/protocols_controller.rb
index 677aa2ec4..d4b46c768 100644
--- a/app/controllers/protocols_controller.rb
+++ b/app/controllers/protocols_controller.rb
@@ -1,8 +1,6 @@
class ProtocolsController < ApplicationController
include RenamingUtil
- include ProtocolsImporter
- include ProtocolsExporter
include ActionView::Helpers::TextHelper
include ActionView::Helpers::UrlHelper
include ApplicationHelper
@@ -10,6 +8,7 @@ class ProtocolsController < ApplicationController
include ProtocolsIoHelper
include TeamsHelper
include CommentHelper
+ include ProtocolsExporterV2
before_action :check_create_permissions, only: %i(
create
@@ -74,6 +73,8 @@ class ProtocolsController < ApplicationController
before_action :check_protocolsio_import_permissions,
only: %i(protocolsio_import_create protocolsio_import_save)
+ before_action :set_importer, only: %i(load_from_file import)
+
def index; end
def datatable
@@ -524,14 +525,14 @@ class ProtocolsController < ApplicationController
if @protocol.can_destroy?
transaction_error = false
Protocol.transaction do
- begin
- import_into_existing(
- @protocol, @protocol_json, current_user, current_team
- )
- rescue Exception
- transaction_error = true
- raise ActiveRecord:: Rollback
- end
+ @importer.import_into_existing(
+ @protocol, @protocol_json
+ )
+ rescue StandardError => e
+ transaction_error = true
+ Rails.logger.error(e.message)
+ Rails.logger.error(e.backtrace.join("\n"))
+ raise ActiveRecord::Rollback
end
if transaction_error
@@ -564,14 +565,12 @@ class ProtocolsController < ApplicationController
respond_to do |format|
transaction_error = false
Protocol.transaction do
- begin
- protocol =
- import_new_protocol(@protocol_json, @team, @type, current_user)
- rescue StandardError => ex
- Rails.logger.error ex.message
- transaction_error = true
- raise ActiveRecord:: Rollback
- end
+ protocol =
+ @importer.import_new_protocol(@protocol_json, @type)
+ rescue StandardError => e
+ Rails.logger.error e.backtrace.join("\n")
+ transaction_error = true
+ raise ActiveRecord::Rollback
end
p_name =
@@ -659,7 +658,7 @@ class ProtocolsController < ApplicationController
# and some modals get closed and opened
end
rescue StandardError => e
- Rails.logger.error(e.message)
+ Rails.logger.error(e.backtrace.join("\n"))
@protocolsio_general_error = true
respond_to do |format|
format.js {}
@@ -697,8 +696,8 @@ class ProtocolsController < ApplicationController
@protocolsio_general_error = false
Protocol.transaction do
begin
- protocol = import_new_protocol(
- @db_json, current_team, params[:type].to_sym, current_user
+ protocol = @importer.import_new_protocol(
+ @db_json, params[:type].to_sym
)
rescue Exception
transaction_error = true
@@ -763,6 +762,10 @@ class ProtocolsController < ApplicationController
end
end
ostream = step.tiny_mce_assets.save_to_eln(ostream, step_dir)
+
+ step.step_texts.each do |step_text|
+ ostream = step_text.tiny_mce_assets.save_to_eln(ostream, step_dir)
+ end
end
end
end
@@ -989,6 +992,15 @@ class ProtocolsController < ApplicationController
private
+ def set_importer
+ case params.dig('protocol', 'elnVersion')
+ when '1.0'
+ @importer = ProtocolsImporter.new(current_user, current_team)
+ when '1.1'
+ @importer = ProtocolsImporterV2.new(current_user, current_team)
+ end
+ end
+
def valid_protocol_json(json)
JSON.parse(json)
return true
diff --git a/app/javascript/vue/protocol/protocolOptions.vue b/app/javascript/vue/protocol/protocolOptions.vue
index cafd8664c..7c19c6b0d 100644
--- a/app/javascript/vue/protocol/protocolOptions.vue
+++ b/app/javascript/vue/protocol/protocolOptions.vue
@@ -43,6 +43,7 @@
{{ i18n.t("my_modules.protocol.options_dropdown.import") }}
diff --git a/app/utilities/protocols_exporter_v2.rb b/app/utilities/protocols_exporter_v2.rb
new file mode 100644
index 000000000..ebe12d35f
--- /dev/null
+++ b/app/utilities/protocols_exporter_v2.rb
@@ -0,0 +1,136 @@
+require 'zip'
+
+module ProtocolsExporterV2
+ include ProtocolsExporter
+
+ private
+
+ def generate_envelope_xml(protocols)
+ envelope_xml = "\n"
+ protocols.each do |protocol|
+ protocol_name = get_protocol_name(protocol)
+ envelope_xml << "#{protocol_name}" \
+ "\n"
+ end
+ envelope_xml << "\n"
+ envelope_xml
+ end
+
+ def generate_protocol_xml(protocol)
+ protocol_name = get_protocol_name(protocol)
+
+ protocol_xml =
+ "\n" \
+ "\n" \
+ "#{protocol_name}\n" \
+ "#{protocol.authors}\n" \
+ "" \
+ "" \
+ "\n"
+
+ if tiny_mce_asset_present?(protocol) && protocol.description
+ protocol_xml << get_tiny_mce_assets(protocol.description)
+ end
+
+ protocol_xml << "#{protocol.created_at.as_json}\n"
+ protocol_xml << "#{protocol.updated_at.as_json}\n"
+
+ # Steps
+ if protocol.steps.any?
+ protocol_xml <<
+ "\n" \
+ "#{protocol.steps.order(:position).map { |s| step_xml(s) }.join}" \
+ "\n"
+ end
+
+ protocol_xml << "\n"
+ protocol_xml << ''
+ protocol_xml
+ end
+
+ def step_xml(step)
+ step_guid = get_guid(step.id)
+ xml = "\n" \
+ "#{step.name}\n"
+
+ # Assets
+ xml << "\n#{step.assets.map { |a| asset_xml(a) }.join}\n" if step.assets.any?
+
+ if step.step_orderable_elements.any?
+ xml << "\n"
+ step.step_orderable_elements.find_each do |step_orderable_element|
+ element = step_orderable_element.orderable
+ element_guid = get_guid(element.id)
+ xml << ""
+
+ case element
+ when StepText
+ xml << step_text_xml(element)
+ when StepTable
+ xml << table_xml(element.table)
+ when Checklist
+ xml << checklist_xml(element)
+ end
+
+ xml << "\n"
+ end
+ xml << "\n"
+ end
+
+ xml << ''
+
+ xml
+ end
+
+ def step_text_xml(step_text)
+ xml = "\n" \
+ "\n" \
+ ""\
+ "\n"
+
+ xml << get_tiny_mce_assets(step_text.text)
+
+ xml << "\n"
+ end
+
+ def table_xml(table)
+ "\n" \
+ "#{table.name}\n" \
+ "#{table.contents.unpack1('H*')}\n" \
+ "\n"
+ end
+
+ def checklist_xml(checklist)
+ xml = "\n" \
+ "#{checklist.name}\n"
+
+ if checklist.checklist_items.any?
+ xml << "\n#{checklist.checklist_items.map { |ci| checklist_item_xml(ci) }.join}\n"
+ end
+
+ xml << "\n"
+
+ xml
+ end
+
+ def checklist_item_xml(checklist_item)
+ "- \n" \
+ "#{checklist_item.text}\n" \
+ "
\n" \
+ end
+
+ def asset_xml(asset)
+ asset_guid = get_guid(asset.id)
+ "#{asset_guid}#{File.extname(asset.file_name)}" \
+ "\n" \
+ "#{asset.file_name}\n" \
+ "#{asset.content_type}\n" \
+ "\n" \
+ "\n"
+ end
+end
diff --git a/app/utilities/protocols_importer.rb b/app/utilities/protocols_importer.rb
index 3d5f6c884..75b5e7211 100644
--- a/app/utilities/protocols_importer.rb
+++ b/app/utilities/protocols_importer.rb
@@ -1,17 +1,22 @@
# frozen_string_literal: true
-module ProtocolsImporter
+class ProtocolsImporter
include RenamingUtil
- def import_new_protocol(protocol_json, team, type, user)
+ def initialize(user, team)
+ @user = user
+ @team = team
+ end
+
+ def import_new_protocol(protocol_json, type)
remove_empty_inputs(protocol_json)
protocol = Protocol.new(
name: protocol_json['name'],
authors: protocol_json['authors'],
protocol_type: (type == :public ? :in_repository_public : :in_repository_private),
published_on: (type == :public ? Time.now : nil),
- added_by: user,
- team: team
+ added_by: @user,
+ team: @team
)
# Try to rename record
@@ -21,19 +26,19 @@ module ProtocolsImporter
protocol.save!
# Protocol is saved, populate it
- populate_protocol(protocol, protocol_json, user, team)
+ populate_protocol(protocol, protocol_json)
protocol
end
- def import_into_existing(protocol, protocol_json, user, team)
+ def import_into_existing(protocol, protocol_json)
# Firstly, destroy existing protocol's contents
protocol.tiny_mce_assets.destroy_all
protocol.destroy_contents
protocol.reload
# Alright, now populate the protocol
- populate_protocol(protocol, protocol_json, user, team)
+ populate_protocol(protocol, protocol_json)
protocol.reload
# Unlink the protocol
@@ -43,9 +48,20 @@ module ProtocolsImporter
private
- def populate_protocol(protocol, protocol_json, user, team)
+ def create_in_step!(step, new_orderable)
+ ActiveRecord::Base.transaction do
+ new_orderable.save!
+
+ step.step_orderable_elements.create!(
+ position: step.step_orderable_elements.length,
+ orderable: new_orderable
+ )
+ end
+ end
+
+ def populate_protocol(protocol, protocol_json)
protocol.reload
- protocol.description = populate_rte(protocol_json, protocol, team)
+ protocol.description = populate_rte(protocol_json, protocol)
protocol.save!
asset_ids = []
step_pos = 0
@@ -55,22 +71,27 @@ module ProtocolsImporter
name: step_json['name'],
position: step_pos,
completed: false,
- user: user,
- last_modified_by: user,
+ user: @user,
+ last_modified_by: @user,
protocol: protocol
)
# need step id to link image to step
- step.description = populate_rte(step_json, step, team)
+ step_description_text = step.step_texts.build(text: populate_rte(step_json, step))
+ create_in_step!(step, step_description_text)
+
step.save!
step_pos += 1
step_json['checklists']&.values&.each do |checklist_json|
- checklist = Checklist.create!(
+ checklist = Checklist.new(
name: checklist_json['name'],
step: step,
- created_by: user,
- last_modified_by: user
+ created_by: @user,
+ last_modified_by: @user
)
+
+ create_in_step!(step, checklist)
+
next unless checklist_json['items']
item_pos = 0
@@ -79,8 +100,8 @@ module ProtocolsImporter
text: item_json['text'],
checked: false,
position: item_pos,
- created_by: user,
- last_modified_by: user,
+ created_by: @user,
+ last_modified_by: @user,
checklist: checklist
)
item_pos += 1
@@ -88,26 +109,27 @@ module ProtocolsImporter
end
step_json['tables']&.values&.each do |table_json|
- table = Table.create!(
- name: table_json['name'],
- contents: Base64.decode64(table_json['contents']),
- created_by: user,
- last_modified_by: user,
- team: team
- )
- StepTable.create!(
+ step_table = StepTable.new(
step: step,
- table: table
+ table: Table.new(
+ name: table_json['name'],
+ contents: Base64.decode64(table_json['contents']),
+ created_by: @user,
+ last_modified_by: @user,
+ team: @team
+ )
)
+
+ create_in_step!(step, step_table)
end
next unless step_json['assets']
step_json['assets']&.values&.each do |asset_json|
asset = Asset.new(
- created_by: user,
- last_modified_by: user,
- team: team
+ created_by: @user,
+ last_modified_by: @user,
+ team: @team
)
# Decode the file bytes
@@ -143,14 +165,14 @@ module ProtocolsImporter
end
# create tiny_mce assets and change the inport tokens
- def populate_rte(object_json, object, team)
+ def populate_rte(object_json, object)
return populate_rte_legacy(object_json) unless object_json['descriptionAssets']
description = TinyMceAsset.update_old_tinymce(object_json['description'], nil, true)
object_json['descriptionAssets'].values.each do |tiny_mce_img_json|
tiny_mce_img = TinyMceAsset.new(
object: object,
- team_id: team.id,
+ team_id: @team.id,
saved: true
)
tiny_mce_img.save!
diff --git a/app/utilities/protocols_importer_v2.rb b/app/utilities/protocols_importer_v2.rb
new file mode 100644
index 000000000..c35e33f90
--- /dev/null
+++ b/app/utilities/protocols_importer_v2.rb
@@ -0,0 +1,224 @@
+# frozen_string_literal: true
+
+class ProtocolsImporterV2
+ include RenamingUtil
+
+ def initialize(user, team)
+ @user = user
+ @team = team
+ end
+
+ def import_new_protocol(protocol_json, type)
+ remove_empty_inputs(protocol_json)
+ protocol = Protocol.new(
+ name: protocol_json['name'],
+ authors: protocol_json['authors'],
+ protocol_type: (type == :public ? :in_repository_public : :in_repository_private),
+ published_on: (type == :public ? Time.now : nil),
+ added_by: @user,
+ team: @team
+ )
+
+ # Try to rename record
+ rename_record(protocol, :name) if protocol.invalid?
+
+ # Okay, now save the protocol
+ protocol.save!
+
+ # Protocol is saved, populate it
+ populate_protocol(protocol, protocol_json)
+
+ protocol
+ end
+
+ def import_into_existing(protocol, protocol_json)
+ # Firstly, destroy existing protocol's contents
+ protocol.tiny_mce_assets.destroy_all
+ protocol.destroy_contents
+ protocol.reload
+
+ # Alright, now populate the protocol
+ populate_protocol(protocol, protocol_json)
+ protocol.reload
+
+ # Unlink the protocol
+ protocol.unlink
+ protocol
+ end
+
+ private
+
+ def create_in_step!(step, new_orderable)
+ ActiveRecord::Base.transaction do
+ new_orderable.save!
+ step.step_orderable_elements.create!(
+ position: step.step_orderable_elements.length,
+ orderable: new_orderable
+ )
+ end
+ end
+
+ def populate_protocol(protocol, protocol_json)
+ protocol.reload
+ protocol.description = populate_rte(protocol_json, protocol)
+ protocol.save!
+ asset_ids = []
+ step_pos = 0
+ # Check if protocol has steps
+ protocol_json['steps']&.values&.each do |step_json|
+ step = Step.create!(
+ name: step_json['name'],
+ position: step_pos,
+ completed: false,
+ user: @user,
+ last_modified_by: @user,
+ protocol: protocol
+ )
+
+ step.save!
+ step_pos += 1
+
+ step_json['stepElements']&.values&.each do |element_params|
+ case element_params['type']
+ when 'StepText'
+ create_step_text(step, element_params['stepText'])
+ when 'StepTable'
+ create_step_table(step, element_params['elnTable'])
+ when 'Checklist'
+ create_checklist(step, element_params['checklist'])
+ end
+ end
+
+ next unless step_json['assets']
+
+ create_assets(step_json)
+ end
+
+ # Post process assets
+ asset_ids.each do |asset_id|
+ Asset.find(asset_id).post_process_file(protocol.team)
+ end
+ end
+
+ def create_assets(step_json)
+ step_json['assets']&.values&.each do |asset_json|
+ asset = Asset.new(
+ created_by: @user,
+ last_modified_by: @user,
+ team: @team
+ )
+
+ # Decode the file bytes
+ asset.file.attach(io: StringIO.new(Base64.decode64(asset_json['bytes'])),
+ filename: asset_json['fileName'],
+ content_type: asset_json['fileType'],
+ metadata: JSON.parse(asset_json['fileMetadata'] || '{}'))
+ asset.save!
+ asset_ids << asset.id
+
+ StepAsset.create!(
+ step: step,
+ asset: asset
+ )
+ end
+ end
+
+ def create_step_text(step, params)
+ step_text = StepText.create!(
+ step: step
+ )
+
+ step_text.update!(text: populate_rte(params, step_text))
+
+ create_in_step!(step, step_text)
+ end
+
+ def create_step_table(step, params)
+ step_table = StepTable.new(
+ step: step,
+ table: Table.new(
+ name: params['name'],
+ contents: Base64.decode64(params['contents']),
+ created_by: @user,
+ last_modified_by: @user,
+ team: @team
+ )
+ )
+
+ create_in_step!(step, step_table)
+ end
+
+ def create_checklist(step, params)
+ checklist = Checklist.new(
+ name: params['name'],
+ step: step,
+ created_by: @user,
+ last_modified_by: @user
+ )
+
+ create_in_step!(step, checklist)
+
+ return unless params['items']
+
+ item_pos = 0
+
+ params['items'].each_value do |item_json|
+ ChecklistItem.create!(
+ text: item_json['text'],
+ checked: false,
+ position: item_pos,
+ created_by: @user,
+ last_modified_by: @user,
+ checklist: checklist
+ )
+ item_pos += 1
+ end
+ end
+
+ def remove_empty_inputs(obj)
+ obj.each_key do |key|
+ case obj[key]
+ when ''
+ obj[key] = nil
+ when Hash
+ # Recursive call
+ remove_empty_inputs(obj[key])
+ end
+ end
+ end
+
+ # create tiny_mce assets and change the import tokens
+ def populate_rte(params, object)
+ description = params['description'] || params['contents']
+
+ return description unless params['descriptionAssets']
+
+ params['descriptionAssets'].each_value do |tiny_mce_img_json|
+ tiny_mce_img = TinyMceAsset.new(
+ object: object,
+ team_id: @team.id,
+ saved: true
+ )
+ tiny_mce_img.save!
+
+ # Decode the file bytes
+ file = StringIO.new(Base64.decode64(tiny_mce_img_json['bytes']))
+ to_blob = ActiveStorage::Blob.create_and_upload!(
+ io: file,
+ filename: tiny_mce_img_json['fileName'],
+ content_type: tiny_mce_img_json['fileType'],
+ metadata: JSON.parse(tiny_mce_img_json['fileMetadata'] || '{}')
+ )
+ tiny_mce_img.image.attach(to_blob)
+ description.gsub!(
+ "data-mce-token=\"#{tiny_mce_img_json['tokenId']}\"",
+ "data-mce-token=\"#{Base62.encode(tiny_mce_img.id)}\""
+ ) || description.gsub!(
+ "data-mce-token=\"#{Base62.encode(tiny_mce_img_json['tokenId'].to_i)}\"",
+ "data-mce-token=\"#{Base62.encode(tiny_mce_img.id)}\""
+ )
+ description.gsub!(' ]]-->', '')
+ end
+ description
+ end
+end
diff --git a/app/views/protocols/import_export/_preview_templates.html.erb b/app/views/protocols/import_export/_preview_templates.html.erb
index fe50a4689..018ab13e3 100644
--- a/app/views/protocols/import_export/_preview_templates.html.erb
+++ b/app/views/protocols/import_export/_preview_templates.html.erb
@@ -17,6 +17,9 @@
+
+