diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index aa6da3a80..3ba96f0c8 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -78,6 +78,10 @@ class ApplicationController < ActionController::Base
@debate_votes = current_user ? current_user.debate_votes(debates) : {}
end
+ def set_proposal_votes(proposals)
+ @proposal_votes = current_user ? current_user.proposal_votes(proposals) : {}
+ end
+
def set_comment_flags(comments)
@comment_flags = current_user ? current_user.comment_flags(comments) : {}
end
diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb
index efad5783e..c788d3ba9 100644
--- a/app/controllers/proposals_controller.rb
+++ b/app/controllers/proposals_controller.rb
@@ -5,7 +5,13 @@ class ProposalsController < ApplicationController
respond_to :html, :js
def show
- render text: ""
+ set_proposal_votes(@proposal)
+ @commentable = @proposal
+ @root_comments = @proposal.comments.roots.recent.page(params[:page]).per(10).for_render
+ @comments = @root_comments.inject([]){|all, root| all + Comment.descendants_of(root).for_render}
+
+ @all_visible_comments = @root_comments + @comments
+ set_comment_flags(@all_visible_comments)
end
def new
diff --git a/app/helpers/votes_helper.rb b/app/helpers/votes_helper.rb
index dfc1bbda0..fa25fcca7 100644
--- a/app/helpers/votes_helper.rb
+++ b/app/helpers/votes_helper.rb
@@ -11,4 +11,13 @@ module VotesHelper
end
end
+ def css_classes_for_proposal_vote(proposal_votes, proposal)
+ case proposal_votes[proposal.id]
+ when true
+ {in_favor: "voted"}
+ else
+ {in_favor: ""}
+ end
+ end
+
end
diff --git a/app/models/proposal.rb b/app/models/proposal.rb
index e956e64e8..3892686af 100644
--- a/app/models/proposal.rb
+++ b/app/models/proposal.rb
@@ -1,12 +1,12 @@
class Proposal < ActiveRecord::Base
apply_simple_captcha
+ acts_as_votable
+ acts_as_taggable
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
has_many :comments, as: :commentable
has_many :flags, as: :flaggable
- acts_as_taggable
-
validates :title, presence: true
validates :question, presence: true
validates :description, presence: true
@@ -21,6 +21,28 @@ class Proposal < ActiveRecord::Base
before_validation :sanitize_description
before_validation :sanitize_tag_list
+ def total_votes
+ cached_votes_up
+ end
+
+ def conflictive?
+ return false unless flags_count > 0 && cached_votes_up > 0
+ cached_votes_up/flags_count.to_f < 5
+ end
+
+ def tag_list_with_limit(limit = nil)
+ return tags if limit.blank?
+
+ tags.sort{|a,b| b.taggings_count <=> a.taggings_count}[0, limit]
+ end
+
+ def tags_count_out_of_limit(limit = nil)
+ return 0 unless limit
+
+ count = tags.size - limit
+ count < 0 ? 0 : count
+ end
+
def self.title_max_length
@@title_max_length ||= self.columns.find { |c| c.name == 'title' }.limit || 80
end
@@ -33,6 +55,18 @@ class Proposal < ActiveRecord::Base
6000
end
+ def editable?
+ total_votes <= 1000
+ end
+
+ def editable_by?(user)
+ editable? && author == user
+ end
+
+ def votable_by?(user)
+ user.level_two_verified? || !user.voted_for?(self)
+ end
+
protected
def sanitize_description
diff --git a/app/models/user.rb b/app/models/user.rb
index 3ddf4df54..4bbd989f4 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -86,6 +86,11 @@ class User < ActiveRecord::Base
voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
end
+ def proposal_votes(proposals)
+ voted = votes.for_proposals(proposals)
+ voted.each_with_object({}) { |v, h| h[v.votable_id] = v.value }
+ end
+
def comment_flags(comments)
comment_flags = flags.for_comments(comments)
comment_flags.each_with_object({}){ |f, h| h[f.flaggable_id] = true }
diff --git a/app/views/proposals/_actions.html.erb b/app/views/proposals/_actions.html.erb
new file mode 100644
index 000000000..b2bc9f111
--- /dev/null
+++ b/app/views/proposals/_actions.html.erb
@@ -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 %>
+ |
+ <%= link_to t("admin.actions.hide_author").capitalize, hide_moderation_user_path(proposal.author_id),
+ method: :put, data: { confirm: t('admin.actions.confirm') } %>
+<% end %>
diff --git a/app/views/proposals/_comments.html.erb b/app/views/proposals/_comments.html.erb
new file mode 100644
index 000000000..6270c58b6
--- /dev/null
+++ b/app/views/proposals/_comments.html.erb
@@ -0,0 +1,27 @@
+
\ No newline at end of file
diff --git a/app/views/proposals/_flag_actions.html.erb b/app/views/proposals/_flag_actions.html.erb
new file mode 100644
index 000000000..b7bea4f79
--- /dev/null
+++ b/app/views/proposals/_flag_actions.html.erb
@@ -0,0 +1,21 @@
+<% if show_flag_action? proposal %>
+
+
+
+
+ -
+ <%= link_to t('shared.flag'), flag_proposal_path(proposal), method: :put, remote: true, id: "flag-proposal-#{ proposal.id }" %>
+
+
+<% end %>
+
+<% if show_unflag_action? proposal %>
+
+
+
+
+ -
+ <%= link_to t('shared.unflag'), unflag_proposal_path(proposal), method: :put, remote: true, id: "unflag-proposal-#{ proposal.id }" %>
+
+
+<% end %>
diff --git a/app/views/proposals/_votes.html.erb b/app/views/proposals/_votes.html.erb
new file mode 100644
index 000000000..9c6188b87
--- /dev/null
+++ b/app/views/proposals/_votes.html.erb
@@ -0,0 +1,37 @@
+<% voted_classes = css_classes_for_proposal_vote(@proposal_votes, proposal) %>
+
+
+ <%= link_to vote_proposal_path(proposal, value: 'yes'),
+ class: "like #{voted_classes[:in_favor]}", title: t('votes.agree'), method: "post", remote: true do %>
+
+ <%= percentage('likes', proposal) %>
+ <% end %>
+
+
+
+
+
+ <%= t("proposals.proposal.votes", count: proposal.total_votes) %>
+
+
+ <% if user_signed_in? && current_user.organization? %>
+
+
+ <%= t("votes.organizations") %>
+
+
+ <% elsif user_signed_in? && !proposal.votable_by?(current_user)%>
+
+
+ <%= t("votes.anonymous",
+ verify_account: link_to(t("votes.verify_account"), verification_path )).html_safe %>
+
+
+ <% elsif !user_signed_in? %>
+
+ <%= 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 %>
+
+ <% end %>
+
diff --git a/app/views/proposals/show.html.erb b/app/views/proposals/show.html.erb
new file mode 100644
index 000000000..b25bf3277
--- /dev/null
+++ b/app/views/proposals/show.html.erb
@@ -0,0 +1,83 @@
+
+
+
+
+ <%= link_to t("proposals.show.back_link"), proposals_path, class: 'left back' %>
+
+ <% if current_user && @proposal.editable_by?(current_user) %>
+ <%= link_to edit_proposal_path(@proposal), class: 'edit-proposal button success tiny radius right' do %>
+
+ <%= t("proposals.show.edit_proposal_link") %>
+ <% end %>
+ <% end %>
+
+
<%= @proposal.title %>
+ <% if @proposal.conflictive? %>
+
+ <%= t("proposals.show.flag") %>
+
+ <% end %>
+
+
+ <%= avatar_image(@proposal.author, seed: @proposal.author_id, size: 32, class: 'author-photo') %>
+
+ <% if @proposal.author.hidden? %>
+
+
+ <%= t("proposals.show.author_deleted") %>
+
+ <% else %>
+
+ <%= @proposal.author.name %>
+
+ <% if @proposal.author.official? %>
+ •
+
+ <%= @proposal.author.official_position %>
+
+ <% end %>
+ <% end %>
+
+ <% if @proposal.author.verified_organization? %>
+ •
+
+ <%= t("shared.collective") %>
+
+ <% end %>
+
+ •
+ <%= l @proposal.created_at.to_date %>
+ •
+
+ <%= link_to t("proposals.show.comments", count: @proposal.comments_count), "#comments" %>
+ •
+
+ <%= render 'proposals/flag_actions', proposal: @proposal %>
+
+
+
+ <%= @proposal.description %>
+
+ <%= render 'shared/tags', proposal: @proposal %>
+
+
+ <%= render 'actions', proposal: @proposal %>
+
+
+
+
+
+
+
+<%= render "comments" %>
diff --git a/app/views/shared/_tags.html.erb b/app/views/shared/_tags.html.erb
index ea3f65c6b..206b29759 100644
--- a/app/views/shared/_tags.html.erb
+++ b/app/views/shared/_tags.html.erb
@@ -1,13 +1,15 @@
<%- limit ||= nil %>
+<%= taggable = defined?(debate) ? debate : proposal %>
-<% if debate.tags.any? %>
+<% if taggable.tags.any? %>
- <% debate.tag_list_with_limit(limit).each do |tag| %>
- <%= link_to sanitize(tag.name), debates_path(tag: tag.name) %>
+ <% taggable.tag_list_with_limit(limit).each do |tag| %>
+ <%= link_to sanitize(tag.name), send("#{taggable.class.to_s.downcase}_path", tag: tag.name) %>
<% end %>
- <% if debate.tags_count_out_of_limit(limit) > 0 %>
- <%= link_to "#{debate.tags_count_out_of_limit(limit)}+", debate_path(debate) %>
+ <% if taggable.tags_count_out_of_limit(limit) > 0 %>
+ <%= link_to "#{taggable.tags_count_out_of_limit(limit)}+",
+ send("#{taggable.class.to_s.downcase}_path", taggable) %>
<% end %>
<% end %>
\ No newline at end of file
diff --git a/config/initializers/vote_extensions.rb b/config/initializers/vote_extensions.rb
index c0a92ef40..2a77bbef6 100644
--- a/config/initializers/vote_extensions.rb
+++ b/config/initializers/vote_extensions.rb
@@ -3,6 +3,10 @@ ActsAsVotable::Vote.class_eval do
where(votable_type: 'Debate', votable_id: debates)
end
+ def self.for_proposals(proposals)
+ where(votable_type: 'Debate', votable_id: proposals)
+ end
+
def value
vote_flag
end
diff --git a/config/routes.rb b/config/routes.rb
index 7246c0807..65e5850aa 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -45,7 +45,21 @@ Rails.application.routes.draw do
end
end
- resources :proposals
+ resources :proposals do
+ member do
+ post :vote
+ put :flag
+ put :unflag
+ end
+
+ resources :comments, only: :create, shallow: true do
+ member do
+ post :vote
+ put :flag
+ put :unflag
+ end
+ end
+ end
resource :account, controller: "account", only: [:show, :update]
resource :verification, controller: "verification", only: [:show]
+ <%= t("proposals.show.comments_title") %> + (<%= @proposal.comments_count %>) +
+ + <% if user_signed_in? %> + <%= render 'comments/form', {commentable: @proposal, parent_id: nil, toggeable: false} %> + <% else %> ++ +