Merge branch 'ux-release-1' into ml-sci-2244

This commit is contained in:
mlorb 2018-04-26 14:07:03 +02:00 committed by GitHub
commit 88d5ba369d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 1506 additions and 255 deletions

View file

@ -55,7 +55,6 @@ gem 'roo', '~> 2.7.1' # Spreadsheet parser
gem 'wicked_pdf', '~> 1.1.0'
gem 'silencer' # Silence certain Rails logs
gem 'wkhtmltopdf-heroku'
gem 'remotipart', '~> 1.2' # Async file uploads
gem 'faker' # Generate fake data
gem 'auto_strip_attributes', '~> 2.1' # Removes unnecessary whitespaces from ActiveRecord or ActiveModel attributes
gem 'deface', '~> 1.0'
@ -70,7 +69,7 @@ gem 'jbuilder' # JSON structures via a Builder-style DSL
gem 'activerecord-import'
gem 'scenic', '~> 1.4'
gem 'paperclip', '~> 5.1' # File attachment, image attachment library
gem 'paperclip', '~> 5.3' # File attachment, image attachment library
gem 'aws-sdk', '~> 2'
gem 'delayed_job_active_record'

View file

@ -149,8 +149,6 @@ GEM
mail
climate_control (0.2.0)
cliver (0.3.2)
cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0)
coderay (1.1.2)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
@ -226,7 +224,7 @@ GEM
activesupport (>= 4.2.0)
hammerjs-rails (2.0.8)
hashie (3.5.7)
i18n (0.9.3)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
i18n-js (3.0.3)
i18n (~> 0.6, >= 0.6.6)
@ -316,12 +314,12 @@ GEM
oauth2 (~> 1.1)
omniauth (~> 1.2)
orm_adapter (0.5.0)
paperclip (5.2.1)
paperclip (5.3.0)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
cocaine (~> 0.5.5)
mime-types
mimemagic (~> 0.3.0)
terrapin (~> 0.6.0)
parallel (1.12.1)
parser (2.4.0.2)
ast (~> 2.3)
@ -389,7 +387,6 @@ GEM
rdoc (4.3.0)
recaptcha (4.6.3)
json
remotipart (1.3.1)
responders (2.4.0)
actionpack (>= 4.2.0, < 5.3)
railties (>= 4.2.0, < 5.3)
@ -482,6 +479,8 @@ GEM
ruby-progressbar (~> 1.9)
sourcemap (~> 0.1)
stream (0.5)
terrapin (0.6.0)
climate_control (>= 0.0.3, < 1.0)
thor (0.20.0)
thread_safe (0.3.6)
tilt (2.0.8)
@ -489,7 +488,7 @@ GEM
railties (>= 3.1.1)
turbolinks (2.5.4)
coffee-rails
tzinfo (1.2.4)
tzinfo (1.2.5)
thread_safe (~> 0.1)
uglifier (4.1.4)
execjs (>= 0.3.0, < 3)
@ -570,7 +569,7 @@ DEPENDENCIES
nokogiri (~> 1.8.1)
omniauth
omniauth-linkedin-oauth2
paperclip (~> 5.1)
paperclip (~> 5.3)
pg (~> 0.18)
phantomjs
poltergeist
@ -583,7 +582,6 @@ DEPENDENCIES
rails_12factor
rails_autolink (~> 1.1, >= 1.1.6)
recaptcha
remotipart (~> 1.2)
rgl
roo (~> 2.7.1)
rspec-rails

View file

@ -1 +1 @@
1.12.11
1.13.1

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -3,7 +3,6 @@
//= require jquery
//= require jquery.turbolinks
//= require jquery_ujs
//= require jquery.remotipart
//= require jquery.mousewheel.min
//= require jquery.scrollTo
//= require jquery.autosize

View file

@ -134,6 +134,9 @@
$form.clearFormErrors();
switch(resultTypeEnum) {
case ResultTypeEnum.FILE:
_handleResultFileSubmit($form, ev);
break;
case ResultTypeEnum.TABLE:
var $nameInput = $form.find('#result_name');
var nameValid = textValidator(ev, $nameInput, 0,
@ -155,6 +158,55 @@
}
}
// create custom ajax request in order to fix issuses with remote: true from
function _handleResultFileSubmit(form, ev) {
ev.preventDefault();
ev.stopPropagation();
animateSpinner();
var data = new FormData();
var file = document.getElementById('result_asset_attributes_file')
.files[0];
data.append('result[name]', form.find('#result_name').val());
data.append('result[asset_attributes][id]',
form.find('#result_asset_attributes_id').val());
if( file ) {
data.append('result[asset_attributes][file]', file);
}
$.ajax({
type: 'PUT',
url: form.attr('action'),
data: data,
success: function(data) {
animateSpinner(null, false);
$('.edit_result').parent().remove();
$(data.html).prependTo('#results').promise().done(function() {
$.each($('#results').find('.result'),
function() {
initFormSubmitLinks($(this));
ResutlAssets.applyEditResultAssetCallback();
applyCollapseLinkCallBack();
toggleResultEditButtons(true);
initPreviewModal();
Comments.initialize();
ResutlAssets.initNewResultAsset();
expandResult($(this));
});
});
$('#results-toolbar').show();
},
error: function(XHR) {
animateSpinner(null, false)
$('.edit_result').renderFormErrors('result',
XHR.responseJSON['errors']);
},
processData: false,
contentType: false,
});
}
// init cancel button
function initCancelFormButton(form, callback) {
$(form).find('.cancel-new').click(function(event) {

View file

@ -327,7 +327,6 @@ function destroyFullZoom() {
$(".module-large .buttons-container [role=tab]").off("ajax:before ajax:success ajax:error");
$("div.module-large").off("mouseenter mouseleave");
$("div.module-large a.due-date-link").off("ajax:success ajax:error");
$("#manage-module-description-modal [data-action='submit']").off("click");
$("#manage-module-due-date-modal [data-action='submit']").off("click");
$("div.module-large a.edit-tags-link").off("ajax:before ajax:success");
$("li[data-module-group]").off("mouseenter mouseleave");
@ -593,46 +592,6 @@ function bindWindowResizeEvent() {
function bindFullZoomAjaxTabs() {
var manageUsersModal = null;
var manageUsersModalBody = null;
var editDescriptionModal = null;
var editDescriptionModalBody = null;
// Initialize edit description modal window
function initEditDescription($el) {
$el.find(".description-link")
.on("ajax:success", function(ev, data, status) {
var descriptionLink = $(this);
var descriptionTab = descriptionLink.closest(".tab-pane");
// Set modal body & title
editDescriptionModalBody.html(data.html);
editDescriptionModal
.find("#manage-module-description-modal-label")
.text(data.title);
editDescriptionModalBody.find("form")
.on("ajax:success", function(ev2, data2, status2) {
// Update module's description in the tab
descriptionTab.find(".description-label")
.html(data2.description_label);
// Close modal
editDescriptionModal.modal("hide");
})
.on("ajax:error", function(ev2, data2, status2) {
// Display errors if needed
$(this).renderFormErrors("my_module", data2.responseJSON);
});
// Disable canvas dragging events
toggleCanvasEvents(false);
// Show modal
editDescriptionModal.modal("show");
})
.on("ajax:error", function(ev, data, status) {
// TODO
});
}
// Initialize users editing modal remote loading.
function initUsersEditLink($el) {
@ -676,8 +635,6 @@ function bindFullZoomAjaxTabs() {
manageUsersModal = $("#manage-module-users-modal");
manageUsersModalBody = manageUsersModal.find(".modal-body");
editDescriptionModal = $("#manage-module-description-modal");
editDescriptionModalBody = editDescriptionModal.find(".modal-body");
// Reload users tab HTML element when modal is closed
manageUsersModal.on("hide.bs.modal", function () {
@ -705,21 +662,6 @@ function bindFullZoomAjaxTabs() {
manageUsersModalBody.html("");
});
// When clicking on description modal "Update" button,
// submit its inner-lying form
editDescriptionModal.find("[data-action='submit']").click(function() {
editDescriptionModalBody.find("form").submit();
});
// Remove description modal content when window is closed
editDescriptionModal.on("hidden.bs.modal", function() {
$(this).find("form").off("ajax:success ajax:error");
editDescriptionModalBody.html("");
// Re-activate canvas dragging events
toggleCanvasEvents(true);
});
// initialize my_module tab remote loading
var elements = $(".module-large .buttons-container [role=tab]");
elements.on("ajax:before", function (e) {

View file

@ -6,7 +6,7 @@
animateSpinner();
location.reload();
}
$(document).ready(function() {
$('#create-new-repository').initializeModal('#create-repo-modal');
});

View file

@ -1,3 +1,44 @@
(function() {
'use strict';
// handles CSV upload for samples import
function postSamplesCSV() {
var form = $('form#form-samples-file');
var submitBtn = form.find('input[type="submit"]');
submitBtn.on('click', function(event) {
event.preventDefault();
event.stopPropagation();
var data = new FormData();
data.append('file', document.getElementById('file').files[0]);
$.ajax({
type: 'POST',
url: form.attr('action'),
data: data,
success: _handleSuccessfulSubmit,
error: _handleErrorSubmit,
processData: false,
contentType: false,
});
});
}
function _handleSuccessfulSubmit(data) {
$('#modal-parse-samples').html(data.html);
$('#modal-import-samples').modal('hide');
$('#modal-parse-samples').modal('show');
}
function _handleErrorSubmit(XHR) {
var formGroup = $('form#form-samples-file').find('.form-group');
formGroup.addClass('has-error');
formGroup.find('.help-block').remove();
formGroup.append('<span class="help-block">' +
XHR.responseJSON.message + '</span>');
}
$(document).ready(postSamplesCSV);
})()
// Create import samples ajax
$("#modal-import-samples").on("show.bs.modal", function(event) {
formGroup = $(this).find(".form-group");
@ -5,18 +46,6 @@ $("#modal-import-samples").on("show.bs.modal", function(event) {
formGroup.find(".help-block").remove();
});
$("form#form-samples-file")
.on("ajax:success", function(ev, data, status) {
$("#modal-parse-samples").html(data.html);
$("#modal-import-samples").modal("hide");
$("#modal-parse-samples").modal("show");
})
.on("ajax:error", function(ev, data, status) {
$(this).find(".form-group").addClass("has-error");
$(this).find(".form-group").find(".help-block").remove();
$(this).find(".form-group").append("<span class='help-block'>" + data.responseJSON.message + "</span>");
});
$('.sample-assign-group > .btn').click(function() {
$('.btn-group > .btn').removeClass('active btn-primary');
$('.btn-group > .btn').addClass('btn-default');

View file

@ -33,7 +33,12 @@ var renderFormError = function(ev, input, errMsgs, clearErr, errAttributes) {
// Add error message/s
var errorText = ($.makeArray(errMsgs).map(function(m) {
return m.strToErrorFormat();
if( m instanceof Array ) {
return m.join(', ').strToErrorFormat();
} else {
return m.strToErrorFormat();
}
})).join('<br />');
var $errSpan = "<span class='help-block'" +
errAttributes + '>' + errorText + '</span>';

View file

@ -1726,3 +1726,11 @@ th.custom-field .modal-tooltiptext {
.parse-records-table {
max-height: 200px;
}
.linkedin-signin-button {
margin: 15px 0;
}
.tiny-mce-pdf-ready {
max-width: 100%;
}

View file

@ -26,8 +26,9 @@ class MyModulesController < ApplicationController
archive)
before_action :check_complete_module_permission, only: :complete_my_module
before_action :check_assign_repository_records_permissions, only:
%i(assign_repository_records unassign_repository_records assign_samples
unassign_samples)
%i(assign_repository_records unassign_repository_records)
before_action :check_assign_samples_permissions, only: %i(assign_samples
unassign_samples)
layout 'fluid'.freeze
@ -624,6 +625,11 @@ class MyModulesController < ApplicationController
can_assign_repository_rows_to_module?(@my_module)
end
def check_assign_samples_permissions
render_403 unless module_page? &&
can_assign_sample_to_module?(@my_module)
end
def check_complete_module_permission
render_403 unless can_complete_module?(@my_module)
end

View file

@ -60,8 +60,11 @@ class ProtocolsController < ApplicationController
copy_to_repository
copy_to_repository_modal
)
before_action :check_import_permissions, only: [:import]
before_action :check_export_permissions, only: [:export]
before_action :check_import_permissions, only: :import
before_action :check_export_permissions, only: :export
before_action :check_protocolsio_import_permissions,
only: %i(protocolsio_import_create protocolsio_import_save)
def index; end
@ -739,6 +742,7 @@ class ProtocolsController < ApplicationController
step_dir = "#{protocol_dir}/#{step_guid}"
if step.assets.exists?
step.assets.order(:id).each do |asset|
next unless asset.file.exists?
asset_guid = get_guid(asset.id)
asset_file_name = asset_guid.to_s +
File.extname(asset.file_file_name).to_s
@ -1169,4 +1173,8 @@ class ProtocolsController < ApplicationController
def metadata_params
params.require(:protocol).permit(:name, :authors, :description)
end
def check_protocolsio_import_permissions
render_403 unless can_create_protocols_in_repository?(current_team)
end
end

View file

@ -5,7 +5,7 @@ class RepositoriesController < ApplicationController
%i(repository_table_index export_repository parse_sheet import_records)
before_action :check_team, only: %i(parse_sheet import_records)
before_action :check_view_all_permissions, only: :index
before_action :check_view_permissions, only: :export_repository
before_action :check_view_permissions, only: %i(export_repository show)
before_action :check_manage_permissions, only:
%i(destroy destroy_modal rename_modal update)
before_action :check_create_permissions, only:

View file

@ -254,7 +254,7 @@ class RepositoryRowsController < ApplicationController
if selected_params
selected_params.each do |row_id|
row = @repository.repository_rows.find_by_id(row_id)
if row && can_manage_repository_row?(row)
if row && can_manage_repository_rows?(@repository.team)
row.destroy && deleted_count += 1
end
end
@ -327,9 +327,7 @@ class RepositoryRowsController < ApplicationController
end
def check_manage_permissions
render_403 unless @repository.repository_rows.all? do |row|
can_manage_repository_row?(row)
end
render_403 unless can_manage_repository_rows?(@repository.team)
end
def record_params

View file

@ -1,7 +1,9 @@
class UserSamplesController < ApplicationController
def save_samples_table_status
samples_table = SamplesTable.where(user: @current_user,
team: params[:team]).first
team: params[:team])
.order(:id)
.first
if samples_table
samples_table.update(status: params[:state])
else
@ -20,7 +22,7 @@ class UserSamplesController < ApplicationController
def load_samples_table_status
samples_table_state = SamplesTable.find_status(current_user,
current_team).first
current_team)
if samples_table_state.blank?
st = SamplesTable.new(user: current_user, team: current_team)
st.save

View file

@ -35,9 +35,9 @@ class WopiController < ActionController::Base
when 'REFRESH_LOCK'
refresh_lock
when 'GET_SHARE_URL'
render nothing: :true, status: 501 and return
render body: nil, status: 501 and return
else
render nothing: :true, status: 404 and return
render body: nil, status: 404 and return
end
end
@ -86,27 +86,27 @@ class WopiController < ActionController::Base
end
def put_relative
render nothing: :true, status: 501 and return
render body: nil, status: 501 and return
end
def lock
lock = request.headers['X-WOPI-Lock']
logger.warn 'WOPI: lock; ' + lock.to_s
render nothing: :true, status: 404 and return if lock.nil? || lock.blank?
render body: nil, status: 404 and return if lock.nil? || lock.blank?
@asset.with_lock do
if @asset.locked?
if @asset.lock == lock
@asset.refresh_lock
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
render body: nil, status: 200 and return
else
response.headers['X-WOPI-Lock'] = @asset.lock
render nothing: :true, status: 409 and return
render body: nil, status: 409 and return
end
else
@asset.lock_asset(lock)
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
render body: nil, status: 200 and return
end
end
end
@ -116,7 +116,7 @@ class WopiController < ActionController::Base
lock = request.headers['X-WOPI-Lock']
old_lock = request.headers['X-WOPI-OldLock']
if lock.nil? || lock.blank? || old_lock.blank?
render nothing: :true, status: 400 and return
render body: nil, status: 400 and return
end
@asset.with_lock do
if @asset.locked?
@ -124,21 +124,21 @@ class WopiController < ActionController::Base
@asset.unlock
@asset.lock_asset(lock)
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
render body: nil, status: 200 and return
else
response.headers['X-WOPI-Lock'] = @asset.lock
render nothing: :true, status: 409 and return
render body: nil, status: 409 and return
end
else
response.headers['X-WOPI-Lock'] = ' '
render nothing: :true, status: 409 and return
render body: nil, status: 409 and return
end
end
end
def unlock
lock = request.headers['X-WOPI-Lock']
render nothing: :true, status: 400 and return if lock.nil? || lock.blank?
render body: nil, status: 400 and return if lock.nil? || lock.blank?
@asset.with_lock do
if @asset.locked?
logger.warn "WOPI: current asset lock: #{@asset.lock},
@ -149,36 +149,36 @@ class WopiController < ActionController::Base
create_wopi_file_activity(@user, false)
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
render body: nil, status: 200 and return
else
response.headers['X-WOPI-Lock'] = @asset.lock
render nothing: :true, status: 409 and return
render body: nil, status: 409 and return
end
else
logger.warn 'WOPI: tried to unlock non-locked file'
response.headers['X-WOPI-Lock'] = ' '
render nothing: :true, status: 409 and return
render body: nil, status: 409 and return
end
end
end
def refresh_lock
lock = request.headers['X-WOPI-Lock']
render nothing: :true, status: 400 and return if lock.nil? || lock.blank?
render body: nil, status: 400 and return if lock.nil? || lock.blank?
@asset.with_lock do
if @asset.locked?
if @asset.lock == lock
@asset.refresh_lock
response.headers['X-WOPI-ItemVersion'] = @asset.version
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
render body: nil, status: 200 and return
else
response.headers['X-WOPI-Lock'] = @asset.lock
render nothing: :true, status: 409 and return
render body: nil, status: 409 and return
end
else
response.headers['X-WOPI-Lock'] = ' '
render nothing: :true, status: 409 and return
render body: nil, status: 409 and return
end
end
end
@ -190,7 +190,7 @@ class WopiController < ActionController::Base
else
response.headers['X-WOPI-Lock'] = ' '
end
render nothing: :true, status: 200 and return
render body: nil, status: 200 and return
end
end
@ -212,11 +212,11 @@ class WopiController < ActionController::Base
@protocol.update(updated_at: Time.now) if @protocol
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
render body: nil, status: 200 and return
else
logger.warn 'WOPI: wrong lock used to try and modify file'
response.headers['X-WOPI-Lock'] = @asset.lock
render nothing: :true, status: 409 and return
render body: nil, status: 409 and return
end
elsif !@asset.file_file_size.nil? && @asset.file_file_size.zero?
logger.warn 'WOPI: initializing empty file'
@ -228,11 +228,11 @@ class WopiController < ActionController::Base
@team.save
response.headers['X-WOPI-ItemVersion'] = @asset.version
render nothing: :true, status: 200 and return
render body: nil, status: 200 and return
else
logger.warn 'WOPI: trying to modify unlocked file'
response.headers['X-WOPI-Lock'] = ' '
render nothing: :true, status: 409 and return
render body: nil, status: 409 and return
end
end
end
@ -240,7 +240,7 @@ class WopiController < ActionController::Base
def load_vars
@asset = Asset.find_by_id(params[:id])
if @asset.nil?
render nothing: :true, status: 404 and return
render body: nil, status: 404 and return
else
logger.warn 'Found asset: ' + @asset.id.to_s
step_assoc = @asset.step
@ -264,13 +264,13 @@ class WopiController < ActionController::Base
wopi_token = params[:access_token]
if wopi_token.nil?
logger.warn 'WOPI: nil wopi token'
render nothing: :true, status: 401 and return
render body: nil, status: 401 and return
end
@user = User.find_by_valid_wopi_token(wopi_token)
if @user.nil?
logger.warn 'WOPI: no user with this token found'
render nothing: :true, status: 401 and return
render body: nil, status: 401 and return
end
logger.warn 'WOPI: user found by token ' + wopi_token +
' ID: ' + @user.id.to_s
@ -320,7 +320,7 @@ class WopiController < ActionController::Base
@breadcrumb_folder_url = @close_url
end
render nothing: :true, status: 404 and return unless @can_read
render body: nil, status: 404 and return unless @can_read
end
def verify_proof!
@ -336,15 +336,15 @@ class WopiController < ActionController::Base
logger.warn 'WOPI: proof verification: successful'
else
logger.warn 'WOPI: proof verification: not verified'
render nothing: :true, status: 500 and return
render body: nil, status: 500 and return
end
else
logger.warn 'WOPI: proof verification: timestamp too old; ' +
timestamp.to_s
render nothing: :true, status: 500 and return
render body: nil, status: 500 and return
end
rescue => e
logger.warn 'WOPI: proof verification: failed; ' + e.message
render nothing: :true, status: 500 and return
render body: nil, status: 500 and return
end
end

View file

@ -489,10 +489,7 @@ class SampleDatatable < CustomDatatable
end
def generate_sortable_displayed_columns
sort_order = SamplesTable.where(user: @user,
team: @team)
.pluck(:status)
.first['ColReorder']
sort_order = SamplesTable.find_status(@user, @team)['ColReorder']
sort_order.shift
sort_order.map! { |i| (i.to_i - 1).to_s }

View file

@ -165,7 +165,11 @@ module ProtocolsIoHelper
end
def step_hash_null?(step_json)
step_json.dig(0, 'components', 0, 'component_type_id').nil?
step_json.dig(
0, 'components', 0, 'component_type_id'
).nil? && step_json.dig(
0, 'components', '0', 'component_type_id'
).nil?
end
# Images are allowed in:
@ -350,7 +354,6 @@ module ProtocolsIoHelper
return unordered_step_json if base_step.nil?
number_of_steps = unordered_step_json.size
return unordered_step_json if number_of_steps == 1
base_step = unordered_step_json.find { |step| step['previous_guid'].nil? }
step_order = []
step_counter = 0
step_order[step_counter] = base_step

View file

@ -56,7 +56,7 @@ module ReportsHelper
end
# "Hack" to omit file preview URL because of WKHTML issues
def report_image_asset_url(asset)
def report_image_asset_url(asset, type = :asset, klass = nil)
prefix = ''
if ENV['PAPERCLIP_STORAGE'].present? &&
ENV['MAIL_SERVER_URL'].present? &&
@ -68,8 +68,9 @@ module ReportsHelper
!prefix.include?('https://')
prefix = "http://#{prefix}"
end
url = prefix + asset.url(:medium, timeout: Constants::URL_LONG_EXPIRE_TIME)
image_tag(url)
size = type == :tiny_mce_asset ? :large : :medium
url = prefix + asset.url(size, timeout: Constants::URL_LONG_EXPIRE_TIME)
image_tag(url, class: klass)
end
# "Hack" to load Glyphicons css directly from the CDN

View file

@ -17,7 +17,8 @@ module TinyMceHelper
html
end
def generate_image_tag_from_token(text, obj)
# @param pdf_export_ready is needed for wicked_pdf in export report action
def generate_image_tag_from_token(text, obj, pdf_export_ready = false)
return unless text
regex = Constants::TINY_MCE_ASSET_REGEX
text.gsub(regex) do |el|
@ -25,9 +26,13 @@ module TinyMceHelper
img = TinyMceAsset.find_by_id(match[1])
next unless img && img.team == current_team
next unless check_image_permissions(obj, img)
image_tag img.url,
class: 'img-responsive',
data: { token: Base62.encode(img.id) }
if pdf_export_ready
report_image_asset_url(img, :tiny_mce_asset, 'tiny-mce-pdf-ready')
else
image_tag(img.url,
class: 'img-responsive',
data: { token: Base62.encode(img.id) })
end
end
end

View file

@ -0,0 +1,19 @@
# When WOPI performs calls onto sciNote WOPI subdomain REST endpoints
# Rack::MethodOverride MUST be omitted because it crashes the requests
# due to trying to parse body of the requests
class WopiMethodOverride
def initialize(app)
@app = app
end
def call(env)
app = @app
unless WopiSubdomain.matches?(ActionDispatch::Request.new(env))
# Use the wrapped Rack::MethodOverride middleware
app = Rack::MethodOverride.new(@app)
end
app.call(env)
end
end

View file

@ -499,13 +499,7 @@ class Protocol < ApplicationRecord
self.protocol_protocol_keywords.destroy_all
if keywords.present?
keywords.each do |kw_name|
kw = ProtocolKeyword.find_by(name: kw_name)
if kw.blank?
kw = ProtocolKeyword.create(
name: kw_name,
team: self.team
)
end
kw = ProtocolKeyword.find_or_create_by(name: kw_name, team: team)
self.protocol_keywords << kw
end
end

View file

@ -3,15 +3,18 @@ class SamplesTable < ApplicationRecord
belongs_to :team, inverse_of: :samples_tables, optional: true
validates :user, :team, presence: true
validates :user, uniqueness: { scope: :team }
scope :find_status,
->(user, team) { where(user: user, team: team).pluck(:status) }
scope :find_status, (lambda do |user, team|
where(user: user, team: team)
.order(:id).pluck(:status).first
end)
def self.update_samples_table_state(custom_field, column_index)
samples_table = SamplesTable.where(user: custom_field.user,
team: custom_field.team)
team_status = samples_table.first['status']
.order(:id)
.first
team_status = samples_table['status']
if column_index
# delete column
team_status['columns'].delete(column_index)
@ -38,7 +41,7 @@ class SamplesTable < ApplicationRecord
SAMPLES_TABLE_DEFAULT_STATE['columns'].first
team_status['ColReorder'].insert(2, index)
end
samples_table.first.update(status: team_status)
samples_table.update(status: team_status)
end
def self.create_samples_table_state(user_team)

View file

@ -58,6 +58,7 @@ Canaid::Permissions.register_for(MyModule) do
# permissions
%i(manage_module
manage_users_in_module
assign_repository_rows_to_module
assign_sample_to_module
complete_module
create_comments_in_module)
@ -88,12 +89,18 @@ Canaid::Permissions.register_for(MyModule) do
user.is_owner_of_project?(my_module.experiment.project)
end
# module: assign/unassign sample, assign/unassign repository record
# module: assign/unassign repository record
# NOTE: Use 'module_page? &&' before calling this permission!
can :assign_repository_rows_to_module do |user, my_module|
user.is_technician_or_higher_of_project?(my_module.experiment.project)
end
# module: assign/unassign sample
# NOTE: Use 'module_page? &&' before calling this permission!
can :assign_sample_to_module do |user, my_module|
user.is_technician_or_higher_of_project?(my_module.experiment.project)
end
# module: complete/uncomplete
can :complete_module do |user, my_module|
user.is_technician_or_higher_of_project?(my_module.experiment.project)

View file

@ -124,13 +124,6 @@ Canaid::Permissions.register_for(Repository) do
end
end
Canaid::Permissions.register_for(RepositoryRow) do
# repository: update/delete record
can :manage_repository_row do |user, repository_row|
can_create_repository_rows?(user, repository_row.repository.team)
end
end
Canaid::Permissions.register_for(RepositoryColumn) do
# repository: update/delete field
can :manage_repository_column do |user, repository_column|

View file

@ -0,0 +1,240 @@
require 'fileutils'
class TeamExporter
def initialize(team_id)
@team = Team.includes(:user_teams).find_by_id(team_id)
raise StandardError, 'Can not load team' unless @team
@assets_to_copy = []
@tiny_mce_assets_to_copy = []
end
def export_to_dir
@asset_counter = 0
@team.transaction(isolation: :serializable) do
@dir_to_export = FileUtils.mkdir_p(
File.join("tmp/team_#{@team.id}_export_#{Time.now.to_i}")
).first
# Writing JSON file with team structure
File.write(
File.join(@dir_to_export, 'team_export.json'),
team(@team).to_json
)
# Copying assets
copy_files(@assets_to_copy, :file, File.join(@dir_to_export, 'assets')) do
@asset_counter += 1
end
# Copying tiny_mce_assets
copy_files(@tiny_mce_assets_to_copy,
:image,
File.join(@dir_to_export, 'tiny_mce_assets'))
puts "Exported assets: #{@asset_counter}"
puts "Exported tinyMCE assets: #{@team.tiny_mce_assets.count}"
puts "Exported users: #{@team.users.count}"
puts "Exported repositories: #{@team.repositories.count}"
puts "Exported projects: #{@team.projects.count}"
puts 'Done!'
end
end
private
def copy_files(assets, attachment_name, dir_name)
assets.flatten.each do |a|
next unless a.public_send(attachment_name).present?
unless a.public_send(attachment_name).exists?
raise StandardError,
"File id:#{a.id} of type #{attachment_name} is missing"
end
yield if block_given?
dir = FileUtils.mkdir_p(File.join(dir_name, a.id.to_s)).first
if defined?(S3_BUCKET)
s3_asset =
S3_BUCKET.object(a.public_send(attachment_name).path.remove(%r{^/}))
file_name = a.public_send(attachment_name).original_filename
File.open(File.join(dir, file_name), 'wb') do |f|
s3_asset.get(response_target: f)
end
else
FileUtils.cp(
a.public_send(attachment_name).path,
File.join(dir, a.public_send(attachment_name).original_filename)
)
end
end
end
def team(team)
if team.tiny_mce_assets.present?
@tiny_mce_assets_to_copy.push(team.tiny_mce_assets)
end
{
team: team,
default_admin_id: team.user_teams.where(role: 2).first.user.id,
users: team.users.map { |u| user(u) },
user_teams: team.user_teams,
notifications: Notification
.includes(:user_notifications)
.where('user_notifications.user_id': team.users)
.map { |n| notification(n) },
samples: team.samples.map { |s| sample(s) },
sample_groups: team.sample_groups,
sample_types: team.sample_types,
custom_fields: team.custom_fields,
repositories: team.repositories.map { |r| repository(r) },
tiny_mce_assets: team.tiny_mce_assets,
protocols: team.protocols.where(my_module: nil).map { |pr| protocol(pr) },
protocol_keywords: team.protocol_keywords,
projects: team.projects.map { |p| project(p) }
}
end
def notification(notification)
notification_json = notification.as_json
notification_json['type_of'] = Extends::NOTIFICATIONS_TYPES
.key(notification.read_attribute('type_of'))
.to_s
notification_json
end
def user(user)
user_json = user.as_json
# Looks like Devise doesn't export some fields to JSON, so add it manually
user_json['encrypted_password'] = user.encrypted_password
user_json['confirmed_at'] = user.confirmed_at
user_json['sign_in_count'] = user.sign_in_count
user_json['last_sign_in_at'] = user.last_sign_in_at
user_json['last_sign_in_ip'] = user.last_sign_in_ip
copy_files([user], :avatar, File.join(@dir_to_export, 'avatars'))
{
user: user_json,
user_notifications: user.user_notifications,
user_identities: user.user_identities,
samples_tables: user.samples_tables.where(team: @team),
repository_table_states:
user.repository_table_states.where(repository: @team.repositories)
}
end
def project(project)
{
project: project,
user_projects: project.user_projects,
activities: project.activities,
project_comments: project.project_comments,
reports: project.reports.map { |r| report(r) },
experiments: project.experiments.map { |e| experiment(e) },
tags: project.tags
}
end
def report(report)
{
report: report,
report_elements: report.report_elements
}
end
def experiment(experiment)
{
experiment: experiment,
my_modules: experiment.my_modules.map { |m| my_module(m) },
my_module_groups: experiment.my_module_groups
}
end
def my_module(my_module)
{
my_module: my_module,
outputs: my_module.outputs,
my_module_tags: my_module.my_module_tags,
task_comments: my_module.task_comments,
my_module_repository_rows: my_module.my_module_repository_rows,
sample_my_modules: my_module.sample_my_modules,
user_my_modules: my_module.user_my_modules,
protocols: my_module.protocols.map { |pr| protocol(pr) },
results: my_module.results.map { |res| result(res) }
}
end
def protocol(protocol)
{
protocol: protocol,
protocol_protocol_keywords: protocol.protocol_protocol_keywords,
steps: protocol.steps.map { |s| step(s) }
}
end
def step(step)
@assets_to_copy.push(step.assets.to_a) if step.assets.present?
{
step: step,
checklists: step.checklists.map { |c| checklist(c) },
step_comments: step.step_comments,
step_assets: step.step_assets,
assets: step.assets,
step_tables: step.step_tables,
tables: step.tables.map { |t| table(t) }
}
end
def checklist(checklist)
{
checklist: checklist,
checklist_items: checklist.checklist_items
}
end
def table(table)
return {} if table.nil?
table_json = table.as_json(except: %i(contents data_vector))
table_json['contents'] = Base64.encode64(table.contents)
table_json['data_vector'] = Base64.encode64(table.data_vector)
table_json
end
def result(result)
@assets_to_copy.push(result.asset) if result.asset.present?
{
result: result,
result_comments: result.result_comments,
asset: result.asset,
table: table(result.table),
result_text: result.result_text
}
end
def sample(sample)
{
sample: sample,
sample_custom_fields: sample.sample_custom_fields
}
end
def repository(repository)
{
repository: repository,
repository_columns: repository.repository_columns,
repository_rows: repository.repository_rows.map do |r|
repository_row(r)
end
}
end
def repository_row(repository_row)
{
repository_row: repository_row,
my_module_repository_rows: repository_row.my_module_repository_rows,
repository_cells: repository_row.repository_cells.map do |c|
repository_cell(c)
end
}
end
def repository_cell(cell)
{
repository_cell: cell,
repository_value: cell.value
}
end
end

View file

@ -0,0 +1,878 @@
class TeamImporter
def initialize
@user_mappings = {}
@notification_mappings = {}
@repository_mappings = {}
@sample_group_mappings = {}
@sample_type_mappings = {}
@custom_field_mappings = {}
@sample_mappings = {}
@project_mappings = {}
@repository_column_mappings = {}
@experiment_mappings = {}
@my_module_group_mappings = {}
@my_module_mappings = {}
@protocol_mappings = {}
@protocol_keyword_mappings = {}
@step_mappings = {}
@asset_mappings = {}
@tag_mappings = {}
@result_text_mappings = {}
@repository_row_mappings = {}
@result_mappings = {}
@checklist_mappings = {}
@table_mappings = {}
@project_counter = 0
@repository_counter = 0
@repository_row_counter = 0
@protocol_counter = 0
@step_counter = 0
@sample_counter = 0
@report_counter = 0
@my_module_counter = 0
@notification_counter = 0
@result_counter = 0
@asset_counter = 0
@user_counter = 0
@mce_asset_counter = 0
end
def import_from_dir(import_dir)
MyModule.skip_callback(:create, :before, :create_blank_protocol)
Activity.skip_callback(:create, :after, :generate_notification)
Protocol.skip_callback(:save, :after, :update_linked_children)
@import_dir = import_dir
team_json = JSON.parse(File.read("#{@import_dir}/team_export.json"))
team = Team.new(team_json['team'].slice(*Team.column_names))
team.id = nil
team.transaction(isolation: :serializable) do
team_creator_id = team.created_by_id
team.created_by_id = nil
team_last_modified_by = team.last_modified_by_id
team.last_modified_by_id = nil
team.save!
create_users(team_json['users'], team)
# Find new id of the first admin in the team
@admin_id = @user_mappings[team_json['default_admin_id']]
create_notifications(team_json['notifications'])
puts 'Assigning users to the team...'
team_json['user_teams'].each do |user_team_json|
user_team = UserTeam.new(user_team_json)
user_team.id = nil
user_team.user_id = find_user(user_team.user_id)
user_team.team_id = team.id
user_team.assigned_by_id = find_user(user_team.assigned_by_id)
user_team.save!
end
create_sample_groups(team_json['sample_groups'], team)
create_sample_types(team_json['sample_types'], team)
create_custom_fields(team_json['custom_fields'], team)
create_samples(team_json['samples'], team)
create_protocol_keywords(team_json['protocol_keywords'], team)
create_protocols(team_json['protocols'], nil, team)
create_projects(team_json['projects'], team)
create_repositories(team_json['repositories'], team)
# Second run, we needed it because of some models should be created
team_json['users'].each do |user_json|
user_json['user_notifications'].each do |user_notification_json|
user_notification = UserNotification.new(user_notification_json)
user_notification.id = nil
user_notification.user_id = find_user(user_notification.user_id)
user_notification.notification_id =
@notification_mappings[user_notification.notification_id]
next if user_notification.notification_id.blank?
user_notification.save!
end
user_json['repository_table_states'].each do |rep_tbl_state_json|
rep_tbl_state = RepositoryTableState.new(rep_tbl_state_json)
rep_tbl_state.id = nil
rep_tbl_state.user_id = find_user(rep_tbl_state.user_id)
rep_tbl_state.repository_id =
@repository_mappings[rep_tbl_state.repository_id]
rep_tbl_state.save!
end
end
team_json['projects'].each do |project_json|
create_activities(project_json['activities'])
create_reports(project_json['reports'])
project_json['experiments'].each do |experiment_json|
experiment_json['my_modules'].each do |my_module_json|
create_task_connections(my_module_json['outputs'])
end
end
end
team_json['repositories'].each do |repository_json|
repository_json['repository_rows'].each do |repository_row_json|
create_repository_cells(repository_row_json['repository_cells'])
end
end
create_tiny_mce_assets(team_json['tiny_mce_assets'], team)
update_smart_annotations(team)
# restoring team's creator
team.created_by_id = find_user(team_creator_id)
team.last_modified_by_id = find_user(team_last_modified_by)
team.save!
puts "Imported users: #{@user_counter}"
puts "Imported notifications: #{@notification_counter}"
puts "Imported projects: #{@project_counter}"
puts "Imported reports: #{@report_counter}"
puts "Imported repositories: #{@repository_counter}"
puts "Imported repository rows: #{@repository_row_counter}"
puts "Imported samples: #{@sample_counter}"
puts "Imported tasks: #{@my_module_counter}"
puts "Imported protocols: #{@protocol_counter}"
puts "Imported steps: #{@step_counter}"
puts "Imported results: #{@result_counter}"
puts "Imported assets: #{@asset_counter}"
puts "Imported tinyMCE assets: #{@mce_asset_counter}"
MyModule.set_callback(:create, :before, :create_blank_protocol)
Activity.set_callback(:create, :after, :generate_notification)
Protocol.set_callback(:save, :after, :update_linked_children)
end
end
private
def update_smart_annotations(team)
team.projects.each do |pr|
pr.project_comments.each do |comment|
comment.save! if update_annotation(comment.message)
end
pr.experiments.each do |exp|
exp.save! if update_annotation(exp.description)
exp.my_modules.each do |task|
task.task_comments.each do |comment|
comment.save! if update_annotation(comment.message)
end
task.save! if update_annotation(task.description)
task.protocol.steps.each do |step|
step.step_comments.each do |comment|
comment.save! if update_annotation(comment.message)
end
step.save! if update_annotation(step.description)
end
task.results.each do |res|
res.result_comments.each do |comment|
comment.save! if update_annotation(comment.message)
end
next unless res.result_text
res.save! if update_annotation(res.result_text.text)
end
end
end
end
team.protocols.where(my_module: nil).each do |protocol|
protocol.steps.each do |step|
step.step_comments.each do |comment|
comment.save! if update_annotation(comment.message)
end
step.save! if update_annotation(step.description)
end
end
team.samples.each do |sample|
sample.sample_custom_fields.find_each do |cf|
cf.save! if update_annotation(cf.value)
end
end
team.repositories.each do |rep|
rep.repository_rows.find_each do |row|
row.repository_cells.each do |cell|
cell.value.save! if update_annotation(cell.value.data)
end
end
end
end
# Returns true if text was updated
def update_annotation(text)
return false if text.nil?
updated = false
%w(prj exp tsk sam).each do |name|
text.scan(/~#{name}~\w+\]/).each do |text_match|
orig_id_encoded = text_match.match(/~#{name}~(\w+)\]/)[1]
orig_id = orig_id_encoded.base62_decode
new_id =
case name
when 'prj'
@project_mappings[orig_id]
when 'exp'
@experiment_mappings[orig_id]
when 'tsk'
@my_module_mappings[orig_id]
when 'sam'
@sample_mappings[orig_id]
end
next unless new_id
new_id_encoded = new_id.base62_encode
text.sub!("~#{name}~#{orig_id_encoded}]", "~#{name}~#{new_id_encoded}]")
updated = true
end
end
text.scan(/\[@[\w+-@?! ]+~\w+\]/).each do |user_match|
orig_id_encoded = user_match.match(/\[@[\w+-@?! ]+~(\w+)\]/)[1]
orig_id = orig_id_encoded.base62_decode
next unless @user_mappings[orig_id]
new_id_encoded = @user_mappings[orig_id].base62_encode
text.sub!("~#{orig_id_encoded}]", "~#{new_id_encoded}]")
updated = true
end
updated
end
def create_task_connections(connections_json)
connections_json.each do |connection_json|
connection = Connection.new(connection_json)
connection.id = nil
connection.input_id = @my_module_mappings[connection.input_id]
connection.output_id = @my_module_mappings[connection.output_id]
connection.save!
end
end
def create_activities(activities_json)
activities_json.each do |activity_json|
activity = Activity.new(activity_json)
activity.id = nil
activity.user_id = find_user(activity.user_id)
activity.project_id = @project_mappings[activity.project_id]
activity.experiment_id =
@experiment_mappings[activity.experiment_id]
activity.my_module_id = @my_module_mappings[activity.my_module_id]
activity.save!
end
end
def create_tiny_mce_assets(tmce_assets_json, team)
tmce_assets_json.each do |tiny_mce_asset_json|
tiny_mce_asset = TinyMceAsset.new(tiny_mce_asset_json)
# Try to find and load file
tiny_mce_file = File.open(
File.join(@import_dir, 'tiny_mce_assets', tiny_mce_asset.id.to_s,
tiny_mce_asset.image_file_name)
)
orig_tmce_id = tiny_mce_asset.id
tiny_mce_asset.id = nil
if tiny_mce_asset.step_id.present?
tiny_mce_asset.step_id = @step_mappings[tiny_mce_asset.step_id]
end
if tiny_mce_asset.result_text_id.present?
tiny_mce_asset.result_text_id =
@result_text_mappings[tiny_mce_asset.result_text_id]
end
tiny_mce_asset.team = team
tiny_mce_asset.image = tiny_mce_file
tiny_mce_asset.save!
@mce_asset_counter += 1
if tiny_mce_asset.step_id.present?
step = Step.find_by_id(tiny_mce_asset.step_id)
step.description.sub!("[~tiny_mce_id:#{orig_tmce_id}]",
"[~tiny_mce_id:#{tiny_mce_asset.id}]")
step.save!
end
if tiny_mce_asset.result_text_id.present?
result_text = ResultText.find_by_id(tiny_mce_asset.result_text_id)
result_text.text.sub!("[~tiny_mce_id:#{orig_tmce_id}]",
"[~tiny_mce_id:#{tiny_mce_asset.id}]")
end
end
end
def create_users(users_json, team)
puts 'Creating users...'
users_json.each do |user_json|
user = User.new(user_json['user'].slice(*User.column_names))
orig_user_id = user.id
user.id = nil
user.password = user_json['user']['encrypted_password']
user.current_team_id = team.id
user.invited_by_id = @user_mappings[user.invited_by_id]
if user.avatar.present?
avatar_path = File.join(@import_dir, 'avatars', orig_user_id.to_s,
user.avatar_file_name)
user.avatar = File.open(avatar_path) if File.exist?(avatar_path)
end
user.save!
@user_counter += 1
user.update_attribute('encrypted_password',
user_json['user']['encrypted_password'])
@user_mappings[orig_user_id] = user.id
user_json['user_identities'].each do |user_identity_json|
user_identity = UserIdentity.new(user_identity_json)
user_identity.id = nil
user_identity.user_id = user.id
user_identity.save!
end
user_json['samples_tables'].each do |samples_table_json|
samples_table = SamplesTable.new(samples_table_json)
samples_table.id = nil
samples_table.user_id = user.id
samples_table.team_id = team.id
samples_table.save!
end
end
end
def create_notifications(notifications_json)
puts 'Creating notifications...'
notifications_json.each do |notification_json|
notification = Notification.new(notification_json)
next if notification.type_of.blank?
orig_notification_id = notification.id
notification.id = nil
notification.generator_user_id = find_user(notification.generator_user_id)
notification.save!
@notification_mappings[orig_notification_id] = notification.id
@notification_counter += 1
end
end
def create_repositories(repositories_json, team)
puts 'Creating repositories...'
repositories_json.each do |repository_json|
repository = Repository.new(repository_json['repository'])
orig_repository_id = repository.id
repository.id = nil
repository.team = team
repository.created_by_id = find_user(repository.created_by_id)
repository.save!
@repository_mappings[orig_repository_id] = repository.id
@repository_counter += 1
repository_json['repository_columns'].each do |repository_column_json|
repository_column = RepositoryColumn.new(repository_column_json)
orig_rep_col_id = repository_column.id
repository_column.id = nil
repository_column.repository = repository
repository_column.created_by_id =
find_user(repository_column.created_by_id)
repository_column.save!
@repository_column_mappings[orig_rep_col_id] = repository_column.id
end
create_repository_rows(repository_json['repository_rows'], repository)
end
end
def create_repository_rows(repository_rows_json, repository)
repository_rows_json.each do |repository_row_json|
repository_row =
RepositoryRow.new(repository_row_json['repository_row'])
orig_rep_row_id = repository_row.id
repository_row.id = nil
repository_row.repository = repository
repository_row.created_by_id = find_user(repository_row.created_by_id)
repository_row.last_modified_by_id =
find_user(repository_row.last_modified_by_id)
repository_row.save!
@repository_row_mappings[orig_rep_row_id] = repository_row.id
@repository_row_counter += 1
repository_row_json['my_module_repository_rows'].each do |mm_rep_row_json|
mm_rep_row = MyModuleRepositoryRow.new(mm_rep_row_json)
mm_rep_row.id = nil
mm_rep_row.repository_row = repository_row
mm_rep_row.my_module_id = @my_module_mappings[mm_rep_row.my_module_id]
mm_rep_row.assigned_by_id = find_user(mm_rep_row.assigned_by_id)
mm_rep_row.save!
end
end
end
def create_repository_cells(repository_cells_json)
repository_cells_json.each do |repository_cell_json|
repository_cell =
RepositoryCell.new(repository_cell_json['repository_cell'])
repository_cell.id = nil
repository_cell.repository_column_id =
@repository_column_mappings[repository_cell.repository_column_id]
repository_cell.repository_row_id =
@repository_row_mappings[repository_cell.repository_row_id]
repository_value =
RepositoryTextValue.new(repository_cell_json['repository_value'])
repository_value.id = nil
repository_value.created_by_id = find_user(repository_value.created_by_id)
repository_value.last_modified_by_id =
find_user(repository_value.last_modified_by_id)
repository_value.repository_cell = repository_cell
repository_value.save!
end
end
def create_sample_groups(sample_groups_json, team)
puts 'Creating sample groups...'
sample_groups_json.each do |sample_group_json|
sample_group = SampleGroup.new(sample_group_json)
orig_group_id = sample_group.id
sample_group.id = nil
sample_group.team = team
sample_group.created_by_id = find_user(sample_group.created_by_id)
sample_group.last_modified_by_id =
find_user(sample_group.last_modified_by_id)
sample_group.save!
@sample_group_mappings[orig_group_id] = sample_group.id
end
end
def create_sample_types(sample_types_json, team)
puts 'Creating sample types...'
sample_types_json.each do |sample_type_json|
sample_type = SampleType.new(sample_type_json)
orig_type_id = sample_type.id
sample_type.id = nil
sample_type.team = team
sample_type.created_by_id = find_user(sample_type.created_by_id)
sample_type.last_modified_by_id =
find_user(sample_type.last_modified_by_id)
sample_type.save!
@sample_type_mappings[orig_type_id] = sample_type.id
end
end
def create_custom_fields(custom_fields_json, team)
puts 'Creating custom fields...'
custom_fields_json.each do |custom_field_json|
custom_field = CustomField.new(custom_field_json)
orig_custom_field_id = custom_field.id
custom_field.id = nil
custom_field.team = team
custom_field.user_id = find_user(custom_field.user_id)
custom_field.last_modified_by_id =
find_user(custom_field.last_modified_by_id)
custom_field.save!
@custom_field_mappings[orig_custom_field_id] = custom_field.id
end
end
def create_samples(samples_json, team)
puts 'Creating samples...'
samples_json.each do |sample_json|
sample = Sample.new(sample_json['sample'])
orig_sample_id = sample.id
sample.id = nil
sample.team = team
sample.user_id = find_user(sample.user_id)
sample.sample_group_id = @sample_group_mappings[sample.sample_group_id]
sample.sample_type_id = @sample_type_mappings[sample.sample_type_id]
sample.last_modified_by_id = find_user(sample.last_modified_by_id)
sample.save!
@sample_mappings[orig_sample_id] = sample.id
@sample_counter += 1
sample_json['sample_custom_fields'].each do |s_custom_field_json|
s_custom_field = SampleCustomField.new(s_custom_field_json)
s_custom_field.id = nil
s_custom_field.sample = sample
s_custom_field.custom_field_id =
@custom_field_mappings[s_custom_field.custom_field_id]
s_custom_field.save!
end
end
end
def create_protocol_keywords(protocol_keywords_json, team)
puts 'Creating keywords...'
protocol_keywords_json.each do |protocol_keyword_json|
protocol_keyword = ProtocolKeyword.new(protocol_keyword_json)
orig_pr_keyword_id = protocol_keyword.id
protocol_keyword.id = nil
protocol_keyword.team = team
protocol_keyword.save!
@protocol_keyword_mappings[orig_pr_keyword_id] = protocol_keyword.id
end
end
def create_projects(projects_json, team)
puts 'Creating projects...'
projects_json.each do |project_json|
project = Project.new(project_json['project'])
orig_project_id = project.id
project.id = nil
project.team = team
project.created_by_id = find_user(project.created_by_id)
project.last_modified_by_id = find_user(project.last_modified_by_id)
project.archived_by_id = find_user(project.archived_by_id)
project.restored_by_id = find_user(project.restored_by_id)
project.save!
@project_mappings[orig_project_id] = project.id
@project_counter += 1
puts 'Creating user_projects...'
project_json['user_projects'].each do |user_project_json|
user_project = UserProject.new(user_project_json)
user_project.id = nil
user_project.project = project
user_project.user_id = find_user(user_project.user_id)
user_project.assigned_by_id = find_user(user_project.assigned_by_id)
user_project.save!
end
puts 'Creating project_comments...'
project_json['project_comments'].each do |project_comment_json|
project_comment = ProjectComment.new(project_comment_json)
project_comment.id = nil
project_comment.user_id = find_user(project_comment.user_id)
project_comment.last_modified_by_id =
find_user(project_comment.last_modified_by_id)
project_comment.project = project
project_comment.save!
end
puts 'Creating tags...'
project_json['tags'].each do |tag_json|
tag = Tag.new(tag_json)
orig_tag_id = tag.id
tag.id = nil
tag.project = project
tag.created_by_id = find_user(tag.created_by_id)
tag.last_modified_by_id = find_user(tag.last_modified_by_id)
tag.save!
@tag_mappings[orig_tag_id] = tag.id
end
create_experiments(project_json['experiments'], project)
end
end
def create_experiments(experiments_json, project)
puts('Creating experiments...')
experiments_json.each do |experiment_json|
experiment = Experiment.new(experiment_json['experiment'])
orig_experiment_id = experiment.id
experiment.id = nil
experiment.project = project
experiment.created_by_id = find_user(experiment.created_by_id)
experiment.last_modified_by_id = find_user(experiment.last_modified_by_id)
experiment.archived_by_id = find_user(experiment.archived_by_id)
experiment.restored_by_id = find_user(experiment.restored_by_id)
experiment.save!
@experiment_mappings[orig_experiment_id] = experiment.id
experiment_json['my_module_groups'].each do |my_module_group_json|
my_module_group = MyModuleGroup.new(my_module_group_json)
orig_module_group_id = my_module_group.id
my_module_group.id = nil
my_module_group.experiment = experiment
my_module_group.created_by_id =
find_user(my_module_group.created_by_id)
my_module_group.save!
@my_module_group_mappings[orig_module_group_id] = my_module_group.id
end
experiment.delay.generate_workflow_img
create_my_modules(experiment_json['my_modules'], experiment)
end
end
def create_my_modules(my_modules_json, experiment)
puts('Creating my_modules...')
my_modules_json.each do |my_module_json|
my_module = MyModule.new(my_module_json['my_module'])
orig_my_module_id = my_module.id
my_module.id = nil
my_module.my_module_group_id =
@my_module_group_mappings[my_module.my_module_group_id]
my_module.created_by_id = find_user(my_module.created_by_id)
my_module.last_modified_by_id =
find_user(my_module.last_modified_by_id)
my_module.archived_by_id = find_user(my_module.archived_by_id)
my_module.restored_by_id = find_user(my_module.restored_by_id)
my_module.experiment = experiment
my_module.save!
@my_module_mappings[orig_my_module_id] = my_module.id
@my_module_counter += 1
my_module_json['my_module_tags'].each do |my_module_tag_json|
my_module_tag = MyModuleTag.new(my_module_tag_json)
my_module_tag.id = nil
my_module_tag.my_module = my_module
my_module_tag.tag_id = @tag_mappings[my_module_tag.tag_id]
my_module_tag.created_by_id =
find_user(my_module_tag.created_by_id)
my_module_tag.save!
end
my_module_json['task_comments'].each do |task_comment_json|
task_comment = TaskComment.new(task_comment_json)
task_comment.id = nil
task_comment.user_id = find_user(task_comment.user_id)
task_comment.last_modified_by_id =
find_user(task_comment.last_modified_by_id)
task_comment.my_module = my_module
task_comment.save!
end
my_module_json['sample_my_modules'].each do |sample_module_json|
sample_module = SampleMyModule.new(sample_module_json)
sample_module.id = nil
sample_module.sample_id =
@sample_mappings[sample_module.sample_id]
sample_module.my_module = my_module
sample_module.assigned_by_id =
find_user(sample_module.assigned_by_id)
sample_module.save!
end
my_module_json['user_my_modules'].each do |user_module_json|
user_module = UserMyModule.new(user_module_json)
user_module.id = nil
user_module.my_module = my_module
user_module.user_id = find_user(user_module.user_id)
user_module.assigned_by_id =
find_user(user_module.assigned_by_id)
user_module.save!
end
create_protocols(my_module_json['protocols'], my_module)
create_results(my_module_json['results'], my_module)
end
end
def create_protocols(protocols_json, my_module = nil, team = nil)
puts 'Creating protocols...'
protocols_json.each do |protocol_json|
protocol = Protocol.new(protocol_json['protocol'])
orig_protocol_id = protocol.id
protocol.id = nil
protocol.added_by_id = find_user(protocol.added_by_id)
protocol.team = team ? team : my_module.experiment.project.team
protocol.archived_by_id = find_user(protocol.archived_by_id)
protocol.restored_by_id = find_user(protocol.restored_by_id)
protocol.my_module = my_module unless protocol.my_module_id.nil?
unless protocol.parent_id.nil?
protocol.parent_id = @protocol_mappings[protocol.parent_id]
end
protocol.save!
@protocol_counter += 1
@protocol_mappings[orig_protocol_id] = protocol.id
protocol_json['protocol_protocol_keywords'].each do |pp_keyword_json|
pp_keyword = ProtocolProtocolKeyword.new(pp_keyword_json)
pp_keyword.id = nil
pp_keyword.protocol = protocol
pp_keyword.protocol_keyword_id =
@protocol_keyword_mappings[pp_keyword.protocol_keyword_id]
pp_keyword.save!
end
create_steps(protocol_json['steps'], protocol)
end
end
def create_steps(steps_json, protocol)
puts('Creating steps...')
steps_json.each do |step_json|
step = Step.new(step_json['step'])
orig_step_id = step.id
step.id = nil
step.user_id = find_user(step.user_id)
step.last_modified_by_id = find_user(step.last_modified_by_id)
step.protocol_id = protocol.id
step.save!
@step_mappings[orig_step_id] = step.id
@step_counter += 1
step_json['step_comments'].each do |step_comment_json|
step_comment = StepComment.new(step_comment_json)
step_comment.id = nil
step_comment.user_id = find_user(step_comment.user_id)
step_comment.last_modified_by_id =
find_user(step_comment.last_modified_by_id)
step_comment.step = step
step_comment.save!
end
step_json['tables'].each do |table_json|
table = Table.new(table_json)
orig_table_id = table.id
table.id = nil
table.created_by_id = find_user(table.created_by_id)
table.last_modified_by_id =
find_user(table.last_modified_by_id)
table.team = protocol.team
table.contents = Base64.decode64(table.contents)
table.data_vector = Base64.decode64(table.data_vector)
table.save!
@table_mappings[orig_table_id] = table.id
StepTable.create!(step: step, table: table)
end
step_json['assets'].each do |asset_json|
asset = create_asset(asset_json, protocol.team)
StepAsset.create!(step: step, asset: asset)
end
create_step_checklists(step_json['checklists'], step)
end
end
def create_results(results_json, my_module)
puts('Creating results...')
results_json.each do |result_json|
result = Result.new(result_json['result'])
orig_result_id = result.id
result.id = nil
result.my_module = my_module
result.user_id = find_user(result.user_id)
result.last_modified_by_id = find_user(result.last_modified_by_id)
result.archived_by_id = find_user(result.archived_by_id)
result.restored_by_id = find_user(result.restored_by_id)
if result_json['table'].present?
table = Table.new(result_json['table'])
orig_table_id = table.id
table.id = nil
table.created_by_id = find_user(table.created_by_id)
table.last_modified_by_id =
find_user(table.last_modified_by_id)
table.team = my_module.experiment.project.team
table.contents = Base64.decode64(table.contents)
table.data_vector = Base64.decode64(table.data_vector)
table.save!
@table_mappings[orig_table_id] = table.id
result.table = table
end
if result_json['asset'].present?
asset = create_asset(result_json['asset'],
my_module.experiment.project.team)
result.asset = asset
end
if result_json['result_text'].present?
result_text = ResultText.new(result_json['result_text'])
orig_result_text_id = result_text.id
result_text.id = nil
result_text.result = result
result_text.save!
@result_text_mappings[orig_result_text_id] = result_text.id
end
result.save!
@result_mappings[orig_result_id] = result.id
@result_counter += 1
result_json['result_comments'].each do |result_comment_json|
result_comment = ResultComment.new(result_comment_json)
result_comment.id = nil
result_comment.user_id = find_user(result_comment.user_id)
result_comment.last_modified_by_id =
find_user(result_comment.last_modified_by_id)
result_comment.result = result
result_comment.save!
end
end
end
# returns asset object
def create_asset(asset_json, team)
asset = Asset.new(asset_json)
orig_asset_id = asset.id
file =
File.open("#{@import_dir}/assets/#{asset.id}/#{asset.file_file_name}")
asset.id = nil
asset.created_by_id = find_user(asset.created_by_id)
asset.last_modified_by_id =
find_user(asset.last_modified_by_id)
asset.team = team
asset.file = file
asset.save!
@asset_mappings[orig_asset_id] = asset.id
@asset_counter += 1
asset
end
def create_step_checklists(step_checklists_json, step)
step_checklists_json.each do |checklist_json|
checklist = Checklist.new(checklist_json['checklist'])
orig_checklist_id = checklist.id
checklist.id = nil
checklist.step = step
checklist.created_by_id = find_user(checklist.created_by_id)
checklist.last_modified_by_id =
find_user(checklist.last_modified_by_id)
checklist.save!
@checklist_mappings[orig_checklist_id] = checklist.id
checklist_json['checklist_items'].each do |checklist_item_json|
checklist_item = ChecklistItem.new(checklist_item_json)
checklist_item.id = nil
checklist_item.checklist = checklist
checklist_item.created_by_id = find_user(checklist_item.created_by_id)
checklist_item.last_modified_by_id =
find_user(checklist_item.last_modified_by_id)
checklist_item.save!
end
end
end
def create_reports(reports_json)
reports_json.each do |report_json|
report_el_parent_mappings = {}
report_element_mappings = {}
report = Report.new(report_json['report'])
report.id = nil
report.project_id = @project_mappings[report.project_id]
report.user_id = find_user(report.user_id)
report.last_modified_by_id = find_user(report.last_modified_by_id)
report.save!
@report_counter += 1
report_json['report_elements'].each do |report_element_json|
report_element = ReportElement.new(report_element_json)
orig_report_element_id = report_element.id
report_element.id = nil
orig_parent_id = report_element.parent_id
report_element.parent_id = nil
report_element.report = report
if report_element.project_id
report_element.project_id =
@project_mappings[report_element.project_id]
end
if report_element.my_module_id
report_element.my_module_id =
@my_module_mappings[report_element.my_module_id]
end
if report_element.step_id
report_element.step_id = @step_mappings[report_element.step_id]
end
if report_element.result_id
report_element.result_id = @result_mappings[report_element.result_id]
end
if report_element.checklist_id
report_element.checklist_id =
@checklist_mappings[report_element.checklist_id]
end
if report_element.asset_id
report_element.asset_id = @asset_mappings[report_element.asset_id]
end
if report_element.table_id
report_element.table_id = @table_mappings[report_element.table_id]
end
if report_element.experiment_id
report_element.experiment_id =
@experiment_mappings[report_element.experiment_id]
end
if report_element.repository_id
report_element.repository_id =
@repository_mappings[report_element.repository_id]
end
report_element.save!
report_element_mappings[orig_report_element_id] = report_element.id
report_el_parent_mappings[report_element.id] = orig_parent_id
end
report_el_parent_mappings.each do |k, v|
re = ReportElement.find_by_id(k)
re.parent_id = report_element_mappings[v]
re.save!
end
end
end
def find_user(user_id)
return nil if user_id.nil?
@user_mappings[user_id] ? @user_mappings[user_id] : @admin_id
end
end

View file

@ -6,9 +6,6 @@
</div>
</div>
<!-- Edit description modal -->
<%= render partial: "my_modules/modals/manage_description_modal" %>
<!-- Edit due date modal -->
<%= render partial: "my_modules/modals/manage_due_date_modal" %>

View file

@ -41,11 +41,6 @@
<div class="panel-footer panel-footer-scinote buttons-container">
<ul class="nav nav-tabs nav-tabs-less" role="tablist">
<% if can_read_experiment?(my_module.experiment) %>
<li role="presentation">
<a class="btn btn-link task-card-view-info" href="<%= my_module_url(id: my_module.id, format: :json) %>" aria-controls="<%= my_module.id %>_info" role="tab" data-remote="true">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
</a>
</li>
<li role="presentation">
<a class="btn btn-link task-card-view-users" href="<%= my_module_user_my_modules_url(my_module_id: my_module.id, format: :json) %>" aria-controls="<%= my_module.id %>_users" role="tab" data-remote="true">
<span class="glyphicon glyphicon-user" aria-hidden="true"></span>

View file

@ -1,20 +1,28 @@
<div class="panel panel-default panel-project panel-archive">
<div class="panel-heading">
<div class="dropdown pull-right">
<button class="btn btn-link dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<span class="caret"></span>
</button>
<% project_form = nil %>
<%= form_for project, method: :patch, format: :html do |f| %>
<% project_form = f %>
<%= f.hidden_field :archived, value: false %>
<% end %>
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu1">
<li class="dropdown-header"><%= t('projects.index.options_header') %></li>
<li><a href="#" class="form-submit-link" data-submit-form="<%= project_form.options[:html][:id] %>"><%= t 'projects.index.restore_option' %></a></li>
</ul>
</div>
<% if can_restore_project?(project) %>
<div class="dropdown pull-right">
<button class="btn btn-link dropdown-toggle"
type="button"
id="dropdownMenu1"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="true">
<span class="caret"></span>
</button>
<% project_form = nil %>
<%= form_for project, method: :patch, format: :html do |f| %>
<% project_form = f %>
<%= f.hidden_field :archived, value: false %>
<% end %>
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenu1">
<li class="dropdown-header"><%= t('projects.index.options_header') %></li>
<li><a href="#"
class="form-submit-link"
data-submit-form="<%= project_form.options[:html][:id] %>"><%= t 'projects.index.restore_option' %></a></li>
</ul>
</div>
<% end %>
<h3 class="panel-title">
<% if project.hidden? then %>

View file

@ -3,7 +3,7 @@
<div class="row">
<% projects.each_index do |i| project = projects[i] %>
<div class="col-lg-3 col-md-4 col-sm-6 col-xs-12">
<%= render partial: "projects/archive/project", locals: {project: project} %>
<%= render partial: "projects/archive/project", locals: { project: project } %>
</div>
<% if (i+1) % 4 == 0 %>
<div class="clearfix visible-lg-block"></div>

View file

@ -12,21 +12,42 @@
<h4 class="modal-title"><%= t('protocols.index.modal_import_json_title') %></h4>
<%= t("protocols.index.modal_import_json_notice") %>
</div>
<%= form_tag({ action: "protocolsio_import_create"}, id:"protocols_io_form",
format: :json, multipart: true,remote: true,:method => "post") do %>
<%= form_with url: url_for(controller: 'protocols', action: 'protocolsio_import_create'), remote:true, id:"protocols_io_form",
authenticity_token:true,method:"post",multipart:true do |form| %>
<div class="modal-body">
<%= file_field_tag 'json_file', accept: '.txt,.json' %>
<%= form.file_field 'json_file', accept: '.txt,.json', id: "json_file_id" %>
<div id="pio_no_file_error_span"></div>
</div>
<% end %>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal"><%= t('general.cancel')%></button>
<%= submit_tag t('protocols.index.modal_import_json_upload'), class: "btn btn-success" %>
<%= submit_tag t('protocols.index.modal_import_json_upload'), class: "btn btn-success", id: "pio_submit_btn_id" %>
</div>
<% end %>
</div>
</div>
</div>
<script>
$('#pio_submit_btn_id').on('click', function(e) {
e.preventDefault();
$('#protocols_io_form').submit();
})
$('#protocols_io_form').on('submit', function(e) {
e.preventDefault();
var form = document.querySelector('#protocols_io_form') // Find the <form> element
var formData = new FormData(form); // Wrap form contents
$.ajax({
url: 'protocols/protocolsio_import_create',
type: 'POST',
data: formData,
contentType: false,
processData: false
});
})
</script>

View file

@ -3,12 +3,12 @@
remote: true, :html=> { :id => "protocolsio-import-form" }) do |f| %>
<%= hidden_field_tag :json_object, JSON.generate(@json_object) %>
<% if URI.parse(request.referrer).query %>
<%= hidden_field_tag :type,CGI.parse(URI.parse(request.referrer).query).fetch('type') %>
<% else %>
<%= hidden_field_tag :type,'public' %>
<% url_query = Rack::Utils.parse_query URI(request.referrer).query %>
<% type_privacy = "public" %>
<% if url_query.key?("type") && url_query["type"]=="private" %>
<% type_privacy = "private" %>
<% end %>
<%= hidden_field_tag :type, type_privacy %>
<!--Get the type of protocol to import (private, public) from the url -->
<div
id="modal-import-json-protocol-preview"

View file

@ -48,28 +48,33 @@
<% end %>
</div>
<div id="import-export-protocols" class="btn-group" role="group">
<a class="btn btn-default btn-open-file" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="#">
<a class="btn btn-default btn-open-file"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
href="#"
<%= 'disabled' unless can_create_protocols_in_repository?(@current_team) %>>
<span class="glyphicon glyphicon-import"></span><span class="hidden-xs">&nbsp;<%= t("protocols.index.import") %></span></a>
<ul class="dropdown-menu">
<li>
<a class="btn-link-alt btn-default-link btn-open-file" <%= can_create_protocols_in_repository?(@current_team) ? 'data-action="import"' : 'disabled="disabled"' %>>
<span class="glyphicon glyphicon-file"></span>
<span class="hidden-xs"><%= t("protocols.index.import_alt") %></span>
<input type="file" value="" accept=".eln" data-role="import-file-input"
data-team-id="<%= @current_team.id %>"
data-type="<%= @type %>" data-import-url="<%= import_protocols_path %>"
<%= 'disabled="disabled"' unless can_create_protocols_in_repository?(@current_team) %>>
</a>
</li>
<li>
<%= link_to "#modal-import-json-protocol", "data-toggle" => "modal" do %>
<span class="glyphicon glyphicon-file"></span>
<span class="hidden-xs"><%= t("protocols.index.import_json") %></span>
<% end %>
</li>
</ul>
<% if can_create_protocols_in_repository?(@current_team) %>
<ul class="dropdown-menu">
<li>
<a class="btn-link-alt btn-default-link btn-open-file" <%= can_create_protocols_in_repository?(@current_team) ? 'data-action="import"' : 'disabled="disabled"' %>>
<span class="glyphicon glyphicon-file"></span>
<span class="hidden-xs"><%= t("protocols.index.import_alt") %></span>
<input type="file" value="" accept=".eln" data-role="import-file-input"
data-team-id="<%= @current_team.id %>"
data-type="<%= @type %>" data-import-url="<%= import_protocols_path %>"
<%= 'disabled="disabled"' unless can_create_protocols_in_repository?(@current_team) %>>
</a>
</li>
<li>
<%= link_to "#modal-import-json-protocol", "data-toggle" => "modal" do %>
<span class="glyphicon glyphicon-file"></span>
<span class="hidden-xs"><%= t("protocols.index.import_json") %></span>
<% end %>
</li>
</ul>
<% end %>
<a class="btn btn-default" data-action="export" data-export-url="<%= export_protocols_path() %>">
<span class="glyphicon glyphicon-export"></span>
<span class="hidden-xs">&nbsp;<%= t("protocols.index.export") %></span>

View file

@ -13,21 +13,15 @@ $('#pio_no_file_error_span').addClass('has-error').html('<span class="help-block
<% @protocolsio_no_file = false %>
<% else %>
$('#modal-import-json-protocol').modal('hide');
<% if remotipart_submitted? %> <%# a workaround to a bug with remotipart, that caused alot of headache, courtesy of github.com/dhampik %>
$('#protocolsio-preview-modal-target').html(
"<%= j "#{render(:partial => 'protocols/import_export/import_json_protocol_preview_modal')}" %>"
);
<% else %>
$('#protocolsio-preview-modal-target').html(
"<%= j render(:partial => 'protocols/import_export/import_json_protocol_preview_modal') %>"
);
<% end %>
$('#modal-import-json-protocol-preview').modal('show');
$('.modal').on('hidden.bs.modal', function (e) {
if($('.modal').hasClass('in')) {
$('body').addClass('modal-open');
}
});
$('#protocolsio-preview-modal-target').html(
"<%= j render(:partial => 'protocols/import_export/import_json_protocol_preview_modal') %>"
);
$('#modal-import-json-protocol-preview').modal('show');
$('.modal').on('hidden.bs.modal', function (e) {
if($('.modal').hasClass('in')) {
$('body').addClass('modal-open');
}
});
<% end %>
$("#protocols_io_form")[0].reset();
$('#protocols_io_form').trigger("reset");

View file

@ -23,7 +23,7 @@
<div class="report-element-body">
<div class="row">
<div class="col-xs-12 text-container ql-editor">
<%= custom_auto_link(generate_image_tag_from_token(result_text.text, result_text),
<%= custom_auto_link(generate_image_tag_from_token(result_text.text, result_text, true),
simple_format: false,
tags: %w(img)) %>
</div>

View file

@ -30,7 +30,7 @@
<div class="row">
<div class="col-xs-12 ql-editor">
<% if strip_tags(step.description).present? %>
<%= custom_auto_link(generate_image_tag_from_token(step.description, step),
<%= custom_auto_link(generate_image_tag_from_token(step.description, step, true),
simple_format: false,
tags: %w(img)) %>
<% else %>

View file

@ -10,7 +10,9 @@
<body class="print-report-body">
<div class="print-report">
<% # Also whitelist <img> and <input type="checkbox"> tags %>
<%= @html.html_safe %>
<%= sanitize_input(fix_smart_annotation_image(@html),
%w(img input),
%w(type disabled checked)) %>
</div>
</body>
</html>

View file

@ -6,10 +6,9 @@
<h4 class="modal-title"><%= t('repositories.modal_import.title') %></h4>
<%= t("repositories.modal_import.notice") %>
</div>
<%= bootstrap_form_tag url: parse_sheet_repository_path(repository, format: :json),
<%= bootstrap_form_tag url: parse_sheet_repository_path(repository),
html: {'data-type' => 'json',
id: 'form-records-file'},
remote: :true do |f| %>
id: 'form-records-file'} do |f| %>
<%= f.hidden_field :team_id, value: current_team.id %>
<div class="modal-body">
<%= f.file_field :file %>

View file

@ -1,5 +1,5 @@
<div class="well">
<%= bootstrap_form_for(@result, url: result_asset_path(format: :json), remote: true, multipart: true, data: { type: :json }) do |f| %>
<%= bootstrap_form_for(@result, url: result_asset_path(format: :json), multipart: true, data: { type: :json }) do |f| %>
<%= f.text_field :name, style: "margin-top: 10px;" %><br />
<%= f.fields_for :asset do |ff| %>
<span><strong><%=t "result_assets.edit.uploaded_asset" %></strong></span>

View file

@ -4,10 +4,9 @@
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><%= t("samples.modal_delete.title") %></h4>
<%= t("samples.modal_delete.notice") %>
</div>
<div class="modal-body">
<%= t("samples.modal_delete.other_samples") %>
<%= t("samples.modal_delete.notice") %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" onclick="$('.delete_samples_submit').click();"><%= t("samples.modal_delete.delete") %></button>
@ -15,4 +14,4 @@
</div>
</div>
</div>
</div>
</div>

View file

@ -6,10 +6,9 @@
<h4 class="modal-title"><%= t('samples.modal_import.title') %></h4>
<%= t("samples.modal_import.notice") %>
</div>
<%= bootstrap_form_tag url: parse_sheet_team_path(@team, format: :json),
<%= bootstrap_form_tag url: parse_sheet_team_path(@team),
html: {'data-type' => 'json',
id: 'form-samples-file'},
remote: :true do |f| %>
id: 'form-samples-file'} do |f| %>
<div class="modal-body">
<%= f.file_field :file %>
</div>

View file

@ -108,7 +108,7 @@
delete_samples_submit" %>
</button>
<% if module_page? && can_assign_repository_rows_to_module?(@my_module) %>
<% if module_page? && can_assign_sample_to_module?(@my_module) %>
<button type="button" class="btn btn-default"
id="assignSamples" onclick="$(this).next().click();" disabled>
<span class="glyphicon glyphicon-ok-circle"></span>

View file

@ -12,7 +12,7 @@
<%= my_module.name %>
<% else %>
<% if can_read_experiment?(my_module.experiment) %>
<%= link_to my_module.name, module_action_to_link_to(my_module), class: "module-link" %>
<%= link_to my_module.name, module_action_to_link_to(my_module), class: "module-link", data: { no_turbolink: true } %>
<% else %>
<%= my_module.name %>
<% end %>
@ -39,7 +39,7 @@
<% if currently_active? my_module %>
<%= my_module.name %>
<% else %>
<%= link_to my_module.name, module_action_to_link_to(my_module) %>
<%= link_to my_module.name, module_action_to_link_to(my_module), data: { no_turbolink: true } %>
<% end %>
<% if is_canvas? %>
<a href="" class="canvas-center-on"><span class="glyphicon glyphicon-map-marker"></span></a>

View file

@ -27,10 +27,12 @@
<%- if Rails.configuration.x.enable_user_registration && Rails.configuration.x.linkedin_signin_enabled %>
<%- if devise_mapping.omniauthable? && resource_class.omniauth_providers.any? && controller_name != 'registrations' %>
<%= link_to omniauth_authorize_path(resource_name, :linkedin), :title => "Sign in with LinkedIn" do %>
<%= image_tag 'linkedin/Sign-in-Small---Default.png', alt: "Sign in with LinkedIn",
onmouseover: "src='#{image_path('linkedin/Sign-in-Small---Hover.png')}'",
onmouseout: "src='#{image_path('linkedin/Sign-in-Small---Default.png')}'",
onclick: "src='#{image_path('linkedin/Sign-in-Small---Active.png')}'" %>
<%= image_tag('linkedin/Sign-in-Large---Default.png',
class: 'linkedin-signin-button',
alt: "Sign in with LinkedIn",
onmouseover: "src='#{image_path('linkedin/Sign-in-Large---Hover.png')}'",
onmouseout: "src='#{image_path('linkedin/Sign-in-Large---Default.png')}'",
onclick: "src='#{image_path('linkedin/Sign-in-Large---Active.png')}'") %>
<% end -%>
<% end -%>
<% end -%>

View file

@ -15,6 +15,10 @@ module Scinote
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Swap the Rack::MethodOverride with a wrapped middleware for WOPI handling
require_relative '../app/middlewares/wopi_method_override'
config.middleware.swap Rack::MethodOverride, WopiMethodOverride
# Load all model concerns, including subfolders
config.autoload_paths += Dir["#{Rails.root}/app/models/concerns/**/*.rb"]

View file

@ -1094,7 +1094,6 @@ en:
modal_delete:
title: "Delete samples"
notice: "Are you sure you want to delete the selected samples?"
other_samples: "Only samples created by you will be deleted."
delete: "Delete samples"
modal_add_custom_field:
title_html: "Add new column to team <strong>%{team}</strong>"

View file

@ -169,7 +169,7 @@ Rails.application.routes.draw do
get 'destroy_html'
end
member do
post 'parse_sheet'
post 'parse_sheet', defaults: { format: 'json' }
post 'import_samples'
post 'export_samples'
post 'export_repository', to: 'repositories#export_repository'
@ -480,7 +480,7 @@ Rails.application.routes.draw do
resources :repository_columns, only: %i(index create edit update destroy)
resources :repository_rows, only: %i(create edit update)
member do
post 'parse_sheet'
post 'parse_sheet', defaults: { format: 'json' }
post 'import_records'
end
end

View file

@ -80,4 +80,20 @@ namespace :data do
desc "Remove temporary and obsolete data"
task clean: [:environment, :clean_temp_files, :clean_unconfirmed_users]
desc 'Export team to directory'
task :team_export, [:team_id] => [:environment] do |_, args|
Rails.logger.info(
"Exporting team with ID:#{args[:team_id]} to directory in tmp"
)
te = TeamExporter.new(args[:team_id])
te.export_to_dir if te
end
desc 'Import team from directory'
task :team_import, [:dir_path] => [:environment] do |_, args|
Rails.logger.info(
"Importing team from directory #{args[:dir_path]}"
)
TeamImporter.new.import_from_dir(args[:dir_path])
end
end

View file

@ -0,0 +1,25 @@
namespace :protocol_keyword_team do
desc 'Fixes false team_id on protocol keyword entry [bug SCI-2257]'
task exec: :environment do
puts '[sciNote] Start processing...'
Protocol.find_each do |protocol|
new_keywords = []
protocol.protocol_keywords.find_each do |protocol_keyword|
next if protocol.team_id == protocol_keyword.team_id
# remove protocol keyword from protocol
ProtocolProtocolKeyword.where(
protocol_id: protocol.id,
protocol_keyword_id: protocol_keyword.id
).destroy_all
# create new keyword with correct team
new_keywords << ProtocolKeyword.create(
name: protocol_keyword.name,
team_id: protocol.team_id
)
end
# append newly created keywords to protocol
protocol.protocol_keywords << new_keywords
end
puts '[sciNote] Done!'
end
end