Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backport: Export issue for Processes Administrators #573

Merged
merged 2 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading