From 90bb06e68461d413f8877003d80d0abf4ddf7149 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Sun, 4 Mar 2018 22:29:40 +0100 Subject: [PATCH 01/29] Fix display of unfeasibility explanation We were missing a check to make sure valuation had finished before displaying the unfeasibility explanation --- spec/features/budgets/investments_spec.rb | 18 +++++++++++ spec/models/budget/investment_spec.rb | 38 +++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index 51445bccc..4347fb212 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -991,6 +991,24 @@ feature 'Budget Investments' do expect(page).not_to have_content("Local government is not competent in this matter") end + scenario "Show (unfeasible budget investment with valuation not finished)" do + user = create(:user) + login_as(user) + + investment = create(:budget_investment, + :unfeasible, + valuation_finished: false, + budget: budget, + group: group, + heading: heading, + unfeasibility_explanation: 'Local government is not competent in this matter') + + visit budget_investment_path(budget_id: budget.id, id: investment.id) + + expect(page).not_to have_content("Unfeasibility explanation") + expect(page).not_to have_content(investment.unfeasibility_explanation) + end + scenario "Show milestones", :js do user = create(:user) investment = create(:budget_investment) diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index a4e1d246d..e9081cf34 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -308,6 +308,44 @@ describe Budget::Investment do end end + describe "#by_budget" do + + it "returns true for unfeasible investments with unfeasibility explanation and valuation finished" do + Budget::Phase::PUBLISHED_PRICES_PHASES.each do |phase| + budget.update(phase: phase) + + expect(investment.should_show_unfeasibility_explanation?).to eq(true) + end + end + + it "returns false in valuation has not finished" do + investment.update(valuation_finished: false) + Budget::Phase::PUBLISHED_PRICES_PHASES.each do |phase| + budget.update(phase: phase) + + expect(investment.should_show_unfeasibility_explanation?).to eq(false) + end + end + + it "returns false if not unfeasible" do + investment.update(feasibility: "undecided") + Budget::Phase::PUBLISHED_PRICES_PHASES.each do |phase| + budget.update(phase: phase) + + expect(investment.should_show_unfeasibility_explanation?).to eq(false) + end + end + + it "returns false if unfeasibility explanation blank" do + investment.update(unfeasibility_explanation: "") + Budget::Phase::PUBLISHED_PRICES_PHASES.each do |phase| + budget.update(phase: phase) + + expect(investment.should_show_unfeasibility_explanation?).to eq(false) + end + end + end + describe "#by_admin" do it "returns investments assigned to specific administrator" do investment1 = create(:budget_investment, administrator_id: 33) From b3978908b2e5cd791c9e159a559de7a7f6d3cd0e Mon Sep 17 00:00:00 2001 From: rgarcia Date: Mon, 5 Mar 2018 01:05:36 +0100 Subject: [PATCH 02/29] Use strings instead of method calls in expectations --- spec/features/budgets/investments_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb index 4347fb212..dbc82ba31 100644 --- a/spec/features/budgets/investments_spec.rb +++ b/spec/features/budgets/investments_spec.rb @@ -1006,7 +1006,7 @@ feature 'Budget Investments' do visit budget_investment_path(budget_id: budget.id, id: investment.id) expect(page).not_to have_content("Unfeasibility explanation") - expect(page).not_to have_content(investment.unfeasibility_explanation) + expect(page).not_to have_content("Local government is not competent in this matter") end scenario "Show milestones", :js do From 8b78dd88a008be28384f03000e5a53e46a40fa3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Mart=C3=ADn?= Date: Wed, 25 Jul 2018 01:43:13 +0200 Subject: [PATCH 03/29] Fix typo in proposal notifications spec. --- spec/features/moderation/proposal_notifications_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/moderation/proposal_notifications_spec.rb b/spec/features/moderation/proposal_notifications_spec.rb index 4af3a815d..396173190 100644 --- a/spec/features/moderation/proposal_notifications_spec.rb +++ b/spec/features/moderation/proposal_notifications_spec.rb @@ -16,7 +16,7 @@ feature 'Moderate proposal notifications' do accept_confirm { click_link 'Hide' } end - expect(page).to have_css("#proposal_notification_#{proposal.id}.faded") + expect(page).to have_css("#proposal_notification_#{proposal_notification.id}.faded") logout login_as(citizen) From 5413c3445836b84f9be1827a1b0fda01f4a37720 Mon Sep 17 00:00:00 2001 From: Marko Lovic Date: Wed, 25 Jul 2018 14:56:32 +0200 Subject: [PATCH 04/29] Restructure and rename translations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on 012e4be by María Checa from AyuntamientoMadrid/consul fork --- app/models/budget/investment/exporter.rb | 20 +++++++-------- .../budget_investments/_investments.html.erb | 24 +++++++++--------- config/locales/en/admin.yml | 25 ++++++++++--------- config/locales/es/admin.yml | 25 ++++++++++--------- 4 files changed, 48 insertions(+), 46 deletions(-) diff --git a/app/models/budget/investment/exporter.rb b/app/models/budget/investment/exporter.rb index 03900fd7e..4d0102e0d 100644 --- a/app/models/budget/investment/exporter.rb +++ b/app/models/budget/investment/exporter.rb @@ -16,16 +16,16 @@ class Budget::Investment::Exporter def headers [ - I18n.t("admin.budget_investments.index.table_id"), - I18n.t("admin.budget_investments.index.table_title"), - I18n.t("admin.budget_investments.index.table_supports"), - I18n.t("admin.budget_investments.index.table_admin"), - I18n.t("admin.budget_investments.index.table_valuator"), - I18n.t("admin.budget_investments.index.table_valuation_group"), - I18n.t("admin.budget_investments.index.table_geozone"), - I18n.t("admin.budget_investments.index.table_feasibility"), - I18n.t("admin.budget_investments.index.table_valuation_finished"), - I18n.t("admin.budget_investments.index.table_selection") + I18n.t("admin.budget_investments.index.list.id"), + I18n.t("admin.budget_investments.index.list.title"), + I18n.t("admin.budget_investments.index.list.supports"), + I18n.t("admin.budget_investments.index.list.admin"), + I18n.t("admin.budget_investments.index.list.valuator"), + I18n.t("admin.budget_investments.index.list.valuation_group"), + I18n.t("admin.budget_investments.index.list.geozone"), + I18n.t("admin.budget_investments.index.list.feasibility"), + I18n.t("admin.budget_investments.index.list.valuation_finished"), + I18n.t("admin.budget_investments.index.list.selected") ] end diff --git a/app/views/admin/budget_investments/_investments.html.erb b/app/views/admin/budget_investments/_investments.html.erb index 17b0315b1..b51c20c3b 100644 --- a/app/views/admin/budget_investments/_investments.html.erb +++ b/app/views/admin/budget_investments/_investments.html.erb @@ -35,21 +35,21 @@ - - - - + + + + - - - - - + + + + + <% if params[:filter] == "selected" %> - + <% end %> diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index ac23897df..7cca0df20 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -187,18 +187,19 @@ en: undecided: "Undecided" selected: "Selected" select: "Select" - table_id: "ID" - table_title: "Title" - table_supports: "Supports" - table_admin: "Administrator" - table_valuator: "Valuator" - table_valuation_group: "Valuation Group" - table_geozone: "Scope of operation" - table_feasibility: "Feasibility" - table_valuation_finished: "Val. Fin." - table_selection: "Selected" - table_evaluation: "Show to valuators" - table_incompatible: "Incompatible" + list: + id: ID + title: Title + supports: Supports + admin: Administrator + valuator: Valuator + valuation_group: Valuation Group + geozone: Scope of operation + feasibility: Feasibility + valuation_finished: Val. Fin. + selected: Selected + visible_to_valuators: Show to valuators + incompatible: Incompatible cannot_calculate_winners: The budget has to stay on phase "Balloting projects", "Reviewing Ballots" or "Finished budget" in order to calculate winners projects see_results: "See results" show: diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 8929f9e3b..dec9a5dfd 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -187,18 +187,19 @@ es: undecided: "Sin decidir" selected: "Seleccionada" select: "Seleccionar" - table_id: "ID" - table_title: "Título" - table_supports: "Apoyos" - table_admin: "Administrador" - table_valuator: "Evaluador" - table_valuation_group: "Grupos evaluadores" - table_geozone: "Ámbito de actuación" - table_feasibility: "Viabilidad" - table_valuation_finished: "Ev. Fin." - table_selection: "Seleccionado" - table_evaluation: "Mostrar a evaluadores" - table_incompatible: "Incompatible" + list: + id: ID + title: Título + supports: Apoyos + admin: Administrador + valuator: Evaluador + valuation_group: Grupos evaluadores + geozone: Ámbito de actuación + feasibility: Viabilidad + valuation_finished: Ev. Fin. + selected: Seleccionado + visible_to_valuators: Mostrar a evaluadores + incompatible: Incompatible cannot_calculate_winners: El presupuesto debe estar en las fases "Votación final", "Votación finalizada" o "Resultados" para poder calcular las propuestas ganadoras see_results: "Ver resultados" show: From 601e3058d865e7bda54d7ce1dddf5f7c37d88ebe Mon Sep 17 00:00:00 2001 From: Marko Lovic Date: Wed, 25 Jul 2018 15:10:56 +0200 Subject: [PATCH 05/29] Add `visible_to_valuators` and author username to admin investments CSV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport based on 012e4be by María Checa from AyuntamientoMadrid/consul fork --- app/models/budget/investment/exporter.rb | 8 ++++++-- config/locales/en/admin.yml | 1 + config/locales/es/admin.yml | 1 + spec/features/admin/budget_investments_spec.rb | 15 +++++++++------ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/app/models/budget/investment/exporter.rb b/app/models/budget/investment/exporter.rb index 4d0102e0d..c7e4ce461 100644 --- a/app/models/budget/investment/exporter.rb +++ b/app/models/budget/investment/exporter.rb @@ -25,7 +25,9 @@ class Budget::Investment::Exporter I18n.t("admin.budget_investments.index.list.geozone"), I18n.t("admin.budget_investments.index.list.feasibility"), I18n.t("admin.budget_investments.index.list.valuation_finished"), - I18n.t("admin.budget_investments.index.list.selected") + I18n.t("admin.budget_investments.index.list.selected"), + I18n.t("admin.budget_investments.index.list.visible_to_valuators"), + I18n.t("admin.budget_investments.index.list.author_username") ] end @@ -40,7 +42,9 @@ class Budget::Investment::Exporter investment.heading.name, price(investment), investment.valuation_finished? ? I18n.t('shared.yes') : I18n.t('shared.no'), - investment.selected? ? I18n.t('shared.yes') : I18n.t('shared.no') + investment.selected? ? I18n.t('shared.yes') : I18n.t('shared.no'), + investment.visible_to_valuators? ? I18n.t('shared.yes') : I18n.t('shared.no'), + investment.author.username ] end diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 7cca0df20..ca619c7d4 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -199,6 +199,7 @@ en: valuation_finished: Val. Fin. selected: Selected visible_to_valuators: Show to valuators + author_username: Author username incompatible: Incompatible cannot_calculate_winners: The budget has to stay on phase "Balloting projects", "Reviewing Ballots" or "Finished budget" in order to calculate winners projects see_results: "See results" diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index dec9a5dfd..909e2509a 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -199,6 +199,7 @@ es: valuation_finished: Ev. Fin. selected: Seleccionado visible_to_valuators: Mostrar a evaluadores + author_username: Usuario autor incompatible: Incompatible cannot_calculate_winners: El presupuesto debe estar en las fases "Votación final", "Votación finalizada" o "Resultados" para poder calcular las propuestas ganadoras see_results: "Ver resultados" diff --git a/spec/features/admin/budget_investments_spec.rb b/spec/features/admin/budget_investments_spec.rb index a745be1c1..3fd4d4175 100644 --- a/spec/features/admin/budget_investments_spec.rb +++ b/spec/features/admin/budget_investments_spec.rb @@ -1060,13 +1060,15 @@ feature 'Admin budget investments' do cached_votes_up: 88, price: 99, valuators: [], valuator_groups: [valuator_group], - administrator: admin) + administrator: admin, + visible_to_valuators: true) second_investment = create(:budget_investment, :unfeasible, title: "Alt Investment", budget: budget, group: budget_group, heading: second_budget_heading, cached_votes_up: 66, price: 88, valuators: [valuator], - valuator_groups: []) + valuator_groups: [], + visible_to_valuators: false) visit admin_budget_budget_investments_path(budget) @@ -1077,10 +1079,11 @@ feature 'Admin budget investments' do expect(header).to match(/filename="budget_investments.csv"$/) csv_contents = "ID,Title,Supports,Administrator,Valuator,Valuation Group,Scope of operation,"\ - "Feasibility,Val. Fin.,Selected\n#{first_investment.id},Le Investment,88,"\ - "Admin,-,Valuator Group,Budget Heading,Feasible (€99),Yes,Yes\n"\ - "#{second_investment.id},Alt Investment,66,No admin assigned,Valuator,-,"\ - "Other Heading,Unfeasible,No,No\n" + "Feasibility,Val. Fin.,Selected,Show to valuators,Author username\n"\ + "#{first_investment.id},Le Investment,88,Admin,-,Valuator Group,"\ + "Budget Heading,Feasible (€99),Yes,Yes,Yes,#{first_investment.author.username}\n#{second_investment.id},"\ + "Alt Investment,66,No admin assigned,Valuator,-,Other Heading,"\ + "Unfeasible,No,No,No,#{second_investment.author.username}\n" expect(page.body).to eq(csv_contents) end From c991d9e7c73f4e713502df0ff8a41e3ae759667d Mon Sep 17 00:00:00 2001 From: Marko Lovic Date: Wed, 25 Jul 2018 17:28:14 +0200 Subject: [PATCH 06/29] Fix typo in i18n key --- app/views/admin/budget_investments/_investments.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/budget_investments/_investments.html.erb b/app/views/admin/budget_investments/_investments.html.erb index b51c20c3b..c5b7493c6 100644 --- a/app/views/admin/budget_investments/_investments.html.erb +++ b/app/views/admin/budget_investments/_investments.html.erb @@ -35,7 +35,7 @@
<%= t("admin.budget_investments.index.table_id") %><%= t("admin.budget_investments.index.table_title") %><%= t("admin.budget_investments.index.table_supports") %><%= t("admin.budget_investments.index.table_admin") %><%= t("admin.budget_investments.index.index.list.id") %><%= t("admin.budget_investments.index.list.title") %><%= t("admin.budget_investments.index.list.supports") %><%= t("admin.budget_investments.index.list.admin") %> - <%= t("admin.budget_investments.index.table_valuation_group") %> - <%= t("admin.budget_investments.index.table_valuator") %> + <%= t("admin.budget_investments.index.list.valuation_group") %> + <%= t("admin.budget_investments.index.list.valuator") %> <%= t("admin.budget_investments.index.table_geozone") %><%= t("admin.budget_investments.index.table_feasibility") %><%= t("admin.budget_investments.index.table_valuation_finished") %><%= t("admin.budget_investments.index.table_evaluation") %><%= t("admin.budget_investments.index.table_selection") %><%= t("admin.budget_investments.index.list.geozone") %><%= t("admin.budget_investments.index.list.feasibility") %><%= t("admin.budget_investments.index.list.valuation_finished") %><%= t("admin.budget_investments.index.list.visible_to_valuators") %><%= t("admin.budget_investments.index.list.selected") %><%= t("admin.budget_investments.index.table_incompatible") %><%= t("admin.budget_investments.index.list.incompatible") %>
- + From b556fe900026ab8306ad120eaff65c9b9f96cdc6 Mon Sep 17 00:00:00 2001 From: Bertocq Date: Wed, 28 Feb 2018 20:52:18 +0100 Subject: [PATCH 07/29] Create AdminNotification database table --- .../20180221002503_create_admin_notifications.rb | 14 ++++++++++++++ db/schema.rb | 11 +++++++++++ 2 files changed, 25 insertions(+) create mode 100644 db/migrate/20180221002503_create_admin_notifications.rb diff --git a/db/migrate/20180221002503_create_admin_notifications.rb b/db/migrate/20180221002503_create_admin_notifications.rb new file mode 100644 index 000000000..041931495 --- /dev/null +++ b/db/migrate/20180221002503_create_admin_notifications.rb @@ -0,0 +1,14 @@ +class CreateAdminNotifications < ActiveRecord::Migration + def change + create_table :admin_notifications do |t| + t.string :title + t.text :body + t.string :link + t.string :segment_recipient + t.integer :recipients_count + t.date :sent_at, default: nil + + t.timestamps null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 45871b884..878c16869 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -30,6 +30,17 @@ ActiveRecord::Schema.define(version: 20180711224810) do add_index "activities", ["actionable_id", "actionable_type"], name: "index_activities_on_actionable_id_and_actionable_type", using: :btree add_index "activities", ["user_id"], name: "index_activities_on_user_id", using: :btree + create_table "admin_notifications", force: :cascade do |t| + t.string "title" + t.text "body" + t.string "link" + t.string "segment_recipient" + t.integer "recipients_count" + t.date "sent_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "administrators", force: :cascade do |t| t.integer "user_id" end From 45488d117a96ec9ee71674b8a50ab18705da11b5 Mon Sep 17 00:00:00 2001 From: Bertocq Date: Wed, 28 Feb 2018 20:55:08 +0100 Subject: [PATCH 08/29] Create AdminNotification model, spec and factory --- app/models/admin_notification.rb | 44 +++++++++++++ spec/factories.rb | 14 ++++ spec/models/admin_notification_spec.rb | 91 ++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 app/models/admin_notification.rb create mode 100644 spec/models/admin_notification_spec.rb diff --git a/app/models/admin_notification.rb b/app/models/admin_notification.rb new file mode 100644 index 000000000..eccd90910 --- /dev/null +++ b/app/models/admin_notification.rb @@ -0,0 +1,44 @@ +class AdminNotification < ActiveRecord::Base + include Notifiable + + validates :title, presence: true + validates :body, presence: true + validates :segment_recipient, presence: true + validate :validate_segment_recipient + + before_validation :complete_link_url + + def list_of_recipients + UserSegments.send(segment_recipient) if valid_segment_recipient? + end + + def valid_segment_recipient? + segment_recipient && UserSegments.respond_to?(segment_recipient) + end + + def draft? + sent_at.nil? + end + + def list_of_recipients_count + list_of_recipients.try(:count) || 0 + end + + def deliver + list_of_recipients.each { |user| Notification.add(user, self) } + self.update(sent_at: Time.current, recipients_count: list_of_recipients.count) + end + + private + + def validate_segment_recipient + errors.add(:segment_recipient, :invalid) unless valid_segment_recipient? + end + + def complete_link_url + return unless link.present? + unless self.link[/\Ahttp:\/\//] || self.link[/\Ahttps:\/\//] + self.link = "http://#{self.link}" + end + end +end diff --git a/spec/factories.rb b/spec/factories.rb index 77deec79a..beb64aa2d 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -1003,6 +1003,20 @@ LOREM_IPSUM sequence(:body) { |n| "Body #{n}" } end + factory :admin_notification do + title { |n| "Admin Notification title #{n}" } + body { |n| "Admin Notification body #{n}" } + link nil + segment_recipient UserSegments::SEGMENTS.sample + recipients_count nil + sent_at nil + + trait :sent do + recipients_count 1 + sent_at Time.current + end + end + factory :widget_card, class: 'Widget::Card' do sequence(:title) { |n| "Title #{n}" } sequence(:description) { |n| "Description #{n}" } diff --git a/spec/models/admin_notification_spec.rb b/spec/models/admin_notification_spec.rb new file mode 100644 index 000000000..eeb974e83 --- /dev/null +++ b/spec/models/admin_notification_spec.rb @@ -0,0 +1,91 @@ +require 'rails_helper' + +describe AdminNotification do + let(:admin_notification) { build(:admin_notification) } + + it "is valid" do + expect(admin_notification).to be_valid + end + + it 'is not valid without a title' do + admin_notification.title = nil + expect(admin_notification).not_to be_valid + end + + it 'is not valid without a body' do + admin_notification.body = nil + expect(admin_notification).not_to be_valid + end + + it 'is not valid without a segment_recipient' do + admin_notification.segment_recipient = nil + expect(admin_notification).not_to be_valid + end + + describe '#complete_link_url' do + it 'does not change link if there is no value' do + expect(admin_notification.link).to be_nil + end + + it 'fixes a link without http://' do + admin_notification.link = 'lol.consul.dev' + + expect(admin_notification).to be_valid + expect(admin_notification.link).to eq('http://lol.consul.dev') + end + + it 'fixes a link with wwww. but without http://' do + admin_notification.link = 'www.lol.consul.dev' + + expect(admin_notification).to be_valid + expect(admin_notification.link).to eq('http://www.lol.consul.dev') + end + + it 'does not modify a link with http://' do + admin_notification.link = 'http://lol.consul.dev' + + expect(admin_notification).to be_valid + expect(admin_notification.link).to eq('http://lol.consul.dev') + end + + it 'does not modify a link with https://' do + admin_notification.link = 'https://lol.consul.dev' + + expect(admin_notification).to be_valid + expect(admin_notification.link).to eq('https://lol.consul.dev') + end + + it 'does not modify a link with http://wwww.' do + admin_notification.link = 'http://www.lol.consul.dev' + + expect(admin_notification).to be_valid + expect(admin_notification.link).to eq('http://www.lol.consul.dev') + end + end + + describe '#valid_segment_recipient?' do + it 'is false when segment_recipient value is invalid' do + admin_notification.update(segment_recipient: 'invalid_segment_name') + error = 'The user recipients segment is invalid' + + expect(admin_notification).not_to be_valid + expect(admin_notification.errors.messages[:segment_recipient]).to include(error) + end + end + + describe '#list_of_recipients' do + let(:erased_user) { create(:user, username: 'erased_user') } + + before do + 2.times { create(:user) } + erased_user.erase + admin_notification.update(segment_recipient: 'all_users') + end + + it 'returns list of all active users' do + expect(admin_notification.list_of_recipients.count).to eq(2) + expect(admin_notification.list_of_recipients).not_to include(erased_user) + end + end + +end From a10169bac0351730d2088c3650d61bce3269bdc0 Mon Sep 17 00:00:00 2001 From: Bertocq Date: Wed, 28 Feb 2018 20:56:11 +0100 Subject: [PATCH 09/29] Add specs for Admin AdminNotification management --- .../admin/admin_notifications_spec.rb | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 spec/features/admin/admin_notifications_spec.rb diff --git a/spec/features/admin/admin_notifications_spec.rb b/spec/features/admin/admin_notifications_spec.rb new file mode 100644 index 000000000..b994cf9f6 --- /dev/null +++ b/spec/features/admin/admin_notifications_spec.rb @@ -0,0 +1,238 @@ +require 'rails_helper' + +feature "Admin Notifications" do + + background do + admin = create(:administrator) + login_as(admin.user) + create(:budget) + end + + context "Show" do + scenario "Valid Admin Notification" do + notification = create(:admin_notification, title: 'Notification title', + body: 'Notification body', + link: 'https://www.decide.madrid.es/vota', + segment_recipient: :all_users) + + visit admin_admin_notification_path(notification) + + expect(page).to have_content('Notification title') + expect(page).to have_content('Notification body') + expect(page).to have_content('https://www.decide.madrid.es/vota') + expect(page).to have_content('All users') + end + + scenario "Notification with invalid segment recipient" do + invalid_notification = create(:admin_notification) + invalid_notification.update_attribute(:segment_recipient, 'invalid_segment') + + visit admin_admin_notification_path(invalid_notification) + + expect(page).to have_content("Recipients user segment is invalid") + end + end + + context "Index" do + scenario "Valid Admin Notifications" do + draft = create(:admin_notification, segment_recipient: :all_users, title: 'Not yet sent') + sent = create(:admin_notification, :sent, segment_recipient: :administrators, + title: 'Sent one') + + visit admin_admin_notifications_path + + expect(page).to have_css(".admin_notification", count: 2) + + within("#admin_notification_#{draft.id}") do + expect(page).to have_content('Not yet sent') + expect(page).to have_content('All users') + expect(page).to have_content('Draft') + end + + within("#admin_notification_#{sent.id}") do + expect(page).to have_content('Sent one') + expect(page).to have_content('Administrators') + expect(page).to have_content(I18n.l(Date.current)) + end + end + + scenario "Notifications with invalid segment recipient" do + invalid_notification = create(:admin_notification) + invalid_notification.update_attribute(:segment_recipient, 'invalid_segment') + + visit admin_admin_notifications_path + + expect(page).to have_content("Recipients user segment is invalid") + end + end + + scenario "Create" do + visit admin_admin_notifications_path + click_link "New notification" + + fill_in_admin_notification_form(segment_recipient: 'Proposal authors', + title: 'This is a title', + body: 'This is a body', + link: 'http://www.dummylink.dev') + + click_button "Create Admin notification" + + expect(page).to have_content "Notification created successfully" + expect(page).to have_content "Proposal authors" + expect(page).to have_content "This is a title" + expect(page).to have_content "This is a body" + expect(page).to have_content "http://www.dummylink.dev" + end + + context "Update" do + scenario "A draft notification can be updated" do + notification = create(:admin_notification) + + visit admin_admin_notifications_path + within("#admin_notification_#{notification.id}") do + click_link "Edit" + end + + + fill_in_admin_notification_form(segment_recipient: 'All users', + title: 'Other title', + body: 'Other body', + link: '') + + click_button "Update Admin notification" + + expect(page).to have_content "Notification updated successfully" + expect(page).to have_content "All users" + expect(page).to have_content "Other title" + expect(page).to have_content "Other body" + expect(page).not_to have_content "http://www.dummylink.dev" + end + + scenario "Sent notification can not be updated" do + notification = create(:admin_notification, :sent) + + visit admin_admin_notifications_path + within("#admin_notification_#{notification.id}") do + expect(page).not_to have_link("Edit") + end + end + end + + context "Destroy" do + scenario "A draft notification can be destroyed" do + notification = create(:admin_notification) + + visit admin_admin_notifications_path + within("#admin_notification_#{notification.id}") do + click_link "Delete" + end + + expect(page).to have_content "Notification deleted successfully" + expect(page).to have_css(".notification", count: 0) + end + + scenario "Sent notification can not be destroyed" do + notification = create(:admin_notification, :sent) + + visit admin_admin_notifications_path + within("#admin_notification_#{notification.id}") do + expect(page).not_to have_link("Delete") + end + end + end + + context "Visualize" do + scenario "A draft notification can be previewed" do + notification = create(:admin_notification, segment_recipient: :administrators) + + visit admin_admin_notifications_path + within("#admin_notification_#{notification.id}") do + click_link "Preview" + end + + expect(page).to have_content "This is how the users will see the notification:" + expect(page).to have_content "Administrators (1 users will be notified)" + end + + scenario "A sent notification can be viewed" do + notification = create(:admin_notification, :sent, recipients_count: 7, + segment_recipient: :administrators) + + visit admin_admin_notifications_path + within("#admin_notification_#{notification.id}") do + click_link "View" + end + + expect(page).to have_content "This is how the users see the notification:" + expect(page).to have_content "Administrators (7 users got notified)" + end + end + + scenario 'Errors on create' do + visit new_admin_admin_notification_path + + click_button "Create Admin notification" + + expect(page).to have_content error_message + end + + scenario "Errors on update" do + notification = create(:admin_notification) + visit edit_admin_admin_notification_path(notification) + + fill_in :admin_notification_title, with: '' + click_button "Update Admin notification" + + expect(page).to have_content error_message + end + + context "Send notification", :js do + scenario "A draft Admin notification can be sent", :js do + 2.times { create(:user) } + notification = create(:admin_notification, segment_recipient: :all_users) + total_users = notification.list_of_recipients.count + confirm_message = "Are you sure you want to send this notification to #{total_users} users?" + + visit admin_admin_notification_path(notification) + + click_link "Send" + + page.accept_confirm(confirm_message) + + expect(page).to have_content "Notification sent successfully" + + User.all.each do |user| + expect(user.notifications.count).to eq(1) + end + end + + scenario "A sent Admin notification can not be sent", :js do + notification = create(:admin_notification, :sent) + + visit admin_admin_notification_path(notification) + + expect(page).not_to have_link("Send") + end + + scenario "Admin notification with invalid segment recipient cannot be sent", :js do + invalid_notification = create(:admin_notification) + invalid_notification.update_attribute(:segment_recipient, 'invalid_segment') + visit admin_admin_notification_path(invalid_notification) + + expect(page).not_to have_link("Send") + end + end + + scenario "Select list of users to send notification" do + UserSegments::SEGMENTS.each do |user_segment| + segment_recipient = I18n.t("admin.segment_recipient.#{user_segment}") + + visit new_admin_admin_notification_path + + fill_in_admin_notification_form(segment_recipient: segment_recipient) + click_button "Create Admin notification" + + expect(page).to have_content(I18n.t("admin.segment_recipient.#{user_segment}")) + end + end +end From a683fcff98ed2f21449b277619544cbeb199b56c Mon Sep 17 00:00:00 2001 From: Bertocq Date: Wed, 28 Feb 2018 20:57:39 +0100 Subject: [PATCH 10/29] Refactor notification partials and index view The notification body has been extracted to a new partial to allow notifications without link to be rendered without needing an if-else duplicating view code. Note the `link_to_if` at _notification partial, as well as the optional body attribute. --- .../notifications/_notification.html.erb | 26 ++++++------------- .../notifications/_notification_body.html.erb | 17 ++++++++++++ app/views/notifications/index.html.erb | 4 ++- 3 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 app/views/notifications/_notification_body.html.erb diff --git a/app/views/notifications/_notification.html.erb b/app/views/notifications/_notification.html.erb index 2d8b115e5..34f1b96b1 100644 --- a/app/views/notifications/_notification.html.erb +++ b/app/views/notifications/_notification.html.erb @@ -1,21 +1,11 @@ -
  • "> - - <% if notification.notifiable_available? %> - <%= link_to notification do %> -

    - - <%= t("notifications.notification.action.#{notification.notifiable_action}", - count: notification.counter) %> - - - <%= notification.notifiable_title %> - -

    - -

    - <%= l notification.timestamp, format: :datetime %> -

    - <% end %> +
  • + <% if notification.try(:notifiable_available?) %> + <% locals = { notification: notification, + timestamp: notification.timestamp, + title: notification.notifiable_title, + body: notification.notifiable.try(:body) } %> + <% link_text = render partial: '/notifications/notification_body', locals: locals %> + <%= link_to_if notification.link.present?, link_text, notification.link %> <% else %>

    diff --git a/app/views/notifications/_notification_body.html.erb b/app/views/notifications/_notification_body.html.erb new file mode 100644 index 000000000..d6ed86673 --- /dev/null +++ b/app/views/notifications/_notification_body.html.erb @@ -0,0 +1,17 @@ +

    + <% if notification && notification.notifiable_action %> + + <%= t("notifications.notification.action.#{notification.notifiable_action}", + count: notification.counter) %> + + <% end %> + + <%= title %> + + <% if body %> +

    <%= body %>

    + <% end %> +

    +

    + <%= l(timestamp, format: :datetime) %> +

    diff --git a/app/views/notifications/index.html.erb b/app/views/notifications/index.html.erb index eccd3ec6a..e005aad88 100644 --- a/app/views/notifications/index.html.erb +++ b/app/views/notifications/index.html.erb @@ -24,7 +24,9 @@ <% else %>
      - <%= render @notifications %> + <% @notifications.each do |notification| %> + <%= render partial: '/notifications/notification', locals: {notification: notification} %> + <% end %>
    <% end %> From 4a5235f96fb2cc59fa4c81e0ddbd702ca2b7b960 Mon Sep 17 00:00:00 2001 From: Bertocq Date: Wed, 28 Feb 2018 21:00:45 +0100 Subject: [PATCH 11/29] Allow notifications with explicit/unexistent links Notifications usually link to the associated notifiable, but the new AdminNotifications have a link attribute that may be empty or contain an external or internal url. --- app/controllers/notifications_controller.rb | 6 +++++- app/models/notification.rb | 12 +++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index 588f2ed6b..ee6878502 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -44,7 +44,11 @@ class NotificationsController < ApplicationController when "Topic" community_topic_path @notification.linkable_resource.community, @notification.linkable_resource else - url_for @notification.linkable_resource + if @notification.linkable_resource.is_a?(AdminNotification) + @notification.linkable_resource.link || notifications_path + else + url_for @notification.linkable_resource + end end end diff --git a/app/models/notification.rb b/app/models/notification.rb index 33bf7701c..dacedb762 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -53,9 +53,19 @@ class Notification < ActiveRecord::Base "proposal_notification" when "Comment" "replies_to" + when "AdminNotification" + nil else "comments_on" end end -end \ No newline at end of file + def link + if notifiable.is_a?(AdminNotification) && notifiable.link.blank? + nil + else + self + end + end + +end From f695a7faf39b72118477a591c9400fb5941e2d65 Mon Sep 17 00:00:00 2001 From: Bertocq Date: Wed, 28 Feb 2018 21:03:24 +0100 Subject: [PATCH 12/29] Add AdminNotification management at admin panel In the same fashion Newsletters is managed, with the only difference that the preview is using the notification partial in the same way the index of notifications. --- app/assets/javascripts/application.js | 2 + .../send_admin_notification_alert.js.coffee | 4 + .../admin/admin_notifications_controller.rb | 67 ++++++++++++++++ app/views/admin/_menu.html.erb | 18 +++-- .../admin/admin_notifications/_form.html.erb | 13 ++++ .../admin/admin_notifications/edit.html.erb | 4 + .../admin/admin_notifications/index.html.erb | 56 ++++++++++++++ .../admin/admin_notifications/new.html.erb | 4 + .../admin/admin_notifications/show.html.erb | 77 +++++++++++++++++++ config/routes/admin.rb | 6 ++ 10 files changed, 243 insertions(+), 8 deletions(-) create mode 100644 app/assets/javascripts/send_admin_notification_alert.js.coffee create mode 100644 app/controllers/admin/admin_notifications_controller.rb create mode 100644 app/views/admin/admin_notifications/_form.html.erb create mode 100644 app/views/admin/admin_notifications/edit.html.erb create mode 100644 app/views/admin/admin_notifications/index.html.erb create mode 100644 app/views/admin/admin_notifications/new.html.erb create mode 100644 app/views/admin/admin_notifications/show.html.erb diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index a9e44d249..44258bc7a 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -79,6 +79,7 @@ //= require send_newsletter_alert //= require managers //= require globalize +//= require send_admin_notification_alert var initialize_modules = function() { App.Comments.initialize(); @@ -124,6 +125,7 @@ var initialize_modules = function() { App.SendNewsletterAlert.initialize(); App.Managers.initialize(); App.Globalize.initialize(); + App.SendAdminNotificationAlert.initialize(); }; $(function(){ diff --git a/app/assets/javascripts/send_admin_notification_alert.js.coffee b/app/assets/javascripts/send_admin_notification_alert.js.coffee new file mode 100644 index 000000000..8c1c928e5 --- /dev/null +++ b/app/assets/javascripts/send_admin_notification_alert.js.coffee @@ -0,0 +1,4 @@ +App.SendAdminNotificationAlert = + initialize: -> + $('#js-send-admin_notification-alert').on 'click', -> + confirm(this.dataset.alert); diff --git a/app/controllers/admin/admin_notifications_controller.rb b/app/controllers/admin/admin_notifications_controller.rb new file mode 100644 index 000000000..1dd03038a --- /dev/null +++ b/app/controllers/admin/admin_notifications_controller.rb @@ -0,0 +1,67 @@ +class Admin::AdminNotificationsController < Admin::BaseController + + def index + @admin_notifications = AdminNotification.all + end + + def show + @admin_notification = AdminNotification.find(params[:id]) + end + + def new + @admin_notification = AdminNotification.new + end + + def create + @admin_notification = AdminNotification.new(admin_notification_params) + + if @admin_notification.save + notice = t("admin.admin_notifications.create_success") + redirect_to [:admin, @admin_notification], notice: notice + else + render :new + end + end + + def edit + @admin_notification = AdminNotification.find(params[:id]) + end + + def update + @admin_notification = AdminNotification.find(params[:id]) + + if @admin_notification.update(admin_notification_params) + notice = t("admin.admin_notifications.update_success") + redirect_to [:admin, @admin_notification], notice: notice + else + render :edit + end + end + + def destroy + @admin_notification = AdminNotification.find(params[:id]) + @admin_notification.destroy + + notice = t("admin.admin_notifications.delete_success") + redirect_to admin_admin_notifications_path, notice: notice + end + + def deliver + @admin_notification = AdminNotification.find(params[:id]) + + if @admin_notification.valid? + @admin_notification.deliver + flash[:notice] = t("admin.admin_notifications.send_success") + else + flash[:error] = t("admin.segment_recipient.invalid_recipients_segment") + end + + redirect_to [:admin, @admin_notification] + end + + private + + def admin_notification_params + params.require(:admin_notification).permit(:title, :body, :link, :segment_recipient) + end +end diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index b830acb46..e5af32cc4 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -79,18 +79,21 @@
  • <% end %> - <% messages_sections = %w(newsletters emails_download) %> - <% messages_menu_active = messages_sections.include?(controller_name) %> -
  • > + <% newsletters_notifications_sections = %w(newsletters emails_download admin_notifications) %> + <% newsletters_menu_active = newsletters_notifications_sections.include?(controller_name) %> +
  • > - <%= t("admin.menu.emails") %> + <%= t("admin.menu.newsletters_and_notifications") %> -
      > -
    • > +
        > +
      • > <%= link_to t("admin.menu.newsletters"), admin_newsletters_path %>
      • -
      • > +
      • > + <%= link_to t("admin.menu.admin_notifications"), admin_admin_notifications_path %> +
      • +
      • > <%= link_to t("admin.menu.emails_download"), admin_emails_download_index_path %>
      @@ -231,7 +234,6 @@
    • > <%= link_to t("admin.menu.site_customization.content_blocks"), admin_site_customization_content_blocks_path%>
    • -
  • diff --git a/app/views/admin/admin_notifications/_form.html.erb b/app/views/admin/admin_notifications/_form.html.erb new file mode 100644 index 000000000..4053bb66d --- /dev/null +++ b/app/views/admin/admin_notifications/_form.html.erb @@ -0,0 +1,13 @@ +<%= form_for [:admin, @admin_notification] do |f| %> + <%= render 'shared/errors', resource: @admin_notification %> + + <%= f.select :segment_recipient, options_for_select(user_segments_options, + @admin_notification[:segment_recipient]) %> + <%= f.text_field :title %> + <%= f.text_field :link %> + <%= f.text_area :body %> + +
    + <%= f.submit class: "button success" %> +
    +<% end %> diff --git a/app/views/admin/admin_notifications/edit.html.erb b/app/views/admin/admin_notifications/edit.html.erb new file mode 100644 index 000000000..cb14f0a0b --- /dev/null +++ b/app/views/admin/admin_notifications/edit.html.erb @@ -0,0 +1,4 @@ +<%= back_link_to %> +

    <%= t("admin.admin_notifications.edit.section_title") %>

    + +<%= render "form" %> diff --git a/app/views/admin/admin_notifications/index.html.erb b/app/views/admin/admin_notifications/index.html.erb new file mode 100644 index 000000000..d16ee476e --- /dev/null +++ b/app/views/admin/admin_notifications/index.html.erb @@ -0,0 +1,56 @@ +

    <%= t("admin.admin_notifications.index.section_title") %>

    +<%= link_to t("admin.admin_notifications.index.new_notification"), new_admin_admin_notification_path, + class: "button float-right" %> + +<% if @admin_notifications.any? %> +
    <%= t("admin.budget_investments.index.index.list.id") %><%= t("admin.budget_investments.index.list.id") %> <%= t("admin.budget_investments.index.list.title") %> <%= t("admin.budget_investments.index.list.supports") %> <%= t("admin.budget_investments.index.list.admin") %>
    + + + + + + + + + + <% @admin_notifications.order(created_at: :desc).each do |admin_notification| %> + + + + + + + <% end %> + +
    <%= t("admin.admin_notifications.index.title") %><%= t("admin.admin_notifications.index.segment_recipient") %><%= t("admin.admin_notifications.index.sent") %><%= t("admin.admin_notifications.index.actions") %>
    + <%= admin_notification.title %> + + <%= segment_name(admin_notification.segment_recipient) %> + + <% if admin_notification.draft? %> + <%= t("admin.admin_notifications.index.draft") %> + <% else %> + <%= l admin_notification.sent_at.to_date %> + <% end %> + + <% if admin_notification.draft? %> + <%= link_to t("admin.admin_notifications.index.edit"), + edit_admin_admin_notification_path(admin_notification), + method: :get, class: "button hollow" %> + <%= link_to t("admin.admin_notifications.index.delete"), + admin_admin_notification_path(admin_notification), + method: :delete, class: "button hollow alert" %> + <%= link_to t("admin.admin_notifications.index.preview"), + admin_admin_notification_path(admin_notification), + class: "button" %> + <% else %> + <%= link_to t("admin.admin_notifications.index.view"), + admin_admin_notification_path(admin_notification), + class: "button" %> + <% end %> +
    +<% else %> +
    + <%= t("admin.admin_notifications.index.empty_notifications") %> +
    +<% end %> diff --git a/app/views/admin/admin_notifications/new.html.erb b/app/views/admin/admin_notifications/new.html.erb new file mode 100644 index 000000000..69bf2a80b --- /dev/null +++ b/app/views/admin/admin_notifications/new.html.erb @@ -0,0 +1,4 @@ +<%= back_link_to %> +

    <%= t("admin.admin_notifications.new.section_title") %>

    + +<%= render "form" %> diff --git a/app/views/admin/admin_notifications/show.html.erb b/app/views/admin/admin_notifications/show.html.erb new file mode 100644 index 000000000..92c0e37fc --- /dev/null +++ b/app/views/admin/admin_notifications/show.html.erb @@ -0,0 +1,77 @@ +<%= back_link_to admin_admin_notifications_path %> + +

    <%= t("admin.admin_notifications.show.section_title") %>

    + +
    +
    +
    +
    + <%= t("admin.admin_notifications.show.sent_at") %>
    + <% if @admin_notification.draft? %> + <%= t("admin.admin_notifications.index.draft") %> + <% else %> + <%= l(@admin_notification.sent_at.to_date) %> + <% end %> +
    +
    + <%= t("admin.admin_notifications.show.title") %>
    + <%= @admin_notification.title %> +
    +
    +
    + +
    + <%= t("admin.admin_notifications.show.body") %>
    + <%= @admin_notification.body %> +
    +
    + <%= t("admin.admin_notifications.show.link") %>
    + <%= @admin_notification.link %> +
    +
    +
    +
    + <%= t("admin.admin_notifications.show.segment_recipient") %>
    + <%= segment_name(@admin_notification.segment_recipient) %> + <% if @admin_notification.draft? %> + <%= t("admin.admin_notifications.show.will_get_notified", + n: @admin_notification.list_of_recipients_count) %> + <% else %> + <%= t("admin.admin_notifications.show.got_notified", + n: @admin_notification.recipients_count) %> + <% end %> +
    +
    +
    + +

    + <% if @admin_notification.draft? %> + <%= t("admin.admin_notifications.show.preview_guide") %> + <% else %> + <%= t("admin.admin_notifications.show.sent_guide") %> + <% end %> +

    +
    +
    +
      +
    • + <% locals = { notification: nil, + title: @admin_notification.title, + body: @admin_notification.body, + timestamp: Time.current } %> + <% link_text = render partial: '/notifications/notification_body', locals: locals %> + <%= link_to_if @admin_notification.link.present?, link_text, @admin_notification.link %> +
    • +
    +
    +
    +
    +<% if @admin_notification.draft? && @admin_notification.valid_segment_recipient? %> + <%= link_to t("admin.admin_notifications.show.send"), + deliver_admin_admin_notification_path(@admin_notification), + "data-alert": t("admin.admin_notifications.show.send_alert", + n: @admin_notification.list_of_recipients_count), + method: :post, + id: "js-send-admin_notification-alert", + class: "button success" %> +<% end %> diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 001456f6e..ec7e4bb5f 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -159,6 +159,12 @@ namespace :admin do get :users, on: :collection end + resources :admin_notifications do + member do + post :deliver + end + end + resources :emails_download, only: :index do get :generate_csv, on: :collection end From e010f95485e60faabc2c669946ef86495090c89d Mon Sep 17 00:00:00 2001 From: Bertocq Date: Wed, 28 Feb 2018 21:05:02 +0100 Subject: [PATCH 13/29] Increase notifications spec with AdminNotification scenarios --- spec/features/notifications_spec.rb | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/spec/features/notifications_spec.rb b/spec/features/notifications_spec.rb index 58aebb472..f8e77ac0d 100644 --- a/spec/features/notifications_spec.rb +++ b/spec/features/notifications_spec.rb @@ -128,4 +128,50 @@ feature "Notifications" do expect(page).to_not have_css("#notifications") end + context "Admin Notifications" do + let(:admin_notification) do + create(:admin_notification, title: 'Notification title', + body: 'Notification body', + link: 'https://www.external.link.dev/', + segment_recipient: 'all_users') + end + + let!(:notification) do + create(:notification, user: user, notifiable: admin_notification) + end + + before do + login_as user + end + + scenario "With external link" do + visit notifications_path + expect(page).to have_content('Notification title') + expect(page).to have_content('Notification body') + + first("#notification_#{notification.id} a").click + expect(page.current_url).to eq('https://www.external.link.dev/') + end + + scenario "With internal link" do + admin_notification.update_attributes(link: '/stats') + + visit notifications_path + expect(page).to have_content('Notification title') + expect(page).to have_content('Notification body') + + first("#notification_#{notification.id} a").click + expect(page).to have_current_path('/stats') + end + + scenario "Without a link" do + admin_notification.update_attributes(link: '/stats') + + visit notifications_path + expect(page).to have_content('Notification title') + expect(page).to have_content('Notification body') + expect(page).not_to have_link(notification_path(notification), visible: false) + end + end + end From 2aa4b5cad611e5dce1ec179ed52cc9edf72117cf Mon Sep 17 00:00:00 2001 From: Bertocq Date: Wed, 28 Feb 2018 21:05:22 +0100 Subject: [PATCH 14/29] Add AdminNotification seed data --- db/dev_seeds.rb | 1 + db/dev_seeds/admin_notifications.rb | 36 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 db/dev_seeds/admin_notifications.rb diff --git a/db/dev_seeds.rb b/db/dev_seeds.rb index 966307e10..7b7af9342 100644 --- a/db/dev_seeds.rb +++ b/db/dev_seeds.rb @@ -34,5 +34,6 @@ require_relative 'dev_seeds/legislation_processes' require_relative 'dev_seeds/newsletters' require_relative 'dev_seeds/notifications' require_relative 'dev_seeds/widgets' +require_relative 'dev_seeds/admin_notifications' log "All dev seeds created successfuly 👍" diff --git a/db/dev_seeds/admin_notifications.rb b/db/dev_seeds/admin_notifications.rb new file mode 100644 index 000000000..2e87c6db1 --- /dev/null +++ b/db/dev_seeds/admin_notifications.rb @@ -0,0 +1,36 @@ +section "Creating Admin Notifications & Templates" do + AdminNotification.create!( + title: 'New usage Terms & Conditions!', + segment_recipient: 'administrators', + body: 'We have improved our usage terms & conditions! please check them out to be up to date.', + link: 'http://localhost:3000/condiciones-de-uso' + ).deliver + + AdminNotification.create!( + title: 'Help us translate consul 🤓', + segment_recipient: 'administrators', + body: 'If you are proficient in a language, please help us translate consul!.', + link: 'https://crwd.in/consul' + ).deliver + + AdminNotification.create!( + title: 'You can now geolocate proposals & investments', + segment_recipient: 'administrators', + body: 'When you create a proposal or investment you now can specify a point on a map 🗺' + ).deliver + + AdminNotification.create!( + title: 'We just opened a new Participatory Budget!', + segment_recipient: 'administrators', + link: 'https://www.decide.madrid.es/presupuestos2018/1', + body: 'Start creating proposals for budget investments!' + ).deliver + + AdminNotification.create!( + title: 'We are closing the 2018 Participatory Budget!!', + segment_recipient: 'administrators', + link: 'https://www.decide.madrid.es/presupuestos2018/1', + body: 'Hurry up and create a last proposal before it ends next in two days!', + sent_at: nil + ) +end From 812002dd7be5e6e46b599e66340300abc9ffb97c Mon Sep 17 00:00:00 2001 From: Bertocq Date: Wed, 28 Feb 2018 21:05:34 +0100 Subject: [PATCH 15/29] Add admin notification related translations --- config/locales/en/activerecord.yml | 4 ++++ config/locales/en/admin.yml | 38 +++++++++++++++++++++++++++++- config/locales/es/activerecord.yml | 4 ++++ config/locales/es/admin.yml | 38 +++++++++++++++++++++++++++++- 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 8e44f6ea9..d3d19f1ed 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -283,6 +283,10 @@ en: attributes: segment_recipient: invalid: "The user recipients segment is invalid" + admin_notification: + attributes: + segment_recipient: + invalid: "The user recipients segment is invalid" map_location: attributes: map: diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 48ee46db6..b8468967a 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -516,8 +516,9 @@ en: administrators: Administrators managers: Managers moderators: Moderators - emails: Sending of emails + newsletters_and_notifications: Newsletters & Notifications newsletters: Newsletters + admin_notifications: Notifications emails_download: Emails download valuators: Valuators poll_officers: Poll officers @@ -611,6 +612,41 @@ en: body: Email content body_help_text: This is how the users will see the email send_alert: Are you sure you want to send this newsletter to %{n} users? + admin_notifications: + create_success: Notification created successfully + update_success: Notification updated successfully + send_success: Notification sent successfully + delete_success: Notification deleted successfully + index: + section_title: Notifications + new_notification: New notification + title: Title + segment_recipient: Recipients + sent: Sent + actions: Actions + draft: Draft + edit: Edit + delete: Delete + preview: Preview + view: View + empty_notifications: There are no notifications to show + new: + section_title: New notification + edit: + section_title: Edit notification + show: + section_title: Notification preview + send: Send + will_get_notified: (%{n} users will be notified) + got_notified: (%{n} users got notified) + sent_at: Sent at + title: Title + body: Text + link: Link + segment_recipient: Recipients + preview_guide: "This is how the users will see the notification:" + sent_guide: "This is how the users see the notification:" + send_alert: Are you sure you want to send this notification to %{n} users? emails_download: index: title: Emails download diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 2da027031..52bb51e9f 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -283,6 +283,10 @@ es: attributes: segment_recipient: invalid: "El segmento de usuarios es inválido" + admin_notification: + attributes: + segment_recipient: + invalid: "El segmento de usuarios es inválido" map_location: attributes: map: diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 8929f9e3b..e64657aee 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -517,8 +517,9 @@ es: administrators: Administradores managers: Gestores moderators: Moderadores - emails: Envío de emails + newsletters_and_notifications: Newsletters & Notificaciones newsletters: Newsletters + admin_notifications: Notificaciones emails_download: Descarga de emails valuators: Evaluadores poll_officers: Presidentes de mesa @@ -612,6 +613,41 @@ es: body: Contenido del email body_help_text: Así es como verán el email los usuarios send_alert: ¿Estás seguro/a de que quieres enviar esta newsletter a %{n} usuarios? + admin_notifications: + create_success: Notificación creada correctamente + update_success: Notificación actualizada correctamente + send_success: Notificación enviada correctamente + delete_success: Notificación borrada correctamente + index: + section_title: Envío de notificaciones + new_notification: Crear notificación + title: Título + segment_recipient: Destinatarios + sent: Enviado + actions: Acciones + draft: Borrador + edit: Editar + delete: Borrar + preview: Previsualizar + view: Visualizar + empty_notifications: No hay notificaciones para mostrar + new: + section_title: Nueva notificación + edit: + section_title: Editar notificación + show: + section_title: Vista previa de notificación + send: Enviar + will_get_notified: (%{n} usuarios serán notificados) + got_notified: (%{n} usuarios fueron notificados) + sent_at: Enviado + title: Título + body: Texto + link: Enlace + segment_recipient: Destinatarios + preview_guide: "Así es como los usuarios verán la notificación:" + sent_guide: "Así es como los usuarios ven la notificación:" + send_alert: ¿Estás seguro/a de que quieres enviar esta notificación a %{n} usuarios? emails_download: index: title: Descarga de emails From a883e842babcf7293e2886034c074dafacde1845 Mon Sep 17 00:00:00 2001 From: Bertocq Date: Fri, 6 Apr 2018 11:27:49 +0200 Subject: [PATCH 16/29] Make admin notifications seed data translatable --- config/locales/en/seeds.yml | 15 +++++++++++++ config/locales/es/seeds.yml | 15 +++++++++++++ db/dev_seeds/admin_notifications.rb | 34 +++++++++++------------------ 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/config/locales/en/seeds.yml b/config/locales/en/seeds.yml index 4e40cfd63..a3587c9e3 100644 --- a/config/locales/en/seeds.yml +++ b/config/locales/en/seeds.yml @@ -53,3 +53,18 @@ en: recounting_poll: "Recounting Poll" expired_poll_without_stats: "Expired Poll without Stats & Results" expired_poll_with_stats: "Expired Poll with Stats & Results" + admin_notifications: + internal_link: + title: 'Do you have a proposal?' + body: 'Remember you can create a proposal with your ideas and people will discuss & support it.' + link: '/proposals' + external_link: + title: Help us translate consul + body: 'If you are proficient in a language, please help us translate consul!.' + link: 'https://crwd.in/consul' + without_link: + title: 'You can now geolocate proposals & investments' + body: 'When you create a proposal or investment you now can specify a point on a map' + not_sent: + title: 'We are closing the Participatory Budget!!' + body: 'Hurry up and create a last proposal before it ends next in few days!' diff --git a/config/locales/es/seeds.yml b/config/locales/es/seeds.yml index 1d6563bef..d8a40471b 100644 --- a/config/locales/es/seeds.yml +++ b/config/locales/es/seeds.yml @@ -53,3 +53,18 @@ es: recounting_poll: "Votación en Recuento" expired_poll_without_stats: "Votación Finalizada (sin Estadísticas o Resultados)" expired_poll_with_stats: "Votación Finalizada (con Estadísticas y Resultado)" + admin_notifications: + internal_link: + title: 'Tienes una propuesta?' + body: 'Recuerda que puedes crear propuestas y los ciudadanos las debatirán y apoyarán.' + link: '/proposals' + external_link: + title: 'Ayúdanos a traducir CONSUL' + body: 'Si dominas un idioma, ayúdanos a completar su traducción en CONSUL.' + link: 'https://crwd.in/consul' + without_link: + title: 'Ahora puedes geolocalizar propuestas y proyectos de inversión' + body: 'Cuando crees una propuesta o proyecto de inversión podrás especificar su localización en el mapa' + not_sent: + title: 'Últimos días para crear proyectos de Presupuestos Participativos' + body: 'Quedan pocos dias para que se cierre el plazo de presentación de proyectos de inversión para los presupuestos participativos!' diff --git a/db/dev_seeds/admin_notifications.rb b/db/dev_seeds/admin_notifications.rb index 2e87c6db1..a07077790 100644 --- a/db/dev_seeds/admin_notifications.rb +++ b/db/dev_seeds/admin_notifications.rb @@ -1,36 +1,28 @@ section "Creating Admin Notifications & Templates" do AdminNotification.create!( - title: 'New usage Terms & Conditions!', - segment_recipient: 'administrators', - body: 'We have improved our usage terms & conditions! please check them out to be up to date.', - link: 'http://localhost:3000/condiciones-de-uso' + title: I18n.t('seeds.admin_notification.internal_link.title'), + body: I18n.t('seeds.admin_notification.internal_link.body'), + link: Setting['url'] + I18n.t('seeds.admin_notification.internal_link.link'), + segment_recipient: 'administrators' ).deliver AdminNotification.create!( - title: 'Help us translate consul 🤓', - segment_recipient: 'administrators', - body: 'If you are proficient in a language, please help us translate consul!.', - link: 'https://crwd.in/consul' + title: I18n.t('seeds.admin_notification.external_link.title'), + body: I18n.t('seeds.admin_notification.external_link.body'), + link: I18n.t('seeds.admin_notification.external_link.link'), + segment_recipient: 'administrators' ).deliver AdminNotification.create!( - title: 'You can now geolocate proposals & investments', - segment_recipient: 'administrators', - body: 'When you create a proposal or investment you now can specify a point on a map 🗺' + title: I18n.t('seeds.admin_notification.without_link.title'), + body: I18n.t('seeds.admin_notification.without_link.body'), + segment_recipient: 'administrators' ).deliver AdminNotification.create!( - title: 'We just opened a new Participatory Budget!', + title: I18n.t('seeds.admin_notification.not_sent.title'), + body: I18n.t('seeds.admin_notification.not_sent.body'), segment_recipient: 'administrators', - link: 'https://www.decide.madrid.es/presupuestos2018/1', - body: 'Start creating proposals for budget investments!' - ).deliver - - AdminNotification.create!( - title: 'We are closing the 2018 Participatory Budget!!', - segment_recipient: 'administrators', - link: 'https://www.decide.madrid.es/presupuestos2018/1', - body: 'Hurry up and create a last proposal before it ends next in two days!', sent_at: nil ) end From bbf3faa783964f327f27ad45428f56c9946df326 Mon Sep 17 00:00:00 2001 From: decabeza Date: Wed, 25 Jul 2018 19:12:48 +0200 Subject: [PATCH 17/29] Fixes admin notifications specs --- spec/features/admin/admin_notifications_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/features/admin/admin_notifications_spec.rb b/spec/features/admin/admin_notifications_spec.rb index b994cf9f6..a97170e7c 100644 --- a/spec/features/admin/admin_notifications_spec.rb +++ b/spec/features/admin/admin_notifications_spec.rb @@ -195,9 +195,7 @@ feature "Admin Notifications" do visit admin_admin_notification_path(notification) - click_link "Send" - - page.accept_confirm(confirm_message) + accept_confirm { click_link "Send" } expect(page).to have_content "Notification sent successfully" From 8b6a8703e0bd753417e19b739be67da186f4ed25 Mon Sep 17 00:00:00 2001 From: decabeza Date: Wed, 25 Jul 2018 19:13:31 +0200 Subject: [PATCH 18/29] Adds missing fill_in_admin_notification_form in common actions --- spec/support/common_actions/notifications.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spec/support/common_actions/notifications.rb b/spec/support/common_actions/notifications.rb index 4ae98c3d0..e387ce1fd 100644 --- a/spec/support/common_actions/notifications.rb +++ b/spec/support/common_actions/notifications.rb @@ -53,4 +53,11 @@ module Notifications field_check_message = 'Please check the marked fields to know how to correct them:' /\d errors? prevented this #{resource_model} from being saved. #{field_check_message}/ end + + def fill_in_admin_notification_form(options = {}) + select (options[:segment_recipient] || 'All users'), from: :admin_notification_segment_recipient + fill_in :admin_notification_title, with: (options[:title] || 'This is the notification title') + fill_in :admin_notification_body, with: (options[:body] || 'This is the notification body') + fill_in :admin_notification_link, with: (options[:link] || 'https://www.decide.madrid.es/vota') + end end From 3fd97b0a9b313dbe3c668008f89e30192d0ab3d1 Mon Sep 17 00:00:00 2001 From: Bertocq Date: Thu, 12 Apr 2018 11:21:15 +0200 Subject: [PATCH 19/29] Rename Newsletter & Notification to User Messages We're increasing the features around messaging users, menu name has to be generic enough. --- app/views/admin/_menu.html.erb | 16 ++++++++-------- config/locales/en/admin.yml | 2 +- config/locales/es/admin.yml | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index e5af32cc4..e1d6cc0de 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -79,21 +79,21 @@ <% end %> - <% newsletters_notifications_sections = %w(newsletters emails_download admin_notifications) %> - <% newsletters_menu_active = newsletters_notifications_sections.include?(controller_name) %> -
  • > + <% messages_sections = %w(newsletters emails_download admin_notifications) %> + <% messages_menu_active = messages_sections.include?(controller_name) %> +
  • > - <%= t("admin.menu.newsletters_and_notifications") %> + <%= t("admin.menu.messaging_users") %> -