enables copying of repository items [fixes SCI-2207]

This commit is contained in:
zmagod 2018-04-11 17:17:19 +02:00
parent eca69cfc75
commit 6291857bbf
9 changed files with 234 additions and 7 deletions

View file

@ -565,6 +565,29 @@ var RepositoryDatatable = (function(global) {
});
}
global.onClickCopyRepositoryRecords = function() {
animateSpinner();
$.ajax({
url: $('table' + TABLE_ID).data('copy-records'),
type: 'POST',
dataType: 'json',
data: { selected_rows: rowsSelected },
success: function(data) {
HelperModule.flashAlertMsg(data.flash, 'success');
rowsSelected = [];
onClickCancel();
},
error: function(e) {
if (e.status === 403) {
HelperModule.flashAlertMsg(
I18n.t('repositories.js.permission_error'), e.responseJSON.style
);
}
}
});
}
// Edit record
global.onClickEdit = function() {
if (rowsSelected.length !== 1) {
@ -768,6 +791,8 @@ var RepositoryDatatable = (function(global) {
$('.repository-row-selector').removeClass('disabled');
$('.repository-row-selector').prop('disabled', false);
if (rowsSelected.length === 0) {
$('#copyRepositoryRecords').prop('disabled', true);
$('#copyRepositoryRecords').addClass('disabled');
$('#editRepositoryRecord').prop('disabled', true);
$('#editRepositoryRecord').addClass('disabled');
$('#deleteRepositoryRecordsButton').prop('disabled', true);
@ -805,6 +830,8 @@ var RepositoryDatatable = (function(global) {
}
$('#deleteRepositoryRecordsButton').prop('disabled', false);
$('#deleteRepositoryRecordsButton').removeClass('disabled');
$('#copyRepositoryRecords').prop('disabled', false);
$('#copyRepositoryRecords').removeClass('disabled');
$('#assignRepositoryRecords').removeClass('disabled');
$('#assignRepositoryRecords').prop('disabled', false);
$('#unassignRepositoryRecords').removeClass('disabled');

View file

@ -5,9 +5,11 @@ class RepositoryRowsController < ApplicationController
before_action :load_info_modal_vars, only: :show
before_action :load_vars, only: %i(edit update)
before_action :load_repository, only: %i(create delete_records index)
before_action :load_repository,
only: %i(create delete_records index copy_records)
before_action :check_create_permissions, only: :create
before_action :check_manage_permissions, only: %i(edit update delete_records)
before_action :check_manage_permissions,
only: %i(edit update delete_records copy_records)
def index
@draw = params[:draw].to_i
@ -276,6 +278,17 @@ class RepositoryRowsController < ApplicationController
end
end
def copy_records
duplicate_service = RepositoryActions::Duplicate.new(current_user,
@repository,
params[:selected_rows])
duplicate_service.call
render json: {
flash: t('repositories.copy_records_report',
number: duplicate_service.number_of_duplicated_items)
}, status: :ok
end
private
def load_info_modal_vars

View file

@ -0,0 +1,57 @@
# frozen_string_literal: true
require 'repository_actions/repository_cell_resolver'
module RepositoryActions
class Duplicate
attr_reader :number_of_duplicated_items
def initialize(user, repository, rows_to_copy = [])
@user = user
@repository = repository
@rows_to_copy = rows_to_copy.map(&:to_i).uniq
@number_of_duplicated_items = 0
end
def call
sanitize_rows_to_copy
@rows_to_copy.each do |row_id|
copy_row(row_id)
end
end
private
def sanitize_rows_to_copy
ids = @repository.repository_rows.pluck(:id)
@rows_to_copy.map! { |el| ids.include?(el) ? el : nil }.compact!
end
def copy_row(id)
row = RepositoryRow.find_by_id(id)
new_row = RepositoryRow.new(
row.attributes.merge(new_row_attributes(row.name))
)
if new_row.save
@number_of_duplicated_items += 1
row.repository_cells.each do |cell|
copy_repository_cell(cell, new_row)
end
end
end
def new_row_attributes(name)
timestamp = DateTime.now
{ id: nil,
name: "#{name} (1)",
created_at: timestamp,
updated_at: timestamp }
end
def copy_repository_cell(cell, new_row)
RepositoryActions::RepositoryCellResolver.new(cell,
new_row,
@user.current_team).call
end
end
end

View file

@ -0,0 +1,113 @@
# frozen_string_literal: true
module RepositoryActions
class RepositoryCellResolver
def initialize(cell, new_row, team)
@cell = cell
@new_row = new_row
@team = team
end
def call
case @cell.value_type
when 'RepositoryListValue'
clone_repository_list_value
when 'RepositoryTextValue'
clone_repository_text_value
when 'RepositoryAssetValue'
clone_repository_asset_value
when 'RepositoryDateValue'
clone_repository_date_value
end
end
private
def clone_repository_list_value
old_value = @cell.value
RepositoryListValue.create(
old_value.attributes.merge(id: nil,
repository_cell_attributes: {
repository_row: @new_row,
repository_column: @cell.repository_column
})
)
end
def clone_repository_text_value
old_value = @cell.value
RepositoryTextValue.create(
old_value.attributes.merge(id: nil,
repository_cell_attributes: {
repository_row: @new_row,
repository_column: @cell.repository_column
})
)
end
def clone_repository_asset_value
old_value = @cell.value
new_asset = create_new_asset(old_value.asset)
RepositoryAssetValue.create(
old_value.attributes.merge(
id: nil,
asset: new_asset,
repository_cell_attributes: {
repository_row: @new_row,
repository_column: @cell.repository_column
}
)
)
end
def clone_repository_date_value
old_value = @cell.value
RepositoryDateValue.create(
old_value.attributes.merge(id: nil,
repository_cell_attributes: {
repository_row: @new_row,
repository_column: @cell.repository_column
})
)
end
# reuses the same code we have in copy protocols action
def create_new_asset(old_asset)
new_asset = Asset.new_empty(
old_asset.file_file_name,
old_asset.file_file_size
)
new_asset.created_by = old_asset.created_by
new_asset.team = old_asset.team
new_asset.last_modified_by = old_asset.last_modified_by
new_asset.file_processing = true if old_asset.is_image?
new_asset.file = old_asset.file
new_asset.save
return unless new_asset.valid?
if new_asset.is_image?
new_asset.file.reprocess!(:large)
new_asset.file.reprocess!(:medium)
end
# Clone extracted text data if it exists
if old_asset.asset_text_datum
AssetTextDatum.create(data: new_asset.data, asset: new_asset)
end
# Update estimated size of cloned asset
# (& file_present flag)
new_asset.update(
estimated_size: old_asset.estimated_size,
file_present: true
)
# Update team's space taken
@team.reload
@team.take_space(new_asset.estimated_size)
@team.save!
new_asset
end
end
end

View file

@ -6,6 +6,7 @@
data-num-columns="<%= 6 + repository.repository_columns.count %>"
data-create-record="<%= repository_repository_rows_path(repository) %>"
data-delete-record="<%= repository_delete_records_path(repository) %>"
data-copy-records="<%= repository_copy_records_path(repository) %>"
data-max-dropdown-length="<%= Constants::NAME_TRUNCATION_LENGTH_DROPDOWN %>"
data-save-text="<%= I18n.t('general.save') %>"
data-edit-text="<%= I18n.t('general.edit') %>"

View file

@ -105,12 +105,11 @@
<!-- These buttons are appended to table in javascript, after table initialization -->
<div class="toolbarButtons" style="display:none">
<% if can_manage_repository_rows?(@repository.team) %>
<button type="button" class="btn btn-default editAdd" id="editRepositoryRecord" onclick="onClickEdit()" disabled>
<span class="glyphicon glyphicon-pencil"></span>
<span class="hidden-xs-custom"><%= t("repositories.edit_record") %></span>
</button>
<% if can_manage_repository_rows?(@repository.team) %>
<button type="button" class="btn btn-default"
id="deleteRepositoryRecordsButton" data-target="#deleteRepositoryRecord" data-toggle="modal" disabled>
<span class="glyphicon glyphicon-trash"></span>
@ -118,6 +117,10 @@
<%= submit_tag I18n.t('repositories.delete_record'), :class => "hidden
delete_repository_records_submit" %>
</button>
<button type="button" class="btn btn-default copyRow" id="copyRepositoryRecords" onclick="onClickCopyRepositoryRecords()" disabled>
<span class="glyphicon glyphicon-duplicate"></span>
<span class="hidden-xs-custom"><%= t("repositories.copy_record") %></span>
</button>
<% end %>
</div>

View file

@ -941,6 +941,7 @@ en:
errors_list_title: "Items were not imported because one or more errors were found:"
no_repository_name: "Item name is required!"
edit_record: "Edit"
copy_record: "Copy"
delete_record: "Delete"
save_record: "Save"
cancel_save: "Cancel"
@ -993,6 +994,7 @@ en:
no_records_assigned_flash: "No items were assigned to task"
no_records_unassigned_flash: "No items were unassigned from task"
default_column: 'Name'
copy_records_report: "%{number} item(s) successfully copied."
libraries:
manange_modal_column:

View file

@ -467,6 +467,9 @@ Rails.application.routes.draw do
to: 'repository_rows#delete_records',
as: 'delete_records',
defaults: { format: 'json' }
post 'copy_records',
to: 'repository_rows#copy_records',
defaults: { format: 'json' }
get 'repository_columns/:id/destroy_html',
to: 'repository_columns#destroy_html',
as: 'columns_destroy_html'

View file

@ -115,4 +115,12 @@ describe RepositoryRowsController, type: :controller do
end
end
end
describe 'POST #copy_records' do
it 'returns a success response' do
post :copy_records, params: { repository_id: repository.id,
selected_rows: [repository_row.id] }
expect(response).to have_http_status(:success)
end
end
end