Merge pull request #1085 from consul/retire-proposals

Retire proposals
This commit is contained in:
Juanjo Bazán
2016-04-25 18:00:34 +02:00
20 changed files with 375 additions and 38 deletions

View File

@@ -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;
} }
} }
} }

View File

@@ -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;
} }

View File

@@ -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

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
@@ -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)

View 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 %>

View File

@@ -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>

View 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>

View File

@@ -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 %>

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: '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>

View File

@@ -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>

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
@@ -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}.

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
@@ -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}.

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

@@ -0,0 +1,5 @@
class AddRetiredToProposals < ActiveRecord::Migration
def change
add_column :proposals, :retired_at, :datetime, default: nil
end
end

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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