authors can retire proposals now

This commit is contained in:
Juanjo Bazán
2016-04-22 14:42:49 +02:00
parent be011a10dc
commit 58a5e2a283
11 changed files with 174 additions and 10 deletions

View File

@@ -35,6 +35,17 @@ class ProposalsController < ApplicationController
set_proposal_votes(@proposal) set_proposal_votes(@proposal)
end end
def retire
if valid_retired_params? && @proposal.update(retired_params.merge(retired_at: Time.now))
redirect_to proposal_path(@proposal), notice: t('proposals.notice.retired')
else
render action: :retire_form
end
end
def retire_form
end
def vote_featured def vote_featured
@proposal.register_vote(current_user, 'yes') @proposal.register_vote(current_user, 'yes')
set_featured_proposal_votes(@proposal) set_featured_proposal_votes(@proposal)
@@ -51,6 +62,16 @@ class ProposalsController < ApplicationController
params.require(:proposal).permit(:title, :question, :summary, :description, :external_url, :video_url, :responsible_name, :tag_list, :terms_of_service, :captcha, :captcha_key, :geozone_id) params.require(:proposal).permit(:title, :question, :summary, :description, :external_url, :video_url, :responsible_name, :tag_list, :terms_of_service, :captcha, :captcha_key, :geozone_id)
end end
def retired_params
params.require(:proposal).permit(:retired_reason, :retired_explanation)
end
def valid_retired_params?
@proposal.errors.add(:retired_reason, I18n.t('errors.messages.blank')) if params[:proposal][:retired_reason].blank?
@proposal.errors.add(:retired_explanation, I18n.t('errors.messages.blank')) if params[:proposal][:retired_explanation].blank?
@proposal.errors.empty?
end
def resource_model def resource_model
Proposal Proposal
end end

View File

@@ -28,4 +28,8 @@ module ProposalsHelper
end end
end end
def retire_proposals_options
Proposal::RETIRE_OPTIONS.collect { |option| [ t("proposals.retire_options.#{option}"), option ] }
end
end end

View File

@@ -16,6 +16,7 @@ module Abilities
can :update, Proposal do |proposal| can :update, Proposal do |proposal|
proposal.editable_by?(user) proposal.editable_by?(user)
end end
can [:retire_form, :retire], Proposal, author_id: user.id
can :read, SpendingProposal can :read, SpendingProposal

View File

@@ -12,6 +12,8 @@ class Proposal < ActiveRecord::Base
acts_as_paranoid column: :hidden_at acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases include ActsAsParanoidAliases
RETIRE_OPTIONS = %w(duplicated started unfeasible done other)
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
belongs_to :geozone belongs_to :geozone
has_many :comments, as: :commentable has_many :comments, as: :commentable
@@ -26,6 +28,7 @@ class Proposal < ActiveRecord::Base
validates :description, length: { maximum: Proposal.description_max_length } validates :description, length: { maximum: Proposal.description_max_length }
validates :question, length: { in: 10..Proposal.question_max_length } validates :question, length: { in: 10..Proposal.question_max_length }
validates :responsible_name, length: { in: 6..Proposal.responsible_name_max_length } validates :responsible_name, length: { in: 6..Proposal.responsible_name_max_length }
validates :retired_reason, inclusion: {in: RETIRE_OPTIONS, allow_nil: true}
validates :terms_of_service, acceptance: { allow_nil: false }, on: :create validates :terms_of_service, acceptance: { allow_nil: false }, on: :create

View File

@@ -0,0 +1,37 @@
<div class="proposal-edit row">
<div class="small-12 column">
<div class="float-right">
<%= link_to @proposal.title, @proposal %>
</div>
<h1><%= t("proposals.retire_form.title") %></h1>
<div data-alert class="callout primary">
<%= t("proposals.retire_form.warning") %>
</div>
<%= form_for(@proposal, url: retire_proposal_path(@proposal)) do |f| %>
<%= render 'shared/errors', resource: @proposal %>
<div class="row">
<div class="small-12 medium-6 column">
<%= f.label :retired_reason, t("proposals.retire_form.retired_reason_label") %>
<%= f.select :retired_reason, retire_proposals_options, {include_blank: t("proposals.retire_form.retired_reason_blank"), label: false} %>
</div>
<div class="small-12 column">
<%= f.label :retired_explanation, t("proposals.retire_form.retired_explanation_label") %>
<%= f.text_area :retired_explanation, rows: 4, maxlength: 500, label: false,
placeholder: t('proposals.retire_form.retired_explanation_placeholder') %>
</div>
<div class="actions small-12 column">
<%= f.submit(class: "button", value: t("proposals.retire_form.submit_button")) %>
</div>
</div>
<% end %>
</div>
</div>

View File

@@ -22,7 +22,11 @@
<% end %> <% end %>
<h1><%= @proposal.title %></h1> <h1><%= @proposal.title %></h1>
<% if @proposal.conflictive? %> <% if @proposal.retired? %>
<div data-alert class="callout alert margin-top">
<strong><%= t("proposals.show.retired_warning") %></strong>
</div>
<% elsif @proposal.conflictive? %>
<div data-alert class="callout alert margin-top"> <div data-alert class="callout alert margin-top">
<strong><%= t("proposals.show.flag") %></strong> <strong><%= t("proposals.show.flag") %></strong>
</div> </div>
@@ -74,6 +78,11 @@
<h4><%= @proposal.question %></h4> <h4><%= @proposal.question %></h4>
<% if @proposal.retired? %>
<h2><%= t('proposals.show.retired') %>: <%= t("proposals.retire_options.#{@proposal.retired_reason}") unless @proposal.retired_reason == 'other' %></h2>
<%= simple_format text_with_links(@proposal.retired_explanation), {}, sanitize: false %>
<% end %>
<%= render 'shared/tags', taggable: @proposal %> <%= render 'shared/tags', taggable: @proposal %>
<%= render 'shared/geozone', geozonable: @proposal %> <%= render 'shared/geozone', geozonable: @proposal %>

View File

@@ -2,10 +2,19 @@
<% @proposals.each do |proposal| %> <% @proposals.each do |proposal| %>
<tr id="proposal_<%= proposal.id %>"> <tr id="proposal_<%= proposal.id %>">
<td> <td>
<%= link_to proposal.title, proposal %> <%= link_to proposal.title, proposal, proposal.retired? ? {class: 'delete'} : {} %>
<br> <br>
<%= proposal.summary %> <%= proposal.summary %>
</td> </td>
<td>
<% if proposal.retired? %>
<%= t('users.show.retired') %>
<% else %>
<%= link_to t('users.show.retire'),
retire_form_proposal_path(proposal),
class: 'delete' %>
<% end %>
</td>
</tr> </tr>
<% end %> <% end %>
</table> </table>

View File

@@ -254,6 +254,20 @@ en:
form: form:
submit_button: Save changes submit_button: Save changes
show_link: View proposal show_link: View proposal
retire_form:
title: Retire proposal
warning: "If you retire the proposal it would still accept supports, but will be removed from the main list and a message will be visible to all users stating that the author considers the proposal should not be supported anymore"
retired_reason_label: Reason to retire the proposal
retired_reason_blank: Choose an option
retired_explanation_label: Explanation
retired_explanation_placeholder: Explain shortly why you think this proposal should not receive more supports
submit_button: Retire proposal
retire_options:
duplicated: Duplicated
started: Already underway
unfeasible: Unfeasible
done: Done
other: Other
form: form:
geozone: Scope of operation geozone: Scope of operation
proposal_external_url: Link to additional documentation proposal_external_url: Link to additional documentation
@@ -305,6 +319,8 @@ en:
recommendation_two: Any proposal or comment suggesting illegal action will be deleted, as well as those intending to sabotage the debate spaces. Anything else is allowed. recommendation_two: Any proposal or comment suggesting illegal action will be deleted, as well as those intending to sabotage the debate spaces. Anything else is allowed.
recommendations_title: Recommendations for creating a proposal recommendations_title: Recommendations for creating a proposal
start_new: Create new proposal start_new: Create new proposal
notice:
retired: Proposal retired
proposal: proposal:
already_supported: You have already supported this proposal. Share it! already_supported: You have already supported this proposal. Share it!
comments: comments:
@@ -333,6 +349,8 @@ en:
edit_proposal_link: Edit edit_proposal_link: Edit
flag: This proposal has been flagged as inappropriate by several users. flag: This proposal has been flagged as inappropriate by several users.
login_to_comment: You must %{signin} or %{signup} to leave a comment. login_to_comment: You must %{signin} or %{signup} to leave a comment.
retired_warning: "The author considers this proposal should not receive more supports. check the explanation before voting for it."
retired: Proposal retired by the author
share: Share share: Share
update: update:
form: form:
@@ -489,6 +507,8 @@ en:
other: "%{count} Spending proposals" other: "%{count} Spending proposals"
no_activity: User has no public activity no_activity: User has no public activity
private_activity: This user decided to keep the activity list private private_activity: This user decided to keep the activity list private
retire: Retire
retired: Retired
votes: votes:
agree: I agree agree: I agree
anonymous: Too many anonymous votes to admit vote %{verify_account}. anonymous: Too many anonymous votes to admit vote %{verify_account}.

View File

@@ -254,6 +254,20 @@ es:
form: form:
submit_button: Guardar cambios submit_button: Guardar cambios
show_link: Ver propuesta show_link: Ver propuesta
retire_form:
title: Retirar propuesta
warning: "Si sigues adelante tu propuesta podrá seguir recibiendo apoyos, pero dejará de ser listada en la lista principal, y aparecerá un mensaje para todos los usuarios avisándoles de que el autor considera que esta propuesta no debe seguir recogiendo apoyos."
retired_reason_label: Razón por la que se retira la propuesta
retired_reason_blank: Selecciona una opción
retired_explanation_label: Explicación
retired_explanation_placeholder: Explica brevemente por que consideras que esta propuesta no debe recoger más apoyos
submit_button: Retirar propuesta
retire_options:
duplicated: Duplicada
started: Ejecutándose
unfeasible: Inviable
done: Hecha
other: Otra
form: form:
geozone: "Ámbito de actuación" geozone: "Ámbito de actuación"
proposal_external_url: Enlace a documentación adicional proposal_external_url: Enlace a documentación adicional
@@ -305,6 +319,8 @@ es:
recommendation_two: Cualquier propuesta o comentario que implique una acción ilegal será eliminada, también las que tengan la intención de sabotear los espacios de propuesta, todo lo demás está permitido. recommendation_two: Cualquier propuesta o comentario que implique una acción ilegal será eliminada, también las que tengan la intención de sabotear los espacios de propuesta, todo lo demás está permitido.
recommendations_title: Recomendaciones para crear una propuesta recommendations_title: Recomendaciones para crear una propuesta
start_new: Crear una propuesta start_new: Crear una propuesta
notice:
retired: Propuesta retirada
proposal: proposal:
already_supported: "¡Ya has apoyado esta propuesta, compártela!" already_supported: "¡Ya has apoyado esta propuesta, compártela!"
comments: comments:
@@ -333,6 +349,8 @@ es:
edit_proposal_link: Editar propuesta edit_proposal_link: Editar propuesta
flag: Esta propuesta ha sido marcada como inapropiada por varios usuarios. flag: Esta propuesta ha sido marcada como inapropiada por varios usuarios.
login_to_comment: Necesitas %{signin} o %{signup} para comentar. login_to_comment: Necesitas %{signin} o %{signup} para comentar.
retired_warning: "El autor de esta propuesta considera que ya no debe seguir recogiendo apoyos. Revisa su explicación antes de apoyarla."
retired: Propuesta retirada por el autor
share: Compartir share: Compartir
update: update:
form: form:
@@ -489,6 +507,8 @@ es:
other: "%{count} Propuestas de inversión" other: "%{count} Propuestas de inversión"
no_activity: Usuario sin actividad pública no_activity: Usuario sin actividad pública
private_activity: Este usuario ha decidido mantener en privado su lista de actividades private_activity: Este usuario ha decidido mantener en privado su lista de actividades
retire: Retirar
retired: Retirada
votes: votes:
agree: Estoy de acuerdo agree: Estoy de acuerdo
anonymous: Demasiados votos anónimos, para poder votar %{verify_account}. anonymous: Demasiados votos anónimos, para poder votar %{verify_account}.

View File

@@ -49,6 +49,8 @@ Rails.application.routes.draw do
post :vote_featured post :vote_featured
put :flag put :flag
put :unflag put :unflag
get :retire_form
patch :retire
end end
collection do collection do
get :map get :map

View File

@@ -375,7 +375,7 @@ feature 'Proposals' do
end end
end end
context "Geozones" do context 'Geozones' do
scenario "Default whole city" do scenario "Default whole city" do
author = create(:user) author = create(:user)
@@ -430,6 +430,44 @@ feature 'Proposals' do
end end
context 'Retire a proposal' do
scenario 'Retire' do
proposal = create(:proposal)
login_as(proposal.author)
visit user_path(proposal.author)
within("#proposal_#{proposal.id}") do
click_link 'Retire'
end
expect(current_path).to eq(retire_form_proposal_path(proposal))
select 'Duplicated', from: 'proposal_retired_reason'
fill_in 'proposal_retired_explanation', with: 'There are three other better proposals with the same subject'
click_button "Retire proposal"
expect(page).to have_content "Proposal retired"
visit proposal_path(proposal)
expect(page).to have_content proposal.title
expect(page).to have_content 'Proposal retired by the author'
expect(page).to have_content 'Duplicated'
expect(page).to have_content 'There are three other better proposals with the same subject'
end
scenario 'Fields are mandatory' do
proposal = create(:proposal)
login_as(proposal.author)
visit retire_form_proposal_path(proposal)
click_button 'Retire proposal'
expect(page).to_not have_content 'Proposal retired'
expect(page).to have_content "can't be blank", count: 2
end
end
scenario 'Update should not be posible if logged user is not the author' do scenario 'Update should not be posible if logged user is not the author' do
proposal = create(:proposal) proposal = create(:proposal)
expect(proposal).to be_editable expect(proposal).to be_editable