Merge pull request #2580 from consul/admin_notifications

Admin notifications
This commit is contained in:
Alberto
2018-07-25 20:05:19 +02:00
committed by GitHub
31 changed files with 891 additions and 31 deletions

View File

@@ -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(){

View File

@@ -0,0 +1,4 @@
App.SendAdminNotificationAlert =
initialize: ->
$('#js-send-admin_notification-alert').on 'click', ->
confirm(this.dataset.alert);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -53,9 +53,19 @@ class Notification < ActiveRecord::Base
"proposal_notification"
when "Comment"
"replies_to"
when "AdminNotification"
nil
else
"comments_on"
end
end
end
def link
if notifiable.is_a?(AdminNotification) && notifiable.link.blank?
nil
else
self
end
end
end

View File

@@ -79,18 +79,21 @@
</li>
<% end %>
<% messages_sections = %w(newsletters emails_download) %>
<% messages_menu_active = messages_sections.include?(controller_name) %>
<li class="section-title" <%= "class=is-active" if messages_menu_active %>>
<% newsletters_notifications_sections = %w(newsletters emails_download admin_notifications) %>
<% newsletters_menu_active = newsletters_notifications_sections.include?(controller_name) %>
<li class="section-title" <%= "class=active" if newsletters_menu_active %>>
<a href="#">
<span class="icon-zip"></span>
<strong><%= t("admin.menu.emails") %></strong>
<strong><%= t("admin.menu.newsletters_and_notifications") %></strong>
</a>
<ul <%= "class=is-active" if messages_menu_active %>>
<li <%= "class=is-active" if controller_name == "newsletters" %>>
<ul id="newsletters_and_notifications_menu" <%= "class=is-active" if newsletters_menu_active %>>
<li <%= "class=active" if controller_name == "newsletters" %>>
<%= link_to t("admin.menu.newsletters"), admin_newsletters_path %>
</li>
<li <%= "class=is-active" if controller_name == "emails_download" %>>
<li <%= "class=active" if controller_name == "admin_notifications" %>>
<%= link_to t("admin.menu.admin_notifications"), admin_admin_notifications_path %>
</li>
<li <%= "class=active" if controller_name == "emails_download" %>>
<%= link_to t("admin.menu.emails_download"), admin_emails_download_index_path %>
</li>
</ul>
@@ -231,7 +234,6 @@
<li <%= "class=is-active" if controller_name == "content_blocks" %>>
<%= link_to t("admin.menu.site_customization.content_blocks"), admin_site_customization_content_blocks_path%>
</li>
</ul>
</li>
</ul>

View File

@@ -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 %>
<div class="margin-top">
<%= f.submit class: "button success" %>
</div>
<% end %>

View File

@@ -0,0 +1,4 @@
<%= back_link_to %>
<h2><%= t("admin.admin_notifications.edit.section_title") %></h2>
<%= render "form" %>

View File

@@ -0,0 +1,56 @@
<h2 class="inline-block"><%= t("admin.admin_notifications.index.section_title") %></h2>
<%= link_to t("admin.admin_notifications.index.new_notification"), new_admin_admin_notification_path,
class: "button float-right" %>
<% if @admin_notifications.any? %>
<table id="admin_notifications">
<thead>
<tr>
<th><%= t("admin.admin_notifications.index.title") %></th>
<th><%= t("admin.admin_notifications.index.segment_recipient") %></th>
<th><%= t("admin.admin_notifications.index.sent") %></th>
<th class="small-5 text-right"><%= t("admin.admin_notifications.index.actions") %></th>
</tr>
</thead>
<tbody>
<% @admin_notifications.order(created_at: :desc).each do |admin_notification| %>
<tr id="<%= dom_id(admin_notification) %>" class="admin_notification">
<td>
<%= admin_notification.title %>
</td>
<td>
<%= segment_name(admin_notification.segment_recipient) %>
</td>
<td>
<% if admin_notification.draft? %>
<%= t("admin.admin_notifications.index.draft") %>
<% else %>
<%= l admin_notification.sent_at.to_date %>
<% end %>
</td>
<td class="text-right">
<% 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 %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<div data-alert class="callout primary margin-top clear">
<%= t("admin.admin_notifications.index.empty_notifications") %>
</div>
<% end %>

View File

@@ -0,0 +1,4 @@
<%= back_link_to %>
<h2><%= t("admin.admin_notifications.new.section_title") %></h2>
<%= render "form" %>

View File

@@ -0,0 +1,77 @@
<%= back_link_to admin_admin_notifications_path %>
<h2><%= t("admin.admin_notifications.show.section_title") %></h2>
<div class="small-12 column">
<div class="callout highlight">
<div class="row">
<div class="small-12 medium-6 column">
<strong><%= t("admin.admin_notifications.show.sent_at") %></strong><br>
<% if @admin_notification.draft? %>
<%= t("admin.admin_notifications.index.draft") %>
<% else %>
<%= l(@admin_notification.sent_at.to_date) %>
<% end %>
</div>
<div class="small-12 medium-6 column">
<strong><%= t("admin.admin_notifications.show.title") %></strong><br>
<%= @admin_notification.title %>
</div>
</div>
<div class="row">
<div class="small-12 medium-6 column">
<strong><%= t("admin.admin_notifications.show.body") %></strong><br>
<%= @admin_notification.body %>
</div>
<div class="small-12 medium-6 column">
<strong><%= t("admin.admin_notifications.show.link") %></strong><br>
<%= @admin_notification.link %>
</div>
</div>
<div class="row">
<div class="small-12 column">
<strong><%= t("admin.admin_notifications.show.segment_recipient") %></strong><br>
<%= 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 %>
</div>
</div>
</div>
<p class="help-text" id="phase-description-help-text">
<% if @admin_notification.draft? %>
<%= t("admin.admin_notifications.show.preview_guide") %>
<% else %>
<%= t("admin.admin_notifications.show.sent_guide") %>
<% end %>
</p>
<hr>
<div class="admin_notification-body-content">
<ul class="no-bullet clear notifications-list">
<li class="notification unread">
<% 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 %>
</li>
</ul>
</div>
<hr>
</div>
<% 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 %>

View File

@@ -1,21 +1,11 @@
<li id="<%= dom_id(notification) %>" class="notification <%= "unread" if notification.unread? %>">
<% if notification.notifiable_available? %>
<%= link_to notification do %>
<p>
<em>
<%= t("notifications.notification.action.#{notification.notifiable_action}",
count: notification.counter) %>
</em>
<strong id="<%= dom_id(notification) %>_title">
<%= notification.notifiable_title %>
</strong>
</p>
<p class="time">
<%= l notification.timestamp, format: :datetime %>
</p>
<% end %>
<li id="<%= dom_id(notification) %>" class="notification <%= 'unread' if notification&.unread? %>">
<% 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 %>
<p>
<strong>

View File

@@ -0,0 +1,17 @@
<p>
<% if notification && notification.notifiable_action %>
<em>
<%= t("notifications.notification.action.#{notification.notifiable_action}",
count: notification.counter) %>
</em>
<% end %>
<strong id="<%= dom_id(notification) if notification %>_title">
<%= title %>
</strong>
<% if body %>
<p><%= body %></p>
<% end %>
</p>
<p class="time">
<%= l(timestamp, format: :datetime) %>
</p>

View File

@@ -24,7 +24,9 @@
</div>
<% else %>
<ul class="no-bullet clear notifications-list">
<%= render @notifications %>
<% @notifications.each do |notification| %>
<%= render partial: '/notifications/notification', locals: {notification: notification} %>
<% end %>
</ul>
<% end %>
</div>

View File

@@ -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:

View File

@@ -518,8 +518,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
@@ -613,6 +614,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

View File

@@ -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!'

View File

@@ -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:

View File

@@ -519,8 +519,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
@@ -614,6 +615,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

View File

@@ -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!'

View File

@@ -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

View File

@@ -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 👍"

View File

@@ -0,0 +1,28 @@
section "Creating Admin Notifications & Templates" do
AdminNotification.create!(
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: 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: I18n.t('seeds.admin_notification.without_link.title'),
body: I18n.t('seeds.admin_notification.without_link.body'),
segment_recipient: 'administrators'
).deliver
AdminNotification.create!(
title: I18n.t('seeds.admin_notification.not_sent.title'),
body: I18n.t('seeds.admin_notification.not_sent.body'),
segment_recipient: 'administrators',
sent_at: nil
)
end

View File

@@ -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

View File

@@ -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

View File

@@ -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}" }

View File

@@ -0,0 +1,236 @@
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)
accept_confirm { click_link "Send" }
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

View File

@@ -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

View File

@@ -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

View File

@@ -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