diff --git a/Gemfile b/Gemfile index 0317203bb..173ad6a3b 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ ruby File.read('.ruby-version').strip gem 'rails', '~> 6.1.1' gem 'rails-i18n', '~> 6.0.0' gem 'rdiscount', '~> 2.2.0.1' +gem 'rubyzip', '~> 2.3.0' gem 'activeadmin', '~> 2.9.0' gem 'bootsnap', '~> 1.7.3', require: false gem 'has_scope', '~> 0.7.2' diff --git a/Gemfile.lock b/Gemfile.lock index 62465c48e..d9eb8b504 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -442,6 +442,7 @@ DEPENDENCIES rspec-rails (~> 4.0.0) rubocop (~> 1.6) rubocop-rails (~> 2.9) + rubyzip (~> 2.3.0) sassc-rails (~> 2.1.2) select2-rails (~> 4.0.13) selenium-webdriver (~> 3.142) diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 8df55ae59..b6047b93d 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -221,7 +221,7 @@ html { } .row.exports { - padding: 10px; + padding: 20px 0; } .table-responsive { diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index b757574e3..5b2b271fa 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -1,48 +1,98 @@ +require 'zip' + class ReportsController < ApplicationController before_action :authenticate_user! layout "report" def user_list - @members = current_organization.members.active. - includes(:user). - order("members.member_uid") + @members = report_collection("Member") report_responder('Member', current_organization, @members) end def post_list @post_type = (params[:type] || "offer").capitalize.constantize - @posts = current_organization.posts. - of_active_members. - active. - merge(@post_type.all). - includes(:user, :category). - group_by(&:category). - to_a. - sort_by { |category, _| category.try(:name).to_s } + @posts = report_collection(@post_type) report_responder('Post', current_organization, @posts, @post_type) end def transfer_list - @transfers = current_organization.all_transfers_with_accounts + @transfers = report_collection('Transfer') report_responder('Transfer', current_organization, @transfers) end + def download_all + filename = "#{current_organization.name.parameterize}_#{Date.today}.zip" + temp_file = Tempfile.new(filename) + + begin + Zip::File.open(temp_file.path, Zip::File::CREATE) do |zipfile| + %w(Member Transfer Inquiry Offer).each do |report_class| + add_csv_to_zip(report_class, zipfile) + end + end + zip_data = File.read(temp_file.path) + send_data(zip_data, type: 'application/zip', disposition: 'attachment', filename: filename) + rescue Errno::ENOENT + redirect_to download_all_report_path + ensure + temp_file.close + temp_file.unlink + end + end + private def report_responder(report_class, *args) respond_to do |format| format.html - format.csv { download_report("Report::Csv::#{report_class}", *args) } - format.pdf { download_report("Report::Pdf::#{report_class}", *args) } + format.csv { download_report("Csv::#{report_class}", *args) } + format.pdf { download_report("Pdf::#{report_class}", *args) } end end def download_report(report_class, *args) - report = report_class.constantize.new(*args) + report = get_report(report_class, *args) send_data report.run, filename: report.name, type: report.mime_type end + + def get_report(report_class, *args) + "Report::#{report_class}".constantize.new(*args) + end + + def report_collection(report_class) + case report_class.to_s + when 'Member' + current_organization.members.active.includes(:user).order('members.member_uid') + when 'Transfer' + current_organization.all_transfers_with_accounts + when 'Inquiry', 'Offer' + report_class = report_class.constantize if report_class.is_a?(String) + + current_organization.posts.of_active_members.active. + merge(report_class.all). + includes(:user, :category). + group_by(&:category). + sort_by { |category, _| category.try(:name).to_s } + end + end + + def add_csv_to_zip(report_class, zip) + collection = report_collection(report_class) + + report = if report_class.in? %w(Inquiry Offer) + get_report("Csv::Post", current_organization, collection, report_class.constantize) + else + get_report("Csv::#{report_class}", current_organization, collection) + end + + file = Tempfile.new + file.write(report.run) + file.rewind + + zip.add("#{report_class.pluralize}_#{Date.today}.csv", file.path) + end end diff --git a/app/views/application/menus/_organization_reports_menu.html.erb b/app/views/application/menus/_organization_reports_menu.html.erb index d87571675..9b590189b 100644 --- a/app/views/application/menus/_organization_reports_menu.html.erb +++ b/app/views/application/menus/_organization_reports_menu.html.erb @@ -29,5 +29,12 @@ <%= Transfer.model_name.human(count: :many) %> <% end %> + +
  • + <%= link_to download_all_report_path do %> + <%= glyph :download %> + <%= t 'reports.download_all' %> + <% end %> +
  • diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 6d7aa4838..261ca1c1b 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -412,11 +412,8 @@ ca: show: info: Aquesta %{type} pertany a %{organization}. reports: - cat_with_users: - title: Serveis ofertats download: Descarregar - user_list: - title: Llistat d'usuaris + download_all: Descarregar tot shared: movements: delete_reason: Esteu segur d'esborrar aquest comentari? diff --git a/config/locales/en.yml b/config/locales/en.yml index e7419738b..0af7f453c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -412,11 +412,8 @@ en: show: info: This %{type} belongs to %{organization}. reports: - cat_with_users: - title: Offered Services download: Download - user_list: - title: User List + download_all: Download all shared: movements: delete_reason: Are you sure to delete this comment? diff --git a/config/locales/es.yml b/config/locales/es.yml index 617a1a733..838e0db8b 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -412,11 +412,8 @@ es: show: info: Esta %{type} pertenece a %{organization}. reports: - cat_with_users: - title: Servicios ofrecidos download: Descargar - user_list: - title: Listado usuarios + download_all: Descargar todo shared: movements: delete_reason: "¿Está seguro de borrar este comentario?" diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 9b8eea255..5c2c785da 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -412,11 +412,8 @@ eu: show: info: "%{type} hau %{organization}(e)ri dagokio." reports: - cat_with_users: - title: Eskaintzen diren zerbitzuak download: Jaitsi - user_list: - title: Erabiltzaile zerrenda + download_all: shared: movements: delete_reason: Zihur zaude azalpen hau ezabatu nahi duzula? diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 5316ba0a6..9798c49b1 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -412,11 +412,8 @@ gl: show: info: Este %{type} pertence a %{organization}. reports: - cat_with_users: - title: Servizos ofrecidos download: Descarga - user_list: - title: Lista de persoas usuarias + download_all: shared: movements: delete_reason: Estás seguro/a de borrar este comentario? diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 2cd7b0755..68b523be0 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -412,11 +412,8 @@ pt-BR: show: info: Este %{type} pertence a %{organization}. reports: - cat_with_users: - title: Serviços oferecidos download: Baixar - user_list: - title: Lista de usuários + download_all: shared: movements: delete_reason: Tem certeza de que quer apagar este comentário? diff --git a/config/routes.rb b/config/routes.rb index cc8fd4c7e..a88d0ee40 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -64,6 +64,7 @@ get "offer_list" => :post_list, type: "offer" get "inquiry_list" => :post_list, type: "inquiry" get "transfer_list" + get "download_all" end end diff --git a/spec/controllers/reports_controller_spec.rb b/spec/controllers/reports_controller_spec.rb index fc6a1688d..369402369 100644 --- a/spec/controllers/reports_controller_spec.rb +++ b/spec/controllers/reports_controller_spec.rb @@ -89,5 +89,24 @@ expect(response.media_type).to eq("application/pdf") end end + + describe 'GET #download_all' do + it 'downloads a zip' do + get :download_all + + expect(response.media_type).to eq('application/zip') + expect(response.body).to include('Inquiries') + expect(response.body).to include('Offers') + expect(response.body).to include('Members') + expect(response.body).to include('Transfers') + end + + it 'redirects to download_all_report_path (retry) if zip is not ready' do + allow(subject).to receive(:add_csv_to_zip).and_raise(Errno::ENOENT) + get :download_all + + expect(response).to redirect_to(download_all_report_path) + end + end end end