Skip to content

Commit

Permalink
All files in a folder can be downloaded as a single zip file, addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
remomueller committed Sep 27, 2019
1 parent a9fc81d commit af2c732
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### Enhancements
- **Folder Changes**
- Folders are now sorted alphabetically in each category
- All files in a folder can be downloaded as a single zip file
- **Document Changes**
- Reduced size of folder names in documents sidebar
- Admins can now set keywords for documents to improve search results for
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ gem "kaminari", "~> 1.1.1"
gem "mini_magick", "~> 4.9.2"
gem "pg_search", "~> 2.3.0"
gem "redcarpet", "~> 3.5.0"
gem "rubyzip", "~> 1.2.3"

# Rails defaults
gem "coffee-rails", "~> 5.0"
Expand Down
14 changes: 13 additions & 1 deletion app/controllers/folders_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class FoldersController < ApplicationController
]
before_action :create_category, only: [:create, :update]
before_action :find_category_and_folder_or_redirect, only: [
:show, :edit, :upload
:show, :edit, :upload, :download_zip
]
before_action :find_folder_or_redirect, only: [
:update, :destroy, :attach_file, :attach_files
Expand All @@ -27,6 +27,18 @@ def show
@documents = docs_scope_order(@folder.documents).page(params[:page]).per(Folder::DOCS_PER_PAGE)
end

# GET /docs/:category/:folder/download-zip
def download_zip
@folder.generate_zipped_folder!
filename = "lofthf-study-#{@folder.category.slug}-#{@folder.slug}.zip"

if Rails.env.production?
redirect_to @folder.zipped_folder.url(query: { "response-content-disposition" => "attachment" }), allow_other_host: true
else
send_file_if_present @folder.zipped_folder, filename: filename
end
end

# GET /docs/new
def new
category = Category.find_by_param(params[:category])
Expand Down
30 changes: 30 additions & 0 deletions app/models/folder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

# Tracks files uploaded to the folder.
class Folder < ApplicationRecord
# Uploaders
mount_uploader :zipped_folder, ZipUploader

# Constants
DOCS_PER_PAGE = 20

Expand Down Expand Up @@ -32,4 +35,31 @@ def attach_file!(file)
content_type: Document.content_type(file.original_filename)
)
end

def generate_zipped_folder!
zip_name = "folder.zip"
temp_zip_file = Tempfile.new(zip_name)
begin
# Initialize temp zip file.
Zip::OutputStream.open(temp_zip_file) { |zos| }
# Write to temp zip file.
Zip::File.open(temp_zip_file, Zip::File::CREATE) do |zip|
documents.each do |document|
# Two arguments:
# - The name of the file as it will appear in the archive
# - The original file, including the path to find it
zip.add(document.filename, document.file.path) if File.exist?(document.file.path) && File.size(document.file.path).positive?
end
end
temp_zip_file.define_singleton_method(:original_filename) do
zip_name
end
update zipped_folder: temp_zip_file
# update file_size: zipped_folder.size # Cache after attaching to model.
ensure
# Close and delete the temp file
temp_zip_file.close
temp_zip_file.unlink
end
end
end
29 changes: 29 additions & 0 deletions app/uploaders/zip_uploader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

# Allows a zip file to be uploaded.
class ZipUploader < CarrierWave::Uploader::Base
# Choose what kind of storage to use for this uploader:
storage Rails.env.production? ? :fog : :file

# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
File.join(model.class.to_s.underscore.pluralize, model.id.to_s, mounted_as.to_s)
end

# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url
# "/assets/fallback/" + [version_name, "default.png"].compact.join('_')
# end

# Add a white list of extensions which are allowed to be uploaded.
def extension_whitelist
%w(zip)
end

# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end
4 changes: 4 additions & 0 deletions app/views/folders/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
%li= link_to "docs", folders_path
%li.breadcrumb-muted= @category.slug
%li.breadcrumb-muted= @folder.slug
%li.breadcrumb-muted
= link_to download_zip_category_folder_path(@folder.category, @folder), method: :post do
= icon("fas", "file-download")
download all
- if current_user.editor?
%li
= link_to edit_category_folder_path(@category, @folder) do
Expand Down
3 changes: 3 additions & 0 deletions config/initializers/app_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

require "zip"
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
get "docs/:category/:folder", to: "folders#show", as: :category_folder
get "docs/:category/:folder/edit", to: "folders#edit", as: :edit_category_folder
get "docs/:category/:folder/upload", to: "folders#upload", as: :upload_category_folder
post "docs/:category/:folder/download-zip", to: "folders#download_zip", as: :download_zip_category_folder
get "docs/:category/:folder/*filename", to: "documents#download", as: :download_document, format: false
get "docs/:category", to: redirect("docs"), as: :docs_category

Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20190926234257_add_zipped_folder_to_folders.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddZippedFolderToFolders < ActiveRecord::Migration[6.0]
def change
add_column :folders, :zipped_folder, :string
end
end
5 changes: 3 additions & 2 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2019_09_04_004415) do
ActiveRecord::Schema.define(version: 2019_09_26_234257) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -79,6 +79,7 @@
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "documents_count", default: 0, null: false
t.string "zipped_folder"
t.index ["archived"], name: "index_folders_on_archived"
t.index ["category_id", "name"], name: "index_folders_on_category_id_and_name", unique: true
t.index ["category_id", "slug"], name: "index_folders_on_category_id_and_slug", unique: true
Expand Down Expand Up @@ -141,7 +142,7 @@
t.string "header_label"
t.jsonb "header"
t.datetime "last_cached_at"
t.boolean "archived"
t.boolean "archived", default: false, null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.bigint "project_id"
Expand Down

0 comments on commit af2c732

Please sign in to comment.