diff --git a/app/controllers/admin/budgets_controller.rb b/app/controllers/admin/budgets_controller.rb index dcf6b0839..771a8c91d 100644 --- a/app/controllers/admin/budgets_controller.rb +++ b/app/controllers/admin/budgets_controller.rb @@ -1,5 +1,6 @@ class Admin::BudgetsController < Admin::BaseController include Translatable + include ReportAttributes include FeatureFlags feature_flag :budgets @@ -62,7 +63,7 @@ class Admin::BudgetsController < Admin::BaseController def budget_params descriptions = Budget::Phase::PHASE_KINDS.map{|p| "description_#{p}"}.map(&:to_sym) valid_attributes = [:phase, :currency_symbol] + descriptions - params.require(:budget).permit(*valid_attributes, translation_params(Budget)) + params.require(:budget).permit(*valid_attributes, *report_attributes, translation_params(Budget)) end end diff --git a/app/controllers/admin/poll/polls_controller.rb b/app/controllers/admin/poll/polls_controller.rb index e257e3052..48503a17d 100644 --- a/app/controllers/admin/poll/polls_controller.rb +++ b/app/controllers/admin/poll/polls_controller.rb @@ -1,6 +1,7 @@ class Admin::Poll::PollsController < Admin::Poll::BaseController include Translatable include ImageAttributes + include ReportAttributes load_and_authorize_resource before_action :load_search, only: [:search_booths, :search_officers] @@ -75,11 +76,10 @@ class Admin::Poll::PollsController < Admin::Poll::BaseController end def poll_params - image_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy] - attributes = [:name, :starts_at, :ends_at, :geozone_restricted, :results_enabled, - :stats_enabled, :budget_id, geozone_ids: [], - image_attributes: image_attributes] - params.require(:poll).permit(*attributes, translation_params(Poll)) + attributes = [:name, :starts_at, :ends_at, :geozone_restricted, :budget_id, + geozone_ids: [], image_attributes: image_attributes] + + params.require(:poll).permit(*attributes, *report_attributes, translation_params(Poll)) end def search_params diff --git a/app/controllers/concerns/report_attributes.rb b/app/controllers/concerns/report_attributes.rb new file mode 100644 index 000000000..520dab316 --- /dev/null +++ b/app/controllers/concerns/report_attributes.rb @@ -0,0 +1,9 @@ +module ReportAttributes + extend ActiveSupport::Concern + + private + + def report_attributes + Report::KINDS.map { |kind| :"#{kind}_enabled" } + end +end diff --git a/app/controllers/dashboard/polls_controller.rb b/app/controllers/dashboard/polls_controller.rb index 116f1d99d..f97f91281 100644 --- a/app/controllers/dashboard/polls_controller.rb +++ b/app/controllers/dashboard/polls_controller.rb @@ -15,8 +15,7 @@ class Dashboard::PollsController < Dashboard::BaseController def create authorize! :manage_polls, proposal - @poll = Poll.new(poll_params.merge(author: current_user, related: proposal, - stats_enabled: false)) + @poll = Poll.new(poll_params.merge(author: current_user, related: proposal)) if @poll.save redirect_to proposal_dashboard_polls_path(proposal), notice: t("flash.actions.create.poll") else @@ -54,7 +53,7 @@ class Dashboard::PollsController < Dashboard::BaseController end def poll_attributes - [:name, :starts_at, :ends_at, :description, :results_enabled, :stats_enabled, + [:name, :starts_at, :ends_at, :description, :results_enabled, questions_attributes: question_attributes] end diff --git a/app/models/abilities/everyone.rb b/app/models/abilities/everyone.rb index 46dc19585..9eab1e14b 100644 --- a/app/models/abilities/everyone.rb +++ b/app/models/abilities/everyone.rb @@ -20,8 +20,9 @@ module Abilities can [:read], Budget can [:read], Budget::Group can [:read, :print, :json_data], Budget::Investment - can [:read_results, :read_executions], Budget, phase: "finished" - can(:read_stats, Budget) { |budget| budget.valuating_or_later? } + can(:read_results, Budget) { |budget| budget.results_enabled? && budget.finished? } + can(:read_stats, Budget) { |budget| budget.stats_enabled? && budget.valuating_or_later? } + can :read_executions, Budget, phase: "finished" can :new, DirectMessage can [:read, :debate, :draft_publication, :allegations, :result_publication, :proposals, :milestones], Legislation::Process, published: true diff --git a/app/models/budget.rb b/app/models/budget.rb index f11c378ff..fffb4f342 100644 --- a/app/models/budget.rb +++ b/app/models/budget.rb @@ -3,6 +3,7 @@ class Budget < ApplicationRecord include Measurable include Sluggable include StatsVersionable + include Reportable translates :name, touch: true include Globalizable diff --git a/app/models/concerns/reportable.rb b/app/models/concerns/reportable.rb new file mode 100644 index 000000000..45cc7b328 --- /dev/null +++ b/app/models/concerns/reportable.rb @@ -0,0 +1,23 @@ +module Reportable + extend ActiveSupport::Concern + + included do + has_one :report, as: :process, dependent: :destroy + accepts_nested_attributes_for :report + end + + def report + super || build_report + end + + Report::KINDS.each do |kind| + define_method "#{kind}_enabled?" do + report.send(kind) + end + alias_method "#{kind}_enabled", "#{kind}_enabled?" + + define_method "#{kind}_enabled=" do |enabled| + report.send("#{kind}=", enabled) + end + end +end diff --git a/app/models/concerns/statisticable.rb b/app/models/concerns/statisticable.rb index acb5d00c9..b45de3f6f 100644 --- a/app/models/concerns/statisticable.rb +++ b/app/models/concerns/statisticable.rb @@ -93,6 +93,10 @@ module Statisticable "v#{resource.find_or_create_stats_version.updated_at.to_i}" end + def advanced? + resource.advanced_stats_enabled? + end + private def base_stats_methods diff --git a/app/models/poll.rb b/app/models/poll.rb index 4484a4589..6d0e344b0 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -7,6 +7,7 @@ class Poll < ApplicationRecord include Notifiable include Sluggable include StatsVersionable + include Reportable translates :name, touch: true translates :summary, touch: true diff --git a/app/models/report.rb b/app/models/report.rb new file mode 100644 index 000000000..857cb462f --- /dev/null +++ b/app/models/report.rb @@ -0,0 +1,5 @@ +class Report < ApplicationRecord + KINDS = %i[results stats advanced_stats] + + belongs_to :process, polymorphic: true +end diff --git a/app/views/admin/budgets/_form.html.erb b/app/views/admin/budgets/_form.html.erb index e570da1bd..4d611d56c 100644 --- a/app/views/admin/budgets/_form.html.erb +++ b/app/views/admin/budgets/_form.html.erb @@ -65,6 +65,10 @@ <% end %> +
+ <%= render "admin/shared/show_results_fields", form: f %> +
+
<%= f.submit nil, class: "button success" %> diff --git a/app/views/admin/poll/results/_show_results.html.erb b/app/views/admin/poll/results/_show_results.html.erb index e607f4779..878733844 100644 --- a/app/views/admin/poll/results/_show_results.html.erb +++ b/app/views/admin/poll/results/_show_results.html.erb @@ -1,11 +1,5 @@ <%= form_for [:admin, @poll], action: "update" do |f| %> -
- <%= t("admin.polls.new.show_results_and_stats") %> - <%= f.check_box :results_enabled, checked: @poll.results_enabled?, label: t("admin.polls.new.show_results") %> - <%= f.check_box :stats_enabled, checked: @poll.stats_enabled?, label: t("admin.polls.new.show_stats") %> -

<%= t("admin.polls.new.results_and_stats_reminder") %>

-
- + <%= render "admin/shared/show_results_fields", form: f %>
<%= f.submit t("admin.polls.#{admin_submit_action(@poll)}.submit_button"), diff --git a/app/views/admin/shared/_show_results_fields.html.erb b/app/views/admin/shared/_show_results_fields.html.erb new file mode 100644 index 000000000..54cd2b70c --- /dev/null +++ b/app/views/admin/shared/_show_results_fields.html.erb @@ -0,0 +1,7 @@ +
+ <%= t("admin.shared.show_results_and_stats") %> + <%= form.check_box :results_enabled %> + <%= form.check_box :stats_enabled %> + <%= form.check_box :advanced_stats_enabled %> +

<%= t("admin.shared.results_and_stats_reminder") %>

+
diff --git a/app/views/budgets/stats/_advanced_stats.html.erb b/app/views/budgets/stats/_advanced_stats.html.erb new file mode 100644 index 000000000..d8424a111 --- /dev/null +++ b/app/views/budgets/stats/_advanced_stats.html.erb @@ -0,0 +1,83 @@ +
+

<%= t("stats.advanced") %>

+ +
+

<%= t("stats.budgets.total_investments") %>

+ + <%= number_with_info_tags( + stats.total_budget_investments, + t("stats.budgets.total_investments"), + html_class: "total-investments" + ) %> + + <%= number_with_info_tags(stats.total_unfeasible_investments, + t("stats.budgets.total_unfeasible_investments")) %> + <%= number_with_info_tags(stats.total_selected_investments, + t("stats.budgets.total_selected_investments")) %> +
+ +
+

<%= t("stats.budgets.by_phase") %>

+ + <% stats.phases.each do |phase| %> + <%= number_with_info_tags( + stats.send("total_participants_#{phase}_phase"), + t("stats.budgets.participants_#{phase}_phase") + ) %> + <% end %> +
+ +
+

<%= t("stats.budgets.by_heading") %>

+ + + + + + + + <% stats.all_phases.each do |phase| %> + + <% end %> + + + <% stats.all_phases.each do %> + + + + <% end %> + + + + <% @headings.each do |heading| %> + + + + + <% stats.all_phases.each do |phase| %> + + + + <% end %> + + <% end %> + +
<%= t("stats.budgets.heading") %><%= t("stats.budgets.investments_sent_html") %> + <%= t("stats.budgets.participants_#{phase}_phase") %> +
<%= t("stats.budgets.total") %><%= t("stats.budgets.percent_total_participants") %><%= t("stats.budgets.percent_heading_census") %>
+ <%= heading.name %> + + <%= stats.headings[heading.id][:total_investments_count] %> + + <%= stats.headings[heading.id]["total_participants_#{phase}_phase".to_sym] %> + + <%= number_to_stats_percentage(stats.headings[heading.id]["percentage_participants_#{phase}_phase".to_sym]) %> + + <%= number_to_stats_percentage(stats.headings[heading.id]["percentage_district_population_#{phase}_phase".to_sym]) %> +
+
+
diff --git a/app/views/budgets/stats/_advanced_stats_links.html.erb b/app/views/budgets/stats/_advanced_stats_links.html.erb new file mode 100644 index 000000000..7e508d2f1 --- /dev/null +++ b/app/views/budgets/stats/_advanced_stats_links.html.erb @@ -0,0 +1,12 @@ +

<%= link_to t("stats.advanced"), "#advanced_statistics" %>

+ diff --git a/app/views/budgets/stats/show.html.erb b/app/views/budgets/stats/show.html.erb index 0ad241529..bbbfda4bb 100644 --- a/app/views/budgets/stats/show.html.erb +++ b/app/views/budgets/stats/show.html.erb @@ -41,107 +41,12 @@
<%= render "shared/stats/participation", stats: @stats %> - -
-

<%= t("stats.advanced") %>

- -
-

<%= t("stats.budgets.total_investments") %>

- - <%= number_with_info_tags( - @stats.total_budget_investments, - t("stats.budgets.total_investments"), - html_class: "total-investments" - ) %> - - <%= number_with_info_tags(@stats.total_unfeasible_investments, - t("stats.budgets.total_unfeasible_investments")) %> - <%= number_with_info_tags(@stats.total_selected_investments, - t("stats.budgets.total_selected_investments")) %> -
- -
-

<%= t("stats.budgets.by_phase") %>

- - <% @stats.phases.each do |phase| %> - <%= number_with_info_tags( - @stats.send("total_participants_#{phase}_phase"), - t("stats.budgets.participants_#{phase}_phase") - ) %> - <% end %> -
- -
-

<%= t("stats.budgets.by_heading") %>

- - - - - - - - <% @stats.all_phases.each do |phase| %> - - <% end %> - - - <% @stats.all_phases.each do %> - - - - <% end %> - - - - <% @headings.each do |heading| %> - - - - - <% @stats.all_phases.each do |phase| %> - - - - <% end %> - - <% end %> - -
<%= t("stats.budgets.heading") %><%= t("stats.budgets.investments_sent_html") %> - <%= t("stats.budgets.participants_#{phase}_phase") %> -
<%= t("stats.budgets.total") %><%= t("stats.budgets.percent_total_participants") %><%= t("stats.budgets.percent_heading_census") %>
- <%= heading.name %> - - <%= @stats.headings[heading.id][:total_investments_count] %> - - <%= @stats.headings[heading.id]["total_participants_#{phase}_phase".to_sym] %> - - <%= number_to_stats_percentage(@stats.headings[heading.id]["percentage_participants_#{phase}_phase".to_sym]) %> - - <%= number_to_stats_percentage(@stats.headings[heading.id]["percentage_district_population_#{phase}_phase".to_sym]) %> -
-
-
+ <%= render "advanced_stats", stats: @stats if @stats.advanced? %>
diff --git a/app/views/polls/_advanced_stats.html.erb b/app/views/polls/_advanced_stats.html.erb new file mode 100644 index 000000000..5b66db75a --- /dev/null +++ b/app/views/polls/_advanced_stats.html.erb @@ -0,0 +1,92 @@ +
+

<%= t("stats.advanced") %>

+ +
+

<%= t("stats.polls.by_channel") %>

+ + <% stats.channels.each do |channel| %> + <%= number_with_info_tags( + stats.send("total_participants_#{channel}"), + t("stats.polls.#{channel}_percentage", + percentage: number_to_stats_percentage(stats.send(:"total_participants_#{channel}_percentage")) + ), + html_class: channel + ) %> + <% end %> +
+ +
+

<%= t("stats.polls.vote_by_channel") %>

+ + + + + + <% stats.channels.each do |channel| %> + + <% end %> + + + + + + + + <% stats.channels.each do |channel| %> + + <% end %> + + + + + + + + <% stats.channels.each do |channel| %> + + <% end %> + + + + + + + <% stats.channels.each do |channel| %> + + <% end %> + + + + + + + <% stats.channels.each do |channel| %> + + <% end %> + + + + +
<%= t("polls.show.stats.votes") %><%= t("polls.show.stats.#{channel}") %><%= t("polls.show.stats.total") %>
<%= t("polls.show.stats.valid") %> + <%= stats.send(:"total_#{channel}_valid") %> + (<%= stats.send(:"valid_percentage_#{channel}").round(2) %>%) + + <%= stats.total_valid_votes %> + (<%= stats.total_valid_percentage.round(2) %>%) +
<%= t("polls.show.stats.white") %> + <%= stats.send(:"total_#{channel}_white") %> + (<%= stats.send(:"white_percentage_#{channel}").round(2) %>%) + <%= stats.total_white_votes %> + (<%= stats.total_white_percentage.round(2) %>%) +
<%= t("polls.show.stats.null_votes") %> + <%= stats.send(:"total_#{channel}_null") %> + (<%= stats.send(:"null_percentage_#{channel}").round(2) %>%) + + <%= stats.total_null_votes %> + (<%= stats.total_null_percentage.round(2) %>%) +
<%= t("polls.show.stats.total") %> + <%= stats.send(:"total_participants_#{channel}") %> + (<%= stats.send(:"total_participants_#{channel}_percentage").round(2) %>%) + <%= stats.total_participants %>
+
+
diff --git a/app/views/polls/_advanced_stats_links.html.erb b/app/views/polls/_advanced_stats_links.html.erb new file mode 100644 index 000000000..2349d984b --- /dev/null +++ b/app/views/polls/_advanced_stats_links.html.erb @@ -0,0 +1,9 @@ +

<%= link_to t("stats.advanced"), "#advanced_statistics" %>

+ diff --git a/app/views/polls/stats.html.erb b/app/views/polls/stats.html.erb index 1284b26fa..8e43d5b58 100644 --- a/app/views/polls/stats.html.erb +++ b/app/views/polls/stats.html.erb @@ -8,118 +8,17 @@
<%= render "shared/stats/participation", stats: @stats %> + <%= render "advanced_stats", stats: @stats if @stats.advanced? %> -
-

<%= t("stats.advanced") %>

- -
-

<%= t("stats.polls.by_channel") %>

- - <% @stats.channels.each do |channel| %> - <%= number_with_info_tags( - @stats.send("total_participants_#{channel}"), - t("stats.polls.#{channel}_percentage", - percentage: number_to_stats_percentage(@stats.send(:"total_participants_#{channel}_percentage")) - ), - html_class: channel - ) %> - <% end %> -
- -
-

<%= t("stats.polls.vote_by_channel") %>

- - - - - - <% @stats.channels.each do |channel| %> - - <% end %> - - - - - - - - <% @stats.channels.each do |channel| %> - - <% end %> - - - - - - - - <% @stats.channels.each do |channel| %> - - <% end %> - - - - - - - <% @stats.channels.each do |channel| %> - - <% end %> - - - - - - - <% @stats.channels.each do |channel| %> - - <% end %> - - - - -
<%= t("polls.show.stats.votes") %><%= t("polls.show.stats.#{channel}") %><%= t("polls.show.stats.total") %>
<%= t("polls.show.stats.valid") %> - <%= @stats.send(:"total_#{channel}_valid") %> - (<%= @stats.send(:"valid_percentage_#{channel}").round(2) %>%) - - <%= @stats.total_valid_votes %> - (<%= @stats.total_valid_percentage.round(2) %>%) -
<%= t("polls.show.stats.white") %> - <%= @stats.send(:"total_#{channel}_white") %> - (<%= @stats.send(:"white_percentage_#{channel}").round(2) %>%) - <%= @stats.total_white_votes %> - (<%= @stats.total_white_percentage.round(2) %>%) -
<%= t("polls.show.stats.null_votes") %> - <%= @stats.send(:"total_#{channel}_null") %> - (<%= @stats.send(:"null_percentage_#{channel}").round(2) %>%) - - <%= @stats.total_null_votes %> - (<%= @stats.total_null_percentage.round(2) %>%) -
<%= t("polls.show.stats.total") %> - <%= @stats.send(:"total_participants_#{channel}") %> - (<%= @stats.send(:"total_participants_#{channel}_percentage").round(2) %>%) - <%= @stats.total_participants %>
-
- -
-

- <%= t("stats.no_demographic_data", count: @stats.total_no_demographic_data) %> -

-
+
+

+ <%= t("stats.no_demographic_data", count: @stats.total_no_demographic_data) %> +

diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 736f12c0d..c4c4b55e6 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -127,6 +127,7 @@ ignore_unused: - "budgets.index.section_header.*" - "activerecord.*" - "activemodel.*" + - "attributes.*" - "date.order" - "unauthorized.*" - "admin.officials.level_*" diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 450dcb797..97c9431ca 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -1,4 +1,8 @@ en: + attributes: + results_enabled: "Show results" + stats_enabled: "Show stats" + advanced_stats_enabled: "Show advanced stats" activerecord: models: activity: diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 9ad73b074..c03001722 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -1049,10 +1049,6 @@ en: geozone_restricted: "Restricted to districts" new: title: "New poll" - show_results_and_stats: "Show results and stats" - show_results: "Show results" - show_stats: "Show stats" - results_and_stats_reminder: "Marking these checkboxes the results and/or stats of this poll will be publicly available and every user will see them." submit_button: "Create poll" edit: title: "Edit poll" @@ -1330,6 +1326,8 @@ en: created_at: Created at delete: Delete color_help: Hexadecimal format + show_results_and_stats: "Show results and stats" + results_and_stats_reminder: "Marking these checkboxes the results and/or stats will be publicly available and every user will see them." spending_proposals: index: geozone_filter_all: All zones diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index c8ef9247d..13dd8783c 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -1,4 +1,8 @@ es: + attributes: + results_enabled: "Mostrar resultados" + stats_enabled: "Mostrar estadísticas" + advanced_stats_enabled: "Mostrar estadísticas avanzadas" activerecord: models: activity: diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 202178493..0e6a91fc0 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -1048,10 +1048,6 @@ es: geozone_restricted: "Restringida a los distritos" new: title: "Nueva votación" - show_results_and_stats: "Mostrar resultados y estadísticas" - show_results: "Mostrar resultados" - show_stats: "Mostrar estadísticas" - results_and_stats_reminder: "Si marcas estas casillas los resultados y/o estadísticas de esta votación serán públicos y podrán verlos todos los usuarios." submit_button: "Crear votación" edit: title: "Editar votación" @@ -1329,6 +1325,8 @@ es: created_at: Fecha de creación delete: Eliminar color_help: Formato hexadecimal + show_results_and_stats: "Mostrar resultados y estadísticas" + results_and_stats_reminder: "Si marcas estas casillas los resultados y/o estadísticas serán públicos y podrán verlos todos los usuarios." spending_proposals: index: geozone_filter_all: Todos los ámbitos de actuación diff --git a/db/migrate/20190424114803_create_reports.rb b/db/migrate/20190424114803_create_reports.rb new file mode 100644 index 000000000..b6a1fe143 --- /dev/null +++ b/db/migrate/20190424114803_create_reports.rb @@ -0,0 +1,11 @@ +class CreateReports < ActiveRecord::Migration[5.0] + def change + create_table :reports do |t| + t.boolean :stats + t.boolean :results + t.references :process, polymorphic: true + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20190429125842_add_advanced_stats_to_reports.rb b/db/migrate/20190429125842_add_advanced_stats_to_reports.rb new file mode 100644 index 000000000..025a2dad2 --- /dev/null +++ b/db/migrate/20190429125842_add_advanced_stats_to_reports.rb @@ -0,0 +1,5 @@ +class AddAdvancedStatsToReports < ActiveRecord::Migration[5.0] + def change + add_column :reports, :advanced_stats, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 1b3fc0471..b9bfc50a7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20190411090023) do +ActiveRecord::Schema.define(version: 20190429125842) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -1234,6 +1234,17 @@ ActiveRecord::Schema.define(version: 20190411090023) do t.index ["related_content_id"], name: "opposite_related_content", using: :btree end + create_table "reports", force: :cascade do |t| + t.boolean "stats" + t.boolean "results" + t.string "process_type" + t.integer "process_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "advanced_stats" + t.index ["process_type", "process_id"], name: "index_reports_on_process_type_and_process_id", using: :btree + end + create_table "settings", force: :cascade do |t| t.string "key" t.string "value" diff --git a/lib/migrations/reports.rb b/lib/migrations/reports.rb new file mode 100644 index 000000000..7a378a126 --- /dev/null +++ b/lib/migrations/reports.rb @@ -0,0 +1,29 @@ +class Migrations::Reports + def migrate + migrate_polls + migrate_budgets + end + + private + + def migrate_polls + Poll.find_each do |poll| + next unless poll.report.new_record? + + poll.report.update!( + results: poll.read_attribute(:results_enabled), + stats: poll.read_attribute(:stats_enabled), + advanced_stats: poll.read_attribute(:stats_enabled), + ) + end + + end + + def migrate_budgets + Budget.find_each do |budget| + next unless budget.report.new_record? + + budget.report.update!(results: true, stats: true, advanced_stats: true) + end + end +end diff --git a/lib/tasks/stats_and_results.rake b/lib/tasks/stats_and_results.rake new file mode 100644 index 000000000..5aa8f7e39 --- /dev/null +++ b/lib/tasks/stats_and_results.rake @@ -0,0 +1,6 @@ +namespace :stats_and_results do + desc "Migrates stats_enabled and results_enabled data to enabled reports" + task migrate_to_reports: :environment do + Migrations::Reports.new.migrate + end +end diff --git a/spec/factories/budgets.rb b/spec/factories/budgets.rb index 0d9faa1ee..66cc1d24f 100644 --- a/spec/factories/budgets.rb +++ b/spec/factories/budgets.rb @@ -61,6 +61,8 @@ FactoryBot.define do trait :finished do phase "finished" + results_enabled true + stats_enabled true end end diff --git a/spec/features/admin/budgets_spec.rb b/spec/features/admin/budgets_spec.rb index 3bc827caf..772330b7b 100644 --- a/spec/features/admin/budgets_spec.rb +++ b/spec/features/admin/budgets_spec.rb @@ -269,7 +269,7 @@ feature "Admin budgets" do end scenario "For a finished Budget" do - budget = create(:budget, phase: "finished") + budget = create(:budget, :finished) allow_any_instance_of(Budget).to receive(:has_winning_investments?).and_return(true) visit edit_admin_budget_path(budget) @@ -279,7 +279,7 @@ feature "Admin budgets" do end scenario "Recalculate for a finished Budget" do - budget = create(:budget, phase: "finished") + budget = create(:budget, :finished) group = create(:budget_group, budget: budget) heading = create(:budget_heading, group: group) create(:budget_investment, :winner, heading: heading) diff --git a/spec/features/budgets/executions_spec.rb b/spec/features/budgets/executions_spec.rb index 32398ce1a..b6c0e60c6 100644 --- a/spec/features/budgets/executions_spec.rb +++ b/spec/features/budgets/executions_spec.rb @@ -2,7 +2,7 @@ require "rails_helper" feature "Executions" do - let(:budget) { create(:budget, phase: "finished") } + let(:budget) { create(:budget, :finished) } let(:group) { create(:budget_group, budget: budget) } let(:heading) { create(:budget_heading, group: group) } diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index 75967555a..4d01a2c12 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -522,7 +522,7 @@ feature "Budget Investments" do context "Results Phase" do - before { budget.update(phase: "finished") } + before { budget.update(phase: "finished", results_enabled: true) } scenario "show winners by default" do investment1 = create(:budget_investment, :winner, heading: heading) diff --git a/spec/features/budgets/results_spec.rb b/spec/features/budgets/results_spec.rb index a2585e150..0fcf809b9 100644 --- a/spec/features/budgets/results_spec.rb +++ b/spec/features/budgets/results_spec.rb @@ -2,7 +2,7 @@ require "rails_helper" feature "Results" do - let(:budget) { create(:budget, phase: "finished") } + let(:budget) { create(:budget, :finished) } let(:group) { create(:budget_group, budget: budget) } let(:heading) { create(:budget_heading, group: group, price: 1000) } diff --git a/spec/features/budgets/stats_spec.rb b/spec/features/budgets/stats_spec.rb index 6318b1cea..f459a74a4 100644 --- a/spec/features/budgets/stats_spec.rb +++ b/spec/features/budgets/stats_spec.rb @@ -7,22 +7,22 @@ feature "Stats" do let(:heading) { create(:budget_heading, group: group, price: 1000) } describe "Show" do + describe "advanced stats" do + let(:budget) { create(:budget, :finished) } - it "is not accessible if supports phase is not finished" do - budget.update(phase: "selecting") + scenario "advanced stats enabled" do + budget.update(advanced_stats_enabled: true) - visit budget_stats_path(budget.id) - expect(page).to have_content "You do not have permission to carry out the action "\ - "'read_stats' on budget." + visit budget_stats_path(budget) + + expect(page).to have_content "Advanced statistics" + end + + scenario "advanced stats disabled" do + visit budget_stats_path(budget) + + expect(page).not_to have_content "Advanced statistics" + end end - - it "is accessible if supports phase is finished" do - budget.update(phase: "valuating") - - visit budget_stats_path(budget.id) - expect(page).to have_content "Stats" - end - end - end diff --git a/spec/features/polls/polls_spec.rb b/spec/features/polls/polls_spec.rb index 8470cd100..12ff3eb93 100644 --- a/spec/features/polls/polls_spec.rb +++ b/spec/features/polls/polls_spec.rb @@ -432,7 +432,18 @@ feature "Polls" do expect(page).to have_content("Questions") visit stats_poll_path(poll) + expect(page).to have_content("Participation data") + expect(page).not_to have_content "Advanced statistics" + end + + scenario "Advanced stats enabled" do + poll = create(:poll, :expired, stats_enabled: true, advanced_stats_enabled: true) + + visit stats_poll_path(poll) + + expect(page).to have_content "Participation data" + expect(page).to have_content "Advanced statistics" end scenario "Don't show poll results and stats if not enabled" do diff --git a/spec/lib/migrations/reports_spec.rb b/spec/lib/migrations/reports_spec.rb new file mode 100644 index 000000000..6a746c4f9 --- /dev/null +++ b/spec/lib/migrations/reports_spec.rb @@ -0,0 +1,53 @@ +require "rails_helper" + +describe Migrations::Reports do + describe "#migrate" do + it "ignores polls with existing reports" do + create(:poll, results_enabled: true, stats_enabled: true) do |poll| + poll.write_attribute(:results_enabled, false) + poll.write_attribute(:stats_enabled, false) + poll.save + end + + Migrations::Reports.new.migrate + + expect(Poll.last.results_enabled).to be true + expect(Poll.last.stats_enabled).to be true + expect(Poll.last.advanced_stats_enabled).to be nil + end + + it "migrates polls with no reports" do + create(:poll) do |poll| + poll.write_attribute(:results_enabled, true) + poll.write_attribute(:stats_enabled, true) + poll.save + end + + Migrations::Reports.new.migrate + + expect(Poll.last.results_enabled).to be true + expect(Poll.last.stats_enabled).to be true + expect(Poll.last.advanced_stats_enabled).to be true + end + + it "ignores budgets with existing reports" do + create(:budget, results_enabled: false, stats_enabled: false, advanced_stats_enabled: false) + + Migrations::Reports.new.migrate + + expect(Budget.last.results_enabled).to be false + expect(Budget.last.stats_enabled).to be false + expect(Budget.last.advanced_stats_enabled).to be false + end + + it "enables results and stats for every budget" do + create(:budget) + + Migrations::Reports.new.migrate + + expect(Budget.last.results_enabled).to be true + expect(Budget.last.stats_enabled).to be true + expect(Budget.last.advanced_stats_enabled).to be true + end + end +end diff --git a/spec/models/abilities/everyone_spec.rb b/spec/models/abilities/everyone_spec.rb index e2fcc3a43..59ba8cdbe 100644 --- a/spec/models/abilities/everyone_spec.rb +++ b/spec/models/abilities/everyone_spec.rb @@ -8,9 +8,6 @@ describe Abilities::Everyone do let(:debate) { create(:debate) } let(:proposal) { create(:proposal) } - let(:reviewing_ballot_budget) { create(:budget, phase: "reviewing_ballots") } - let(:finished_budget) { create(:budget, phase: "finished") } - it { should be_able_to(:index, Debate) } it { should be_able_to(:show, debate) } it { should_not be_able_to(:edit, Debate) } @@ -32,8 +29,6 @@ describe Abilities::Everyone do it { should be_able_to(:index, Budget) } - it { should be_able_to(:read_results, finished_budget) } - it { should_not be_able_to(:read_results, reviewing_ballot_budget) } it { should_not be_able_to(:manage, Dashboard::Action) } context "when accessing poll results" do @@ -73,4 +68,44 @@ describe Abilities::Everyone do it { should_not be_able_to(:stats, poll) } end end + + context "when accessing budget results" do + context "budget is not finished" do + let(:budget) { create(:budget, phase: "reviewing_ballots", results_enabled: true) } + + it { should_not be_able_to(:read_results, budget) } + end + + context "budget is finished" do + let(:budget) { create(:budget, :finished) } + + it { should be_able_to(:read_results, budget) } + end + + context "results disabled" do + let(:budget) { create(:budget, :finished, results_enabled: false) } + + it { should_not be_able_to(:read_results, budget) } + end + end + + context "when accessing budget stats" do + context "supports phase is not finished" do + let(:budget) { create(:budget, phase: "selecting", stats_enabled: true) } + + it { should_not be_able_to(:read_stats, budget) } + end + + context "supports phase is finished" do + let(:budget) { create(:budget, phase: "valuating", stats_enabled: true) } + + it { should be_able_to(:read_stats, budget) } + end + + context "stats disabled" do + let(:budget) { create(:budget, phase: "valuating", stats_enabled: false) } + + it { should_not be_able_to(:read_stats, budget) } + end + end end diff --git a/spec/models/budget_spec.rb b/spec/models/budget_spec.rb index 87063b549..123035732 100644 --- a/spec/models/budget_spec.rb +++ b/spec/models/budget_spec.rb @@ -5,6 +5,7 @@ describe Budget do let(:budget) { create(:budget) } it_behaves_like "sluggable", updatable_slug_trait: :drafting + it_behaves_like "reportable" describe "name" do before do diff --git a/spec/models/concerns/reportable.rb b/spec/models/concerns/reportable.rb new file mode 100644 index 000000000..c18caa8dd --- /dev/null +++ b/spec/models/concerns/reportable.rb @@ -0,0 +1,75 @@ +shared_examples "reportable" do + let(:reportable) { create(model_name(described_class)) } + + describe "#results_enabled" do + it "can write and read the attribute" do + reportable.results_enabled = true + + expect(reportable.results_enabled?).to be true + expect(reportable.results_enabled).to be true + + reportable.results_enabled = false + + expect(reportable.results_enabled?).to be false + expect(reportable.results_enabled).to be false + end + + it "can save the value to the database" do + reportable.update(results_enabled: true) + saved_reportable = described_class.last + + expect(saved_reportable.results_enabled?).to be true + expect(saved_reportable.results_enabled).to be true + + reportable.update(results_enabled: false) + saved_reportable = described_class.last + + expect(saved_reportable.results_enabled?).to be false + expect(saved_reportable.results_enabled).to be false + end + + it "uses the `has_one` relation instead of the original column" do + skip "there's no original column" unless reportable.has_attribute?(:results_enabled) + + reportable.update(results_enabled: true) + + expect(reportable.read_attribute(:results_enabled)).to be false + end + end + + describe "#stats_enabled" do + it "can write and read the attribute" do + reportable.stats_enabled = true + + expect(reportable.stats_enabled?).to be true + expect(reportable.stats_enabled).to be true + + reportable.stats_enabled = false + + expect(reportable.stats_enabled?).to be false + expect(reportable.stats_enabled).to be false + end + + it "can save the attribute to the database" do + reportable.update(stats_enabled: true) + saved_reportable = described_class.last + + expect(saved_reportable.stats_enabled?).to be true + expect(saved_reportable.stats_enabled).to be true + + reportable.update(stats_enabled: false) + saved_reportable = described_class.last + + expect(saved_reportable.stats_enabled?).to be false + expect(saved_reportable.stats_enabled).to be false + end + + it "uses the `has_one` relation instead of the original column" do + skip "there's no original column" unless reportable.has_attribute?(:stats_enabled) + + reportable.update(stats_enabled: true) + + expect(reportable.read_attribute(:stats_enabled)).to be false + end + end +end diff --git a/spec/models/poll/poll_spec.rb b/spec/models/poll/poll_spec.rb index 7015df269..581123997 100644 --- a/spec/models/poll/poll_spec.rb +++ b/spec/models/poll/poll_spec.rb @@ -6,6 +6,7 @@ describe Poll do describe "Concerns" do it_behaves_like "notifiable" + it_behaves_like "reportable" end describe "validations" do