Skip to content

Commit

Permalink
Add verification data export page in stats module (#552)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
mllocs and fblupi authored Nov 11, 2024
1 parent 4ad485f commit 84e0cbb
Show file tree
Hide file tree
Showing 11 changed files with 240 additions and 0 deletions.
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions decidim-stats/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions decidim-stats/app/form/decidim/stats/authorization_exports_form.rb
Original file line number Diff line number Diff line change
@@ -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
46 changes: 46 additions & 0 deletions decidim-stats/app/jobs/decidim/stats/authorization_exports_job.rb
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<% add_decidim_page_title(t("title", scope: "decidim.stats.authorization_exports")) %>

<div class="item_show__header">
<h1 class="item_show__header-title">
<%= t("title", scope: "decidim.stats.authorization_exports") %>
</h1>
</div>

<div class="item__edit item__edit-1col">
<div class="item__edit-form">
<div class="form__wrapper">
<div class="card">
<div class="card-section">
<div class="row column">
<%= decidim_form_for @form, url: authorization_exports_path, multipart: true, html: { class: "form form-defaults" } do |form| %>
<div class="row column">
<%= form.date_field :start_date, label: t("start_date", scope: "decidim.stats.authorization_exports") %>
</div>

<div class="row column">
<%= form.date_field :end_date, label: t("end_date", scope: "decidim.stats.authorization_exports") %>
</div>

<div class="row column">
<%= form.select :authorization_handler_name, @workflows.map { |workflow| [workflow.fullname, workflow.name] }, label: t("authorization_handler_name", scope: "decidim.stats.authorization_exports") %>
</div>

<div class="item__edit-sticky">
<div class="item__edit-sticky-container">
<%= submit_tag t("submit", scope: "decidim.stats.authorization_exports"), class: "button button__sm button__secondary" %>
</div>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
</div>
10 changes: 10 additions & 0 deletions decidim-stats/config/locales/ca.yml
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions decidim-stats/config/locales/en.yml
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions decidim-stats/config/locales/es.yml
Original file line number Diff line number Diff line change
@@ -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
14 changes: 14 additions & 0 deletions decidim-stats/lib/decidim/stats/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 84e0cbb

Please sign in to comment.