From e63fb45b9ef774d042fbfbaa2b301e986504a20f Mon Sep 17 00:00:00 2001 From: Andrej Date: Tue, 13 May 2025 11:59:49 +0200 Subject: [PATCH] Add step result link [SCI-11879] --- app/controllers/step_results_controller.rb | 53 +++++++++++++++++++ app/models/result.rb | 2 + app/models/step.rb | 2 + app/models/step_result.rb | 7 +++ app/serializers/result_serializer.rb | 8 ++- app/serializers/step_serializer.rb | 8 ++- config/routes.rb | 7 +++ .../20250513050951_create_step_results.rb | 12 +++++ .../step_results_controller_spec.rb | 51 ++++++++++++++++++ spec/factories/step_results.rb | 9 ++++ spec/models/result_spec.rb | 2 + spec/models/step_result_spec.rb | 26 +++++++++ spec/models/step_spec.rb | 2 + 13 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 app/controllers/step_results_controller.rb create mode 100644 app/models/step_result.rb create mode 100644 db/migrate/20250513050951_create_step_results.rb create mode 100644 spec/controllers/step_results_controller_spec.rb create mode 100644 spec/factories/step_results.rb create mode 100644 spec/models/step_result_spec.rb diff --git a/app/controllers/step_results_controller.rb b/app/controllers/step_results_controller.rb new file mode 100644 index 000000000..e1e32197c --- /dev/null +++ b/app/controllers/step_results_controller.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +class StepResultsController < ApplicationController + before_action :load_step, only: :create + before_action :load_result, only: :create + before_action :load_step_result, only: :destroy + before_action :check_manage_permissions, only: %i(create destroy) + + def create + ActiveRecord::Base.transaction do + @step_result = StepResult.create!(step: @step, result: @result, created_by: current_user) + render json: { step_result: { id: @step_result.id } } + rescue ActiveRecord::RecordInvalid => e + Rails.logger.error e.message + render json: { errors: @step_result.errors.full_messages }, status: :unprocessable_entity + end + end + + def destroy + ActiveRecord::Base.transaction do + if @step_result.destroy + render json: {}, status: :ok + else + render json: { errors: @step_result.errors.full_messages }, status: :unprocessable_entity + end + end + @step_result.destroy! + end + + private + + def load_step + @step = Step.find_by(id: params[:step_id]) + render_404 unless @step + end + + def load_result + @result = Result.find_by(id: params[:result_id]) + render_404 unless @result + end + + def load_step_result + @step_result = StepResult.find_by(id: params[:id]) + render_404 unless @step_result + + @step = @step_result.step + @result = @step_result.result + end + + def check_manage_permissions + render_403 unless @step.my_module == @result.my_module && can_manage_my_module?(@step.my_module) + end +end diff --git a/app/models/result.rb b/app/models/result.rb index 86f152946..b23b63e49 100644 --- a/app/models/result.rb +++ b/app/models/result.rb @@ -31,6 +31,8 @@ class Result < ApplicationRecord has_many :result_texts, inverse_of: :result, dependent: :destroy has_many :result_comments, inverse_of: :result, foreign_key: :associated_id, dependent: :destroy has_many :report_elements, inverse_of: :result, dependent: :destroy + has_many :step_results, inverse_of: :result, dependent: :destroy + has_many :steps, through: :step_results accepts_nested_attributes_for :result_texts accepts_nested_attributes_for :assets diff --git a/app/models/step.rb b/app/models/step.rb index 435b5be6c..6603cf2ff 100644 --- a/app/models/step.rb +++ b/app/models/step.rb @@ -44,6 +44,8 @@ class Step < ApplicationRecord has_many :tables, through: :step_tables, dependent: :destroy has_many :report_elements, inverse_of: :step, dependent: :destroy has_many :form_responses, as: :parent, inverse_of: :parent, dependent: :destroy + has_many :step_results, inverse_of: :step, dependent: :destroy + has_many :results, through: :step_results accepts_nested_attributes_for :checklists, reject_if: :all_blank, diff --git a/app/models/step_result.rb b/app/models/step_result.rb new file mode 100644 index 000000000..72fc2db97 --- /dev/null +++ b/app/models/step_result.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class StepResult < ApplicationRecord + belongs_to :result + belongs_to :step + belongs_to :created_by, class_name: 'User' +end diff --git a/app/serializers/result_serializer.rb b/app/serializers/result_serializer.rb index 9988a28a6..643643b44 100644 --- a/app/serializers/result_serializer.rb +++ b/app/serializers/result_serializer.rb @@ -10,13 +10,19 @@ class ResultSerializer < ActiveModel::Serializer attributes :name, :id, :urls, :updated_at, :created_at_formatted, :updated_at_formatted, :user, :my_module_id, :attachments_manageble, :marvinjs_enabled, :marvinjs_context, :type, :wopi_enabled, :wopi_context, :created_at, :created_by, :archived, :assets_order, - :open_vector_editor_context, :comments_count, :assets_view_mode, :storage_limit, :collapsed + :open_vector_editor_context, :comments_count, :assets_view_mode, :storage_limit, :collapsed, :steps def collapsed result_states = current_user.settings.fetch('result_states', {}) result_states[object.id.to_s] == true end + def steps + object.steps.map do |step| + { id: step.id, name: step.name } + end + end + def marvinjs_enabled MarvinJsService.enabled? end diff --git a/app/serializers/step_serializer.rb b/app/serializers/step_serializer.rb index cab680382..b6dc4f5aa 100644 --- a/app/serializers/step_serializer.rb +++ b/app/serializers/step_serializer.rb @@ -10,7 +10,7 @@ class StepSerializer < ActiveModel::Serializer attributes :name, :position, :completed, :attachments_manageble, :urls, :assets_view_mode, :marvinjs_enabled, :marvinjs_context, :created_by, :created_at, :assets_order, :wopi_enabled, :wopi_context, :comments_count, :unseen_comments, :storage_limit, - :type, :open_vector_editor_context, :collapsed + :type, :open_vector_editor_context, :collapsed, :results def collapsed step_states = @instance_options[:user].settings.fetch('task_step_states', {}) @@ -21,6 +21,12 @@ class StepSerializer < ActiveModel::Serializer MarvinJsService.enabled? end + def results + object.results.map do |result| + { id: result.id, name: result.name } + end + end + def type 'Step' end diff --git a/config/routes.rb b/config/routes.rb index 93a466267..1bdf5647e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -459,6 +459,13 @@ Rails.application.routes.draw do # as well as 'module info' page for single module (HTML) get 'experiments/:experiment_id/table', to: 'my_modules#index' get 'experiments/:experiment_id/modules', to: 'my_modules#index', as: :my_modules + + resources :step_results, only: %i(destroy) do + collection do + post :create + end + end + resources :my_modules, path: '/modules', only: [:show, :update] do post 'save_table_state', on: :collection, defaults: { format: 'json' } diff --git a/db/migrate/20250513050951_create_step_results.rb b/db/migrate/20250513050951_create_step_results.rb new file mode 100644 index 000000000..bc4b8cd1b --- /dev/null +++ b/db/migrate/20250513050951_create_step_results.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class CreateStepResults < ActiveRecord::Migration[7.0] + def change + create_table :step_results do |t| + t.references :step, null: false, foreign_key: true + t.references :result, null: false, foreign_key: true + t.references :created_by, null: false, foreign_key: { to_table: :users } + t.timestamps + end + end +end diff --git a/spec/controllers/step_results_controller_spec.rb b/spec/controllers/step_results_controller_spec.rb new file mode 100644 index 000000000..e0dfd3b28 --- /dev/null +++ b/spec/controllers/step_results_controller_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe StepResultsController, type: :controller do + login_user + + include_context 'reference_project_structure', { + my_modules: 1, + step: true, + result_text: true + } + + let(:step_second) { create :step, protocol: my_modules.first.protocol, user: user } + let(:result_second) { create :result, my_module: my_modules.first, user: user } + let(:step_result) { create :step_result, step: step_second, result: result_second } + + describe 'POST create link step result succesfully' do + let(:action) { post :create, params: params } + let(:params) do + { + step_id: step.id, + result_id: result_text.result.id + } + end + + it 'calls create activity service' do + action + expect(response).to have_http_status(:success) + end + + it 'calls create activity service' do + params[:step_id] = step_second.id + action + expect(response).to have_http_status(:forbidden) + end + end + + describe 'DELETE destroy' do + let(:action) { delete :destroy, params: params, format: :json } + + context 'when in protocol repository' do + let(:params) { { id: step_result.id } } + + it 'calls create activity for deleting step in protocol repository' do + action + expect(response).to have_http_status(:success) + end + end + end +end diff --git a/spec/factories/step_results.rb b/spec/factories/step_results.rb new file mode 100644 index 000000000..919f3920d --- /dev/null +++ b/spec/factories/step_results.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :step_result do + association :step, factory: :step + association :result, factory: :result + association :created_by, factory: :user + end +end diff --git a/spec/models/result_spec.rb b/spec/models/result_spec.rb index a769b1828..7b928267b 100644 --- a/spec/models/result_spec.rb +++ b/spec/models/result_spec.rb @@ -40,6 +40,8 @@ describe Result, type: :model do it { should have_many :result_texts } it { should have_many :result_comments } it { should have_many :report_elements } + it { should have_many :step_results } + it { should have_many :steps } end describe 'Validations' do diff --git a/spec/models/step_result_spec.rb b/spec/models/step_result_spec.rb new file mode 100644 index 000000000..aa60b9d2a --- /dev/null +++ b/spec/models/step_result_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe StepResult, type: :model do + let(:step_result) { build :step_result } + + it 'is valid' do + expect(step_result).to be_valid + end + + it 'should be of class form field value' do + expect(subject.class).to eq StepResult + end + + describe 'Database table' do + it { should have_db_column :created_at } + it { should have_db_column :updated_at } + end + + describe 'Relations' do + it { should belong_to(:step) } + it { should belong_to(:result) } + it { should belong_to(:created_by).class_name('User') } + end +end diff --git a/spec/models/step_spec.rb b/spec/models/step_spec.rb index 634f4b7a2..39f3b4578 100644 --- a/spec/models/step_spec.rb +++ b/spec/models/step_spec.rb @@ -38,6 +38,8 @@ describe Step, type: :model do it { should have_many :tables } it { should have_many :report_elements } it { should have_many :tiny_mce_assets } + it { should have_many :step_results } + it { should have_many :results } end describe 'Validations' do