Add API endpoints for checklists, checklist items, tables, API code improvements [SCI-4776]

This commit is contained in:
Oleksii Kriuchykhin 2020-07-02 17:03:29 +02:00
parent 6726a19cbe
commit dc481cf236
35 changed files with 1505 additions and 260 deletions

View file

@ -31,9 +31,6 @@ Style/BarePercentLiterals:
Style/BlockDelimiters:
EnforcedStyle: line_count_based
Style/BracesAroundHashParameters:
EnforcedStyle: no_braces
Layout/CaseIndentation:
EnforcedStyle: case

View file

@ -5,6 +5,7 @@ module Api
class BaseController < ApiController
class TypeError < StandardError; end
class IDMismatchError < StandardError; end
class IncludeNotSupportedError < StandardError; end
class PermissionError < StandardError
attr_reader :klass
attr_reader :mode
@ -43,6 +44,18 @@ module Api
:bad_request)
end
rescue_from NotImplementedError do
render_error(I18n.t('api.core.errors.not_implemented.title'),
I18n.t('api.core.errors.not_implemented.detail'),
:bad_request)
end
rescue_from IncludeNotSupportedError do
render_error(I18n.t('api.core.errors.include_not_supported.title'),
I18n.t('api.core.errors.include_not_supported.detail'),
:bad_request)
end
rescue_from ActionController::ParameterMissing do |e|
render_error(
I18n.t('api.core.errors.parameter.title'), e.message, :bad_request
@ -74,6 +87,28 @@ module Api
)
end
before_action :check_include_param, only: %i(index show)
def index
raise NotImplementedError
end
def show
raise NotImplementedError
end
def create
raise NotImplementedError
end
def update
raise NotImplementedError
end
def destroy
raise NotImplementedError
end
private
def render_error(title, message, status)
@ -90,6 +125,26 @@ module Api
}, status: status
end
def check_include_param
return if params[:include].blank?
include_params
end
# redefine it in the specific controller if includes are used there
def permitted_includes
[]
end
def include_params
return nil if params[:include].blank?
provided_includes = params[:include].split(',')
raise IncludeNotSupportedError if (provided_includes - permitted_includes).any?
provided_includes
end
def load_team(key = :team_id)
@team = Team.find(params.require(key))
raise PermissionError.new(Team, :read) unless can_read_team?(@team)
@ -131,6 +186,21 @@ module Api
@step = @protocol.steps.find(params.require(key))
raise PermissionError.new(Protocol, :read) unless can_read_protocol_in_module?(@step.protocol)
end
def load_table(key = :table_id)
@table = @step.tables.find(params.require(key))
raise PermissionError.new(Protocol, :read) unless can_read_protocol_in_module?(@step.protocol)
end
def load_checklist(key = :checklist_id)
@checklist = @step.checklists.find(params.require(key))
raise PermissionError.new(Protocol, :read) unless can_read_protocol_in_module?(@step.protocol)
end
def load_checklist_item(key = :checklist_item_id)
@checklist_item = @checklist.checklist_items.find(params.require(key))
raise PermissionError.new(Protocol, :read) unless can_read_protocol_in_module?(@step.protocol)
end
end
end
end

View file

@ -0,0 +1,59 @@
# frozen_string_literal: true
module Api
module V1
class ChecklistItemsController < BaseController
before_action :load_team, :load_project, :load_experiment, :load_task, :load_protocol, :load_step, :load_checklist
before_action only: :show do
load_checklist_item(:id)
end
before_action :load_checklist_item_for_managing, only: %i(update destroy)
def index
checklist_items = @checklist.checklist_items.page(params.dig(:page, :number)).per(params.dig(:page, :size))
render jsonapi: checklist_items, each_serializer: ChecklistItemSerializer
end
def show
render jsonapi: @checklist_item, serializer: ChecklistItemSerializer
end
def create
raise PermissionError.new(Protocol, :create) unless can_manage_protocol_in_module?(@protocol)
checklist_item = @checklist.checklist_items.create!(checklist_item_params.merge!(created_by: current_user))
render jsonapi: checklist_item, serializer: ChecklistItemSerializer, status: :created
end
def update
@checklist_item.assign_attributes(checklist_item_params)
if @checklist_item.changed? && @checklist_item.save!
render jsonapi: @checklist_item, serializer: ChecklistItemSerializer, status: :ok
else
render body: nil, status: :no_content
end
end
def destroy
@checklist_item.destroy!
render body: nil
end
private
def checklist_item_params
raise TypeError unless params.require(:data).require(:type) == 'checklist_items'
params.require(:data).require(:attributes).permit(:text, :checked, :position)
end
def load_checklist_item_for_managing
@checklist_item = @checklist.checklist_items.find(params.require(:id))
raise PermissionError.new(Protocol, :manage) unless can_manage_protocol_in_module?(@protocol)
end
end
end
end

View file

@ -0,0 +1,63 @@
# frozen_string_literal: true
module Api
module V1
class ChecklistsController < BaseController
before_action :load_team, :load_project, :load_experiment, :load_task, :load_protocol, :load_step
before_action only: :show do
load_checklist(:id)
end
before_action :load_checklist_for_managing, only: %i(update destroy)
def index
checklists = @step.checklists.page(params.dig(:page, :number)).per(params.dig(:page, :size))
render jsonapi: checklists, each_serializer: ChecklistSerializer, include: include_params
end
def show
render jsonapi: @checklist, serializer: ChecklistSerializer, include: include_params
end
def create
raise PermissionError.new(Protocol, :create) unless can_manage_protocol_in_module?(@protocol)
checklist = @step.checklists.create!(checklist_params.merge!(created_by: current_user))
render jsonapi: checklist, serializer: ChecklistSerializer, status: :created
end
def update
@checklist.assign_attributes(checklist_params)
if @checklist.changed? && @checklist.save!
render jsonapi: @checklist, serializer: ChecklistSerializer, status: :ok
else
render body: nil, status: :no_content
end
end
def destroy
@checklist.destroy!
render body: nil
end
private
def checklist_params
raise TypeError unless params.require(:data).require(:type) == 'checklists'
params.require(:data).require(:attributes).permit(:name)
end
def permitted_includes
%w(checklist_items)
end
def load_checklist_for_managing
@checklist = @step.checklists.find(params.require(:id))
raise PermissionError.new(Protocol, :manage) unless can_manage_protocol_in_module?(@protocol)
end
end
end
end

View file

@ -12,10 +12,9 @@ module Api
def index
@connections = @connections.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
incl = params[:include] == 'tasks' ? %i(input_task output_task) : nil
render jsonapi: @connections,
each_serializer: ConnectionSerializer,
include: incl
include: include_params
end
def show
@ -40,6 +39,10 @@ module Api
def load_connection
@connection = @connections.find(params.require(:id))
end
def permitted_includes
%w(tasks)
end
end
end
end

View file

@ -11,17 +11,13 @@ module Api
before_action :check_manage_permissions, only: %i(create update destroy)
def index
items =
@inventory.repository_rows
.active
.preload(repository_cells: :repository_column)
.preload(repository_cells: @inventory.cell_preload_includes)
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
incl = params[:include] == 'inventory_cells' ? :inventory_cells : nil
render jsonapi: items,
each_serializer: InventoryItemSerializer,
include: incl
items = @inventory.repository_rows
.active
.preload(repository_cells: :repository_column)
.preload(repository_cells: @inventory.cell_preload_includes)
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
render jsonapi: items, each_serializer: InventoryItemSerializer, include: include_params
end
def create
@ -120,6 +116,10 @@ module Api
def inventory_cells_params
params[:included]&.select { |el| el[:type] == 'inventory_cells' }
end
def permitted_includes
%w(inventory_cells)
end
end
end
end

View file

@ -7,7 +7,7 @@ module Api
before_action only: :show do
load_project(:id)
end
before_action :load_project_relative, only: :activities
before_action :load_project, only: :activities
def index
projects = @team.projects
@ -29,15 +29,6 @@ module Api
render jsonapi: activities,
each_serializer: ActivitySerializer
end
private
def load_project_relative
@project = @team.projects.find(params.require(:project_id))
unless can_read_project?(@project)
raise PermissionError.new(Project, :read)
end
end
end
end
end

View file

@ -3,33 +3,51 @@
module Api
module V1
class StepsController < BaseController
include Api::V1::ExtraParams
before_action :load_team, :load_project, :load_experiment, :load_task, :load_protocol
before_action only: :show do
load_step(:id)
end
before_action :load_step_for_managing, only: %i(update destroy)
def index
steps = @protocol.steps
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
steps = @protocol.steps.page(params.dig(:page, :number)).per(params.dig(:page, :size))
render jsonapi: steps, each_serializer: StepSerializer
render jsonapi: steps, each_serializer: StepSerializer,
include: include_params,
rte_rendering: render_rte?
end
def show
render jsonapi: @step, serializer: StepSerializer
render jsonapi: @step, serializer: StepSerializer,
include: include_params,
rte_rendering: render_rte?
end
def create
raise PermissionError.new(Protocol, :create) unless can_manage_protocol_in_module?(@protocol)
step = @protocol.steps.create!(step_params.merge!(completed: false,
user_id: current_user.id,
user: current_user,
position: @protocol.number_of_steps))
render jsonapi: step,
serializer: StepSerializer,
status: :created
render jsonapi: step, serializer: StepSerializer, status: :created
end
def update
@step.assign_attributes(step_params)
if @step.changed? && @step.save!
render jsonapi: @step, serializer: StepSerializer, status: :ok
else
render body: nil, status: :no_content
end
end
def destroy
@step.destroy!
render body: nil
end
private
@ -37,9 +55,16 @@ module Api
def step_params
raise TypeError unless params.require(:data).require(:type) == 'steps'
attr_list = %i(name)
params.require(:data).require(:attributes).require(attr_list)
params.require(:data).require(:attributes).permit(attr_list + [:description])
params.require(:data).require(:attributes).permit(:name, :description, :completed)
end
def permitted_includes
%w(tables assets checklists checklists.checklist_items comments)
end
def load_step_for_managing
@step = @protocol.steps.find(params.require(:id))
raise PermissionError.new(Protocol, :manage) unless can_manage_protocol_in_module?(@step.protocol)
end
end
end

View file

@ -0,0 +1,59 @@
# frozen_string_literal: true
module Api
module V1
class TablesController < BaseController
before_action :load_team, :load_project, :load_experiment, :load_task, :load_protocol, :load_step
before_action only: :show do
load_table(:id)
end
before_action :load_table_for_managing, only: %i(update destroy)
def index
tables = @step.tables.page(params.dig(:page, :number)).per(params.dig(:page, :size))
render jsonapi: tables, each_serializer: TableSerializer
end
def show
render jsonapi: @table, serializer: TableSerializer
end
def create
raise PermissionError.new(Protocol, :create) unless can_manage_protocol_in_module?(@protocol)
table = @step.tables.create!(table_params.merge!(team: @team, created_by: current_user))
render jsonapi: table, serializer: TableSerializer, status: :created
end
def update
@table.assign_attributes(table_params)
if @table.changed? && @table.save!
render jsonapi: @table, serializer: TableSerializer, status: :ok
else
render body: nil, status: :no_content
end
end
def destroy
@table.destroy!
render body: nil
end
private
def table_params
raise TypeError unless params.require(:data).require(:type) == 'tables'
params.require(:data).require(:attributes).permit(:name, :contents)
end
def load_table_for_managing
@table = @step.tables.find(params.require(:id))
raise PermissionError.new(Protocol, :manage) unless can_manage_protocol_in_module?(@protocol)
end
end
end
end

View file

@ -12,10 +12,7 @@ module Api
task_groups = @experiment.my_module_groups
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
incl = params[:include] == 'tasks' ? :tasks : nil
render jsonapi: task_groups,
each_serializer: TaskGroupSerializer,
include: incl
render jsonapi: task_groups, each_serializer: TaskGroupSerializer, include: include_params
end
def show
@ -29,6 +26,10 @@ module Api
def load_task_group
@task_group = @experiment.my_module_groups.find(params.require(:id))
end
def permitted_includes
%w(tasks)
end
end
end
end

View file

@ -15,11 +15,10 @@ module Api
.includes(repository_cells: Extends::REPOSITORY_SEARCH_INCLUDES)
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
incl = params[:include] == 'inventory_cells' ? :inventory_cells : nil
render jsonapi: items,
each_serializer: InventoryItemSerializer,
show_repository: true,
include: incl
include: include_params
end
def show
@ -28,6 +27,12 @@ module Api
show_repository: true,
include: %i(inventory_cells inventory)
end
private
def permitted_includes
%w(inventory_cells)
end
end
end
end

View file

@ -3,34 +3,47 @@
module Api
module V1
class TasksController < BaseController
include Api::V1::ExtraParams
before_action :load_team
before_action :load_project
before_action :load_experiment
before_action only: :show do
load_task(:id)
end
before_action :load_task_relative, only: :activities
before_action :load_task_for_managing, only: %i(update)
before_action :load_task, only: :activities
def index
tasks = @experiment.my_modules
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
render jsonapi: tasks, each_serializer: TaskSerializer
render jsonapi: tasks, each_serializer: TaskSerializer, rte_rendering: render_rte?
end
def show
render jsonapi: @task, serializer: TaskSerializer
render jsonapi: @task, serializer: TaskSerializer, rte_rendering: render_rte?
end
def create
raise PermissionError.new(MyModule, :create) unless can_manage_experiment?(@experiment)
my_module = @experiment.my_modules.create!(my_module_params)
my_module = @experiment.my_modules.create!(task_params)
render jsonapi: my_module,
serializer: TaskSerializer,
status: :created
render jsonapi: my_module, serializer: TaskSerializer,
rte_rendering: render_rte?,
status: :created
end
def update
@task.assign_attributes(task_params)
if @task.changed? && @task.save!
render jsonapi: @task, serializer: TaskSerializer, status: :ok
else
render body: nil, status: :no_content
end
end
def activities
@ -38,26 +51,20 @@ module Api
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
render jsonapi: activities,
each_serializer: ActivitySerializer
render jsonapi: activities, each_serializer: ActivitySerializer
end
private
def my_module_params
def task_params
raise TypeError unless params.require(:data).require(:type) == 'tasks'
attr_list = %i(name x y)
params.require(:data).require(:attributes).require(attr_list)
params.require(:data).require(:attributes).permit(attr_list + [:description])
params.require(:data).require(:attributes).permit(%i(name x y description state))
end
# Made the method below because its more elegant than changing parameters
# in routes file, and here. It exists because when we call input or output
# for a task, the "id" that used to be task id is now an id for the output
# or input.
def load_task_relative
@task = @experiment.my_modules.find(params.require(:task_id))
def load_task_for_managing
@task = @experiment.my_modules.find(params.require(:id))
raise PermissionError.new(MyModule, :manage) unless can_manage_module?(@task)
end
end
end

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
module Api
module V1
module ExtraParams
extend ActiveSupport::Concern
def render_rte?
params[:render_rte] == 'true'
end
end
end
end

View file

@ -13,7 +13,7 @@ class MyModulesController < ApplicationController
before_action :check_manage_permissions, only: %i(description due_date update_description update_protocol_description)
before_action :check_view_permissions, except: %i(update update_description update_protocol_description
toggle_task_state)
before_action :check_complete_module_permission, only: :complete_my_module
before_action :check_complete_module_permission, only: %i(complete_my_module toggle_task_state)
before_action :set_inline_name_editing, only: %i(protocols results activities archive)
layout 'fluid'.freeze
@ -258,38 +258,29 @@ class MyModulesController < ApplicationController
# Complete/uncomplete task
def toggle_task_state
respond_to do |format|
if can_complete_module?(@my_module)
@my_module.completed? ? @my_module.uncomplete : @my_module.complete
completed = @my_module.completed?
if @my_module.save
task_completion_activity
@my_module.completed? ? @my_module.uncompleted! : @my_module.completed!
task_completion_activity
# Render new button HTML
if completed
new_btn_partial = 'my_modules/state_button_uncomplete.html.erb'
else
new_btn_partial = 'my_modules/state_button_complete.html.erb'
end
# Render new button HTML
new_btn_partial = if @my_module.completed?
'my_modules/state_button_uncomplete.html.erb'
else
'my_modules/state_button_complete.html.erb'
end
format.json do
render json: {
new_btn: render_to_string(partial: new_btn_partial),
completed: completed,
module_header_due_date: render_to_string(
partial: 'my_modules/module_header_due_date.html.erb',
locals: { my_module: @my_module }
),
module_state_label: render_to_string(
partial: 'my_modules/module_state_label.html.erb',
locals: { my_module: @my_module }
)
}
end
else
format.json { render json: {}, status: :unprocessable_entity }
end
else
format.json { render json: {}, status: :unauthorized }
format.json do
render json: {
new_btn: render_to_string(partial: new_btn_partial),
completed: @my_module.completed?,
module_header_due_date: render_to_string(
partial: 'my_modules/module_header_due_date.html.erb',
locals: { my_module: @my_module }
),
module_state_label: render_to_string(
partial: 'my_modules/module_state_label.html.erb',
locals: { my_module: @my_module }
)
}
end
end
end
@ -297,22 +288,21 @@ class MyModulesController < ApplicationController
def complete_my_module
respond_to do |format|
if @my_module.uncompleted? && @my_module.check_completness_status
@my_module.complete
@my_module.save
@my_module.completed!
task_completion_activity
format.json do
render json: {
task_button_title: t('my_modules.buttons.uncomplete'),
module_header_due_date: render_to_string(
partial: 'my_modules/module_header_due_date.html.erb',
locals: { my_module: @my_module }
),
module_state_label: render_to_string(
partial: 'my_modules/module_state_label.html.erb',
locals: { my_module: @my_module }
)
}, status: :ok
end
render json: {
task_button_title: t('my_modules.buttons.uncomplete'),
module_header_due_date: render_to_string(
partial: 'my_modules/module_header_due_date.html.erb',
locals: { my_module: @my_module }
),
module_state_label: render_to_string(
partial: 'my_modules/module_state_label.html.erb',
locals: { my_module: @my_module }
)
}, status: :ok
end
else
format.json { render json: {}, status: :unprocessable_entity }
end

View file

@ -4,17 +4,16 @@ class StepsController < ApplicationController
include StepsActions
include MarvinJsActions
before_action :load_vars, only: %i(edit update destroy show toggle_step_state checklistitem_state update_view_state)
before_action :load_vars_nested, only: [:new, :create]
before_action :convert_table_contents_to_utf8, only: [:create, :update]
before_action :load_vars, only: %i(edit update destroy show toggle_step_state checklistitem_state update_view_state
move_up move_down)
before_action :load_vars_nested, only: %i(new create)
before_action :convert_table_contents_to_utf8, only: %i(create update)
before_action :check_view_permissions, only: %i(show update_view_state)
before_action :check_manage_permissions, only: %i(new create edit update
destroy)
before_action :check_complete_and_checkbox_permissions, only:
%i(toggle_step_state checklistitem_state)
before_action :check_manage_permissions, only: %i(new create edit update destroy move_up move_down)
before_action :check_complete_and_checkbox_permissions, only: %i(toggle_step_state checklistitem_state)
before_action :update_checklist_item_positions, only: [:create, :update]
before_action :update_checklist_item_positions, only: %i(create update)
def new
@step = Step.new
@ -244,7 +243,7 @@ class StepsController < ApplicationController
end
# Destroy the step
@step.destroy(current_user)
@step.destroy
# Release space taken by the step
team.release_space(previous_size)
@ -371,95 +370,58 @@ class StepsController < ApplicationController
end
def move_up
step = Step.find_by_id(params[:id])
respond_to do |format|
if step
protocol = step.protocol
if can_manage_protocol_in_module?(protocol) ||
can_manage_protocol_in_repository?(protocol)
if step.position > 0
step_down = step.protocol.steps.where(position: step.position - 1).first
step.position -= 1
step.save
if @step.position.positive?
step_down = @step.protocol.steps.find_by(position: @step.position - 1)
@step.position -= 1
@step.save
if step_down
step_down.position += 1
step_down.save
if step_down
step_down.position += 1
step_down.save
# Update protocol timestamp
update_protocol_ts(step)
# Update protocol timestamp
update_protocol_ts(@step)
format.json {
render json: { move_direction: "up", step_up_position: step.position, step_down_position: step_down.position },
status: :ok
}
else
format.json {
render json: {}, status: :forbidden
}
end
else
format.json {
render json: {}, status: :forbidden
}
format.json do
render json: { move_direction: 'up',
step_up_position: @step.position,
step_down_position: step_down.position },
status: :ok
end
else
format.json {
render json: {}, status: :forbidden
}
format.json { render json: {}, status: :forbidden }
end
else
format.json {
render json: {}, status: :not_found
}
format.json { render json: {}, status: :forbidden }
end
end
end
def move_down
step = Step.find_by_id(params[:id])
respond_to do |format|
if step
protocol = step.protocol
if can_manage_protocol_in_module?(protocol) ||
can_manage_protocol_in_repository?(protocol)
if step.position < step.protocol.steps.count - 1
step_up = step.protocol.steps.where(position: step.position + 1).first
step.position += 1
step.save
if @step.position < @step.protocol.steps.count - 1
step_up = @step.protocol.steps.find_by(position: @step.position + 1)
@step.position += 1
@step.save
if step_up
step_up.position -= 1
step_up.save
if step_up
step_up.position -= 1
step_up.save
# Update protocol timestamp
update_protocol_ts(step)
# Update protocol timestamp
update_protocol_ts(@step)
format.json {
render json: { move_direction: "down", step_up_position: step_up.position, step_down_position: step.position },
status: :ok
}
else
format.json {
render json: {}, status: :forbidden
}
end
else
format.json {
render json: {}, status: :forbidden
}
format.json do
render json: { move_direction: 'down',
step_up_position: step_up.position,
step_down_position: @step.position }
end
else
format.json {
render json: {}, status: :forbidden
}
format.json { render json: {}, status: :forbidden }
end
else
format.json {
render json: {}, status: :not_found
}
format.json { render json: {}, status: :forbidden }
end
end
end
@ -545,31 +507,20 @@ class StepsController < ApplicationController
end
def load_vars
@step = Step.find_by_id(params[:id])
@protocol = @step&.protocol
if params[:checklistitem_id]
@chk_item = ChecklistItem.find_by_id(params[:checklistitem_id])
end
@step = Step.find_by(id: params[:id])
return render_404 unless @step
unless @protocol
render_404
end
if @protocol.in_module?
@my_module = @protocol.my_module
end
@protocol = @step.protocol
@chk_item = ChecklistItem.find_by(id: params[:checklistitem_id]) if params[:checklistitem_id]
@my_module = @protocol.my_module if @protocol.in_module?
end
def load_vars_nested
@protocol = Protocol.find_by_id(params[:protocol_id])
@protocol = Protocol.find_by(id: params[:protocol_id])
unless @protocol
render_404
end
return render_404 unless @protocol
if @protocol.in_module?
@my_module = @protocol.my_module
end
@my_module = @protocol.my_module if @protocol.in_module?
end
def convert_table_contents_to_utf8
@ -589,13 +540,11 @@ class StepsController < ApplicationController
end
def check_view_permissions
render_403 unless can_read_protocol_in_module?(@protocol) ||
can_read_protocol_in_repository?(@protocol)
render_403 unless can_read_protocol_in_module?(@protocol) || can_read_protocol_in_repository?(@protocol)
end
def check_manage_permissions
render_403 unless can_manage_protocol_in_module?(@protocol) ||
can_manage_protocol_in_repository?(@protocol)
render_403 unless can_manage_protocol_in_module?(@protocol) || can_manage_protocol_in_repository?(@protocol)
end
def check_complete_and_checkbox_permissions

View file

@ -5,6 +5,7 @@ class ChecklistItem < ApplicationRecord
length: { maximum: Constants::TEXT_MAX_LENGTH }
validates :checklist, presence: true
validates :checked, inclusion: { in: [true, false] }
validates :position, uniqueness: { scope: :checklist }
belongs_to :checklist,
inverse_of: :checklist_items

View file

@ -7,6 +7,7 @@ class MyModule < ApplicationRecord
enum state: Extends::TASKS_STATES
before_create :create_blank_protocol
before_save -> { self.completed_on = completed? ? DateTime.now : nil }, if: :state_changed?
auto_strip_attributes :name, :description, nullify: false
validates :name,
@ -506,10 +507,6 @@ class MyModule < ApplicationRecord
{ x: 0, y: positions.last[1] + HEIGHT }
end
def completed?
state == 'completed'
end
# Check if my_module is ready to become completed
def check_completness_status
if protocol && protocol.steps.count > 0
@ -522,16 +519,6 @@ class MyModule < ApplicationRecord
false
end
def complete
self.state = 'completed'
self.completed_on = DateTime.now
end
def uncomplete
self.state = 'uncompleted'
self.completed_on = nil
end
def assign_user(user, assigned_by = nil)
user_my_modules.create(
assigned_by: assigned_by || user,

View file

@ -525,7 +525,7 @@ class Protocol < ApplicationRecord
def update_parent(current_user)
# First, destroy parent's step contents
parent.destroy_contents(current_user)
parent.destroy_contents
parent.reload
# Now, clone step contents
@ -543,7 +543,7 @@ class Protocol < ApplicationRecord
def update_from_parent(current_user)
# First, destroy step contents
destroy_contents(current_user)
destroy_contents
# Now, clone parent's step contents
Protocol.clone_contents(parent, self, current_user, false)
@ -559,7 +559,7 @@ class Protocol < ApplicationRecord
def load_from_repository(source, current_user)
# First, destroy step contents
destroy_contents(current_user)
destroy_contents
# Now, clone source's step contents
Protocol.clone_contents(source, self, current_user, false)
@ -656,12 +656,10 @@ class Protocol < ApplicationRecord
cloned
end
def destroy_contents(current_user)
def destroy_contents
# Calculate total space taken by the protocol
st = space_taken
steps.pluck(:id).each do |id|
raise ActiveRecord::RecordNotDestroyed unless Step.find(id).destroy(current_user)
end
steps.destroy_all
# Release space taken by the step
team.release_space(st)

View file

@ -14,6 +14,10 @@ class Step < ApplicationRecord
validates :user, :protocol, presence: true
validates :completed_on, presence: true, if: proc { |s| s.completed? }
before_destroy :cascade_before_destroy
before_destroy :adjust_positions_on_destroy
before_save :set_last_modified_by
belongs_to :user, inverse_of: :steps
belongs_to :last_modified_by, foreign_key: 'last_modified_by_id', class_name: 'User', optional: true
belongs_to :protocol, inverse_of: :steps
@ -37,9 +41,6 @@ class Step < ApplicationRecord
},
allow_destroy: true
after_destroy :cascade_after_destroy
before_save :set_last_modified_by
def self.search(user,
include_archived,
query = nil,
@ -76,17 +77,6 @@ class Step < ApplicationRecord
end
end
def destroy(current_user)
@current_user = current_user
# Store IDs of assets & tables so they
# can be destroyed in after_destroy
@a_ids = self.assets.collect { |a| a.id }
@t_ids = self.tables.collect { |t| t.id }
super()
end
def self.viewable_by_user(user, teams)
where(protocol: Protocol.viewable_by_user(user, teams))
end
@ -132,13 +122,17 @@ class Step < ApplicationRecord
end
end
protected
private
def cascade_after_destroy
# Assets already deleted by here
@a_ids = nil
Table.destroy(@t_ids)
@t_ids = nil
def adjust_positions_on_destroy
protocol.steps.where('position > ?', position).find_each do |step|
step.update(position: step.position - 1)
end
end
def cascade_before_destroy
assets.each(&:destroy)
tables.each(&:destroy)
end
def set_last_modified_by

View file

@ -19,7 +19,7 @@ class Table < ApplicationRecord
class_name: 'User',
optional: true
belongs_to :team, optional: true
has_one :step_table, inverse_of: :table
has_one :step_table, inverse_of: :table, dependent: :destroy
has_one :step, through: :step_table
has_one :result_table, inverse_of: :table

View file

@ -0,0 +1,10 @@
# frozen_string_literal: true
module Api
module V1
class ChecklistItemSerializer < ActiveModel::Serializer
type :checklist_items
attributes :id, :text, :checked, :position
end
end
end

View file

@ -0,0 +1,11 @@
# frozen_string_literal: true
module Api
module V1
class ChecklistSerializer < ActiveModel::Serializer
type :checklists
attributes :id, :name
has_many :checklist_items, serializer: ChecklistItemSerializer
end
end
end

View file

@ -3,14 +3,25 @@
module Api
module V1
class StepSerializer < ActiveModel::Serializer
include ApplicationHelper
include ActionView::Helpers::TextHelper
include InputSanitizeHelper
type :steps
attributes :id, :name, :description, :position, :completed
attribute :completed_on, if: :completed?
attribute :completed_on, if: -> { object.completed? }
belongs_to :protocol, serializer: ProtocolSerializer
has_many :assets, serializer: AssetSerializer
has_many :checklists, serializer: ChecklistSerializer
has_many :tables, serializer: TableSerializer
has_many :step_comments, key: :comments, serializer: CommentSerializer
def completed?
object.completed
def description
if instance_options[:rte_rendering]
custom_auto_link(object.tinymce_render(:description), simple_format: false, tags: %w(img))
else
object.description
end
end
end
end

View file

@ -0,0 +1,14 @@
# frozen_string_literal: true
module Api
module V1
class TableSerializer < ActiveModel::Serializer
type :tables
attributes :id, :name, :contents
def contents
object.contents&.force_encoding(Encoding::UTF_8)
end
end
end
end

View file

@ -19,6 +19,14 @@ module Api
def input_tasks
object.my_module_antecessors
end
def description
if instance_options[:rte_rendering]
custom_auto_link(object.tinymce_render(:description), simple_format: false, tags: %w(img))
else
object.description
end
end
end
end
end

View file

@ -29,7 +29,7 @@ module ProtocolsImporter
def import_into_existing(protocol, protocol_json, user, team)
# Firstly, destroy existing protocol's contents
protocol.tiny_mce_assets.destroy_all
protocol.destroy_contents(user)
protocol.destroy_contents
protocol.reload
# Alright, now populate the protocol

View file

@ -2339,6 +2339,12 @@ en:
record_not_found:
title: "Not found"
detail: "%{model} record with id %{id} not found in the specified scope"
not_implemented:
title: "Not implemented"
detail: "This endpoint is not implemented yet"
include_not_supported:
title: "Not supported"
detail: "Include param is not supported by this endpoint"
id_mismatch:
title: "Object ID mismatch"
detail: "Object ID mismatch in URL and request body"

View file

@ -706,7 +706,7 @@ Rails.application.routes.draw do
resources :experiments, only: %i(index show) do
resources :task_groups, only: %i(index show)
resources :connections, only: %i(index show)
resources :tasks, only: %i(index show create) do
resources :tasks, only: %i(index show create update) do
resources :task_inventory_items, only: %i(index show),
path: 'items',
as: :items
@ -717,8 +717,12 @@ Rails.application.routes.draw do
path: 'tags',
as: :tags
resources :protocols, only: %i(index) do
resources :steps, only: %i(index show create) do
resources :steps do
resources :assets, only: %i(index show create), path: 'attachments'
resources :checklists, path: 'checklists' do
resources :checklist_items, as: :items, path: 'items'
end
resources :tables, path: 'tables'
end
end
resources :results, only: %i(index create show update)

View file

@ -2,8 +2,8 @@
FactoryBot.define do
factory :asset do
file do
fixture_file_upload(Rails.root.join('spec', 'fixtures', 'files', 'test.jpg'), 'image/jpg')
after(:create) do |asset|
asset.file.attach(io: File.open(Rails.root.join('spec/fixtures/files/test.jpg')), filename: 'test.jpg')
end
end
end

View file

@ -0,0 +1,255 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Api::V1::ChecklistsController', type: :request do
before :all do
@user = create(:user)
@team = create(:team, created_by: @user)
@project = create(:project, team: @team)
@experiment = create(:experiment, :with_tasks, project: @project)
@task = @experiment.my_modules.first
@protocol = create(:protocol, my_module: @task)
@step = create(:step, protocol: @protocol)
@checklist = create(:checklist, step: @step)
create(:user_team, user: @user, team: @team)
create(:user_project, :normal_user, user: @user, project: @project)
@valid_headers = {
'Authorization': 'Bearer ' + generate_token(@user.id),
'Content-Type': 'application/json'
}
end
describe 'GET checklist_items, #index' do
context 'when has valid params' do
it 'renders 200' do
get api_v1_team_project_experiment_task_protocol_step_checklist_items_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
checklist_id: @checklist.id
), headers: @valid_headers
expect(response).to have_http_status(200)
end
end
context 'when checklist is not found' do
it 'renders 404' do
get api_v1_team_project_experiment_task_protocol_step_checklist_items_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
checklist_id: -1
), headers: @valid_headers
expect(response).to have_http_status(404)
end
end
end
describe 'GET checklist_item, #show' do
let(:checklist_item) { create(:checklist_item, checklist: @checklist) }
context 'when has valid params' do
it 'renders 200' do
get api_v1_team_project_experiment_task_protocol_step_checklist_item_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
checklist_id: @checklist.id,
id: checklist_item.id
), headers: @valid_headers
expect(response).to have_http_status(200)
end
end
context 'when experiment is archived and permission checks fails' do
it 'renders 403' do
@experiment.update_attribute(:archived, true)
get api_v1_team_project_experiment_task_protocol_step_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
checklist_id: @checklist.id,
id: checklist_item.id
), headers: @valid_headers
expect(response).to have_http_status(403)
end
end
end
describe 'POST checklist_item, #create' do
let(:action) do
post(api_v1_team_project_experiment_task_protocol_step_checklist_items_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
checklist_id: @checklist.id
), params: request_body.to_json, headers: @valid_headers)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'checklist_items',
attributes: {
text: 'New checklist_item'
}
}
}
end
it 'creates new checklist_item' do
expect { action }.to change { ChecklistItem.count }.by(1)
end
it 'returns status 201' do
action
expect(response).to have_http_status 201
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'checklist_items',
attributes: hash_including(text: 'New checklist_item')
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'checklist_items',
attributes: {
}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
end
describe 'PATCH checklist_item, #update' do
let(:checklist_item) { create(:checklist_item, checklist: @checklist) }
let(:action) do
patch(api_v1_team_project_experiment_task_protocol_step_checklist_item_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
checklist_id: @checklist.id,
id: checklist_item.id
), params: request_body.to_json, headers: @valid_headers)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'checklist_items',
attributes: {
text: 'New checklist_item name'
}
}
}
end
it 'returns status 200' do
action
expect(response).to have_http_status 200
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'checklist_items',
attributes: hash_including(
text: 'New checklist_item name'
)
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'checklist_items',
attributes: {
}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
end
describe 'DELETE checklist_item, #destroy' do
let(:checklist_item) { create(:checklist_item, checklist: @checklist) }
let(:action) do
delete(api_v1_team_project_experiment_task_protocol_step_checklist_item_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
checklist_id: @checklist.id,
id: checklist_item.id
), headers: @valid_headers)
end
it 'deletes checklist_item' do
action
expect(response).to have_http_status(200)
expect(ChecklistItem.where(id: checklist_item.id)).to_not exist
end
end
end

View file

@ -0,0 +1,247 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Api::V1::ChecklistsController', type: :request do
before :all do
@user = create(:user)
@team = create(:team, created_by: @user)
@project = create(:project, team: @team)
@experiment = create(:experiment, :with_tasks, project: @project)
@task = @experiment.my_modules.first
@protocol = create(:protocol, my_module: @task)
@step = create(:step, protocol: @protocol)
create(:user_team, user: @user, team: @team)
create(:user_project, :normal_user, user: @user, project: @project)
@valid_headers = {
'Authorization': 'Bearer ' + generate_token(@user.id),
'Content-Type': 'application/json'
}
end
describe 'GET checklists, #index' do
context 'when has valid params' do
it 'renders 200' do
get api_v1_team_project_experiment_task_protocol_step_checklists_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id
), headers: @valid_headers
expect(response).to have_http_status(200)
end
end
context 'when step is not found' do
it 'renders 404' do
get api_v1_team_project_experiment_task_protocol_step_checklists_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: -1
), headers: @valid_headers
expect(response).to have_http_status(404)
end
end
end
describe 'GET checklist, #show' do
let(:checklist) { create(:checklist, step: @step) }
context 'when has valid params' do
it 'renders 200' do
get api_v1_team_project_experiment_task_protocol_step_checklist_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
id: checklist.id
), headers: @valid_headers
expect(response).to have_http_status(200)
end
end
context 'when experiment is archived and permission checks fails' do
it 'renders 403' do
@experiment.update_attribute(:archived, true)
get api_v1_team_project_experiment_task_protocol_step_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
id: checklist.id
), headers: @valid_headers
expect(response).to have_http_status(403)
end
end
end
describe 'POST checklist, #create' do
let(:action) do
post(api_v1_team_project_experiment_task_protocol_step_checklists_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id
), params: request_body.to_json, headers: @valid_headers)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'checklists',
attributes: {
name: 'New checklist'
}
}
}
end
it 'creates new checklist' do
expect { action }.to change { Checklist.count }.by(1)
end
it 'returns status 201' do
action
expect(response).to have_http_status 201
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'checklists',
attributes: hash_including(name: 'New checklist')
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'checklists',
attributes: {
}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
end
describe 'PATCH checklist, #update' do
let(:checklist) { create(:checklist, step: @step) }
let(:action) do
patch(api_v1_team_project_experiment_task_protocol_step_checklist_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
id: checklist.id
), params: request_body.to_json, headers: @valid_headers)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'checklists',
attributes: {
name: 'New checklist name'
}
}
}
end
it 'returns status 200' do
action
expect(response).to have_http_status 200
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'checklists',
attributes: hash_including(
name: 'New checklist name'
)
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'checklists',
attributes: {
}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
end
describe 'DELETE checklist, #destroy' do
let(:checklist) { create(:checklist, step: @step) }
let(:action) do
delete(api_v1_team_project_experiment_task_protocol_step_checklist_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
id: checklist.id
), headers: @valid_headers)
end
it 'deletes checklist' do
action
expect(response).to have_http_status(200)
expect(Checklist.where(id: checklist.id)).to_not exist
end
end
end

View file

@ -481,10 +481,10 @@ RSpec.describe 'Api::V1::ResultsController', type: :request do
), params: @valid_text_hash_body.to_json, headers: @valid_headers)
end
it 'returns status 500' do
it 'returns status 400' do
action
expect(response).to have_http_status 500
expect(response).to have_http_status 400
end
end
end

View file

@ -18,6 +18,7 @@ RSpec.describe 'Api::V1::StepsController', type: :request do
let(:protocol) { create :protocol, my_module: @task }
let(:steps) { create_list(:step, 3, protocol: protocol) }
let(:step) { steps.first }
describe 'GET steps, #index' do
context 'when has valid params' do
@ -34,6 +35,20 @@ RSpec.describe 'Api::V1::StepsController', type: :request do
end
end
context 'when has valid params, with rendered RTE field' do
it 'renders 200' do
get api_v1_team_project_experiment_task_protocol_steps_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: protocol.id
), params: { render_rte: true }, headers: @valid_headers
expect(response).to have_http_status(200)
end
end
context 'when protocol is not found' do
it 'renders 404' do
get api_v1_team_project_experiment_task_protocol_steps_path(
@ -155,4 +170,102 @@ RSpec.describe 'Api::V1::StepsController', type: :request do
end
end
end
describe 'PATCH step, #update' do
before :all do
@valid_headers['Content-Type'] = 'application/json'
end
let(:action) do
patch(
api_v1_team_project_experiment_task_protocol_step_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: protocol.id,
id: step.id
),
params: request_body.to_json,
headers: @valid_headers
)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'steps',
attributes: {
name: 'New step name',
description: 'New description about step'
}
}
}
end
it 'returns status 200' do
action
expect(response).to have_http_status 200
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'steps',
attributes: hash_including(name: 'New step name', description: 'New description about step')
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'steps',
attributes: {
}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
end
describe 'DELETE step, #destroy' do
before :all do
@valid_headers['Content-Type'] = 'application/json'
end
let(:action) do
delete(
api_v1_team_project_experiment_task_protocol_step_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: protocol.id,
id: step.id
),
headers: @valid_headers
)
end
it 'deletes step' do
action
expect(response).to have_http_status(200)
expect(Step.where(id: step.id)).to_not exist
end
end
end

View file

@ -0,0 +1,250 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Api::V1::TablesController', type: :request do
before :all do
@user = create(:user)
@team = create(:team, created_by: @user)
@project = create(:project, team: @team)
@experiment = create(:experiment, :with_tasks, project: @project)
@task = @experiment.my_modules.first
@protocol = create(:protocol, my_module: @task)
@step = create(:step, protocol: @protocol)
create(:user_team, user: @user, team: @team)
create(:user_project, :normal_user, user: @user, project: @project)
@valid_headers = {
'Authorization': 'Bearer ' + generate_token(@user.id),
'Content-Type': 'application/json'
}
end
describe 'GET tables, #index' do
context 'when has valid params' do
it 'renders 200' do
get api_v1_team_project_experiment_task_protocol_step_tables_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id
), headers: @valid_headers
expect(response).to have_http_status(200)
end
end
context 'when step is not found' do
it 'renders 404' do
get api_v1_team_project_experiment_task_protocol_step_tables_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: -1
), headers: @valid_headers
expect(response).to have_http_status(404)
end
end
end
describe 'GET table, #show' do
let(:table) { create(:table, step: @step) }
context 'when has valid params' do
it 'renders 200' do
get api_v1_team_project_experiment_task_protocol_step_table_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
id: table.id
), headers: @valid_headers
expect(response).to have_http_status(200)
end
end
context 'when experiment is archived and permission checks fails' do
it 'renders 403' do
@experiment.update_attribute(:archived, true)
get api_v1_team_project_experiment_task_protocol_step_table_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
id: table.id
), headers: @valid_headers
expect(response).to have_http_status(403)
end
end
end
describe 'POST table, #create' do
let(:action) do
post(api_v1_team_project_experiment_task_protocol_step_tables_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id
), params: request_body.to_json, headers: @valid_headers)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'tables',
attributes: {
name: 'New table',
contents: '{"data": [["group/time", "1 dpi", "6 dpi", "", ""], ["PVYNTN", "1", "1", "", ""]]}'
}
}
}
end
it 'creates new table' do
expect { action }.to change { Table.count }.by(1)
end
it 'returns status 201' do
action
expect(response).to have_http_status 201
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'tables',
attributes: hash_including(name: 'New table')
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'tables',
attributes: {
}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
end
describe 'PATCH table, #update' do
let(:table) { create(:table, step: @step) }
let(:action) do
patch(api_v1_team_project_experiment_task_protocol_step_table_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
id: table.id
), params: request_body.to_json, headers: @valid_headers)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'tables',
attributes: {
name: 'New table name',
contents: '{"data": [["group/time", "2 dpi", "7 dpi", "", ""], ["PVYNTN", "2", "2", "", ""]]}'
}
}
}
end
it 'returns status 200' do
action
expect(response).to have_http_status 200
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'tables',
attributes: hash_including(
name: 'New table name',
contents: '{"data": [["group/time", "2 dpi", "7 dpi", "", ""], ["PVYNTN", "2", "2", "", ""]]}'
)
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'tables',
attributes: {
}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
end
describe 'DELETE table, #destroy' do
let(:table) { create(:table, step: @step) }
let(:action) do
delete(api_v1_team_project_experiment_task_protocol_step_table_path(
team_id: @team.id,
project_id: @project.id,
experiment_id: @experiment.id,
task_id: @task.id,
protocol_id: @protocol.id,
step_id: @step.id,
id: table.id
), headers: @valid_headers)
end
it 'deletes table' do
action
expect(response).to have_http_status(200)
expect(Table.where(id: table.id)).to_not exist
end
end
end

View file

@ -236,4 +236,108 @@ RSpec.describe 'Api::V1::TasksController', type: :request do
end
end
end
describe 'PATCH task, #update' do
before :all do
@valid_headers['Content-Type'] = 'application/json'
end
let(:task) { @valid_experiment.my_modules.take }
let(:action) do
patch(
api_v1_team_project_experiment_task_path(
team_id: @valid_project.team.id,
project_id: @valid_project.id,
experiment_id: @valid_experiment.id,
id: task.id
),
params: request_body.to_json,
headers: @valid_headers
)
end
context 'when has valid params' do
let(:request_body) do
{
data: {
type: 'tasks',
attributes: {
name: 'New task name',
description: 'New description about task'
}
}
}
end
it 'returns status 200' do
action
expect(response).to have_http_status 200
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'tasks',
attributes: hash_including(name: 'New task name', description: 'New description about task')
)
)
)
end
end
context 'task completion, when has valid params' do
let(:request_body) do
{
data: {
type: 'tasks',
attributes: {
state: 'completed'
}
}
}
end
it 'returns status 200' do
action
expect(response).to have_http_status 200
end
it 'returns well formated response' do
action
expect(json).to match(
hash_including(
data: hash_including(
type: 'tasks',
attributes: hash_including(state: 'completed')
)
)
)
end
end
context 'when has missing param' do
let(:request_body) do
{
data: {
type: 'tasks',
attributes: {
}
}
}
end
it 'renders 400' do
action
expect(response).to have_http_status(400)
end
end
end
end