mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-09-20 06:35:56 +08:00
Merge branch 'develop' into features/inventory-items-relationships
This commit is contained in:
commit
95ab33a58b
|
@ -100,8 +100,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
function initActionButtons() {
|
||||
initUpdatePDFReport();
|
||||
initGenerateDocxReport();
|
||||
initUpdateDocxReport();
|
||||
initEditReport();
|
||||
initSaveReportPDFToInventory();
|
||||
initDeleteReports();
|
||||
}
|
||||
|
||||
function updateButtons() {
|
||||
if (window.actionToolbarComponent) {
|
||||
window.actionToolbarComponent.setActionsLoadedCallback(initActionButtons);
|
||||
window.actionToolbarComponent.fetchActions({ report_ids: CHECKBOX_SELECTOR.selectedRows });
|
||||
$('.dataTables_scrollBody').css('padding-bottom', `${CHECKBOX_SELECTOR.selectedRows.length > 0 ? 68 : 0}px`);
|
||||
}
|
||||
|
@ -263,7 +273,7 @@
|
|||
}
|
||||
|
||||
function initUpdatePDFReport() {
|
||||
$(document).on('click', '#updatePdf', function(ev) {
|
||||
$('#updatePdf').on('click', function(ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
|
@ -283,7 +293,7 @@
|
|||
}
|
||||
|
||||
function initGenerateDocxReport() {
|
||||
$(document).on('click', '#requestDocx', function(ev) {
|
||||
$('#requestDocx').on('click', function(ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
$(this).closest('.dropdown-menu').dropdown('toggle');
|
||||
|
@ -292,7 +302,7 @@
|
|||
}
|
||||
|
||||
function initUpdateDocxReport() {
|
||||
$(document).on('click', '#updateDocx', function(ev) {
|
||||
$('#updateDocx').on('click', function(ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
|
@ -325,7 +335,7 @@
|
|||
}
|
||||
|
||||
function initSaveReportPDFToInventory() {
|
||||
$(document).on('click', '#savePdfToInventoryButton', function(ev) {
|
||||
$('#savePdfToInventoryButton').on('click', function(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
|
@ -347,7 +357,7 @@
|
|||
}
|
||||
|
||||
function initDeleteReports() {
|
||||
$(document).on('click', '#delete-reports-btn', function() {
|
||||
$('#delete-reports-btn').on('click', function() {
|
||||
if (CHECKBOX_SELECTOR.selectedRows.length > 0) {
|
||||
$('#report-ids').attr('value', '[' + CHECKBOX_SELECTOR.selectedRows + ']');
|
||||
$('#delete-reports-modal').modal('show');
|
||||
|
@ -376,10 +386,4 @@
|
|||
$('#show_report_preview').click();
|
||||
|
||||
initDatatable();
|
||||
initUpdatePDFReport();
|
||||
initGenerateDocxReport();
|
||||
initUpdateDocxReport();
|
||||
initEditReport();
|
||||
initSaveReportPDFToInventory();
|
||||
initDeleteReports();
|
||||
}());
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
orderable: false,
|
||||
render: function() {
|
||||
return `<div class="sci-checkbox-container">
|
||||
<input class='repository-row-selector sci-checkbox' type='checkbox' data-e2e="e2e-CB-inventory">
|
||||
<input class='repository-row-selector sci-checkbox' type='checkbox' data-e2e="e2e-CB-inventories-all">
|
||||
<span class='sci-checkbox-label'></span>
|
||||
</div>`;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ $.fn.dataTable.render.editRowName = function(formId, cell) {
|
|||
name="repository_row[name]"
|
||||
value=""
|
||||
placeholder="${I18n.t('repositories.table.enter_row_name')}"
|
||||
data-type="RowName">
|
||||
data-type="RowName"
|
||||
data-e2e="e2e-IF-invInventoryEditItemTR-name">
|
||||
</div>
|
||||
`);
|
||||
$cell.find('input').val(text);
|
||||
|
|
|
@ -13,7 +13,8 @@ $.fn.dataTable.render.newRowName = function(formId, $cell) {
|
|||
name="repository_row[name]"
|
||||
value=""
|
||||
placeholder="${I18n.t('repositories.table.enter_row_name')}"
|
||||
data-type="RowName">
|
||||
data-type="RowName"
|
||||
data-e2e="e2e-IF-invInventoryNewItemTR-name">
|
||||
</div>
|
||||
`);
|
||||
};
|
||||
|
|
|
@ -671,7 +671,7 @@ var RepositoryDatatable = (function(global) {
|
|||
visible: true,
|
||||
render: function(data, type, row) {
|
||||
return "<a href='" + row.recordInfoUrl + "'"
|
||||
+ "class='record-info-link' data-e2e='e2e-TL-invInventory-Item-" + row.DT_RowId + "'>" + data + '</a>';
|
||||
+ "class='record-info-link' data-e2e='e2e-TL-invInventoryTR-Item-" + row.DT_RowId + "'>" + data + '</a>';
|
||||
}
|
||||
}, {
|
||||
targets: 4,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
formGroup.append(
|
||||
'<span class="help-block">' + XHR.responseJSON.message + '</span>'
|
||||
);
|
||||
HelperModule.flashAlertMsg(XHR.responseJSON.message, 'danger');
|
||||
}
|
||||
|
||||
function handleSuccessfulSubmit(data) {
|
||||
|
|
|
@ -385,14 +385,16 @@ var RepositoryColumns = (function() {
|
|||
|
||||
function initBackToManageColumns() {
|
||||
var $manageModal = $(manageModal);
|
||||
$manageModal.on('click', '.back-to-column-modal', function() {
|
||||
$manageModal.on('click', '.back-to-column-modal', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
var button = $(this);
|
||||
initManageColumnModal(button);
|
||||
});
|
||||
}
|
||||
|
||||
function initColumnsButton() {
|
||||
$(document).on('click', '.manage-repo-column-index', function() {
|
||||
$(document).on('click', '.manage-repo-column-index', function(e) {
|
||||
e.stopImmediatePropagation();
|
||||
var button = $(this);
|
||||
initManageColumnModal(button);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/* global */
|
||||
|
||||
(function () {
|
||||
const rtf = $('.rtf-view').toArray();
|
||||
for (let i = 0; i < rtf.length; i += 1) {
|
||||
const container = $(rtf[i]).find('table').toArray();
|
||||
|
||||
for (let j = 0; j < container.length; j += 1) {
|
||||
const table = $(container[j]);
|
||||
if ($(table).parent().hasClass('table-wrapper')) return;
|
||||
|
||||
$(table).wrap(`
|
||||
<div class="table-wrapper" style="overflow: auto; width: ${$($(rtf)[0]).parent().width()}px"></div>
|
||||
`);
|
||||
}
|
||||
}
|
||||
}());
|
|
@ -24,7 +24,13 @@
|
|||
});
|
||||
}
|
||||
$('.activity-filters-list').on('ajax:error', '.webhook-form', function(e, data) {
|
||||
$(this).renderFormErrors('webhook', data.responseJSON.errors);
|
||||
const { errors } = data.responseJSON;
|
||||
// display url errors with data-error-text attribute
|
||||
if (errors.url) {
|
||||
$(this).find('.url-input-container').addClass('error').attr('data-error-text', `${errors.url.join(', ')}`);
|
||||
delete errors.url;
|
||||
}
|
||||
$(this).renderFormErrors('webhook', errors);
|
||||
});
|
||||
|
||||
$('.activity-filters-list').on('click', '.create-webhook', function() {
|
||||
|
@ -33,6 +39,11 @@
|
|||
filterElement.find('.create-webhook-container').removeClass('hidden');
|
||||
});
|
||||
|
||||
// clear url form errors
|
||||
$('.activity-filters-list').on('click', '.cancel-action, .save-webhook', () => {
|
||||
$('.url-input-container').removeClass('error').attr('data-error-text', '');
|
||||
});
|
||||
|
||||
$('.activity-filters-list').on('click', '.create-webhook-container .cancel-action', function(e) {
|
||||
let webhookContainer = $(this).closest('.create-webhook-container');
|
||||
e.preventDefault();
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
module StepElements
|
||||
class AssetsController < ::Api::V1::AssetsController; end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
module StepElements
|
||||
class ChecklistItemsController < ::Api::V1::ChecklistItemsController; end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
module StepElements
|
||||
class ChecklistsController < ::Api::V1::ChecklistsController; end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
module StepElements
|
||||
class TablesController < ::Api::V1::TablesController; end
|
||||
end
|
||||
end
|
||||
end
|
9
app/controllers/api/v2/step_elements/texts_controller.rb
Normal file
9
app/controllers/api/v2/step_elements/texts_controller.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
module StepElements
|
||||
class TextsController < ::Api::V1::StepTextsController; end
|
||||
end
|
||||
end
|
||||
end
|
66
app/controllers/api/v2/steps_controller.rb
Normal file
66
app/controllers/api/v2/steps_controller.rb
Normal file
|
@ -0,0 +1,66 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class StepsController < ::Api::V1::StepsController
|
||||
def index
|
||||
steps = timestamps_filter(@protocol.steps).page(params.dig(:page, :number))
|
||||
.per(params.dig(:page, :size))
|
||||
|
||||
render jsonapi: steps, each_serializer: StepSerializer,
|
||||
include: include_params,
|
||||
rte_rendering: render_rte?,
|
||||
team: @team
|
||||
end
|
||||
|
||||
def show
|
||||
render jsonapi: @step, serializer: StepSerializer,
|
||||
include: include_params,
|
||||
rte_rendering: render_rte?,
|
||||
team: @team
|
||||
end
|
||||
|
||||
def create
|
||||
raise PermissionError.new(Protocol, :create) unless can_manage_protocol_in_module?(@protocol)
|
||||
|
||||
@protocol.transaction do
|
||||
@step = @protocol.steps.create!(
|
||||
step_params.merge!(completed: false,
|
||||
user: current_user,
|
||||
position: @protocol.number_of_steps,
|
||||
last_modified_by_id: current_user.id)
|
||||
)
|
||||
end
|
||||
render jsonapi: @step, serializer: StepSerializer, status: :created
|
||||
end
|
||||
|
||||
def update
|
||||
@step.assign_attributes(
|
||||
step_params.merge!(last_modified_by_id: current_user.id)
|
||||
)
|
||||
|
||||
if @step.changed? && @step.save!
|
||||
if @step.saved_change_to_attribute?(:completed)
|
||||
completed_steps = @protocol.steps.where(completed: true).count
|
||||
all_steps = @protocol.steps.count
|
||||
type_of = @step.saved_change_to_attribute(:completed).last ? :complete_step : :uncomplete_step
|
||||
log_activity(type_of, my_module: @task.id,
|
||||
num_completed: completed_steps.to_s,
|
||||
num_all: all_steps.to_s)
|
||||
end
|
||||
render jsonapi: @step, serializer: StepSerializer, status: :ok
|
||||
else
|
||||
render body: nil, status: :no_content
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def step_params
|
||||
raise TypeError unless params.require(:data).require(:type) == 'steps'
|
||||
|
||||
params.require(:data).require(:attributes).permit(:name, :completed)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -13,11 +13,13 @@ module ActiveStorage
|
|||
def check_read_permissions
|
||||
return render_404 if @blob.attachments.blank?
|
||||
|
||||
@blob.attachments.any? { |attachment| check_attachment_read_permissions(attachment) }
|
||||
render_403 unless @blob.attachments.any? { |attachment| check_attachment_read_permissions(attachment) }
|
||||
end
|
||||
|
||||
def check_attachment_read_permissions(attachment)
|
||||
current_user.permission_team = attachment.record.team || current_team if attachment.record.respond_to?(:team)
|
||||
current_user.permission_team = attachment.record.team if attachment.record.respond_to?(:team)
|
||||
|
||||
return false if attachment.record.blank?
|
||||
|
||||
case attachment.record_type
|
||||
when 'Asset'
|
||||
|
@ -25,73 +27,52 @@ module ActiveStorage
|
|||
when 'TinyMceAsset'
|
||||
check_tinymce_asset_read_permissions(attachment.record)
|
||||
when 'Experiment'
|
||||
check_experiment_read_permissions(attachment.record)
|
||||
can_read_experiment?(attachment.record)
|
||||
when 'Report'
|
||||
check_report_read_permissions(attachment.record)
|
||||
can_read_project?(attachment.record.project)
|
||||
when 'User'
|
||||
# No read restrictions for avatars
|
||||
true
|
||||
when 'ZipExport', 'TeamZipExport'
|
||||
check_zip_export_read_permissions(attachment.record)
|
||||
attachment.record.user == current_user
|
||||
when 'TempFile'
|
||||
check_temp_file_read_permissions(attachment.record)
|
||||
attachment.record.session_id == request.session_options[:id].to_s
|
||||
else
|
||||
render_403
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def check_asset_read_permissions(asset)
|
||||
return render_403 unless asset
|
||||
|
||||
if asset.step
|
||||
protocol = asset.step.protocol
|
||||
render_403 unless can_read_protocol_in_module?(protocol) || can_read_protocol_in_repository?(protocol)
|
||||
can_read_protocol_in_module?(protocol) || can_read_protocol_in_repository?(protocol)
|
||||
elsif asset.result
|
||||
experiment = asset.result.my_module.experiment
|
||||
render_403 unless can_read_experiment?(experiment)
|
||||
can_read_experiment?(experiment)
|
||||
elsif asset.repository_cell
|
||||
repository = asset.repository_cell.repository_column.repository
|
||||
render_403 unless can_read_repository?(repository)
|
||||
can_read_repository?(repository)
|
||||
else
|
||||
render_403
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def check_tinymce_asset_read_permissions(asset)
|
||||
return render_403 unless asset
|
||||
|
||||
return true if asset.object.nil? && can_read_team?(asset.team)
|
||||
|
||||
case asset.object_type
|
||||
when 'MyModule'
|
||||
render_403 unless can_read_my_module?(asset.object)
|
||||
can_read_my_module?(asset.object)
|
||||
when 'Protocol'
|
||||
render_403 unless can_read_protocol_in_module?(asset.object) ||
|
||||
can_read_protocol_in_repository?(asset.object)
|
||||
can_read_protocol_in_module?(asset.object) || can_read_protocol_in_repository?(asset.object)
|
||||
when 'ResultText'
|
||||
render_403 unless can_read_my_module?(asset.object.result.my_module)
|
||||
can_read_my_module?(asset.object.result.my_module)
|
||||
when 'StepText'
|
||||
render_403 unless can_read_protocol_in_module?(asset.object.step.protocol) ||
|
||||
can_read_protocol_in_repository?(asset.object.step.protocol)
|
||||
can_read_protocol_in_module?(asset.object.step.protocol) ||
|
||||
can_read_protocol_in_repository?(asset.object.step.protocol)
|
||||
else
|
||||
render_403
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def check_experiment_read_permissions(experiment)
|
||||
render_403 && return unless can_read_experiment?(experiment)
|
||||
end
|
||||
|
||||
def check_report_read_permissions(report)
|
||||
render_403 && return unless can_read_project?(report.project)
|
||||
end
|
||||
|
||||
def check_zip_export_read_permissions(zip_export)
|
||||
render_403 unless zip_export.user == current_user
|
||||
end
|
||||
|
||||
def check_temp_file_read_permissions(temp_file)
|
||||
render_403 unless temp_file.session_id == request.session_options[:id].to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,8 +8,8 @@ class GlobalActivitiesController < ApplicationController
|
|||
def index
|
||||
# Preload filter format
|
||||
# {
|
||||
# from_date: "YYYY-MM-DD",
|
||||
# to_date: "YYYY-MM-DD",
|
||||
# from_date: "YYYY-MM-DD",
|
||||
# teams: [*team_ids],
|
||||
# types: [*activity_type_ids],
|
||||
# users: [*user_ids],
|
||||
|
@ -21,8 +21,8 @@ class GlobalActivitiesController < ApplicationController
|
|||
|
||||
# Example
|
||||
# {
|
||||
# to_date: "2018-02-28",
|
||||
# from_date: "2019-03-29",
|
||||
# to_date: "2019-03-29",
|
||||
# teams: [1,2],
|
||||
# types: [32,33,34],
|
||||
# users: [1,2,3],
|
||||
|
|
|
@ -87,7 +87,7 @@ module Users
|
|||
end
|
||||
|
||||
if filters['to_date'] || filters['from_date']
|
||||
result.push("#{t('global_activities.index.period_label')} #{filters['from_date']} - #{filters['to_date']}")
|
||||
result.push("#{t('global_activities.index.period_label')} #{filters['to_date']} - #{filters['from_date']}")
|
||||
end
|
||||
|
||||
filters['subjects']&.each do |subject, ids|
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module NotificationsHelper
|
||||
def send_email_notification(user, notification)
|
||||
AppMailer.delay.notification(user.id, notification)
|
||||
|
@ -17,14 +19,17 @@ module NotificationsHelper
|
|||
team: team.name,
|
||||
assigned_by_user: user.name)
|
||||
end
|
||||
message = "#{I18n.t('search.index.team')} #{team.name}"
|
||||
end
|
||||
|
||||
GeneralNotification.send_notifications({
|
||||
type: role ? :invite_user_to_team : :remove_user_from_team,
|
||||
title: sanitize_input(title),
|
||||
message: sanitize_input(message),
|
||||
user: target_user
|
||||
})
|
||||
GeneralNotification.send_notifications(
|
||||
{
|
||||
type: role ? :invite_user_to_team : :remove_user_from_team,
|
||||
title: sanitize_input(title),
|
||||
subject_id: team.id,
|
||||
subject_class: team.class.name,
|
||||
subject_name: team.respond_to?(:name) && team.name,
|
||||
user: target_user
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,7 +30,7 @@ module RepositoriesDatatableHelper
|
|||
'data-rename-modal-url': team_repository_rename_modal_path(team, repository_id: repository),
|
||||
'data-shared': repository.shared_with?(team),
|
||||
'data-i-shared': repository.i_shared?(team),
|
||||
'data-e2e': "e2e-RT-inventories-tableItemRow-#{repository.id}"
|
||||
'data-e2e': "e2e-TR-inventories-bodyRow-#{repository.id}"
|
||||
}
|
||||
)
|
||||
end
|
||||
|
|
|
@ -17,7 +17,7 @@ module RepositoryDatatableHelper
|
|||
row = public_send("#{repository.class.name.underscore}_default_columns", record)
|
||||
row.merge!(
|
||||
DT_RowId: record.id,
|
||||
DT_RowAttr: { 'data-state': row_style(record), 'data-e2e': "e2e-RT-invInventory-row-#{record.id}" },
|
||||
DT_RowAttr: { 'data-state': row_style(record), 'data-e2e': "e2e-TR-invInventory-bodyRow-#{record.id}" },
|
||||
recordInfoUrl: Rails.application.routes.url_helpers.repository_repository_row_path(repository, record),
|
||||
rowRemindersUrl:
|
||||
Rails.application.routes.url_helpers
|
||||
|
@ -62,7 +62,7 @@ module RepositoryDatatableHelper
|
|||
else
|
||||
{ stock_url: new_repository_stock_repository_repository_row_url(repository, record) }
|
||||
end
|
||||
row['stock'][:stock_managable] = stock_managable
|
||||
row['stock'][:stock_managable] = stock_managable && record.active?
|
||||
row['stock']['displayWarnings'] = display_stock_warnings?(repository)
|
||||
row['stock'][:stock_status] = stock_cell&.value&.status
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
:data-object-type="groupAction.item_type"
|
||||
:data-object-id="groupAction.item_id"
|
||||
:data-action="groupAction.type"
|
||||
:data-e2e="`e2e-BT-actionToolbar-${groupAction.name}`"
|
||||
@click="closeExportDropdown($event); doAction(groupAction, $event);">
|
||||
<span class="sn-action-toolbar__button-text">{{ groupAction.label }}</span>
|
||||
</a>
|
||||
|
@ -46,6 +47,7 @@
|
|||
:data-object-type="action.actions[0].item_type"
|
||||
:data-object-id="action.actions[0].item_id"
|
||||
:data-action="action.actions[0].type"
|
||||
:data-e2e="`e2e-BT-actionToolbar-${action.name}`"
|
||||
@click="doAction(action.actions[0], $event);">
|
||||
<i :class="action.actions[0].icon"></i>
|
||||
<span class="sn-action-toolbar__button-text">{{ action.group_label }}</span>
|
||||
|
@ -61,6 +63,7 @@
|
|||
:data-object-type="action.item_type"
|
||||
:data-object-id="action.item_id"
|
||||
:data-action="action.type"
|
||||
:data-e2e="`e2e-BT-actionToolbar-${action.name}`"
|
||||
@click="doAction(action, $event)">
|
||||
<i :class="action.icon"></i>
|
||||
<span class="sn-action-toolbar__button-text">{{ action.label }}</span>
|
||||
|
@ -85,6 +88,7 @@
|
|||
multiple: false,
|
||||
params: {},
|
||||
reloadCallback: null,
|
||||
actionsLoadedCallback: null,
|
||||
loaded: false,
|
||||
loading: false,
|
||||
width: 0,
|
||||
|
@ -104,6 +108,7 @@
|
|||
this.actions = data.actions;
|
||||
this.loading = false;
|
||||
this.setButtonOverflow();
|
||||
if (this.actionsLoadedCallback) this.$nextTick(this.actionsLoadedCallback);
|
||||
});
|
||||
}, 10);
|
||||
},
|
||||
|
@ -158,6 +163,9 @@
|
|||
setReloadCallback(func) {
|
||||
this.reloadCallback = func;
|
||||
},
|
||||
setActionsLoadedCallback(func) {
|
||||
this.actionsLoadedCallback = func;
|
||||
},
|
||||
doAction(action, event) {
|
||||
switch(action.type) {
|
||||
case 'legacy':
|
||||
|
|
|
@ -98,9 +98,9 @@ export default {
|
|||
},
|
||||
reloadCurrentLevel: function() {
|
||||
if (this.reloadCurrentLevel && (
|
||||
this.currentItemId.length == 0 ||
|
||||
this.menuItems.filter(item => item.id == this.currentItemId)
|
||||
)) {
|
||||
this.currentItemId?.length === 0
|
||||
|| this.menuItems.filter((item) => item.id === this.currentItemId)
|
||||
)) {
|
||||
this.loadTree();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="protocol-description-container" :class=" inRepository ? 'protocol-description collapse in' : ''" >
|
||||
<div id="protocol-description-container" class="text-base" :class=" inRepository ? 'protocol-description collapse in' : ''" >
|
||||
<div v-if="urls.update_protocol_description_url">
|
||||
<Tinymce
|
||||
:value="protocol.attributes.description"
|
||||
|
|
|
@ -211,7 +211,8 @@
|
|||
{ text: I18n.t('protocols.steps.insert.well_plate_options.16_x_24'), emit: 'create:table', params: [16, 24] },
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.8_x_12'), emit: 'create:table', params: [8, 12] },
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.6_x_8'), emit: 'create:table', params: [6, 8] },
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.6_x_4'), emit: 'create:table', params: [6, 4] },
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.4_x_6'), emit: 'create:table', params: [4, 6] },
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.3_x_4'), emit: 'create:table', params: [3, 4]},
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.2_x_3'), emit: 'create:table', params: [2, 3] }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
<transition enter-from-class="translate-x-full w-0"
|
||||
enter-active-class="transition-all ease-sharp duration-[588ms]"
|
||||
leave-active-class="transition-all ease-sharp duration-[588ms]"
|
||||
leave-to-class="translate-x-full w-0">
|
||||
leave-to-class="translate-x-full w-0"
|
||||
v-click-outside="handleOutsideClick">
|
||||
<div ref="wrapper" v-show="isShowing" id="repository-item-sidebar-wrapper"
|
||||
class='items-sidebar-wrapper bg-white gap-2.5 self-stretch rounded-tl-4 rounded-bl-4 shadow-lg h-full w-[565px]'>
|
||||
|
||||
|
@ -299,7 +300,7 @@
|
|||
:class="{ 'pb-6': customColumns?.length }">
|
||||
<div id="divider" class="w-500 bg-sn-light-grey flex px-8 items-center self-stretch h-px mb-6"></div>
|
||||
<div id="bottom-button-wrapper" class="flex h-10 justify-end">
|
||||
<button type="button" class="btn btn-primary print-label-button"
|
||||
<button type="button" class="btn btn-primary print-label-button" data-e2e="e2e-BT-invInventoryItemSB-print"
|
||||
:data-rows="JSON.stringify([repositoryRowId])">
|
||||
{{ i18n.t('repositories.item_card.print_label') }}
|
||||
</button>
|
||||
|
@ -317,6 +318,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { vOnClickOutside } from '@vueuse/components';
|
||||
import InlineEdit from '../shared/inline_edit.vue';
|
||||
import ScrollSpy from './repository_values/ScrollSpy.vue';
|
||||
import CustomColumns from './customColumns.vue';
|
||||
|
@ -333,6 +335,9 @@ export default {
|
|||
'scroll-spy': ScrollSpy,
|
||||
'unlink-modal': UnlinkModal,
|
||||
},
|
||||
directives: {
|
||||
'click-outside': vOnClickOutside
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentItemUrl: null,
|
||||
|
@ -389,12 +394,10 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
// Add a click event listener to the document
|
||||
document.addEventListener('mousedown', this.handleOutsideClick);
|
||||
this.inRepository = $('.assign-items-to-task-modal-container').length > 0;
|
||||
},
|
||||
beforeUnmount() {
|
||||
delete window.repositoryItemSidebarComponent;
|
||||
document.removeEventListener('mousedown', this.handleOutsideClick);
|
||||
},
|
||||
methods: {
|
||||
handleOpenAddRelationshipsModal(event, relation) {
|
||||
|
@ -424,11 +427,14 @@ export default {
|
|||
handleOutsideClick(event) {
|
||||
if (!this.isShowing) return;
|
||||
|
||||
// Check if the clicked element is not within the sidebar and it's not another item link or belogs to modals
|
||||
const selectors = ['a', '.modal', '.label-printing-progress-modal', '.atwho-view'];
|
||||
const allowedSelectors = ['a', '.modal', '.label-printing-progress-modal', '.atwho-view'];
|
||||
const excludeSelectors = ['#myModuleRepositoryFullViewModal'];
|
||||
|
||||
if (!$(event.target).parents('#repository-item-sidebar-wrapper').length
|
||||
&& !selectors.some((selector) => event.target.closest(selector))) {
|
||||
const isOutsideSidebar = !$(event.target).parents('#repository-item-sidebar-wrapper').length;
|
||||
const isAllowedClick = !allowedSelectors.some((selector) => event.target.closest(selector));
|
||||
const isExcludedClick = excludeSelectors.some((selector) => event.target.closest(selector));
|
||||
|
||||
if (isOutsideSidebar && (isAllowedClick || isExcludedClick)) {
|
||||
this.toggleShowHideSidebar(null);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<span v-for="(checklistItem, index) in selectedChecklistItems"
|
||||
:key="index"
|
||||
:id="`checklist-item-${index}`"
|
||||
class="flex w-fit break-words mr-1">
|
||||
class="flex w-fit break-words">
|
||||
{{
|
||||
index + 1 === selectedChecklistItems.length
|
||||
? checklistItem?.label
|
||||
|
|
|
@ -27,15 +27,16 @@
|
|||
@update="update"
|
||||
className="px-3" />
|
||||
</div>
|
||||
<div v-else-if="colVal?.edit"
|
||||
ref="textRef"
|
||||
class="text-sn-dark-grey box-content text-sm font-normal leading-5 overflow-y-auto pr-3 rounded w-[calc(100%-2rem)]]"
|
||||
:class="{
|
||||
'max-h-[4rem]': collapsed,
|
||||
'max-h-[40rem]': !collapsed
|
||||
}"
|
||||
<div v-else-if="colVal?.view"
|
||||
ref="textRef"
|
||||
v-html="colVal?.view"
|
||||
class="text-sn-dark-grey box-content text-sm font-normal leading-5
|
||||
overflow-y-auto pr-3 rounded w-[calc(100%-2rem)]]"
|
||||
:class="{
|
||||
'max-h-[4rem]': collapsed,
|
||||
'max-h-[40rem]': !collapsed
|
||||
}"
|
||||
>
|
||||
{{ colVal?.edit }}
|
||||
</div>
|
||||
<div v-else class="text-sn-dark-grey font-inter text-sm font-normal leading-5 pr-3 py-2 w-[calc(100%-2rem)]]">
|
||||
{{ i18n.t("repositories.item_card.repository_text_value.no_text") }}
|
||||
|
|
|
@ -191,8 +191,8 @@
|
|||
this.defaultEndDate = this.endDate;
|
||||
if ($('.dataTable')[0]) {
|
||||
$('.dataTable').DataTable().ajax.reload(null, false);
|
||||
this.reloadRepoItemSidebar();
|
||||
}
|
||||
this.reloadRepoItemSidebar();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div ref="modal" class="modal fade" id="modal-print-repository-row-label" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-dialog" role="document" data-e2e="e2e-MD-printLabel">
|
||||
<div class="modal-content">
|
||||
<div v-if="availablePrinters.length > 0" class="printers-available">
|
||||
<div class="modal-header">
|
||||
|
@ -70,7 +70,7 @@
|
|||
</div>
|
||||
<div v-else class="no-printers-available">
|
||||
<div class="modal-body no-printers-container">
|
||||
<button type="button" class="close modal-absolute-close-button" data-dismiss="modal" aria-label="Close"><i class="sn-icon sn-icon-close"></i></button>
|
||||
<button type="button" class="close modal-absolute-close-button" data-dismiss="modal" aria-label="Close"><i class="sn-icon sn-icon-close" data-e2e="e2e-BT-printLabelMD-close"></i></button>
|
||||
<img src='/images/printers/no_available_printers.png'>
|
||||
<p class="no-printer-title">
|
||||
{{ i18n.t('repository_row.modal_print_label.no_printers.title') }}
|
||||
|
@ -80,7 +80,7 @@
|
|||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a :href="urls.fluicsInfo" target="blank" class="btn btn-primary" >
|
||||
<a :href="urls.fluicsInfo" target="blank" class="btn btn-primary" data-e2e="e2e-BT-printLabelMD-visitBlog" >
|
||||
{{ i18n.t('repository_row.modal_print_label.no_printers.visit_blog') }}
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
class="flex items-center mr-3 flex-nowrap relative"
|
||||
v-click-outside="closeSearchInputs"
|
||||
>
|
||||
<button :class="{hidden: searchOpened}" ref='searchInputBtn' class="btn btn-light btn-black icon-btn" :title="i18n.t('repositories.show.search_button_tooltip')" @click="openSearch">
|
||||
<button :class="{hidden: searchOpened}" ref='searchInputBtn' class="btn btn-light btn-black icon-btn" data-e2e="e2e-BT-invInventoryRT-search" :title="i18n.t('repositories.show.search_button_tooltip')" @click="openSearch">
|
||||
<i class="sn-icon sn-icon-search"></i>
|
||||
</button>
|
||||
<div v-if="searchOpened || barcodeSearchOpened" class="w-52 flex">
|
||||
|
@ -28,7 +28,7 @@
|
|||
<i class='sn-icon sn-icon-barcode barcode-scanner !mr-2.5'></i>
|
||||
</div>
|
||||
</div>
|
||||
<button :class="{hidden: barcodeSearchOpened}" ref='barcodeSearchInputBtn' class="btn btn-light btn-black icon-btn ml-2" :title="i18n.t('repositories.show.ean_search_button_tooltip')" @click="openBarcodeSearch">
|
||||
<button :class="{hidden: barcodeSearchOpened}" ref='barcodeSearchInputBtn' class="btn btn-light btn-black icon-btn ml-2" data-e2e="e2e-BT-invInventoryRT-barcode" :title="i18n.t('repositories.show.ean_search_button_tooltip')" @click="openBarcodeSearch">
|
||||
<i class='sn-icon sn-icon-barcode barcode-scanner'></i>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -170,7 +170,8 @@
|
|||
{ text: I18n.t('protocols.steps.insert.well_plate_options.16_x_24'), emit: 'create:table', params: [[16, 24], true] },
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.8_x_12'), emit: 'create:table', params: [[8, 12], true] },
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.6_x_8'), emit: 'create:table', params: [[6, 8], true] },
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.6_x_4'), emit: 'create:table', params: [[6, 4], true] },
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.4_x_6'), emit: 'create:table', params: [[4, 6], true] },
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.3_x_4'), emit: 'create:table', params: [[3, 4], true] },
|
||||
{ text: I18n.t('protocols.steps.insert.well_plate_options.2_x_3'), emit: 'create:table', params: [[2, 3], true] }
|
||||
],
|
||||
editingName: false,
|
||||
|
|
|
@ -16,8 +16,9 @@
|
|||
{{ attachment.attributes.file_name }}
|
||||
</span>
|
||||
</a>
|
||||
<div v-if="attachment.attributes.medium_preview !== null" class="attachment-image-tooltip bg-white sn-shadow-menu-sm" >
|
||||
<img :src="this.imageLoadError ? attachment.attributes.urls.blob : attachment.attributes.medium_preview" @error="handleImageError"/>
|
||||
<div v-if="attachment.attributes.medium_preview !== null" class="attachment-image-tooltip bg-white sn-shadow-menu-sm">
|
||||
<img :src="this.imageLoadError ? attachment.attributes.urls.blob : attachment.attributes.medium_preview" @error="ActiveStoragePreviews.reCheckPreview"
|
||||
@load="ActiveStoragePreviews.showPreview"/>
|
||||
</div>
|
||||
<div class="file-metadata">
|
||||
<span>
|
||||
|
|
|
@ -30,7 +30,7 @@ export default {
|
|||
$wopiModal.modal('hide');
|
||||
$wopiModal.find('form').off('submit');
|
||||
$wopiModal.find('form').off('ajax:success');
|
||||
window.open(data.edit_url, '_blank');
|
||||
window.open(data.data.attributes.urls.edit_asset, '_blank');
|
||||
window.focus();
|
||||
} else {
|
||||
HelperModule.flashAlertMsg(this.i18n.t('errors.general'), 'danger');
|
||||
|
|
|
@ -35,12 +35,14 @@
|
|||
:attributeName="`${i18n.t('ChecklistItem')} ${i18n.t('name')}`"
|
||||
:editOnload="checklistItem.attributes.isNew"
|
||||
:smartAnnotation="true"
|
||||
:allowNewLine="true"
|
||||
@editingEnabled="enableTextEdit"
|
||||
@editingDisabled="disableTextEdit"
|
||||
@update="updateText"
|
||||
@delete="removeItem()"
|
||||
@keypress="keyPressHandler"
|
||||
@blur="onBlurHandler"
|
||||
@paste="pasteHandler"
|
||||
/>
|
||||
<span v-if="!editingText && (!checklistItem.attributes.urls || deleteUrl)" class="absolute right-0 top-0.5 leading-6 tw-hidden group-hover/checklist-item-header:inline-block !text-sn-blue cursor-pointer" @click="showDeleteModal" tabindex="0">
|
||||
<i class="sn-icon sn-icon-delete"></i>
|
||||
|
@ -164,10 +166,16 @@
|
|||
this.$emit('update', this.checklistItem, withKey);
|
||||
},
|
||||
keyPressHandler(e) {
|
||||
if (e.key === 'Enter' && e.shiftKey) {
|
||||
if (
|
||||
((e.shiftKey || e.metaKey) && e.key === 'Enter')
|
||||
|| ((e.ctrlKey || e.metaKey) && e.key === 'v')
|
||||
) {
|
||||
this.checklistItem.attributes.with_paragraphs = true;
|
||||
}
|
||||
},
|
||||
pasteHandler() {
|
||||
this.checklistItem.attributes.with_paragraphs = true;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -113,7 +113,7 @@
|
|||
},
|
||||
computed: {
|
||||
wrapTables() {
|
||||
const container = $(`<span>${this.element.attributes.orderable.text_view}</span>`);
|
||||
const container = $(`<span class="text-base">${this.element.attributes.orderable.text_view}</span>`);
|
||||
container.find('table').toArray().forEach((table) => {
|
||||
if ($(table).parent().hasClass('table-wrapper')) return;
|
||||
$(table).css('float', 'none').wrapAll(`
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
@keydown="handleKeypress"
|
||||
@blur="handleBlur"
|
||||
@keyup.escape="cancelEdit && this.atWhoOpened"
|
||||
@paste="$emit('paste', e)"
|
||||
@focus="setCaretAtEnd"/>
|
||||
<textarea v-else
|
||||
ref="input"
|
||||
|
@ -29,6 +30,7 @@
|
|||
@keydown="handleKeypress"
|
||||
@blur="handleBlur"
|
||||
@keyup.escape="cancelEdit && this.atWhoOpened"
|
||||
@paste="$emit('paste', e)"
|
||||
@focus="setCaretAtEnd"/>
|
||||
</template>
|
||||
<div
|
||||
|
|
|
@ -119,7 +119,7 @@ class Asset < ApplicationRecord
|
|||
|
||||
new_query = new_query.where(
|
||||
"(active_storage_blobs.filename #{like} ? " \
|
||||
"OR asset_text_data.data_vector @@ to_tsquery(?))",
|
||||
"OR asset_text_data.data_vector @@ plainto_tsquery(?))",
|
||||
a_query,
|
||||
s_query
|
||||
)
|
||||
|
@ -140,7 +140,7 @@ class Asset < ApplicationRecord
|
|||
.tr('\'', '"')
|
||||
new_query = new_query.where(
|
||||
"(active_storage_blobs.filename #{like} ANY (array[?]) " \
|
||||
"OR asset_text_data.data_vector @@ to_tsquery(?))",
|
||||
"OR asset_text_data.data_vector @@ plainto_tsquery(?))",
|
||||
a_query,
|
||||
s_query
|
||||
)
|
||||
|
@ -152,9 +152,9 @@ class Asset < ApplicationRecord
|
|||
.limit(Constants::SEARCH_LIMIT)
|
||||
.offset((page - 1) * Constants::SEARCH_LIMIT)
|
||||
Asset.select(
|
||||
"assets_search.*, ts_headline(assets_search.data, to_tsquery('" +
|
||||
sanitize_sql_for_conditions(s_query) +
|
||||
"'), 'StartSel=<mark>, StopSel=</mark>') AS headline"
|
||||
"assets_search.*, " \
|
||||
"ts_headline(assets_search.data, plainto_tsquery('#{sanitize_sql_for_conditions(s_query)}'), " \
|
||||
"'StartSel=<mark>, StopSel=</mark>') AS headline"
|
||||
).from(new_query, 'assets_search')
|
||||
else
|
||||
new_query
|
||||
|
|
|
@ -142,7 +142,7 @@ class Project < ApplicationRecord
|
|||
experiments: {
|
||||
active: { sort: 'new' },
|
||||
archived: { sort: 'new' },
|
||||
view_type: 'cards'
|
||||
view_type: 'table'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -76,6 +76,8 @@ class RepositoryAssetValue < ApplicationRecord
|
|||
def snapshot!(cell_snapshot)
|
||||
value_snapshot = dup
|
||||
asset_snapshot = asset.dup
|
||||
# Needed to handle shared repositories from another teams
|
||||
asset_snapshot.team_id = cell_snapshot.repository_column.repository.team_id
|
||||
|
||||
asset_snapshot.save!
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ class Team < ApplicationRecord
|
|||
projects: {
|
||||
active: { sort: 'new' },
|
||||
archived: { sort: 'new' },
|
||||
view_type: 'cards'
|
||||
view_type: 'table'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -6,11 +6,11 @@ class RepositoryItemDateNotification < BaseNotification
|
|||
end
|
||||
|
||||
def title
|
||||
unit = human_readable_unit(column.metadata['reminder_unit'], column.metadata['reminder_value'])
|
||||
unit = human_readable_unit(params[:reminder_unit], params[:reminder_value])
|
||||
I18n.t(
|
||||
'notifications.content.item_date_reminder.message_html',
|
||||
repository_row_name: subject.name,
|
||||
value: column.metadata['reminder_value'],
|
||||
value: params[:reminder_value],
|
||||
units: unit
|
||||
)
|
||||
end
|
||||
|
@ -21,12 +21,6 @@ class RepositoryItemDateNotification < BaseNotification
|
|||
NonExistantRecord.new(params[:repository_row_name])
|
||||
end
|
||||
|
||||
def column
|
||||
RepositoryColumn.find(params[:repository_column_id])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
NonExistantRecord.new(params[:repository_column_name])
|
||||
end
|
||||
|
||||
after_deliver do
|
||||
if params[:repository_date_time_value_id]
|
||||
RepositoryDateTimeValue.find(params[:repository_date_time_value_id]).update(notification_sent: true)
|
||||
|
|
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
|
25
app/serializers/api/v2/step_serializer.rb
Normal file
25
app/serializers/api/v2/step_serializer.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class StepSerializer < ActiveModel::Serializer
|
||||
include ApplicationHelper
|
||||
include ActionView::Helpers::TextHelper
|
||||
include InputSanitizeHelper
|
||||
|
||||
type :steps
|
||||
attributes :id, :name, :position, :completed
|
||||
attribute :completed_on, if: -> { object.completed? }
|
||||
belongs_to :user, serializer: Api::V1::UserSerializer
|
||||
belongs_to :protocol, serializer: Api::V1::ProtocolSerializer
|
||||
has_many :assets, serializer: Api::V1::AssetSerializer
|
||||
has_many :checklists, serializer: Api::V1::ChecklistSerializer
|
||||
has_many :tables, serializer: Api::V1::TableSerializer
|
||||
has_many :step_texts, serializer: Api::V1::StepTextSerializer
|
||||
has_many :step_comments, key: :comments, serializer: Api::V1::CommentSerializer
|
||||
has_many :step_orderable_elements, key: :step_elements, serializer: Api::V1::StepOrderableElementSerializer
|
||||
|
||||
include TimestampableModel
|
||||
end
|
||||
end
|
||||
end
|
|
@ -21,16 +21,16 @@ module Activities
|
|||
|
||||
def filter_date!
|
||||
@activity_filters = @activity_filters.where(
|
||||
"(CASE "\
|
||||
"WHEN (filter ->> 'to_date') = '' " \
|
||||
"(CASE " \
|
||||
"WHEN ((filter ->> 'to_date') = '') IS NOT FALSE " \
|
||||
"THEN :date >= '-infinity'::date " \
|
||||
"ELSE :date >= (filter ->> 'to_date')::date " \
|
||||
"END) " \
|
||||
" AND " \
|
||||
"(CASE "\
|
||||
"WHEN (filter ->> 'from_date') = '' " \
|
||||
"AND " \
|
||||
"(CASE " \
|
||||
"WHEN ((filter ->> 'from_date') = '') IS NOT FALSE " \
|
||||
"THEN :date <= 'infinity'::date " \
|
||||
"ELSE :date <= (filter ->> 'from_date')::date "\
|
||||
"ELSE :date <= (filter ->> 'from_date')::date " \
|
||||
"END)",
|
||||
date: @activity.created_at.to_date
|
||||
)
|
||||
|
|
|
@ -37,6 +37,8 @@ class ActivitiesService
|
|||
to: Time.zone.parse(filters[:to_date]).beginning_of_day.utc)
|
||||
elsif filters[:from_date].present? && filters[:to_date].blank?
|
||||
query.where('created_at <= :from', from: Time.zone.parse(filters[:from_date]).end_of_day.utc)
|
||||
elsif filters[:from_date].blank? && filters[:to_date].present?
|
||||
query.where('created_at >= :to', to: Time.zone.parse(filters[:to_date]).beginning_of_day.utc)
|
||||
else
|
||||
query
|
||||
end
|
||||
|
|
|
@ -14,6 +14,7 @@ module ProtocolImporters
|
|||
@errors = {}
|
||||
end
|
||||
|
||||
# rubocop:disable Metrics/BlockLength
|
||||
def call
|
||||
return self unless valid?
|
||||
|
||||
|
@ -26,7 +27,7 @@ module ProtocolImporters
|
|||
step_params.symbolize_keys!
|
||||
|
||||
# Create step with nested attributes for tables
|
||||
step = @protocol.steps.create!(step_params.slice(:name, :position, :tables_attributes)
|
||||
step = @protocol.steps.create!(step_params.slice(:name, :position)
|
||||
.merge(user: @user, completed: false)
|
||||
.merge(last_modified_by_id: @user.id))
|
||||
|
||||
|
@ -36,21 +37,44 @@ module ProtocolImporters
|
|||
position: 0,
|
||||
orderable: step_text
|
||||
)
|
||||
|
||||
TinyMceAsset.update_images(step_text, '[]', @user)
|
||||
|
||||
# Add tables
|
||||
if step_params[:tables_attributes].present?
|
||||
step_params[:tables_attributes].each do |table_attributes|
|
||||
table_attributes.symbolize_keys!
|
||||
table = step.tables.create!(
|
||||
name: table_attributes[:name],
|
||||
contents: JSON.parse(table_attributes[:contents].encode('UTF-8', 'UTF-8')).to_json,
|
||||
metadata: JSON.parse(table_attributes[:metadata].presence || '{}'),
|
||||
created_by: @user,
|
||||
last_modified_by: @user,
|
||||
team: @team
|
||||
)
|
||||
step.step_orderable_elements.create!(
|
||||
position: step.step_orderable_elements.size,
|
||||
orderable: table.step_table
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# 'Manually' create assets here. "Accept nested attributes" won't work for assets
|
||||
step.assets << AttachmentsBuilder.generate(step_params.deep_symbolize_keys, user: @user, team: @team)
|
||||
step
|
||||
end
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
@errors[:protocol] = e.record.errors
|
||||
raise ActiveRecord::Rollback
|
||||
rescue StandardError => e
|
||||
Rails.logger.error(e.message)
|
||||
Rails.logger.error(e.backtrace.join("\n"))
|
||||
@errors[:protocol] = e.message
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
# rubocop:enable Metrics/BlockLength
|
||||
|
||||
def succeed?
|
||||
@errors.none?
|
||||
|
|
|
@ -130,6 +130,7 @@ module Toolbars
|
|||
|
||||
def export_actions
|
||||
{
|
||||
name: 'export_group',
|
||||
type: :group,
|
||||
group_label: I18n.t('repositories.exports.export'),
|
||||
actions: [export_items_action, export_consumption_action].compact
|
||||
|
|
|
@ -48,14 +48,12 @@ class ProtocolsImporter
|
|||
private
|
||||
|
||||
def create_in_step!(step, new_orderable)
|
||||
ActiveRecord::Base.transaction do
|
||||
new_orderable.save!
|
||||
new_orderable.save!
|
||||
|
||||
step.step_orderable_elements.create!(
|
||||
position: step.step_orderable_elements.length,
|
||||
orderable: new_orderable
|
||||
)
|
||||
end
|
||||
step.step_orderable_elements.create!(
|
||||
position: step.step_orderable_elements.length,
|
||||
orderable: new_orderable
|
||||
)
|
||||
end
|
||||
|
||||
def populate_protocol(protocol, protocol_json)
|
||||
|
|
|
@ -48,13 +48,11 @@ class ProtocolsImporterV2
|
|||
private
|
||||
|
||||
def create_in_step!(step, new_orderable)
|
||||
ActiveRecord::Base.transaction do
|
||||
new_orderable.save!
|
||||
step.step_orderable_elements.create!(
|
||||
position: step.step_orderable_elements.length,
|
||||
orderable: new_orderable
|
||||
)
|
||||
end
|
||||
new_orderable.save!
|
||||
step.step_orderable_elements.create!(
|
||||
position: step.step_orderable_elements.size,
|
||||
orderable: new_orderable
|
||||
)
|
||||
end
|
||||
|
||||
def populate_protocol(protocol, protocol_json)
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
item_id = dom_id(user, :assignment_member)
|
||||
%>
|
||||
|
||||
<%= form_with(model: assignment, url: update_path, method: :put, html: { class: 'member-item', id: item_id, data: { remote: true, action: 'replace-form autosave-form', object_type: :assignment_member } }) do |f| %>
|
||||
<%= f.hidden_field :user_id, value: f.object.user.id %>
|
||||
<% if assignment.present? %>
|
||||
<%= form_with(model: assignment, url: update_path, method: :put, html: { class: 'member-item', id: item_id, data: { remote: true, action: 'replace-form autosave-form', object_type: :assignment_member } }) do |f| %>
|
||||
<%= f.hidden_field :user_id, value: f.object.user.id %>
|
||||
<div class="user-assignment-info">
|
||||
<div class="global-avatar-container">
|
||||
<%= image_tag avatar_path(user, :icon_small), title: current_assignee_name(user), class: 'img-circle pull-left' %>
|
||||
|
@ -50,4 +51,5 @@
|
|||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
|
@ -131,6 +131,8 @@
|
|||
<%= render "users/sessions/session_end_modal" %>
|
||||
<%= render "label_printers/label_printer_modal" %>
|
||||
<%= render "shared/export_stock_consumption_modal" %>
|
||||
<!-- Manage Stock Modal -->
|
||||
<%= render partial: 'shared/manage_stock_value_modal' %>
|
||||
<% end %>
|
||||
|
||||
<span style="display: none;" data-hook="application-body-end-html"></span>
|
||||
|
|
|
@ -41,5 +41,6 @@
|
|||
|
||||
<%= javascript_include_tag 'prism' %>
|
||||
<%= javascript_include_tag 'shareable_links/date_formatting' %>
|
||||
<%= javascript_include_tag 'shareable_links/handson_table_wraping' %>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="task-notes">
|
||||
<div class="task-notes-content">
|
||||
<div class="task-notes-content text-base">
|
||||
<% if can_update_my_module_description?(@my_module) %>
|
||||
<%= render partial: "my_modules/description_form" %>
|
||||
<% elsif @my_module.description.present? %>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="task-sharing-and-flows flex items-center gap-2 pl-3">
|
||||
<%= render partial: 'my_modules/status_flow/task_flow_button', locals: { my_module: @my_module } if @my_module.my_module_status_flow %>
|
||||
<%= javascript_include_tag("my_modules/status_flow") %>
|
||||
<% if current_team.shareable_links_enabled? && can_share_my_module?(@my_module) %>
|
||||
<% if current_team.shareable_links_enabled? %>
|
||||
<div id="share-task-container" data-behaviour="vue">
|
||||
<share-task-container
|
||||
shareable-link-url="<%= my_module_shareable_link_path(@my_module) %>"
|
||||
|
|
|
@ -152,9 +152,6 @@
|
|||
<!-- Delete file modal -->
|
||||
<%= render partial: 'assets/asset_delete_modal' %>
|
||||
|
||||
<!-- Manage Stock Modal -->
|
||||
<%= render partial: 'shared/manage_stock_value_modal' %>
|
||||
|
||||
<!-- Consume Stock Modal -->
|
||||
<%= render partial: 'my_modules/repositories/consume_stock_modal'%>
|
||||
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
<div class="modal-dialog" role="document" data-e2e="e2e-MD-invNewInventory">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" data-e2e="e2e-BT-invNewInventory-close"><i class="sn-icon sn-icon-close"></i></button>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" data-e2e="e2e-BT-invNewInventoryMD-close"><i class="sn-icon sn-icon-close"></i></button>
|
||||
<h3 class="modal-title" id="create-repo-modal-label">
|
||||
<%= t("repositories.index.modal_create.title") %>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group sci-input-container" data-e2e="e2e-IF-invNewInventory-input">
|
||||
<div class="form-group sci-input-container">
|
||||
<label><%= t("repositories.index.modal_create.name_label") %> </label>
|
||||
<%= f.text_field :name,
|
||||
autofocus: true,
|
||||
|
@ -18,8 +18,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" data-e2e="e2e-BT-invNewInventory-cancel" class="btn btn-secondary" data-dismiss="modal"><%=t "general.cancel" %></button>
|
||||
<%= f.submit t("repositories.index.modal_create.submit"), class: "btn btn-success", 'data-e2e':"e2e-BT-invNewInventory-create" %>
|
||||
<button type="button" data-e2e="e2e-BT-invNewInventoryMD-cancel" class="btn btn-secondary" data-dismiss="modal"><%=t "general.cancel" %></button>
|
||||
<%= f.submit t("repositories.index.modal_create.submit"), class: "btn btn-success", 'data-e2e':"e2e-BT-invNewInventoryMD-create" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
<div class="modal fade" id="deleteRepositoryRecord" tabindex="-1" role="dialog" aria-labelledby="deleteRepositoryRecordLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-dialog" role="document" data-e2e="e2e-MD-invInventoryDeleteAT">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="sn-icon sn-icon-close"></i></button>
|
||||
<button type="button" data-e2e="e2e-BT-invInventoryDeleteMD-close" class="close" data-dismiss="modal" aria-label="Close"><i class="sn-icon sn-icon-close"></i></button>
|
||||
<h4 class="modal-title"><%= t("repositories.modal_delete_record.title") %></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<%= t("repositories.modal_delete_record.notice") %>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><%= t("general.cancel")%></button>
|
||||
<button type="button" class="btn btn-danger delete-record-modal-button" data-dismiss="modal">
|
||||
<button type="button" data-e2e="e2e-BT-invInventoryDeleteMD-cancel" class="btn btn-secondary" data-dismiss="modal"><%= t("general.cancel")%></button>
|
||||
<button type="button" data-e2e="e2e-BT-invInventoryDeleteMD-delete" class="btn btn-danger delete-record-modal-button" data-dismiss="modal">
|
||||
<%= t("repositories.modal_delete_record.delete") %>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
<%= form_with(url: export_repository_team_path(repository),
|
||||
html: { id: 'form-repository-rows-export' },
|
||||
data: { remote: true }) do |f| %>
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-dialog" role="document" data-e2e="e2e-MD-invInventoryExportAT">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="sn-icon sn-icon-close"></i></button>
|
||||
<button type="button" data-e2e="e2e-BT-invInventoryExportMD-close" class="close" data-dismiss="modal" aria-label="Close"><i class="sn-icon sn-icon-close"></i></button>
|
||||
<h4 class="modal-title"><%=t 'zip_export.repositories_modal_label' %></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
@ -18,7 +18,7 @@
|
|||
<div><%=t 'zip_export.repository_footer_html' %></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type='button' class='btn btn-secondary' data-dismiss='modal' id='close-modal-export-repository-rows'><%= t('general.cancel')%></button>
|
||||
<button type='button' data-e2e='e2e-BT-invInventoryExportMD-cancel' class='btn btn-secondary' data-dismiss='modal' id='close-modal-export-repository-rows'><%= t('general.cancel')%></button>
|
||||
<%= f.submit t('my_modules.repository.export'), id: "export-repository-rows", class: "btn btn-success" %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<div class="modal fade" id="modal-info-repository-row" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content" data-e2e="e2e-MD-invInventoryItem">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="sn-icon sn-icon-close" data-e2e="e2e-BT-invInventoryItem-cancel"></i></button>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="sn-icon sn-icon-close"></i></button>
|
||||
<h4 class="modal-title">
|
||||
<%= t('repository_row.modal_info.head_title', repository_row: @repository_row.name) %>
|
||||
<%= @repository_row.archived? ? I18n.t('atwho.res.archived') : '' %>
|
||||
|
@ -138,8 +138,8 @@
|
|||
</button>
|
||||
</span>
|
||||
<% else %>
|
||||
<button data-e2e="e2e-BT-invInventoryItem-close" type="button" class="btn btn-secondary" data-dismiss="modal"><%= t('general.close')%></button>
|
||||
<button data-e2e="e2e-BT-invInventoryItem-print" type="button" class="btn btn-primary print-label-button" data-rows="[<%= @repository_row.id %>]"><%= t('repository_row.modal_print_label.print_label') %></button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal"><%= t('general.close')%></button>
|
||||
<button type="button" class="btn btn-primary print-label-button" data-rows="[<%= @repository_row.id %>]"><%= t('repository_row.modal_print_label.print_label') %></button>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
data-snapshot-provisioning="<%= @snapshot_provisioning %>"
|
||||
data-status-url="<%= repository_status_path(@repository) %>">
|
||||
<thead>
|
||||
<tr class="repository-table-head-<%= repository.id %> hidden" data-e2e="e2e-RT-invInventory-tableHeadRow-<%= repository.id %>">
|
||||
<tr class="repository-table-head-<%= repository.id %> hidden" data-e2e="e2e-TR-invInventory-headRow-<%= repository.id %>">
|
||||
<th id="checkbox" data-unmanageable="true">
|
||||
<div class="sci-checkbox-container">
|
||||
<input name="select_all" value="1" type="checkbox" class="sci-checkbox">
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
<button class="btn btn-light btn-black icon-btn manage-repo-column-index" title="<%= t("libraries.manange_modal_column.button_tooltip") %>"
|
||||
data-modal-url="<%= repository_repository_columns_path(@repository) %>"
|
||||
data-action="new">
|
||||
<span class="sn-icon sn-icon sn-icon-reports">
|
||||
<span class="sn-icon sn-icon sn-icon-reports" data-e2e="e2e-BT-invInventoryRT-manageColumns">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -78,7 +78,6 @@
|
|||
|
||||
<%= render partial: 'repository_filters' %>
|
||||
<%= render partial: 'save_repository_filter_modal' %>
|
||||
<%= render partial: 'shared/manage_stock_value_modal' %>
|
||||
|
||||
|
||||
<%= javascript_include_tag 'vue_components_action_toolbar' %>
|
||||
|
|
|
@ -46,7 +46,9 @@
|
|||
<div class="task-notes">
|
||||
<div class="task-notes-content">
|
||||
<% if @my_module.description.present? %>
|
||||
<%= smart_annotation_text(@my_module.shareable_tinymce_render(:description)) %>
|
||||
<div class="rtf-view w-full">
|
||||
<%= smart_annotation_text(@my_module.shareable_tinymce_render(:description)) %>
|
||||
</div>
|
||||
<% else %>
|
||||
<span class="no-description"><%= t('my_modules.notes.no_description') %></span>
|
||||
<% end %>
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
<div>
|
||||
<div id="protocol-description-container" >
|
||||
<% if protocol.description.present? %>
|
||||
<div>
|
||||
<div class="rtf-view w-full">
|
||||
<%= smart_annotation_text(protocol.shareable_tinymce_render(:description)) %>
|
||||
</div>
|
||||
<% else %>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
</div>
|
||||
<% end %>
|
||||
<% if element.text.present? %>
|
||||
<div class="rounded min-h-[2.25rem] mb-4 relative group/text_container content__text-body">
|
||||
<div class="rtf-view w-full rounded min-h-[2.25rem] mb-4 relative group/text_container content__text-body">
|
||||
<%= smart_annotation_text(element.shareable_tinymce_render(:text)) %>
|
||||
</div>
|
||||
<% else %>
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
<div class="dropdown view-switch" >
|
||||
<div href="#" class="btn btn-light btn-black view-switch-button prevent-shrink <%= "disabled" if disabled %>" id="viewSwitchButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<span class="state-view-switch-btn-name"><%= archived ? t('toolbar.archived_state') : t('toolbar.active_state') %></span>
|
||||
<span class="state-view-switch-btn-name" data-e2e="e2e-TX-invInventoryViewSwitchRT-selected"><%= archived ? t('toolbar.archived_state') : t('toolbar.active_state') %></span>
|
||||
<span class="sn-icon sn-icon-down"></span>
|
||||
</div>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="viewSwitchButton">
|
||||
<% if switchable %>
|
||||
<li class="view-switch-active">
|
||||
<li class="view-switch-active" data-e2e="e2e-BT-invInventoryViewSwitchRT-active">
|
||||
<%= link_to active_url, class: "#{ 'form-dropdown-state-item prevent-shrink' unless archived }" do %>
|
||||
<%= t('toolbar.active_state') %>
|
||||
<% end %>
|
||||
</li>
|
||||
<li class="view-switch-archived">
|
||||
<li class="view-switch-archived" data-e2e="e2e-BT-invInventoryViewSwitchRT-archived">
|
||||
<%= link_to archived_url, class: "#{ 'form-dropdown-state-item prevent-shrink' if archived }" do %>
|
||||
<%= t('toolbar.archived_state') %>
|
||||
<% end %>
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="edit-webhook-container hidden">
|
||||
<%= form_with model: webhook, url: users_settings_webhook_path(webhook, filter_id: filter.id, sort: @current_sort), class: 'webhook-form', method: :patch do |f| %>
|
||||
<%= form_with model: webhook, url: users_settings_webhook_path(webhook, filter_id: filter.id, sort: @current_sort), class: 'webhook-form', method: :patch, data: { remote: true } do |f| %>
|
||||
<%= render partial: 'webhook_form', locals: {f: f} %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -112,6 +112,7 @@ Rails.application.config.assets.precompile += %w(reports/template_helpers.js)
|
|||
Rails.application.config.assets.precompile += %w(shareable_links/my_module_protocol_show.js)
|
||||
Rails.application.config.assets.precompile += %w(shareable_links/repositories.js)
|
||||
Rails.application.config.assets.precompile += %w(shareable_links/date_formatting.js)
|
||||
Rails.application.config.assets.precompile += %w(shareable_links/handson_table_wraping.js)
|
||||
Rails.application.config.assets.precompile += %w(shareable_links/my_module_results_show.js)
|
||||
|
||||
# Libraries needed for Handsontable formulas
|
||||
|
|
|
@ -220,7 +220,7 @@ en:
|
|||
configuration:
|
||||
disabled: 'Webhooks are disabled'
|
||||
url:
|
||||
not_valid: 'Not valid URL'
|
||||
not_valid: 'not valid URL'
|
||||
result_text:
|
||||
attributes:
|
||||
text:
|
||||
|
@ -1297,7 +1297,8 @@ en:
|
|||
16_x_24: '384 (16 x 24)'
|
||||
8_x_12: '96 (8 x 12)'
|
||||
6_x_8: '48 (6 x 8 )'
|
||||
6_x_4: '24 (6 x 4)'
|
||||
4_x_6: '24 (4 x 6)'
|
||||
3_x_4: '12 (3 x 4)'
|
||||
2_x_3: '6 (2 x 3)'
|
||||
text:
|
||||
placeholder: "Enter result text"
|
||||
|
@ -3310,7 +3311,8 @@ en:
|
|||
16_x_24: '384 (16 x 24)'
|
||||
8_x_12: '96 (8 x 12)'
|
||||
6_x_8: '48 (6 x 8 )'
|
||||
6_x_4: '24 (6 x 4)'
|
||||
4_x_6: '24 (4 x 6)'
|
||||
3_x_4: '12 (3 x 4)'
|
||||
2_x_3: '6 (2 x 3)'
|
||||
table:
|
||||
default_name: 'Table %{position}'
|
||||
|
|
|
@ -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',
|
||||
|
@ -960,6 +956,8 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
draw(:api_v2) if Rails.configuration.x.core_api_v2_enabled
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -81,6 +81,7 @@ namespace :v2, module: 'v1' do
|
|||
resources :step_texts, only: %i(index show create update destroy), path: 'step_texts'
|
||||
end
|
||||
end
|
||||
|
||||
get 'activities', to: 'tasks#activities'
|
||||
end
|
||||
end
|
||||
|
@ -112,6 +113,19 @@ namespace :v2 do
|
|||
resources :result_tables, only: %i(index show create update destroy), path: 'tables'
|
||||
resources :result_texts, only: %i(index show create update destroy)
|
||||
end
|
||||
|
||||
resources :protocols, only: :show do
|
||||
resources :steps, except: %i(new edit) do
|
||||
scope module: 'step_elements' do
|
||||
resources :assets, except: %i(new edit)
|
||||
resources :checklists, except: %i(new edit) do
|
||||
resources :checklist_items, except: %i(new edit), as: :items
|
||||
end
|
||||
resources :tables, except: %i(new edit)
|
||||
resources :texts, except: %i(new edit)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
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
|
||||
|
|
|
@ -3,6 +3,6 @@
|
|||
FactoryBot.define do
|
||||
factory :table do
|
||||
name { Faker::Name.unique.name }
|
||||
contents { { data: [%w(A B C), %w(D E F), %w(G H I)] } }
|
||||
contents { { data: [%w(A B C), %w(D E F), %w(G H I)] }.to_json }
|
||||
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
|
198
spec/requests/api/v2/step_elements/assets_controller_spec.rb
Normal file
198
spec/requests/api/v2/step_elements/assets_controller_spec.rb
Normal file
|
@ -0,0 +1,198 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api::V2::AssetsController', 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_assignment(@task, UserRole.find_by(name: I18n.t('user_roles.predefined.owner')), @user)
|
||||
|
||||
@valid_headers =
|
||||
{ 'Authorization': 'Bearer ' + generate_token(@user.id) }
|
||||
end
|
||||
|
||||
let(:asset) { create :asset, step: @step }
|
||||
|
||||
describe 'GET steps, #index' do
|
||||
context 'when has valid params' do
|
||||
it 'renders 200' do
|
||||
create(:step_asset, step: @step, asset: asset)
|
||||
|
||||
get(api_v2_team_project_experiment_task_protocol_step_assets_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 protocol is not found' do
|
||||
it 'renders 404' do
|
||||
get(api_v2_team_project_experiment_task_protocol_step_assets_path(
|
||||
team_id: @team.id,
|
||||
project_id: @project.id,
|
||||
experiment_id: @experiment.id,
|
||||
task_id: @task.id,
|
||||
protocol_id: -1,
|
||||
step_id: @step.id
|
||||
), headers: @valid_headers)
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET step, #show' do
|
||||
context 'when has valid params' do
|
||||
it 'renders 200' do
|
||||
create(:step_asset, step: @step, asset: asset)
|
||||
|
||||
get(api_v2_team_project_experiment_task_protocol_step_asset_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: asset.id
|
||||
), headers: @valid_headers)
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when experiment is not found' do
|
||||
it 'renders 404' do
|
||||
get(api_v2_team_project_experiment_task_protocol_step_asset_path(
|
||||
team_id: @team.id,
|
||||
project_id: @project.id,
|
||||
experiment_id: -1,
|
||||
task_id: @task.id,
|
||||
protocol_id: @protocol.id,
|
||||
step_id: @step.id,
|
||||
id: asset.id
|
||||
), headers: @valid_headers)
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when asset is not found' do
|
||||
it 'renders 404' do
|
||||
get(api_v2_team_project_experiment_task_protocol_step_asset_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: -1
|
||||
), headers: @valid_headers)
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST step, #create' do
|
||||
before :all do
|
||||
@valid_headers['Content-Type'] = 'application/json'
|
||||
end
|
||||
|
||||
before :each do
|
||||
allow_any_instance_of(Asset).to receive(:post_process_file)
|
||||
end
|
||||
|
||||
let(:action) do
|
||||
post(api_v2_team_project_experiment_task_protocol_step_assets_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,
|
||||
headers: @valid_headers)
|
||||
end
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'attachments',
|
||||
attributes: attributes
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
context 'when has valid params' do
|
||||
context 'when multipart form' do
|
||||
let(:file) { Rack::Test::UploadedFile.new(file_fixture('test.jpg').open) }
|
||||
let(:attributes) { { file: file } }
|
||||
|
||||
it 'creates new asset' do
|
||||
expect { action }.to change { Asset.count }.by(1)
|
||||
end
|
||||
|
||||
it 'returns status 201' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status 201
|
||||
end
|
||||
|
||||
it 'calls post_process_file function for text extraction' do
|
||||
expect_any_instance_of(Asset).to receive(:post_process_file)
|
||||
|
||||
action
|
||||
end
|
||||
end
|
||||
|
||||
context 'when base64 with json' do
|
||||
let(:filedata_base64) do
|
||||
'iVBORw0KGgoAAAANSUhEUgAAAAIAA'\
|
||||
'AACCAIAAAD91JpzAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAE0lE'\
|
||||
'QVQIHWP8//8/AwMDExADAQAkBgMBOOSShwAAAABJRU5ErkJggg=='
|
||||
end
|
||||
let(:attributes) { { file_data: filedata_base64, file_name: 'file.png', file_type: 'image/png' } }
|
||||
let(:request_body) { super().to_json }
|
||||
|
||||
it 'creates new asset' do
|
||||
expect { action }.to change { Asset.count }.by(1)
|
||||
end
|
||||
|
||||
it 'returns status 201' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status 201
|
||||
end
|
||||
|
||||
it 'calls post_process_file function for text extraction' do
|
||||
expect_any_instance_of(Asset).to receive(:post_process_file)
|
||||
|
||||
action
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when has missing param' do
|
||||
let(:request_body) { { data: { type: 'attachments', attributes: {} } } }
|
||||
|
||||
it 'renders 400' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status(400)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,234 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api::V2::ChecklistsController', type: :request do
|
||||
before :all do
|
||||
@user = create(:user)
|
||||
@team = create(:team, created_by: @user)
|
||||
@project = create(:project, team: @team, created_by: @user)
|
||||
@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)
|
||||
|
||||
@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_v2_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_v2_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_v2_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
|
||||
end
|
||||
|
||||
describe 'POST checklist_item, #create' do
|
||||
let(:action) do
|
||||
post(api_v2_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_v2_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_v2_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
|
226
spec/requests/api/v2/step_elements/checklists_controller_spec.rb
Normal file
226
spec/requests/api/v2/step_elements/checklists_controller_spec.rb
Normal file
|
@ -0,0 +1,226 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api::V2::ChecklistsController', type: :request do
|
||||
before :all do
|
||||
@user = create(:user)
|
||||
@team = create(:team, created_by: @user)
|
||||
@project = create(:project, team: @team, created_by: @user)
|
||||
@experiment = create(:experiment, :with_tasks, project: @project)
|
||||
@task = @experiment.my_modules.first
|
||||
@protocol = create(:protocol, my_module: @task)
|
||||
@step = create(:step, protocol: @protocol)
|
||||
@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_v2_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_v2_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_v2_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
|
||||
end
|
||||
|
||||
describe 'POST checklist, #create' do
|
||||
let(:action) do
|
||||
post(api_v2_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_v2_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_v2_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
|
230
spec/requests/api/v2/step_elements/tables_controller_spec.rb
Normal file
230
spec/requests/api/v2/step_elements/tables_controller_spec.rb
Normal file
|
@ -0,0 +1,230 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api::V2::StepElements::TablesController', type: :request do
|
||||
before :all do
|
||||
@user = create(:user)
|
||||
@team = create(:team, created_by: @user)
|
||||
@project = create(:project, team: @team, created_by: @user)
|
||||
@experiment = create(:experiment, :with_tasks, project: @project, created_by: @user)
|
||||
@task = @experiment.my_modules.first
|
||||
@protocol = create(:protocol, my_module: @task)
|
||||
@step = create(:step, protocol: @protocol)
|
||||
|
||||
@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_v2_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_v2_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_v2_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
|
||||
end
|
||||
|
||||
describe 'POST table, #create' do
|
||||
let(:action) do
|
||||
post(api_v2_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_v2_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_v2_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
|
227
spec/requests/api/v2/step_elements/texts_controller_spec.rb
Normal file
227
spec/requests/api/v2/step_elements/texts_controller_spec.rb
Normal file
|
@ -0,0 +1,227 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api::V2::StepElements::TextsController', type: :request do
|
||||
before :all do
|
||||
@user = create(:user)
|
||||
@team = create(:team, created_by: @user)
|
||||
@project = create(:project, team: @team, created_by: @user)
|
||||
@experiment = create(:experiment, :with_tasks, project: @project, created_by: @user)
|
||||
@task = @experiment.my_modules.first
|
||||
@protocol = create(:protocol, my_module: @task)
|
||||
@step = create(:step, protocol: @protocol)
|
||||
|
||||
@valid_headers = {
|
||||
'Authorization': 'Bearer ' + generate_token(@user.id),
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
end
|
||||
|
||||
describe 'GET texts, #index' do
|
||||
context 'when has valid params' do
|
||||
it 'renders 200' do
|
||||
get api_v2_team_project_experiment_task_protocol_step_texts_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_v2_team_project_experiment_task_protocol_step_texts_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 step_text, #show' do
|
||||
let(:step_text) { create(:step_text, step: @step) }
|
||||
|
||||
context 'when has valid params' do
|
||||
it 'renders 200' do
|
||||
get api_v2_team_project_experiment_task_protocol_step_text_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: step_text.id
|
||||
), headers: @valid_headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST step_text, #create' do
|
||||
let(:action) do
|
||||
post(api_v2_team_project_experiment_task_protocol_step_texts_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: 'step_texts',
|
||||
attributes: {
|
||||
text: "<p>Hello!</p>"
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates new step_text' do
|
||||
expect { action }.to change { StepText.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: 'step_texts',
|
||||
attributes: hash_including(text: '<p>Hello!</p>')
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when has missing param' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'step_texts',
|
||||
attributes: {
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'renders 400' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status(400)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PATCH step_text, #update' do
|
||||
let(:step_text) { create(:step_text, step: @step) }
|
||||
let(:action) do
|
||||
patch(api_v2_team_project_experiment_task_protocol_step_text_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: step_text.id
|
||||
), params: request_body.to_json, headers: @valid_headers)
|
||||
end
|
||||
|
||||
context 'when has valid params' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'step_texts',
|
||||
attributes: {
|
||||
text: '<h1>Hello!</h1>'
|
||||
}
|
||||
}
|
||||
}
|
||||
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: 'step_texts',
|
||||
attributes: hash_including(
|
||||
text: '<h1>Hello!</h1>'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when has missing param' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'step_texts',
|
||||
attributes: {
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'renders 400' do
|
||||
action
|
||||
|
||||
expect(response).to have_http_status(400)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE step_text, #destroy' do
|
||||
let(:step_text) { create(:step_text, step: @step) }
|
||||
let(:action) do
|
||||
delete(api_v2_team_project_experiment_task_protocol_step_text_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: step_text.id
|
||||
), headers: @valid_headers)
|
||||
end
|
||||
|
||||
it 'deletes step_text' do
|
||||
action
|
||||
expect(response).to have_http_status(200)
|
||||
expect(StepText.where(id: step_text.id)).to_not exist
|
||||
end
|
||||
end
|
||||
end
|
280
spec/requests/api/v2/steps_controller_spec.rb
Normal file
280
spec/requests/api/v2/steps_controller_spec.rb
Normal file
|
@ -0,0 +1,280 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api::V2::StepsController', type: :request do
|
||||
before :all do
|
||||
@user = create(:user)
|
||||
@team = create(:team, created_by: @user)
|
||||
@project = create(:project, team: @team, created_by: @user)
|
||||
@experiment = create(:experiment, :with_tasks, project: @project, created_by: @user)
|
||||
@task = @experiment.my_modules.first
|
||||
|
||||
@valid_headers =
|
||||
{ 'Authorization': 'Bearer ' + generate_token(@user.id) }
|
||||
end
|
||||
|
||||
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
|
||||
it 'renders 200' do
|
||||
get api_v2_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
|
||||
), headers: @valid_headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when has valid params, with rendered RTE field' do
|
||||
it 'renders 200' do
|
||||
get api_v2_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_v2_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: -1
|
||||
), headers: @valid_headers
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET step, #show' do
|
||||
context 'when has valid params' do
|
||||
it 'renders 200' do
|
||||
get api_v2_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: steps.first.id
|
||||
), headers: @valid_headers
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST step, #create' do
|
||||
before :all do
|
||||
@valid_headers['Content-Type'] = 'application/json'
|
||||
end
|
||||
|
||||
let(:action) do
|
||||
post(api_v2_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: request_body.to_json,
|
||||
headers: @valid_headers)
|
||||
end
|
||||
|
||||
context 'when has valid params' do
|
||||
let(:request_body) do
|
||||
{
|
||||
data: {
|
||||
type: 'steps',
|
||||
attributes: {
|
||||
name: 'Step name',
|
||||
description: 'Description about step'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates new step' do
|
||||
expect { action }.to change { Step.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: 'steps',
|
||||
attributes: hash_including(name: 'Step name')
|
||||
)
|
||||
)
|
||||
)
|
||||
expect(json).to match(
|
||||
hash_including(
|
||||
data: hash_including(
|
||||
type: 'steps',
|
||||
attributes: hash_not_including(:description)
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets the last_changed_by' do
|
||||
action
|
||||
|
||||
expect(Step.find(json['data']['id']).last_modified_by_id).to be @user.id
|
||||
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 'PATCH step, #update' do
|
||||
before :all do
|
||||
@valid_headers['Content-Type'] = 'application/json'
|
||||
end
|
||||
|
||||
let(:action) do
|
||||
patch(
|
||||
api_v2_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')
|
||||
)
|
||||
)
|
||||
)
|
||||
expect(json).to match(
|
||||
hash_including(
|
||||
data: hash_including(
|
||||
type: 'steps',
|
||||
attributes: hash_not_including(:description)
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets the last_changed_by' do
|
||||
action
|
||||
expect(Step.find(json['data']['id']).last_modified_by_id).to be @user.id
|
||||
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_v2_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,
|
||||
data: {attributes: {name: 'Test'}, type: "steps"}
|
||||
),
|
||||
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
|
Loading…
Reference in a new issue