From 84e0cbb28d5f421f0744224d8a2342a044075c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A0xim=20Colls?= Date: Mon, 11 Nov 2024 08:53:32 +0100 Subject: [PATCH 1/2] Add verification data export page in stats module (#552) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add verification data export page in stats module * Add filtering by current organization * Remove byebug * Fix export fields * Translate into ca and es * Add icon to export data menu item * Add user hash column in authorization serializer * Fix scope name serialization key * Add documentation to Readme --------- Co-authored-by: Francisco Bolívar --- config/routes.rb | 1 + decidim-stats/README.md | 7 +++ .../stats/authorization_exports_controller.rb | 39 +++++++++++++++ .../stats/authorization_exports_form.rb | 17 +++++++ .../stats/authorization_exports_job.rb | 46 ++++++++++++++++++ .../decidim/stats/authorization_serializer.rb | 47 +++++++++++++++++++ .../authorization_exports/index.html.erb | 39 +++++++++++++++ decidim-stats/config/locales/ca.yml | 10 ++++ decidim-stats/config/locales/en.yml | 10 ++++ decidim-stats/config/locales/es.yml | 10 ++++ decidim-stats/lib/decidim/stats/engine.rb | 14 ++++++ 11 files changed, 240 insertions(+) create mode 100644 decidim-stats/app/controllers/decidim/stats/authorization_exports_controller.rb create mode 100644 decidim-stats/app/form/decidim/stats/authorization_exports_form.rb create mode 100644 decidim-stats/app/jobs/decidim/stats/authorization_exports_job.rb create mode 100644 decidim-stats/app/serializers/decidim/stats/authorization_serializer.rb create mode 100644 decidim-stats/app/views/decidim/stats/authorization_exports/index.html.erb create mode 100644 decidim-stats/config/locales/ca.yml create mode 100644 decidim-stats/config/locales/en.yml create mode 100644 decidim-stats/config/locales/es.yml diff --git a/config/routes.rb b/config/routes.rb index 7427c3e8c1..ba864d5d27 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -51,6 +51,7 @@ end mount Decidim::Core::Engine => "/" + mount Decidim::Stats::Engine, at: "/stats", as: "decidim_stats" mount Decidim::EphemeralParticipation::Engine, at: "/", as: "decidim_ephemeral_participation" mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development? authenticate :user, ->(u) { u.admin? } do diff --git a/decidim-stats/README.md b/decidim-stats/README.md index 76bb7af3fc..225edaeef1 100644 --- a/decidim-stats/README.md +++ b/decidim-stats/README.md @@ -38,6 +38,13 @@ participatory_space_type,participatory_space_id,component_id,action,metric_type, participatory_processes,2,4,comment,age_group,20-24,6 ``` +## Authorization data export page + +This module adds a new admin page, “Export verification data” accessible under the Admin > Participants menu as “Export Data.” + +On this page, admins can fill out a form to specify a Start Date, End Date, and Verification Method. Using these parameters, the form allows the export of census data gathered during the user verification process. Internally, it exports selected metadata fields from the Authorization model. + + ## Development guide The module has different pieces: diff --git a/decidim-stats/app/controllers/decidim/stats/authorization_exports_controller.rb b/decidim-stats/app/controllers/decidim/stats/authorization_exports_controller.rb new file mode 100644 index 0000000000..49d05ebda4 --- /dev/null +++ b/decidim-stats/app/controllers/decidim/stats/authorization_exports_controller.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Decidim + module Stats + class AuthorizationExportsController < Decidim::Admin::ApplicationController + layout "decidim/admin/users" + + def index + enforce_permission_to :index, :authorization_workflow + + @workflows = Decidim::Verifications.workflows.select do |manifest| + current_organization.available_authorizations.include?(manifest.name.to_s) + end + + @form = form(AuthorizationExportsForm).instance + end + + def create + AuthorizationExportsJob.perform_later( + current_user, + current_organization, + name: authorization_params[:authorization_handler_name], + start_date: authorization_params[:start_date], + end_date: authorization_params[:end_date] + ) + + flash[:notice] = t("decidim.admin.exports.notice") + + redirect_to authorization_exports_path + end + + private + + def authorization_params + params.require(:authorization_exports).permit(:authorization_handler_name, :start_date, :end_date) + end + end + end +end diff --git a/decidim-stats/app/form/decidim/stats/authorization_exports_form.rb b/decidim-stats/app/form/decidim/stats/authorization_exports_form.rb new file mode 100644 index 0000000000..22aa5ead5e --- /dev/null +++ b/decidim-stats/app/form/decidim/stats/authorization_exports_form.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Decidim + module Stats + # A form to validate the date range for authorization exports + class AuthorizationExportsForm < Form + include TranslatableAttributes + + attribute :start_date, Decidim::Attributes::LocalizedDate + attribute :end_date, Decidim::Attributes::LocalizedDate + attribute :authorization_handler_name, String + + validates :start_date, presence: true + validates :end_date, presence: true + end + end +end diff --git a/decidim-stats/app/jobs/decidim/stats/authorization_exports_job.rb b/decidim-stats/app/jobs/decidim/stats/authorization_exports_job.rb new file mode 100644 index 0000000000..996e1dab23 --- /dev/null +++ b/decidim-stats/app/jobs/decidim/stats/authorization_exports_job.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module Decidim + module Stats + class AuthorizationExportsJob < ApplicationJob + queue_as :default + + def perform(user, organization, filters) + ExportMailer.export( + user, + export_file_name, + export_data(organization, filters) + ).deliver_now + end + + def export_data(organization, filters) + Decidim::Exporters::CSV.new( + collection(organization, filters), + serializer + ).export + end + + def export_file_name + "authorizations_export" + end + + def collection(organization, filters) + Decidim::Authorization.joins(:user) + .where( + granted_at: filters[:start_date]..filters[:end_date], + name: filters[:name] + ) + Decidim::Authorization.joins(:user) + .where(decidim_users: { decidim_organization_id: organization.id }) + .where( + granted_at: filters[:start_date]..filters[:end_date], + name: filters[:name] + ) + end + + def serializer + Decidim::Stats::AuthorizationSerializer + end + end + end +end diff --git a/decidim-stats/app/serializers/decidim/stats/authorization_serializer.rb b/decidim-stats/app/serializers/decidim/stats/authorization_serializer.rb new file mode 100644 index 0000000000..62121834ab --- /dev/null +++ b/decidim-stats/app/serializers/decidim/stats/authorization_serializer.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Decidim + module Stats + # This class serializes a Authorization so can be exported to CSV + class AuthorizationSerializer < Decidim::Exporters::Serializer + attr_reader :authorization + + def initialize(authorization) + @authorization = authorization + end + + def serialize + { + user_hash:, + date_of_birth: metadata["date_of_birth"], + postal_code: metadata["postal_code"], + scope_name: metadata["scope"], + scope_id: metadata["scope_id"], + scope_code: metadata["scope_code"], + gender: metadata_extras["gender"], + granted_at: authorization.granted_at + } + end + + private + + def metadata + authorization.metadata || {} + end + + def metadata_extras + metadata["extras"] || {} + end + + def user_hash + return "" unless user + + Digest::SHA256.hexdigest(user.id.to_s).last(8) + end + + def user + authorization.user + end + end + end +end diff --git a/decidim-stats/app/views/decidim/stats/authorization_exports/index.html.erb b/decidim-stats/app/views/decidim/stats/authorization_exports/index.html.erb new file mode 100644 index 0000000000..17ed76d9a0 --- /dev/null +++ b/decidim-stats/app/views/decidim/stats/authorization_exports/index.html.erb @@ -0,0 +1,39 @@ +<% add_decidim_page_title(t("title", scope: "decidim.stats.authorization_exports")) %> + +
+

+ <%= t("title", scope: "decidim.stats.authorization_exports") %> +

+
+ +
+
+
+
+
+
+ <%= decidim_form_for @form, url: authorization_exports_path, multipart: true, html: { class: "form form-defaults" } do |form| %> +
+ <%= form.date_field :start_date, label: t("start_date", scope: "decidim.stats.authorization_exports") %> +
+ +
+ <%= form.date_field :end_date, label: t("end_date", scope: "decidim.stats.authorization_exports") %> +
+ +
+ <%= form.select :authorization_handler_name, @workflows.map { |workflow| [workflow.fullname, workflow.name] }, label: t("authorization_handler_name", scope: "decidim.stats.authorization_exports") %> +
+ +
+
+ <%= submit_tag t("submit", scope: "decidim.stats.authorization_exports"), class: "button button__sm button__secondary" %> +
+
+ <% end %> +
+
+
+
+
+
diff --git a/decidim-stats/config/locales/ca.yml b/decidim-stats/config/locales/ca.yml new file mode 100644 index 0000000000..193d64cd8d --- /dev/null +++ b/decidim-stats/config/locales/ca.yml @@ -0,0 +1,10 @@ +ca: + decidim: + stats: + authorization_exports: + title: Exportar dades de verificació + authorization_handler_name: Mètode de verificació + end_date: Data fi + start_date: Data inici + submit: Exportar dades + menu: Exportar dades diff --git a/decidim-stats/config/locales/en.yml b/decidim-stats/config/locales/en.yml new file mode 100644 index 0000000000..904335942c --- /dev/null +++ b/decidim-stats/config/locales/en.yml @@ -0,0 +1,10 @@ +en: + decidim: + stats: + authorization_exports: + title: Export verification data + authorization_handler_name: Verification method + end_date: End date + start_date: Start date + submit: Export verification data + menu: Export data diff --git a/decidim-stats/config/locales/es.yml b/decidim-stats/config/locales/es.yml new file mode 100644 index 0000000000..6381d8ffde --- /dev/null +++ b/decidim-stats/config/locales/es.yml @@ -0,0 +1,10 @@ +es: + decidim: + stats: + authorization_exports: + title: Exportar datos de verificación + authorization_handler_name: Método de verificación + end_date: Fecha fin + start_date: Fecha inicio + submit: Exportar datos + menu: Exportar datos diff --git a/decidim-stats/lib/decidim/stats/engine.rb b/decidim-stats/lib/decidim/stats/engine.rb index ddd3554c74..282cd70c25 100644 --- a/decidim-stats/lib/decidim/stats/engine.rb +++ b/decidim-stats/lib/decidim/stats/engine.rb @@ -4,6 +4,20 @@ module Decidim module Stats class Engine < ::Rails::Engine isolate_namespace Decidim::Stats + + routes do + resources :authorization_exports, only: [:index, :create] + end + + initializer "decidim_stats.admin_menus" do + Decidim.menu :admin_user_menu do |menu| + menu.add_item :authorization_exports, + I18n.t("authorization_exports.menu", scope: "decidim.stats"), + decidim_stats.authorization_exports_path, + active: is_active_link?(decidim_stats.authorization_exports_path), + icon_name: "download-line" + end + end end end end From d98fbfc20ace23816b0752958a5d2a320584964c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=20Bol=C3=ADvar?= Date: Fri, 15 Nov 2024 10:56:47 +0100 Subject: [PATCH 2/2] Bump decidim from `4bfc73b` to `f3b1252` (#577) * Bump decidim from 4bfc73b to f3b1252 * Install wkhtmltopdf in workflow jobs * Remove wkhtmltopdf-binary dependency * Do not remove node_modules after running the compilation --- .github/workflows/test.yml | 6 +++--- .github/workflows/test_census_sms.yml | 6 +++--- .github/workflows/test_stats.yml | 6 +++--- Gemfile | 1 - Gemfile.lock | 6 +----- Rakefile | 4 ---- 6 files changed, 10 insertions(+), 19 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 66c106dead..65b83f1956 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,15 +37,15 @@ jobs: ruby-version: ${{ env.RUBY_VERSION }} bundler-cache: true - uses: nanasess/setup-chromedriver@v2 + - run: | + sudo apt install wkhtmltopdf - run: bundle exec rake db:test:prepare name: Setup database - name: Precompile assets run: | npm install bundle exec rake assets:precompile - - run: | - mkdir node_modules - bundle exec rspec + - run: bundle exec rspec name: Run specs - uses: actions/upload-artifact@v4 if: always() diff --git a/.github/workflows/test_census_sms.yml b/.github/workflows/test_census_sms.yml index 84332e4584..ad9f89b8bf 100644 --- a/.github/workflows/test_census_sms.yml +++ b/.github/workflows/test_census_sms.yml @@ -37,15 +37,15 @@ jobs: ruby-version: ${{ env.RUBY_VERSION }} bundler-cache: true - uses: nanasess/setup-chromedriver@v2 + - run: | + sudo apt install wkhtmltopdf - run: bundle exec rake db:test:prepare name: Setup database - name: Precompile assets run: | npm install bundle exec rake assets:precompile - - run: | - mkdir node_modules - bundle exec rspec decidim-census_sms + - run: bundle exec rspec decidim-census_sms name: Run specs - uses: actions/upload-artifact@v4 if: always() diff --git a/.github/workflows/test_stats.yml b/.github/workflows/test_stats.yml index e53d2e1951..a1236acdce 100644 --- a/.github/workflows/test_stats.yml +++ b/.github/workflows/test_stats.yml @@ -37,15 +37,15 @@ jobs: ruby-version: ${{ env.RUBY_VERSION }} bundler-cache: true - uses: nanasess/setup-chromedriver@v2 + - run: | + sudo apt install wkhtmltopdf - run: bundle exec rake db:test:prepare name: Setup database - name: Precompile assets run: | npm install bundle exec rake assets:precompile - - run: | - mkdir node_modules - bundle exec rspec decidim-stats + - run: bundle exec rspec decidim-stats name: Run specs - uses: actions/upload-artifact@v4 if: always() diff --git a/Gemfile b/Gemfile index c23cc5a58c..3cb02946c1 100644 --- a/Gemfile +++ b/Gemfile @@ -24,7 +24,6 @@ gem "decidim-term_customizer", git: "https://github.com/mainio/decidim-module-te gem "origami" gem "wicked_pdf", "< 2.8" -gem "wkhtmltopdf-binary" gem "progressbar" gem "puma" diff --git a/Gemfile.lock b/Gemfile.lock index 6ebd3b570b..42137d45c6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://github.com/AjuntamentdeBarcelona/decidim - revision: 4bfc73be0724b60918f93867ae0a03d662aea1fd + revision: f3b125243e409476b07c75a7438eafc529dd96c8 branch: release/0.28-stable-bcn specs: decidim (0.28.4) @@ -136,7 +136,6 @@ GIT decidim-forms (0.28.4) decidim-core (= 0.28.4) wicked_pdf (~> 2.1) - wkhtmltopdf-binary (~> 0.12) decidim-generators (0.28.4) decidim-core (= 0.28.4) decidim-initiatives (0.28.4) @@ -146,7 +145,6 @@ GIT decidim-verifications (= 0.28.4) hexapdf (~> 0.32.0) wicked_pdf (~> 2.1) - wkhtmltopdf-binary (~> 0.12) decidim-meetings (0.28.4) decidim-core (= 0.28.4) decidim-forms (= 0.28.4) @@ -968,7 +966,6 @@ GEM activesupport wisper (2.0.1) wisper-rspec (1.1.0) - wkhtmltopdf-binary (0.12.6.6) xpath (3.2.0) nokogiri (~> 1.8) zeitwerk (2.6.18) @@ -1030,7 +1027,6 @@ DEPENDENCIES stackprof web-console wicked_pdf (< 2.8) - wkhtmltopdf-binary RUBY VERSION ruby 3.1.1p18 diff --git a/Rakefile b/Rakefile index bf012913fa..03f34b28d0 100644 --- a/Rakefile +++ b/Rakefile @@ -116,7 +116,3 @@ namespace :decidim_surveys_patch do end end end - -Rake::Task["assets:precompile"].enhance do - FileUtils.remove_dir("node_modules", true) -end