mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-26 01:35:34 +08:00
enables copying of repository items [fixes SCI-2207]
This commit is contained in:
parent
eca69cfc75
commit
6291857bbf
9 changed files with 234 additions and 7 deletions
|
@ -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');
|
||||
|
|
|
@ -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
|
||||
|
|
57
app/services/repository_actions/duplicate.rb
Normal file
57
app/services/repository_actions/duplicate.rb
Normal 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
|
113
app/services/repository_actions/repository_cell_resolver.rb
Normal file
113
app/services/repository_actions/repository_cell_resolver.rb
Normal 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
|
|
@ -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') %>"
|
||||
|
|
|
@ -105,12 +105,11 @@
|
|||
|
||||
<!-- These buttons are appended to table in javascript, after table initialization -->
|
||||
<div class="toolbarButtons" style="display:none">
|
||||
<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 editAdd" id="editRepositoryRecord" onclick="onClickEdit()" disabled>
|
||||
<span class="glyphicon glyphicon-pencil"></span>
|
||||
<span class="hidden-xs-custom"><%= t("repositories.edit_record") %></span>
|
||||
</button>
|
||||
<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>
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue