mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-03-04 19:53:19 +08:00
Merge branch 'ur-SCI-2925-copy-experiment-refactor'
This commit is contained in:
commit
293eef01c1
4 changed files with 169 additions and 58 deletions
|
@ -185,37 +185,15 @@ class ExperimentsController < ApplicationController
|
||||||
|
|
||||||
# POST: clone_experiment(id)
|
# POST: clone_experiment(id)
|
||||||
def clone
|
def clone
|
||||||
project = Project.find_by_id(params[:experiment].try(:[], :project_id))
|
service = Experiments::CopyExperimentAsTemplateService
|
||||||
|
.call(experiment_id: @experiment.id,
|
||||||
# Try to clone the experiment
|
project_id: move_experiment_param,
|
||||||
success = true
|
user_id: current_user.id)
|
||||||
if @experiment.projects_with_role_above_user(current_user).include?(project)
|
|
||||||
cloned_experiment = @experiment.deep_clone_to_project(current_user,
|
|
||||||
project)
|
|
||||||
success = cloned_experiment.valid?
|
|
||||||
# Create workflow image
|
|
||||||
cloned_experiment.delay.generate_workflow_img if success
|
|
||||||
else
|
|
||||||
success = false
|
|
||||||
end
|
|
||||||
|
|
||||||
if success
|
|
||||||
Activity.create(
|
|
||||||
type_of: :clone_experiment,
|
|
||||||
project: project,
|
|
||||||
experiment: @experiment,
|
|
||||||
user: current_user,
|
|
||||||
message: I18n.t(
|
|
||||||
'activities.clone_experiment',
|
|
||||||
user: current_user.full_name,
|
|
||||||
experiment_new: cloned_experiment.name,
|
|
||||||
experiment_original: @experiment.name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
if service.succeed?
|
||||||
flash[:success] = t('experiments.clone.success_flash',
|
flash[:success] = t('experiments.clone.success_flash',
|
||||||
experiment: @experiment.name)
|
experiment: @experiment.name)
|
||||||
redirect_to canvas_experiment_path(cloned_experiment)
|
redirect_to canvas_experiment_path(service.cloned_experiment)
|
||||||
else
|
else
|
||||||
flash[:error] = t('experiments.clone.error_flash',
|
flash[:error] = t('experiments.clone.error_flash',
|
||||||
experiment: @experiment.name)
|
experiment: @experiment.name)
|
||||||
|
|
|
@ -225,36 +225,6 @@ class Experiment < ApplicationRecord
|
||||||
Experiments::GenerateWorkflowImageService.call(experiment_id: id)
|
Experiments::GenerateWorkflowImageService.call(experiment_id: id)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Clone this experiment to given project
|
|
||||||
def deep_clone_to_project(current_user, project)
|
|
||||||
# First we have to find unique name for our little experiment
|
|
||||||
experiment_names = project.experiments.map(&:name)
|
|
||||||
format = 'Clone %d - %s'
|
|
||||||
|
|
||||||
i = 1
|
|
||||||
i += 1 while experiment_names.include?(format(format, i, name))
|
|
||||||
|
|
||||||
clone = Experiment.new(
|
|
||||||
name: format(format, i, name).truncate(Constants::NAME_MAX_LENGTH),
|
|
||||||
description: description,
|
|
||||||
created_by: current_user,
|
|
||||||
last_modified_by: current_user,
|
|
||||||
project: project
|
|
||||||
)
|
|
||||||
|
|
||||||
# Copy all workflows
|
|
||||||
my_module_groups.each do |g|
|
|
||||||
clone.my_module_groups << g.deep_clone_to_experiment(current_user, clone)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Copy modules without group
|
|
||||||
clone.my_modules << my_modules.without_group.map do |m|
|
|
||||||
m.deep_clone_to_experiment(current_user, clone)
|
|
||||||
end
|
|
||||||
clone.save
|
|
||||||
clone
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get projects where user is either owner or user in the same team
|
# Get projects where user is either owner or user in the same team
|
||||||
# as this experiment
|
# as this experiment
|
||||||
def projects_with_role_above_user(current_user)
|
def projects_with_role_above_user(current_user)
|
||||||
|
|
103
app/services/experiments/copy_experiment_as_template_service.rb
Normal file
103
app/services/experiments/copy_experiment_as_template_service.rb
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Experiments
|
||||||
|
class CopyExperimentAsTemplateService
|
||||||
|
extend Service
|
||||||
|
|
||||||
|
attr_reader :errors, :c_exp
|
||||||
|
alias cloned_experiment c_exp
|
||||||
|
|
||||||
|
def initialize(experiment_id:, project_id:, user_id:)
|
||||||
|
@exp = Experiment.find experiment_id
|
||||||
|
@project = Project.find project_id
|
||||||
|
@user = User.find user_id
|
||||||
|
@original_project = @exp&.project
|
||||||
|
@c_exp = nil
|
||||||
|
@errors = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
return self unless valid?
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
@c_exp = Experiment.new(
|
||||||
|
name: find_uniq_name,
|
||||||
|
description: @exp.description,
|
||||||
|
created_by: @user,
|
||||||
|
last_modified_by: @user,
|
||||||
|
project: @project
|
||||||
|
)
|
||||||
|
|
||||||
|
# Copy all signle taskas
|
||||||
|
@c_exp.my_modules << @exp.my_modules.without_group.map do |m|
|
||||||
|
m.deep_clone_to_experiment(@user, @c_exp)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Copy all grouped tasks
|
||||||
|
@exp.my_module_groups.each do |g|
|
||||||
|
@c_exp.my_module_groups << g.deep_clone_to_experiment(@user, @c_exp)
|
||||||
|
end
|
||||||
|
|
||||||
|
raise ActiveRecord::Rollback unless @c_exp.save
|
||||||
|
end
|
||||||
|
@errors.merge!(@c_exp.errors.to_hash) unless @c_exp.valid?
|
||||||
|
|
||||||
|
@c_exp = nil unless succeed?
|
||||||
|
@c_exp.delay.generate_workflow_img if succeed?
|
||||||
|
track_activity if succeed?
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def succeed?
|
||||||
|
@errors.none?
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_uniq_name
|
||||||
|
experiment_names = @project.experiments.map(&:name)
|
||||||
|
format = 'Clone %d - %s'
|
||||||
|
free_index = 1
|
||||||
|
free_index += 1 while experiment_names
|
||||||
|
.include?(format(format, free_index, @exp.name))
|
||||||
|
format(format, free_index, @exp.name).truncate(Constants::NAME_MAX_LENGTH)
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid?
|
||||||
|
unless @exp && @project && @user
|
||||||
|
@errors[:invalid_arguments] =
|
||||||
|
{ 'experiment': @exp,
|
||||||
|
'project': @project,
|
||||||
|
'user': @user }
|
||||||
|
.map do |key, value|
|
||||||
|
"Can't find #{key.capitalize}" if value.nil?
|
||||||
|
end.compact
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if @exp.projects_with_role_above_user(@user).include?(@project)
|
||||||
|
true
|
||||||
|
else
|
||||||
|
@errors[:user_without_permissions] =
|
||||||
|
['You are not allowed to copy this experiment to this project']
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def track_activity
|
||||||
|
Activity.create(
|
||||||
|
type_of: :clone_experiment,
|
||||||
|
project: @project,
|
||||||
|
experiment: @exp,
|
||||||
|
user: @user,
|
||||||
|
message: I18n.t(
|
||||||
|
'activities.clone_experiment',
|
||||||
|
user: @user,
|
||||||
|
experiment_new: @c_exp.name,
|
||||||
|
experiment_original: @exp.name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,60 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Experiments::CopyExperimentAsTemplateService do
|
||||||
|
let(:team) { create :team, :with_members }
|
||||||
|
let(:user_project) { create :user_project, :normal_user, user: user }
|
||||||
|
|
||||||
|
let(:project) do
|
||||||
|
create :project, team: team
|
||||||
|
end
|
||||||
|
let(:new_project) do
|
||||||
|
create :project, team: team, user_projects: [user_project]
|
||||||
|
end
|
||||||
|
let(:experiment) do
|
||||||
|
create :experiment_with_tasks, name: 'MyExp', project: project
|
||||||
|
end
|
||||||
|
let(:user) { create :user }
|
||||||
|
let(:service_call) do
|
||||||
|
Experiments::CopyExperimentAsTemplateService
|
||||||
|
.call(experiment_id: experiment.id,
|
||||||
|
project_id: new_project.id,
|
||||||
|
user_id: user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when service call is successful' do
|
||||||
|
it 'adds new experiment to target project' do
|
||||||
|
expect { service_call }.to(change { new_project.experiments.count })
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds Activity record' do
|
||||||
|
expect { service_call }.to(change { Activity.all.count })
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'copies all tasks to new experiment' do
|
||||||
|
expect(service_call.cloned_experiment.my_modules.count)
|
||||||
|
.to be == experiment.my_modules.count
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'copies all task groups to new experiment' do
|
||||||
|
expect(service_call.cloned_experiment.my_module_groups.count)
|
||||||
|
.to be == experiment.my_module_groups.count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when service call is not successful' do
|
||||||
|
it 'returns an error when can\'t find experiment' do
|
||||||
|
allow(Experiment).to receive(:find).and_return(nil)
|
||||||
|
|
||||||
|
expect(service_call.errors).to have_key(:invalid_arguments)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns error when user don\'t have permissions' do
|
||||||
|
expect_any_instance_of(Experiment)
|
||||||
|
.to receive(:projects_with_role_above_user).and_return([])
|
||||||
|
|
||||||
|
expect(service_call.errors).not_to be_empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue