Merge pull request #3099 from consul/backport-2740-add_milestones_to_proposals

Add milestones to proposals
This commit is contained in:
Javier Martín
2018-12-12 15:05:01 +01:00
committed by GitHub
20 changed files with 262 additions and 103 deletions

View File

@@ -284,10 +284,6 @@ $sidebar-active: #f4fcd0;
.proposal-form {
padding-top: 0;
}
.proposal-show {
padding-top: rem-calc(54);
}
}
.is-featured {

View File

@@ -0,0 +1,8 @@
class Admin::ProposalMilestonesController < Admin::MilestonesController
private
def milestoneable
Proposal.find(params[:proposal_id])
end
end

View File

@@ -0,0 +1,18 @@
class Admin::ProposalsController < Admin::BaseController
include HasOrders
include CommentableActions
include FeatureFlags
feature_flag :proposals
has_orders %w[created_at]
def show
@proposal = Proposal.find(params[:id])
end
private
def resource_model
Proposal
end
end

View File

@@ -20,6 +20,7 @@ class Proposal < ActiveRecord::Base
accepted_content_types: [ "application/pdf" ]
include EmbedVideosHelper
include Relationable
include Milestoneable
acts_as_votable
acts_as_paranoid column: :hidden_at

View File

@@ -79,6 +79,15 @@
</li>
<% end %>
<% if feature?(:proposals) %>
<li class="section-title">
<%= link_to admin_proposals_path do %>
<span class="icon-proposals"></span>
<strong><%= t("admin.menu.proposals") %></strong>
<% end %>
</li>
<% end %>
<% messages_sections = %w(newsletters emails_download admin_notifications system_emails) %>
<% messages_menu_active = messages_sections.include?(controller_name) %>
<li class="section-title" <%= "class=is-active" if messages_menu_active %>>

View File

@@ -0,0 +1,39 @@
<% provide(:title) do %>
<%= t("admin.header.title") %> - <%= t("admin.proposals.index.title") %>
<% end %>
<h2><%= t("admin.proposals.index.title") %></h2>
<% if @proposals.any? %>
<%= render "/admin/shared/proposal_search", url: admin_proposals_path %>
<h3><%= page_entries_info @proposals %></h3>
<table>
<thead>
<tr>
<th class="text-center"><%= t("admin.proposals.index.id") %></th>
<th><%= t("admin.proposals.index.title") %></th>
<th><%= t("admin.proposals.index.author") %></th>
<th><%= t("admin.proposals.index.milestones") %></th>
</tr>
</thead>
<tbody>
<% @proposals.each do |proposal| %>
<tr id="<%= dom_id(proposal) %>" class="proposal">
<td class="text-center"><%= proposal.id %></td>
<td><%= link_to proposal.title, admin_proposal_path(proposal) %></td>
<td><%= proposal.author.username %></td>
<td><%= proposal.milestones.count %></td>
</tr>
<% end %>
</tbody>
</table>
<%= paginate @proposals %>
<% else %>
<div class="callout primary">
<%= t("admin.proposals.index.no_proposals") %>
</div>
<% end %>

View File

@@ -0,0 +1,11 @@
<% provide :title do %>
<%= t("admin.header.title") %> - <%= t("admin.menu.proposals") %> - <%= @proposal.title %>
<% end %>
<div class="proposal-show">
<h2><%= @proposal.title %></h2>
<%= render "proposals/info", proposal: @proposal %>
</div>
<%= render "admin/milestones/milestones", milestoneable: @proposal %>

View File

@@ -21,4 +21,12 @@
</h3>
<% end %>
</li>
<li class="tabs-title">
<%= link_to "#tab-milestones" do %>
<h3>
<%= t("proposals.show.milestones_tab") %>
(<%= @proposal.milestones.count %>)
</h3>
<% end %>
</li>
</ul>

View File

@@ -0,0 +1,84 @@
<div class="proposal-info">
<%= render '/shared/author_info', resource: @proposal %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<%= l @proposal.created_at.to_date %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<span class="icon-comments"></span>&nbsp;
<%= link_to t("proposals.show.comments", count: @proposal.comments_count), "#comments" %>
<% if current_user %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<span class="js-flag-actions">
<%= render 'proposals/flag_actions', proposal: @proposal %>
</span>
<% end %>
</div>
<%= render_image(@proposal.image, :large, true) if @proposal.image.present? %>
<br>
<p>
<%= t("proposals.show.code") %>
<strong><%= @proposal.code %></strong>
</p>
<blockquote><%= @proposal.summary %></blockquote>
<% if @proposal.video_url.present? %>
<div class="small-12 medium-7 small-centered">
<div class="flex-video">
<div id="js-embedded-video" data-video-code="<%= embedded_video_code %>"></div>
</div>
</div>
<% end %>
<%= safe_html_with_links @proposal.description %>
<% if feature?(:map) && map_location_available?(@proposal.map_location) %>
<div class="margin">
<%= render_map(@proposal.map_location, "proposal", false, nil) %>
</div>
<% end %>
<% if @proposal.external_url.present? %>
<div class="document-link">
<p>
<span class="icon-document"></span>&nbsp;
<strong><%= t('proposals.show.title_external_url') %></strong>
</p>
<%= text_with_links @proposal.external_url %>
</div>
<% end %>
<% if @proposal.video_url.present? %>
<div class="video-link">
<p>
<span class="icon-video"></span>&nbsp;
<strong><%= t('proposals.show.title_video_url') %></strong>
</p>
<%= text_with_links @proposal.video_url %>
</div>
<% end %>
<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 %>
<% if feature?(:allow_attached_documents) %>
<%= render 'documents/documents',
documents: @proposal.documents,
max_documents_allowed: Proposal.max_documents_allowed %>
<% end %>
<%= render 'shared/tags', taggable: @proposal %>

View File

@@ -37,93 +37,8 @@
</div>
<% end %>
<div class="proposal-info">
<%= render '/shared/author_info', resource: @proposal %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<%= l @proposal.created_at.to_date %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<span class="icon-comments"></span>&nbsp;
<%= link_to t("proposals.show.comments", count: @proposal.comments_count), "#comments" %>
<% if current_user %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<span class="js-flag-actions">
<%= render 'proposals/flag_actions', proposal: @proposal %>
</span>
<% end %>
</div>
<%= render_image(@proposal.image, :large, true) if @proposal.image.present? %>
<br>
<p>
<%= t("proposals.show.code") %>
<strong><%= @proposal.code %></strong>
</p>
<blockquote><%= @proposal.summary %></blockquote>
<% if @proposal.video_url.present? %>
<div class="small-12 medium-7 small-centered">
<div class="flex-video">
<div id="js-embedded-video" data-video-code="<%= embedded_video_code %>"></div>
</div>
</div>
<% end %>
<%= safe_html_with_links @proposal.description %>
<% if feature?(:map) && map_location_available?(@proposal.map_location) %>
<div class="margin">
<%= render_map(@proposal.map_location, "proposal", false, nil) %>
</div>
<% end %>
<% if @proposal.external_url.present? %>
<div class="document-link">
<p>
<span class="icon-document"></span>&nbsp;
<strong><%= t('proposals.show.title_external_url') %></strong>
</p>
<%= text_with_links @proposal.external_url %>
</div>
<% end %>
<% if @proposal.video_url.present? %>
<div class="video-link">
<p>
<span class="icon-video"></span>&nbsp;
<strong><%= t('proposals.show.title_video_url') %></strong>
</p>
<%= text_with_links @proposal.video_url %>
</div>
<% end %>
<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 %>
<% if feature?(:allow_attached_documents) %>
<%= render 'documents/documents',
documents: @proposal.documents,
max_documents_allowed: Proposal.max_documents_allowed %>
<% end %>
<%= render 'shared/tags', taggable: @proposal %>
<%= render "proposals/info", proposal: @proposal %>
<%= render 'shared/geozone', geozonable: @proposal %>
<%= render 'relationable/related_content', relationable: @proposal %>
<div class="js-moderator-proposal-actions margin">
@@ -225,4 +140,5 @@
</div>
<%= render "proposals/notifications" %>
<%= render "milestones/milestones", milestoneable: @proposal %>
</div>

View File

@@ -536,6 +536,7 @@ en:
admin: Admin menu
banner: Manage banners
poll_questions: Questions
proposals: Proposals
proposals_topics: Proposals topics
budgets: Participatory budgets
geozones: Manage geozones
@@ -1040,6 +1041,13 @@ en:
search:
title: Search Organisations
no_results: No organizations found.
proposals:
index:
title: Proposals
id: ID
author: Author
milestones: Milestones
no_proposals: There are no proposals.
hidden_proposals:
index:
filter: Filter

View File

@@ -437,6 +437,7 @@ en:
flag: This proposal has been flagged as inappropriate by several users.
login_to_comment: You must %{signin} or %{signup} to leave a comment.
notifications_tab: Notifications
milestones_tab: Milestones
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

View File

@@ -532,6 +532,7 @@ es:
admin: Menú de administración
banner: Gestionar banners
poll_questions: Preguntas
proposals: Propuestas
proposals_topics: Temas de propuestas
budgets: Presupuestos participativos
geozones: Gestionar distritos
@@ -1036,6 +1037,13 @@ es:
search:
title: Buscar Organizaciones
no_results: No se han encontrado organizaciones.
proposals:
index:
title: Propuestas
id: ID
author: Autor
milestones: Hitos
no_proposals: No hay propuestas.
hidden_proposals:
index:
filter: Filtro

View File

@@ -437,6 +437,7 @@ es:
flag: Esta propuesta ha sido marcada como inapropiada por varios usuarios.
login_to_comment: Necesitas %{signin} o %{signup} para comentar.
notifications_tab: Notificaciones
milestones_tab: Seguimiento
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

View File

@@ -434,6 +434,7 @@ val:
flag: Esta proposta ha sigut marcada com inapropiada per diversos usuaris.
login_to_comment: Necessites %{signin} o %{signup} per a comentar.
notifications_tab: Notificacions
milestones_tab: Seguiments
retired_warning: "L'autor d'esta proposta considera que ja no ha de seguir recollint avals."
retired_warning_link_to_explanation: Revisa la seua explicació abans d'avalar-la.
retired: Proposta retirada per l'autor

View File

@@ -29,6 +29,10 @@ namespace :admin do
end
end
resources :proposals, only: [:index, :show] do
resources :milestones, controller: "proposal_milestones"
end
resources :hidden_proposals, only: :index do
member do
put :restore

View File

@@ -6,17 +6,20 @@ section "Creating default Milestone Statuses" do
end
section "Creating investment milestones" do
Budget::Investment.find_each do |investment|
rand(1..5).times do
milestone = investment.milestones.build(
publication_date: rand(Date.tomorrow..(Date.current + 3.weeks)),
status_id: Milestone::Status.all.sample
)
I18n.available_locales.map do |locale|
Globalize.with_locale(locale) do
milestone.description = "Description for locale #{locale}"
milestone.title = I18n.l(Time.current, format: :datetime)
milestone.save!
[Budget::Investment, Proposal].each do |model|
model.find_each do |record|
rand(1..5).times do
milestone = record.milestones.build(
publication_date: Date.tomorrow,
status_id: Milestone::Status.all.sample
)
I18n.available_locales.map do |locale|
Globalize.with_locale(locale) do
milestone.description = "Description for locale #{locale}"
milestone.title = I18n.l(Time.current, format: :datetime)
milestone.save!
end
end
end
end

View File

@@ -0,0 +1,39 @@
require "rails_helper"
feature "Admin proposals" do
background do
login_as create(:administrator).user
end
it_behaves_like "admin_milestoneable",
:proposal,
"admin_proposal_path"
context "Index" do
scenario "Search" do
create(:proposal, title: "Make Pluto a planet again")
create(:proposal, title: "Build a monument to honour CONSUL developers")
visit admin_root_path
within("#side_menu") { click_link "Proposals" }
expect(page).to have_content "Make Pluto a planet again"
expect(page).to have_content "Build a monument"
fill_in "search", with: "Pluto"
click_button "Search"
expect(page).to have_content "Make Pluto a planet again"
expect(page).not_to have_content "Build a monument"
end
end
scenario "Show" do
create(:proposal, title: "Create a chaotic future", summary: "Chaos isn't controlled")
visit admin_proposals_path
click_link "Create a chaotic future"
expect(page).to have_content "Chaos isn't controlled"
end
end

View File

@@ -21,7 +21,7 @@ feature "Admin custom information texts" do
click_link 'Community'
expect(page).to have_content 'Access the community'
click_link 'Proposals'
within("#information-texts-tabs") { click_link "Proposals" }
expect(page).to have_content 'Create proposal'
within "#information-texts-tabs" do
@@ -49,7 +49,7 @@ feature "Admin custom information texts" do
scenario 'check that tabs are highlight when click it' do
visit admin_site_customization_information_texts_path
click_link 'Proposals'
within("#information-texts-tabs") { click_link "Proposals" }
expect(find("a[href=\"/admin/site_customization/information_texts?tab=proposals\"].is-active"))
.to have_content "Proposals"
end

View File

@@ -3,6 +3,10 @@ require 'rails_helper'
feature 'Proposals' do
it_behaves_like "milestoneable",
:proposal,
"proposal_path"
scenario 'Disabled with a feature flag' do
Setting['feature.proposals'] = nil
expect{ visit proposals_path }.to raise_exception(FeatureFlags::FeatureDisabled)