Skip to content

Commit

Permalink
Merge pull request #495 from gencat/feat/unified_notification_on_prop…
Browse files Browse the repository at this point in the history
…oses_loaded_massively

Feat/unified notification on proposes loaded massively
  • Loading branch information
ivan-mr authored Oct 7, 2024
2 parents 81ab4e3 + 6d749b1 commit 1a512be
Show file tree
Hide file tree
Showing 22 changed files with 420 additions and 4 deletions.
29 changes: 29 additions & 0 deletions app/decorators/decidim/admin/import/importer_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

module Decidim::Admin::Import::ImporterDecorator
def self.decorate
Decidim::Admin::Import::Importer.class_eval do
def import!
finished_collection = collection.map { |elem| object_to_manage_without_notify_uniquely?(elem) ? elem.finish_without_notif! : elem.finish! }
notify_collection(finished_collection, collection.first)
end

def notify_collection(collection, klass)
recipients = collection.flat_map { |elem| elem.participatory_space.followers.where(notification_types: %w(all followed-only)).uniq }.uniq
case klass
when Decidim::Proposals::Import::ProposalCreator
recipients.each { |recipient| ProposalsMailer.notify_massive_import(collection, recipient).deliver_later }
when Decidim::Proposals::Import::ProposalAnswerCreator
recipients.each { |recipient| ProposalsAnswersMailer.notify_massive_import(collection, recipient).deliver_later }
end
end

def object_to_manage_without_notify_uniquely?(obj)
# These types of object must be notified in group, not uniquely
[Decidim::Proposals::Import::ProposalCreator, Decidim::Proposals::Import::ProposalAnswerCreator].include? obj.class
end
end
end
end

::Decidim::Admin::Import::ImporterDecorator.decorate
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

module Decidim::Proposals::Import::ProposalAnswerCreatorDecorator
def self.decorate
Decidim::Proposals::Import::ProposalAnswerCreator.class_eval do
def finish_without_notif!
Decidim.traceability.perform_action!(
"answer",
resource,
current_user
) do
resource.try(:save!)
end
resource
end
end
end
end

Decidim::Proposals::Import::ProposalAnswerCreatorDecorator.decorate
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

module Decidim::Proposals::Import::ProposalCreatorDecorator
def self.decorate
Decidim::Proposals::Import::ProposalCreator.class_eval do
def finish_without_notif!
Decidim.traceability.perform_action!(:create, self.class.resource_klass, context[:current_user], visibility: "admin-only") do
resource.save!
resource
end
resource
end
end
end
end

::Decidim::Proposals::Import::ProposalCreatorDecorator.decorate
2 changes: 1 addition & 1 deletion app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class ApplicationMailer < ActionMailer::Base
default from: "[email protected]"
default from: Decidim.mailer_sender
layout "mailer"
end
26 changes: 26 additions & 0 deletions app/mailers/proposals_answers_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

class ProposalsAnswersMailer < ApplicationMailer
include Decidim::SanitizeHelper
include Decidim::ComponentPathHelper

layout "decidim/mailer"

def notify_massive_import(answers_collection, user)
@organization = user.organization
first_answer = answers_collection.first
@participatory_space_title = decidim_sanitize_translated(first_answer.participatory_space.title) if first_answer.present?
@user = user
@component_url = manage_component_url(first_answer.component)
I18n.locale = user.locale if user.locale.present?

subject = I18n.t("proposals_answers_imported.email_subject", scope: "decidim.events.proposals", participatory_space_title: @participatory_space_title)
mail(to: user.email, subject: subject)
end

private

def manage_component_url(component)
Decidim::EngineRouter.main_proxy(component).root_url
end
end
26 changes: 26 additions & 0 deletions app/mailers/proposals_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

class ProposalsMailer < ApplicationMailer
include Decidim::SanitizeHelper
include Decidim::ComponentPathHelper

layout "decidim/mailer"

def notify_massive_import(proposals_collection, user)
@organization = user.organization
first_proposal = proposals_collection.first
@participatory_space_title = decidim_sanitize_translated(first_proposal.participatory_space.title) if first_proposal.present?
@user = user
@component_url = manage_component_url(first_proposal.component)
I18n.locale = user.locale if user.locale.present?

subject = I18n.t("proposals_imported.email_subject", scope: "decidim.events.proposals", participatory_space_title: @participatory_space_title)
mail(to: user.email, subject: subject)
end

private

def manage_component_url(component)
Decidim::EngineRouter.main_proxy(component).root_url
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<p class="email-greeting"><%= I18n.t("decidim.events.email_event.email_greeting", user_name: @user.name) %></p>
<p class="email-instructions"><%= I18n.t("decidim.events.proposals.proposals_answers_imported.email_intro", participatory_space_title: @participatory_space_title).html_safe %></p>
<p class="email-instructions"><%= I18n.t("decidim.events.proposals.proposals_answers_imported.email_link", participatory_space_url: @component_url).html_safe %></p>
<p class="email-closing"><%= I18n.t("decidim.events.proposals.proposals_answers_imported.email_outro", participatory_space_title: @participatory_space_title) %></p>
4 changes: 4 additions & 0 deletions app/views/proposals_mailer/notify_massive_import.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<p class="email-greeting"><%= I18n.t("decidim.events.email_event.email_greeting", user_name: @user.name) %></p>
<p class="email-instructions"><%= I18n.t("decidim.events.proposals.proposals_imported.email_intro", participatory_space_title: @participatory_space_title).html_safe %></p>
<p class="email-instructions"><%= I18n.t("decidim.events.proposals.proposals_imported.email_link", participatory_space_url: @component_url).html_safe %></p>
<p class="email-closing"><%= I18n.t("decidim.events.proposals.proposals_imported.email_outro", participatory_space_title: @participatory_space_title) %></p>
12 changes: 12 additions & 0 deletions config/locales/ca_proposals.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ ca:
step:
endorsements_blocked: Adhesions bloquejades
endorsements_enabled: Adhesions habilitades
events:
proposals:
proposals_answers_imported:
email_intro: S'ha donat resposta a propostes de l'espai "%{participatory_space_title}".
email_link: "Pots llegir les respostes des d'aquesta pàgina: <a href='%{participatory_space_url}'>enllaç</a>."
email_outro: Has rebut aquesta notificació perquè estas seguint l'espai "%{participatory_space_title}". Pots deixar de rebre notificacions seguint l'enllaç anterior.
email_subject: Noves respostes a propostes de %{participatory_space_title}
proposals_imported:
email_intro: S'han afegit noves propostes a l'espai "%{participatory_space_title}".
email_link: Pots veure les noves propostes seguint <a href="%{participatory_space_url}">aquest enllaç</a>.
email_outro: Has rebut aquesta notificació perquè estas seguint l'espai "%{participatory_space_title}". Pots deixar de rebre notificacions seguint l'enllaç anterior.
email_subject: Noves propostes afegides a %{participatory_space_title}
proposals:
application_helper:
filter_type_values:
Expand Down
12 changes: 12 additions & 0 deletions config/locales/en_proposals.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
---
en:
decidim:
events:
proposals:
proposals_answers_imported:
email_intro: Proposals have been answered in the "%{participatory_space_title}" space.
email_link: "You can read the answers from this page: <a href='%{participatory_space_url}'>link</a>."
email_outro: You have received this notification because you are following "%{participatory_space_title}". You can unfollow it from the previous link.
email_subject: New responses to proposals in %{participatory_space_title}
proposals_imported:
email_intro: New proposals has been added to "%{participatory_space_title}".
email_link: You can see the new proposals by following <a href="%{participatory_space_url}">this link</a>.
email_outro: You have received this notification because you are following "%{participatory_space_title}". You can unfollow it from the previous link.
email_subject: New proposals added to %{participatory_space_title}
proposals:
proposals:
show:
Expand Down
14 changes: 13 additions & 1 deletion config/locales/es_proposals.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
---
es:
decidim:
events:
proposals:
proposals_answers_imported:
email_intro: Se ha dado respuesta a propuestas del espacio "%{participatory_space_title}".
email_link: "Puedes leer las respuestas desde esta página: <a href='%{participatory_space_url}'>enlace</a>."
email_outro: Has recibido esta notificación porque estas siguiendo el espacio "%{participatory_space_title}". Puedes dejar de recibir notificaciones siguiendo el enlace anterior.
email_subject: Nuevas respuestas a propuestas de %{participatory_space_title}
proposals_imported:
email_intro: Se han añadido nuevas propuestas al espacio "%{participatory_space_title}".
email_link: Puedes ver las nuevas propuestas siguiendo <a href="%{participatory_space_url}">este enlace</a>.
email_outro: Has recibido esta notificación porque estas siguiendo el espacio "%{participatory_space_title}". Puedes dejar de recibir notificaciones siguiendo el enlace anterior.
email_subject: Nuevas propuestas añadidas a %{participatory_space_title}
proposals:
proposals:
show:
proposal_in_evaluation_reason: 'Esta propuesta está en evaluación porque:'
proposal_in_evaluation_reason: 'Esta propuesta está en evaluación porque:'
10 changes: 10 additions & 0 deletions config/locales/oc_proposals.yml
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,16 @@ oc:
email_outro: Has rebut aquesta notificació perquè estàs seguint "%{participatory_space_title}". Pots deixar de rebre notificacions seguint l'enllaç anterior.
email_subject: Nova proposta "%{resource_title}" afegida a %{participatory_space_title}
notification_title: La proposta <a href="%{resource_path}">%{resource_title}</a> s'ha afegit a %{participatory_space_title}
proposals_answers_imported:
email_intro: S'a dat responsa a prepauses der espaci "%{participatory_space_title}".
email_link: "Pòdes liéger es responses dempús d'aguesta pagina: <a href='%{participatory_space_url}'>ligam</a>."
email_outro: As arrecebut aguesta notificacion pr'amor qu'estas en tot seguir er espaci "%{participatory_space_title}". Pòdes quitar d'arrecéber notificacions en tot seguir eth ligam anterior.
email_subject: Naues responses a prepauses en %{participatory_space_title}
proposals_imported:
email_intro: S'han ahijut naues prepauses ar espaci "%{participatory_space_title}", que seguisses.
email_link: Pòdes veir es naues prepauses en tot seguir <a href="%{participatory_space_url}">aguest lligam</a>.
email_outro: As arrecebut aguesta notificacion pr'amor qu'estas en tot seguir er espaci "%{participatory_space_title}". Pòdes quitar d'arrecéber notificacions en tot seguir eth ligam anterior.
email_subject: Naues prepauses ahijudes en %{participatory_space_title}
proposal_rejected:
affected_user:
email_intro: 'La teva proposta "%{resource_title}" ha estat rebutjada. Pots llegir la resposta en aquesta pàgina:'
Expand Down
3 changes: 1 addition & 2 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,8 @@
t.string "facebook_handler"
t.string "youtube_handler"
t.string "github_handler"
t.bigint "decidim_assemblies_type_id"
t.boolean "destacat", default: false
t.boolean "show_home", default: false
t.bigint "decidim_assemblies_type_id"
t.integer "weight", default: 1, null: false
t.integer "follows_count", default: 0, null: false
t.jsonb "announcement"
Expand Down
3 changes: 3 additions & 0 deletions decidim-process-extended/config/locales/ca.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ ca:
left: Restant
title: Té %{limit} suports a distribuir
votes: Suports
events:
publish_proposals_event:
email_intro: S'han afegit noves propostes a l'espai "%{resource_title}". Pots veure les noves propostes seguint <a href="%{resource_url}">aquest enllaç</a>.
activemodel:
attributes:
participatory_process:
Expand Down
3 changes: 3 additions & 0 deletions decidim-process-extended/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ en:
left: Left
title: You have %{limit} supports to distribute
votes: Votes
events:
publish_proposals_event:
email_intro: New proposals has been added to "%{resource_title}". You can see the new proposals by following <a href="%{resource_url}">this link</a>.
activemodel:
attributes:
participatory_process:
Expand Down
3 changes: 3 additions & 0 deletions decidim-process-extended/config/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ es:
left: Restante
title: Tiene %{limit} soportes a distribuir
votes: Soportes
events:
publish_proposals_event:
email_intro: Se han añadido nuevas propuestas al espacio "%{resource_title}. Puedes ver las nuevas propuestas siguiendo <a href="%{resource_url}">este enlace</a>.
activemodel:
attributes:
participatory_process:
Expand Down
3 changes: 3 additions & 0 deletions decidim-process-extended/config/locales/oc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ oc:
application:
attachments:
meetings_available: Hi ha trobades programades actualment
events:
publish_proposals_event:
email_intro: S'han ahijut naues prepauses ar espaci "%{participatory_space_title}", que seguisses. Pòdes veir es naues prepauses en tot seguir <a href="%{participatory_space_url}">aguest lligam</a>.
activemodel:
attributes:
participatory_process:
Expand Down
4 changes: 4 additions & 0 deletions lib/assets/import_answers.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
id;state;answer/ca;answer/es;answer/oc;answer/en
89117;accepted;Example answer;Example answer;Example answer;Example answer
89117;rejected;Example answer;Example answer;Example answer;Example answer
89117;evaluating;Example answer;Example answer;Example answer;Example answer
62 changes: 62 additions & 0 deletions spec/decorators/decidim/admin/import/importer_decorator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# frozen_string_literal: true

require "rails_helper"
require "decidim/proposals/import/proposal_creator_decorator"

describe Decidim::Admin::Import::Importer do
subject { described_class.new(file: blob, reader: reader, creator: creator, context: context) }

let(:organization) { create(:organization, available_locales: [:en]) }
let(:user) { create(:user, organization: organization) }
let(:follower) { create(:user, organization: organization, notification_types: "all") }
let(:context) do
{
current_organization: organization,
current_user: user,
current_component: current_component,
current_participatory_space: participatory_process
}
end
let(:participatory_process) { create :participatory_process, organization: organization }
let(:current_component) { create :component, manifest_name: :proposals, participatory_space: participatory_process }
let(:reader) { Decidim::Admin::Import::Readers::CSV }

describe "#notify_collection" do
context "when imported collection are proposals" do
let(:creator) { Decidim::Proposals::Import::ProposalCreator }
let(:blob) { upload_test_file(Decidim::Dev.asset("import_proposals.csv"), return_blob: true) }

before do
participatory_process.followers << follower
ActionMailer::Base.deliveries.clear
allow(ProposalsMailer).to receive(:notify_massive_import).and_call_original
end

it_behaves_like "proposal importer"

it "will call ProposalsMailer.notify_massive_import with the collection" do
subject.prepare
subject.import!
expect(ProposalsMailer).to have_received(:notify_massive_import)
end
end

context "when imported collection are answers proposals" do
let(:creator) { Decidim::Proposals::Import::ProposalAnswerCreator }
let(:blob) { upload_test_file(Rails.root.join("lib", "assets", "import_answers.csv").to_s, return_blob: true) }

before do
participatory_process.followers << follower
create(:proposal, :evaluating, component: current_component, id: 89_117)
ActionMailer::Base.deliveries.clear
allow(ProposalsAnswersMailer).to receive(:notify_massive_import).and_call_original
end

it "will call ProposalsMailer.notify_massive_import with the collection" do
subject.prepare
subject.import!
expect(ProposalsAnswersMailer).to have_received(:notify_massive_import)
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

require "rails_helper"
require "decidim/proposals/import/proposal_answer_creator"

describe Decidim::Proposals::Import::ProposalAnswerCreator do
subject { described_class.new(data, context) }

let(:proposal) { create(:proposal, state: state, component: component) }
let!(:moment) { Time.current }
let(:data) do
{
id: proposal.id,
state: state,
"answer/en": Faker::Lorem.paragraph
}
end
let(:organization) { create(:organization, available_locales: [:en]) }
let(:user) { create(:user, organization: organization) }
let(:context) do
{
current_organization: organization,
current_user: user,
current_component: component,
current_participatory_space: participatory_process
}
end
let(:participatory_process) { create :participatory_process, organization: organization }
let(:component) { create :component, manifest_name: :proposals, participatory_space: participatory_process }
let(:state) { %w(evaluating accepted rejected).sample }

describe "#finish_without_notif!" do
it "saves the answer proposal" do
record = subject.produce
subject.finish!
expect(record.new_record?).to be(false)
end

it "creates an admin log record" do
record = subject.produce
subject.finish!

log = Decidim::ActionLog.last
expect(log.resource).to eq(record)
expect(log.action).to eq("answer")
end

context "when proposal state changes" do
let!(:proposal) { create(:proposal, :evaluating, component: component) }
let(:state) { "accepted" }

it "returns broadcast :ok" do
expect(subject.finish!).to eq({ ok: [] })
end
end
end
end
Loading

0 comments on commit 1a512be

Please sign in to comment.