2016-02-12 23:52:43 +08:00
|
|
|
class CanvasController < ApplicationController
|
|
|
|
before_action :load_vars
|
|
|
|
|
2022-05-09 17:40:31 +08:00
|
|
|
before_action :check_view_canvas, except: %i(edit update)
|
|
|
|
before_action :check_edit_canvas, only: %i(edit update)
|
2016-02-12 23:52:43 +08:00
|
|
|
|
|
|
|
def edit
|
|
|
|
render partial: 'canvas/edit',
|
2022-05-09 17:40:31 +08:00
|
|
|
locals: {
|
|
|
|
experiment: @experiment,
|
|
|
|
my_modules: @my_modules
|
|
|
|
}, content_type: 'text/html'
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def full_zoom
|
2022-06-09 20:13:29 +08:00
|
|
|
@my_modules = @my_modules.left_outer_joins(:designated_users, :task_comments)
|
|
|
|
.select('COUNT(DISTINCT users.id) as designated_users_count')
|
|
|
|
.select('COUNT(DISTINCT comments.id) as task_comments_count')
|
|
|
|
.select('my_modules.*').group(:id)
|
|
|
|
render partial: 'canvas/full_zoom', locals: { experiment: @experiment, my_modules: @my_modules }
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def medium_zoom
|
2022-06-09 20:13:29 +08:00
|
|
|
render partial: 'canvas/medium_zoom', locals: { experiment: @experiment, my_modules: @my_modules }
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def small_zoom
|
2022-06-09 20:13:29 +08:00
|
|
|
render partial: 'canvas/small_zoom', locals: { experiment: @experiment, my_modules: @my_modules }
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def update
|
|
|
|
# Make sure that remove parameter is valid
|
|
|
|
to_archive = []
|
2018-02-07 18:49:15 +08:00
|
|
|
if update_params[:remove].present?
|
2017-10-05 22:19:25 +08:00
|
|
|
to_archive = update_params[:remove].split(',')
|
2021-09-14 17:08:35 +08:00
|
|
|
if to_archive.all? { |id| can_archive_my_module?(MyModule.find_by(id: id)) }
|
2017-10-05 22:19:25 +08:00
|
|
|
to_archive.collect!(&:to_i)
|
2016-02-12 23:52:43 +08:00
|
|
|
else
|
2017-10-05 22:19:25 +08:00
|
|
|
return render_403
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Make sure connections parameter is valid
|
|
|
|
connections = []
|
2018-02-09 23:14:40 +08:00
|
|
|
if update_params[:connections].present?
|
2017-10-05 22:19:25 +08:00
|
|
|
conns = update_params[:connections].split(',')
|
|
|
|
if conns.length.even? && conns.all? { |c| c.is_a? String }
|
2016-02-12 23:52:43 +08:00
|
|
|
conns.each_slice(2).each do |c|
|
|
|
|
connections << [c[0], c[1]]
|
|
|
|
end
|
2017-10-05 22:19:25 +08:00
|
|
|
else
|
|
|
|
return render_403
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Make sure positions parameter is valid
|
2017-10-05 22:19:25 +08:00
|
|
|
positions = {}
|
2018-02-09 23:14:40 +08:00
|
|
|
if update_params[:positions].present?
|
2017-10-05 22:19:25 +08:00
|
|
|
poss = update_params[:positions].split(';')
|
2020-07-21 19:49:59 +08:00
|
|
|
(poss.collect { |pos| pos.split(',') }).each_with_index do |pos, _|
|
|
|
|
unless pos.length == 3 && pos[0].is_a?(String) && float?(pos[1]) && float?(pos[2])
|
2017-10-05 22:19:25 +08:00
|
|
|
return render_403
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
2019-12-19 22:48:25 +08:00
|
|
|
x = pos[1].to_i
|
|
|
|
y = pos[2].to_i
|
2020-06-17 17:55:43 +08:00
|
|
|
|
2016-02-12 23:52:43 +08:00
|
|
|
positions[pos[0]] = { x: x, y: y }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Make sure that to_add is an array of strings,
|
|
|
|
# as well as that positions for newly added modules exist
|
|
|
|
to_add = []
|
2018-02-09 23:14:40 +08:00
|
|
|
if update_params[:add].present? &&
|
2017-10-05 22:19:25 +08:00
|
|
|
update_params['add-names'].present?
|
|
|
|
ids = update_params[:add].split(',')
|
|
|
|
names = update_params['add-names'].split('|')
|
|
|
|
if ids.length == names.length &&
|
|
|
|
ids.all? { |id| id.is_a?(String) && positions.include?(id) } &&
|
|
|
|
names.all? { |name| name.is_a? String }
|
2016-02-12 23:52:43 +08:00
|
|
|
ids.each_with_index do |id, i|
|
2017-10-05 22:19:25 +08:00
|
|
|
to_add << { id: id, name: names[i],
|
|
|
|
x: positions[id][:x], y: positions[id][:y] }
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
2017-10-05 22:19:25 +08:00
|
|
|
else
|
|
|
|
return render_403
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Make sure rename parameter is valid
|
2017-10-05 22:19:25 +08:00
|
|
|
to_rename = {}
|
2018-02-09 23:14:40 +08:00
|
|
|
if update_params[:rename].present?
|
2016-02-12 23:52:43 +08:00
|
|
|
begin
|
|
|
|
to_rename = JSON.parse(update_params[:rename])
|
|
|
|
# Okay, JSON parsed!
|
2017-10-05 22:19:25 +08:00
|
|
|
unless to_rename.is_a?(Hash) &&
|
2018-02-07 18:49:15 +08:00
|
|
|
to_rename.keys.all? do |id|
|
2018-02-09 23:14:40 +08:00
|
|
|
id.is_a?(String) &&
|
2021-09-14 17:08:35 +08:00
|
|
|
can_manage_my_module?(MyModule.find_by(id: id))
|
2018-02-09 23:14:40 +08:00
|
|
|
end &&
|
|
|
|
to_rename.values.all? { |new_name| new_name.is_a? String }
|
2017-10-05 22:19:25 +08:00
|
|
|
return render_403
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
rescue
|
2017-10-05 22:19:25 +08:00
|
|
|
return render_403
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-08-19 19:53:43 +08:00
|
|
|
# Make sure move parameter is valid
|
2016-08-23 17:08:10 +08:00
|
|
|
to_move = {}
|
2018-02-07 18:49:15 +08:00
|
|
|
if update_params[:move].present?
|
2016-08-19 19:53:43 +08:00
|
|
|
begin
|
|
|
|
to_move = JSON.parse(update_params[:move])
|
|
|
|
# Okay, JSON parsed!
|
2017-10-05 22:19:25 +08:00
|
|
|
unless to_move.is_a?(Hash) &&
|
2018-02-09 23:14:40 +08:00
|
|
|
to_move.keys.all? do |id|
|
2021-11-24 17:56:25 +08:00
|
|
|
!is_int?(id) || can_move_my_module?(MyModule.find_by(id: id))
|
2018-02-09 23:14:40 +08:00
|
|
|
end &&
|
2018-02-10 01:02:04 +08:00
|
|
|
to_move.values.all? do |exp_id|
|
2020-07-25 00:38:53 +08:00
|
|
|
can_manage_experiment?(Experiment.find_by(id: exp_id))
|
2018-02-10 01:02:04 +08:00
|
|
|
end
|
2017-10-05 22:19:25 +08:00
|
|
|
return render_403
|
2016-08-19 19:53:43 +08:00
|
|
|
end
|
2020-07-24 23:00:42 +08:00
|
|
|
rescue StandardError
|
2017-10-05 22:19:25 +08:00
|
|
|
return render_403
|
2016-08-19 19:53:43 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-08-22 23:26:21 +08:00
|
|
|
# Distinguish between moving modules/module_groups
|
2016-08-23 17:08:10 +08:00
|
|
|
to_move_groups = {}
|
2016-08-22 23:26:21 +08:00
|
|
|
to_move.each do |key, value|
|
2016-08-23 17:08:10 +08:00
|
|
|
if key =~ /.*,.*/
|
2016-08-23 15:00:25 +08:00
|
|
|
to_move_groups[key.split(',')] = value
|
2016-08-22 23:26:21 +08:00
|
|
|
to_move.delete(key)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-02-12 23:52:43 +08:00
|
|
|
# Make sure that to_clone is an array of pairs,
|
|
|
|
# as well as that all IDs exist
|
2017-10-05 22:19:25 +08:00
|
|
|
to_clone = {}
|
2018-02-09 23:14:40 +08:00
|
|
|
if update_params[:cloned].present?
|
2017-10-05 22:19:25 +08:00
|
|
|
clones = update_params[:cloned].split(';')
|
|
|
|
(clones.collect { |v| v.split(',') }).each do |val|
|
|
|
|
if val.length == 2 && is_int?(val[0]) && val[1].is_a?(String) &&
|
|
|
|
to_add.any? { |m| m[:id] == val[1] }
|
2016-02-12 23:52:43 +08:00
|
|
|
to_clone[val[1]] = val[0]
|
2017-10-05 22:19:25 +08:00
|
|
|
else
|
|
|
|
return render_403
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Call the "master" function to do all the updating for us
|
2016-07-26 20:02:06 +08:00
|
|
|
unless @experiment.update_canvas(
|
2016-02-12 23:52:43 +08:00
|
|
|
to_archive,
|
|
|
|
to_add,
|
|
|
|
to_rename,
|
2016-08-19 19:53:43 +08:00
|
|
|
to_move,
|
2016-08-22 23:26:21 +08:00
|
|
|
to_move_groups,
|
2016-02-12 23:52:43 +08:00
|
|
|
to_clone,
|
|
|
|
connections,
|
|
|
|
positions,
|
2017-10-05 22:19:25 +08:00
|
|
|
current_user
|
2016-02-12 23:52:43 +08:00
|
|
|
)
|
2017-10-05 22:19:25 +08:00
|
|
|
return render_403
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
2017-10-05 22:19:25 +08:00
|
|
|
# Save activities that modules were archived
|
2016-02-12 23:52:43 +08:00
|
|
|
to_archive.each do |module_id|
|
|
|
|
my_module = MyModule.find_by_id(module_id)
|
2017-10-05 22:19:25 +08:00
|
|
|
next if my_module.blank?
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
2017-10-05 22:19:25 +08:00
|
|
|
flash[:success] = t('experiments.canvas.update.success_flash')
|
2016-07-26 20:02:06 +08:00
|
|
|
redirect_to canvas_experiment_path(@experiment)
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def update_params
|
|
|
|
params.permit(
|
|
|
|
:id,
|
|
|
|
:connections,
|
|
|
|
:positions,
|
|
|
|
:add,
|
|
|
|
"add-names",
|
|
|
|
:rename,
|
2016-08-19 19:53:43 +08:00
|
|
|
:move,
|
2016-02-12 23:52:43 +08:00
|
|
|
:cloned,
|
|
|
|
:remove,
|
|
|
|
"module-groups"
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
def load_vars
|
2022-06-09 20:13:29 +08:00
|
|
|
@experiment = Experiment.preload(user_assignments: %i(user user_role)).find_by(id: params[:id])
|
2016-07-26 20:02:06 +08:00
|
|
|
unless @experiment
|
2016-02-12 23:52:43 +08:00
|
|
|
respond_to do |format|
|
|
|
|
format.html { render_404 and return }
|
|
|
|
format.any(:xml, :json, :js) { render(json: { redirect_url: not_found_url }, status: :not_found) and return }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-06-09 20:13:29 +08:00
|
|
|
@my_modules = @experiment.my_modules
|
|
|
|
.active
|
|
|
|
.preload(:tags, outputs: :to, user_assignments: %i(user user_role))
|
|
|
|
.preload(:my_module_status, :my_module_group)
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_edit_canvas
|
2022-05-09 17:40:31 +08:00
|
|
|
@experiment_managable = can_manage_experiment?(@experiment)
|
|
|
|
return render_403 unless @experiment_managable
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def check_view_canvas
|
2018-01-29 18:36:36 +08:00
|
|
|
render_403 unless can_read_experiment?(@experiment)
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
# Check if given value is "integer" string (e.g. "15")
|
|
|
|
def is_int?(val)
|
|
|
|
/\A[-+]?\d+\z/ === val
|
|
|
|
end
|
|
|
|
|
2017-05-26 17:13:27 +08:00
|
|
|
def float?(val)
|
|
|
|
true if Float(val)
|
|
|
|
rescue ArgumentError
|
|
|
|
false
|
|
|
|
end
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|