mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-27 10:14:17 +08:00
494 lines
19 KiB
Ruby
494 lines
19 KiB
Ruby
class RepositoryRowsController < ApplicationController
|
|
include InputSanitizeHelper
|
|
include ActionView::Helpers::TextHelper
|
|
include ApplicationHelper
|
|
include MyModulesHelper
|
|
include RepositoryDatatableHelper
|
|
include StorageLocationsHelper
|
|
|
|
before_action :load_repository, except: %i(show print rows_to_print print_zpl validate_label_template_columns)
|
|
before_action :load_repository_or_snapshot, only: %i(show print rows_to_print print_zpl
|
|
validate_label_template_columns)
|
|
before_action :load_repository_row, only: %i(show update update_cell assigned_task_list
|
|
active_reminder_repository_cells relationships)
|
|
before_action :load_repository_rows, only: %i(print rows_to_print print_zpl validate_label_template_columns)
|
|
|
|
before_action :check_read_permissions, except: %i(create update update_cell delete_records
|
|
copy_records archive_records restore_records)
|
|
before_action :check_snapshotting_status, only: %i(create update delete_records copy_records)
|
|
before_action :check_create_permissions, only: :create
|
|
before_action :check_delete_permissions, only: %i(delete_records archive_records restore_records)
|
|
before_action :check_manage_permissions, only: %i(update update_cell copy_records)
|
|
|
|
def index
|
|
@draw = params[:draw].to_i
|
|
per_page = params[:length] == '-1' ? 100 : params[:length].to_i
|
|
page = (params[:start].to_i / per_page) + 1
|
|
datatable_service = RepositoryDatatableService.new(@repository, params, current_user)
|
|
|
|
@all_rows_count = datatable_service.all_count
|
|
@columns_mappings = datatable_service.mappings
|
|
repository_rows = datatable_service.repository_rows
|
|
repository_rows = repository_rows.where(archived: params[:archived]) unless @repository.archived?
|
|
@repository_rows = repository_rows.page(page).per(per_page)
|
|
@filtered_rows_count = @repository_rows.load.take&.filtered_count || 0
|
|
rescue RepositoryFilters::ColumnNotFoundException
|
|
render json: { custom_error: I18n.t('repositories.show.repository_filter.errors.column_not_found') }
|
|
rescue RepositoryFilters::ValueNotFoundException
|
|
render json: { custom_error: I18n.t('repositories.show.repository_filter.errors.value_not_found') }
|
|
end
|
|
|
|
def show
|
|
respond_to do |format|
|
|
format.html do
|
|
redirect_to repository_path(@repository)
|
|
end
|
|
|
|
format.json do
|
|
@my_module = if params[:my_module_id].present?
|
|
MyModule.repository_row_assignable_by_user(current_user).find_by(id: params[:my_module_id])
|
|
end
|
|
return render_403 if @my_module && !can_read_my_module?(@my_module)
|
|
|
|
if @my_module
|
|
@my_module_assign_error = if !can_assign_my_module_repository_rows?(@my_module)
|
|
I18n.t('repository_row.modal_info.assign_to_task_error.no_access')
|
|
elsif @repository_row.my_modules.where(id: @my_module.id).any?
|
|
I18n.t('repository_row.modal_info.assign_to_task_error.already_assigned')
|
|
end
|
|
end
|
|
|
|
@assigned_modules = @repository_row.my_modules
|
|
.joins(experiment: :project)
|
|
.joins(:my_module_repository_rows)
|
|
.select('my_module_repository_rows.created_at, my_modules.*')
|
|
.order('my_module_repository_rows.created_at': :desc)
|
|
.distinct
|
|
@viewable_modules = @assigned_modules.viewable_by_user(current_user, current_user.teams)
|
|
@reminders_present = @repository_row.repository_cells.with_active_reminder(@current_user).any?
|
|
end
|
|
end
|
|
end
|
|
|
|
def create
|
|
service = RepositoryRows::CreateRepositoryRowService
|
|
.call(repository: @repository, user: current_user, params: update_params)
|
|
|
|
if service.succeed?
|
|
repository_row = service.repository_row
|
|
log_activity(:create_item_inventory, repository_row, { repository_row: repository_row.id,
|
|
repository: @repository.id })
|
|
repository_row.repository_cells.where(value_type: 'RepositoryTextValue').each do |repository_cell|
|
|
record_annotation_notification(repository_row, repository_cell)
|
|
end
|
|
|
|
render json: { id: service.repository_row.id, flash: t('repositories.create.success_flash',
|
|
record: escape_input(repository_row.name),
|
|
repository: escape_input(@repository.name)) },
|
|
status: :ok
|
|
else
|
|
render json: service.errors, status: :bad_request
|
|
end
|
|
end
|
|
|
|
def validate_label_template_columns
|
|
label_template = LabelTemplate.where(team_id: current_team.id).find(params[:label_template_id])
|
|
|
|
label_code = LabelTemplates::RepositoryRowService.new(label_template, @repository_rows.first).render
|
|
if label_code[:error].empty?
|
|
render json: { label_code: label_code[:label] }
|
|
else
|
|
render json: { error: label_code[:error].first, label_code: label_code[:label] }, status: :unprocessable_entity
|
|
end
|
|
end
|
|
|
|
def print_zpl
|
|
label_template = LabelTemplate.find_by(id: params[:label_template_id])
|
|
labels = @repository_rows.flat_map do |repository_row|
|
|
LabelTemplates::RepositoryRowService.new(label_template,
|
|
repository_row).render[:label]
|
|
end
|
|
|
|
render(
|
|
json: {
|
|
html:
|
|
render_to_string(
|
|
partial: 'label_printers/print_zebra_progress_modal'
|
|
),
|
|
labels: labels
|
|
}
|
|
)
|
|
end
|
|
|
|
def rows_to_print
|
|
render json: @repository_rows, each_serializer: RepositoryRowSerializer, user: current_user
|
|
end
|
|
|
|
def print
|
|
# reset all potential error states for printers and discard all jobs
|
|
|
|
# rubocop:disable Rails/SkipsModelValidations
|
|
LabelPrinter.update_all(status: :ready, current_print_job_ids: [])
|
|
# rubocop:enable Rails/SkipsModelValidations
|
|
|
|
label_printer = LabelPrinter.find(params[:label_printer_id])
|
|
label_template = LabelTemplate.find_by(id: params[:label_template_id])
|
|
|
|
job_ids = @repository_rows.flat_map do |repository_row|
|
|
LabelPrinters::PrintJob.perform_later(
|
|
label_printer,
|
|
LabelTemplates::RepositoryRowService.new(label_template,
|
|
repository_row).render[:label],
|
|
params[:copies].to_i
|
|
).job_id
|
|
end
|
|
|
|
label_printer.update!(current_print_job_ids: job_ids * params[:copies].to_i)
|
|
|
|
render json: {
|
|
html: render_to_string(
|
|
partial: 'label_printers/print_progress_modal',
|
|
locals: { starting_item_count: label_printer.current_print_job_ids.length,
|
|
label_printer: label_printer }
|
|
)
|
|
}
|
|
end
|
|
|
|
def update
|
|
row_update = RepositoryRows::UpdateRepositoryRowService
|
|
.call(repository_row: @repository_row, user: current_user, params: update_params)
|
|
|
|
if row_update.succeed?
|
|
if row_update.record_updated
|
|
log_activity(:edit_item_inventory, @repository_row, { repository_row: @repository_row.id,
|
|
repository: @repository.id })
|
|
@repository_row.repository_cells.where(value_type: 'RepositoryTextValue').each do |repository_cell|
|
|
record_annotation_notification(@repository_row, repository_cell)
|
|
end
|
|
end
|
|
|
|
render json: {
|
|
id: @repository_row.id,
|
|
flash: t(
|
|
'repositories.update.success_flash',
|
|
record: escape_input(@repository_row.name),
|
|
repository: escape_input(@repository.name)
|
|
)
|
|
}, status: :ok
|
|
else
|
|
render json: row_update.errors, status: :bad_request
|
|
end
|
|
end
|
|
|
|
def update_cell
|
|
return render_422(t('.invalid_params')) if
|
|
update_params['repository_row'].present? && update_params['repository_cells'].present?
|
|
return render_422(t('.invalid_params')) if
|
|
update_params['repository_cells'] && update_params['repository_cells'].size != 1
|
|
|
|
row_cell_update =
|
|
RepositoryRows::UpdateRepositoryRowService.call(
|
|
repository_row: @repository_row, user: current_user, params: update_params
|
|
)
|
|
|
|
if row_cell_update.succeed?
|
|
if row_cell_update.record_updated
|
|
log_activity(:edit_item_field_inventory, @repository_row,
|
|
{ repository_row: @repository_row.id,
|
|
repository_column: update_params['repository_cells']&.keys&.first ||
|
|
I18n.t('repositories.table.row_name') })
|
|
end
|
|
@reminders_present = @repository_row.repository_cells.with_active_reminder(@current_user).any?
|
|
|
|
return render json: { name: @repository_row.name } if update_params['repository_row'].present?
|
|
|
|
column = row_cell_update.column
|
|
cell = row_cell_update.cell&.reload || row_cell_update.cell
|
|
data = { value_type: column.data_type, id: column.id, value: nil }
|
|
|
|
return render json: data if cell.blank?
|
|
|
|
data['hasActiveReminders'] = @reminders_present
|
|
data.merge! serialize_repository_cell_value(cell,
|
|
@repository.team,
|
|
@repository,
|
|
reminders_enabled: @reminders_present)
|
|
render json: data
|
|
else
|
|
render json: row_cell_update.errors, status: :bad_request
|
|
end
|
|
end
|
|
|
|
def delete_records
|
|
deleted_count = 0
|
|
if selected_params
|
|
selected_params.each do |row_id|
|
|
row = @repository.repository_rows.find_by(id: row_id)
|
|
next unless row && can_manage_repository_rows?(@repository)
|
|
|
|
log_activity(:delete_item_inventory, row, { repository_row: row.id, repository: @repository.id })
|
|
row.destroy && deleted_count += 1
|
|
end
|
|
if deleted_count.zero?
|
|
flash = t('repositories.destroy.no_deleted_records_flash',
|
|
other_records_number: selected_params.count)
|
|
elsif deleted_count != selected_params.count
|
|
not_deleted_count = selected_params.count - deleted_count
|
|
flash = t('repositories.destroy.contains_other_records_flash',
|
|
records_number: deleted_count,
|
|
other_records_number: not_deleted_count)
|
|
else
|
|
flash = t('repositories.destroy.success_flash',
|
|
records_number: deleted_count)
|
|
end
|
|
color = deleted_count.zero? ? 'info' : 'success'
|
|
render json: { flash: flash, color: color }, status: :ok
|
|
else
|
|
render json: {
|
|
flash: t('repositories.destroy.no_records_selected_flash')
|
|
}, status: :bad_request
|
|
end
|
|
end
|
|
|
|
def copy_records
|
|
duplicate_service = RepositoryActions::DuplicateRows.new(
|
|
current_user, @repository, selected_rows_in_repo_params
|
|
)
|
|
duplicate_service.call
|
|
render json: {
|
|
flash: t('repositories.copy_records_report',
|
|
number: duplicate_service.number_of_duplicated_items)
|
|
}, status: :ok
|
|
end
|
|
|
|
def available_rows
|
|
if @repository.repository_rows.active.blank?
|
|
no_items_string =
|
|
"#{t('projects.reports.new.save_PDF_to_inventory_modal.no_items')} " \
|
|
"#{link_to(t('projects.reports.new.save_PDF_to_inventory_modal.here'),
|
|
repository_path(@repository),
|
|
data: { 'no-turbolink' => true })}"
|
|
render json: { no_items: no_items_string }, status: :unprocessable_entity
|
|
else
|
|
render json: { results: load_available_rows }, status: :ok
|
|
end
|
|
end
|
|
|
|
def assigned_task_list
|
|
assigned_modules = @repository_row.my_modules.joins(experiment: :project)
|
|
.where_attributes_like(
|
|
['my_modules.name', 'experiments.name', 'projects.name'],
|
|
params[:query],
|
|
whole_phrase: true
|
|
)
|
|
viewable_modules = assigned_modules.viewable_by_user(current_user, current_user.teams)
|
|
private_modules_number = assigned_modules.where.not(id: viewable_modules).count
|
|
render json: {
|
|
html: render_to_string(partial: 'shared/my_modules_list_partial', locals: {
|
|
my_modules: viewable_modules,
|
|
private_modules_number: private_modules_number
|
|
})
|
|
}
|
|
end
|
|
|
|
def reminder_repository_cells
|
|
render json: @repository_row.repository_cells.with_active_reminder(current_user)
|
|
end
|
|
|
|
def archive_records
|
|
service = RepositoryActions::ArchiveRowsService.call(repository: @repository,
|
|
repository_rows: selected_rows_in_repo_params,
|
|
user: current_user,
|
|
team: current_team)
|
|
|
|
if service.succeed?
|
|
render json: { flash: t('repositories.archive_records.success_flash', repository: escape_input(@repository.name)) }
|
|
else
|
|
render json: { error: service.error_message }, status: :unprocessable_entity
|
|
end
|
|
end
|
|
|
|
def restore_records
|
|
service = RepositoryActions::RestoreRowsService.call(repository: @repository,
|
|
repository_rows: selected_rows_in_repo_params,
|
|
user: current_user,
|
|
team: current_team)
|
|
|
|
if service.succeed?
|
|
render json: { flash: t('repositories.restore_records.success_flash', repository: escape_input(@repository.name)) }
|
|
else
|
|
render json: { error: service.error_message }, status: :unprocessable_entity
|
|
end
|
|
end
|
|
|
|
def active_reminder_repository_cells
|
|
reminder_cells = @repository_row.repository_cells.with_active_reminder(current_user).distinct
|
|
render json: {
|
|
html: render_to_string(partial: 'shared/repository_row_reminder', formats: :html, locals: {
|
|
reminders: reminder_cells
|
|
})
|
|
}
|
|
end
|
|
|
|
def actions_toolbar
|
|
render json: {
|
|
actions:
|
|
Toolbars::RepositoryRowsService.new(
|
|
current_user,
|
|
repository_row_ids: params[:repository_row_ids].split(',')
|
|
).actions
|
|
}
|
|
end
|
|
|
|
def relationships
|
|
render json: {
|
|
repository_row: RepositoryRowSerializer.new(@repository_row),
|
|
parents: @repository_row.parent_repository_rows.map { |r| RepositoryRowSerializer.new(r) },
|
|
children: @repository_row.child_repository_rows.map { |r| RepositoryRowSerializer.new(r) }
|
|
}
|
|
end
|
|
|
|
private
|
|
|
|
include StringUtility
|
|
AvailableRepositoryRow = Struct.new(:id, :name, :has_file_attached)
|
|
|
|
def load_repository
|
|
@repository = Repository.viewable_by_user(current_user)
|
|
.eager_load(:repository_columns)
|
|
.find_by(id: params[:repository_id])
|
|
render_404 unless @repository
|
|
end
|
|
|
|
def load_repository_or_snapshot
|
|
@repository = Repository.viewable_by_user(current_user).find_by(id: params[:repository_id]) ||
|
|
RepositorySnapshot.find_by(id: params[:repository_id])
|
|
return render_404 unless @repository
|
|
end
|
|
|
|
def load_repository_row
|
|
@repository_row = @repository.repository_rows.eager_load(:repository_columns).find_by(id: params[:id])
|
|
render_404 unless @repository_row
|
|
end
|
|
|
|
def load_repository_rows
|
|
@repository_rows = @repository.repository_rows.eager_load(:repository_columns).where(id: params[:row_ids])
|
|
|
|
render_404 if @repository_rows.blank?
|
|
end
|
|
|
|
def check_read_permissions
|
|
render_403 unless can_read_repository?(@repository)
|
|
end
|
|
|
|
def check_snapshotting_status
|
|
return if @repository.repository_snapshots.provisioning.none?
|
|
|
|
render json: {
|
|
flash: t('repositories.index.snapshot_provisioning_in_progress')
|
|
}, status: :unprocessable_entity
|
|
end
|
|
|
|
def check_create_permissions
|
|
render_403 unless can_create_repository_rows?(@repository)
|
|
end
|
|
|
|
def check_manage_permissions
|
|
render_403 unless can_manage_repository_rows?(@repository)
|
|
end
|
|
|
|
def check_delete_permissions
|
|
render_403 unless can_delete_repository_rows?(@repository)
|
|
end
|
|
|
|
def remove_file_columns_params
|
|
JSON.parse(params.fetch(:remove_file_columns) { '[]' })
|
|
end
|
|
|
|
def selected_params
|
|
params.permit(selected_rows: []).to_h[:selected_rows]
|
|
end
|
|
|
|
# Selected rows in scope of current @repository
|
|
def selected_rows_in_repo_params
|
|
process_ids = params[:selected_rows].map(&:to_i).uniq
|
|
@repository.repository_rows.where(id: process_ids).pluck(:id)
|
|
end
|
|
|
|
def load_available_rows
|
|
@repository.repository_rows
|
|
.active
|
|
.includes(:repository_cells)
|
|
.name_like(search_params[:q])
|
|
.limit(Constants::SEARCH_LIMIT)
|
|
.select(:id, :name)
|
|
.collect do |row|
|
|
with_asset_cell = row.repository_cells.where(
|
|
'repository_cells.repository_column_id = ?',
|
|
search_params[:repository_column_id]
|
|
)
|
|
AvailableRepositoryRow.new(row.id,
|
|
ellipsize(row.name, 75, 50),
|
|
with_asset_cell.present?)
|
|
end
|
|
end
|
|
|
|
def search_params
|
|
params.permit(:q, :repository_id, :repository_column_id)
|
|
end
|
|
|
|
def record_annotation_notification(record, cell, old_text = nil)
|
|
smart_annotation_notification(
|
|
old_text: old_text,
|
|
new_text: cell.value.data,
|
|
subject: cell.repository_column.repository,
|
|
title: t('notifications.repository_annotation_title',
|
|
user: current_user.full_name,
|
|
column: cell.repository_column.name,
|
|
record: record.name,
|
|
repository: record.repository.name),
|
|
message: t('notifications.repository_annotation_message_html',
|
|
record: link_to(record.name, repository_url(@repository)),
|
|
column: link_to(cell.repository_column.name, repository_url(@repository)))
|
|
)
|
|
end
|
|
|
|
def fetch_list_items(cell)
|
|
return [] if cell.value_type != 'RepositoryListValue'
|
|
RepositoryListItem.where(repository: @repository)
|
|
.where(repository_column: cell.repository_column)
|
|
.limit(Constants::SEARCH_LIMIT)
|
|
.pluck(:id, :data)
|
|
.map { |li| [li[0], escape_input(li[1])] }
|
|
end
|
|
|
|
def fetch_columns_list_items
|
|
collection = []
|
|
@repository.repository_columns
|
|
.list_type
|
|
.preload(:repository_list_items)
|
|
.each do |column|
|
|
collection << {
|
|
column_id: column.id,
|
|
list_items: column.repository_list_items
|
|
.limit(Constants::SEARCH_LIMIT)
|
|
.pluck(:id, :data)
|
|
.map { |li| [li[0], escape_input(li[1])] }
|
|
}
|
|
end
|
|
collection
|
|
end
|
|
|
|
def update_params
|
|
params.permit(repository_row: :name, repository_cells: {}).to_h
|
|
end
|
|
|
|
def log_activity(type_of, repository_row, message_items = {})
|
|
Activities::CreateActivityService
|
|
.call(activity_type: type_of,
|
|
owner: current_user,
|
|
subject: repository_row,
|
|
team: @repository.team,
|
|
message_items: message_items)
|
|
end
|
|
end
|