From 44aa2c441955f5ec48c8ef1f7d308428bfbd6e3e Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 09:44:18 +0100 Subject: [PATCH 01/14] Added statistics fields to app backbone --- app/commands/decidim/superspaces/admin/create_superspace.rb | 3 ++- app/commands/decidim/superspaces/admin/update_superspace.rb | 3 ++- app/forms/decidim/superspaces/admin/superspace_form.rb | 1 + app/models/decidim/superspaces/superspace.rb | 4 ++++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/commands/decidim/superspaces/admin/create_superspace.rb b/app/commands/decidim/superspaces/admin/create_superspace.rb index 84d5c60..59b99cb 100644 --- a/app/commands/decidim/superspaces/admin/create_superspace.rb +++ b/app/commands/decidim/superspaces/admin/create_superspace.rb @@ -58,7 +58,8 @@ def create_superspace! title: form.title, description: form.description, locale: form.locale, - hero_image: form.hero_image + hero_image: form.hero_image, + show_statistics: form.show_statistics } @superspace = Decidim.traceability.create!( diff --git a/app/commands/decidim/superspaces/admin/update_superspace.rb b/app/commands/decidim/superspaces/admin/update_superspace.rb index d513ccf..a42bd6a 100644 --- a/app/commands/decidim/superspaces/admin/update_superspace.rb +++ b/app/commands/decidim/superspaces/admin/update_superspace.rb @@ -44,7 +44,8 @@ def update_superspace! title: form.title, description: form.description, hero_image: form.hero_image, - locale: form.locale + locale: form.locale, + show_statistics: form.show_statistics ) update_associations(assembly_ids, participatory_process_ids, conference_ids) end diff --git a/app/forms/decidim/superspaces/admin/superspace_form.rb b/app/forms/decidim/superspaces/admin/superspace_form.rb index 062334b..7390b35 100644 --- a/app/forms/decidim/superspaces/admin/superspace_form.rb +++ b/app/forms/decidim/superspaces/admin/superspace_form.rb @@ -14,6 +14,7 @@ class SuperspaceForm < Decidim::Form attribute :assembly_ids attribute :participatory_process_ids attribute :conference_ids + attribute :show_statistics, Boolean validates :title, translatable_presence: true validates :locale, presence: true diff --git a/app/models/decidim/superspaces/superspace.rb b/app/models/decidim/superspaces/superspace.rb index 1e53431..b101a3b 100644 --- a/app/models/decidim/superspaces/superspace.rb +++ b/app/models/decidim/superspaces/superspace.rb @@ -35,6 +35,10 @@ def conferences find_spaces_by_type("Decidim::Conference") end + def statistics + Decidim::Superspaces::SuperspaceStatsPresenter.new(self).collection + end + def self.log_presenter_class_for(_log) = Decidim::Superspaces::AdminLog::SuperspacePresenter private From ebe1cb2f19381e725796a74bdc28a6297cddb560 Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 09:44:39 +0100 Subject: [PATCH 02/14] Added show statistics field migration --- ...add_show_statistics_to_decidim_superspaces_superspaces.rb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 db/migrate/20250218123528_add_show_statistics_to_decidim_superspaces_superspaces.rb diff --git a/db/migrate/20250218123528_add_show_statistics_to_decidim_superspaces_superspaces.rb b/db/migrate/20250218123528_add_show_statistics_to_decidim_superspaces_superspaces.rb new file mode 100644 index 0000000..7e44a7e --- /dev/null +++ b/db/migrate/20250218123528_add_show_statistics_to_decidim_superspaces_superspaces.rb @@ -0,0 +1,5 @@ +class AddShowStatisticsToDecidimSuperspacesSuperspaces < ActiveRecord::Migration[6.1] + def change + add_column :decidim_superspaces_superspaces, :show_statistics, :boolean + end +end From 617d1c66458859417b0a71dc6042f2451a00c905 Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 11:20:44 +0100 Subject: [PATCH 03/14] Added query class to get the participants count --- .../stats_superspace_participants_count.rb | 322 ++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 app/queries/decidim/superspaces/stats_superspace_participants_count.rb diff --git a/app/queries/decidim/superspaces/stats_superspace_participants_count.rb b/app/queries/decidim/superspaces/stats_superspace_participants_count.rb new file mode 100644 index 0000000..59091cd --- /dev/null +++ b/app/queries/decidim/superspaces/stats_superspace_participants_count.rb @@ -0,0 +1,322 @@ +# frozen_string_literal: true + +module Decidim + module Superspaces + # TODO: Change the name of the class to StatsParticipantsCount + class StatsSuperspaceParticipantsCount < Decidim::Query + def self.for(superspace) + return 0 unless superspace.is_a?(Decidim::Superspaces::Superspace) + + new(superspace).query + end + + def initialize(superspace) + @superspace = superspace + end + + def query + solution = [ + comments_query, + debates_query, + meetings_query, + endorsements_query, + project_votes_query, + proposals_query, + proposal_votes_query, + survey_answer_query + ].flatten.uniq.count + + data = [{ participatory_space: @superspace.to_s, stat_title: "participants_count", stat_value: solution }] + + data.map do |d| + [d[:participatory_space].to_sym, d[:stat_title].to_sym, d[:stat_value].to_i] + end + end + + private + + attr_reader :participatory_space + + def participatory_space_ids + @participatory_space_ids ||= @superspace.participatory_spaces.map(&:id) + end + + def assemblies_ids + @assemblies_ids ||= @superspace.assemblies.map(&:id) + end + + def conferences_ids + @conferences_ids ||= @superspace.conferences.map(&:id) + end + + def participatory_spaces_comments_query + Decidim::Comments::Comment + .where(decidim_participatory_space_type: Decidim::ParticipatoryProcess.class.name) + .where(decidim_participatory_space_id: participatory_space_ids) + .pluck(:decidim_author_id) + .uniq + end + + def assemblies_comments_query + Decidim::Comments::Comment + .where(decidim_participatory_space_type: Decidim::Assembly.class.name) + .where(decidim_participatory_space_id: assemblies_ids) + .pluck(:decidim_author_id) + .uniq + end + + def conferences_comments_query + Decidim::Comments::Comment + .where(decidim_participatory_space_type: Decidim::Conference.class.name) + .where(decidim_participatory_space_id: conferences_ids) + .pluck(:decidim_author_id) + .uniq + end + + def comments_query + return [] unless Decidim.module_installed?(:comments) + + [participatory_spaces_comments_query, assemblies_comments_query, conferences_comments_query].flatten.uniq + end + + def assemblies_debates_query + Decidim::Debates::Debate + .where( + component: assemblies_components, + decidim_author_type: Decidim::UserBaseEntity.name + ) + .not_hidden + .pluck(:decidim_author_id) + .uniq + end + + def participatory_processes_debates_query + Decidim::Debates::Debate + .where( + component: space_components, + decidim_author_type: Decidim::UserBaseEntity.name + ) + .not_hidden + .pluck(:decidim_author_id) + .uniq + end + + def conferences_debates_query + Decidim::Debates::Debate + .where( + component: conferences_components, + decidim_author_type: Decidim::UserBaseEntity.name + ) + .not_hidden + .pluck(:decidim_author_id) + .uniq + end + + def debates_query + return [] unless Decidim.module_installed?(:debates) + + [participatory_processes_debates_query, assemblies_debates_query, conferences_debates_query].flatten.uniq + end + + def assemblies_meetings_query + assemblies_meetings = Decidim::Meetings::Meeting.where(component: assemblies_components).not_hidden + assemblies_registrations = Decidim::Meetings::Registration.where(decidim_meeting_id: assemblies_meetings).distinct.pluck(:decidim_user_id) + assemblies_organizers = assemblies_meetings.where(decidim_author_type: Decidim::UserBaseEntity.name).distinct.pluck(:decidim_author_id) + + [assemblies_registrations, assemblies_organizers].flatten.uniq + end + + def participatory_processes_meetings_query + meetings = Decidim::Meetings::Meeting.where(component: @space_components).not_hidden + registrations = Decidim::Meetings::Registration.where(decidim_meeting_id: meetings).distinct.pluck(:decidim_user_id) + organizers = meetings.where(decidim_author_type: Decidim::UserBaseEntity.name).distinct.pluck(:decidim_author_id) + + [registrations, organizers].flatten.uniq + end + + def conferences_meetings_query + conferences_meetings = Decidim::Meetings::Meeting.where(component: conferences_components).not_hidden + conferences_registrations = Decidim::Meetings::Registration.where(decidim_meeting_id: conferences_meetings).distinct.pluck(:decidim_user_id) + conferences_organizers = conferences_meetings.where(decidim_author_type: Decidim::UserBaseEntity.name).distinct.pluck(:decidim_author_id) + + [conferences_registrations, conferences_organizers].flatten.uniq + end + + def meetings_query + return [] unless Decidim.module_installed?(:meetings) + + [participatory_processes_meetings_query + assemblies_meetings_query + conferences_meetings_query].uniq + end + + def assemblies_endorsements_query + Decidim::Endorsement + .where(resource: assemblies_components) + .pluck(:decidim_author_id) + .uniq + end + + def participatory_processes_endorsements_query + Decidim::Endorsement + .where(resource: space_components) + .pluck(:decidim_author_id) + .uniq + end + + def conferences_endorsements_query + Decidim::Endorsement + .where(resource: conferences_components) + .pluck(:decidim_author_id) + .uniq + end + + def endorsements_query + [participatory_processes_endorsements_query, assemblies_endorsements_query, conferences_endorsements_query].flatten.uniq + end + + def assemblies_proposals_query + Decidim::Coauthorship + .where( + coauthorable: assemblies_proposals_components, + decidim_author_type: Decidim::UserBaseEntity.name + ) + .pluck(:decidim_author_id) + .uniq + end + + def participatory_processes_proposals_query + Decidim::Coauthorship + .where( + coauthorable: proposals_components, + decidim_author_type: Decidim::UserBaseEntity.name + ) + .pluck(:decidim_author_id) + .uniq + end + + def conferences_proposals_query + Decidim::Coauthorship + .where( + coauthorable: conferences_proposals_components, + decidim_author_type: Decidim::UserBaseEntity.name + ) + .pluck(:decidim_author_id) + .uniq + end + + def proposals_query + return [] unless Decidim.module_installed?(:proposals) + + [participatory_processes_proposals_query, assemblies_proposals_query, conferences_proposals_query].flatten.uniq + end + + def assemblies_proposal_votes_query + Decidim::Proposals::ProposalVote + .where( + proposal: assemblies_proposals_components + ) + .final + .pluck(:decidim_author_id) + .uniq + end + + def participatory_processes_proposal_votes_query + Decidim::Proposals::ProposalVote + .where( + proposal: proposals_components + ) + .final + .pluck(:decidim_author_id) + .uniq + end + + def conferences_proposal_votes_query + Decidim::Proposals::ProposalVote + .where( + proposal: conferences_proposals_components + ) + .final + .pluck(:decidim_author_id) + .uniq + end + + def proposal_votes_query + return [] unless Decidim.module_installed?(:proposals) + + [participatory_processes_proposal_votes_query, assemblies_proposal_votes_query, conferences_proposal_votes_query].flatten.uniq + end + + def assemblies_project_votes_query + Decidim::Budgets::Order.joins(budget: [:component]) + .where(budget: { + decidim_components: { id: assemblies_components.pluck(:id) } + }) + .pluck(:decidim_user_id) + .uniq + end + + def participatory_processes_project_votes_query + Decidim::Budgets::Order.joins(budget: [:component]) + .where(budget: { + decidim_components: { id: space_components.pluck(:id) } + }) + .pluck(:decidim_user_id) + .uniq + end + + def conferences_project_votes_query + Decidim::Budgets::Order.joins(budget: [:component]) + .where(budget: { + decidim_components: { id: conferences_components.pluck(:id) } + }) + .pluck(:decidim_user_id) + .uniq + end + + def project_votes_query + return [] unless Decidim.module_installed?(:budgets) + + [participatory_processes_project_votes_query, assemblies_project_votes_query, conferences_project_votes_query].flatten.uniq + end + + def assemblies_survey_answer_query + Decidim::Forms::Answer.newsletter_participant_ids(assemblies_components) + end + + def participatory_processes_survey_answer_query + Decidim::Forms::Answer.newsletter_participant_ids(space_components) + end + + def conferences_survey_answer_query + Decidim::Forms::Answer.newsletter_participant_ids(conferences_components) + end + + def survey_answer_query + [participatory_processes_survey_answer_query, assemblies_survey_answer_query, conferences_survey_answer_query].flatten.uniq + end + + def space_components + Decidim::Component.where(participatory_space: @superspace.participatory_processes) + end + + def assemblies_components + Decidim::Component.where(participatory_space: @superspace.assemblies) + end + + def conferences_components + Decidim::Component.where(participatory_space: @superspace.conferences) + end + + def proposals_components + @proposals_components ||= Decidim::Proposals::FilteredProposals.for(space_components).published.not_hidden + end + + def assemblies_proposals_components + @assemblies_proposals_components ||= Decidim::Proposals::FilteredProposals.for(assemblies_components).published.not_hidden + end + + def conferences_proposals_components + @conferences_proposals_components ||= Decidim::Proposals::FilteredProposals.for(conferences_components).published.not_hidden + end + end + end +end From 958560198b39619bb1c588ed1135ed1407fbb86c Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 11:52:54 +0100 Subject: [PATCH 04/14] Added query class to get the number of followers --- .../superspaces/stats_followers_count.rb | 59 +++++++++++++++++++ ...s_count.rb => stats_participants_count.rb} | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 app/queries/decidim/superspaces/stats_followers_count.rb rename app/queries/decidim/superspaces/{stats_superspace_participants_count.rb => stats_participants_count.rb} (99%) diff --git a/app/queries/decidim/superspaces/stats_followers_count.rb b/app/queries/decidim/superspaces/stats_followers_count.rb new file mode 100644 index 0000000..fd3467d --- /dev/null +++ b/app/queries/decidim/superspaces/stats_followers_count.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +module Decidim + module Superspaces + class StatsFollowersCount < Decidim::Query + def self.for(superspace) + return 0 unless superspace.is_a?(Decidim::Superspaces::Superspace) + + new(superspace).query + end + + def initialize(superspace) + @superspace = superspace + end + + def query + count=space_query + components_query + + data = [{participatory_space: superspace.to_s, stat_title: "followers_count", stat_value: count}] + + data.map do |d| + [d[:participatory_space].to_sym, d[:stat_title].to_sym, d[:stat_value].to_i] + end + end + + private + + attr_reader :superspace + + def components_query + Decidim.component_manifests.sum do |component| + component.stats + .filter(tag: :followers) + .with_context(space_components) + .map { |_name, value| value } + .sum + end + end + + def space_query + Decidim.participatory_space_manifests.sum do |space| + space.stats + .filter(tag: :followers) + .with_context(participatory_space_items) + .map { |_name, value| value } + .sum + end + end + + def participatory_space_items + @participatory_space_items ||= superspace.participatory_spaces + end + + def space_components + @space_components ||= Decidim::Component.where(participatory_space: participatory_space_items).published + end + end + end +end diff --git a/app/queries/decidim/superspaces/stats_superspace_participants_count.rb b/app/queries/decidim/superspaces/stats_participants_count.rb similarity index 99% rename from app/queries/decidim/superspaces/stats_superspace_participants_count.rb rename to app/queries/decidim/superspaces/stats_participants_count.rb index 59091cd..fb988d8 100644 --- a/app/queries/decidim/superspaces/stats_superspace_participants_count.rb +++ b/app/queries/decidim/superspaces/stats_participants_count.rb @@ -3,7 +3,7 @@ module Decidim module Superspaces # TODO: Change the name of the class to StatsParticipantsCount - class StatsSuperspaceParticipantsCount < Decidim::Query + class StatsParticipantsCount < Decidim::Query def self.for(superspace) return 0 unless superspace.is_a?(Decidim::Superspaces::Superspace) From 716e21e6f3248f68fab67b76da346f4e7cbad389 Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 11:53:48 +0100 Subject: [PATCH 05/14] Added presenter to get all the superspace stats --- .../superspaces/superspace_stats_presenter.rb | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 app/presenters/decidim/superspaces/superspace_stats_presenter.rb diff --git a/app/presenters/decidim/superspaces/superspace_stats_presenter.rb b/app/presenters/decidim/superspaces/superspace_stats_presenter.rb new file mode 100644 index 0000000..a2d9c39 --- /dev/null +++ b/app/presenters/decidim/superspaces/superspace_stats_presenter.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Decidim + module Superspaces + class SuperspaceStatsPresenter < Decidim::StatsPresenter + include Decidim::IconHelper + + private + + def participatory_space = __getobj__ + + def participatory_processes + @participatory_processes ||= participatory_space.participatory_processes + participatory_space.assemblies + participatory_space.conferences + end + + def participatory_space_participants_stats + Decidim::Superspaces::StatsParticipantsCount.for(participatory_space) + end + + def participatory_space_followers_stats(conditions) + Decidim::Superspaces::StatsFollowersCount.for(participatory_space) + end + + def published_components + @published_components ||= Component.where(participatory_space: participatory_processes).published + end + + def participatory_space_sym = :superspace + end + end +end From b113b051f814e6b59f646735ea908e476cae448f Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 11:54:43 +0100 Subject: [PATCH 06/14] Added statistics to the views --- .../decidim/superspaces/admin/superspaces/_form.html.erb | 3 +++ app/views/decidim/superspaces/superspaces/show.html.erb | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/app/views/decidim/superspaces/admin/superspaces/_form.html.erb b/app/views/decidim/superspaces/admin/superspaces/_form.html.erb index fde4eae..d781c5f 100644 --- a/app/views/decidim/superspaces/admin/superspaces/_form.html.erb +++ b/app/views/decidim/superspaces/admin/superspaces/_form.html.erb @@ -76,6 +76,9 @@ +
+ <%= form.check_box :show_statistics %> +
diff --git a/app/views/decidim/superspaces/superspaces/show.html.erb b/app/views/decidim/superspaces/superspaces/show.html.erb index bd5c0bc..c29dca9 100644 --- a/app/views/decidim/superspaces/superspaces/show.html.erb +++ b/app/views/decidim/superspaces/superspaces/show.html.erb @@ -41,6 +41,13 @@ <% end %> <% end %> + + <% if superspace.show_statistics %> +
+

<%= t("statistics", scope: "decidim.superspaces.superspaces.show") %>

+ <%= cell("decidim/statistics",superspace.statistics) %> +
+ <% end %> <% end %> <%= render partial: "language_selector" %> From c54ec6354e3b7e92d784f2c56d10e4f3ed2a7666 Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 11:55:27 +0100 Subject: [PATCH 07/14] Added locales --- config/locales/en.yml | 1 + config/locales/es.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index 38fefdc..a48eb7b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -58,3 +58,4 @@ en: show: assemblies: Assemblies participatory_processes: Participatory Processes + statistics: Statistics diff --git a/config/locales/es.yml b/config/locales/es.yml index 4279cfa..1ce7f24 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -57,3 +57,4 @@ es: show: assemblies: Asambleas participatory_processes: Procesos participativos + statistics: Estadísticas From 2362337d204679bafc98e8a7b01202a2cbca0b4b Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 11:56:05 +0100 Subject: [PATCH 08/14] Fixed rubocop issues --- .../decidim/superspaces/superspace_stats_presenter.rb | 2 +- app/queries/decidim/superspaces/stats_followers_count.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/presenters/decidim/superspaces/superspace_stats_presenter.rb b/app/presenters/decidim/superspaces/superspace_stats_presenter.rb index a2d9c39..4650da5 100644 --- a/app/presenters/decidim/superspaces/superspace_stats_presenter.rb +++ b/app/presenters/decidim/superspaces/superspace_stats_presenter.rb @@ -17,7 +17,7 @@ def participatory_space_participants_stats Decidim::Superspaces::StatsParticipantsCount.for(participatory_space) end - def participatory_space_followers_stats(conditions) + def participatory_space_followers_stats(_conditions) Decidim::Superspaces::StatsFollowersCount.for(participatory_space) end diff --git a/app/queries/decidim/superspaces/stats_followers_count.rb b/app/queries/decidim/superspaces/stats_followers_count.rb index fd3467d..31c32ff 100644 --- a/app/queries/decidim/superspaces/stats_followers_count.rb +++ b/app/queries/decidim/superspaces/stats_followers_count.rb @@ -14,12 +14,12 @@ def initialize(superspace) end def query - count=space_query + components_query + count = space_query + components_query - data = [{participatory_space: superspace.to_s, stat_title: "followers_count", stat_value: count}] + data = [{ participatory_space: superspace.to_s, stat_title: "followers_count", stat_value: count }] data.map do |d| - [d[:participatory_space].to_sym, d[:stat_title].to_sym, d[:stat_value].to_i] + [d[:participatory_space].to_sym, d[:stat_title].to_sym, d[:stat_value].to_i] end end From 6a03d751d8e1e9b0b86a6eaec964a2eb35c710f3 Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 13:03:47 +0100 Subject: [PATCH 09/14] Refactored participants query class --- .../superspaces/stats_followers_count.rb | 4 + .../superspaces/stats_participants_count.rb | 251 +++++------------- 2 files changed, 71 insertions(+), 184 deletions(-) diff --git a/app/queries/decidim/superspaces/stats_followers_count.rb b/app/queries/decidim/superspaces/stats_followers_count.rb index 31c32ff..58d64d1 100644 --- a/app/queries/decidim/superspaces/stats_followers_count.rb +++ b/app/queries/decidim/superspaces/stats_followers_count.rb @@ -3,6 +3,10 @@ module Decidim module Superspaces class StatsFollowersCount < Decidim::Query + + #This class is responsible for calculating the number of followers of a superspace. + #The number of followers in a superspace is equal to the sum of the number of followers in all the participatory spaces that belong to the superspace. + def self.for(superspace) return 0 unless superspace.is_a?(Decidim::Superspaces::Superspace) diff --git a/app/queries/decidim/superspaces/stats_participants_count.rb b/app/queries/decidim/superspaces/stats_participants_count.rb index fb988d8..cc669dc 100644 --- a/app/queries/decidim/superspaces/stats_participants_count.rb +++ b/app/queries/decidim/superspaces/stats_participants_count.rb @@ -2,8 +2,12 @@ module Decidim module Superspaces - # TODO: Change the name of the class to StatsParticipantsCount class StatsParticipantsCount < Decidim::Query + + #This class is responsible for calculating the number of participants of a superspace. + #The number of participants in a superspace is equal to the sum of participants of the participatory spaces that belong to the superspace. + #If a user has participated in more than one participatory space, it will only be counted once. + def self.for(superspace) return 0 unless superspace.is_a?(Decidim::Superspaces::Superspace) @@ -15,15 +19,35 @@ def initialize(superspace) end def query + participatory_process_class_name=Decidim::ParticipatoryProcess.class.name + assemblies_class_name=Decidim::Assembly.class.name + conferences_class_name=Decidim::Conference.class.name + solution = [ - comments_query, - debates_query, - meetings_query, - endorsements_query, - project_votes_query, - proposals_query, - proposal_votes_query, - survey_answer_query + comments_query(participatory_process_class_name, participatory_space_ids), + comments_query(assemblies_class_name, assemblies_ids), + comments_query(conferences_class_name, conferences_ids), + debates_query(space_components), + debates_query(assemblies_components), + debates_query(conferences_components), + meetings_query(space_components), + meetings_query(assemblies_components), + meetings_query(conferences_components), + endorsements_query(space_components), + endorsements_query(assemblies_components), + endorsements_query(conferences_components), + project_votes_query(space_components), + project_votes_query(assemblies_components), + project_votes_query(conferences_components), + proposals_query(proposals_components), + proposals_query(assemblies_proposals_components), + proposals_query(conferences_proposals_components), + proposal_votes_query(proposals_components), + proposal_votes_query(assemblies_proposals_components), + proposal_votes_query(conferences_proposals_components), + survey_answer_query(space_components), + survey_answer_query(assemblies_components), + survey_answer_query(conferences_components), ].flatten.uniq.count data = [{ participatory_space: @superspace.to_s, stat_title: "participants_count", stat_value: solution }] @@ -35,10 +59,8 @@ def query private - attr_reader :participatory_space - def participatory_space_ids - @participatory_space_ids ||= @superspace.participatory_spaces.map(&:id) + @participatory_space_ids ||= @superspace.participatory_processes.map(&:id) end def assemblies_ids @@ -49,141 +71,49 @@ def conferences_ids @conferences_ids ||= @superspace.conferences.map(&:id) end - def participatory_spaces_comments_query - Decidim::Comments::Comment - .where(decidim_participatory_space_type: Decidim::ParticipatoryProcess.class.name) - .where(decidim_participatory_space_id: participatory_space_ids) - .pluck(:decidim_author_id) - .uniq - end - - def assemblies_comments_query - Decidim::Comments::Comment - .where(decidim_participatory_space_type: Decidim::Assembly.class.name) - .where(decidim_participatory_space_id: assemblies_ids) - .pluck(:decidim_author_id) - .uniq - end - - def conferences_comments_query - Decidim::Comments::Comment - .where(decidim_participatory_space_type: Decidim::Conference.class.name) - .where(decidim_participatory_space_id: conferences_ids) - .pluck(:decidim_author_id) - .uniq - end - - def comments_query + def comments_query(class_name, ids) return [] unless Decidim.module_installed?(:comments) - [participatory_spaces_comments_query, assemblies_comments_query, conferences_comments_query].flatten.uniq - end - - def assemblies_debates_query - Decidim::Debates::Debate - .where( - component: assemblies_components, - decidim_author_type: Decidim::UserBaseEntity.name - ) - .not_hidden - .pluck(:decidim_author_id) - .uniq - end - - def participatory_processes_debates_query - Decidim::Debates::Debate - .where( - component: space_components, - decidim_author_type: Decidim::UserBaseEntity.name - ) - .not_hidden - .pluck(:decidim_author_id) - .uniq - end - - def conferences_debates_query - Decidim::Debates::Debate - .where( - component: conferences_components, - decidim_author_type: Decidim::UserBaseEntity.name - ) - .not_hidden - .pluck(:decidim_author_id) - .uniq + Decidim::Comments::Comment + .where(decidim_participatory_space_type: class_name) + .where(decidim_participatory_space_id: ids) + .pluck(:decidim_author_id) + .uniq end - def debates_query + def debates_query(components) return [] unless Decidim.module_installed?(:debates) - [participatory_processes_debates_query, assemblies_debates_query, conferences_debates_query].flatten.uniq + Decidim::Debates::Debate + .where( + component: components, + decidim_author_type: Decidim::UserBaseEntity.name + ) + .not_hidden + .pluck(:decidim_author_id) + .uniq end - def assemblies_meetings_query - assemblies_meetings = Decidim::Meetings::Meeting.where(component: assemblies_components).not_hidden - assemblies_registrations = Decidim::Meetings::Registration.where(decidim_meeting_id: assemblies_meetings).distinct.pluck(:decidim_user_id) - assemblies_organizers = assemblies_meetings.where(decidim_author_type: Decidim::UserBaseEntity.name).distinct.pluck(:decidim_author_id) - - [assemblies_registrations, assemblies_organizers].flatten.uniq - end + def meetings_query(components) + return [] unless Decidim.module_installed?(:meetings) - def participatory_processes_meetings_query - meetings = Decidim::Meetings::Meeting.where(component: @space_components).not_hidden + meetings = Decidim::Meetings::Meeting.where(component: components).not_hidden registrations = Decidim::Meetings::Registration.where(decidim_meeting_id: meetings).distinct.pluck(:decidim_user_id) organizers = meetings.where(decidim_author_type: Decidim::UserBaseEntity.name).distinct.pluck(:decidim_author_id) [registrations, organizers].flatten.uniq end - def conferences_meetings_query - conferences_meetings = Decidim::Meetings::Meeting.where(component: conferences_components).not_hidden - conferences_registrations = Decidim::Meetings::Registration.where(decidim_meeting_id: conferences_meetings).distinct.pluck(:decidim_user_id) - conferences_organizers = conferences_meetings.where(decidim_author_type: Decidim::UserBaseEntity.name).distinct.pluck(:decidim_author_id) - - [conferences_registrations, conferences_organizers].flatten.uniq - end - - def meetings_query - return [] unless Decidim.module_installed?(:meetings) - - [participatory_processes_meetings_query + assemblies_meetings_query + conferences_meetings_query].uniq - end - - def assemblies_endorsements_query - Decidim::Endorsement - .where(resource: assemblies_components) - .pluck(:decidim_author_id) - .uniq - end - - def participatory_processes_endorsements_query - Decidim::Endorsement - .where(resource: space_components) - .pluck(:decidim_author_id) - .uniq - end - - def conferences_endorsements_query + def endorsements_query(components) Decidim::Endorsement - .where(resource: conferences_components) + .where(resource: components) .pluck(:decidim_author_id) .uniq end - def endorsements_query - [participatory_processes_endorsements_query, assemblies_endorsements_query, conferences_endorsements_query].flatten.uniq - end - - def assemblies_proposals_query - Decidim::Coauthorship - .where( - coauthorable: assemblies_proposals_components, - decidim_author_type: Decidim::UserBaseEntity.name - ) - .pluck(:decidim_author_id) - .uniq - end + def proposals_query(proposals_components) + return [] unless Decidim.module_installed?(:proposals) - def participatory_processes_proposals_query Decidim::Coauthorship .where( coauthorable: proposals_components, @@ -193,58 +123,18 @@ def participatory_processes_proposals_query .uniq end - def conferences_proposals_query - Decidim::Coauthorship - .where( - coauthorable: conferences_proposals_components, - decidim_author_type: Decidim::UserBaseEntity.name - ) - .pluck(:decidim_author_id) - .uniq - end - - def proposals_query + def proposal_votes_query(proposals_components) return [] unless Decidim.module_installed?(:proposals) - [participatory_processes_proposals_query, assemblies_proposals_query, conferences_proposals_query].flatten.uniq - end - - def assemblies_proposal_votes_query - Decidim::Proposals::ProposalVote - .where( - proposal: assemblies_proposals_components - ) - .final - .pluck(:decidim_author_id) - .uniq - end - - def participatory_processes_proposal_votes_query Decidim::Proposals::ProposalVote .where( - proposal: proposals_components + proposal: proposals_components, ) .final .pluck(:decidim_author_id) .uniq end - def conferences_proposal_votes_query - Decidim::Proposals::ProposalVote - .where( - proposal: conferences_proposals_components - ) - .final - .pluck(:decidim_author_id) - .uniq - end - - def proposal_votes_query - return [] unless Decidim.module_installed?(:proposals) - - [participatory_processes_proposal_votes_query, assemblies_proposal_votes_query, conferences_proposal_votes_query].flatten.uniq - end - def assemblies_project_votes_query Decidim::Budgets::Order.joins(budget: [:component]) .where(budget: { @@ -272,26 +162,19 @@ def conferences_project_votes_query .uniq end - def project_votes_query + def project_votes_query(components) return [] unless Decidim.module_installed?(:budgets) - [participatory_processes_project_votes_query, assemblies_project_votes_query, conferences_project_votes_query].flatten.uniq - end - - def assemblies_survey_answer_query - Decidim::Forms::Answer.newsletter_participant_ids(assemblies_components) - end - - def participatory_processes_survey_answer_query - Decidim::Forms::Answer.newsletter_participant_ids(space_components) - end - - def conferences_survey_answer_query - Decidim::Forms::Answer.newsletter_participant_ids(conferences_components) + Decidim::Budgets::Order.joins(budget: [:component]) + .where(budget: { + decidim_components: { id: components.pluck(:id) } + }) + .pluck(:decidim_user_id) + .uniq end - def survey_answer_query - [participatory_processes_survey_answer_query, assemblies_survey_answer_query, conferences_survey_answer_query].flatten.uniq + def survey_answer_query(components) + Decidim::Forms::Answer.newsletter_participant_ids(components) end def space_components From 24425bad6abf05d31443109edd1a46e4ebf7cfd1 Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 13:23:41 +0100 Subject: [PATCH 10/14] Deleted extra lines in participants query class --- .../superspaces/stats_participants_count.rb | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/app/queries/decidim/superspaces/stats_participants_count.rb b/app/queries/decidim/superspaces/stats_participants_count.rb index cc669dc..deb4b81 100644 --- a/app/queries/decidim/superspaces/stats_participants_count.rb +++ b/app/queries/decidim/superspaces/stats_participants_count.rb @@ -135,33 +135,6 @@ def proposal_votes_query(proposals_components) .uniq end - def assemblies_project_votes_query - Decidim::Budgets::Order.joins(budget: [:component]) - .where(budget: { - decidim_components: { id: assemblies_components.pluck(:id) } - }) - .pluck(:decidim_user_id) - .uniq - end - - def participatory_processes_project_votes_query - Decidim::Budgets::Order.joins(budget: [:component]) - .where(budget: { - decidim_components: { id: space_components.pluck(:id) } - }) - .pluck(:decidim_user_id) - .uniq - end - - def conferences_project_votes_query - Decidim::Budgets::Order.joins(budget: [:component]) - .where(budget: { - decidim_components: { id: conferences_components.pluck(:id) } - }) - .pluck(:decidim_user_id) - .uniq - end - def project_votes_query(components) return [] unless Decidim.module_installed?(:budgets) From ed1733a7af8a175ed45fef0f2f22f34eb5662d96 Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 13:24:28 +0100 Subject: [PATCH 11/14] Added comments to presenter --- .../decidim/superspaces/superspace_stats_presenter.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/presenters/decidim/superspaces/superspace_stats_presenter.rb b/app/presenters/decidim/superspaces/superspace_stats_presenter.rb index 4650da5..a6af0ce 100644 --- a/app/presenters/decidim/superspaces/superspace_stats_presenter.rb +++ b/app/presenters/decidim/superspaces/superspace_stats_presenter.rb @@ -2,6 +2,11 @@ module Decidim module Superspaces + + # This class holds the logic to present superspace stats. + # It inherits from `Decidim::StatsPresenter` and overrides the methods + # needed to adapt the stats to the superspace context. + class SuperspaceStatsPresenter < Decidim::StatsPresenter include Decidim::IconHelper From 4045a08478ee325e1f7e17a80a5d062347427b37 Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 13:26:06 +0100 Subject: [PATCH 12/14] Changed show view --- app/views/decidim/superspaces/superspaces/show.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/decidim/superspaces/superspaces/show.html.erb b/app/views/decidim/superspaces/superspaces/show.html.erb index c29dca9..bedb4b0 100644 --- a/app/views/decidim/superspaces/superspaces/show.html.erb +++ b/app/views/decidim/superspaces/superspaces/show.html.erb @@ -43,7 +43,7 @@ <% end %> <% if superspace.show_statistics %> -
+

<%= t("statistics", scope: "decidim.superspaces.superspaces.show") %>

<%= cell("decidim/statistics",superspace.statistics) %>
From 2ffee1e09259970c76283ead403ded6450e4da32 Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Wed, 19 Feb 2025 13:26:39 +0100 Subject: [PATCH 13/14] Refactored tests --- .../superspaces/admin/create_superspace_spec.rb | 4 +++- .../superspaces/admin/update_superspace_spec.rb | 6 ++++-- spec/system/superspaces_spec.rb | 14 +++++++++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/spec/commands/decidim/superspaces/admin/create_superspace_spec.rb b/spec/commands/decidim/superspaces/admin/create_superspace_spec.rb index 8cedd20..8e70f30 100644 --- a/spec/commands/decidim/superspaces/admin/create_superspace_spec.rb +++ b/spec/commands/decidim/superspaces/admin/create_superspace_spec.rb @@ -18,6 +18,7 @@ module Admin let(:participatory_process_ids) { nil } let(:conference_ids) { nil } let(:invalid) { false } + let(:show_statistics) { false } let(:form) do double( invalid?: invalid, @@ -28,7 +29,8 @@ module Admin locale:, assembly_ids:, participatory_process_ids:, - conference_ids: + conference_ids:, + show_statistics:, ) end diff --git a/spec/commands/decidim/superspaces/admin/update_superspace_spec.rb b/spec/commands/decidim/superspaces/admin/update_superspace_spec.rb index e12eb35..6f5f1d3 100644 --- a/spec/commands/decidim/superspaces/admin/update_superspace_spec.rb +++ b/spec/commands/decidim/superspaces/admin/update_superspace_spec.rb @@ -19,6 +19,7 @@ module Admin let(:assembly_ids) { nil } let(:participatory_process_ids) { nil } let(:conference_ids) { nil } + let(:show_statistics) { false } let(:form) do double( invalid?: invalid, @@ -29,7 +30,8 @@ module Admin locale:, assembly_ids:, participatory_process_ids:, - conference_ids: + conference_ids:, + show_statistics:, ) end @@ -67,7 +69,7 @@ module Admin it "traces the action", :versioning do expect(Decidim.traceability) .to receive(:update!) - .with(superspace, current_user, { title: { en: title }, description: { en: description }, locale:, hero_image: }) + .with(superspace, current_user, { title: { en: title }, description: { en: description }, locale:, hero_image: , show_statistics: false }) .and_call_original expect { subject.call }.to change(Decidim::ActionLog, :count) diff --git a/spec/system/superspaces_spec.rb b/spec/system/superspaces_spec.rb index 04ebef8..67c970e 100644 --- a/spec/system/superspaces_spec.rb +++ b/spec/system/superspaces_spec.rb @@ -5,7 +5,7 @@ describe "User sees superspaces" do let!(:organization) { create(:organization) } let!(:user) { create(:user, :admin, :confirmed, organization:) } - let!(:superspaces) { create_list(:superspace, 10, organization:) } + let!(:superspaces) { create_list(:superspace, 10, organization: , show_statistics: true) } let!(:assemblies) { create_list(:assembly, 10, organization:) } let!(:participatory_processes) { create_list(:participatory_process, 10, organization:) } let!(:assembly) { assemblies.first } @@ -42,6 +42,9 @@ within all("#assemblies-grid").last do expect(page).to have_content("Assemblies") end + within all("#statistics-grid").last do + expect(page).to have_content("Statistics") + end end end @@ -53,6 +56,15 @@ it "doesn't render grid if the superspace is empty" do expect(page).to have_no_selector("#processes-grid") expect(page).to have_no_selector("#assemblies-grid") + expect(page).to have_selector("#statistics-grid") + end + + it "doesn't render statistics if the superspace show statistics is false" do + superspaces.last.update!(show_statistics: false) + visit decidim_superspaces.superspace_path(superspaces.last) + + expect(page).to have_no_selector("#statistics-grid") + end end end From 2e92b1ce84b9a591fe443f3f49fab0391e3fb8a2 Mon Sep 17 00:00:00 2001 From: Jose Illana Lope Date: Thu, 20 Feb 2025 09:09:08 +0100 Subject: [PATCH 14/14] Fixed rubocop offenses --- .../superspaces/superspace_stats_presenter.rb | 1 - .../superspaces/stats_followers_count.rb | 5 +-- .../superspaces/stats_participants_count.rb | 39 +++++++++---------- .../admin/create_superspace_spec.rb | 2 +- .../admin/update_superspace_spec.rb | 4 +- spec/system/superspaces_spec.rb | 5 +-- 6 files changed, 26 insertions(+), 30 deletions(-) diff --git a/app/presenters/decidim/superspaces/superspace_stats_presenter.rb b/app/presenters/decidim/superspaces/superspace_stats_presenter.rb index a6af0ce..8b9e083 100644 --- a/app/presenters/decidim/superspaces/superspace_stats_presenter.rb +++ b/app/presenters/decidim/superspaces/superspace_stats_presenter.rb @@ -2,7 +2,6 @@ module Decidim module Superspaces - # This class holds the logic to present superspace stats. # It inherits from `Decidim::StatsPresenter` and overrides the methods # needed to adapt the stats to the superspace context. diff --git a/app/queries/decidim/superspaces/stats_followers_count.rb b/app/queries/decidim/superspaces/stats_followers_count.rb index 58d64d1..cdd670b 100644 --- a/app/queries/decidim/superspaces/stats_followers_count.rb +++ b/app/queries/decidim/superspaces/stats_followers_count.rb @@ -3,10 +3,9 @@ module Decidim module Superspaces class StatsFollowersCount < Decidim::Query + # This class is responsible for calculating the number of followers of a superspace. + # The number of followers in a superspace is equal to the sum of the number of followers in all the participatory spaces that belong to the superspace. - #This class is responsible for calculating the number of followers of a superspace. - #The number of followers in a superspace is equal to the sum of the number of followers in all the participatory spaces that belong to the superspace. - def self.for(superspace) return 0 unless superspace.is_a?(Decidim::Superspaces::Superspace) diff --git a/app/queries/decidim/superspaces/stats_participants_count.rb b/app/queries/decidim/superspaces/stats_participants_count.rb index deb4b81..081a15d 100644 --- a/app/queries/decidim/superspaces/stats_participants_count.rb +++ b/app/queries/decidim/superspaces/stats_participants_count.rb @@ -3,10 +3,9 @@ module Decidim module Superspaces class StatsParticipantsCount < Decidim::Query - - #This class is responsible for calculating the number of participants of a superspace. - #The number of participants in a superspace is equal to the sum of participants of the participatory spaces that belong to the superspace. - #If a user has participated in more than one participatory space, it will only be counted once. + # This class is responsible for calculating the number of participants of a superspace. + # The number of participants in a superspace is equal to the sum of participants of the participatory spaces that belong to the superspace. + # If a user has participated in more than one participatory space, it will only be counted once. def self.for(superspace) return 0 unless superspace.is_a?(Decidim::Superspaces::Superspace) @@ -19,9 +18,9 @@ def initialize(superspace) end def query - participatory_process_class_name=Decidim::ParticipatoryProcess.class.name - assemblies_class_name=Decidim::Assembly.class.name - conferences_class_name=Decidim::Conference.class.name + participatory_process_class_name = Decidim::ParticipatoryProcess.class.name + assemblies_class_name = Decidim::Assembly.class.name + conferences_class_name = Decidim::Conference.class.name solution = [ comments_query(participatory_process_class_name, participatory_space_ids), @@ -47,7 +46,7 @@ def query proposal_votes_query(conferences_proposals_components), survey_answer_query(space_components), survey_answer_query(assemblies_components), - survey_answer_query(conferences_components), + survey_answer_query(conferences_components) ].flatten.uniq.count data = [{ participatory_space: @superspace.to_s, stat_title: "participants_count", stat_value: solution }] @@ -75,23 +74,23 @@ def comments_query(class_name, ids) return [] unless Decidim.module_installed?(:comments) Decidim::Comments::Comment - .where(decidim_participatory_space_type: class_name) - .where(decidim_participatory_space_id: ids) - .pluck(:decidim_author_id) - .uniq + .where(decidim_participatory_space_type: class_name) + .where(decidim_participatory_space_id: ids) + .pluck(:decidim_author_id) + .uniq end def debates_query(components) return [] unless Decidim.module_installed?(:debates) Decidim::Debates::Debate - .where( - component: components, - decidim_author_type: Decidim::UserBaseEntity.name - ) - .not_hidden - .pluck(:decidim_author_id) - .uniq + .where( + component: components, + decidim_author_type: Decidim::UserBaseEntity.name + ) + .not_hidden + .pluck(:decidim_author_id) + .uniq end def meetings_query(components) @@ -128,7 +127,7 @@ def proposal_votes_query(proposals_components) Decidim::Proposals::ProposalVote .where( - proposal: proposals_components, + proposal: proposals_components ) .final .pluck(:decidim_author_id) diff --git a/spec/commands/decidim/superspaces/admin/create_superspace_spec.rb b/spec/commands/decidim/superspaces/admin/create_superspace_spec.rb index 8e70f30..b97fd44 100644 --- a/spec/commands/decidim/superspaces/admin/create_superspace_spec.rb +++ b/spec/commands/decidim/superspaces/admin/create_superspace_spec.rb @@ -30,7 +30,7 @@ module Admin assembly_ids:, participatory_process_ids:, conference_ids:, - show_statistics:, + show_statistics: ) end diff --git a/spec/commands/decidim/superspaces/admin/update_superspace_spec.rb b/spec/commands/decidim/superspaces/admin/update_superspace_spec.rb index 6f5f1d3..8f9f4ac 100644 --- a/spec/commands/decidim/superspaces/admin/update_superspace_spec.rb +++ b/spec/commands/decidim/superspaces/admin/update_superspace_spec.rb @@ -31,7 +31,7 @@ module Admin assembly_ids:, participatory_process_ids:, conference_ids:, - show_statistics:, + show_statistics: ) end @@ -69,7 +69,7 @@ module Admin it "traces the action", :versioning do expect(Decidim.traceability) .to receive(:update!) - .with(superspace, current_user, { title: { en: title }, description: { en: description }, locale:, hero_image: , show_statistics: false }) + .with(superspace, current_user, { title: { en: title }, description: { en: description }, locale:, hero_image:, show_statistics: false }) .and_call_original expect { subject.call }.to change(Decidim::ActionLog, :count) diff --git a/spec/system/superspaces_spec.rb b/spec/system/superspaces_spec.rb index 67c970e..fd74648 100644 --- a/spec/system/superspaces_spec.rb +++ b/spec/system/superspaces_spec.rb @@ -5,7 +5,7 @@ describe "User sees superspaces" do let!(:organization) { create(:organization) } let!(:user) { create(:user, :admin, :confirmed, organization:) } - let!(:superspaces) { create_list(:superspace, 10, organization: , show_statistics: true) } + let!(:superspaces) { create_list(:superspace, 10, organization:, show_statistics: true) } let!(:assemblies) { create_list(:assembly, 10, organization:) } let!(:participatory_processes) { create_list(:participatory_process, 10, organization:) } let!(:assembly) { assemblies.first } @@ -56,7 +56,7 @@ it "doesn't render grid if the superspace is empty" do expect(page).to have_no_selector("#processes-grid") expect(page).to have_no_selector("#assemblies-grid") - expect(page).to have_selector("#statistics-grid") + expect(page).to have_css("#statistics-grid") end it "doesn't render statistics if the superspace show statistics is false" do @@ -64,7 +64,6 @@ visit decidim_superspaces.superspace_path(superspaces.last) expect(page).to have_no_selector("#statistics-grid") - end end end