diff --git a/app/controllers/dashboard/base_controller.rb b/app/controllers/dashboard/base_controller.rb
new file mode 100644
index 000000000..d60bf4d9c
--- /dev/null
+++ b/app/controllers/dashboard/base_controller.rb
@@ -0,0 +1,22 @@
+class Dashboard::BaseController < ApplicationController
+ before_action :authenticate_user!
+
+ helper_method :proposal, :proposed_actions, :resources
+
+ respond_to :html
+ layout 'proposals_dashboard'
+
+ private
+
+ def proposal
+ @proposal ||= Proposal.find(params[:proposal_id])
+ end
+
+ def proposed_actions
+ @proposed_actions ||= ProposalDashboardAction.proposed_actions.active_for(proposal)
+ end
+
+ def resources
+ @resources ||= ProposalDashboardAction.resources.active_for(proposal)
+ end
+end
diff --git a/app/controllers/dashboard/polls_controller.rb b/app/controllers/dashboard/polls_controller.rb
new file mode 100644
index 000000000..7f5e8380c
--- /dev/null
+++ b/app/controllers/dashboard/polls_controller.rb
@@ -0,0 +1,89 @@
+class Dashboard::PollsController < Dashboard::BaseController
+ before_action :load_geozones, only: [:new, :create, :edit, :update]
+
+ helper_method :poll
+
+ def index
+ authorize! :manage_polls, proposal
+
+ @polls = Poll.for(proposal)
+ end
+
+ def new
+ authorize! :manage_polls, proposal
+ @poll = Poll.new
+ end
+
+ def show
+ authorize! :manage_polls, proposal
+ end
+
+ def create
+ authorize! :manage_polls, proposal
+
+ @poll = Poll.new(poll_params.merge(author: current_user, related: proposal))
+ if @poll.save
+ redirect_to proposal_dashboard_poll_path(proposal, poll), notice: t("flash.actions.create.poll")
+ else
+ render :new
+ end
+ end
+
+ def edit
+ authorize! :manage_polls, proposal
+ end
+
+ def update
+ authorize! :manage_polls, proposal
+
+ byebug
+
+ if poll.update(poll_params)
+ redirect_to proposal_dashboard_poll_path(proposal, poll), notice: t("flash.actions.update.poll")
+ else
+ render :edit
+ end
+ end
+
+ def results
+ authorize! :manage_polls, proposal
+ @partial_results = poll.partial_results
+ end
+
+ private
+
+ def poll
+ @poll ||= Poll.includes(:questions).find(params[:id])
+ end
+
+ def load_geozones
+ @geozones = Geozone.all.order(:name)
+ end
+
+ def poll_params
+ params.require(:poll).permit(poll_attributes)
+ end
+
+ def poll_attributes
+ [:name, :starts_at, :ends_at, :geozone_restricted, :summary, :description,
+ :results_enabled, :stats_enabled, geozone_ids: [],
+ questions_attributes: question_attributes,
+ image_attributes: image_attributes]
+ end
+
+ def image_attributes
+ [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy]
+ end
+
+ def question_attributes
+ [:id, :title, :author_id, :proposal_id, :_destroy, question_answers_attributes: question_answers_attributes]
+ end
+
+ def question_answers_attributes
+ [:id, :_destroy, :title, :description, :question_id, documents_attributes: documents_attributes]
+ end
+
+ def documents_attributes
+ [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy]
+ end
+end
diff --git a/app/controllers/proposals_dashboard_controller.rb b/app/controllers/proposals_dashboard_controller.rb
index 532a25db3..c597637af 100644
--- a/app/controllers/proposals_dashboard_controller.rb
+++ b/app/controllers/proposals_dashboard_controller.rb
@@ -1,9 +1,5 @@
-class ProposalsDashboardController < ApplicationController
- before_action :authenticate_user!
-
- helper_method :proposal, :proposed_actions, :resources, :proposal_dashboard_action
- respond_to :html
- layout 'proposals_dashboard'
+class ProposalsDashboardController < Dashboard::BaseController
+ helper_method :proposal_dashboard_action
def index
authorize! :dashboard, proposal
@@ -65,16 +61,4 @@ class ProposalsDashboardController < ApplicationController
def proposal_dashboard_action
@proposal_dashboard_action ||= ProposalDashboardAction.find(params[:id])
end
-
- def proposal
- @proposal ||= Proposal.find(params[:proposal_id])
- end
-
- def proposed_actions
- @proposed_actions ||= ProposalDashboardAction.proposed_actions.active_for(proposal)
- end
-
- def resources
- @resources ||= ProposalDashboardAction.resources.active_for(proposal)
- end
end
diff --git a/app/models/abilities/common.rb b/app/models/abilities/common.rb
index 16a3bf510..3629d03b8 100644
--- a/app/models/abilities/common.rb
+++ b/app/models/abilities/common.rb
@@ -22,6 +22,9 @@ module Abilities
can :dashboard, Proposal do |proposal|
proposal.author.id == user.id
end
+ can :manage_polls, Proposal do |proposal|
+ proposal.author.id == user.id
+ end
can [:retire_form, :retire], Proposal, author_id: user.id
diff --git a/app/models/poll.rb b/app/models/poll.rb
index bf5a5a0a8..bed81bfa0 100644
--- a/app/models/poll.rb
+++ b/app/models/poll.rb
@@ -18,11 +18,15 @@ class Poll < ActiveRecord::Base
has_and_belongs_to_many :geozones
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
+ belongs_to :related, polymorphic: true
validates :name, presence: true
validate :date_range
+ accepts_nested_attributes_for :questions, reject_if: :all_blank, allow_destroy: true
+
+ scope :for, ->(element) { where(related: element) }
scope :current, -> { where('starts_at <= ? and ? <= ends_at', Date.current.beginning_of_day, Date.current.beginning_of_day) }
scope :incoming, -> { where('? < starts_at', Date.current.beginning_of_day) }
scope :expired, -> { where('ends_at < ?', Date.current.beginning_of_day) }
diff --git a/app/models/poll/question.rb b/app/models/poll/question.rb
index 6be729757..e589401ac 100644
--- a/app/models/poll/question.rb
+++ b/app/models/poll/question.rb
@@ -20,6 +20,8 @@ class Poll::Question < ActiveRecord::Base
validates :title, length: { minimum: 4 }
+ accepts_nested_attributes_for :question_answers, reject_if: :all_blank, allow_destroy: true
+
scope :by_poll_id, ->(poll_id) { where(poll_id: poll_id) }
scope :sort_for_list, -> { order('poll_questions.proposal_id IS NULL', :created_at)}
diff --git a/app/views/dashboard/polls/_form.html.erb b/app/views/dashboard/polls/_form.html.erb
new file mode 100644
index 000000000..c34ecadd4
--- /dev/null
+++ b/app/views/dashboard/polls/_form.html.erb
@@ -0,0 +1,76 @@
+<%= form_for [proposal, :dashboard, poll] do |f| %>
+
+
+ <%= f.text_field :name %>
+
+
+
+
+
+ <%= f.text_field :starts_at,
+ value: poll.starts_at.present? ? l(poll.starts_at.to_date) : nil,
+ class: "js-calendar-full" %>
+
+
+
+ <%= f.text_field :ends_at,
+ value: poll.ends_at.present? ? l(poll.ends_at.to_date) : nil,
+ class: "js-calendar-full" %>
+
+
+
+
+
+ <%=f.text_area :summary, rows: 4%>
+
+
+
+
+
+ <%=f.text_area :description, rows: 8%>
+
+
+
+
+
+ <%= render 'images/admin_image', imageable: poll, f: f %>
+
+
+
+
+
+ <%= f.check_box :geozone_restricted, data: { checkbox_toggle: "#geozones" } %>
+
+
+
+
+
+ <%= f.collection_check_boxes(:geozone_ids, @geozones, :id, :name) do |b| %>
+
+ <%= b.label do %>
+ <%= b.check_box %><%= b.text %>
+ <% end %>
+
+ <% end %>
+
+
+
+
+ <%= f.fields_for :questions do |question| %>
+ <%= render 'question_fields', f: question %>
+ <% end %>
+
+
+
+ <%= link_to_add_association t('.add_question'), f, :questions, class: 'button hollow' %>
+
+
+
+
+
+
+ <%= f.submit t("admin.polls.#{admin_submit_action(poll)}.submit_button"),
+ class: "button success expanded" %>
+
+
+<% end %>
diff --git a/app/views/dashboard/polls/_poll.html.erb b/app/views/dashboard/polls/_poll.html.erb
new file mode 100644
index 000000000..72edf1b77
--- /dev/null
+++ b/app/views/dashboard/polls/_poll.html.erb
@@ -0,0 +1,18 @@
+
+ |
+
+ <%= link_to poll.name, proposal_dashboard_poll_path(proposal, poll) %>
+
+ |
+
+ <%= l poll.starts_at.to_date %> - <%= l poll.ends_at.to_date %>
+ |
+
+ <%= link_to t("admin.actions.edit"),
+ edit_proposal_dashboard_poll_path(proposal, poll),
+ class: "button hollow" %>
+ <%= link_to t("admin.actions.configure"),
+ proposal_dashboard_poll_path(proposal, poll),
+ class: "button hollow" %>
+ |
+
diff --git a/app/views/dashboard/polls/_poll_header.html.erb b/app/views/dashboard/polls/_poll_header.html.erb
new file mode 100644
index 000000000..2204f5e0f
--- /dev/null
+++ b/app/views/dashboard/polls/_poll_header.html.erb
@@ -0,0 +1,25 @@
+<%= link_to t("admin.polls.edit.title"),
+ edit_proposal_dashboard_poll_path(proposal, poll),
+ class: "button hollow float-right" %>
+
+
+ <%= poll.name %>
+
+
+
+
+
+
+ <%= t("admin.polls.index.dates") %>
+
+ <%= l poll.starts_at.to_date %> - <%= l poll.ends_at.to_date %>
+
+
+ <% if poll.geozone_restricted %>
+
+ <%= t("admin.polls.index.geozone_restricted") %>
+
+ <%= poll.geozones.pluck(:name).to_sentence %>
+
+ <% end %>
+
diff --git a/app/views/dashboard/polls/_question_answer_fields.html.erb b/app/views/dashboard/polls/_question_answer_fields.html.erb
new file mode 100644
index 000000000..3b79ffadb
--- /dev/null
+++ b/app/views/dashboard/polls/_question_answer_fields.html.erb
@@ -0,0 +1,21 @@
+
+
+
+ <%= f.text_field :title %>
+
+
+ <%= link_to_remove_association f, class: 'button hollow' do %>
+
+ <%=t(".remove_answer") %>
+ <% end %>
+
+
+
+
+ <%= f.cktext_area :description,
+ maxlength: Poll::Question.description_max_length,
+ ckeditor: { language: I18n.locale } %>
+
+
+
+
diff --git a/app/views/dashboard/polls/_question_fields.html.erb b/app/views/dashboard/polls/_question_fields.html.erb
new file mode 100644
index 000000000..1552f0669
--- /dev/null
+++ b/app/views/dashboard/polls/_question_fields.html.erb
@@ -0,0 +1,29 @@
+
+ <%= f.hidden_field :author_id, value: f.object.author_id || current_user.id %>
+ <%= f.hidden_field :proposal_id, value: f.object.proposal_id || proposal.id %>
+
+
+ <%= f.text_field :title %>
+
+
+ <%= link_to_remove_association f, class: 'button hollow' do %>
+
+ <%=t(".remove_question") %>
+ <% end %>
+
+
+
+
+ <%= f.fields_for :question_answers do |answer| %>
+ <%= render 'question_answer_fields', f: answer %>
+ <% end %>
+
+
+
+ <%= link_to_add_association t('.add_answer'), f, :question_answers, class: 'button hollow' %>
+
+
+
+
+
+
diff --git a/app/views/dashboard/polls/_questions.html.erb b/app/views/dashboard/polls/_questions.html.erb
new file mode 100644
index 000000000..16355e84d
--- /dev/null
+++ b/app/views/dashboard/polls/_questions.html.erb
@@ -0,0 +1,24 @@
+<%= t("admin.polls.show.questions_title") %>
+
+<% if poll.questions.empty? %>
+
+ <%= t('admin.polls.show.no_questions') %>
+
+<% else %>
+
+
+
+ | <%= t('admin.polls.show.table_title') %> |
+
+
+ <% poll.questions.each do |question| %>
+
+ |
+
+ <%= question.title %>
+
+ |
+
+ <% end %>
+
+<% end %>
diff --git a/app/views/dashboard/polls/_subnav.html.erb b/app/views/dashboard/polls/_subnav.html.erb
new file mode 100644
index 000000000..bad924c2a
--- /dev/null
+++ b/app/views/dashboard/polls/_subnav.html.erb
@@ -0,0 +1,30 @@
+
+
diff --git a/app/views/dashboard/polls/edit.html.erb b/app/views/dashboard/polls/edit.html.erb
new file mode 100644
index 000000000..f7bd93212
--- /dev/null
+++ b/app/views/dashboard/polls/edit.html.erb
@@ -0,0 +1,7 @@
+<%= back_link_to %>
+
+<%= t("admin.polls.edit.title") %>
+
+
+ <%= render "form" %>
+
diff --git a/app/views/dashboard/polls/index.html.erb b/app/views/dashboard/polls/index.html.erb
new file mode 100644
index 000000000..3796b4fbd
--- /dev/null
+++ b/app/views/dashboard/polls/index.html.erb
@@ -0,0 +1,22 @@
+<%= t("admin.polls.index.title") %>
+
+<%= link_to t("admin.polls.index.create"),
+ new_proposal_dashboard_poll_path(proposal),
+ class: "button success float-right" %>
+
+<% if @polls.any? %>
+
+
+ | <%= t("admin.polls.index.name") %> |
+ <%= t("admin.polls.index.dates") %> |
+ <%= t("admin.actions.actions") %> |
+
+
+ <%= render @polls %>
+
+
+<% else %>
+
+ <%= t("admin.polls.index.no_polls") %>
+
+<% end %>
diff --git a/app/views/dashboard/polls/new.html.erb b/app/views/dashboard/polls/new.html.erb
new file mode 100644
index 000000000..ac3ba5a4d
--- /dev/null
+++ b/app/views/dashboard/polls/new.html.erb
@@ -0,0 +1,7 @@
+<%= back_link_to %>
+
+<%= t("admin.polls.new.title") %>
+
+
+ <%= render "form" %>
+
diff --git a/app/views/dashboard/polls/results.html.erb b/app/views/dashboard/polls/results.html.erb
new file mode 100644
index 000000000..4074ee875
--- /dev/null
+++ b/app/views/dashboard/polls/results.html.erb
@@ -0,0 +1,18 @@
+<%= render 'poll_header' %>
+
+
+ <%= render "subnav" %>
+
+
<%= t("admin.results.index.title") %>
+
+ <% if @partial_results.empty? %>
+
+ <%= t("admin.results.index.no_results") %>
+
+ <% else %>
+ <%= render "/admin/poll/polls/recount", resource: @poll %>
+ <%= render "/admin/poll/polls/result" %>
+ <%= render "/admin/poll/polls/results_by_booth" %>
+ <%= render "/admin/poll/polls/show_results", resource: @poll %>
+ <% end %>
+
diff --git a/app/views/dashboard/polls/show.html.erb b/app/views/dashboard/polls/show.html.erb
new file mode 100644
index 000000000..be45eeb31
--- /dev/null
+++ b/app/views/dashboard/polls/show.html.erb
@@ -0,0 +1,7 @@
+<%= render "poll_header" %>
+
+
+ <%= render "subnav" %>
+
+ <%= render "questions" %>
+
diff --git a/app/views/proposals_dashboard/_menu.html.erb b/app/views/proposals_dashboard/_menu.html.erb
index 1efcab290..e9314b007 100644
--- a/app/views/proposals_dashboard/_menu.html.erb
+++ b/app/views/proposals_dashboard/_menu.html.erb
@@ -75,25 +75,32 @@
-<% if resources.any? %>
+
+
+
<%= t '.resources' %>
+
+
+<% if can?(:manage_polls, proposal) %>
-
<%= t '.resources' %>
-
-
- <% resources.each do |resource| %>
-
-
-
-
- <% if resource.request_to_administrators? %>
- <%= link_to resource.title,
- new_request_proposal_dashboard_path(proposal, resource) %>
- <% else %>
- <%= link_to resource.title, resource.link, target: '_blank' %>
- <% end %>
-
-
+
+ <%= link_to t('.polls'), proposal_dashboard_polls_path(proposal.to_param) %>
- <% end %>
+
+<% end %>
+
+<% resources.each do |resource| %>
+
+
+
+
+ <% if resource.request_to_administrators? %>
+ <%= link_to resource.title,
+ new_request_proposal_dashboard_path(proposal, resource) %>
+ <% else %>
+ <%= link_to resource.title, resource.link, target: '_blank' %>
+ <% end %>
+
+
+
<% end %>
diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml
index 15d89cec4..d57a787d3 100644
--- a/config/locales/en/general.yml
+++ b/config/locales/en/general.yml
@@ -501,6 +501,7 @@ en:
resources: Resources
actions: Actions
graphic: Graphic
+ polls: Polls
proposed_action:
execute: Execute
form:
@@ -514,6 +515,12 @@ en:
group_by_date: Group by date
progress: Acumulated progress
supports: Supports
+ dashboard:
+ polls:
+ form:
+ add_question: Add question
+ question_fields:
+ remove_question: Remove question
polls:
all: "All"
no_dates: "no date assigned"
diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml
index 8938e0eaa..7684cb0e3 100644
--- a/config/locales/es/general.yml
+++ b/config/locales/es/general.yml
@@ -501,6 +501,7 @@ es:
resources: Recursos
actions: Acciones
graphic: Gráfico
+ polls: Encuestas
proposed_action:
execute: Ejecutar
form:
@@ -514,6 +515,12 @@ es:
group_by_date: Agrupar por fechas
progress: Progreso acumulado
supports: Apoyos
+ dashboard:
+ polls:
+ form:
+ add_question: Añadir pregunta
+ question_fields:
+ remove_question: Borrar pregunta
polls:
all: "Todas"
no_dates: "sin fecha asignada"
diff --git a/config/routes/proposal.rb b/config/routes/proposal.rb
index 799021c83..dc2e65b38 100644
--- a/config/routes/proposal.rb
+++ b/config/routes/proposal.rb
@@ -11,6 +11,15 @@ resources :proposals do
get :new_request
post :create_request
end
+
+ end
+
+ namespace :dashboard do
+ resources :polls, except: :destroy do
+ member do
+ get :results
+ end
+ end
end
member do
diff --git a/db/migrate/20180625075520_add_related_to_polls.rb b/db/migrate/20180625075520_add_related_to_polls.rb
new file mode 100644
index 000000000..2c3466367
--- /dev/null
+++ b/db/migrate/20180625075520_add_related_to_polls.rb
@@ -0,0 +1,5 @@
+class AddRelatedToPolls < ActiveRecord::Migration
+ def change
+ add_reference :polls, :related, index: true, polymorphic: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 8550390c4..6998489f7 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20180615102215) do
+ActiveRecord::Schema.define(version: 20180625075520) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -886,8 +886,11 @@ ActiveRecord::Schema.define(version: 20180615102215) do
t.boolean "stats_enabled", default: false
t.datetime "created_at"
t.datetime "updated_at"
+ t.integer "related_id"
+ t.string "related_type"
end
+ add_index "polls", ["related_type", "related_id"], name: "index_polls_on_related_type_and_related_id", using: :btree
add_index "polls", ["starts_at", "ends_at"], name: "index_polls_on_starts_at_and_ends_at", using: :btree
create_table "proposal_dashboard_actions", force: :cascade do |t|