@@ -545,7 +545,7 @@ footer {
|
|||||||
// 04. Tags
|
// 04. Tags
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
.tags a , .tag-cloud a, .categories a, .geozone a {
|
.tags a , .tag-cloud a, .categories a, .geozone a, .sidebar-links a {
|
||||||
background: #ececec;
|
background: #ececec;
|
||||||
border-radius: rem-calc(6);
|
border-radius: rem-calc(6);
|
||||||
color: $text;
|
color: $text;
|
||||||
@@ -1730,9 +1730,12 @@ table {
|
|||||||
border: 0;
|
border: 0;
|
||||||
|
|
||||||
td {
|
td {
|
||||||
padding-left: $line-height*1.5;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
word-break: break-all;
|
|
||||||
|
&:first-child {
|
||||||
|
padding-left: $line-height*1.5;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
color: $brand;
|
color: $brand;
|
||||||
@@ -1743,19 +1746,31 @@ table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.activity-comments td:before {
|
&.activity-comments td:first-child:before {
|
||||||
content: "e";
|
content: "e";
|
||||||
top: 18px;
|
top: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.activity-debates td:before {
|
&.activity-debates td:first-child:before {
|
||||||
content: "i";
|
content: "i";
|
||||||
top: 14px;
|
top: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.activity-proposals td:before {
|
&.activity-proposals {
|
||||||
content: "h";
|
|
||||||
top: 18px;
|
td:first-child:before {
|
||||||
|
content: "h";
|
||||||
|
top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.retired {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.activity-investment-projects td:first-child:before {
|
||||||
|
content: "\53";
|
||||||
|
top: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -343,6 +343,10 @@
|
|||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.callout.proposal-retired {
|
||||||
|
font-size: $base-font-size;
|
||||||
|
}
|
||||||
|
|
||||||
.social-share-full .social-share-button {
|
.social-share-full .social-share-button {
|
||||||
display:inline;
|
display:inline;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,14 @@ class ProposalsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def index_customization
|
def index_customization
|
||||||
@featured_proposals = Proposal.all.sort_by_confidence_score.limit(3) if (!@advanced_search_terms && @search_terms.blank? && @tag_filter.blank?)
|
if params[:retired].present?
|
||||||
|
@resources = @resources.retired
|
||||||
|
@resources = @resources.where(retired_reason: params[:retired]) if Proposal::RETIRE_OPTIONS.include?(params[:retired])
|
||||||
|
else
|
||||||
|
@resources = @resources.not_retired
|
||||||
|
end
|
||||||
|
|
||||||
|
@featured_proposals = Proposal.all.sort_by_confidence_score.limit(3) if (!@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank?)
|
||||||
if @featured_proposals.present?
|
if @featured_proposals.present?
|
||||||
set_featured_proposal_votes(@featured_proposals)
|
set_featured_proposal_votes(@featured_proposals)
|
||||||
@resources = @resources.where('proposals.id NOT IN (?)', @featured_proposals.map(&:id))
|
@resources = @resources.where('proposals.id NOT IN (?)', @featured_proposals.map(&:id))
|
||||||
@@ -35,6 +42,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 +69,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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -42,6 +45,8 @@ class Proposal < ActiveRecord::Base
|
|||||||
scope :sort_by_relevance, -> { all }
|
scope :sort_by_relevance, -> { all }
|
||||||
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
|
||||||
scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
|
scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
|
||||||
|
scope :retired, -> { where.not(retired_at: nil) }
|
||||||
|
scope :not_retired, -> { where(retired_at: nil) }
|
||||||
|
|
||||||
def to_param
|
def to_param
|
||||||
"#{id}-#{title}".parameterize
|
"#{id}-#{title}".parameterize
|
||||||
@@ -105,6 +110,10 @@ class Proposal < ActiveRecord::Base
|
|||||||
user && user.level_two_or_three_verified?
|
user && user.level_two_or_three_verified?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def retired?
|
||||||
|
retired_at.present?
|
||||||
|
end
|
||||||
|
|
||||||
def register_vote(user, vote_value)
|
def register_vote(user, vote_value)
|
||||||
if votable_by?(user)
|
if votable_by?(user)
|
||||||
vote_by(voter: user, vote: vote_value)
|
vote_by(voter: user, vote: vote_value)
|
||||||
|
|||||||
13
app/views/proposals/_retired.html.erb
Normal file
13
app/views/proposals/_retired.html.erb
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<div class="sidebar-divider"></div>
|
||||||
|
<h3 class="sidebar-title"><%= t("proposals.index.retired_proposals") %></h3>
|
||||||
|
|
||||||
|
<% if params[:retired].blank? %>
|
||||||
|
<p><%= link_to t("proposals.index.retired_proposals_link"), proposals_path(retired: 'all'), class: "small" %></p>
|
||||||
|
<% else %>
|
||||||
|
<div class="sidebar-links">
|
||||||
|
<%= link_to t("proposals.index.retired_links.all"), proposals_path(retired: 'all'), ({class: "small"} unless params[:retired] == 'all') %>
|
||||||
|
<% Proposal::RETIRE_OPTIONS.each do |option| %>
|
||||||
|
<%= link_to t("proposals.index.retired_links.#{option}"), proposals_path(retired: option), ({class: "small"} unless params[:retired] == option) %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
@@ -22,6 +22,8 @@
|
|||||||
<%= page_entries_info @proposals %>
|
<%= page_entries_info @proposals %>
|
||||||
<%= t("proposals.index.filter_topic", count: @proposals.size, topic: @tag_filter) %>
|
<%= t("proposals.index.filter_topic", count: @proposals.size, topic: @tag_filter) %>
|
||||||
</h2>
|
</h2>
|
||||||
|
<% elsif params[:retired].present? %>
|
||||||
|
<h2><%= t("proposals.index.retired_proposals") %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -38,7 +40,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= render "shared/advanced_search", search_path: proposals_path(page: 1)%>
|
<%= render("shared/advanced_search", search_path: proposals_path(page: 1)) unless params[:retired].present? %>
|
||||||
|
|
||||||
<%= render 'shared/order_links', i18n_namespace: "proposals.index" %>
|
<%= render 'shared/order_links', i18n_namespace: "proposals.index" %>
|
||||||
|
|
||||||
@@ -53,10 +55,13 @@
|
|||||||
<div class="small-12 medium-3 column">
|
<div class="small-12 medium-3 column">
|
||||||
<aside class="margin-bottom">
|
<aside class="margin-bottom">
|
||||||
<%= link_to t("proposals.index.start_proposal"), new_proposal_path, class: 'button expanded' %>
|
<%= link_to t("proposals.index.start_proposal"), new_proposal_path, class: 'button expanded' %>
|
||||||
<%= render "shared/tag_cloud", taggable: 'proposal' %>
|
<% if params[:retired].blank? %>
|
||||||
<%= render 'categories' %>
|
<%= render "shared/tag_cloud", taggable: 'proposal' %>
|
||||||
<%= render 'geozones' %>
|
<%= render 'categories' %>
|
||||||
<%= render 'popular' %>
|
<%= render 'geozones' %>
|
||||||
|
<%= render 'popular' %>
|
||||||
|
<% end %>
|
||||||
|
<%= render 'retired' %>
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
38
app/views/proposals/retire_form.html.erb
Normal file
38
app/views/proposals/retire_form.html.erb
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<div class="proposal-edit row">
|
||||||
|
|
||||||
|
<div class="small-12 column">
|
||||||
|
|
||||||
|
<h1 class="inline-block"><%= t("proposals.retire_form.title") %></h1>
|
||||||
|
|
||||||
|
<h3><%= link_to @proposal.title, @proposal %></h3>
|
||||||
|
|
||||||
|
<div data-alert class="callout warning">
|
||||||
|
<%= 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 large-4 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>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="small-12 medium-9 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>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="actions small-12 medium-3 column">
|
||||||
|
<%= f.submit(class: "button expanded", value: t("proposals.retire_form.submit_button")) %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -22,7 +22,14 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<h1><%= @proposal.title %></h1>
|
<h1><%= @proposal.title %></h1>
|
||||||
<% if @proposal.conflictive? %>
|
<% if @proposal.retired? %>
|
||||||
|
<div data-alert class="callout alert margin-top proposal-retired">
|
||||||
|
<strong>
|
||||||
|
<%= t("proposals.show.retired_warning") %><br>
|
||||||
|
<%= link_to t("proposals.show.retired_warning_link_to_explanation"), "#retired_explanation" %>
|
||||||
|
</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 +81,13 @@
|
|||||||
|
|
||||||
<h4><%= @proposal.question %></h4>
|
<h4><%= @proposal.question %></h4>
|
||||||
|
|
||||||
|
<% if @proposal.retired? %>
|
||||||
|
<div id="retired_explanation" class="callout">
|
||||||
|
<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 %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<%= render 'shared/tags', taggable: @proposal %>
|
<%= render 'shared/tags', taggable: @proposal %>
|
||||||
|
|
||||||
<%= render 'shared/geozone', geozonable: @proposal %>
|
<%= render 'shared/geozone', geozonable: @proposal %>
|
||||||
|
|||||||
@@ -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: 'retired'} : {} %>
|
||||||
<br>
|
<br>
|
||||||
<%= proposal.summary %>
|
<%= proposal.summary %>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<% if proposal.retired? %>
|
||||||
|
<span class="label alert"><%= t('users.show.retired') %></span>
|
||||||
|
<% else %>
|
||||||
|
<%= link_to t('users.show.retire'),
|
||||||
|
retire_form_proposal_path(proposal),
|
||||||
|
class: 'delete' %>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
<table id="spending_proposals_list" class="clear activity-proposals">
|
<table id="spending_proposals_list" class="clear activity-investment-projects">
|
||||||
<% @spending_proposals.each do |spending_proposal| %>
|
<% @spending_proposals.each do |spending_proposal| %>
|
||||||
<tr id="spending_proposal_<%= spending_proposal.id %>">
|
<tr id="spending_proposal_<%= spending_proposal.id %>">
|
||||||
<td>
|
<td>
|
||||||
<%= link_to spending_proposal.title, spending_proposal %>
|
<%= link_to spending_proposal.title, spending_proposal %>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
<% if can?(:destroy, spending_proposal) %>
|
<% if can?(:destroy, spending_proposal) %>
|
||||||
<%= link_to t("users.show.delete_spending_proposal"),
|
<%= link_to t("users.show.delete_spending_proposal"),
|
||||||
spending_proposal,
|
spending_proposal,
|
||||||
method: :delete,
|
method: :delete,
|
||||||
data: { confirm: t("users.show.confirm_deletion_spending_proposal") },
|
data: { confirm: t("users.show.confirm_deletion_spending_proposal") },
|
||||||
class: 'button small warning' %>
|
class: 'delete' %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -282,6 +296,15 @@ en:
|
|||||||
hot_score: most active
|
hot_score: most active
|
||||||
most_commented: most commented
|
most_commented: most commented
|
||||||
relevance: relevance
|
relevance: relevance
|
||||||
|
retired_proposals: Retired proposals
|
||||||
|
retired_proposals_link: "Proposals retired by the author"
|
||||||
|
retired_links:
|
||||||
|
all: All
|
||||||
|
duplicated: Duplicated
|
||||||
|
started: Underway
|
||||||
|
unfeasible: Unfeasible
|
||||||
|
done: Done
|
||||||
|
other: Other
|
||||||
search_form:
|
search_form:
|
||||||
button: Search
|
button: Search
|
||||||
placeholder: Search proposals...
|
placeholder: Search proposals...
|
||||||
@@ -305,6 +328,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 +358,9 @@ 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."
|
||||||
|
retired_warning_link_to_explanation: Read the explanation before voting for it.
|
||||||
|
retired: Proposal retired by the author
|
||||||
share: Share
|
share: Share
|
||||||
update:
|
update:
|
||||||
form:
|
form:
|
||||||
@@ -490,6 +518,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}.
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -282,6 +296,15 @@ es:
|
|||||||
hot_score: Más activas hoy
|
hot_score: Más activas hoy
|
||||||
most_commented: Más comentadas
|
most_commented: Más comentadas
|
||||||
relevance: Más relevantes
|
relevance: Más relevantes
|
||||||
|
retired_proposals: Propuestas retiradas
|
||||||
|
retired_proposals_link: "Propuestas retiradas por sus autores"
|
||||||
|
retired_links:
|
||||||
|
all: Todas
|
||||||
|
duplicated: Duplicadas
|
||||||
|
started: Empezadas
|
||||||
|
unfeasible: Inviables
|
||||||
|
done: Hechas
|
||||||
|
other: Otras
|
||||||
search_form:
|
search_form:
|
||||||
button: Buscar
|
button: Buscar
|
||||||
placeholder: Buscar propuestas...
|
placeholder: Buscar propuestas...
|
||||||
@@ -305,6 +328,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 +358,9 @@ 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."
|
||||||
|
retired_warning_link_to_explanation: Revisa su explicación antes de apoyarla.
|
||||||
|
retired: Propuesta retirada por el autor
|
||||||
share: Compartir
|
share: Compartir
|
||||||
update:
|
update:
|
||||||
form:
|
form:
|
||||||
@@ -490,6 +518,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}.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
5
db/migrate/20160420105023_add_retired_to_proposals.rb
Normal file
5
db/migrate/20160420105023_add_retired_to_proposals.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class AddRetiredToProposals < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :proposals, :retired_at, :datetime, default: nil
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
class AddRetiredTextsToProposals < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :proposals, :retired_reason, :string, default: nil
|
||||||
|
add_column :proposals, :retired_explanation, :text, default: nil
|
||||||
|
end
|
||||||
|
end
|
||||||
25
db/schema.rb
25
db/schema.rb
@@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20160418172919) do
|
ActiveRecord::Schema.define(version: 20160422094733) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@@ -239,27 +239,30 @@ ActiveRecord::Schema.define(version: 20160418172919) do
|
|||||||
add_index "organizations", ["user_id"], name: "index_organizations_on_user_id", using: :btree
|
add_index "organizations", ["user_id"], name: "index_organizations_on_user_id", using: :btree
|
||||||
|
|
||||||
create_table "proposals", force: :cascade do |t|
|
create_table "proposals", force: :cascade do |t|
|
||||||
t.string "title", limit: 80
|
t.string "title", limit: 80
|
||||||
t.text "description"
|
t.text "description"
|
||||||
t.string "question"
|
t.string "question"
|
||||||
t.string "external_url"
|
t.string "external_url"
|
||||||
t.integer "author_id"
|
t.integer "author_id"
|
||||||
t.datetime "hidden_at"
|
t.datetime "hidden_at"
|
||||||
t.integer "flags_count", default: 0
|
t.integer "flags_count", default: 0
|
||||||
t.datetime "ignored_flag_at"
|
t.datetime "ignored_flag_at"
|
||||||
t.integer "cached_votes_up", default: 0
|
t.integer "cached_votes_up", default: 0
|
||||||
t.integer "comments_count", default: 0
|
t.integer "comments_count", default: 0
|
||||||
t.datetime "confirmed_hide_at"
|
t.datetime "confirmed_hide_at"
|
||||||
t.integer "hot_score", limit: 8, default: 0
|
t.integer "hot_score", limit: 8, default: 0
|
||||||
t.integer "confidence_score", default: 0
|
t.integer "confidence_score", default: 0
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.string "responsible_name", limit: 60
|
t.string "responsible_name", limit: 60
|
||||||
t.text "summary"
|
t.text "summary"
|
||||||
t.string "video_url"
|
t.string "video_url"
|
||||||
t.integer "physical_votes", default: 0
|
t.integer "physical_votes", default: 0
|
||||||
t.tsvector "tsv"
|
t.tsvector "tsv"
|
||||||
t.integer "geozone_id"
|
t.integer "geozone_id"
|
||||||
|
t.datetime "retired_at"
|
||||||
|
t.string "retired_reason"
|
||||||
|
t.text "retired_explanation"
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "proposals", ["author_id", "hidden_at"], name: "index_proposals_on_author_id_and_hidden_at", using: :btree
|
add_index "proposals", ["author_id", "hidden_at"], name: "index_proposals_on_author_id_and_hidden_at", using: :btree
|
||||||
|
|||||||
@@ -88,27 +88,27 @@ feature 'Proposals' do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "Embedded video" do
|
context "Embedded video" do
|
||||||
scenario "Show YouTube video" do
|
scenario "Show YouTube video" do
|
||||||
proposal = create(:proposal, video_url: "http://www.youtube.com/watch?v=a7UFm6ErMPU")
|
proposal = create(:proposal, video_url: "http://www.youtube.com/watch?v=a7UFm6ErMPU")
|
||||||
visit proposal_path(proposal)
|
visit proposal_path(proposal)
|
||||||
expect(page).to have_selector("div[id='js-embedded-video']")
|
expect(page).to have_selector("div[id='js-embedded-video']")
|
||||||
expect(page.html).to include 'https://www.youtube.com/embed/a7UFm6ErMPU'
|
expect(page.html).to include 'https://www.youtube.com/embed/a7UFm6ErMPU'
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "Show Vimeo video" do
|
scenario "Show Vimeo video" do
|
||||||
proposal = create(:proposal, video_url: "https://vimeo.com/7232823" )
|
proposal = create(:proposal, video_url: "https://vimeo.com/7232823" )
|
||||||
visit proposal_path(proposal)
|
visit proposal_path(proposal)
|
||||||
expect(page).to have_selector("div[id='js-embedded-video']")
|
expect(page).to have_selector("div[id='js-embedded-video']")
|
||||||
expect(page.html).to include 'https://player.vimeo.com/video/7232823'
|
expect(page.html).to include 'https://player.vimeo.com/video/7232823'
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "Dont show video" do
|
scenario "Dont show video" do
|
||||||
proposal = create(:proposal, video_url: nil)
|
proposal = create(:proposal, video_url: nil)
|
||||||
|
|
||||||
visit proposal_path(proposal)
|
visit proposal_path(proposal)
|
||||||
expect(page).to_not have_selector("div[id='js-embedded-video']")
|
expect(page).to_not have_selector("div[id='js-embedded-video']")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario 'Social Media Cards' do
|
scenario 'Social Media Cards' do
|
||||||
proposal = create(:proposal)
|
proposal = create(:proposal)
|
||||||
@@ -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,100 @@ feature 'Proposals' do
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'Retired proposals' 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
|
||||||
|
|
||||||
|
scenario 'Index do not list retired proposals by default' do
|
||||||
|
create_featured_proposals
|
||||||
|
not_retired = create(:proposal)
|
||||||
|
retired = create(:proposal, retired_at: Time.now)
|
||||||
|
|
||||||
|
visit proposals_path
|
||||||
|
|
||||||
|
expect(page).to have_selector('#proposals .proposal', count: 1)
|
||||||
|
within('#proposals') do
|
||||||
|
expect(page).to have_content not_retired.title
|
||||||
|
expect(page).to_not have_content retired.title
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Index has a link to retired proposals list' do
|
||||||
|
create_featured_proposals
|
||||||
|
not_retired = create(:proposal)
|
||||||
|
retired = create(:proposal, retired_at: Time.now)
|
||||||
|
|
||||||
|
visit proposals_path
|
||||||
|
|
||||||
|
expect(page).to_not have_content retired.title
|
||||||
|
click_link 'Proposals retired by the author'
|
||||||
|
|
||||||
|
expect(page).to have_content retired.title
|
||||||
|
expect(page).to_not have_content not_retired.title
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Retired proposals index interface elements' do
|
||||||
|
visit proposals_path(retired: 'all')
|
||||||
|
|
||||||
|
expect(page).to_not have_content 'Advanced search'
|
||||||
|
expect(page).to_not have_content 'Categories'
|
||||||
|
expect(page).to_not have_content 'Districts'
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Retired proposals index has links to filter by retired_reason' do
|
||||||
|
unfeasible = create(:proposal, retired_at: Time.now, retired_reason: 'unfeasible')
|
||||||
|
duplicated = create(:proposal, retired_at: Time.now, retired_reason: 'duplicated')
|
||||||
|
|
||||||
|
visit proposals_path(retired: 'all')
|
||||||
|
|
||||||
|
expect(page).to have_content unfeasible.title
|
||||||
|
expect(page).to have_content duplicated.title
|
||||||
|
expect(page).to have_link 'Duplicated'
|
||||||
|
expect(page).to have_link 'Underway'
|
||||||
|
expect(page).to have_link 'Unfeasible'
|
||||||
|
expect(page).to have_link 'Done'
|
||||||
|
expect(page).to have_link 'Other'
|
||||||
|
|
||||||
|
click_link 'Unfeasible'
|
||||||
|
|
||||||
|
expect(page).to have_content unfeasible.title
|
||||||
|
expect(page).to_not have_content duplicated.title
|
||||||
|
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
|
||||||
|
|||||||
@@ -741,4 +741,30 @@ describe Proposal do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "retired" do
|
||||||
|
before(:all) do
|
||||||
|
@proposal1 = create(:proposal)
|
||||||
|
@proposal2 = create(:proposal, retired_at: Time.now)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "retired? is true" do
|
||||||
|
expect(@proposal1.retired?).to eq false
|
||||||
|
expect(@proposal2.retired?).to eq true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "scope retired" do
|
||||||
|
retired = Proposal.retired
|
||||||
|
|
||||||
|
expect(retired.size).to eq(1)
|
||||||
|
expect(retired.first).to eq(@proposal2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "scope not_retired" do
|
||||||
|
not_retired = Proposal.not_retired
|
||||||
|
|
||||||
|
expect(not_retired.size).to eq(1)
|
||||||
|
expect(not_retired.first).to eq(@proposal1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user