improve download releases button

This commit is contained in:
Bilal
2020-09-01 03:51:56 +03:00
parent f611382e9e
commit 3471e21429
10 changed files with 199 additions and 23 deletions

View File

@@ -0,0 +1,20 @@
$(document).on("click", "#download_releases", function(event) {
event.preventDefault();
const releasable_ids = JSON.parse($("#selected_releases_form").attr('data-releasable-ids'));
const total_entries = $('#total_entries').val();
const input_ids = $('<input>').attr({ type: 'hidden', name: 'release_ids', value: JSON.stringify(releasable_ids) });
const search_query = $('<input>').attr({ type: 'hidden', name: 'search_query', value: $("form input[type='search']").val() });
const type_filter = $('<input>').attr({ type: 'hidden', name: 'type_filter', value: $('#type_filter_value').val() });
const download_count = releasable_ids.length > 0 ? releasable_ids.length : total_entries;
$(this).parent().append(input_ids);
$(this).parent().append(search_query);
$(this).parent().append(type_filter);
if (confirm(`${download_count} release(s) will be downloaded. Is this correct?`)){
Rails.fire($(this).parent()[0], 'submit');
}
});

View File

@@ -7,28 +7,41 @@ class ContractDownloadsController < ApplicationController
def create def create
authorize policy_scope(Download).create authorize policy_scope(Download).create
fetch_releases
download = @project.downloads.create!(release_type: release_type)
download = @project.downloads.create!(release_type: params[:release_type])
other_downloads_in_progress = @project.downloads.unfinished_desc_order.offset(1) other_downloads_in_progress = @project.downloads.unfinished_desc_order.offset(1)
if other_downloads_in_progress.any? if other_downloads_in_progress.any?
in_progress_downloads_details = render_to_string "_other_pending_downloads", locals: { downloads: other_downloads_in_progress, release_type: params[:release_type] }, :layout => false in_progress_downloads_details = render_to_string "_other_pending_downloads", locals: { downloads: other_downloads_in_progress, release_type: release_type }, :layout => false
ProjectsChannel.broadcast_download_generation_update(download, in_progress_downloads_details) ProjectsChannel.broadcast_download_generation_update(download, in_progress_downloads_details)
else else
ProjectsChannel.broadcast_download_generation_update(download, I18n.t("contract_downloads.download.pending", release_type: params[:release_type].titleize)) ProjectsChannel.broadcast_download_generation_update(download, I18n.t("contract_downloads.download.pending", release_type: release_type.titleize))
end end
GenerateContractsZipJob.perform_later(@project, download, params[:release_type], @releases.ids) GenerateContractsZipJob.perform_later(@project, download, release_type, release_ids, search_query, type_filter)
end end
private private
def fetch_releases def release_type
@releases = policy_scope(@project.public_send(releases)) params[:release_type]
end end
def releases def search_query
params[:release_type].constantize.model_name.plural params[:search_query]
end
def type_filter
params[:type_filter]
end
def release_ids
JSON.parse(params[:release_ids])
rescue StandardError
[]
end
def release_name(release_type)
release_type.constantize.model_name.plural
end end
end end

View File

@@ -17,6 +17,7 @@ module TagsHelper
disable_with: disabled_content, disable_with: disabled_content,
}, },
form: { form: {
id: "selected_releases_form",
data: { data: {
releasable_ids: [], releasable_ids: [],
}, },

View File

@@ -7,13 +7,14 @@ class GenerateContractsZipJob < ApplicationJob
@project = job.arguments.first @project = job.arguments.first
@download = job.arguments.second @download = job.arguments.second
@release_type = job.arguments.third @release_type = job.arguments.third
@folder_name = "#{@project.name.parameterize}_#{get_release_name(@release_type).gsub('_', '-')}" @release_ids = job.arguments.fourth
@search_query = job.arguments.fifth
@type_filter = job.arguments[5]
@folder_name = "#{@project.name.parameterize}_#{release_name.gsub('_', '-')}"
@download.update!(name: @folder_name, status: :pending) @download.update!(name: @folder_name, status: :pending)
end end
def perform(project, download, release_type, release_ids) def perform(project, download, release_type, release_ids, search_query, type_filter)
releases = project.public_send(get_release_name(release_type)).where(id: release_ids)
::ReleaseContractCollectionService.new(releases, @folder_name).build do |dir, files| ::ReleaseContractCollectionService.new(releases, @folder_name).build do |dir, files|
zipfile_name = "#{dir}/#{@folder_name}.zip" zipfile_name = "#{dir}/#{@folder_name}.zip"
Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile| Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
@@ -31,7 +32,7 @@ class GenerateContractsZipJob < ApplicationJob
end end
rescue StandardError => e rescue StandardError => e
Rails.logger.error("Failed to generate download for project (##{project.id}) with release type #{release_type}\n" + e.message) Rails.logger.error("Failed to generate download for project (##{project.id}) with release type #{release_type}\n" + e.message)
@download.failure! @download.failure!
ProjectsChannel.broadcast_download_generation_update(@download, I18n.t("contract_downloads.download.failure")) ProjectsChannel.broadcast_download_generation_update(@download, I18n.t("contract_downloads.download.failure"))
end end
@@ -61,7 +62,32 @@ class GenerateContractsZipJob < ApplicationJob
end end
end end
def get_release_name(release_type) def release_name
release_type.constantize.model_name.plural @release_type.constantize.model_name.plural
end
def all_releases
@project.public_send(release_name)
end
def releases
if @release_ids.any?
return all_releases.where(id: @release_ids)
end
results = all_releases
if all_releases.respond_to?(:complete, :incomplete)
results = case @type_filter
when 'complete'
all_releases.complete
when 'incomplete'
all_releases.incomplete
else
all_releases
end
end
results = results.search(@search_query) if @search_query.present?
results
end end
end end

View File

@@ -164,6 +164,10 @@ class AppearanceRelease < ApplicationRecord
"#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime('%Y.%m.%d')}_#{release_number}_#{filename_suffix.parameterize}" "#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime('%Y.%m.%d')}_#{release_number}_#{filename_suffix.parameterize}"
end end
def complete?
person_photo.attached? && contract.attached?
end
private private
# Validates the quality of the person photo # Validates the quality of the person photo

View File

@@ -24,7 +24,7 @@ class ReleaseContractCollectionService
end end
files = Dir.entries("#{dir}/").select { |f| !File.directory? f } files = Dir.entries("#{dir}/").select { |f| !File.directory? f }
raise StandardError.new "Contracts or Contract Templates not found." unless files.any? # raise StandardError.new "Contracts or Contract Templates not found." unless files.any?
yield(dir, files) yield(dir, files)
} }
end end

View File

@@ -1,5 +1,6 @@
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<input id="total_entries" type=hidden value=<%= @appearance_releases.total_entries %> />
<div id="upload-progress-container" class="mb-1"></div> <div id="upload-progress-container" class="mb-1"></div>
<div class="d-md-flex d-sm-flex flex-sm-column flex-md-row flex-md-wrap mb-2"> <div class="d-md-flex d-sm-flex flex-sm-column flex-md-row flex-md-wrap mb-2">
<% if policy(AppearanceRelease).new? %> <% if policy(AppearanceRelease).new? %>
@@ -16,7 +17,7 @@
<% end %> <% end %>
<% if @appearance_releases.any? && policy(AppearanceRelease).download_multiple? %> <% if @appearance_releases.any? && policy(AppearanceRelease).download_multiple? %>
<%= link_to "Download All", [@project, :contract_downloads, release_type: @appearance_releases.name], method: :post, remote: true, class: "btn btn-light border mr-2 mb-2", data: { disable_with: "Please wait..." } %> <%= button_to "Download", [@project, :contract_downloads, release_type: @appearance_releases.name], id: "download_releases", method: :post, remote: true, class: "btn btn-light border mr-2 mb-2", data: { disable_with: "Please wait..." } %>
<% end %> <% end %>
</div> </div>
</div> </div>

View File

@@ -3,3 +3,5 @@ $("form input[type='search']").val("<%= params[:query] %>");
$("#type_filter_actions").html("<%= j render 'type_filter_actions' %>"); $("#type_filter_actions").html("<%= j render 'type_filter_actions' %>");
$("#appearance_releases_pagination").html("<%= j will_paginate(@appearance_releases) %>"); $("#appearance_releases_pagination").html("<%= j will_paginate(@appearance_releases) %>");
$('#type_filter_value').val("<%= params[:type_filter] %>"); $('#type_filter_value').val("<%= params[:type_filter] %>");
$("#selected_releases_form").attr('data-releasable-ids', JSON.stringify([]));
$("#total_entries").val(<%= @appearance_releases.total_entries %>);

View File

@@ -1492,6 +1492,7 @@ CREATE TABLE public.settings (
-- --
CREATE SEQUENCE public.settings_id_seq CREATE SEQUENCE public.settings_id_seq
AS integer
START WITH 1 START WITH 1
INCREMENT BY 1 INCREMENT BY 1
NO MINVALUE NO MINVALUE
@@ -1527,6 +1528,7 @@ CREATE TABLE public.taggings (
-- --
CREATE SEQUENCE public.taggings_id_seq CREATE SEQUENCE public.taggings_id_seq
AS integer
START WITH 1 START WITH 1
INCREMENT BY 1 INCREMENT BY 1
NO MINVALUE NO MINVALUE
@@ -1557,6 +1559,7 @@ CREATE TABLE public.tags (
-- --
CREATE SEQUENCE public.tags_id_seq CREATE SEQUENCE public.tags_id_seq
AS integer
START WITH 1 START WITH 1
INCREMENT BY 1 INCREMENT BY 1
NO MINVALUE NO MINVALUE

View File

@@ -19,7 +19,7 @@ describe GenerateContractsZipJob do
describe ".perform_later" do describe ".perform_later" do
it "enqueues a background job for generating zip file" do it "enqueues a background job for generating zip file" do
expect { expect {
GenerateContractsZipJob.perform_later(project, download, "AppearanceRelease", project.appearance_releases.ids) GenerateContractsZipJob.perform_later(project, download, "AppearanceRelease", project.appearance_releases.ids, '', '')
}.to have_enqueued_job }.to have_enqueued_job
end end
end end
@@ -28,7 +28,7 @@ describe GenerateContractsZipJob do
shared_examples "generates ZIP containig CSV file with all releases data" do shared_examples "generates ZIP containig CSV file with all releases data" do
it "generates ZIP containing CSV file with all releases data for all release types" do it "generates ZIP containing CSV file with all releases data for all release types" do
lowercase_plural = subject.constantize.model_name.plural lowercase_plural = subject.constantize.model_name.plural
GenerateContractsZipJob.perform_now(project, download, subject, project.public_send(lowercase_plural).ids) GenerateContractsZipJob.perform_now(project, download, subject, project.public_send(lowercase_plural).ids, '', '')
generated_zip = download.file.blob.download generated_zip = download.file.blob.download
csv_file_name = "#{project.name.parameterize}_#{lowercase_plural.gsub('_', '-')}.csv" csv_file_name = "#{project.name.parameterize}_#{lowercase_plural.gsub('_', '-')}.csv"
@@ -50,8 +50,111 @@ describe GenerateContractsZipJob do
end end
end end
shared_examples "generates ZIP containig CSV file with specific releases data" do
it "generates ZIP containing CSV file with all selected releases data for selected releases" do
lowercase_plural = subject.constantize.model_name.plural
all_releases = project.public_send(lowercase_plural)
included_releases = all_releases.where(id: all_releases.ids[0..1])
not_included_releases = all_releases.where.not(id: all_releases.ids[0..1])
GenerateContractsZipJob.perform_now(project, download, subject, included_releases.ids, '', '')
generated_zip = download.file.blob.download
csv_file_name = "#{project.name.parameterize}_#{lowercase_plural.gsub('_', '-')}.csv"
Zip::InputStream.open(StringIO.new(generated_zip)) do |io|
while entry = io.get_next_entry
next unless entry.name == csv_file_name
csv_file = entry.get_input_stream.read
release_class = Object.const_get subject
release_headers = release_class.csv_headers
release_headers.each do |header|
expect(csv_file).to match header
expect(csv_file).not_to match translation_missing
end
included_releases.each do |release|
expect(csv_file).to match release.person_first_name
end
not_included_releases.each do |release|
expect(csv_file).not_to match release.person_first_name
end
end
end
end
it "generates ZIP containing CSV file with all filtered releases data for filtered releases" do
lowercase_plural = subject.constantize.model_name.plural
GenerateContractsZipJob.perform_now(project, download, subject, [], '', 'complete')
complete_releases = project.public_send(lowercase_plural).complete
incomplete_releases = project.public_send(lowercase_plural).incomplete
generated_zip = download.file.blob.download
csv_file_name = "#{project.name.parameterize}_#{lowercase_plural.gsub('_', '-')}.csv"
Zip::InputStream.open(StringIO.new(generated_zip)) do |io|
while entry = io.get_next_entry
next unless entry.name == csv_file_name
csv_file = entry.get_input_stream.read
release_class = Object.const_get subject
release_headers = release_class.csv_headers
release_headers.each do |header|
expect(csv_file).to match header
expect(csv_file).not_to match translation_missing
end
complete_releases.each do |release|
expect(csv_file).to match release.person_first_name
end
incomplete_releases.each do |release|
expect(csv_file).not_to match release.person_first_name
end
end
end
end
it "generates ZIP containing CSV file with all search query matching releases" do
lowercase_plural = subject.constantize.model_name.plural
matched_releases = project.public_send(lowercase_plural).search('Brad')
not_matched_releases = project.public_send(lowercase_plural).where.not(id: matched_releases.ids)
GenerateContractsZipJob.perform_now(project, download, subject, [], 'Brad', '')
generated_zip = download.file.blob.download
csv_file_name = "#{project.name.parameterize}_#{lowercase_plural.gsub('_', '-')}.csv"
Zip::InputStream.open(StringIO.new(generated_zip)) do |io|
while entry = io.get_next_entry
next unless entry.name == csv_file_name
csv_file = entry.get_input_stream.read
release_class = Object.const_get subject
release_headers = release_class.csv_headers
release_headers.each do |header|
expect(csv_file).to match header
expect(csv_file).not_to match translation_missing
end
matched_releases.each do |release|
expect(csv_file).to match release.person_first_name
end
not_matched_releases.each do |release|
expect(csv_file).not_to match release.person_first_name
end
end
end
end
end
it "updates a download record and creates attachment for it" do it "updates a download record and creates attachment for it" do
GenerateContractsZipJob.perform_now(project, download, "AppearanceRelease", project.appearance_releases.ids) GenerateContractsZipJob.perform_now(project, download, "AppearanceRelease", project.appearance_releases.ids, '', '')
expect(download.project).to eq project expect(download.project).to eq project
expect(download.release_type).to eq "AppearanceRelease" expect(download.release_type).to eq "AppearanceRelease"
@@ -69,9 +172,12 @@ describe GenerateContractsZipJob do
context "generates ZIP for appearance releases" do context "generates ZIP for appearance releases" do
let(:release) { create(:appearance_release_with_contract_template, :native, project: project, person_name: "John Doe") } let(:release) { create(:appearance_release_with_contract_template, :native, project: project, person_name: "John Doe") }
let(:incomplete_release) { create(:appearance_release_with_contract_template, project: project, person_name: "Jane Doe") }
let(:complete_release) { create(:appearance_release_with_contract_template, :non_native, project: project, person_name: "Brad Doe") }
subject { 'AppearanceRelease' } subject { 'AppearanceRelease' }
it_behaves_like "generates ZIP containig CSV file with all releases data" it_behaves_like "generates ZIP containig CSV file with all releases data"
it_behaves_like "generates ZIP containig CSV file with specific releases data"
end end
context "generates ZIP for location releases" do context "generates ZIP for location releases" do
@@ -125,7 +231,7 @@ describe GenerateContractsZipJob do
end end
it "updates status to 'failure' and sends user a notification" do it "updates status to 'failure' and sends user a notification" do
GenerateContractsZipJob.perform_now(project, download, "AppearanceRelease", project.appearance_releases.ids) GenerateContractsZipJob.perform_now(project, download, "AppearanceRelease", project.appearance_releases.ids, '', '')
expect(download.status).to eq "failure" expect(download.status).to eq "failure"
expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(download, I18n.t("contract_downloads.download.failure")) expect(ProjectsChannel).to have_received(:broadcast_download_generation_update).with(download, I18n.t("contract_downloads.download.failure"))