mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-09-20 06:35:56 +08:00
Implement api v2 for results [SCI-9651] (#6699)
This commit is contained in:
parent
2baeabc752
commit
a343701299
|
@ -88,9 +88,13 @@ module Api
|
|||
metadata_cells = metadata[:cells]
|
||||
data = contents['data']
|
||||
|
||||
if data.present? && data[0].present? && (data.size * data[0].size) < metadata_cells.size
|
||||
error_message = I18n.t('api.core.errors.table.metadata.detail_too_many_cells')
|
||||
raise ActionController::BadRequest, error_message
|
||||
if data.present? && data[0].present?
|
||||
data_size = (data[0].is_a?(Array) ? data.size * data[0].size : data.size)
|
||||
|
||||
if data_size < metadata_cells.size
|
||||
error_message = I18n.t('api.core.errors.table.metadata.detail_too_many_cells')
|
||||
raise ActionController::BadRequest, error_message
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
25
app/controllers/api/v2/base_controller.rb
Normal file
25
app/controllers/api/v2/base_controller.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class BaseController < Api::V1::BaseController
|
||||
private
|
||||
|
||||
def load_result(key = :result_id)
|
||||
@result = @task.results.find(params.require(key))
|
||||
|
||||
raise PermissionError.new(Result, :read) unless can_read_result?(@result)
|
||||
end
|
||||
|
||||
def load_result_text(key = :result_text_id)
|
||||
@result_text = @result.result_texts.find(params.require(key))
|
||||
raise PermissionError.new(Result, :read) unless can_read_result?(@result)
|
||||
end
|
||||
|
||||
def load_result_table(key = :table_id)
|
||||
@table = @result.tables.find(params.require(key))
|
||||
raise PermissionError.new(Result, :read) unless can_read_result?(@result)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
74
app/controllers/api/v2/result_assets_controller.rb
Normal file
74
app/controllers/api/v2/result_assets_controller.rb
Normal file
|
@ -0,0 +1,74 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class ResultAssetsController < BaseController
|
||||
before_action :load_team, :load_project, :load_experiment, :load_task, :load_result
|
||||
before_action :check_manage_permission, only: %i(create destroy)
|
||||
before_action :load_asset, only: %i(show destroy)
|
||||
before_action :check_upload_type, only: :create
|
||||
|
||||
def index
|
||||
result_assets =
|
||||
timestamps_filter(@result.result_assets).page(params.dig(:page, :number))
|
||||
.per(params.dig(:page, :size))
|
||||
|
||||
render jsonapi: result_assets, each_serializer: ResultAssetSerializer
|
||||
end
|
||||
|
||||
def show
|
||||
render jsonapi: @asset.result_asset, serializer: ResultAssetSerializer
|
||||
end
|
||||
|
||||
def create
|
||||
asset = if @form_multipart_upload
|
||||
@result.assets.new(asset_params.merge({ team_id: @team.id }))
|
||||
else
|
||||
blob = ActiveStorage::Blob.create_and_upload!(
|
||||
io: StringIO.new(Base64.decode64(asset_params[:file_data])),
|
||||
filename: asset_params[:file_name],
|
||||
content_type: asset_params[:file_type]
|
||||
)
|
||||
@result.assets.new(file: blob, team: @team)
|
||||
end
|
||||
|
||||
asset.save!(context: :on_api_upload)
|
||||
asset.post_process_file
|
||||
|
||||
render jsonapi: asset.result_asset,
|
||||
serializer: ResultAssetSerializer,
|
||||
status: :created
|
||||
end
|
||||
|
||||
def destroy
|
||||
@asset.destroy!
|
||||
render body: nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def asset_params
|
||||
raise TypeError unless params.require(:data).require(:type) == 'attachments'
|
||||
|
||||
return params.require(:data).require(:attributes).permit(:file) if @form_multipart_upload
|
||||
|
||||
attr_list = %i(file_data file_type file_name)
|
||||
params.require(:data).require(:attributes).require(attr_list)
|
||||
params.require(:data).require(:attributes).permit(attr_list)
|
||||
end
|
||||
|
||||
def load_asset
|
||||
@asset = @result.assets.find(params.require(:id))
|
||||
raise PermissionError.new(Result, :read) unless can_read_result?(@result)
|
||||
end
|
||||
|
||||
def check_upload_type
|
||||
@form_multipart_upload = true if params.dig(:data, :attributes, :file)
|
||||
end
|
||||
|
||||
def check_manage_permission
|
||||
raise PermissionError.new(Result, :manage) unless can_manage_result?(@result)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
102
app/controllers/api/v2/result_tables_controller.rb
Normal file
102
app/controllers/api/v2/result_tables_controller.rb
Normal file
|
@ -0,0 +1,102 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class ResultTablesController < BaseController
|
||||
before_action :load_team, :load_project, :load_experiment, :load_task, :load_result
|
||||
before_action only: %i(show update destroy) do
|
||||
load_result_table(:id)
|
||||
end
|
||||
before_action :check_manage_permission, only: %i(create update destroy)
|
||||
|
||||
def index
|
||||
result_tables = timestamps_filter(@result.result_tables).page(params.dig(:page, :number))
|
||||
.per(params.dig(:page, :size))
|
||||
|
||||
render jsonapi: result_tables, each_serializer: ResultTableSerializer
|
||||
end
|
||||
|
||||
def show
|
||||
render jsonapi: @table.result_table, serializer: ResultTableSerializer
|
||||
end
|
||||
|
||||
def create
|
||||
table = @result.tables.new(table_params.merge!(team: @team, created_by: current_user))
|
||||
|
||||
@result.with_lock do
|
||||
@result.result_orderable_elements.create!(
|
||||
position: @result.result_orderable_elements.size,
|
||||
orderable: table.result_table
|
||||
)
|
||||
|
||||
table.save!
|
||||
end
|
||||
|
||||
render jsonapi: table.result_table, serializer: ResultTableSerializer, status: :created
|
||||
end
|
||||
|
||||
def update
|
||||
@table.assign_attributes(table_params)
|
||||
|
||||
if @table.changed? && @table.save!
|
||||
render jsonapi: @table.result_table, serializer: ResultTableSerializer
|
||||
else
|
||||
render body: nil, status: :no_content
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@table.destroy!
|
||||
render body: nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_manage_permission
|
||||
raise PermissionError.new(Result, :manage) unless can_manage_result?(@result)
|
||||
end
|
||||
|
||||
def convert_plate_template(metadata_params)
|
||||
if metadata_params.present? && metadata_params['plateTemplate']
|
||||
metadata_params['plateTemplate'] = ActiveRecord::Type::Boolean.new.cast(metadata_params['plateTemplate'])
|
||||
end
|
||||
end
|
||||
|
||||
def table_params
|
||||
raise TypeError unless params.require(:data).require(:type) == 'tables'
|
||||
|
||||
attributes_params = params.require(:data).require(:attributes).permit(
|
||||
:name,
|
||||
:contents,
|
||||
metadata: [
|
||||
:plateTemplate,
|
||||
{ cells: %i(col row className) }
|
||||
]
|
||||
)
|
||||
|
||||
convert_plate_template(attributes_params[:metadata])
|
||||
validate_metadata_params(attributes_params)
|
||||
attributes_params
|
||||
end
|
||||
|
||||
def validate_metadata_params(attributes_params)
|
||||
metadata = attributes_params[:metadata]
|
||||
contents = JSON.parse(attributes_params[:contents] || '{}')
|
||||
|
||||
if metadata.present? && metadata[:cells].present? && contents.present?
|
||||
metadata_cells = metadata[:cells]
|
||||
data = contents['data']
|
||||
|
||||
if data.present? && data[0].present?
|
||||
data_size = (data[0].is_a?(Array) ? data.size * data[0].size : data.size)
|
||||
|
||||
if data_size < metadata_cells.size
|
||||
error_message = I18n.t('api.core.errors.table.metadata.detail_too_many_cells')
|
||||
raise ActionController::BadRequest, error_message
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
66
app/controllers/api/v2/result_texts_controller.rb
Normal file
66
app/controllers/api/v2/result_texts_controller.rb
Normal file
|
@ -0,0 +1,66 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class ResultTextsController < BaseController
|
||||
before_action :load_team, :load_project, :load_experiment, :load_task, :load_result
|
||||
before_action only: %i(show update destroy) do
|
||||
load_result_text(:id)
|
||||
end
|
||||
before_action :check_manage_permission, only: %i(create update destroy)
|
||||
|
||||
def index
|
||||
result_texts = timestamps_filter(@result.result_texts).page(params.dig(:page, :number))
|
||||
.per(params.dig(:page, :size))
|
||||
|
||||
render jsonapi: result_texts, each_serializer: ResultTextSerializer
|
||||
end
|
||||
|
||||
def show
|
||||
render jsonapi: @result_text, serializer: ResultTextSerializer
|
||||
end
|
||||
|
||||
def create
|
||||
result_text = @result.result_texts.new(result_text_params)
|
||||
|
||||
@result.with_lock do
|
||||
@result.result_orderable_elements.create!(
|
||||
position: @result.result_orderable_elements.size,
|
||||
orderable: result_text
|
||||
)
|
||||
|
||||
result_text.save!
|
||||
end
|
||||
|
||||
render jsonapi: result_text, serializer: ResultTextSerializer, status: :created
|
||||
end
|
||||
|
||||
def update
|
||||
@result_text.assign_attributes(result_text_params)
|
||||
|
||||
if @result_text.changed? && @result_text.save!
|
||||
render jsonapi: @result_text, serializer: ResultTextSerializer, status: :ok
|
||||
else
|
||||
render body: nil, status: :no_content
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@result_text.destroy!
|
||||
render body: nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_manage_permission
|
||||
raise PermissionError.new(Result, :manage) unless can_manage_result?(@result)
|
||||
end
|
||||
|
||||
def result_text_params
|
||||
raise TypeError unless params.require(:data).require(:type) == 'result_texts'
|
||||
|
||||
params.require(:data).require(:attributes).permit(:text, :name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
76
app/controllers/api/v2/results_controller.rb
Normal file
76
app/controllers/api/v2/results_controller.rb
Normal file
|
@ -0,0 +1,76 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class ResultsController < BaseController
|
||||
before_action :load_team, :load_project, :load_experiment, :load_task
|
||||
before_action only: %i(show update destroy) do
|
||||
load_result(:id)
|
||||
end
|
||||
before_action :check_create_permissions, only: :create
|
||||
before_action :check_delete_permissions, only: :destroy
|
||||
before_action :check_update_permissions, only: :update
|
||||
|
||||
def index
|
||||
results = timestamps_filter(@task.results).page(params.dig(:page, :number))
|
||||
.per(params.dig(:page, :size))
|
||||
render jsonapi: results, each_serializer: ResultSerializer,
|
||||
include: include_params
|
||||
end
|
||||
|
||||
def show
|
||||
render jsonapi: @result, serializer: ResultSerializer,
|
||||
include: include_params
|
||||
end
|
||||
|
||||
def create
|
||||
@result = Result.create!(
|
||||
user: current_user,
|
||||
my_module: @task,
|
||||
name: result_params[:name]
|
||||
)
|
||||
render jsonapi: @result, serializer: ResultSerializer
|
||||
end
|
||||
|
||||
def update
|
||||
@result.assign_attributes(result_params)
|
||||
|
||||
if @result.changed? && @result.save!
|
||||
render jsonapi: @result, serializer: ResultSerializer
|
||||
else
|
||||
render body: nil, status: :no_content
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@result.destroy!
|
||||
render body: nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_create_permissions
|
||||
raise PermissionError.new(MyModule, :manage) unless can_manage_my_module?(@task)
|
||||
end
|
||||
|
||||
def check_delete_permissions
|
||||
raise PermissionError.new(Result, :delete) unless can_delete_result?(@result)
|
||||
end
|
||||
|
||||
def check_update_permissions
|
||||
raise PermissionError.new(Result, :manage) unless can_manage_result?(@result)
|
||||
end
|
||||
|
||||
def permitted_includes
|
||||
%w(comments result_texts tables assets)
|
||||
end
|
||||
|
||||
def result_params
|
||||
raise TypeError unless params.require(:data).require(:type) == 'results'
|
||||
|
||||
params.require(:data).require(:attributes).require(:name)
|
||||
params.require(:data).permit(attributes: %i(name archived))[:attributes]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
32
app/serializers/api/v2/result_asset_serializer.rb
Normal file
32
app/serializers/api/v2/result_asset_serializer.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class ResultAssetSerializer < ActiveModel::Serializer
|
||||
type :assets
|
||||
attributes :file_id, :file_name, :file_size, :file_type, :file_url
|
||||
|
||||
def file_id
|
||||
object.asset&.id
|
||||
end
|
||||
|
||||
def file_name
|
||||
object.asset&.file_name
|
||||
end
|
||||
|
||||
def file_size
|
||||
object.asset&.file_size
|
||||
end
|
||||
|
||||
def file_type
|
||||
object.asset&.content_type
|
||||
end
|
||||
|
||||
def file_url
|
||||
if object.asset&.file&.attached?
|
||||
Rails.application.routes.url_helpers.rails_blob_path(object.asset.file, disposition: 'attachment')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class ResultOrderableElementSerializer < ActiveModel::Serializer
|
||||
attributes :id, :position, :orderable, :orderable_type
|
||||
|
||||
def orderable
|
||||
case object.orderable_type
|
||||
when 'ResultTable'
|
||||
ResultTableSerializer.new(object.orderable, scope: { user: @instance_options[:user] }).as_json
|
||||
when 'ResultText'
|
||||
ResultTextSerializer.new(object.orderable, scope: { user: @instance_options[:user] }).as_json
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
19
app/serializers/api/v2/result_serializer.rb
Normal file
19
app/serializers/api/v2/result_serializer.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class ResultSerializer < ActiveModel::Serializer
|
||||
type :results
|
||||
attributes :name, :archived
|
||||
belongs_to :user, serializer: Api::V1::UserSerializer
|
||||
|
||||
has_many :result_comments, key: :comments, serializer: Api::V1::CommentSerializer
|
||||
has_many :result_texts, key: :result_texts, serializer: ResultTextSerializer
|
||||
has_many :result_tables, key: :tables, serializer: ResultTableSerializer
|
||||
has_many :result_assets, key: :assets, serializer: ResultAssetSerializer
|
||||
has_many :result_orderable_elements, key: :result_elements, serializer: ResultOrderableElementSerializer
|
||||
|
||||
include TimestampableModel
|
||||
end
|
||||
end
|
||||
end
|
22
app/serializers/api/v2/result_table_serializer.rb
Normal file
22
app/serializers/api/v2/result_table_serializer.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class ResultTableSerializer < ActiveModel::Serializer
|
||||
type :tables
|
||||
attributes :table_id, :table_contents, :table_metadata
|
||||
|
||||
def table_id
|
||||
object.table&.id
|
||||
end
|
||||
|
||||
def table_contents
|
||||
object.table&.contents&.force_encoding(Encoding::UTF_8)
|
||||
end
|
||||
|
||||
def table_metadata
|
||||
object.table&.metadata
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
14
app/serializers/api/v2/result_text_serializer.rb
Normal file
14
app/serializers/api/v2/result_text_serializer.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class ResultTextSerializer < ActiveModel::Serializer
|
||||
type :result_texts
|
||||
attributes :name, :text
|
||||
|
||||
def text
|
||||
object.tinymce_render('text')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -10,4 +10,6 @@ Rails.application.configure do
|
|||
config.x.core_api_rate_limit = ENV['CORE_API_RATE_LIMIT'] ? ENV['CORE_API_RATE_LIMIT'].to_i : 1000
|
||||
|
||||
config.x.core_api_v1_enabled = ENV['CORE_API_V1_ENABLED'] || false
|
||||
|
||||
config.x.core_api_v2_enabled = ENV['CORE_API_V2_ENABLED'] || false
|
||||
end
|
||||
|
|
|
@ -7,10 +7,6 @@ Rails.application.routes.draw do
|
|||
|
||||
# Addons
|
||||
|
||||
def draw(routes_name)
|
||||
instance_eval(File.read(Rails.root.join("config/routes/#{routes_name}.rb")))
|
||||
end
|
||||
|
||||
constraints UserSubdomain do
|
||||
devise_for :users, controllers: { registrations: 'users/registrations',
|
||||
sessions: 'users/sessions',
|
||||
|
@ -953,6 +949,8 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
draw(:api_v2) if Rails.configuration.x.core_api_v2_enabled
|
||||
end
|
||||
end
|
||||
|
||||
|
|
120
config/routes/api_v2.rb
Normal file
120
config/routes/api_v2.rb
Normal file
|
@ -0,0 +1,120 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop:disable Metrics/BlockLength
|
||||
|
||||
namespace :v2, module: 'v1' do
|
||||
resources :teams, only: %i(index show) do
|
||||
resources :inventories, only: %i(index create show update destroy) do
|
||||
resources :inventory_columns,
|
||||
only: %i(index create show update destroy),
|
||||
path: 'columns',
|
||||
as: :columns do
|
||||
resources :inventory_list_items,
|
||||
only: %i(index create show update destroy),
|
||||
path: 'list_items',
|
||||
as: :list_items
|
||||
resources :inventory_checklist_items,
|
||||
only: %i(index create show update destroy),
|
||||
path: 'checklist_items',
|
||||
as: :checklist_items
|
||||
resources :inventory_status_items,
|
||||
only: %i(index create show update destroy),
|
||||
path: 'status_items',
|
||||
as: :status_items
|
||||
resources :inventory_stock_unit_items,
|
||||
only: %i(index create show update destroy),
|
||||
path: 'stock_unit_items',
|
||||
as: :stock_unit_items
|
||||
end
|
||||
resources :inventory_items,
|
||||
only: %i(index create show update destroy),
|
||||
path: 'items',
|
||||
as: :items do
|
||||
resources :inventory_cells,
|
||||
only: %i(index create show update destroy),
|
||||
path: 'cells',
|
||||
as: :cells
|
||||
end
|
||||
end
|
||||
resources :projects, only: %i(index show create update) do
|
||||
resources :user_assignments,
|
||||
only: %i(index show create update destroy),
|
||||
controller: :project_user_assignments,
|
||||
path: 'users',
|
||||
as: :users
|
||||
resources :project_comments, only: %i(index show), path: 'comments', as: :comments
|
||||
get 'activities', to: 'projects#activities'
|
||||
resources :reports, only: %i(index show), path: 'reports', as: :reports
|
||||
resources :experiments, only: %i(index show create update) do
|
||||
resources :user_assignments,
|
||||
only: %i(index show update),
|
||||
controller: :experiment_user_assignments
|
||||
resources :task_groups, only: %i(index show)
|
||||
resources :connections, only: %i(index show create destroy)
|
||||
resources :tasks, only: %i(index show create update) do
|
||||
resources :user_assignments,
|
||||
only: %i(index show update),
|
||||
controller: :task_user_assignments
|
||||
resources :task_inventory_items, only: %i(index show update),
|
||||
path: 'items',
|
||||
as: :items
|
||||
resources :task_users, only: %i(index show),
|
||||
path: 'users',
|
||||
as: :users
|
||||
resources :task_tags, only: %i(index show),
|
||||
path: 'tags',
|
||||
as: :tags
|
||||
resources :task_assignments, only: %i(index create destroy),
|
||||
path: 'task_assignments',
|
||||
as: :task_assignments
|
||||
resources :protocols, only: %i(index show) do
|
||||
resources :steps, only: %i(index show create update destroy) do
|
||||
resources :assets, only: %i(index show create), path: 'attachments'
|
||||
resources :checklists, only: %i(index show create update destroy), path: 'checklists' do
|
||||
resources :checklist_items,
|
||||
only: %i(index show create update destroy),
|
||||
as: :items,
|
||||
path: 'items'
|
||||
end
|
||||
resources :tables, only: %i(index show create update destroy), path: 'tables'
|
||||
resources :step_texts, only: %i(index show create update destroy), path: 'step_texts'
|
||||
end
|
||||
end
|
||||
get 'activities', to: 'tasks#activities'
|
||||
end
|
||||
end
|
||||
end
|
||||
resources :project_folders, only: %i(index show create update)
|
||||
resources :users, only: %i(index)
|
||||
resources :protocol_templates, only: %i(index show)
|
||||
end
|
||||
resources :users, only: %i(show) do
|
||||
resources :user_identities,
|
||||
only: %i(index create show update destroy),
|
||||
path: 'identities',
|
||||
as: :identities
|
||||
end
|
||||
|
||||
resources :user_roles, only: :index
|
||||
resources :workflows, only: %i(index show) do
|
||||
resources :workflow_statuses, path: :statuses, only: %i(index)
|
||||
end
|
||||
end
|
||||
|
||||
namespace :v2 do
|
||||
resources :teams do
|
||||
resources :projects do
|
||||
resources :experiments do
|
||||
resources :tasks do
|
||||
resources :results, only: %i(index create show update destroy) do
|
||||
resources :result_assets, only: %i(index show create update destroy), path: 'assets'
|
||||
resources :result_tables, only: %i(index show create update destroy), path: 'tables'
|
||||
resources :result_texts, only: %i(index show create update destroy)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:enable Metrics/BlockLength
|
20
spec/factories/result_orderable_elements.rb
Normal file
20
spec/factories/result_orderable_elements.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :result_orderable_element do
|
||||
result
|
||||
sequence(:position) { |n| n }
|
||||
|
||||
trait :result_text do
|
||||
after(:build) do |result_orderable_element|
|
||||
result_orderable_element.orderable ||= build(:result_text, result: result_orderable_element.result)
|
||||
end
|
||||
end
|
||||
|
||||
trait :result_table do
|
||||
after(:build) do |result_orderable_element|
|
||||
result_orderable_element.orderable ||= build(:result_table, result: result_orderable_element.result)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
FactoryBot.define do
|
||||
factory :result_text do
|
||||
name { Faker::Name.unique.name }
|
||||
text { Faker::Lorem.paragraph }
|
||||
result
|
||||
end
|
||||
|
|
|
@ -4,6 +4,6 @@ FactoryBot.define do
|
|||
factory :step_orderable_element do
|
||||
orderable { create :step_text, step: step }
|
||||
step
|
||||
position { step ? step.step_orderable_elements.count : Faker::Number.between(from: 1, to: 10) }
|
||||
sequence(:position) { |n| n }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,6 +7,7 @@ require_relative 'support/controller_macros'
|
|||
ENV['RAILS_ENV'] = 'test'
|
||||
|
||||
ENV['CORE_API_V1_ENABLED'] = 'true'
|
||||
ENV['CORE_API_V2_ENABLED'] = 'true'
|
||||
|
||||
require File.expand_path('../../config/environment', __FILE__)
|
||||
# Prevent database truncation if the environment is production
|
||||
|
|
195
spec/requests/api/v2/result_assets_controller_spec.rb
Normal file
195
spec/requests/api/v2/result_assets_controller_spec.rb
Normal file
|
@ -0,0 +1,195 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop:disable Metrics/BlockLength
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api::V2::ResultAssetsController', type: :request do
|
||||
let(:user) { create(:user) }
|
||||
let(:team) { create(:team, created_by: user) }
|
||||
let(:project) { create(:project, team: team, created_by: user) }
|
||||
let(:experiment) { create(:experiment, :with_tasks, project: project, created_by: user) }
|
||||
let(:task) { experiment.my_modules.first }
|
||||
let(:result) { create(:result, user: user, my_module: task) }
|
||||
let(:result_archived) { create(:result, :archived, user: user, my_module: task) }
|
||||
let(:valid_headers) { { Authorization: "Bearer #{generate_token(user.id)}", 'Content-Type': 'application/json' } }
|
||||
|
||||
let(:api_path) do
|
||||
api_v2_team_project_experiment_task_result_result_assets_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result.id
|
||||
)
|
||||
end
|
||||
|
||||
describe 'GET result_assets, #index' do
|
||||
let(:result_asset) { create(:result_asset, result: result) }
|
||||
|
||||
context 'when has valid params' do
|
||||
it 'renders 200' do
|
||||
get api_path, headers: valid_headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
hash_body = nil
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match_array(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(result.result_assets, each_serializer: Api::V2::ResultAssetSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when result is not found' do
|
||||
it 'renders 404' do
|
||||
get api_v2_team_project_experiment_task_result_result_assets_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: -1
|
||||
), headers: valid_headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET result_asset, #show' do
|
||||
let(:result_asset) { create(:result_asset, result: result) }
|
||||
|
||||
context 'when has valid params' do
|
||||
it 'renders 200' do
|
||||
hash_body = nil
|
||||
get api_v2_team_project_experiment_task_result_result_asset_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result.id,
|
||||
id: result_asset.asset.id
|
||||
), headers: valid_headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(result_asset, serializer: Api::V2::ResultAssetSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST result_asset, #create' do
|
||||
let(:action) do
|
||||
post(api_path, params: request_body.to_json, headers: valid_headers)
|
||||
end
|
||||
|
||||
context 'when has valid params' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'attachments',
|
||||
attributes: {
|
||||
file_data: "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAE0lEQVQIHWP8//8/
|
||||
AwMDExADAQAkBgMBOOSShwAAAABJRU5ErkJggg=='\''",
|
||||
file_type: 'image/jpeg',
|
||||
file_name: 'test.jpg'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates new result_asset' do
|
||||
expect { action }.to change { ResultAsset.count }.by(1)
|
||||
end
|
||||
|
||||
it 'returns status 201' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
end
|
||||
|
||||
it 'returns well-formatted response' do
|
||||
hash_body = nil
|
||||
action
|
||||
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(ResultAsset.last, serializer: Api::V2::ResultAssetSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when has missing param' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'attachments',
|
||||
attributes: {}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'renders 400' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status(400)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE result_asset, #destroy' do
|
||||
let(:result_asset) { create(:result_asset, result: result) }
|
||||
let(:result_asset_archived) { create(:result_asset, result: result_archived) }
|
||||
|
||||
let(:action) do
|
||||
delete(api_v2_team_project_experiment_task_result_result_asset_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result.id,
|
||||
id: result_asset.asset.id
|
||||
), headers: valid_headers)
|
||||
end
|
||||
|
||||
let(:action_archived) do
|
||||
delete(api_v2_team_project_experiment_task_result_result_asset_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result_archived.id,
|
||||
id: result_asset_archived.asset.id
|
||||
), headers: valid_headers)
|
||||
end
|
||||
|
||||
it 'deletes result_asset' do
|
||||
action
|
||||
expect(response).to have_http_status(200)
|
||||
expect(ResultAsset.where(id: result_asset.id)).to_not exist
|
||||
expect(Asset.where(id: result_asset.asset.id)).to_not exist
|
||||
end
|
||||
|
||||
it 'does not delete result_asset of archived result' do
|
||||
action_archived
|
||||
expect(response).to have_http_status(403)
|
||||
expect(ResultAsset.where(id: result_asset_archived.id)).to exist
|
||||
expect(Asset.where(id: result_asset_archived.asset.id)).to exist
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:enable Metrics/BlockLength
|
289
spec/requests/api/v2/result_tables_controller_spec.rb
Normal file
289
spec/requests/api/v2/result_tables_controller_spec.rb
Normal file
|
@ -0,0 +1,289 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop:disable Metrics/BlockLength
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api::V2::ResultTablesController', type: :request do
|
||||
let(:user) { create(:user) }
|
||||
let(:team) { create(:team, created_by: user) }
|
||||
let(:project) { create(:project, team: team, created_by: user) }
|
||||
let(:experiment) { create(:experiment, :with_tasks, project: project, created_by: user) }
|
||||
let(:task) { experiment.my_modules.first }
|
||||
let(:result) { create(:result, user: user, my_module: task) }
|
||||
let(:result_archived) { create(:result, :archived, user: user, my_module: task) }
|
||||
let(:valid_headers) { { Authorization: "Bearer #{generate_token(user.id)}", 'Content-Type': 'application/json' } }
|
||||
|
||||
let(:api_path) do
|
||||
api_v2_team_project_experiment_task_result_result_tables_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result.id
|
||||
)
|
||||
end
|
||||
|
||||
describe 'GET result_tables, #index' do
|
||||
let!(:result_orderable_element) { create(:result_orderable_element, :result_table, result: result) }
|
||||
|
||||
context 'when has valid params' do
|
||||
it 'renders 200' do
|
||||
get api_path, headers: valid_headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
hash_body = nil
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match_array(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(result.result_tables, each_serializer: Api::V2::ResultTableSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when result is not found' do
|
||||
it 'renders 404' do
|
||||
get api_v2_team_project_experiment_task_result_result_tables_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: -1
|
||||
), headers: valid_headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET result_table, #show' do
|
||||
let(:result_table) { create(:result_table, result: result) }
|
||||
|
||||
context 'when has valid params' do
|
||||
it 'renders 200' do
|
||||
hash_body = nil
|
||||
get api_v2_team_project_experiment_task_result_result_table_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result.id,
|
||||
id: result_table.table.id
|
||||
), headers: valid_headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(result_table, serializer: Api::V2::ResultTableSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST result_table, #create' do
|
||||
let(:action) do
|
||||
post(api_path, params: request_body.to_json, headers: valid_headers)
|
||||
end
|
||||
|
||||
context 'when has valid params' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'tables',
|
||||
attributes: {
|
||||
name: 'Result table',
|
||||
contents: '{"data": [["group/time", "1 dpi", "6 dpi", "", ""], ["PVYNTN", "1", "1", "", ""]]}'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates new result_table' do
|
||||
expect { action }.to change { ResultTable.count }.by(1)
|
||||
end
|
||||
|
||||
it 'returns status 201' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status 201
|
||||
end
|
||||
|
||||
it 'returns well-formatted response' do
|
||||
hash_body = nil
|
||||
action
|
||||
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(ResultTable.last, serializer: Api::V2::ResultTableSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when has missing param' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'result_tables',
|
||||
attributes: {}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'renders 400' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status(400)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH result_table, #update' do
|
||||
let(:result_table) { create(:result_table, result: result) }
|
||||
let(:result_table_archived) { create(:result_table, result: result_archived) }
|
||||
let(:action) do
|
||||
patch(api_v2_team_project_experiment_task_result_result_table_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result.id,
|
||||
id: result_table.table.id
|
||||
), params: request_body.to_json, headers: valid_headers)
|
||||
end
|
||||
|
||||
let(:action_archived) do
|
||||
patch(api_v2_team_project_experiment_task_result_result_table_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result_archived.id,
|
||||
id: result_table_archived.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: 'Result table',
|
||||
contents: '{"data": [["group/time", "1 dpi", "6 dpi", "", ""], ["PVYNTN", "1", "1", "", ""]]}'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'returns status 200' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status 200
|
||||
end
|
||||
|
||||
it 'returns well-formatted response' do
|
||||
hash_body = nil
|
||||
action
|
||||
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(ResultTable.last, serializer: Api::V2::ResultTableSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when has missing param' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'result_tables',
|
||||
attributes: {}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'renders 400' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status(400)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when result is archived' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'result_tables',
|
||||
attributes: {
|
||||
name: 'Result table',
|
||||
contents: '{"data": [["group/time", "1 dpi", "6 dpi", "", ""], ["PVYNTN", "1", "1", "", ""]]}'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'renders 403' do
|
||||
action_archived
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE result_table, #destroy' do
|
||||
let(:result_table) { create(:result_table, result: result) }
|
||||
let(:result_table_archived) { create(:result_table, result: result_archived) }
|
||||
let(:delete_action) do
|
||||
delete(api_v2_team_project_experiment_task_result_result_table_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result.id,
|
||||
id: result_table.table.id
|
||||
), headers: valid_headers)
|
||||
end
|
||||
|
||||
let(:delete_action_archived) do
|
||||
delete(api_v2_team_project_experiment_task_result_result_table_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result_archived.id,
|
||||
id: result_table_archived.table.id
|
||||
), headers: valid_headers)
|
||||
end
|
||||
|
||||
it 'deletes result_table' do
|
||||
delete_action
|
||||
expect(response).to have_http_status(200)
|
||||
expect(ResultTable.where(id: result_table.id)).to_not exist
|
||||
expect(Table.where(id: result_table.table.id)).to_not exist
|
||||
end
|
||||
|
||||
it 'does not delete result_table of archived result' do
|
||||
delete_action_archived
|
||||
expect(response).to have_http_status(403)
|
||||
expect(ResultTable.where(id: result_table_archived.id)).to exist
|
||||
expect(Table.where(id: result_table_archived.table.id)).to exist
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:enable Metrics/BlockLength
|
373
spec/requests/api/v2/result_texts_controller_spec.rb
Normal file
373
spec/requests/api/v2/result_texts_controller_spec.rb
Normal file
|
@ -0,0 +1,373 @@
|
|||
# frozen_string_literal: true
|
||||
# rubocop:disable Metrics/BlockLength
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api::V2::ResultTextsController', type: :request do
|
||||
let(:user) { create(:user) }
|
||||
let(:team) { create(:team, created_by: user) }
|
||||
let(:project) { create(:project, team: team, created_by: user) }
|
||||
let(:experiment) { create(:experiment, :with_tasks, project: project, created_by: user) }
|
||||
let(:task) { experiment.my_modules.first }
|
||||
let(:result) { create(:result, user: user, my_module: task) }
|
||||
let(:result_archived) { create(:result, :archived, user: user, my_module: task) }
|
||||
let(:valid_headers) { { Authorization: "Bearer #{generate_token(user.id)}", 'Content-Type': 'application/json' } }
|
||||
|
||||
let(:api_path) do
|
||||
api_v2_team_project_experiment_task_result_result_texts_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result.id
|
||||
)
|
||||
end
|
||||
|
||||
describe 'GET result_texts, #index' do
|
||||
let!(:result_orderable_element) { create(:result_orderable_element, :result_text, result: result) }
|
||||
|
||||
context 'when has valid params' do
|
||||
it 'renders 200' do
|
||||
get api_path, headers: valid_headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
hash_body = nil
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match_array(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(result.result_texts, each_serializer: Api::V2::ResultTextSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when result is not found' do
|
||||
it 'renders 404' do
|
||||
get api_v2_team_project_experiment_task_result_result_texts_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: -1
|
||||
), headers: valid_headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET result_text, #show' do
|
||||
let(:result_text) { create(:result_text, result: result) }
|
||||
|
||||
context 'when has valid params' do
|
||||
it 'renders 200' do
|
||||
hash_body = nil
|
||||
get api_v2_team_project_experiment_task_result_result_text_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result.id,
|
||||
id: result_text.id
|
||||
), headers: valid_headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(result_text, serializer: Api::V2::ResultTextSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST result_text, #create' do
|
||||
let(:action) do
|
||||
post(api_path, params: request_body.to_json, headers: valid_headers)
|
||||
end
|
||||
|
||||
context 'when has valid params' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'result_texts',
|
||||
attributes: {
|
||||
name: 'Result text',
|
||||
text: '<p>Hello!</p>'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates new result_text' do
|
||||
expect { action }.to change { ResultText.count }.by(1)
|
||||
end
|
||||
|
||||
it 'returns status 201' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
end
|
||||
|
||||
it 'returns well-formatted response' do
|
||||
hash_body = nil
|
||||
action
|
||||
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(ResultText.last, serializer: Api::V2::ResultTextSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when has missing param' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'result_texts',
|
||||
attributes: {}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'renders 400' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status(400)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when include tinymce' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'result_texts',
|
||||
attributes: {
|
||||
name: 'Result text',
|
||||
text: "Result text 1 <img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAA" \
|
||||
"AACCAIAAAD91JpzAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAE0lE" \
|
||||
"QVQIHWP8//8/AwMDExADAQAkBgMBOOSShwAAAABJRU5ErkJggg=='\" data-mce-token=\"1\">"
|
||||
}
|
||||
},
|
||||
included: [
|
||||
{
|
||||
type: 'tiny_mce_assets',
|
||||
attributes: {
|
||||
file_data: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAA'\
|
||||
'AACCAIAAAD91JpzAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAE0lE'\
|
||||
'QVQIHWP8//8/AwMDExADAQAkBgMBOOSShwAAAABJRU5ErkJggg==',
|
||||
file_token: '1',
|
||||
file_name: 'test.png'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
it 'Response with correct text result and TinyMCE images' do
|
||||
hash_body = nil
|
||||
action
|
||||
|
||||
expect(response).to have_http_status 201
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(ResultText.last, serializer: Api::V2::ResultTextSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
expect(ResultText.last.text).to include "data-mce-token=\"#{Base62.encode(TinyMceAsset.last.id)}\""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH result_text, #update' do
|
||||
let(:result_text) { create(:result_text, result: result) }
|
||||
let(:result_text_archived) { create(:result_text, result: result_archived) }
|
||||
let(:action) do
|
||||
patch(api_v2_team_project_experiment_task_result_result_text_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result.id,
|
||||
id: result_text.id
|
||||
), params: request_body.to_json, headers: valid_headers)
|
||||
end
|
||||
let(:action_archived) do
|
||||
patch(api_v2_team_project_experiment_task_result_result_text_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result_archived.id,
|
||||
id: result_text_archived.id
|
||||
), params: request_body.to_json, headers: valid_headers)
|
||||
end
|
||||
|
||||
context 'when has valid params' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'result_texts',
|
||||
attributes: {
|
||||
name: 'Result text',
|
||||
text: '<h1>Hello!</h1>'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'returns status 200' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status 200
|
||||
end
|
||||
|
||||
it 'returns well-formatted response' do
|
||||
hash_body = nil
|
||||
action
|
||||
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(ResultText.last, serializer: Api::V2::ResultTextSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when has missing param' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'result_texts',
|
||||
attributes: {}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'renders 400' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status(400)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when result is archived' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'result_texts',
|
||||
attributes: {
|
||||
name: 'Result text',
|
||||
text: '<h1>Hello!</h1>'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'renders 403' do
|
||||
action_archived
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when include tinymce' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'result_texts',
|
||||
attributes: {
|
||||
name: 'Result text',
|
||||
text: 'Result text 1 <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAA'\
|
||||
'AACCAIAAAD91JpzAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAE0lE'\
|
||||
'QVQIHWP8//8/AwMDExADAQAkBgMBOOSShwAAAABJRU5ErkJgg==" data-mce-token="1">'
|
||||
}
|
||||
},
|
||||
included: [
|
||||
{
|
||||
type: 'tiny_mce_assets',
|
||||
attributes: {
|
||||
file_data: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAA'\
|
||||
'AACCAIAAAD91JpzAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAE0lE'\
|
||||
'QVQIHWP8//8/AwMDExADAQAkBgMBOOSShwAAAABJRU5ErkJggg==',
|
||||
file_token: '1',
|
||||
file_name: 'test.png'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
it 'Response with correct text result and TinyMCE images' do
|
||||
hash_body = nil
|
||||
action
|
||||
|
||||
expect(response).to have_http_status 200
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(ResultText.last, serializer: Api::V2::ResultTextSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
expect(ResultText.last.text).to include "data-mce-token=\"#{Base62.encode(TinyMceAsset.last.id)}\""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE result_text, #destroy' do
|
||||
let(:result_text) { create(:result_text, result: result) }
|
||||
let(:result_text_archived) { create(:result_text, result: result_archived) }
|
||||
let(:action) do
|
||||
delete(api_v2_team_project_experiment_task_result_result_text_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result.id,
|
||||
id: result_text.id
|
||||
), headers: valid_headers)
|
||||
end
|
||||
|
||||
let(:action_archived) do
|
||||
delete(api_v2_team_project_experiment_task_result_result_text_path(
|
||||
team_id: team.id,
|
||||
project_id: project.id,
|
||||
experiment_id: experiment.id,
|
||||
task_id: task.id,
|
||||
result_id: result_archived.id,
|
||||
id: result_text_archived.id
|
||||
), headers: valid_headers)
|
||||
end
|
||||
|
||||
it 'deletes result_text' do
|
||||
action
|
||||
expect(response).to have_http_status(200)
|
||||
expect(ResultText.where(id: result_text.id)).to_not exist
|
||||
end
|
||||
|
||||
it 'does not delete result_text of archived result' do
|
||||
action_archived
|
||||
expect(response).to have_http_status(403)
|
||||
expect(ResultText.where(id: result_text_archived.id)).to exist
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:enable Metrics/BlockLength
|
369
spec/requests/api/v2/results_controller_spec.rb
Normal file
369
spec/requests/api/v2/results_controller_spec.rb
Normal file
|
@ -0,0 +1,369 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# rubocop:disable Metrics/BlockLength
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api::V2::ResultsController', type: :request do
|
||||
let(:user) { create(:user) }
|
||||
let(:another_user) { create(:user) }
|
||||
let(:team1) { create(:team, created_by: user) }
|
||||
let(:team2) { create(:team, created_by: another_user) }
|
||||
|
||||
let(:valid_project) { create(:project, name: Faker::Name.unique.name, created_by: user, team: team1) }
|
||||
let(:unaccessible_project) { create(:project, name: Faker::Name.unique.name, created_by: user, team: team2) }
|
||||
|
||||
let(:valid_experiment) { create(:experiment, created_by: user, last_modified_by: user, project: valid_project) }
|
||||
let(:unaccessible_experiment) { create(:experiment, created_by: user, last_modified_by: user, project: unaccessible_project) }
|
||||
|
||||
let(:valid_task) { create(:my_module, created_by: user, last_modified_by: user, experiment: valid_experiment) }
|
||||
let(:unaccessible_task) { create(:my_module, created_by: user, last_modified_by: user, experiment: unaccessible_experiment) }
|
||||
|
||||
let!(:results) { create_list(:result, 3, user: user, last_modified_by: user, my_module: valid_task) }
|
||||
let!(:unaccessible_result) { create(:result, user: user, last_modified_by: user, my_module: unaccessible_task) }
|
||||
|
||||
let(:valid_hash_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'results',
|
||||
attributes: {
|
||||
name: Faker::Name.unique.name
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
let(:valid_headers) do
|
||||
{
|
||||
Authorization: "Bearer #{generate_token(user.id)}",
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
end
|
||||
|
||||
describe 'GET results, #index' do
|
||||
let(:api_path) do
|
||||
api_v2_team_project_experiment_task_results_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: valid_task
|
||||
)
|
||||
end
|
||||
|
||||
it 'Response with correct results' do
|
||||
hash_body = nil
|
||||
get api_path, headers: valid_headers
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(valid_task.results, each_serializer: Api::V2::ResultSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
|
||||
it 'When invalid request, task from another experiment' do
|
||||
hash_body = nil
|
||||
get api_v2_team_project_experiment_task_results_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: unaccessible_task
|
||||
), headers: valid_headers
|
||||
expect(response).to have_http_status(404)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body['errors'][0]).to include(status: 404)
|
||||
end
|
||||
|
||||
it 'When invalid request, user is not a member of the team' do
|
||||
hash_body = nil
|
||||
get api_v2_team_project_experiment_task_results_path(
|
||||
team_id: team2.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: valid_task
|
||||
), headers: valid_headers
|
||||
expect(response).to have_http_status(403)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body['errors'][0]).to include(status: 403)
|
||||
end
|
||||
|
||||
it 'When invalid request, non-existing task' do
|
||||
hash_body = nil
|
||||
get api_v2_team_project_experiment_task_results_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: -1
|
||||
), headers: valid_headers
|
||||
expect(response).to have_http_status(404)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body['errors'][0]).to include(status: 404)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET result, #show' do
|
||||
let(:result_valid) { valid_task.results.first }
|
||||
let(:api_path) do
|
||||
api_v2_team_project_experiment_task_result_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: valid_task,
|
||||
id: result_valid.id
|
||||
)
|
||||
end
|
||||
|
||||
it 'When valid request, user can read result' do
|
||||
hash_body = nil
|
||||
get api_path, headers: valid_headers
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(result_valid, serializer: Api::V2::ResultSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
|
||||
it 'When invalid request, user is not a member of the team' do
|
||||
hash_body = nil
|
||||
get api_v2_team_project_experiment_task_result_path(
|
||||
team_id: team2.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: valid_task,
|
||||
id: result_valid.id
|
||||
), headers: valid_headers
|
||||
expect(response).to have_http_status(403)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body['errors'][0]).to include(status: 403)
|
||||
end
|
||||
|
||||
it 'When invalid request, non-existing result' do
|
||||
hash_body = nil
|
||||
get api_v2_team_project_experiment_task_result_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: valid_task,
|
||||
id: -1
|
||||
), headers: valid_headers
|
||||
expect(response).to have_http_status(404)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body['errors'][0]).to include(status: 404)
|
||||
end
|
||||
|
||||
it 'When invalid request, result from an unaccessible task' do
|
||||
hash_body = nil
|
||||
get api_v2_team_project_experiment_task_result_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: unaccessible_task,
|
||||
id: unaccessible_result.id
|
||||
), headers: valid_headers
|
||||
expect(response).to have_http_status(404)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body['errors'][0]).to include(status: 404)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST result, #create' do
|
||||
let(:api_path) do
|
||||
api_v2_team_project_experiment_task_results_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: valid_task
|
||||
)
|
||||
end
|
||||
|
||||
it 'Response with correct result' do
|
||||
hash_body = nil
|
||||
post api_path, params: valid_hash_body.to_json, headers: valid_headers
|
||||
expect(response).to have_http_status 200
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body[:data]).to match(
|
||||
JSON.parse(
|
||||
ActiveModelSerializers::SerializableResource
|
||||
.new(Result.last, serializer: Api::V2::ResultSerializer)
|
||||
.to_json
|
||||
)['data']
|
||||
)
|
||||
end
|
||||
|
||||
it 'When invalid request, non-existing task' do
|
||||
hash_body = nil
|
||||
post api_v2_team_project_experiment_task_results_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: -1
|
||||
), params: valid_hash_body.to_json, headers: valid_headers
|
||||
expect(response).to have_http_status(404)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body['errors'][0]).to include(status: 404)
|
||||
end
|
||||
|
||||
it 'When invalid request, user is not a member of the team' do
|
||||
hash_body = nil
|
||||
post api_v2_team_project_experiment_task_results_path(
|
||||
team_id: team2.id,
|
||||
project_id: unaccessible_project,
|
||||
experiment_id: unaccessible_experiment,
|
||||
task_id: unaccessible_task
|
||||
), params: valid_hash_body.to_json, headers: valid_headers
|
||||
expect(response).to have_http_status(403)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body['errors'][0]).to include(status: 403)
|
||||
end
|
||||
|
||||
it 'When invalid request, task from another experiment' do
|
||||
hash_body = nil
|
||||
post api_v2_team_project_experiment_task_results_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: unaccessible_task
|
||||
), params: valid_hash_body.to_json, headers: valid_headers
|
||||
expect(response).to have_http_status(404)
|
||||
expect { hash_body = json }.not_to raise_exception
|
||||
expect(hash_body['errors'][0]).to include(status: 404)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT result, #update' do
|
||||
let(:result_valid) { valid_task.results.first }
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'results',
|
||||
attributes: {
|
||||
name: 'my result'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
let(:action) do
|
||||
put(api_v2_team_project_experiment_task_result_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: valid_task,
|
||||
id: result_valid.id
|
||||
), params: request_body.to_json, headers: valid_headers)
|
||||
end
|
||||
|
||||
context 'when has attributes for update' do
|
||||
it 'updates tasks name' do
|
||||
action
|
||||
expect(result_valid.reload.name).to eq('my result')
|
||||
end
|
||||
|
||||
it 'returns status 200' do
|
||||
action
|
||||
expect(response).to have_http_status 200
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is nothing to update' do
|
||||
let(:request_body_with_same_name) do
|
||||
{
|
||||
data: {
|
||||
type: 'results',
|
||||
attributes: {
|
||||
name: result_valid.reload.name
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'returns 204' do
|
||||
put(api_v2_team_project_experiment_task_result_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: valid_task,
|
||||
id: result_valid.id
|
||||
), params: request_body_with_same_name.to_json, headers: valid_headers)
|
||||
|
||||
expect(response).to have_http_status 204
|
||||
end
|
||||
end
|
||||
|
||||
context 'when result is archived' do
|
||||
let(:result_archived) do
|
||||
create(:result, :archived, user: user, last_modified_by: user, my_module: valid_task)
|
||||
end
|
||||
|
||||
let(:request_with_archived_result) do
|
||||
{
|
||||
data: {
|
||||
type: 'results',
|
||||
attributes: {
|
||||
name: 'Result archived'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'returns 403' do
|
||||
put(api_v2_team_project_experiment_task_result_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: valid_task,
|
||||
id: result_archived.id
|
||||
), params: request_with_archived_result.to_json, headers: valid_headers)
|
||||
|
||||
expect(response).to have_http_status 403
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE result, #destroy' do
|
||||
let(:result_archived) do
|
||||
create(:result, :archived, user: user, last_modified_by: user, my_module: valid_task)
|
||||
end
|
||||
|
||||
let(:result_valid) { valid_task.results.first }
|
||||
|
||||
let(:action) do
|
||||
delete(api_v2_team_project_experiment_task_result_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: valid_task,
|
||||
id: result_valid.id
|
||||
), headers: valid_headers)
|
||||
end
|
||||
|
||||
let(:action_archived) do
|
||||
delete(api_v2_team_project_experiment_task_result_path(
|
||||
team_id: team1.id,
|
||||
project_id: valid_project,
|
||||
experiment_id: valid_experiment,
|
||||
task_id: valid_task,
|
||||
id: result_archived.id
|
||||
), headers: valid_headers)
|
||||
end
|
||||
|
||||
it 'deletes result' do
|
||||
action_archived
|
||||
expect(response).to have_http_status(200)
|
||||
expect(Result.where(id: result_archived.id)).to_not exist
|
||||
end
|
||||
|
||||
it 'does not delete archived result' do
|
||||
action
|
||||
expect(response).to have_http_status(403)
|
||||
expect(Result.where(id: result_valid.id)).to exist
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:enable Metrics/BlockLength
|
Loading…
Reference in a new issue