mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-29 11:45:18 +08:00
Merge pull request #1014 from ZmagoD/zd_SCI_2025
Fix custom repositories export so it supports "list of values" custom column types [fixes SCI-2025]
This commit is contained in:
commit
f778415321
9 changed files with 228 additions and 67 deletions
|
@ -261,7 +261,7 @@ class RepositoriesController < ApplicationController
|
|||
|
||||
def export_repository
|
||||
if params[:row_ids] && params[:header_ids]
|
||||
generate_zip
|
||||
RepositoryZipExport.generate_zip(params, @repository, current_user)
|
||||
else
|
||||
flash[:alert] = t('zip_export.export_error')
|
||||
end
|
||||
|
@ -333,66 +333,4 @@ class RepositoriesController < ApplicationController
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def generate_zip
|
||||
# Fetch rows in the same order as in the currently viewed datatable
|
||||
ordered_row_ids = params[:row_ids]
|
||||
id_row_map = RepositoryRow.where(id: ordered_row_ids,
|
||||
repository: @repository)
|
||||
.index_by(&:id)
|
||||
ordered_rows = ordered_row_ids.collect { |id| id_row_map[id.to_i] }
|
||||
|
||||
zip = ZipExport.create(user: current_user)
|
||||
zip.generate_exportable_zip(
|
||||
current_user,
|
||||
to_csv(ordered_rows, params[:header_ids]),
|
||||
:repositories
|
||||
)
|
||||
end
|
||||
|
||||
def to_csv(rows, column_ids)
|
||||
require 'csv'
|
||||
|
||||
# Parse column names
|
||||
csv_header = []
|
||||
column_ids.each do |c_id|
|
||||
csv_header << case c_id.to_i
|
||||
when -1, -2
|
||||
next
|
||||
when -3
|
||||
I18n.t('repositories.table.row_name')
|
||||
when -4
|
||||
I18n.t('repositories.table.added_by')
|
||||
when -5
|
||||
I18n.t('repositories.table.added_on')
|
||||
else
|
||||
column = RepositoryColumn.find_by_id(c_id)
|
||||
column ? column.name : nil
|
||||
end
|
||||
end
|
||||
|
||||
CSV.generate do |csv|
|
||||
csv << csv_header
|
||||
rows.each do |row|
|
||||
csv_row = []
|
||||
column_ids.each do |c_id|
|
||||
csv_row << case c_id.to_i
|
||||
when -1, -2
|
||||
next
|
||||
when -3
|
||||
row.name
|
||||
when -4
|
||||
row.created_by.full_name
|
||||
when -5
|
||||
I18n.l(row.created_at, format: :full)
|
||||
else
|
||||
cell = row.repository_cells
|
||||
.find_by(repository_column_id: c_id)
|
||||
cell ? cell.value.formatted : nil
|
||||
end
|
||||
end
|
||||
csv << csv_row
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,7 +13,11 @@ class RepositoryListValue < ApplicationRecord
|
|||
validates :repository_cell, presence: true
|
||||
|
||||
def formatted
|
||||
return '' unless repository_list_item
|
||||
data.to_s
|
||||
end
|
||||
|
||||
def data
|
||||
return nil unless repository_list_item
|
||||
repository_list_item.data
|
||||
end
|
||||
end
|
||||
|
|
62
app/services/repository_zip_export.rb
Normal file
62
app/services/repository_zip_export.rb
Normal file
|
@ -0,0 +1,62 @@
|
|||
require 'csv'
|
||||
module RepositoryZipExport
|
||||
def self.generate_zip(params, repository, current_user)
|
||||
# Fetch rows in the same order as in the currently viewed datatable
|
||||
ordered_row_ids = params[:row_ids]
|
||||
id_row_map = RepositoryRow.where(id: ordered_row_ids,
|
||||
repository: repository)
|
||||
.index_by(&:id)
|
||||
ordered_rows = ordered_row_ids.collect { |id| id_row_map[id.to_i] }
|
||||
|
||||
zip = ZipExport.create(user: current_user)
|
||||
zip.generate_exportable_zip(
|
||||
current_user,
|
||||
to_csv(ordered_rows, params[:header_ids]),
|
||||
:repositories
|
||||
)
|
||||
end
|
||||
|
||||
def self.to_csv(rows, column_ids)
|
||||
# Parse column names
|
||||
csv_header = []
|
||||
column_ids.each do |c_id|
|
||||
csv_header << case c_id.to_i
|
||||
when -1, -2
|
||||
next
|
||||
when -3
|
||||
I18n.t('repositories.table.row_name')
|
||||
when -4
|
||||
I18n.t('repositories.table.added_by')
|
||||
when -5
|
||||
I18n.t('repositories.table.added_on')
|
||||
else
|
||||
column = RepositoryColumn.find_by_id(c_id)
|
||||
column ? column.name : nil
|
||||
end
|
||||
end
|
||||
|
||||
CSV.generate do |csv|
|
||||
csv << csv_header
|
||||
rows.each do |row|
|
||||
csv_row = []
|
||||
column_ids.each do |c_id|
|
||||
csv_row << case c_id.to_i
|
||||
when -1, -2
|
||||
next
|
||||
when -3
|
||||
row.name
|
||||
when -4
|
||||
row.created_by.full_name
|
||||
when -5
|
||||
I18n.l(row.created_at, format: :full)
|
||||
else
|
||||
cell = row.repository_cells
|
||||
.find_by(repository_column_id: c_id)
|
||||
cell ? cell.value.formatted : nil
|
||||
end
|
||||
end
|
||||
csv << csv_row
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
6
spec/factories/repository_text_value.rb
Normal file
6
spec/factories/repository_text_value.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
FactoryBot.define do
|
||||
factory :repository_text_value do
|
||||
created_by { User.first || association(:project_user) }
|
||||
last_modified_by { User.first || association(:project_user) }
|
||||
end
|
||||
end
|
|
@ -6,7 +6,6 @@ describe 'samples_to_repository_migration:run' do
|
|||
let!(:team) { create :team, created_by: user }
|
||||
let!(:user_team) { create :user_team, user: user, team: team }
|
||||
let!(:my_module) { create :my_module }
|
||||
let!(:samples_table) { create :samples_table, user: user, team: team }
|
||||
let(:sample_types_names) { %w(type_one type_two type_three) }
|
||||
let(:sample_group_names) { %w(group_one group_two group_three) }
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ RSpec.describe RepositoryListValue, type: :model do
|
|||
it { should accept_nested_attributes_for(:repository_cell) }
|
||||
end
|
||||
|
||||
describe '#data' do
|
||||
describe '#formatted' do
|
||||
let!(:repository) { create :repository }
|
||||
let!(:repository_column) { create :repository_column, name: 'My column' }
|
||||
let!(:repository_column) do
|
||||
|
@ -32,7 +32,7 @@ RSpec.describe RepositoryListValue, type: :model do
|
|||
}
|
||||
end
|
||||
|
||||
it 'returns the data of a selected item' do
|
||||
it 'returns the formatted data of a selected item' do
|
||||
list_item = create :repository_list_item,
|
||||
data: 'my item',
|
||||
repository: repository,
|
||||
|
@ -71,4 +71,58 @@ RSpec.describe RepositoryListValue, type: :model do
|
|||
expect(repository_list_value.reload.formatted).to eq ''
|
||||
end
|
||||
end
|
||||
|
||||
describe '#data' do
|
||||
let!(:repository) { create :repository }
|
||||
let!(:repository_column) { create :repository_column, name: 'My column' }
|
||||
let!(:repository_column) do
|
||||
create :repository_column, data_type: :RepositoryListValue
|
||||
end
|
||||
let!(:repository_row) { create :repository_row, name: 'My row' }
|
||||
let!(:repository_list_value) do
|
||||
create :repository_list_value, repository_cell_attributes: {
|
||||
repository_column: repository_column,
|
||||
repository_row: repository_row
|
||||
}
|
||||
end
|
||||
|
||||
it 'returns the data of a selected item' do
|
||||
list_item = create :repository_list_item,
|
||||
data: 'my item',
|
||||
repository: repository,
|
||||
repository_column: repository_column
|
||||
repository_list_value.repository_list_item = list_item
|
||||
repository_list_value.save
|
||||
expect(repository_list_value.reload.data).to eq 'my item'
|
||||
end
|
||||
|
||||
it 'retuns only the the item related to the list' do
|
||||
repository_row_two = create :repository_row, name: 'New row'
|
||||
repository_list_value_two =
|
||||
create :repository_list_value, repository_cell_attributes: {
|
||||
repository_column: repository_column,
|
||||
repository_row: repository_row_two
|
||||
}
|
||||
list_item = create :repository_list_item,
|
||||
data: 'new item',
|
||||
repository: repository,
|
||||
repository_column: repository_column
|
||||
repository_list_value.repository_list_item = list_item
|
||||
expect(repository_list_value.reload.data).to_not eq 'my item'
|
||||
expect(repository_list_value.data).to be_nil
|
||||
end
|
||||
|
||||
it 'returns an empty string if no item selected' do
|
||||
list_item = create :repository_list_item,
|
||||
data: 'my item',
|
||||
repository: repository,
|
||||
repository_column: repository_column
|
||||
expect(repository_list_value.reload.data).to eq nil
|
||||
end
|
||||
|
||||
it 'returns an empty string if item does not exists' do
|
||||
repository_list_value.repository_list_item = nil
|
||||
expect(repository_list_value.reload.data).to eq nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,6 +58,14 @@ RSpec.configure do |config|
|
|||
config.after(:each) do
|
||||
DatabaseCleaner.clean
|
||||
end
|
||||
|
||||
config.around(:each, type: :background_job) do |example|
|
||||
run_background_jobs_immediately do
|
||||
example.run
|
||||
end
|
||||
end
|
||||
|
||||
config.include BackgroundJobs
|
||||
# RSpec Rails can automatically mix in different behaviours to your tests
|
||||
# based on their file location, for example enabling you to call `get` and
|
||||
# `post` in specs under `spec/controllers`.
|
||||
|
|
82
spec/services/repository_zip_export_spec.rb
Normal file
82
spec/services/repository_zip_export_spec.rb
Normal file
|
@ -0,0 +1,82 @@
|
|||
require 'rails_helper'
|
||||
require 'zip'
|
||||
|
||||
describe RepositoryZipExport, type: :background_job do
|
||||
let(:user) { create :user }
|
||||
let(:team) { create :team, created_by: user }
|
||||
let(:user_team) { create :user_team, user: user, team: team }
|
||||
let(:repository) { create :repository, team: team, created_by: user }
|
||||
let!(:sample_group_column) do
|
||||
create :repository_column, repository: repository,
|
||||
created_by: user,
|
||||
name: 'Sample group',
|
||||
data_type: 'RepositoryListValue'
|
||||
end
|
||||
let!(:repository_list_item) do
|
||||
create :repository_list_item, data: 'item one',
|
||||
repository: repository,
|
||||
repository_column: sample_group_column
|
||||
end
|
||||
let!(:custom_column) do
|
||||
create :repository_column, repository: repository,
|
||||
created_by: user,
|
||||
name: 'Custom items',
|
||||
data_type: 'RepositoryTextValue'
|
||||
end
|
||||
|
||||
before do
|
||||
@row_ids = []
|
||||
10.times do |index|
|
||||
row = create :repository_row, name: "row #{index}",
|
||||
repository: repository,
|
||||
created_by: user,
|
||||
last_modified_by: user
|
||||
create :repository_list_value, repository_list_item: repository_list_item,
|
||||
repository_cell_attributes: {
|
||||
repository_row: row,
|
||||
repository_column: sample_group_column
|
||||
}
|
||||
create :repository_text_value, data: 'custum column value',
|
||||
repository_cell_attributes: {
|
||||
repository_row: row,
|
||||
repository_column: custom_column
|
||||
}
|
||||
|
||||
@row_ids << row.id.to_s
|
||||
end
|
||||
end
|
||||
|
||||
describe '#generate_zip/2' do
|
||||
let(:params) do
|
||||
{ header_ids: ['-1',
|
||||
'-2',
|
||||
sample_group_column.id.to_s,
|
||||
custom_column.id.to_s,
|
||||
'-3',
|
||||
'-5',
|
||||
'-4'],
|
||||
row_ids: @row_ids }
|
||||
end
|
||||
|
||||
it 'generates a new zip export object' do
|
||||
RepositoryZipExport.generate_zip(params, repository, user)
|
||||
expect(ZipExport.count).to eq 1
|
||||
end
|
||||
|
||||
it 'generates a zip with csv file with exported rows' do
|
||||
RepositoryZipExport.generate_zip(params, repository, user)
|
||||
zip = ZipExport.first.zip_file_file_name
|
||||
.gsub('export-', '')
|
||||
.gsub('.zip', '')
|
||||
csv_path = Rails.root.join('tmp', "temp-zip-#{zip}", 'export.csv').to_s
|
||||
index = 0
|
||||
CSV.foreach(csv_path, headers: true) do |row|
|
||||
row_hash = row.to_h
|
||||
expect(row_hash.fetch('Sample group')).to eq 'item one'
|
||||
expect(row_hash.fetch('Custom items')).to eq 'custum column value'
|
||||
expect(row_hash.fetch('Name')).to eq "row #{index}"
|
||||
index += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
8
spec/support/background_job.rb
Normal file
8
spec/support/background_job.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
module BackgroundJobs
|
||||
def run_background_jobs_immediately
|
||||
delay_jobs = Delayed::Worker.delay_jobs
|
||||
Delayed::Worker.delay_jobs = false
|
||||
yield
|
||||
Delayed::Worker.delay_jobs = delay_jobs
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue