2017-01-25 00:06:51 +08:00
|
|
|
class TeamsController < ApplicationController
|
2016-02-12 23:52:43 +08:00
|
|
|
before_action :load_vars, only: [:parse_sheet, :import_samples, :export_samples]
|
|
|
|
|
2018-02-16 01:46:29 +08:00
|
|
|
before_action :check_create_samples_permissions, only: %i(parse_sheet
|
|
|
|
import_samples)
|
2016-02-12 23:52:43 +08:00
|
|
|
before_action :check_view_samples_permission, only: [:export_samples]
|
|
|
|
|
|
|
|
def parse_sheet
|
|
|
|
session[:return_to] ||= request.referer
|
|
|
|
|
2018-01-17 00:50:33 +08:00
|
|
|
unless import_params[:file]
|
2017-10-12 20:43:25 +08:00
|
|
|
return parse_sheet_error(t('teams.parse_sheet.errors.no_file_selected'))
|
|
|
|
end
|
2018-06-19 20:15:14 +08:00
|
|
|
if import_params[:file].size > Rails.configuration.x.file_max_size_mb.megabytes
|
2017-10-12 20:43:25 +08:00
|
|
|
error = t('general.file.size_exceeded',
|
2018-06-19 20:15:14 +08:00
|
|
|
file_size: Rails.configuration.x.file_max_size_mb)
|
2017-10-12 20:43:25 +08:00
|
|
|
return parse_sheet_error(error)
|
|
|
|
end
|
2016-02-12 23:52:43 +08:00
|
|
|
|
2017-10-12 20:43:25 +08:00
|
|
|
begin
|
2018-01-17 00:50:33 +08:00
|
|
|
sheet = SpreadsheetParser.open_spreadsheet(import_params[:file])
|
2017-10-17 20:42:06 +08:00
|
|
|
@header, @columns = SpreadsheetParser.first_two_rows(sheet)
|
2016-02-12 23:52:43 +08:00
|
|
|
|
2017-10-17 21:23:54 +08:00
|
|
|
if @header.empty? || @columns.empty?
|
2017-10-12 20:43:25 +08:00
|
|
|
return parse_sheet_error(t('teams.parse_sheet.errors.empty_file'))
|
|
|
|
end
|
2016-02-12 23:52:43 +08:00
|
|
|
|
2017-10-12 20:43:25 +08:00
|
|
|
# Fill in fields for dropdown
|
|
|
|
@available_fields = @team.get_available_sample_fields
|
|
|
|
# Truncate long fields
|
|
|
|
@available_fields.update(@available_fields) do |_k, v|
|
|
|
|
v.truncate(Constants::NAME_TRUNCATION_LENGTH_DROPDOWN)
|
|
|
|
end
|
2016-02-12 23:52:43 +08:00
|
|
|
|
2017-10-12 20:43:25 +08:00
|
|
|
# Save file for next step (importing)
|
|
|
|
@temp_file = TempFile.new(
|
|
|
|
session_id: session.id,
|
2018-01-17 00:50:33 +08:00
|
|
|
file: import_params[:file]
|
2017-10-12 20:43:25 +08:00
|
|
|
)
|
2016-02-12 23:52:43 +08:00
|
|
|
|
2017-10-12 20:43:25 +08:00
|
|
|
if @temp_file.save
|
|
|
|
@temp_file.destroy_obsolete
|
|
|
|
respond_to do |format|
|
|
|
|
format.json do
|
|
|
|
render json: {
|
|
|
|
html: render_to_string(
|
|
|
|
partial: 'samples/parse_samples_modal.html.erb'
|
|
|
|
)
|
|
|
|
}
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
2017-10-12 20:43:25 +08:00
|
|
|
return parse_sheet_error(
|
|
|
|
t('teams.parse_sheet.errors.temp_file_failure')
|
|
|
|
)
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
2017-10-12 20:43:25 +08:00
|
|
|
rescue ArgumentError, CSV::MalformedCSVError
|
|
|
|
return parse_sheet_error(t('teams.parse_sheet.errors.invalid_file',
|
|
|
|
encoding: ''.encoding))
|
|
|
|
rescue TypeError
|
|
|
|
return parse_sheet_error(t('teams.parse_sheet.errors.invalid_extension'))
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def import_samples
|
|
|
|
session[:return_to] ||= request.referer
|
|
|
|
|
|
|
|
respond_to do |format|
|
2018-01-17 00:50:33 +08:00
|
|
|
if import_params[:file_id]
|
|
|
|
@temp_file = TempFile.find_by_id(import_params[:file_id])
|
2016-02-12 23:52:43 +08:00
|
|
|
|
|
|
|
if @temp_file
|
|
|
|
# Check if session_id is equal to prevent file stealing
|
|
|
|
if @temp_file.session_id == session.id
|
|
|
|
# Check if mappings exists or else we don't have anything to parse
|
2018-01-17 00:50:33 +08:00
|
|
|
if import_params[:mappings]
|
2017-10-17 20:42:06 +08:00
|
|
|
@sheet = SpreadsheetParser.open_spreadsheet(@temp_file.file)
|
2016-02-12 23:52:43 +08:00
|
|
|
|
|
|
|
# Check for duplicated values
|
2018-01-17 00:50:33 +08:00
|
|
|
h1 = import_params[:mappings].clone.delete_if { |_, v| v.empty? }
|
2016-02-12 23:52:43 +08:00
|
|
|
if h1.length == h1.invert.length
|
|
|
|
|
|
|
|
# Check if there exist mapping for sample name (it's mandatory)
|
2018-01-17 00:50:33 +08:00
|
|
|
if import_params[:mappings].value?('-1')
|
|
|
|
result = @team.import_samples(@sheet,
|
|
|
|
import_params[:mappings],
|
|
|
|
current_user)
|
2016-02-12 23:52:43 +08:00
|
|
|
nr_of_added = result[:nr_of_added]
|
|
|
|
total_nr = result[:total_nr]
|
|
|
|
|
|
|
|
if result[:status] == :ok
|
|
|
|
# If no errors are present, redirect back
|
|
|
|
# to samples table
|
|
|
|
flash[:success] = t(
|
2017-01-24 23:57:14 +08:00
|
|
|
"teams.import_samples.success_flash",
|
2016-02-12 23:52:43 +08:00
|
|
|
nr: nr_of_added,
|
|
|
|
samples: t(
|
2017-01-24 23:57:14 +08:00
|
|
|
"teams.import_samples.sample",
|
2016-02-12 23:52:43 +08:00
|
|
|
count: total_nr
|
|
|
|
)
|
|
|
|
)
|
|
|
|
@temp_file.destroy
|
|
|
|
format.html {
|
|
|
|
redirect_to session.delete(:return_to)
|
|
|
|
}
|
|
|
|
format.json {
|
|
|
|
flash.keep(:success)
|
|
|
|
render json: { status: :ok }
|
|
|
|
}
|
|
|
|
else
|
|
|
|
# Otherwise, also redirect back,
|
|
|
|
# but display different message
|
|
|
|
flash[:alert] = t(
|
2017-01-24 23:57:14 +08:00
|
|
|
"teams.import_samples.partial_success_flash",
|
2016-02-12 23:52:43 +08:00
|
|
|
nr: nr_of_added,
|
|
|
|
samples: t(
|
2017-01-24 23:57:14 +08:00
|
|
|
"teams.import_samples.sample",
|
2016-02-12 23:52:43 +08:00
|
|
|
count: total_nr
|
|
|
|
)
|
|
|
|
)
|
|
|
|
@temp_file.destroy
|
|
|
|
format.html {
|
|
|
|
redirect_to session.delete(:return_to)
|
|
|
|
}
|
|
|
|
format.json {
|
|
|
|
flash.keep(:alert)
|
|
|
|
render json: { status: :unprocessable_entity }
|
|
|
|
}
|
|
|
|
end
|
|
|
|
else
|
|
|
|
# This is currently the only AJAX error response
|
|
|
|
flash_alert = t(
|
2017-01-24 23:57:14 +08:00
|
|
|
"teams.import_samples.errors.no_sample_name")
|
2016-02-12 23:52:43 +08:00
|
|
|
format.html {
|
|
|
|
flash[:alert] = flash_alert
|
|
|
|
redirect_to session.delete(:return_to)
|
|
|
|
}
|
|
|
|
format.json {
|
|
|
|
render json: {
|
|
|
|
html: render_to_string({
|
|
|
|
partial: "parse_error.html.erb",
|
|
|
|
locals: { error: flash_alert }
|
|
|
|
})
|
|
|
|
},
|
|
|
|
status: :unprocessable_entity
|
|
|
|
}
|
|
|
|
end
|
|
|
|
else
|
|
|
|
# This code should never execute unless user tampers with
|
|
|
|
# JS (selects same column in more than one dropdown)
|
|
|
|
flash_alert = t(
|
2017-01-24 23:57:14 +08:00
|
|
|
"teams.import_samples.errors.duplicated_values")
|
2016-02-12 23:52:43 +08:00
|
|
|
format.html {
|
|
|
|
flash[:alert] = flash_alert
|
|
|
|
redirect_to session.delete(:return_to)
|
|
|
|
}
|
|
|
|
format.json {
|
|
|
|
render json: {
|
|
|
|
html: render_to_string({
|
|
|
|
partial: "parse_error.html.erb",
|
|
|
|
locals: { error: flash_alert }
|
|
|
|
})
|
|
|
|
},
|
|
|
|
status: :unprocessable_entity
|
|
|
|
}
|
|
|
|
end
|
|
|
|
else
|
|
|
|
@temp_file.destroy
|
|
|
|
flash[:alert] = t(
|
2017-01-24 23:57:14 +08:00
|
|
|
"teams.import_samples.errors.no_data_to_parse")
|
2016-02-12 23:52:43 +08:00
|
|
|
format.html {
|
|
|
|
redirect_to session.delete(:return_to)
|
|
|
|
}
|
|
|
|
format.json {
|
|
|
|
flash.keep(:alert)
|
|
|
|
render json: { status: :unprocessable_entity }
|
|
|
|
}
|
|
|
|
end
|
|
|
|
else
|
|
|
|
@temp_file.destroy
|
|
|
|
flash[:alert] = t(
|
2017-01-24 23:57:14 +08:00
|
|
|
"teams.import_samples.errors.session_expired")
|
2016-02-12 23:52:43 +08:00
|
|
|
format.html {
|
|
|
|
redirect_to session.delete(:return_to)
|
|
|
|
}
|
|
|
|
format.json {
|
|
|
|
flash.keep(:alert)
|
|
|
|
render json: { status: :unprocessable_entity }
|
|
|
|
}
|
|
|
|
end
|
|
|
|
else
|
|
|
|
# No temp file to begin with, so no need to destroy it
|
|
|
|
flash[:alert] = t(
|
2017-01-24 23:57:14 +08:00
|
|
|
"teams.import_samples.errors.temp_file_not_found")
|
2016-02-12 23:52:43 +08:00
|
|
|
format.html {
|
|
|
|
redirect_to session.delete(:return_to)
|
|
|
|
}
|
|
|
|
format.json {
|
|
|
|
flash.keep(:alert)
|
|
|
|
render json: { status: :unprocessable_entity }
|
|
|
|
}
|
|
|
|
end
|
|
|
|
else
|
|
|
|
flash[:alert] = t(
|
2017-01-24 23:57:14 +08:00
|
|
|
"teams.import_samples.errors.temp_file_not_found")
|
2016-02-12 23:52:43 +08:00
|
|
|
format.html {
|
|
|
|
redirect_to session.delete(:return_to)
|
|
|
|
}
|
|
|
|
format.json {
|
|
|
|
flash.keep(:alert)
|
|
|
|
render json: { status: :unprocessable_entity }
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def export_samples
|
2018-01-17 00:50:33 +08:00
|
|
|
if export_params[:sample_ids] && export_params[:header_ids]
|
2017-06-07 19:51:16 +08:00
|
|
|
generate_samples_zip
|
2017-05-29 20:42:55 +08:00
|
|
|
else
|
|
|
|
flash[:alert] = t('zip_export.export_error')
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
2017-12-08 00:59:23 +08:00
|
|
|
redirect_back(fallback_location: root_path)
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
2017-05-29 20:42:55 +08:00
|
|
|
def routing_error(error = 'Routing error', status = :not_found, exception=nil)
|
|
|
|
redirect_to root_path
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2017-10-12 20:43:25 +08:00
|
|
|
def parse_sheet_error(error)
|
|
|
|
respond_to do |format|
|
|
|
|
format.html do
|
|
|
|
flash[:alert] = error
|
|
|
|
session[:return_to] ||= request.referer
|
|
|
|
redirect_to session.delete(:return_to)
|
|
|
|
end
|
|
|
|
format.json do
|
|
|
|
render json: { message: error },
|
|
|
|
status: :unprocessable_entity
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-02-12 23:52:43 +08:00
|
|
|
def load_vars
|
2017-01-25 00:06:51 +08:00
|
|
|
@team = Team.find_by_id(params[:id])
|
2016-02-12 23:52:43 +08:00
|
|
|
|
2017-01-24 23:57:14 +08:00
|
|
|
unless @team
|
2016-02-12 23:52:43 +08:00
|
|
|
render_404
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-01-17 00:50:33 +08:00
|
|
|
def import_params
|
|
|
|
params.permit(:id, :file, :file_id, mappings: {}).to_h
|
|
|
|
end
|
|
|
|
|
|
|
|
def export_params
|
|
|
|
params.permit(sample_ids: [], header_ids: []).to_h
|
|
|
|
end
|
|
|
|
|
2018-02-16 01:46:29 +08:00
|
|
|
def check_create_samples_permissions
|
|
|
|
render_403 unless can_create_samples?(@team)
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_view_samples_permission
|
2017-12-07 20:35:15 +08:00
|
|
|
unless can_read_team?(@team)
|
2016-02-12 23:52:43 +08:00
|
|
|
render_403
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-06-07 19:51:16 +08:00
|
|
|
def generate_samples_zip
|
2017-05-29 20:42:55 +08:00
|
|
|
zip = ZipExport.create(user: current_user)
|
|
|
|
zip.generate_exportable_zip(
|
|
|
|
current_user,
|
2018-01-17 00:50:33 +08:00
|
|
|
@team.to_csv(
|
|
|
|
Sample.where(id: export_params[:sample_ids]),
|
|
|
|
export_params[:header_ids]
|
|
|
|
),
|
2017-05-29 20:42:55 +08:00
|
|
|
:samples
|
|
|
|
)
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
end
|