-
Notifications
You must be signed in to change notification settings - Fork 13
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
Refactor/add notification after adding a proposal #620
base: develop
Are you sure you want to change the base?
Changes from all commits
5d2076c
b4ef566
490cc23
f8b938b
a28f39a
4c9be63
eb00e65
df4935d
cb8772a
d4beb61
2fbbf92
899f214
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
# frozen_string_literal: true | ||
|
||
module Decidim | ||
module Proposals | ||
# A command with all the business logic when a user publishes a draft proposal. | ||
class PublishProposal < Decidim::Command | ||
include Decidim::AnonymousProposals::AnonymousBehaviorCommandsConcern | ||
|
||
# Public: Initializes the command. | ||
# | ||
# proposal - The proposal to publish. | ||
# current_user - The current user. | ||
# override: decidim-module-anonymous_proposals/app/commands/decidim/anonymous_proposals/publish_proposal_command_overrides.rb | ||
def initialize(proposal, current_user) | ||
@proposal = proposal | ||
@is_anonymous = allow_anonymous_proposals? && (current_user.blank? || proposal.authored_by?(anonymous_group)) | ||
set_current_user(current_user) | ||
end | ||
|
||
# Executes the command. Broadcasts these events: | ||
# | ||
# - :ok when everything is valid and the proposal is published. | ||
# - :invalid if the proposal's author is not the current user. | ||
# | ||
# Returns nothing. | ||
def call | ||
return broadcast(:invalid) unless @proposal.authored_by?(@current_user) | ||
|
||
transaction do | ||
publish_proposal | ||
increment_scores | ||
send_notification | ||
send_notification_to_participatory_space | ||
send_publication_notification | ||
end | ||
|
||
broadcast(:ok, @proposal) | ||
end | ||
|
||
private | ||
|
||
# This will be the PaperTrail version that is | ||
# shown in the version control feature (1 of 1) | ||
# | ||
# For an attribute to appear in the new version it has to be reset | ||
# and reassigned, as PaperTrail only keeps track of object CHANGES. | ||
def publish_proposal | ||
title = reset(:title) | ||
body = reset(:body) | ||
|
||
Decidim.traceability.perform_action!( | ||
"publish", | ||
@proposal, | ||
@current_user, | ||
visibility: "public-only" | ||
) do | ||
@proposal.update title: title, body: body, published_at: Time.current | ||
end | ||
end | ||
|
||
# Reset the attribute to an empty string and return the old value | ||
def reset(attribute) | ||
attribute_value = @proposal[attribute] | ||
PaperTrail.request(enabled: false) do | ||
# rubocop:disable Rails/SkipsModelValidations | ||
@proposal.update_attribute attribute, "" | ||
# rubocop:enable Rails/SkipsModelValidations | ||
end | ||
attribute_value | ||
end | ||
|
||
def send_notification | ||
return if @proposal.coauthorships.empty? | ||
|
||
Decidim::EventsManager.publish( | ||
event: "decidim.events.proposals.proposal_published", | ||
event_class: Decidim::Proposals::PublishProposalEvent, | ||
resource: @proposal, | ||
followers: coauthors_followers | ||
) | ||
end | ||
|
||
def send_publication_notification | ||
Decidim::EventsManager.publish( | ||
event: "decidim.events.proposals.proposal_published_event", | ||
event_class: Decidim::Proposals::ProposalPublishedEvent, | ||
resource: @proposal, | ||
affected_users: [@proposal.creator_identity], | ||
extra: { force_email: true }, | ||
force_send: true | ||
) | ||
end | ||
|
||
def send_notification_to_participatory_space | ||
Decidim::EventsManager.publish( | ||
event: "decidim.events.proposals.proposal_published", | ||
event_class: Decidim::Proposals::PublishProposalEvent, | ||
resource: @proposal, | ||
followers: @proposal.participatory_space.followers - coauthors_followers, | ||
extra: { | ||
participatory_space: true | ||
} | ||
) | ||
end | ||
|
||
def coauthors_followers | ||
@coauthors_followers ||= @proposal.authors.flat_map(&:followers) | ||
end | ||
|
||
def increment_scores | ||
@proposal.coauthorships.find_each do |coauthorship| | ||
if coauthorship.user_group | ||
Decidim::Gamification.increment_score(coauthorship.user_group, :proposals) | ||
else | ||
Decidim::Gamification.increment_score(coauthorship.author, :proposals) | ||
end | ||
end | ||
end | ||
|
||
# override: decidim-module-anonymous_proposals/app/commands/decidim/anonymous_proposals/publish_proposal_command_overrides.rb | ||
def component | ||
@component ||= @proposal.component | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,10 @@ | ||||||
# app/events/decidim/proposals/proposal_published_event.rb | ||||||
module Decidim | ||||||
module Proposals | ||||||
class ProposalPublishedEvent < Decidim::Events::SimpleEvent | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
To be easier to read, we should rename the class Event as follow and also rename the file to |
||||||
def resource_title | ||||||
translated_attribute(resource.title) | ||||||
end | ||||||
end | ||||||
end | ||||||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -147,6 +147,11 @@ en: | |
exports: | ||
awesome_private_proposals: Proposals with private fields | ||
proposal_comments: Comments | ||
notifications: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. English keys must match french keys |
||
proposal_published: | ||
title: "Your proposal %{proposal_title} has been published!" | ||
body: "Your proposal is now live. View it here: %{proposal_link}" | ||
subject: "Your proposal has been published!" | ||
collaborative_drafts: | ||
new: | ||
add_file: Add file | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -67,6 +67,12 @@ fr: | |||||
new: | ||||||
sign_in_disabled: Vous pouvez accéder avec un compte externe | ||||||
events: | ||||||
proposals: | ||||||
proposal_published_event: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
email_intro: 'que vous suivez, a publié une nouvelle proposition appelée "%{resource_title}". Découvrez-le et contribuez:' | ||||||
email_outro: Vous avez reçu cette notification car vous suivez . Si vous souhaitez vous désabonner des notifications, connectez-vous à la plateforme, puis rendez-vous dans l'onglet “Mon compte” > “Paramètres des notifications”. | ||||||
email_subject: Nouvelle proposition "%{resource_title}" publiée | ||||||
notification_title: La proposition <a href="%{resource_path}">%{resource_title}</a> a été publiée. | ||||||
budgets: | ||||||
pending_order: | ||||||
email_intro: Le vote sur le budget "%{resource_title}" n'est pas encore finalisé sur la concertation "%{participatory_space_title}". | ||||||
|
@@ -158,6 +164,11 @@ fr: | |||||
collaborative_drafts_list: Accéder aux brouillons collaboratifs | ||||||
new_proposal: Nouvelle proposition | ||||||
view_proposal: Voir la proposition | ||||||
notifications: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This locale key is no longer needed because it is called above with |
||||||
proposal_published: | ||||||
title: "Votre proposition %{proposal_title} a bien été publiée!" | ||||||
body: "Votre proposition est en ligne. Lien ici: %{proposal_link}" | ||||||
subject: "Votre proposition est publiée!" | ||||||
update: | ||||||
error: Il y a eu une erreur lors de la mise à jour de la proposition. | ||||||
success: Proposition mise à jour avec succès. | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
# frozen_string_literal: true | ||
|
||
require "spec_helper" | ||
|
||
module Decidim | ||
module Proposals | ||
describe ProposalPublishedEvent do | ||
let(:resource) { create :extended_proposal } | ||
let(:participatory_process) { create :participatory_process, organization: organization } | ||
let(:proposal_component) { create(:extended_proposal_component, participatory_space: participatory_process) } | ||
let(:resource_title) { decidim_sanitize_translated(resource.title) } | ||
let(:event_name) { "decidim.events.proposals.proposal_published" } | ||
|
||
include_context "when a simple event" | ||
|
||
it_behaves_like "a simple event" | ||
|
||
describe "resource_text" do | ||
it "returns the proposal body" do | ||
expect(subject.resource_text).to eq(resource.body) | ||
end | ||
end | ||
|
||
describe "email_subject" do | ||
context "when resource title contains apostrophes" do | ||
it "is generated correctly" do | ||
expect(subject.email_subject).to eq("New proposal \"#{resource_title}\" by @#{author.nickname}") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should match the expected translation |
||
end | ||
end | ||
|
||
it "is generated correctly" do | ||
expect(subject.email_subject).to eq("New proposal \"#{resource_title}\" by @#{author.nickname}") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should match the expected translation |
||
end | ||
end | ||
|
||
describe "email_intro" do | ||
it "is generated correctly" do | ||
expect(subject.email_intro) | ||
.to eq("#{author.name} @#{author.nickname}, who you are following, has published a new proposal called \"#{resource_title}\". Check it out and contribute:") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should match the expected translation |
||
end | ||
end | ||
|
||
describe "email_outro" do | ||
it "is generated correctly" do | ||
expect(subject.email_outro) | ||
.to eq("You have received this notification because you are following @#{author.nickname}. You can stop receiving notifications following the previous link.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should match the expected translation |
||
end | ||
end | ||
|
||
describe "notification_title" do | ||
it "is generated correctly" do | ||
expect(subject.notification_title) | ||
.to include("The <a href=\"#{resource_path}\">#{resource_title}</a> proposal was published by ") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should match the expected translation |
||
|
||
expect(subject.notification_title) | ||
.to include("<a href=\"/profiles/#{author.nickname}\">#{author.name} @#{author.nickname}</a>.") | ||
end | ||
end | ||
|
||
describe "translated notifications" do | ||
let(:en_body) { "A nice proposal" } | ||
let(:body) { { en: en_body, machine_translations: { ca: "Une belle idee" } } } | ||
let(:resource) do | ||
create :extended_proposal, | ||
component: proposal_component, | ||
title: { en: "A nice proposal", machine_translations: { ca: "Une belle idee" } }, | ||
body: body | ||
end | ||
|
||
let(:en_version) { subject.resource_text["en"] } | ||
let(:machine_translated) { subject.resource_text["machine_translations"]["ca"] } | ||
let(:translatable) { true } | ||
|
||
it_behaves_like "a translated event" | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.