Add nested documents to proposal form.

This commit is contained in:
Senén Rodero Rodríguez
2017-08-23 18:26:05 +02:00
parent 723173ae39
commit cc89907bff
25 changed files with 501 additions and 104 deletions

View File

@@ -1,17 +1,26 @@
App.Documentable = App.Documentable =
initialize: -> initialize: ->
@initializeDirectUploads()
@initializeInterface()
initializeDirectUploads: ->
$('input.document_ajax_attachment[type=file]').fileupload $('input.document_ajax_attachment[type=file]').fileupload
paramName : "document[attachment]" paramName: "document[attachment]"
formData: null formData: null
add: (e, data) -> add: (e, data) ->
wrapper = $(e.target).parent() wrapper = $(e.target).parent()
index = $(e.target).data('index')
$(wrapper).find('.progress-bar-placeholder').empty() $(wrapper).find('.progress-bar-placeholder').empty()
data.progressBar = $(wrapper).find('.progress-bar-placeholder').html('<div class="progress-bar"><div class="loading-bar uploading"></div></div>') data.progressBar = $(wrapper).find('.progress-bar-placeholder').html('<div class="progress-bar"><div class="loading-bar uploading"></div></div>')
data.formData = {
"document[title]": $(wrapper).find('input.document-title').val() || data.files[0].name
"index": index
}
data.submit() data.submit()
change: (e, data) -> change: (e, data) ->
@@ -25,15 +34,51 @@ App.Documentable =
$(data.progressBar).find('.loading-bar').css 'width', progress + '%' $(data.progressBar).find('.loading-bar').css 'width', progress + '%'
return return
done: (e, data) -> initializeInterface: ->
result = data.response().result input_files = $('input.document_ajax_attachment[type=file]')
if result.status == 200
$(data.progressBar).find('.loading-bar').removeClass 'uploading'
$(data.progressBar).find('.loading-bar').addClass 'complete'
inputId = '#' + $(e.target).data('cached-attachment-input-field')
$(inputId).val result.attachment
else
$(data.progressBar).find('.loading-bar').addClass 'errors'
$(data.progressBar).prepend("<span>" + result.msg + "</span>")
return
$.each input_files, (index, file) ->
wrapper = $(file).parent()
App.Documentable.watchRemoveDocumentbutton(wrapper)
watchRemoveDocumentbutton: (wrapper) ->
remove_document_button = $(wrapper).find('.remove-document')
$(remove_document_button).on 'click', (e) ->
e.preventDefault()
$(wrapper).remove()
$('#new_document_link').show()
$('.max-documents-notice').hide()
upload: (id, nested_document, result) ->
$('#' + id).replaceWith(nested_document)
if result
$('#' + id).find('.loading-bar').addClass 'complete'
else
$('#' + id).find('.loading-bar').addClass 'errors'
@initialize()
new: (nested_fields) ->
$(".documents-list").append(nested_fields)
@initialize()
destroy: (id, notice) ->
$('#' + id).remove()
@updateNotice(notice)
updateNotice: (notice) ->
if $('[data-alert]').length > 0
$('[data-alert]').replaceWith(notice)
else
$("body").append(notice)
updateNewDocumentButton: (link) ->
if $('.document').length >= $('.documents').data('max-documents')
$('#new_document_link').hide()
$('.max-documents-notice').removeClass('hide')
$('.max-documents-notice').show()
else if $('#new_document_link').length > 0
$('#new_document_link').replaceWith(link)
$('.max-documents-notice').hide()
else
$('.max-documents-notice').hide()
$(link).insertBefore('.documents hr:last')

View File

@@ -28,7 +28,7 @@ App.Forms =
i = 0 i = 0
while i < element.length while i < element.length
element[i].addEventListener 'change', -> element[i].addEventListener 'change', ->
$(element).parent().find('.file-name').text(@files[0].name) $(element).parent().find('.file-name').text(@files[i].name)
return return
i++ i++

View File

@@ -18,9 +18,11 @@
} }
&.complete{ &.complete{
background-color: #0f0; background-color: #0f0;
width: 100%;
} }
&.errors{ &.errors{
background-color: #f00; background-color: #f00;
width: 100%;
} }
} }

View File

@@ -28,7 +28,6 @@ module CommentableActions
def new def new
@resource = resource_model.new @resource = resource_model.new
prepare_new_resource_documents(@resource)
set_geozone set_geozone
set_resource_instance set_resource_instance
end end
@@ -55,12 +54,12 @@ module CommentableActions
end end
def edit def edit
prepare_edit_resource_documents(resource)
end end
def update def update
resource.assign_attributes(strong_params) resource.assign_attributes(strong_params)
parse_documents(resource) recover_documents_from_cache(resource)
if resource.save if resource.save
redirect_to resource, notice: t("flash.actions.update.#{resource_name.underscore}") redirect_to resource, notice: t("flash.actions.update.#{resource_name.underscore}")
else else
@@ -113,28 +112,12 @@ module CommentableActions
nil nil
end end
def prepare_new_resource_documents(resource) def recover_documents_from_cache(resource)
return false unless resource.try(:documents) return false unless resource.try(:documents)
(1..resource.class.max_documents_allowed).each do
resource.documents.build
end
end
def prepare_edit_resource_documents(resource)
return false unless resource.try(:documents)
(resource.documents.size + 1 .. resource.class.max_documents_allowed).each do
resource.documents.build
end
resource
end
def parse_documents(resource)
return false unless resource.try(:documents)
resource.documents.each do |document|
document.user = current_user
end
resource.documents = resource.documents.each do |document| resource.documents = resource.documents.each do |document|
document.attachment = File.open(document.cached_attachment) if document.cached_attachment.present? if document.cached_attachment.present? && File.exists?(document.cached_attachment)
document.attachment = File.open(document.cached_attachment)
end
end end
end end

View File

@@ -1,6 +1,6 @@
class DocumentsController < ApplicationController class DocumentsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_filter :find_documentable, except: :destroy before_filter :find_documentable, except: [:destroy]
before_filter :prepare_new_document, only: :new before_filter :prepare_new_document, only: :new
before_filter :prepare_document_for_creation, only: :create before_filter :prepare_document_for_creation, only: :create
@@ -22,6 +22,8 @@ class DocumentsController < ApplicationController
end end
def destroy def destroy
respond_to do |format|
format.html do
if @document.destroy if @document.destroy
flash[:notice] = t "documents.actions.destroy.notice" flash[:notice] = t "documents.actions.destroy.notice"
else else
@@ -29,30 +31,52 @@ class DocumentsController < ApplicationController
end end
redirect_to params[:from] redirect_to params[:from]
end end
format.js do
if @document.destroy
flash.now[:notice] = t "documents.actions.destroy.notice"
else
flash.now[:alert] = t "documents.actions.destroy.alert"
end
end
end
end
def destroy_upload
@document = Document.new(attachment: File.open(params[:path]))
@document.documentable = @documentable
if @document.attachment.destroy
flash.now[:notice] = t "documents.actions.destroy.notice"
else
flash.now[:alert] = t "documents.actions.destroy.alert"
end
render:destroy
end
def upload def upload
attachment = params[:document][:attachment] @document = Document.new(document_params.merge(user: current_user))
document = Document.new(documentable: @documentable, attachment: attachment.tempfile, title: "faketitle", user: current_user ) @document.documentable = @documentable
# We only are intested in attachment validators. We set some fake data to get attachment errors only if @document.valid?
document.valid? @document.attachment.save
if document.errors[:attachment].empty? @document.cached_attachment = @document.attachment.path
# Move image from tmp to cache
msg = { status: 200, attachment: attachment.tempfile.path }
else else
attachment.tempfile.delete @document.attachment.destroy
msg = { status: 422, msg: document.errors[:attachment].join(', ') }
end end
render :json => msg
end end
private private
def document_params
params.require(:document).permit(:title, :documentable_type, :documentable_id,
:attachment, :cached_attachment, :user_id)
end
def find_documentable def find_documentable
@documentable = params[:documentable_type].constantize.find_or_initialize_by(id: params[:documentable_id]) @documentable = params[:documentable_type].constantize.find_or_initialize_by(id: params[:documentable_id])
end end
def prepare_new_document def prepare_new_document
@document = Document.new(documentable: @documentable, user_id: @documentable.author_id) @document = Document.new(documentable: @documentable, user_id: current_user.id)
end end
def prepare_document_for_creation def prepare_document_for_creation
@@ -61,11 +85,6 @@ class DocumentsController < ApplicationController
@document.user = current_user @document.user = current_user
end end
def document_params
params.require(:document).permit(:title, :documentable_type, :documentable_id,
:attachment, :cached_attachment)
end
def recover_attachment_from_cache def recover_attachment_from_cache
if @document.attachment.blank? && @document.cached_attachment.present? if @document.attachment.blank? && @document.cached_attachment.present?
@document.attachment = File.open(@document.cached_attachment) @document.attachment = File.open(@document.cached_attachment)

View File

@@ -25,12 +25,11 @@ class ProposalsController < ApplicationController
def create def create
@proposal = Proposal.new(proposal_params.merge(author: current_user)) @proposal = Proposal.new(proposal_params.merge(author: current_user))
parse_documents(@proposal) recover_documents_from_cache(@proposal)
if @proposal.save if @proposal.save
redirect_to share_proposal_path(@proposal), notice: I18n.t('flash.actions.create.proposal') redirect_to share_proposal_path(@proposal), notice: I18n.t('flash.actions.create.proposal')
else else
@proposal = prepare_edit_resource_documents(@proposal)
render :new render :new
end end
end end
@@ -79,7 +78,7 @@ class ProposalsController < ApplicationController
def proposal_params def proposal_params
params.require(:proposal).permit(:title, :question, :summary, :description, :external_url, :video_url, params.require(:proposal).permit(:title, :question, :summary, :description, :external_url, :video_url,
:responsible_name, :tag_list, :terms_of_service, :geozone_id, :responsible_name, :tag_list, :terms_of_service, :geozone_id,
documents_attributes: [:id, :title, :attachment, :cached_attachment ] ) documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id] )
end end
def retired_params def retired_params

View File

@@ -16,8 +16,8 @@ module DocumentablesHelper
documentable.class.accepted_content_types documentable.class.accepted_content_types
end end
def accepted_content_types_extensions(documentable) def accepted_content_types_extensions(documentable_class)
documentable.class.accepted_content_types documentable_class.accepted_content_types
.collect{ |content_type| ".#{content_type.split("/").last}" } .collect{ |content_type| ".#{content_type.split("/").last}" }
.join(",") .join(",")
end end
@@ -28,4 +28,10 @@ module DocumentablesHelper
.join(", ") .join(", ")
end end
def documentables_note(documentable)
t "documents.form.note", max_documents_allowed: max_documents_allowed(documentable),
accepted_content_types: humanized_accepted_content_types(documentable),
max_file_size: max_file_size(documentable)
end
end end

View File

@@ -1,7 +1,7 @@
module DocumentsHelper module DocumentsHelper
def document_attachment_file_name(document) def document_attachment_file_name(document)
document.attachment_file_name if document.attachment.exists? document.attachment_file_name
end end
def errors_on_attachment(document) def errors_on_attachment(document)
@@ -22,4 +22,18 @@ module DocumentsHelper
bytes / Numeric::MEGABYTE bytes / Numeric::MEGABYTE
end end
def document_nested_field_name(document, index, field)
parent = document.documentable_type.constantize.name.downcase
"#{parent}[documents_attributes][#{index}][#{field}]"
end
def document_nested_field_id(document, index, field)
parent = document.documentable_type.constantize.name.downcase
"#{parent}_documents_attributes_#{index}_#{field}"
end
def document_nested_field_wrapper_id(index)
"document_#{index}"
end
end end

View File

@@ -37,6 +37,7 @@ module Abilities
can [:create, :destroy], Follow can [:create, :destroy], Follow
can [:create, :destroy], Document, documentable: { author_id: user.id } can [:create, :destroy], Document, documentable: { author_id: user.id }
can [:new, :destroy_upload], Document
unless user.organization? unless user.organization?
can :vote, Debate can :vote, Debate

View File

@@ -16,7 +16,7 @@ class Document < ActiveRecord::Base
validate :validate_attachment_content_type, if: -> { attachment.present? } validate :validate_attachment_content_type, if: -> { attachment.present? }
validate :validate_attachment_size, if: -> { attachment.present? } validate :validate_attachment_size, if: -> { attachment.present? }
validates :title, presence: true validates :title, presence: true
validates :user, presence: true validates :user_id, presence: true
# validates :documentable_id, presence: true # validates :documentable_id, presence: true
# validates :documentable_type, presence: true # validates :documentable_type, presence: true

View File

@@ -13,7 +13,7 @@
<% if can? :destroy, Document %> <% if can? :destroy, Document %>
<%= link_to t('documents.buttons.destroy_document'), <%= link_to t('documents.buttons.destroy_document'),
document_path(document, from: request.url), method: :delete, document_path(document, from: request.url), method: :delete,
data: { confirm: t('documents.actions.destroy.alert') }, data: { confirm: t('documents.actions.destroy.confirm') },
class: 'button hollow alert' %> class: 'button hollow alert' %>
<% end %> <% end %>
</td> </td>

View File

@@ -18,7 +18,7 @@
<div class="small-12 column"> <div class="small-12 column">
<%= f.hidden_field :cached_attachment %> <%= f.hidden_field :cached_attachment %>
<%= f.file_field :attachment, <%= f.file_field :attachment,
accept: accepted_content_types_extensions(@document.documentable), accept: accepted_content_types_extensions(@document.documentable.class),
label: false, label: false,
class: 'document_ajax_attachment show-for-sr', class: 'document_ajax_attachment show-for-sr',
data: { data: {

View File

@@ -0,0 +1,68 @@
<div id="<%= document_nested_field_wrapper_id(index) %>" class="document">
<%= hidden_field_tag :id,
document.id,
name: document_nested_field_name(document, index, :id),
id: document_nested_field_id(document, index, :id) if document.persisted? %>
<%= hidden_field_tag :user_id,
current_user.id,
name: document_nested_field_name(document, index, :user_id),
id: document_nested_field_id(document, index, :user_id) %>
<%= hidden_field_tag :cached_attachment,
document.cached_attachment,
name: document_nested_field_name(document, index, :cached_attachment),
id: document_nested_field_id(document, index, :cached_attachment) %>
<%= label_tag :title, t("activerecord.attributes.document.title") %>
<%= text_field_tag :title,
document.title,
name: document_nested_field_name(document, index, :title),
id: document_nested_field_id(document, index, :title),
class: "document-title" %>
<% if document.errors[:title].any? %>
<small class="error"><%= document.errors[:title].join(", ") %></small>
<br>
<% end %>
<%= file_field_tag :attachment,
accept: accepted_content_types_extensions(document.documentable_type.constantize),
class: 'document_ajax_attachment show-for-sr',
data: {
url: upload_documents_url(
documentable_type: document.documentable_type,
documentable_id: document.documentable_id,
format: :js
),
cached_attachment_input_field: "#{document.documentable.class.name.downcase}_documents_attributes_#{index}_cached_attachment",
multiple: false,
index: index
},
name: document_nested_field_name(document, index, :attachment),
id: document_nested_field_id(document, index, :attachment) %>
<% if document.persisted? %>
<%= link_to t('documents.form.delete_button'), document_path(document, index: index),
method: :delete,
remote: true,
data: { confirm: t('documents.actions.destroy.confirm') },
class: "button hollow alert" if document.persisted? %>
<% elsif !document.persisted? && document.cached_attachment.present? %>
<%= link_to t('documents.form.delete_button'), destroy_upload_documents_path(path: document.cached_attachment, index: index, documentable_type: document.documentable_type, documentable_id: document.documentable_id),
method: :delete,
remote: true,
class: "button hollow alert" %>
<% else %>
<%= label_tag document_nested_field_id(document, index, :attachment),
t("documents.form.attachment_label"),
class: "button hollow #{"error" if document.errors[:attachment].any?}" %>
<%= link_to t('documents.form.delete_button'), "#", class: "button hollow alert remove-document" %>
<% if document.errors[:attachment].any? %>
<br>
<small class="error"><%= document.errors[:attachment].join(", ") %></small>
<br>
<% end %>
<% end %>
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
<p class="file-name"><%= document_attachment_file_name(document) %></p>
<hr>
</div>

View File

@@ -0,0 +1,24 @@
<div class="documents-list">
<%= label_tag :documents, t("documents.form.title") %>
<p class="help-text"><%= documentables_note(resource) %></p>
<% resource.documents.each_with_index do |document, index| %>
<%= render 'documents/nested_document', document: document, index: index, resource: resource %>
<% end %>
</div>
<% if resource.documents.count < resource.class.max_documents_allowed %>
<%= link_to t("documents.form.add_new_document"),
new_document_path(documentable_type: resource.class.name, index: resource.documents.size),
remote: true,
id: "new_document_link" %>
<div class="max-documents-notice callout warning text-center hide">
<%= t "documents.max_documents_allowed_reached_html" %>
</div>
<% else %>
<div class="max-documents-notice callout warning text-center">
<%= t "documents.max_documents_allowed_reached_html" %>
</div>
<% end %>
<hr>

View File

@@ -1,29 +0,0 @@
<%= form.label :documents %>
<p class="help-text">Aquí puedes añadir hasta 3 doucmentos en formato PDF </p>
<% documents.each_with_index do |document, index| %>
<div>
<%= form.fields_for :documents, document do |document_fields| %>
<%= document_fields.text_field :title %>
<%= document_fields.hidden_field :cached_attachment, value: document.attachment.path %>
<%= document_fields.file_field :attachment,
accept: accepted_content_types_extensions(resource),
label: false,
class: 'document_ajax_attachment show-for-sr',
data: {
url: upload_documents_url(
documentable_type: document_fields.object.documentable_type,
documentable_id: document_fields.object.documentable_id
),
cached_attachment_input_field: "#{resource.class.name.downcase}_documents_attributes_#{index}_cached_attachment",
multiple: false
} %>
<%= document_fields.label :attachment, t("documents.form.attachment_label"), class: 'button hollow' %>
<div class="progress-bar-placeholder"></div>
<p class="file-name"><%= document_attachment_file_name(document) %></p>
<% if document.errors[:attachment].any? %>
<div class="error"><%= document.errors[:attachment].join(", ") %></div>
<% end %>
<% end %>
</div>
<hr>
<% end %>

View File

@@ -0,0 +1,6 @@
App.Documentable.destroy("<%= document_nested_field_wrapper_id(params[:index]) %>", "<%= j render('layouts/flash') %>")
<% new_document_link = link_to t("documents.form.add_new_document"),
new_document_path(documentable_type: @document.documentable_type, index: params[:index]),
remote: true,
id: "new_document_link" %>
App.Documentable.updateNewDocumentButton("<%= j new_document_link %>")

View File

@@ -0,0 +1,9 @@
<%
nested_fields = render 'documents/nested_document', document: @document, index: params[:index]
new_document_link = link_to "Añadir nuevo documento",
new_document_path(documentable_type: params[:documentable_type], index: params[:index].to_i + 1),
remote: true,
id: "new_document_link"
%>
App.Documentable.new("<%= j nested_fields %>")
App.Documentable.updateNewDocumentButton("<%= j new_document_link %>")

View File

@@ -0,0 +1,9 @@
<%
nested_fields = render 'documents/nested_document', document: @document, index: params[:index]
%>
<% if @document.cached_attachment.present? %>
App.Documentable.upload("<%= document_nested_field_wrapper_id(params[:index]) %>", "<%= j nested_fields %>", true)
<% else %>
App.Documentable.upload("<%= document_nested_field_wrapper_id(params[:index]) %>", "<%= j nested_fields %>", false)
<% end %>

View File

@@ -34,7 +34,6 @@
<%= f.cktext_area :description, maxlength: Proposal.description_max_length, ckeditor: { language: I18n.locale }, label: false %> <%= f.cktext_area :description, maxlength: Proposal.description_max_length, ckeditor: { language: I18n.locale }, label: false %>
</div> </div>
<div class="small-12 column"> <div class="small-12 column">
<%= f.label :video_url, t("proposals.form.proposal_video_url") %> <%= f.label :video_url, t("proposals.form.proposal_video_url") %>
<p class="help-text" id="video-url-help-text"><%= t("proposals.form.proposal_video_url_note") %></p> <p class="help-text" id="video-url-help-text"><%= t("proposals.form.proposal_video_url_note") %></p>
@@ -47,8 +46,8 @@
<%= f.text_field :external_url, placeholder: t("proposals.form.proposal_external_url"), label: false %> <%= f.text_field :external_url, placeholder: t("proposals.form.proposal_external_url"), label: false %>
</div> </div>
<div class="small-12 column"> <div class="documents small-12 column" data-max-documents="<%= Proposal.max_documents_allowed %>">
<%= render 'documents/nested_form_fields', form: f, resource: @proposal, documents: @proposal.documents %> <%= render 'documents/nested_documents', resource: @proposal %>
</div> </div>
<div class="small-12 medium-6 column"> <div class="small-12 medium-6 column">

View File

@@ -5,14 +5,19 @@ en:
upload_document: Upload document upload_document: Upload document
max_documents_allowed_reached_html: You have reached the maximum number of documents allowed! <strong>You have to delete one before you can upload another.</strong> max_documents_allowed_reached_html: You have reached the maximum number of documents allowed! <strong>You have to delete one before you can upload another.</strong>
form: form:
attachment_label: Choose attachment file title: Documents
attachment_label: Choose document
submit_button: Upload document submit_button: Upload document
delete_button: Remove document
note: "You can upload up to a maximum of %{max_documents_allowed} documents of following content types: %{accepted_content_types}, up to %{max_file_size} MB per file."
add_new_document: Add new document
new: new:
title: Upload document title: Upload document
recommendations_title: File upload tips recommendations_title: File upload tips
recommendation_one_html: You can upload up to a <strong>maximum of %{max_documents_allowed} documents</strong>. recommendation_one_html: You can upload up to a <strong>maximum of %{max_documents_allowed} documents</strong>.
recommendation_two_html: You can upload <strong>%{accepted_content_types}</strong> files. recommendation_two_html: You can upload <strong>%{accepted_content_types}</strong> files.
recommendation_three_html: You can upload files up to <strong>%{max_file_size} MB</strong>. recommendation_three_html: You can upload files up to <strong>%{max_file_size} MB</strong>.
actions: actions:
create: create:
notice: Document was created successfully. notice: Document was created successfully.
@@ -20,6 +25,7 @@ en:
destroy: destroy:
notice: Document was deleted successfully. notice: Document was deleted successfully.
alert: Cannot destroy document. alert: Cannot destroy document.
confirm: Are you sure you want to delete the document? This action cannot be undone!
buttons: buttons:
download_document: Dowload file download_document: Dowload file
destroy_document: Destroy destroy_document: Destroy

View File

@@ -5,8 +5,12 @@ es:
upload_document: Subir documento upload_document: Subir documento
max_documents_allowed_reached_html: ¡Has alcanzado el número máximo de documentos permitidos! <strong>Tienes que eliminar uno antes de poder subir otro.</strong> max_documents_allowed_reached_html: ¡Has alcanzado el número máximo de documentos permitidos! <strong>Tienes que eliminar uno antes de poder subir otro.</strong>
form: form:
attachment_label: Selecciona un archivo title: Documentos
attachment_label: Selecciona un documento
submit_button: Subir documento submit_button: Subir documento
delete_button: Eliminar documento
note: "Puedes subir hasta un máximo de %{max_documents_allowed} documentos en los formatos: %{accepted_content_types}, y de hasta %{max_file_size} MB por archivo."
add_new_document: Añadir nuevo documento
new: new:
title: Subir un documento title: Subir un documento
recommendations_title: Consejos para subir archivos recommendations_title: Consejos para subir archivos
@@ -20,6 +24,7 @@ es:
destroy: destroy:
notice: "El documento se ha eliminado correctamente." notice: "El documento se ha eliminado correctamente."
alert: "El documento no se ha podido eliminar." alert: "El documento no se ha podido eliminar."
confirm: "¿Está seguro de que desea eliminar el documento? Esta acción no se puede deshacer!"
buttons: buttons:
download_document: Descargar archivo download_document: Descargar archivo
destroy_document: Eliminar destroy_document: Eliminar

View File

@@ -96,8 +96,11 @@ Rails.application.routes.draw do
resources :follows, only: [:create, :destroy] resources :follows, only: [:create, :destroy]
resources :documents, only: [:new, :create, :destroy] do resources :documents, only: [:new, :create, :destroy] do
collection { post :upload, format: :json} collection do
collection { post :progress, format: :json} delete :destroy_upload
post :upload
post :progress
end
end end
resources :stats, only: [:index] resources :stats, only: [:index]

View File

@@ -936,7 +936,7 @@ ActiveRecord::Schema.define(version: 20170720092638) do
t.boolean "email_digest", default: true t.boolean "email_digest", default: true
t.boolean "email_on_direct_message", default: true t.boolean "email_on_direct_message", default: true
t.boolean "official_position_badge", default: false t.boolean "official_position_badge", default: false
t.datetime "password_changed_at", default: '2017-07-31 21:36:00', null: false t.datetime "password_changed_at", default: '2017-08-22 16:28:06', null: false
t.boolean "created_from_signature", default: false t.boolean "created_from_signature", default: false
t.integer "failed_email_digests_count", default: 0 t.integer "failed_email_digests_count", default: 0
t.text "former_users_data_log", default: "" t.text "former_users_data_log", default: ""

View File

@@ -1230,6 +1230,8 @@ feature 'Proposals' do
it_behaves_like "documentable", "proposal", "proposal_path", { "id": "id" } it_behaves_like "documentable", "proposal", "proposal_path", { "id": "id" }
it_behaves_like "nested documentable", "proposal", "new_proposal_path"
scenario 'Erased author' do scenario 'Erased author' do
user = create(:user) user = create(:user)
proposal = create(:proposal, author: user) proposal = create(:proposal, author: user)

View File

@@ -0,0 +1,226 @@
shared_examples "nested documentable" do |documentable_factory_name, new_documentable_path, documentable_path_arguments|
include ActionView::Helpers
include DocumentsHelper
include DocumentablesHelper
let!(:administrator) { create(:user) }
let!(:user) { create(:user) }
let!(:arguments) { {} }
let!(:documentable) { create(documentable_factory_name, author: user) }
before do
create(:administrator, user: administrator)
if documentable_path_arguments
documentable_path_arguments.each do |argument_name, path_to_value|
arguments.merge!("#{argument_name}": documentable.send(path_to_value))
end
end
end
context "Nested documents" do
context "On documentable new" do
scenario "Should show new document link" do
login_as user
visit send(new_documentable_path, arguments)
expect(page).to have_selector "#new_document_link", visible: true
end
scenario "Should not show new document when documentable max documents allowed limit is reached", :js do
login_as user
visit send(new_documentable_path, arguments)
find("#new_document_link").click
sleep 1
find("#new_document_link").click
sleep 1
find("#new_document_link").click
expect(page).to have_selector "#new_document_link", visible: false
end
scenario "Should not show max documents warning when no documents added", :js do
login_as user
visit send(new_documentable_path, arguments)
expect(page).to have_selector ".max-documents-notice", visible: false
end
scenario "Should show max documents warning when max documents allowed limit is reached", :js do
login_as user
visit send(new_documentable_path, arguments)
find("#new_document_link").click
sleep 1
find("#new_document_link").click
sleep 1
find("#new_document_link").click
expect(page).to have_selector ".max-documents-notice", visible: true
end
scenario "Should hide max documents warning after any document link", :js do
login_as user
visit send(new_documentable_path, arguments)
find("#new_document_link").click
sleep 1
find("#new_document_link").click
sleep 1
find("#new_document_link").click
sleep 1
within "#document_0" do
find("a", text: "Remove document").click
end
sleep 1
expect(page).to have_selector ".max-documents-notice", visible: false
end
scenario "Should update nested document file name after choosing a file", :js do
login_as user
visit send(new_documentable_path, arguments)
click_link "Add new document"
attach_file "#{documentable_factory_name}[documents_attributes][0][attachment]", "spec/fixtures/files/empty.pdf"
expect(page).to have_selector ".file-name", text: "empty.pdf"
end
scenario "Should update nested document file title with file name after choosing a file when no title defined", :js do
login_as user
visit send(new_documentable_path, arguments)
click_link "Add new document"
attach_file "#{documentable_factory_name}[documents_attributes][0][attachment]", "spec/fixtures/files/empty.pdf"
sleep 1
expect(find("##{documentable_factory_name}_documents_attributes_0_title").value).to eq "empty.pdf"
end
scenario "Should not update nested document file title with file name after choosing a file when title already defined", :js do
login_as user
visit send(new_documentable_path, arguments)
click_link "Add new document"
fill_in "#{documentable_factory_name}[documents_attributes][0][title]", with: "Title"
attach_file "#{documentable_factory_name}[documents_attributes][0][attachment]", "spec/fixtures/files/empty.pdf"
sleep 1
expect(find("##{documentable_factory_name}_documents_attributes_0_title").value).to eq "Title"
end
scenario "Should update loading bar style after valid file upload", :js do
login_as user
visit send(new_documentable_path, arguments)
click_link "Add new document"
fill_in "#{documentable_factory_name}[documents_attributes][0][title]", with: "Title"
attach_file "#{documentable_factory_name}[documents_attributes][0][attachment]", "spec/fixtures/files/empty.pdf"
sleep 1
expect(page).to have_selector ".loading-bar.complete"
end
scenario "Should update loading bar style after unvalid file upload", :js do
login_as user
visit send(new_documentable_path, arguments)
click_link "Add new document"
fill_in "#{documentable_factory_name}[documents_attributes][0][title]", with: "Title"
attach_file "#{documentable_factory_name}[documents_attributes][0][attachment]", "spec/fixtures/files/logo_header.png"
sleep 1
expect(page).to have_selector ".loading-bar.errors"
end
scenario "Should update document cached_attachment field after valid file upload", :js do
login_as user
visit send(new_documentable_path, arguments)
click_link "Add new document"
fill_in "#{documentable_factory_name}[documents_attributes][0][title]", with: "Title"
attach_file "#{documentable_factory_name}[documents_attributes][0][attachment]", "spec/fixtures/files/empty.pdf"
sleep 1
expect(find("input[name='#{documentable_factory_name}[documents_attributes][0][cached_attachment]']", visible: false).value).to include("empty.pdf")
end
scenario "Should not update document cached_attachment field after unvalid file upload", :js do
login_as user
visit send(new_documentable_path, arguments)
click_link "Add new document"
fill_in "#{documentable_factory_name}[documents_attributes][0][title]", with: "Title"
attach_file "#{documentable_factory_name}[documents_attributes][0][attachment]", "spec/fixtures/files/logo_header.png"
sleep 1
expect(find("input[name='#{documentable_factory_name}[documents_attributes][0][cached_attachment]']", visible: false).value).to eq ""
end
scenario "Should show document errors after unvalid file upload", :js do
login_as user
visit send(new_documentable_path, arguments)
click_link "Add new document"
sleep 1
click_on "Create #{documentable_factory_name}"
within "#document_0" do
expect(page).to have_content("can't be blank", count: 2)
end
end
scenario "Should delete document after valid file upload and click on remove button", :js do
login_as user
visit send(new_documentable_path, arguments)
click_link "Add new document"
sleep 1
attach_file "#{documentable_factory_name}[documents_attributes][0][attachment]", "spec/fixtures/files/empty.pdf"
sleep 1
within "#document_0" do
click_link "Remove document"
end
expect(page).not_to have_selector("#document_0")
end
scenario "Should delete document after valid file upload and click on remove button", :js do
login_as user
visit send(new_documentable_path, arguments)
click_link "Add new document"
sleep 1
attach_file "#{documentable_factory_name}[documents_attributes][0][attachment]", "spec/fixtures/files/empty.pdf"
sleep 1
within "#document_0" do
click_link "Remove document"
end
expect(page).to have_content "Document was deleted successfully."
end
scenario "Should delete document after valid file upload and click on remove button", :js do
login_as user
visit send(new_documentable_path, arguments)
click_link "Add new document"
sleep 1
attach_file "#{documentable_factory_name}[documents_attributes][0][attachment]", "spec/fixtures/files/empty.pdf"
sleep 1
within "#document_0" do
click_link "Remove document"
end
expect(page).to have_content "Document was deleted successfully."
end
end
end
end