Skip to content

Commit

Permalink
backport: Export issue for Processes Administrators (#573)
Browse files Browse the repository at this point in the history
Co-authored-by: Lucie Grau <[email protected]>
  • Loading branch information
AyakorK and luciegrau authored Aug 19, 2024
1 parent 1da9b76 commit 075dd38
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 0 deletions.
31 changes: 31 additions & 0 deletions app/jobs/decidim/export_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module Decidim
class ExportJob < ApplicationJob
queue_as :exports

def perform(user, component, name, format, resource_id = nil)
export_manifest = component.manifest.export_manifests.find do |manifest|
manifest.name == name.to_sym
end

collection = export_manifest.collection.call(component, user, resource_id)
serializer = export_manifest.serializer

export_data = if (serializer == Decidim::Proposals::ProposalSerializer) && (user.admin? || admin_of_process?(user, component))
Decidim::Exporters.find_exporter(format).new(collection, serializer).admin_export
else
Decidim::Exporters.find_exporter(format).new(collection, serializer).export
end
ExportMailer.export(user, name, export_data).deliver_now
end

private

def admin_of_process?(user, component)
return unless component.respond_to?(:participatory_space)

Decidim::ParticipatoryProcessUserRole.exists?(decidim_user_id: user.id, decidim_participatory_process_id: component.participatory_space.id, role: "admin")
end
end
end
1 change: 1 addition & 0 deletions config/initializers/extends.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require "extends/cells/decidim/content_blocks/hero_cell_extends"
require "extends/uploaders/decidim/application_uploader_extends"
require "extends/lib/decidim/proposals/imports/proposal_answer_creator_extends"
require "extends/lib/decidim/phone_authorization_handler/proposal_serializer_extend"

require "decidim/exporters/serializer"
require "extends/lib/decidim/forms/user_answers_serializer_extend"
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

module ProposalSerializerExtend
def author_metadata
author_metadata = {
name: "",
nickname: "",
email: "",
phone_number: ""
}

if proposal.creator.decidim_author_type == "Decidim::UserBaseEntity"
begin
user = Decidim::User.find(proposal.creator_author.id)
author_metadata[:name] = user.try(:name).presence || ""
author_metadata[:nickname] = user.try(:nickname).presence || ""
author_metadata[:email] = user.try(:email).presence || ""
author_metadata[:phone_number] = phone_number(user.id)
rescue ActiveRecord::RecordNotFound => e
Rails.logger.error "User not found: #{e.message}"
author_metadata[:name] = ""
author_metadata[:nickname] = ""
author_metadata[:email] = ""
author_metadata[:phone_number] = ""
end
end

author_metadata
end
end

Decidim::PhoneAuthorizationHandler::Extends::ProposalSerializerExtend.prepend(ProposalSerializerExtend)
125 changes: 125 additions & 0 deletions spec/jobs/export_job_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# frozen_string_literal: true

require "spec_helper"

module Decidim
module Admin
describe ExportJob do
let!(:component) { create(:component, manifest_name: "dummy") }
let(:organization) { component.organization }
let!(:user) { create(:user, organization: organization) }
let!(:admin) { create(:user, :admin, organization: organization) }
let!(:admin_of_the_process) { create(:user, organization: organization) }
let!(:participatory_process) { create(:participatory_process, organization: organization) }
let(:proposal) { create(:proposal) }
let(:collection) { [proposal] } # Use an array with the instance_double
let(:export_manifest) do
instance_double(
# rubocop:disable RSpec/VerifiedDoubleReference
"Decidim::ComponentExportManifest",
# rubocop:enable RSpec/VerifiedDoubleReference
name: :proposals,
collection: ->(_component, _user, _resource_id) { collection },
serializer: Decidim::Proposals::ProposalSerializer
)
end

before do
component.update!(participatory_space: participatory_process)
create(:participatory_process_user_role, user: admin_of_the_process, participatory_process: participatory_process, role: "admin")

allow(component.manifest).to receive(:export_manifests).and_return([export_manifest])
end

it "sends an email with the result of the export" do
ExportJob.perform_now(user, component, "proposals", "CSV")

email = last_email
expect(email.subject).to include("proposals")
attachment = email.attachments.first

expect(attachment.read.length).to be_positive
expect(attachment.mime_type).to eq("application/zip")
expect(attachment.filename).to match(/^proposals-[0-9]+-[0-9]+-[0-9]+-[0-9]+\.zip$/)
end

describe "CSV" do
it "uses the CSV exporter" do
export_data = double

expect(Decidim::Exporters::CSV)
.to(receive(:new).with(anything, Decidim::Proposals::ProposalSerializer))
.and_return(double(export: export_data))

expect(ExportMailer)
.to(receive(:export).with(user, anything, export_data))
.and_return(double(deliver_now: true))

ExportJob.perform_now(user, component, "proposals", "CSV")
end
end

describe "JSON" do
it "uses the JSON exporter" do
export_data = double

expect(Decidim::Exporters::JSON)
.to(receive(:new).with(anything, Decidim::Proposals::ProposalSerializer))
.and_return(double(export: export_data))

expect(ExportMailer)
.to(receive(:export).with(user, anything, export_data))
.and_return(double(deliver_now: true))

ExportJob.perform_now(user, component, "proposals", "JSON")
end
end

describe "Admin export" do
let(:serializer) { Decidim::Proposals::ProposalSerializer }

before do
allow(Decidim::Exporters::CSV)
.to(receive(:new).with(anything, serializer))
.and_return(double(export: "normal export data"))
end

it "allows admin to access admin_export" do
expect(Decidim::Exporters::CSV)
.to(receive(:new).with(anything, serializer))
.and_return(double(admin_export: "admin export data"))

expect(ExportMailer)
.to(receive(:export).with(admin, anything, "admin export data"))
.and_return(double(deliver_now: true))

ExportJob.perform_now(admin, component, "proposals", "CSV")
end

it "allows admin of the process to access admin_export" do
expect(Decidim::Exporters::CSV)
.to(receive(:new).with(anything, serializer))
.and_return(double(admin_export: "admin export data"))

expect(ExportMailer)
.to(receive(:export).with(admin_of_the_process, anything, "admin export data"))
.and_return(double(deliver_now: true))

ExportJob.perform_now(admin_of_the_process, component, "proposals", "CSV")
end

it "does not allow normal user to access admin_export" do
expect(Decidim::Exporters::CSV)
.to(receive(:new).with(anything, serializer))
.and_return(double(export: "normal export data"))

expect(ExportMailer)
.to(receive(:export).with(user, anything, "normal export data"))
.and_return(double(deliver_now: true))

ExportJob.perform_now(user, component, "proposals", "CSV")
end
end
end
end
end

0 comments on commit 075dd38

Please sign in to comment.