Merge pull request #1906 from consul/1856-legislation_processes_proposals_phase

[WIP] Legislation Process Proposals
This commit is contained in:
Alberto García
2017-10-27 12:41:09 +02:00
committed by GitHub
62 changed files with 1227 additions and 31 deletions

View File

@@ -109,16 +109,13 @@ $border-dark: darken($border, 10%);
li {
cursor: pointer;
display: inline-block;
margin: 0 1rem 1rem 0;
margin-bottom: $line-height;
margin-right: $line-height;
transition: all 0.4s;
border-bottom: 2px solid transparent;
@include breakpoint(medium) {
margin-left: $line-height * 2;
}
&:first-of-type {
margin-left: 0;
margin-bottom: 0;
}
&:hover,

View File

@@ -855,7 +855,9 @@
}
.debate,
.debate-show {
.debate-show,
.proposal-show,
.legislation-proposals {
.votes {
@include votes;
@@ -870,6 +872,7 @@
}
}
.proposal-show .votes,
.debate-show .votes {
border: 0;
padding: $line-height / 2 0;

View File

@@ -19,8 +19,10 @@ class Admin::Legislation::ProcessesController < Admin::Legislation::BaseControll
def update
if @process.update(process_params)
set_tag_list
link = legislation_process_path(@process).html_safe
redirect_to edit_admin_legislation_process_path(@process), notice: t('admin.legislation.processes.update.notice', link: link)
redirect_to :back, notice: t('admin.legislation.processes.update.notice', link: link)
else
flash.now[:error] = t('admin.legislation.processes.update.error')
render :edit
@@ -47,12 +49,22 @@ class Admin::Legislation::ProcessesController < Admin::Legislation::BaseControll
:draft_publication_date,
:allegations_start_date,
:allegations_end_date,
:proposals_phase_start_date,
:proposals_phase_end_date,
:result_publication_date,
:debate_phase_enabled,
:allegations_phase_enabled,
:proposals_phase_enabled,
:draft_publication_enabled,
:result_publication_enabled,
:published
:published,
:proposals_description,
:custom_list
)
end
def set_tag_list
@process.set_tag_list_on(:customs, process_params[:custom_list])
@process.save
end
end

View File

@@ -0,0 +1,7 @@
class Admin::Legislation::ProposalsController < Admin::Legislation::BaseController
load_and_authorize_resource :process, class: "Legislation::Process"
load_and_authorize_resource :proposal, class: "Legislation::Proposal", through: :process
def index
end
end

View File

@@ -2,4 +2,8 @@ class Legislation::BaseController < ApplicationController
include FeatureFlags
feature_flag :legislation
def set_legislation_proposal_votes(proposals)
@legislation_proposal_votes = current_user ? current_user.legislation_proposal_votes(proposals) : {}
end
end

View File

@@ -14,6 +14,8 @@ class Legislation::ProcessesController < Legislation::BaseController
redirect_to legislation_process_draft_version_path(@process, draft_version)
elsif @process.debate_phase.enabled?
redirect_to debate_legislation_process_path(@process)
elsif @process.proposals_phase.enabled?
redirect_to proposals_legislation_process_path(@process)
else
redirect_to allegations_legislation_process_path(@process)
end
@@ -81,6 +83,18 @@ class Legislation::ProcessesController < Legislation::BaseController
end
end
def proposals
set_process
@phase = :proposals_phase
if @process.proposals_phase.started?
set_legislation_proposal_votes(@process.proposals)
render :proposals
else
render :phase_not_open
end
end
private
def member_method?

View File

@@ -0,0 +1,70 @@
class Legislation::ProposalsController < Legislation::BaseController
include CommentableActions
include FlagActions
load_and_authorize_resource :process, class: "Legislation::Process"
load_and_authorize_resource :proposal, class: "Legislation::Proposal", through: :process
before_action :parse_tag_filter, only: :index
before_action :load_categories, only: [:index, :new, :create, :edit, :map, :summary]
before_action :load_geozones, only: [:edit, :map, :summary]
before_action :authenticate_user!, except: [:index, :show, :map, :summary]
invisible_captcha only: [:create, :update], honeypot: :subtitle
has_orders %w{confidence_score created_at}, only: :index
has_orders %w{most_voted newest oldest}, only: :show
helper_method :resource_model, :resource_name
respond_to :html, :js
def show
super
set_legislation_proposal_votes(@process.proposals)
@document = Document.new(documentable: @proposal)
redirect_to legislation_process_proposal_path(params[:process_id], @proposal),
status: :moved_permanently if request.path != legislation_process_proposal_path(params[:process_id], @proposal)
end
def create
@proposal = Legislation::Proposal.new(proposal_params.merge(author: current_user))
if @proposal.save
redirect_to legislation_process_proposal_path(params[:process_id], @proposal), notice: I18n.t('flash.actions.create.proposal')
else
render :new
end
end
def index_customization
load_successful_proposals
load_featured unless @proposal_successful_exists
end
def vote
@proposal.register_vote(current_user, params[:value])
set_legislation_proposal_votes(@proposal)
end
private
def proposal_params
params.require(:legislation_proposal).permit(:legislation_process_id, :title,
:question, :summary, :description, :video_url, :tag_list,
:terms_of_service, :geozone_id,
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id] )
end
def resource_model
Legislation::Proposal
end
def resource_name
'proposal'
end
def load_successful_proposals
@proposal_successful_exists = Legislation::Proposal.successful.exists?
end
end

View File

@@ -17,7 +17,7 @@ module AdminHelper
end
def menu_moderated_content?
["proposals", "debates", "comments", "hidden_users"].include? controller_name
["proposals", "debates", "comments", "hidden_users"].include? controller_name && controller.class.parent != Admin::Legislation
end
def menu_budget?

View File

@@ -8,6 +8,8 @@ module TagsHelper
proposals_path(search: tag_name)
when 'budget/investment'
budget_investments_path(@budget, search: tag_name)
when 'legislation/proposal'
legislation_process_proposals_path(@process, search: tag_name)
else
'#'
end
@@ -22,6 +24,8 @@ module TagsHelper
proposal_path(taggable)
when 'budget/investment'
budget_investment_path(taggable.budget_id, taggable)
when 'legislation/proposal'
legislation_process_proposal_path(@process, taggable)
else
'#'
end

View File

@@ -14,6 +14,9 @@ module Abilities
can :restore, Proposal
cannot :restore, Proposal, hidden_at: nil
can :restore, Legislation::Proposal
cannot :restore, Legislation::Proposal, hidden_at: nil
can :restore, User
cannot :restore, User, hidden_at: nil
@@ -26,6 +29,9 @@ module Abilities
can :confirm_hide, Proposal
cannot :confirm_hide, Proposal, hidden_at: nil
can :confirm_hide, Legislation::Proposal
cannot :confirm_hide, Legislation::Proposal, hidden_at: nil
can :confirm_hide, User
cannot :confirm_hide, User, hidden_at: nil
@@ -33,7 +39,7 @@ module Abilities
can :unmark_featured, Debate
can :comment_as_administrator, [Debate, Comment, Proposal, Poll::Question, Budget::Investment,
Legislation::Question, Legislation::Annotation, Topic]
Legislation::Question, Legislation::Proposal, Legislation::Annotation, Topic]
can [:search, :create, :index, :destroy], ::Administrator
can [:search, :create, :index, :destroy], ::Moderator
@@ -71,7 +77,8 @@ module Abilities
can [:manage], ::Legislation::Process
can [:manage], ::Legislation::DraftVersion
can [:manage], ::Legislation::Question
cannot :comment_as_moderator, [::Legislation::Question, Legislation::Annotation]
can [:manage], ::Legislation::Proposal
cannot :comment_as_moderator, [::Legislation::Question, Legislation::Annotation, ::Legislation::Proposal]
can [:create, :destroy], Document
can [:destroy], Image

View File

@@ -18,12 +18,20 @@ module Abilities
end
can [:retire_form, :retire], Proposal, author_id: user.id
can :read, Legislation::Proposal
cannot [:edit, :update], Legislation::Proposal do |proposal|
proposal.editable_by?(user)
end
can [:retire_form, :retire], Legislation::Proposal, author_id: user.id
can :create, Comment
can :create, Debate
can :create, Proposal
can :create, Legislation::Proposal
can :suggest, Debate
can :suggest, Proposal
can :suggest, Legislation::Proposal
can :suggest, ActsAsTaggableOn::Tag
can [:flag, :unflag], Comment
@@ -35,6 +43,9 @@ module Abilities
can [:flag, :unflag], Proposal
cannot [:flag, :unflag], Proposal, author_id: user.id
can [:flag, :unflag], Legislation::Proposal
cannot [:flag, :unflag], Legislation::Proposal, author_id: user.id
can [:create, :destroy], Follow
can [:destroy], Document, documentable: { author_id: user.id }
@@ -54,6 +65,10 @@ module Abilities
can :vote, SpendingProposal
can :create, SpendingProposal
can :vote, Legislation::Proposal
can :vote_featured, Legislation::Proposal
can :create, Legislation::Answer
can :create, Budget::Investment, budget: { phase: "accepting" }
can :suggest, Budget::Investment, budget: { phase: "accepting" }
can :destroy, Budget::Investment, budget: { phase: ["accepting", "reviewing"] }, author_id: user.id

View File

@@ -24,10 +24,10 @@ module Abilities
can [:read, :print], Budget::Investment
can :read_results, Budget, phase: "finished"
can :new, DirectMessage
can [:read, :debate, :draft_publication, :allegations, :result_publication], Legislation::Process, published: true
can [:read, :debate, :draft_publication, :allegations, :result_publication, :proposals], Legislation::Process, published: true
can [:read, :changes, :go_to_version], Legislation::DraftVersion
can [:read], Legislation::Question
can [:create], Legislation::Answer
can [:read, :map, :share], Legislation::Proposal
can [:search, :comments, :read, :create, :new_comment], Legislation::Annotation
end
end

View File

@@ -38,6 +38,15 @@ module Abilities
can :moderate, Proposal
cannot :moderate, Proposal, author_id: user.id
can :hide, Legislation::Proposal, hidden_at: nil
cannot :hide, Legislation::Proposal, author_id: user.id
can :ignore_flag, Legislation::Proposal, ignored_flag_at: nil, hidden_at: nil
cannot :ignore_flag, Legislation::Proposal, author_id: user.id
can :moderate, Legislation::Proposal
cannot :moderate, Legislation::Proposal, author_id: user.id
can :hide, User
cannot :hide, User, id: user.id

View File

@@ -6,7 +6,7 @@ module Abilities
merge Abilities::Moderation.new(user)
can :comment_as_moderator, [Debate, Comment, Proposal, Budget::Investment, Poll::Question,
Legislation::Question, Legislation::Annotation, Topic]
Legislation::Question, Legislation::Annotation, Legislation::Proposal, Topic]
end
end
end

View File

@@ -3,7 +3,7 @@ class Comment < ActiveRecord::Base
include HasPublicAuthor
include Graphqlable
COMMENTABLE_TYPES = %w(Debate Proposal Budget::Investment Poll::Question Legislation::Question Legislation::Annotation Topic Poll).freeze
COMMENTABLE_TYPES = %w(Debate Proposal Budget::Investment Poll::Question Legislation::Question Legislation::Annotation Topic Legislation::Proposal Poll).freeze
acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases

View File

@@ -1,14 +1,18 @@
class Legislation::Process < ActiveRecord::Base
acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases
include Taggable
PHASES_AND_PUBLICATIONS = %i(debate_phase allegations_phase draft_publication result_publication).freeze
acts_as_paranoid column: :hidden_at
acts_as_taggable_on :customs
PHASES_AND_PUBLICATIONS = %i(debate_phase allegations_phase proposals_phase draft_publication result_publication).freeze
has_many :draft_versions, -> { order(:id) }, class_name: 'Legislation::DraftVersion',
foreign_key: 'legislation_process_id', dependent: :destroy
has_one :final_draft_version, -> { where final_version: true, status: 'published' }, class_name: 'Legislation::DraftVersion',
foreign_key: 'legislation_process_id'
has_many :questions, -> { order(:id) }, class_name: 'Legislation::Question', foreign_key: 'legislation_process_id', dependent: :destroy
has_many :proposals, -> { order(:id) }, class_name: 'Legislation::Proposal', foreign_key: 'legislation_process_id', dependent: :destroy
validates :title, presence: true
validates :start_date, presence: true
@@ -17,6 +21,7 @@ class Legislation::Process < ActiveRecord::Base
validates :debate_end_date, presence: true, if: :debate_start_date?
validates :allegations_start_date, presence: true, if: :allegations_end_date?
validates :allegations_end_date, presence: true, if: :allegations_start_date?
validates :proposals_phase_end_date, presence: true, if: :proposals_phase_start_date?
validate :valid_date_ranges
scope :open, -> { where("start_date <= ? and end_date >= ?", Date.current, Date.current).order('id DESC') }
@@ -33,6 +38,10 @@ class Legislation::Process < ActiveRecord::Base
Legislation::Process::Phase.new(allegations_start_date, allegations_end_date, allegations_phase_enabled)
end
def proposals_phase
Legislation::Process::Phase.new(proposals_phase_start_date, proposals_phase_end_date, proposals_phase_enabled)
end
def draft_publication
Legislation::Process::Publication.new(draft_publication_date, draft_publication_enabled)
end

View File

@@ -0,0 +1,147 @@
class Legislation::Proposal < ActiveRecord::Base
include ActsAsParanoidAliases
include Flaggable
include Taggable
include Conflictable
include Measurable
include Sanitizable
include Searchable
include Filterable
include Followable
include Communitable
include Documentable
documentable max_documents_allowed: 3,
max_file_size: 3.megabytes,
accepted_content_types: [ "application/pdf" ]
accepts_nested_attributes_for :documents, allow_destroy: true
acts_as_votable
acts_as_paranoid column: :hidden_at
belongs_to :process, class_name: 'Legislation::Process', foreign_key: 'legislation_process_id'
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
belongs_to :geozone
has_many :comments, as: :commentable
validates :title, presence: true
validates :summary, presence: true
validates :author, presence: true
validates :title, length: { in: 4..Legislation::Proposal.title_max_length }
validates :description, length: { maximum: Legislation::Proposal.description_max_length }
validates :terms_of_service, acceptance: { allow_nil: false }, on: :create
before_validation :set_responsible_name
before_save :calculate_hot_score, :calculate_confidence_score
scope :for_render, -> { includes(:tags) }
scope :sort_by_hot_score, -> { reorder(hot_score: :desc) }
scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc) }
scope :sort_by_created_at, -> { reorder(created_at: :desc) }
scope :sort_by_most_commented, -> { reorder(comments_count: :desc) }
scope :sort_by_random, -> { reorder("RANDOM()") }
scope :sort_by_flags, -> { order(flags_count: :desc, updated_at: :desc) }
scope :last_week, -> { where("proposals.created_at >= ?", 7.days.ago)}
def to_param
"#{id}-#{title}".parameterize
end
def searchable_values
{ title => 'A',
question => 'B',
author.username => 'B',
tag_list.join(' ') => 'B',
geozone.try(:name) => 'B',
summary => 'C',
description => 'D'
}
end
def self.search(terms)
by_code = search_by_code(terms.strip)
by_code.present? ? by_code : pg_search(terms)
end
def self.search_by_code(terms)
matched_code = match_code(terms)
results = where(id: matched_code[1]) if matched_code
return results if (results.present? && results.first.code == terms)
end
def self.match_code(terms)
/\A#{Setting["proposal_code_prefix"]}-\d\d\d\d-\d\d-(\d*)\z/.match(terms)
end
def likes
cached_votes_up
end
def dislikes
cached_votes_down
end
def total_votes
cached_votes_total
end
def voters
User.active.where(id: votes_for.voters)
end
def editable?
total_votes <= Setting["max_votes_for_proposal_edit"].to_i
end
def editable_by?(user)
author_id == user.id && editable?
end
def votable_by?(user)
user && user.level_two_or_three_verified?
end
def register_vote(user, vote_value)
if votable_by?(user)
vote_by(voter: user, vote: vote_value)
end
end
def code
"#{Setting['proposal_code_prefix']}-#{created_at.strftime('%Y-%m')}-#{id}"
end
def after_commented
save # updates the hot_score because there is a before_save
end
def calculate_hot_score
self.hot_score = ScoreCalculator.hot_score(created_at,
total_votes,
total_votes,
comments_count)
end
def calculate_confidence_score
self.confidence_score = ScoreCalculator.confidence_score(total_votes, total_votes)
end
def after_hide
tags.each{ |t| t.decrement_custom_counter_for('LegislationProposal') }
end
def after_restore
tags.each{ |t| t.increment_custom_counter_for('LegislationProposal') }
end
protected
def set_responsible_name
if author && author.document_number?
self.responsible_name = author.document_number
end
end
end

View File

@@ -97,6 +97,12 @@ class User < ActiveRecord::Base
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
end
def legislation_proposal_votes(proposals)
voted = votes.for_legislation_proposals(proposals)
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
end
def spending_proposal_votes(spending_proposals)
voted = votes.for_spending_proposals(spending_proposals)
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }

View File

@@ -19,7 +19,7 @@
<strong><%= t("admin.menu.title_moderated_content") %></strong>
</a>
<ul <%= "class=is-active" if menu_moderated_content? %>>
<li <%= "class=active" if controller_name == "proposals" %>>
<li <%= "class=active" if controller_name == "proposals" && controller.class.parent != Admin::Legislation %>>
<%= link_to t("admin.menu.hidden_proposals"), admin_proposals_path %>
</li>

View File

@@ -114,6 +114,39 @@
</div>
</div>
<div class="row">
<div class="small-12 medium-4 column">
<label><%= t('admin.legislation.processes.form.proposals_phase') %></label>
</div>
<div class="small-12 medium-1 column legislation-process-start">
<%= t('admin.legislation.processes.form.start') %>
</div>
<div class="small-12 medium-2 column">
<%= f.text_field :proposals_phase_start_date,
label: false,
value: format_date_for_calendar_form(@process.proposals_phase_start_date),
class: "js-calendar-full",
id: "proposals_phase_start_date" %>
</div>
<div class="small-12 medium-1 column legislation-process-end">
<%= t('admin.legislation.processes.form.end') %>
</div>
<div class="small-12 medium-2 column">
<%= f.text_field :proposals_phase_end_date,
label: false,
value: format_date_for_calendar_form(@process.proposals_phase_end_date),
class: "js-calendar-full",
id: "proposals_phase_end_date" %>
</div>
<div class="small-12 medium-2 column">
<%= f.check_box :proposals_phase_enabled, checked: @process.proposals_phase.enabled?, label: t('admin.legislation.processes.form.enabled') %>
</div>
<div class="small-12 column">
<hr>
</div>
</div>
<div class="row">
<div class="small-12 medium-4 column">
<%= f.label :draft_publication_date %>

View File

@@ -19,6 +19,16 @@
</li>
<% end %>
<% if active == 'proposals' %>
<li class="active">
<h2><%= t("admin.legislation.processes.subnav.proposals") %></h2>
</li>
<% else %>
<li>
<%= link_to t("admin.legislation.processes.subnav.proposals"), admin_legislation_process_proposals_path(process) %>
</li>
<% end %>
<% if active == 'draft_versions' %>
<li class="active">
<h2><%= t("admin.legislation.processes.subnav.draft_texts") %></h2>

View File

@@ -0,0 +1,50 @@
<%= form_for [:admin, @process], html: {data: {watch_changes: true}} do |f| %>
<% if @process.errors.any? %>
<div id="error_explanation" data-alert class="callout alert" data-closable>
<button class="close-button" aria-label="<%= t("application.close") %>" type="button" data-close>
<span aria-hidden="true">&times;</span>
</button>
<strong>
<%= @process.errors.count %>
<%= t("admin.legislation.processes.errors.form.error", count: @process.errors.count) %>
</strong>
</div>
<% end %>
<div class="row">
<div class="small-12 medium-4 column">
<%= label_tag t('admin.legislation.proposals.form.header_information') %>
<small><%= t('admin.legislation.proposals.form.header_information_description') %></small>
</div>
<div class="small-12 medium-8 column">
<%= f.text_area :proposals_description,
label: false,
rows: 5,
placeholder: t('admin.legislation.proposals.form.header_information_placeholder') %>
</div>
</div>
<div class="row">
<div class="small-12 medium-4 column">
<%= label_tag t('admin.legislation.proposals.form.custom_categories') %>
<small><%= t('admin.legislation.proposals.form.custom_categories_description') %></small>
</div>
<div class="small-12 medium-8 column">
<%= f.text_field :custom_list, value: @process.tag_list_on(:customs).to_s,
label: false,
placeholder: t("proposals.form.tags_placeholder"),
class: 'js-tag-list',
aria: {describedby: "tag-list-help-text"} %>
</div>
</div>
<div class="row">
<div class="actions small-12 medium-3 column legislation-process-save">
<%= f.submit(class: "button expanded", value: t("admin.legislation.processes.#{admin_submit_action(@process)}.submit_button")) %>
</div>
</div>
<% end %>

View File

@@ -0,0 +1,16 @@
<% provide :title do %>
Admin - <%= t("admin.menu.legislation") %> - <%= @process.title %> - <%= t("admin.legislation.proposals.index.title") %>
<% end %>
<div class="legislation-admin legislation-draft-versions-index row">
<div class="small-12 column">
<%= back_link_to admin_legislation_processes_path, t("admin.legislation.proposals.index.back") %>
<h2><%= @process.title %></h2>
<%= render 'admin/legislation/processes/subnav', process: @process, active: 'proposals' %>
<%= render "form" %>
</div>
</div>

View File

@@ -6,7 +6,7 @@
<ul>
<% if process.debate_phase.enabled? %>
<li <%= 'class="active"' if phase.to_sym == :debate_phase %>>
<li <%= 'class=active' if phase.to_sym == :debate_phase %>>
<%= link_to debate_legislation_process_path(process) do %>
<h4><%= t('legislation.processes.shared.debate_dates') %></h4>
<p><%= format_date(process.debate_start_date) %> - <%= format_date(process.debate_end_date) %></p>
@@ -14,8 +14,17 @@
</li>
<% end %>
<% if process.proposals_phase.enabled? %>
<li <%= 'class=active' if phase.to_sym == :proposals_phase %>>
<%= link_to proposals_legislation_process_path(process) do %>
<h4><%= t('legislation.processes.shared.proposals_dates') %></h4>
<p><%= format_date(process.proposals_phase_start_date) %> - <%= format_date(process.proposals_phase_end_date) %></p>
<% end %>
</li>
<% end %>
<% if process.draft_publication.enabled? %>
<li <%= 'class="active"' if phase.to_sym == :draft_publication %>>
<li <%= 'class=active' if phase.to_sym == :draft_publication %>>
<%= link_to draft_publication_legislation_process_path(process) do %>
<h4><%= t('legislation.processes.shared.draft_publication_date') %></h4>
<p><%= format_date(process.draft_publication_date) %></p>
@@ -24,7 +33,7 @@
<% end %>
<% if process.allegations_phase.enabled? %>
<li <%= 'class="active"' if phase.to_sym == :allegations_phase %>>
<li <%= 'class=active' if phase.to_sym == :allegations_phase %>>
<%= link_to allegations_legislation_process_path(process) do %>
<h4><%= t('legislation.processes.shared.allegations_dates') %></h4>
<p><%= format_date(process.allegations_start_date) %> - <%= format_date(process.allegations_end_date) %></p>
@@ -33,7 +42,7 @@
<% end %>
<% if process.result_publication.enabled? %>
<li <%= 'class="active"' if phase.to_sym == :result_publication %>>
<li <%= 'class=active' if phase.to_sym == :result_publication %>>
<%= link_to result_publication_legislation_process_path(process) do %>
<h4><%= t('legislation.processes.shared.result_publication_date') %></h4>
<p><%= format_date(process.result_publication_date) %></p>

View File

@@ -40,6 +40,13 @@
</div>
<% end %>
<% if process.proposals_phase.enabled? %>
<div class="small-6 medium-<%= column_width %> column">
<h5><%= t('legislation.processes.shared.proposals_dates') %></h5>
<p><%= format_date(process.proposals_phase_start_date) %> - <%= format_date(process.proposals_phase_end_date) %></p>
</div>
<% end %>
<% if process.allegations_phase.enabled? %>
<div class="small-6 medium-<%= column_width %> column">
<h5><%= t('legislation.processes.shared.allegations_dates') %></h5>

View File

@@ -0,0 +1,30 @@
<% provide :title do %><%= @process.title %><% end %>
<%= render 'legislation/processes/header', process: @process, header: :full %>
<%= render 'key_dates', process: @process, phase: :proposals %>
<div class="row">
<div class="debate-chooser">
<div class="row">
<div class="small-12 medium-9 column">
<div class="legislation-proposals">
<% if @process.proposals.empty? %>
<div class="callout primary">
<p><%= t('.empty_proposals') %></p>
</div>
<% else %>
<%= render @process.proposals %>
<% end %>
</div>
</div>
<div class="small-12 medium-3 column">
<% if @process.proposals_phase.open? %>
<p><%= link_to t("proposals.index.start_proposal"), new_legislation_process_proposal_path(@process), class: 'button expanded' %></p>
<% end %>
<%= render 'legislation/proposals/categories', taggable: @process %>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,10 @@
<% if can? :hide, proposal %>
<%= link_to t("admin.actions.hide").capitalize, hide_moderation_proposal_path(proposal),
method: :put, remote: true, data: { confirm: t('admin.actions.confirm') } %>
<% end %>
<% if can? :hide, proposal.author %>
&nbsp;|&nbsp;
<%= link_to t("admin.actions.hide_author").capitalize, hide_moderation_user_path(proposal.author_id),
method: :put, data: { confirm: t('admin.actions.confirm') } %>
<% end %>

View File

@@ -0,0 +1,14 @@
<div class="sidebar-divider"></div>
<h2 class="sidebar-title"><%= t("shared.tags_cloud.categories") %></h2>
<br>
<ul id="categories" class="no-bullet categories">
<% @process.tag_list_on(:customs).each do |tag| %>
<li class="inline-block">
<% css_class = { class: 'active' } if params[:search] == tag %>
<%= link_to tag,
legislation_process_proposals_path(process_id: @process, search: tag),
css_class || {} %>
</li>
<% end %>
</ul>

View File

@@ -0,0 +1,24 @@
<% cache [locale_and_user_status, @current_order, commentable_cache_key(@proposal), @comment_tree.comments, @comment_tree.comment_authors, @proposal.comments_count, @comment_flags] do %>
<div class="row comments">
<div id="comments" class="small-12 column">
<%= render 'shared/wide_order_selector', i18n_namespace: "comments" %>
<% if user_signed_in? %>
<%= render 'comments/form', {commentable: @proposal, parent_id: nil, toggeable: false} %>
<% else %>
<br>
<div data-alert class="callout primary">
<%= t("proposals.show.login_to_comment",
signin: link_to(t("votes.signin"), new_user_session_path),
signup: link_to(t("votes.signup"), new_user_registration_path)).html_safe %>
</div>
<% end %>
<% @comment_tree.root_comments.each do |comment| %>
<%= render 'comments/comment', comment: comment %>
<% end %>
<%= paginate @comment_tree.root_comments %>
</div>
</div>
<% end %>

View File

@@ -0,0 +1,27 @@
<div id="<%= dom_id(proposal) %>" class="proposal-featured clear">
<div class="small-12 medium-9 column">
<h3><%= link_to proposal.title, proposal %></h3>
<div class="info">
<% if proposal.author.hidden? || proposal.author.erased? %>
<%= t("proposals.show.author_deleted") %>
<% else %>
<%= proposal.author.name %>
<% end %>
&nbsp;&bull;&nbsp;
<% if proposal.author.display_official_position_badge? %>
<span class="label round level-<%= proposal.author.official_level %>">
<%= proposal.author.official_position %>
</span>
&nbsp;&bull;&nbsp;
<% end %>
<strong><%= t("proposals.proposal.votes", count: proposal.total_votes) %></strong>
</div>
</div>
<div id="<%= dom_id(proposal) %>_votes" class="small-12 medium-3 column">
<%= render 'featured_votes', proposal: proposal %>
</div>
</div>

View File

@@ -0,0 +1,44 @@
<div class="supports text-center">
<div class="in-favor">
<% if voted_for?(@featured_proposals_votes, proposal) %>
<div class="supported">
<%= t("proposals.proposal.already_supported") %>
</div>
<% else %>
<%= link_to vote_featured_proposal_path(proposal, value: 'yes'),
class: "button button-support small expanded",
title: t('proposals.proposal.support_title'), method: "post", remote: true do %>
<%= t("proposals.proposal.support") %>
<% end %>
<% end %>
</div>
<% if user_signed_in? && current_user.organization? %>
<div class="participation-not-allowed" style='display:none' aria-hidden="false">
<p>
<%= t("votes.organizations") %>
</p>
</div>
<% elsif user_signed_in? && !proposal.votable_by?(current_user)%>
<div class="participation-not-allowed" style='display:none' aria-hidden="false">
<p>
<%= t("votes.verified_only",
verify_account: link_to(t("votes.verify_account"), verification_path )).html_safe %>
</p>
</div>
<% elsif !user_signed_in? %>
<div class="participation-not-allowed" style='display:none' aria-hidden="false">
<%= t("votes.unauthenticated",
signin: link_to(t("votes.signin"), new_user_session_path),
signup: link_to(t("votes.signup"), new_user_registration_path)).html_safe %>
</div>
<% end %>
<% if voted_for?(@featured_proposals_votes, proposal) %>
<% if setting['twitter_handle'] %>
<div class="share-supported">
<%= social_share_button_tag("#{proposal.title} #{setting['twitter_hashtag']}", url: proposal_url(proposal), via: setting['twitter_handle']) %>
</div>
<% end %>
<% end %>
</div>

View File

@@ -0,0 +1,22 @@
<div class="row">
<div class="small-12 column">
<ul class="tabs" data-tabs id="proposals-tabs">
<li class="tabs-title is-active">
<%= link_to "#tab-comments" do %>
<h3>
<%= t("proposals.show.comments_tab") %>
<span class="js-comments-count">(<%= @proposal.comments_count %>)</span>
</h3>
<% end %>
</li>
<li class="tabs-title">
<%= link_to "#tab-documents" do %>
<h3>
<%= t("documents.tab") %>
(<%= @proposal.documents.count %>)
</h3>
<% end %>
</li>
</ul>
</div>
</div>

View File

@@ -0,0 +1,21 @@
<span class="js-flag-actions">
<span class="flag-content">
<% if show_flag_action? proposal %>
<a id="flag-expand-proposal-<%= proposal.id %>" data-toggle="flag-drop-proposal-<%= proposal.id %>" title="<%= t('shared.flag') %>">
<span class="icon-flag flag-disable"></span>
</a>
<span class="dropdown-pane" id="flag-drop-proposal-<%= proposal.id %>" data-dropdown data-auto-focus="true">
<%= link_to t('shared.flag'), flag_proposal_path(proposal), method: :put, remote: true, id: "flag-proposal-#{ proposal.id }" %>
</span>
<% end %>
<% if show_unflag_action? proposal %>
<a id="unflag-expand-proposal-<%= proposal.id %>" data-toggle="unflag-drop-proposal-<%= proposal.id %>" title="<%= t('shared.unflag') %>">
<span class="icon-flag flag-active"></span>
</a>
<span class="dropdown-pane" id="unflag-drop-proposal-<%= proposal.id %>" data-dropdown data-auto-focus="true">
<%= link_to t('shared.unflag'), unflag_proposal_path(proposal), method: :put, remote: true, id: "unflag-proposal-#{ proposal.id }" %>
</span>
<% end %>
</span>
</span>

View File

@@ -0,0 +1,78 @@
<%= form_for(@proposal, url: form_url) do |f| %>
<%= render 'shared/errors', resource: @proposal %>
<%= f.hidden_field(:legislation_process_id, :value => params[:process_id]) %>
<div class="row">
<div class="small-12 column">
<%= f.label :title, t("proposals.form.proposal_title") %>
<%= f.text_field :title, maxlength: Legislation::Proposal.title_max_length, placeholder: t("proposals.form.proposal_title"), label: false %>
</div>
<%= f.invisible_captcha :subtitle %>
<div class="small-12 column">
<%= f.label :summary, t("proposals.form.proposal_summary") %>
<p class="help-text" id="summary-help-text"><%= t("proposals.form.proposal_summary_note") %></p>
<%= f.text_area :summary, rows: 4, maxlength: 200, label: false,
placeholder: t('proposals.form.proposal_summary'),
aria: {describedby: "summary-help-text"} %>
</div>
<div class="ckeditor small-12 column">
<%= f.label :description, t("proposals.form.proposal_text") %>
<%= f.cktext_area :description, maxlength: Legislation::Proposal.description_max_length, ckeditor: { language: I18n.locale }, label: false %>
</div>
<div class="small-12 column">
<%= f.label :video_url, t("proposals.form.proposal_video_url") %>
<p class="help-text" id="video-url-help-text"><%= t("proposals.form.proposal_video_url_note") %></p>
<%= f.text_field :video_url, placeholder: t("proposals.form.proposal_video_url"), label: false,
aria: {describedby: "video-url-help-text"} %>
</div>
<div class="documents small-12 column" data-max-documents="<%= Legislation::Proposal.max_documents_allowed %>">
<%= render 'documents/nested_documents', documentable: @proposal, f: f %>
</div>
<div class="small-12 medium-6 column">
<%= f.label :geozone_id, t("proposals.form.geozone") %>
<%= f.select :geozone_id, geozone_select_options, {include_blank: t("geozones.none"), label: false} %>
</div>
<div class="small-12 column">
<%= f.label :tag_list, t("legislation.proposals.form.tags_label") %>
<p class="help-text" id="tag-list-help-text"><%= t("proposals.form.tags_instructions") %></p>
<div id="category_tags" class="tags">
<% @process.tag_list_on(:customs).each do |tag| %>
<a class="js-add-tag-link"><%= tag %></a>
<% end %>
</div>
<br>
<%= f.text_field :tag_list, value: @proposal.tag_list.to_s,
label: false,
placeholder: t("proposals.form.tags_placeholder"),
class: 'js-tag-list',
aria: {describedby: "tag-list-help-text"} %>
</div>
<div class="small-12 column">
<% if @proposal.new_record? %>
<%= f.label :terms_of_service do %>
<%= f.check_box :terms_of_service, title: t('form.accept_terms_title'), label: false %>
<span class="checkbox">
<%= t("form.accept_terms",
policy: link_to(t("form.policy"), "/privacy", target: "blank"),
conditions: link_to(t("form.conditions"), "/conditions", target: "blank")).html_safe %>
</span>
<% end %>
<% end %>
</div>
<div class="actions small-12 column">
<%= f.submit(class: "button", value: t("proposals.#{action_name}.form.submit_button")) %>
</div>
</div>
<% end %>

View File

@@ -0,0 +1,6 @@
<div class="sidebar-divider"></div>
<h2 class="sidebar-title"><%= t("shared.tags_cloud.districts") %></h2>
<br>
<%= link_to map_proposals_path, id: 'map', title: t("shared.tags_cloud.districts_list") do %>
<%= image_tag("map.jpg", alt: t("shared.tags_cloud.districts_list")) %>
<% end %>

View File

@@ -0,0 +1,17 @@
<div class="tabs-panel" id="tab-notifications">
<div class="row">
<div class="small-12 column">
<% if @notifications.blank? %>
<div class="callout primary text-center">
<%= t('proposals.show.no_notifications') %>
</div>
<% end %>
<% @notifications.each do |notification| %>
<h3><%= notification.title %></h3>
<p class="more-info"><%= notification.created_at.to_date %></p>
<p><%= notification.body %></p>
<% end %>
</div>
</div>
</div>

View File

@@ -0,0 +1,6 @@
<div class="sidebar-divider"></div>
<h2 class="sidebar-title"><%= t("proposals.index.top") %></h2>
<p>
<%= link_to t("proposals.index.top_link_proposals"), summary_proposals_path, class: "small" %><br>
</p>

View File

@@ -0,0 +1,59 @@
<div id="<%= dom_id(proposal) %>"
class="proposal clear <%= ("successful" if proposal.total_votes > Proposal.votes_needed_for_success) %>"
data-type="proposal">
<div class="panel">
<div class="icon-successful"></div>
<div class="row">
<div class="small-12 medium-9 column">
<div class="proposal-content">
<% cache [locale_and_user_status(proposal), 'index', proposal, proposal.author] do %>
<h3><%= link_to proposal.title, legislation_process_proposal_path(proposal.legislation_process_id, proposal) %></h3>
<p class="proposal-info">
<span class="icon-comments"></span>&nbsp;
<%= link_to t("proposals.proposal.comments", count: proposal.comments_count), legislation_process_proposal_path(proposal.legislation_process_id, proposal, anchor: "comments") %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<%= l proposal.created_at.to_date %>
<% if proposal.author.hidden? || proposal.author.erased? %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<span class="author">
<%= t("proposals.show.author_deleted") %>
</span>
<% else %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<span class="author">
<%= proposal.author.name %>
</span>
<% if proposal.author.display_official_position_badge? %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<span class="label round level-<%= proposal.author.official_level %>">
<%= proposal.author.official_position %>
</span>
<% end %>
<% end %>
<% if proposal.author.verified_organization? %>
<span class="bullet">&nbsp;&bull;&nbsp;</span>
<span class="label round is-association">
<%= t("shared.collective") %>
</span>
<% end %>
</p>
<div class="proposal-description">
<p><%= proposal.summary %></p>
<div class="truncate"></div>
</div>
<%= render "shared/tags", taggable: proposal, limit: 5 %>
<% end %>
</div>
</div>
<div id="<%= dom_id(proposal) %>_votes" class="small-12 medium-3 column">
<%= render 'legislation/proposals/votes',
{ proposal: proposal, vote_url: vote_legislation_process_proposal_path(proposal.legislation_process_id, proposal, value: 'yes') } %>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1 @@
$("#<%= dom_id(@proposal) %> .js-flag-actions").html('<%= j render("proposals/flag_actions", proposal: @proposal) %>');

View File

@@ -0,0 +1,78 @@
<% voted_classes = css_classes_for_vote(@legislation_proposal_votes, proposal) %>
<div class="votes">
<% if @process.proposals_phase.open? %>
<div class="in-favor inline-block">
<% if user_signed_in? %>
<%= link_to vote_legislation_process_proposal_path(process_id: proposal.process, id: proposal, value: 'yes'),
class: "like #{voted_classes[:in_favor]}", title: t('votes.agree'), method: "post", remote: true do %>
<span class="icon-like">
<span class="show-for-sr"><%= t('votes.agree') %></span>
</span>
<span class="percentage"><%= votes_percentage('likes', proposal) %></span>
<% end %>
<% else %>
<div class="like">
<span class="icon-like">
<span class="show-for-sr"><%= t('votes.agree') %></span>
</span>
<span class="percentage"><%= votes_percentage('likes', proposal) %></span>
</div>
<% end %>
</div>
<span class="divider"></span>
<div class="against inline-block">
<% if user_signed_in? %>
<%= link_to vote_legislation_process_proposal_path(process_id: proposal.process, id: proposal, value: 'no'), class: "unlike #{voted_classes[:against]}", title: t('votes.disagree'), method: "post", remote: true do %>
<span class="icon-unlike">
<span class="show-for-sr"><%= t('votes.disagree') %></span>
</span>
<span class="percentage"><%= votes_percentage('dislikes', proposal) %></span>
<% end %>
<% else %>
<div class="unlike">
<span class="icon-unlike">
<span class="show-for-sr"><%= t('votes.disagree') %></span>
</span>
<span class="percentage"><%= votes_percentage('dislikes', proposal) %></span>
</div>
<% end %>
</div>
<% else %>
<p><%= t("legislation.proposals.closed") %></p>
<% end %>
<span class="total-votes">
<%= t("proposals.proposal.votes", count: proposal.total_votes) %>
</span>
<% if user_signed_in? && current_user.organization? %>
<div class="participation-not-allowed" style='display:none' aria-hidden="false">
<p>
<%= t("votes.organizations") %>
</p>
</div>
<% elsif user_signed_in? && !proposal.votable_by?(current_user) %>
<div class="participation-not-allowed" style='display:none' aria-hidden="false">
<p>
<%= t("legislation.proposals.not_verified",
verify_account: link_to(t("votes.verify_account"), verification_path )).html_safe %>
</p>
</div>
<% elsif !user_signed_in? %>
<div tabindex="0">
<div class="participation-not-allowed" style='display:none' aria-hidden="false">
<%= t("votes.unauthenticated",
signin: link_to(t("votes.signin"), new_user_session_path),
signup: link_to(t("votes.signup"), new_user_registration_path)).html_safe %>
</div>
</div>
<% end %>
<% if voted_for?(@legislation_proposal_votes, proposal) && setting['twitter_handle'] %>
<div class="share-supported">
<%= social_share_button_tag("#{proposal.title} #{setting['twitter_hashtag']}", url: proposal_url(proposal), via: setting['twitter_handle']) %>
</div>
<% end %>
</div>

View File

@@ -0,0 +1,14 @@
<div class="proposal-edit row">
<div class="small-12 column">
<%= back_link_to %>
<div class="float-right">
<%= link_to t("proposals.edit.show_link"), legislation_process_proposal_path(@proposal.legislation_process_id, @proposal) %>
</div>
<h1><%= t("proposals.edit.editing") %></h1>
<%= render "form", form_url: legislation_process_proposal_url(@proposal.legislation_process_id, @proposal) %>
</div>
</div>

View File

@@ -0,0 +1 @@
<%= render 'shared/map', new_url_path: new_proposal_path %>

View File

@@ -0,0 +1,24 @@
<div class="proposal-form row">
<div class="small-12 medium-9 column">
<%= back_link_to %>
<h1><%= t("proposals.new.start_new") %></h1>
<div data-alert class="callout primary">
<%= link_to more_info_path(anchor: "proposals") ,title: t('shared.target_blank_html'), target: "_blank" do %>
<%= t("proposals.new.more_info")%>
<% end %>
</div>
<%= render "legislation/proposals/form", form_url: legislation_process_proposals_url, id: @proposal.id %>
</div>
<div class="small-12 medium-3 column">
<span class="icon-proposals float-right"></span>
<h2><%= t("proposals.new.recommendations_title") %></h2>
<ul class="recommendations">
<li><%= t("proposals.new.recommendation_one") %></li>
<li><%= t("proposals.new.recommendation_two") %></li>
<li><%= t("proposals.new.recommendation_three") %></li>
</ul>
</div>
</div>

View File

@@ -0,0 +1,121 @@
<% provide :title do %><%= @proposal.title %><% end %>
<% content_for :meta_description do %><%= @proposal.summary %><% end %>
<% provide :social_media_meta_tags do %>
<%= render "shared/social_media_meta_tags",
social_url: proposal_url(@proposal),
social_title: @proposal.title,
social_description: @proposal.summary %>
<% end %>
<% content_for :canonical do %>
<%= render "shared/canonical", href: proposal_url(@proposal) %>
<% end %>
<% cache [locale_and_user_status(@proposal), @proposal, @proposal.author, Flag.flagged?(current_user, @proposal), @legislation_proposal_votes] do %>
<div class="proposal-show">
<div id="<%= dom_id(@proposal) %>" class="row">
<div class="small-12 medium-9 column">
<%= back_link_to legislation_process_proposals_path(process_id: @process) %>
<h1><%= @proposal.title %></h1>
<% if @proposal.conflictive? %>
<div data-alert class="callout alert margin-top">
<strong><%= t("proposals.show.flag") %></strong>
</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>
<%= render 'proposals/flag_actions', proposal: @proposal %>
<% end %>
</div>
<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 @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>
<%= render 'shared/tags', taggable: @proposal %>
<%= render 'shared/geozone', geozonable: @proposal %>
<div class="js-moderator-proposal-actions margin">
<%= render 'proposals/actions', proposal: @proposal %>
</div>
</div>
<aside class="small-12 medium-3 column">
<div class="sidebar-divider"></div>
<h2><%= t("votes.supports") %></h2>
<div id="<%= dom_id(@proposal) %>_votes">
<%= render 'votes',
{ proposal: @proposal, vote_url: vote_legislation_process_proposal_path(@proposal.legislation_process_id, @proposal, value: 'yes') } %>
</div>
<%= render partial: 'shared/social_share', locals: {
share_title: t("proposals.show.share"),
title: @proposal.title,
url: proposal_url(@proposal)
} %>
</aside>
</div>
</div>
<% end %>
<div class="tabs-content" data-tabs-content="proposals-tabs" role="tablist">
<%= render "legislation/proposals/filter_subnav" %>
<div class="tabs-panel is-active" id="tab-comments">
<%= render "legislation/proposals/comments" %>
</div>
<div class="tabs-panel" id="tab-documents">
<%= render 'documents/documents',
documents: @proposal.documents,
max_documents_allowed: Proposal.max_documents_allowed %>
</div>
</div>

View File

@@ -0,0 +1 @@
<%= render "shared/suggest" %>

View File

@@ -0,0 +1 @@
$("#<%= dom_id(@proposal) %>_votes").html('<%= j render("legislation/proposals/votes", proposal: @proposal) %>');

View File

@@ -12,7 +12,7 @@
<li>
<%= layout_menu_link_to t("layouts.header.proposals"),
proposals_path,
controller_name == 'proposals',
controller_name == 'proposals' && !controller.class.parent == Legislation,
accesskey: "2",
title: t("shared.go_to_page") + t("layouts.header.proposals") %>
</li>