Remove documents single uploads

This commit is contained in:
Senén Rodero Rodríguez
2017-09-27 11:04:56 +02:00
parent eef8ad1b73
commit 2993ef8707
11 changed files with 73 additions and 502 deletions

View File

@@ -1,24 +1,8 @@
class DocumentsController < ApplicationController class DocumentsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action :find_documentable, except: :destroy
before_action :prepare_new_document, only: [:new]
before_action :prepare_document_for_creation, only: :create
load_and_authorize_resource load_and_authorize_resource
def new
end
def create
if @document.save
flash[:notice] = t "documents.actions.create.notice"
redirect_to params[:from]
else
flash[:alert] = t "documents.actions.create.alert"
render :new
end
end
def destroy def destroy
respond_to do |format| respond_to do |format|
format.html do format.html do
@@ -39,25 +23,4 @@ class DocumentsController < ApplicationController
end end
end end
private
def document_params
params.require(:document).permit(:title, :documentable_type, :documentable_id,
:attachment, :cached_attachment, :user_id)
end
def find_documentable
@documentable = params[:documentable_type].constantize.find_or_initialize_by(id: params[:documentable_id])
end
def prepare_new_document
@document = Document.new(documentable: @documentable, user_id: current_user.id)
end
def prepare_document_for_creation
@document = Document.new(document_params)
@document.documentable = @documentable
@document.user = current_user
end
end end

View File

@@ -1,9 +1,5 @@
module DocumentablesHelper module DocumentablesHelper
def can_create_document?(documentable)
can?(:create, Document.new(documentable: documentable)) && documentable.documents.size < documentable.class.max_documents_allowed
end
def documentable_class(documentable) def documentable_class(documentable)
documentable.class.name.parameterize('_') documentable.class.name.parameterize('_')
end end

View File

@@ -37,7 +37,7 @@ module Abilities
can [:create, :destroy], Follow can [:create, :destroy], Follow
can [:create, :destroy, :new], Document, documentable: { author_id: user.id } can [:destroy], Document, documentable: { author_id: user.id }
can [:destroy], Image, imageable: { author_id: user.id } can [:destroy], Image, imageable: { author_id: user.id }

View File

@@ -4,12 +4,6 @@
<div class="small-12 medium-9 column"> <div class="small-12 medium-9 column">
<%= back_link_to budget_investments_path(investment.budget, heading_id: investment.heading) %> <%= back_link_to budget_investments_path(investment.budget, heading_id: investment.heading) %>
<% if can_create_document?(investment) %>
<%= link_to t("documents.upload_document"),
new_document_path(documentable_id:investment, documentable_type: investment.class.name, from: request.url),
class: 'button hollow float-right' %>
<% end %>
<% if can_destroy_image?(investment) %> <% if can_destroy_image?(investment) %>
<%= link_to t("images.remove_image"), <%= link_to t("images.remove_image"),
image_path(investment.image, from: request.url), image_path(investment.image, from: request.url),

View File

@@ -1,6 +1,6 @@
<% if documents.any? %> <% if documents.any? %>
<% if documents.size == max_documents_allowed && can?(:create, Document) %> <% if documents.size == max_documents_allowed && can?(:destroy, Document) %>
<div class="row documents-list"> <div class="row documents-list">
<div class="small-12 column"> <div class="small-12 column">
<div class="callout warning text-center"> <div class="callout warning text-center">

View File

@@ -1,63 +0,0 @@
<%= form_for @document,
url: documents_path(
documentable_type: @document.documentable_type,
documentable_id: @document.documentable_id,
from: params[:from]
),
html: { multipart: true, class: "documentable document-form" } do |f| %>
<%= render 'shared/errors', resource: @document %>
<div class="row document direct-upload">
<%= f.hidden_field :cached_attachment %>
<div class="small-12 column title">
<%= f.text_field :title, placeholder: t("documents.new.form.title_placeholder") %>
</div>
<div class="small-12 column attachment-actions">
<div class="small-6 column action-add attachment-errors">
<%= f.label :attachment, t("documents.form.attachment_label"), class: 'button hollow' %>
<%= f.file_field :attachment,
accept: accepted_content_types_extensions(@document.documentable.class),
label: false,
class: 'js-document-attachment',
data: {
url: direct_uploads_url("direct_upload[resource_type]": @document.documentable_type,
"direct_upload[resource_id]": @document.documentable_id,
"direct_upload[resource_relation]": "documents"),
cached_attachment_input_field: "document_cached_attachment",
title_input_field: "document_title"
} %>
</div>
<div class="small-6 column action-remove text-right">
<% if @document.cached_attachment.present? %>
<%= link_to t('documents.form.delete_button'),
direct_upload_destroy_url("direct_upload[resource_type]": @document.documentable_type,
"direct_upload[resource_id]": @document.documentable_id,
"direct_upload[resource_relation]": "documents",
"direct_upload[cached_attachment]": @document.cached_attachment),
method: :delete,
remote: true,
class: "delete remove-cached-attachment" %>
<% end %>
</div>
</div>
<div class="small-12 column">
<p class="file-name">
<%= document_attachment_file_name(@document) %>
</p>
</div>
<div class="small-12 column">
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
</div>
<div class="actions small-12 medium-6 large-4 end column">
<%= f.submit(t("documents.form.submit_button"), class: "button expanded") %>
</div>
</div>
<% end %>

View File

@@ -108,18 +108,10 @@
</div> </div>
<aside class="small-12 medium-3 column"> <aside class="small-12 medium-3 column">
<% if can_create_document?(@proposal) || author_of_proposal?(@proposal) || current_editable?(@proposal) || <% if author_of_proposal?(@proposal) || current_editable?(@proposal) || can_destroy_image?(@proposal) %>
can_destroy_image?(@proposal) %>
<div class="sidebar-divider"></div> <div class="sidebar-divider"></div>
<h2><%= t("proposals.show.author") %></h2> <h2><%= t("proposals.show.author") %></h2>
<div class="show-actions-menu"> <div class="show-actions-menu">
<% if can_create_document?(@proposal) %>
<%= link_to new_document_path(documentable_id: @proposal, documentable_type: @proposal.class.name, from: request.url),
class: 'button hollow expanded' do %>
<span class="icon-document"></span>
<%= t("documents.upload_document") %>
<% end %>
<% end %>
<% if author_of_proposal?(@proposal) %> <% if author_of_proposal?(@proposal) %>
<%= link_to new_proposal_notification_path(proposal_id: @proposal.id), <%= link_to new_proposal_notification_path(proposal_id: @proposal.id),

View File

@@ -97,7 +97,7 @@ Rails.application.routes.draw do
resources :follows, only: [:create, :destroy] resources :follows, only: [:create, :destroy]
resources :documents, only: [:new, :create, :destroy] resources :documents, only: [:destroy]
resources :images, only: [:destroy] resources :images, only: [:destroy]

View File

@@ -81,16 +81,8 @@ describe "Abilities::Administrator" do
it { should be_able_to(:valuate, create(:budget_investment, budget: create(:budget, phase: 'valuating'))) } it { should be_able_to(:valuate, create(:budget_investment, budget: create(:budget, phase: 'valuating'))) }
it { should be_able_to(:valuate, create(:budget_investment, budget: create(:budget, phase: 'finished'))) } it { should be_able_to(:valuate, create(:budget_investment, budget: create(:budget, phase: 'finished'))) }
it { should be_able_to(:new, proposal_document) }
it { should be_able_to(:create, proposal_document) }
it { should be_able_to(:destroy, proposal_document) } it { should be_able_to(:destroy, proposal_document) }
it { should be_able_to(:new, budget_investment_document) }
it { should be_able_to(:create, budget_investment_document) }
it { should be_able_to(:destroy, budget_investment_document) } it { should be_able_to(:destroy, budget_investment_document) }
it { should be_able_to(:new, poll_question_document) }
it { should be_able_to(:create, poll_question_document) }
it { should be_able_to(:destroy, poll_question_document) } it { should be_able_to(:destroy, poll_question_document) }
it { should be_able_to(:destroy, proposal_image) } it { should be_able_to(:destroy, proposal_image) }

View File

@@ -92,20 +92,10 @@ describe "Abilities::Common" do
it { should_not be_able_to(:create, DirectMessage) } it { should_not be_able_to(:create, DirectMessage) }
it { should_not be_able_to(:show, DirectMessage) } it { should_not be_able_to(:show, DirectMessage) }
it { should be_able_to(:new, own_proposal_document) }
it { should be_able_to(:create, own_proposal_document) }
it { should be_able_to(:destroy, own_proposal_document) } it { should be_able_to(:destroy, own_proposal_document) }
it { should_not be_able_to(:new, proposal_document) }
it { should_not be_able_to(:create, proposal_document) }
it { should_not be_able_to(:destroy, proposal_document) } it { should_not be_able_to(:destroy, proposal_document) }
it { should be_able_to(:new, own_budget_investment_document) }
it { should be_able_to(:create, own_budget_investment_document) }
it { should be_able_to(:destroy, own_budget_investment_document) } it { should be_able_to(:destroy, own_budget_investment_document) }
it { should_not be_able_to(:new, budget_investment_document) }
it { should_not be_able_to(:create, budget_investment_document) }
it { should_not be_able_to(:destroy, budget_investment_document) } it { should_not be_able_to(:destroy, budget_investment_document) }
it { should be_able_to(:destroy, own_proposal_image) } it { should be_able_to(:destroy, own_proposal_image) }

View File

@@ -1,7 +1,5 @@
shared_examples "documentable" do |documentable_factory_name, documentable_path, documentable_path_arguments| shared_examples "documentable" do |documentable_factory_name, documentable_path, documentable_path_arguments|
include ActionView::Helpers include ActionView::Helpers
include DocumentsHelper
include DocumentablesHelper
let!(:administrator) { create(:user) } let!(:administrator) { create(:user) }
let!(:user) { create(:user) } let!(:user) { create(:user) }
@@ -17,372 +15,81 @@ shared_examples "documentable" do |documentable_factory_name, documentable_path,
end end
end end
context "Show" do context "Show documents tab" do
scenario "Should not display upload document button when there is no logged user" do let!(:document) { create(:document, documentable: documentable, user: documentable.author)}
scenario "Should not display maximum number of documents alert when reached for users without document creation permission" do
create_list(:document, 2, documentable: documentable)
visit send(documentable_path, arguments) visit send(documentable_path, arguments)
within "##{dom_id(documentable)}" do
expect(page).not_to have_link("Upload document")
end
end
scenario "Should not display upload document button when maximum number of documents reached " do
create_list(:document, 3, documentable: documentable)
visit send(documentable_path, arguments)
within "##{dom_id(documentable)}" do
expect(page).not_to have_link("Upload document")
end
end
scenario "Should display upload document button when user is logged in and is documentable owner" do
login_as(user)
visit send(documentable_path, arguments)
within "##{dom_id(documentable)}" do
expect(page).to have_link("Upload document")
end
end
scenario "Should display upload document button when admin is logged in" do
login_as(administrator)
visit send(documentable_path, arguments)
within "##{dom_id(documentable)}" do
expect(page).to have_link("Upload document")
end
end
scenario "Should navigate to new document page when click un upload button" do
login_as(user)
visit send(documentable_path, arguments)
click_link "Upload document"
expect(page).to have_selector("h1", text: "Upload document")
end
describe "Documents tab" do
let!(:document) { create(:document, documentable: documentable, user: documentable.author)}
scenario "Should not display maximum number of documents alert when reached for users without document creation permission" do
create_list(:document, 2, documentable: documentable)
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).not_to have_content "You have reached the maximum number of documents allowed! You have to delete one before you can upload another."
end
end
scenario "Should display maximum number of documents alert when reached and when current user has document creation permission" do
login_as documentable.author
create_list(:document, 2, documentable: documentable)
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_content "You have reached the maximum number of documents allowed! You have to delete one before you can upload another."
end
end
scenario "Download action should be able to anyone" do
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_link("Dowload file")
end
end
scenario "Download file link should have blank target attribute" do
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_selector("a[target=_blank]", text: "Dowload file")
end
end
scenario "Download file links should have rel attribute setted to no follow" do
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_selector("a[rel=nofollow]", text: "Dowload file")
end
end
describe "Destroy action" do
scenario "Should not be able when no user logged in" do
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).not_to have_link("Destroy")
end
end
scenario "Should be able when documentable author is logged in" do
login_as documentable.author
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_link("Destroy")
end
end
scenario "Should be able when any administrator logged in" do
login_as administrator
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_link("Destroy")
end
end
end
end
end
context "New" do
scenario "Should not be able for unathenticated users" do
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
expect(page).to have_content("You must sign in or register to continue.")
end
scenario "Should not be able for other users" do
login_as create(:user)
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
expect(page).to have_content("You do not have permission to carry out the action 'new' on document. ")
end
scenario "Should be able to documentable author" do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
expect(page).to have_selector("h1", text: "Upload document")
end
scenario "Should display file name after file selection", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true
expect(page).to have_content "empty.pdf"
end
scenario "Should not display file name after file selection", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_document("spec/fixtures/files/logo_header.png", false)
expect(page).not_to have_content "logo_header.jpg"
end
scenario "Should update loading bar style after valid file upload", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_document("spec/fixtures/files/empty.pdf", true)
expect(page).to have_selector ".loading-bar.complete"
end
scenario "Should update loading bar style after unvalid file upload", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_document("spec/fixtures/files/logo_header.png", false)
expect(page).to have_selector ".loading-bar.errors"
end
scenario "Should update document title with attachment original file name after valid upload if no title defined by user", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_document("spec/fixtures/files/empty.pdf", true)
expect(find("input#document_title").value).to eq("empty.pdf")
end
scenario "Should update document title with attachment original file name after invalid upload if no title defined by user", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_document("spec/fixtures/files/logo_header.png", false)
expect(find("input#document_title").value).to be_empty
end
scenario "Should not update document title with attachment original file name after file selection when title already defined by user", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
fill_in :document_title, with: "My custom title"
attach_document("spec/fixtures/files/empty.pdf", true)
expect(find("input[name='document[title]']").value).to eq("My custom title")
end
scenario "Should update document cached_attachment field after valid file upload", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_document("spec/fixtures/files/empty.pdf", true)
expect(page).to have_css("input[name='document[cached_attachment]'][value$='.pdf']", visible: false)
end
scenario "Should not show 'Choose document' button after valid upload", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true
sleep 1
expect(page).not_to have_content "Choose document"
end
scenario "Should show 'Remove document' button after valid upload", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true
sleep 1
expect(page).to have_link("Remove document")
end
scenario "Should show 'Choose document' button after remove valid upload", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_file :document_attachment, "spec/fixtures/files/empty.pdf", make_visible: true
sleep 1
click_link "Remove document"
sleep 1
expect(page).to have_content "Choose document"
end
scenario "Should not update document cached_attachment field after unvalid file upload", :js do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
attach_document("spec/fixtures/files/logo_header.png", false)
expect(find("input[name='document[cached_attachment]']", visible: false).value).to eq("")
end
scenario "Should show documentable custom recomentations" do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id,
from: send(documentable_path, arguments))
expect(page).to have_content "You can upload up to a maximum of #{max_file_size(documentable.class)} documents."
expect(page).to have_content "You can upload #{documentable_humanized_accepted_content_types(documentable.class)} files."
expect(page).to have_content "You can upload files up to #{max_file_size(documentable.class)} MB."
end
end
context "Create" do
scenario "Should show validation errors" do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id)
click_on "Upload document"
expect(page).to have_content "2 errors prevented this Document from being saved: "
expect(page).to have_selector "small.error", text: "can't be blank", count: 2
end
scenario "Should show error notice after unsuccessfull document upload" do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id,
from: send(documentable_path, arguments))
attach_file :document_attachment, "spec/fixtures/files/empty.pdf"
click_on "Upload document"
expect(page).to have_content "Cannot create document. Check form errors and try again."
end
scenario "Should show success notice after successfull document upload" do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id,
from: send(documentable_path, arguments))
fill_in :document_title, with: "Document title"
attach_file :document_attachment, "spec/fixtures/files/empty.pdf"
click_on "Upload document"
expect(page).to have_content "Document was created successfully."
end
scenario "Should redirect to documentable path after successfull document upload" do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id,
from: send(documentable_path, arguments))
fill_in :document_title, with: "Document title"
attach_file :document_attachment, "spec/fixtures/files/empty.pdf"
click_on "Upload document"
within "##{dom_id(documentable)}" do
expect(page).to have_selector "h1", text: documentable.title
end
end
scenario "Should show new document on documentable documents tab after successfull document upload" do
login_as documentable.author
visit new_document_path(documentable_type: documentable.class.name,
documentable_id: documentable.id,
from: send(documentable_path, arguments))
fill_in :document_title, with: "Document title"
attach_file :document_attachment, "spec/fixtures/files/empty.pdf"
click_on "Upload document"
expect(page).to have_link "Documents (1)"
within "#tab-documents" do within "#tab-documents" do
within "#document_#{Document.last.id}" do expect(page).not_to have_content "You have reached the maximum number of documents allowed! You have to delete one before you can upload another."
expect(page).to have_content "Document title" end
expect(page).to have_link "Dowload file" end
expect(page).to have_link "Destroy"
scenario "Should display maximum number of documents alert when reached and when current user has document creation permission" do
login_as documentable.author
create_list(:document, 2, documentable: documentable)
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_content "You have reached the maximum number of documents allowed! You have to delete one before you can upload another."
end
end
scenario "Download action should be able to anyone" do
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_link("Dowload file")
end
end
scenario "Download file link should have blank target attribute" do
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_selector("a[target=_blank]", text: "Dowload file")
end
end
scenario "Download file links should have rel attribute setted to no follow" do
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_selector("a[rel=nofollow]", text: "Dowload file")
end
end
describe "Destroy action" do
scenario "Should not be able when no user logged in" do
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).not_to have_link("Destroy")
end end
end end
scenario "Should be able when documentable author is logged in" do
login_as documentable.author
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_link("Destroy")
end
end
scenario "Should be able when any administrator logged in" do
login_as administrator
visit send(documentable_path, arguments)
within "#tab-documents" do
expect(page).to have_link("Destroy")
end
end
end end
end end