Merge pull request #481 from OWASP/feature/improve-file-upload-ux
Improve file upload UX with validation and feedback messages
This commit is contained in:
@@ -3,6 +3,7 @@ class BenefitFormsController < ApplicationController
|
|||||||
|
|
||||||
def index
|
def index
|
||||||
@benefits = Benefits.new
|
@benefits = Benefits.new
|
||||||
|
load_uploaded_files
|
||||||
end
|
end
|
||||||
|
|
||||||
def download
|
def download
|
||||||
@@ -17,13 +18,58 @@ class BenefitFormsController < ApplicationController
|
|||||||
|
|
||||||
def upload
|
def upload
|
||||||
file = params[:benefits][:upload]
|
file = params[:benefits][:upload]
|
||||||
if file
|
|
||||||
flash[:success] = "File Successfully Uploaded!"
|
if file.nil?
|
||||||
Benefits.save(file, params[:benefits][:backup])
|
flash.now[:error] = "Please select a file to upload"
|
||||||
else
|
@benefits = Benefits.new
|
||||||
flash[:error] = "Something went wrong"
|
load_uploaded_files
|
||||||
|
render :index
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Validate file type
|
||||||
|
allowed_extensions = %w[.pdf .doc .docx .jpg .jpeg .png]
|
||||||
|
file_extension = File.extname(file.original_filename).downcase
|
||||||
|
|
||||||
|
unless allowed_extensions.include?(file_extension)
|
||||||
|
flash.now[:error] = "Invalid file type. Accepted formats: PDF, DOC, DOCX, JPG, PNG. You uploaded: #{file_extension}"
|
||||||
|
@benefits = Benefits.new
|
||||||
|
load_uploaded_files
|
||||||
|
render :index
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Validate file size (10MB max)
|
||||||
|
max_size = 10.megabytes
|
||||||
|
if file.size > max_size
|
||||||
|
flash.now[:error] = "File too large. Maximum size: 10MB. Your file: #{(file.size / 1.megabyte.to_f).round(2)}MB"
|
||||||
|
@benefits = Benefits.new
|
||||||
|
load_uploaded_files
|
||||||
|
render :index
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
Benefits.save(file, params[:benefits][:backup])
|
||||||
|
flash[:success] = "File '#{file.original_filename}' uploaded successfully!"
|
||||||
|
rescue => e
|
||||||
|
flash[:error] = "Failed to upload file: #{e.message}"
|
||||||
|
end
|
||||||
|
|
||||||
redirect_to user_benefit_forms_path(user_id: current_user.id)
|
redirect_to user_benefit_forms_path(user_id: current_user.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_uploaded_files
|
||||||
|
data_path = Rails.root.join("public", "data")
|
||||||
|
@uploaded_files = Dir.glob("#{data_path}/*").reject { |f| File.directory?(f) || File.basename(f) == '.gitkeep' }.map do |file|
|
||||||
|
{
|
||||||
|
name: File.basename(file),
|
||||||
|
size: File.size(file),
|
||||||
|
modified: File.mtime(file)
|
||||||
|
}
|
||||||
|
end.sort_by { |f| f[:modified] }.reverse
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -118,6 +118,58 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Uploaded Files Section -->
|
||||||
|
<% if @uploaded_files.any? %>
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-header bg-white py-3">
|
||||||
|
<h4 class="mb-0">
|
||||||
|
<i class="bi bi-folder2-open text-success"></i> Uploaded Files
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover mb-0">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th><i class="bi bi-file-earmark"></i> File Name</th>
|
||||||
|
<th><i class="bi bi-hdd"></i> Size</th>
|
||||||
|
<th><i class="bi bi-clock"></i> Uploaded</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% @uploaded_files.each do |file| %>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<% icon_class = case File.extname(file[:name]).downcase
|
||||||
|
when '.pdf' then 'bi-file-earmark-pdf text-danger'
|
||||||
|
when '.doc', '.docx' then 'bi-file-earmark-word text-primary'
|
||||||
|
when '.jpg', '.jpeg', '.png' then 'bi-file-earmark-image text-success'
|
||||||
|
else 'bi-file-earmark'
|
||||||
|
end %>
|
||||||
|
<i class="bi <%= icon_class %> me-2"></i>
|
||||||
|
<strong><%= file[:name] %></strong>
|
||||||
|
</td>
|
||||||
|
<td><%= number_to_human_size(file[:size]) %></td>
|
||||||
|
<td><%= file[:modified].strftime("%b %d, %Y at %I:%M %p") %></td>
|
||||||
|
<td>
|
||||||
|
<%= link_to download_path(type: "File", name: "public/data/#{file[:name]}"), class: "btn btn-sm btn-outline-primary" do %>
|
||||||
|
<i class="bi bi-download"></i> Download
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<!-- Info Box -->
|
<!-- Info Box -->
|
||||||
<div class="row mt-4">
|
<div class="row mt-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
|
|||||||
Reference in New Issue
Block a user