From 2ce9f95283793c2acb259a9c6a527640d4e96de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Salvador=20P=C3=A9rez=20Garc=C3=ADa?= Date: Tue, 26 Jun 2018 08:05:38 +0200 Subject: [PATCH] Polls in the dashboard A reduced version of polls has been added to the dashboard --- app/controllers/dashboard/base_controller.rb | 22 +++++ app/controllers/dashboard/polls_controller.rb | 89 +++++++++++++++++++ .../proposals_dashboard_controller.rb | 20 +---- app/models/abilities/common.rb | 3 + app/models/poll.rb | 4 + app/models/poll/question.rb | 2 + app/views/dashboard/polls/_form.html.erb | 76 ++++++++++++++++ app/views/dashboard/polls/_poll.html.erb | 18 ++++ .../dashboard/polls/_poll_header.html.erb | 25 ++++++ .../polls/_question_answer_fields.html.erb | 21 +++++ .../dashboard/polls/_question_fields.html.erb | 29 ++++++ app/views/dashboard/polls/_questions.html.erb | 24 +++++ app/views/dashboard/polls/_subnav.html.erb | 30 +++++++ app/views/dashboard/polls/edit.html.erb | 7 ++ app/views/dashboard/polls/index.html.erb | 22 +++++ app/views/dashboard/polls/new.html.erb | 7 ++ app/views/dashboard/polls/results.html.erb | 18 ++++ app/views/dashboard/polls/show.html.erb | 7 ++ app/views/proposals_dashboard/_menu.html.erb | 43 +++++---- config/locales/en/general.yml | 7 ++ config/locales/es/general.yml | 7 ++ config/routes/proposal.rb | 9 ++ .../20180625075520_add_related_to_polls.rb | 5 ++ db/schema.rb | 5 +- 24 files changed, 463 insertions(+), 37 deletions(-) create mode 100644 app/controllers/dashboard/base_controller.rb create mode 100644 app/controllers/dashboard/polls_controller.rb create mode 100644 app/views/dashboard/polls/_form.html.erb create mode 100644 app/views/dashboard/polls/_poll.html.erb create mode 100644 app/views/dashboard/polls/_poll_header.html.erb create mode 100644 app/views/dashboard/polls/_question_answer_fields.html.erb create mode 100644 app/views/dashboard/polls/_question_fields.html.erb create mode 100644 app/views/dashboard/polls/_questions.html.erb create mode 100644 app/views/dashboard/polls/_subnav.html.erb create mode 100644 app/views/dashboard/polls/edit.html.erb create mode 100644 app/views/dashboard/polls/index.html.erb create mode 100644 app/views/dashboard/polls/new.html.erb create mode 100644 app/views/dashboard/polls/results.html.erb create mode 100644 app/views/dashboard/polls/show.html.erb create mode 100644 db/migrate/20180625075520_add_related_to_polls.rb 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 %> + + +
+ +
+
+ <%= 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 %> + + +
+ +
+
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 %> + + + + + + + <% poll.questions.each do |question| %> + + + + <% end %> +
<%= t('admin.polls.show.table_title') %>
+ + <%= question.title %> + +
+<% 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? %> + + + + + + + + <%= render @polls %> + +
<%= t("admin.polls.index.name") %><%= t("admin.polls.index.dates") %><%= t("admin.actions.actions") %>
+<% 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|