Merge branch 'master' into backport-2588-fix_supports_filter
This commit is contained in:
@@ -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(){
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
App.SendAdminNotificationAlert =
|
||||
initialize: ->
|
||||
$('#js-send-admin_notification-alert').on 'click', ->
|
||||
confirm(this.dataset.alert);
|
||||
67
app/controllers/admin/admin_notifications_controller.rb
Normal file
67
app/controllers/admin/admin_notifications_controller.rb
Normal 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
|
||||
@@ -75,17 +75,9 @@ class Admin::BudgetInvestmentsController < Admin::BaseController
|
||||
resource_model.parameterize('_')
|
||||
end
|
||||
|
||||
def sort_by(params)
|
||||
if params.present? && Budget::Investment::SORTING_OPTIONS.include?(params)
|
||||
"#{params == 'supports' ? 'cached_votes_up' : params} ASC"
|
||||
else
|
||||
"cached_votes_up DESC, created_at DESC"
|
||||
end
|
||||
end
|
||||
|
||||
def load_investments
|
||||
@investments = Budget::Investment.scoped_filter(params, @current_filter)
|
||||
.order(sort_by(params[:sort_by]))
|
||||
@investments = @investments.order_filter(params[:sort_by]) if params[:sort_by].present?
|
||||
@investments = @investments.page(params[:page]) unless request.format.csv?
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Admin::SignatureSheetsController < Admin::BaseController
|
||||
|
||||
def index
|
||||
@signature_sheets = SignatureSheet.all
|
||||
@signature_sheets = SignatureSheet.all.order(created_at: :desc)
|
||||
end
|
||||
|
||||
def new
|
||||
@@ -29,4 +29,4 @@ class Admin::SignatureSheetsController < Admin::BaseController
|
||||
params.require(:signature_sheet).permit(:signable_type, :signable_id, :document_numbers)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
37
app/controllers/admin/system_emails_controller.rb
Normal file
37
app/controllers/admin/system_emails_controller.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
class Admin::SystemEmailsController < Admin::BaseController
|
||||
|
||||
before_action :load_system_email, only: [:view, :preview_pending]
|
||||
|
||||
def index
|
||||
@system_emails = {
|
||||
proposal_notification_digest: %w(view preview_pending)
|
||||
}
|
||||
end
|
||||
|
||||
def view
|
||||
case @system_email
|
||||
when "proposal_notification_digest"
|
||||
@notifications = Notification.where(notifiable_type: "ProposalNotification").limit(2)
|
||||
@subject = t('mailers.proposal_notification_digest.title', org_name: Setting['org_name'])
|
||||
end
|
||||
end
|
||||
|
||||
def preview_pending
|
||||
case @system_email
|
||||
when "proposal_notification_digest"
|
||||
@previews = ProposalNotification.where(id: unsent_proposal_notifications_ids)
|
||||
.page(params[:page])
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_system_email
|
||||
@system_email = params[:system_email_id]
|
||||
end
|
||||
|
||||
def unsent_proposal_notifications_ids
|
||||
Notification.where(notifiable_type: "ProposalNotification", emailed_at: nil)
|
||||
.group(:notifiable_id).count.keys
|
||||
end
|
||||
end
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -50,8 +50,7 @@ module Abilities
|
||||
can :manage, Annotation
|
||||
|
||||
can [:read, :update, :valuate, :destroy, :summary], SpendingProposal
|
||||
|
||||
can [:index, :read, :new, :create, :update, :destroy, :calculate_winners, :read_results], Budget
|
||||
can [:index, :read, :new, :create, :update, :destroy, :calculate_winners], Budget
|
||||
can [:read, :create, :update, :destroy], Budget::Group
|
||||
can [:read, :create, :update, :destroy], Budget::Heading
|
||||
can [:hide, :update, :toggle_selection], Budget::Investment
|
||||
|
||||
44
app/models/admin_notification.rb
Normal file
44
app/models/admin_notification.rb
Normal 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
|
||||
@@ -57,6 +57,10 @@ class Budget
|
||||
scope :sort_by_price, -> { reorder(price: :desc, confidence_score: :desc, id: :desc) }
|
||||
scope :sort_by_random, ->(seed) { reorder("budget_investments.id % #{seed.to_f.nonzero? ? seed.to_f : 1}, budget_investments.id") }
|
||||
|
||||
scope :sort_by_id, -> { order("id DESC") }
|
||||
scope :sort_by_title, -> { order("title ASC") }
|
||||
scope :sort_by_supports, -> { order("cached_votes_up DESC") }
|
||||
|
||||
scope :valuation_open, -> { where(valuation_finished: false) }
|
||||
scope :without_admin, -> { valuation_open.where(administrator_id: nil) }
|
||||
scope :without_valuator, -> { valuation_open.where(valuator_assignments_count: 0) }
|
||||
@@ -133,6 +137,24 @@ class Budget
|
||||
results.where("budget_investments.id IN (?)", ids)
|
||||
end
|
||||
|
||||
def self.order_filter(sorting_param)
|
||||
if sorting_param.present? && SORTING_OPTIONS.include?(sorting_param)
|
||||
send("sort_by_#{sorting_param}")
|
||||
end
|
||||
end
|
||||
|
||||
def self.limit_results(budget, params, results)
|
||||
max_per_heading = params[:max_per_heading].to_i
|
||||
return results if max_per_heading <= 0
|
||||
|
||||
ids = []
|
||||
budget.headings.pluck(:id).each do |hid|
|
||||
ids += Investment.where(heading_id: hid).order(confidence_score: :desc).limit(max_per_heading).pluck(:id)
|
||||
end
|
||||
|
||||
results.where("budget_investments.id IN (?)", ids)
|
||||
end
|
||||
|
||||
def self.search_by_title_or_id(title_or_id, results)
|
||||
if title_or_id =~ /^[0-9]+$/
|
||||
results.where(id: title_or_id)
|
||||
|
||||
@@ -16,16 +16,18 @@ 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"),
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -79,17 +79,23 @@
|
||||
</li>
|
||||
<% end %>
|
||||
|
||||
<% messages_sections = %w(newsletters emails_download) %>
|
||||
<% messages_sections = %w(newsletters emails_download admin_notifications system_emails) %>
|
||||
<% messages_menu_active = messages_sections.include?(controller_name) %>
|
||||
<li class="section-title" <%= "class=is-active" if messages_menu_active %>>
|
||||
<a href="#">
|
||||
<span class="icon-zip"></span>
|
||||
<strong><%= t("admin.menu.emails") %></strong>
|
||||
<strong><%= t("admin.menu.messaging_users") %></strong>
|
||||
</a>
|
||||
<ul <%= "class=is-active" if messages_menu_active %>>
|
||||
<ul id="messaging_users_menu" <%= "class=is-active" if messages_menu_active %>>
|
||||
<li <%= "class=is-active" if controller_name == "newsletters" %>>
|
||||
<%= link_to t("admin.menu.newsletters"), admin_newsletters_path %>
|
||||
</li>
|
||||
<li <%= "class=is-active" if controller_name == "admin_notifications" %>>
|
||||
<%= link_to t("admin.menu.admin_notifications"), admin_admin_notifications_path %>
|
||||
</li>
|
||||
<li <%= "class=is-active" if controller_name == "system_emails" %>>
|
||||
<%= link_to t("admin.menu.system_emails"), admin_system_emails_path %>
|
||||
</li>
|
||||
<li <%= "class=is-active" if controller_name == "emails_download" %>>
|
||||
<%= link_to t("admin.menu.emails_download"), admin_emails_download_index_path %>
|
||||
</li>
|
||||
@@ -231,7 +237,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>
|
||||
|
||||
@@ -33,12 +33,18 @@
|
||||
<%= activity.actionable.username %> (<%= activity.actionable.email %>)
|
||||
<% when "Comment" %>
|
||||
<%= activity.actionable.body %>
|
||||
<% when "Newsletter" %>
|
||||
<strong><%= activity.actionable.subject %></strong>
|
||||
<br>
|
||||
<%= activity.actionable.body %>
|
||||
<% when "ProposalNotification" %>
|
||||
<strong><%= activity.actionable.title %></strong>
|
||||
<br>
|
||||
<%= activity.actionable.body %>
|
||||
<% else %>
|
||||
<strong><%= activity.actionable.title %></strong>
|
||||
<br>
|
||||
<div class="proposal-description">
|
||||
<%= activity.actionable.description %>
|
||||
</div>
|
||||
<%= activity.actionable.description %>
|
||||
<% end %>
|
||||
<td class="align-top">
|
||||
<%= activity.user.name %> (<%= activity.user.email %>)
|
||||
|
||||
13
app/views/admin/admin_notifications/_form.html.erb
Normal file
13
app/views/admin/admin_notifications/_form.html.erb
Normal 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 %>
|
||||
4
app/views/admin/admin_notifications/edit.html.erb
Normal file
4
app/views/admin/admin_notifications/edit.html.erb
Normal file
@@ -0,0 +1,4 @@
|
||||
<%= back_link_to %>
|
||||
<h2><%= t("admin.admin_notifications.edit.section_title") %></h2>
|
||||
|
||||
<%= render "form" %>
|
||||
56
app/views/admin/admin_notifications/index.html.erb
Normal file
56
app/views/admin/admin_notifications/index.html.erb
Normal 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 %>
|
||||
4
app/views/admin/admin_notifications/new.html.erb
Normal file
4
app/views/admin/admin_notifications/new.html.erb
Normal file
@@ -0,0 +1,4 @@
|
||||
<%= back_link_to %>
|
||||
<h2><%= t("admin.admin_notifications.new.section_title") %></h2>
|
||||
|
||||
<%= render "form" %>
|
||||
77
app/views/admin/admin_notifications/show.html.erb
Normal file
77
app/views/admin/admin_notifications/show.html.erb
Normal 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 %>
|
||||
@@ -35,21 +35,21 @@
|
||||
<table class="table-for-mobile">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.budget_investments.index.table_id") %></th>
|
||||
<th class="small-3"><%= t("admin.budget_investments.index.table_title") %></th>
|
||||
<th><%= t("admin.budget_investments.index.table_supports") %></th>
|
||||
<th><%= t("admin.budget_investments.index.table_admin") %></th>
|
||||
<th><%= t("admin.budget_investments.index.list.id") %></th>
|
||||
<th class="small-3"><%= t("admin.budget_investments.index.list.title") %></th>
|
||||
<th><%= t("admin.budget_investments.index.list.supports") %></th>
|
||||
<th><%= t("admin.budget_investments.index.list.admin") %></th>
|
||||
<th>
|
||||
<%= 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") %>
|
||||
</th>
|
||||
<th><%= t("admin.budget_investments.index.table_geozone") %></th>
|
||||
<th><%= t("admin.budget_investments.index.table_feasibility") %></th>
|
||||
<th class="text-center"><%= t("admin.budget_investments.index.table_valuation_finished") %></th>
|
||||
<th class="text-center"><%= t("admin.budget_investments.index.table_evaluation") %></th>
|
||||
<th class="text-center"><%= t("admin.budget_investments.index.table_selection") %></th>
|
||||
<th><%= t("admin.budget_investments.index.list.geozone") %></th>
|
||||
<th><%= t("admin.budget_investments.index.list.feasibility") %></th>
|
||||
<th class="text-center"><%= t("admin.budget_investments.index.list.valuation_finished") %></th>
|
||||
<th class="text-center"><%= t("admin.budget_investments.index.list.visible_to_valuators") %></th>
|
||||
<th class="text-center"><%= t("admin.budget_investments.index.list.selected") %></th>
|
||||
<% if params[:filter] == "selected" %>
|
||||
<th class="text-center"><%= t("admin.budget_investments.index.table_incompatible") %></th>
|
||||
<th class="text-center"><%= t("admin.budget_investments.index.list.incompatible") %></th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<%= signature_sheet.author.name %>
|
||||
</td>
|
||||
<td>
|
||||
<%= l(signature_sheet.created_at, format: :short) %>
|
||||
<%= l(signature_sheet.created_at, format: :long) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<div class="callout secondary float-right">
|
||||
<%= t("admin.signature_sheets.show.created_at") %>
|
||||
<strong><%= l(@signature_sheet.created_at, format: :short) %></strong>
|
||||
<strong><%= l(@signature_sheet.created_at, format: :long) %></strong>
|
||||
<span class="bullet"> • </span>
|
||||
<%= t("admin.signature_sheets.show.author") %>
|
||||
<strong><%= @signature_sheet.author.name %></strong>
|
||||
@@ -41,4 +41,4 @@
|
||||
<div class="callout primary margin-top">
|
||||
<%= t("admin.signature_sheets.show.loading") %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
34
app/views/admin/system_emails/index.html.erb
Normal file
34
app/views/admin/system_emails/index.html.erb
Normal file
@@ -0,0 +1,34 @@
|
||||
<h2 class="inline-block"><%= t("admin.menu.system_emails") %></h2>
|
||||
|
||||
<table id="system_emails">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.shared.title") %></th>
|
||||
<th><%= t("admin.shared.description") %></th>
|
||||
<th class="small-5 text-right"><%= t("admin.shared.actions") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @system_emails.each do |system_email_title, system_email_actions| %>
|
||||
<tr id="<%= system_email_title %>" class="system_email">
|
||||
<td>
|
||||
<%= t("admin.system_emails.#{system_email_title}.title") %>
|
||||
</td>
|
||||
<td>
|
||||
<%= t("admin.system_emails.#{system_email_title}.description") %>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<% if system_email_actions.include?('view') %>
|
||||
<%= link_to t("admin.shared.view"), admin_system_email_view_path(system_email_title),
|
||||
class: "button hollow" %>
|
||||
<% end %>
|
||||
<% if system_email_actions.include?('preview_pending') %>
|
||||
<%= link_to t("admin.system_emails.preview_pending.action"),
|
||||
admin_system_email_preview_pending_path(system_email_title),
|
||||
class: "button" %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
16
app/views/admin/system_emails/preview_pending.html.erb
Normal file
16
app/views/admin/system_emails/preview_pending.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
<%= back_link_to admin_system_emails_path %>
|
||||
|
||||
<% system_email_name = t("admin.system_emails.#{@system_email}.title") %>
|
||||
<h2><%= t("admin.system_emails.preview_pending.preview_of", name: system_email_name) %></h2>
|
||||
|
||||
<div class="small-12 column">
|
||||
<h4><%= t("admin.system_emails.preview_pending.pending_to_be_sent") %></h4>
|
||||
<p><%= t("admin.system_emails.#{@system_email}.preview_detail") %></p>
|
||||
|
||||
<% @previews.each do |preview| %>
|
||||
<%= render partial: "admin/system_emails/preview_pending/#{@system_email}",
|
||||
locals: { preview: preview } %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= paginate @previews %>
|
||||
@@ -0,0 +1,33 @@
|
||||
<% if preview.proposal.present? %>
|
||||
<div class="callout highlight">
|
||||
<div class="row">
|
||||
<div class="small-12 medium-6 column">
|
||||
<strong><%= t("admin.shared.proposal") %></strong><br>
|
||||
<%= link_to preview.proposal.title, proposal_url(preview.proposal) %>
|
||||
</div>
|
||||
<div class="small-12 medium-6 column">
|
||||
<strong><%= t("admin.shared.title") %></strong><br>
|
||||
<%= link_to preview.title, proposal_url(preview.proposal, anchor: "tab-notifications") %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="small-12 medium-6 column">
|
||||
<strong><%= t("admin.shared.author") %></strong><br>
|
||||
<%= preview.proposal.author&.username || '-' %>
|
||||
</div>
|
||||
<div class="small-12 medium-6 column">
|
||||
<strong><%= t("admin.shared.created_at") %></strong><br>
|
||||
<%= l(preview.created_at, format: :datetime) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="column">
|
||||
<strong><%= t("admin.shared.content") %></strong>
|
||||
<p class="help-text" id="phase-description-help-text">
|
||||
<%= preview.body %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
36
app/views/admin/system_emails/view.html.erb
Normal file
36
app/views/admin/system_emails/view.html.erb
Normal file
@@ -0,0 +1,36 @@
|
||||
<%= back_link_to admin_system_emails_path %>
|
||||
|
||||
<h2><%= t("admin.system_emails.#{@system_email}.title") %></h2>
|
||||
|
||||
<div class="small-12 column">
|
||||
<div class="callout highlight">
|
||||
<div class="row">
|
||||
<div class="small-12 medium-4 column">
|
||||
<strong><%= t("admin.newsletters.show.from") %></strong><br>
|
||||
<%= Setting['mailer_from_address'] %>
|
||||
</div>
|
||||
<div class="small-12 medium-8 column">
|
||||
<strong><%= t("admin.newsletters.show.subject") %></strong><br>
|
||||
<%= @subject %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<strong><%= t("admin.newsletters.show.body") %></strong>
|
||||
<p class="help-text" id="phase-description-help-text">
|
||||
<%= t("admin.newsletters.show.body_help_text") %>
|
||||
</p>
|
||||
<div class="newsletter-body-content">
|
||||
<%= render file: "app/views/layouts/_mailer_header.html.erb" %>
|
||||
|
||||
<table cellpadding="0" cellspacing="0" border="0" style="background: #fff; margin: 0 auto; max-width: 700px; width:100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<%= render file: "app/views/mailer/#{@system_email}.html.erb" %>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= render file: "app/views/layouts/_mailer_footer.html.erb" %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -36,7 +36,7 @@
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if @budget.finished? || (@budget.balloting? && can?(:read_results, @budget)) %>
|
||||
<% if @budget.finished? %>
|
||||
<%= link_to t("budgets.show.see_results"),
|
||||
budget_results_path(@budget, heading_id: @budget.headings.first),
|
||||
class: "button margin-top expanded" %>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<tr>
|
||||
<td style="padding-bottom: 20px; padding-left: 10px;">
|
||||
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 20px;font-weight: bold;line-height: 24px; margin: 0;">
|
||||
<%= link_to notification.notifiable.title, notification_url(notification), style: "color: #2895F1; text-decoration: none;" %>
|
||||
<%= link_to notification.notifiable.title, proposal_url(notification.notifiable.proposal, anchor: "tab-notifications"), style: "color: #2895F1; text-decoration: none;" %>
|
||||
</p>
|
||||
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;font-weight: normal;line-height: 24px; margin-top: 0; color: #cccccc;">
|
||||
<%= notification.notifiable.proposal.title %> •
|
||||
|
||||
@@ -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.notifiable.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>
|
||||
|
||||
17
app/views/notifications/_notification_body.html.erb
Normal file
17
app/views/notifications/_notification_body.html.erb
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -186,18 +186,20 @@ 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
|
||||
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"
|
||||
show:
|
||||
@@ -516,8 +518,10 @@ en:
|
||||
administrators: Administrators
|
||||
managers: Managers
|
||||
moderators: Moderators
|
||||
emails: Sending of emails
|
||||
messaging_users: Messages to users
|
||||
newsletters: Newsletters
|
||||
admin_notifications: Notifications
|
||||
system_emails: System Emails
|
||||
emails_download: Emails download
|
||||
valuators: Valuators
|
||||
poll_officers: Poll officers
|
||||
@@ -611,6 +615,50 @@ 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?
|
||||
system_emails:
|
||||
preview_pending:
|
||||
action: Preview Pending
|
||||
preview_of: Preview of %{name}
|
||||
pending_to_be_sent: This is the content pending to be sent
|
||||
proposal_notification_digest:
|
||||
title: Proposal Notification Digest
|
||||
description: Gathers all proposal notifications for an user in a single message, to avoid too much emails.
|
||||
preview_detail: Users will only recieve notifications from the proposals they are following
|
||||
emails_download:
|
||||
index:
|
||||
title: Emails download
|
||||
@@ -1007,6 +1055,11 @@ en:
|
||||
image: Image
|
||||
show_image: Show image
|
||||
moderated_content: "Check the content moderated by the moderators, and confirm if the moderation has been done correctly."
|
||||
view: View
|
||||
proposal: Proposal
|
||||
author: Author
|
||||
content: Content
|
||||
created_at: Created at
|
||||
spending_proposals:
|
||||
index:
|
||||
geozone_filter_all: All zones
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -187,18 +187,20 @@ 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
|
||||
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"
|
||||
show:
|
||||
@@ -517,8 +519,10 @@ es:
|
||||
administrators: Administradores
|
||||
managers: Gestores
|
||||
moderators: Moderadores
|
||||
emails: Envío de emails
|
||||
messaging_users: Mensajes a usuarios
|
||||
newsletters: Newsletters
|
||||
admin_notifications: Notificaciones
|
||||
system_emails: Emails del sistema
|
||||
emails_download: Descarga de emails
|
||||
valuators: Evaluadores
|
||||
poll_officers: Presidentes de mesa
|
||||
@@ -612,6 +616,50 @@ 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?
|
||||
system_emails:
|
||||
preview_pending:
|
||||
action: Previsualizar Pendientes
|
||||
preview_of: Vista previa de %{name}
|
||||
pending_to_be_sent: Este es todo el contenido pendiente de enviar
|
||||
proposal_notification_digest:
|
||||
title: Resumen de Notificationes de Propuestas
|
||||
description: Reune todas las notificaciones de propuestas en un único mensaje, para evitar demasiados emails.
|
||||
preview_detail: Los usuarios sólo recibirán las notificaciones de aquellas propuestas que siguen.
|
||||
emails_download:
|
||||
index:
|
||||
title: Descarga de emails
|
||||
@@ -1008,6 +1056,11 @@ es:
|
||||
image: Imagen
|
||||
show_image: Mostrar imagen
|
||||
moderated_content: "Revisa el contenido moderado por los moderadores, y confirma si la moderación se ha realizado correctamente."
|
||||
view: Ver
|
||||
proposal: Propuesta
|
||||
author: Autor
|
||||
content: Contenido
|
||||
created_at: Fecha de creación
|
||||
spending_proposals:
|
||||
index:
|
||||
geozone_filter_all: Todos los ámbitos de actuación
|
||||
|
||||
@@ -159,6 +159,17 @@ namespace :admin do
|
||||
get :users, on: :collection
|
||||
end
|
||||
|
||||
resources :admin_notifications do
|
||||
member do
|
||||
post :deliver
|
||||
end
|
||||
end
|
||||
|
||||
resources :system_emails, only: [:index] do
|
||||
get :view
|
||||
get :preview_pending
|
||||
end
|
||||
|
||||
resources :emails_download, only: :index do
|
||||
get :generate_csv, on: :collection
|
||||
end
|
||||
|
||||
@@ -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 👍"
|
||||
|
||||
28
db/dev_seeds/admin_notifications.rb
Normal file
28
db/dev_seeds/admin_notifications.rb
Normal 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
|
||||
14
db/migrate/20180221002503_create_admin_notifications.rb
Normal file
14
db/migrate/20180221002503_create_admin_notifications.rb
Normal 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
|
||||
11
db/schema.rb
11
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
|
||||
|
||||
@@ -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}" }
|
||||
|
||||
236
spec/features/admin/admin_notifications_spec.rb
Normal file
236
spec/features/admin/admin_notifications_spec.rb
Normal 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
|
||||
@@ -589,8 +589,8 @@ feature 'Admin budget investments' do
|
||||
scenario 'Sort by ID' do
|
||||
visit admin_budget_budget_investments_path(budget, sort_by: 'id')
|
||||
|
||||
expect('B First Investment').to appear_before('A Second Investment')
|
||||
expect('A Second Investment').to appear_before('C Third Investment')
|
||||
expect('C Third Investment').to appear_before('A Second Investment')
|
||||
expect('A Second Investment').to appear_before('B First Investment')
|
||||
end
|
||||
|
||||
scenario 'Sort by title' do
|
||||
@@ -603,8 +603,8 @@ feature 'Admin budget investments' do
|
||||
scenario 'Sort by supports' do
|
||||
visit admin_budget_budget_investments_path(budget, sort_by: 'supports')
|
||||
|
||||
expect('C Third Investment').to appear_before('A Second Investment')
|
||||
expect('A Second Investment').to appear_before('B First Investment')
|
||||
expect('B First Investment').to appear_before('A Second Investment')
|
||||
expect('A Second Investment').to appear_before('C Third Investment')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1192,13 +1192,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)
|
||||
|
||||
@@ -1209,10 +1211,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
|
||||
|
||||
|
||||
@@ -7,15 +7,28 @@ feature 'Signature sheets' do
|
||||
login_as(admin.user)
|
||||
end
|
||||
|
||||
scenario "Index" do
|
||||
3.times { create(:signature_sheet) }
|
||||
context "Index" do
|
||||
scenario 'Lists all signature_sheets' do
|
||||
3.times { create(:signature_sheet) }
|
||||
|
||||
visit admin_signature_sheets_path
|
||||
visit admin_signature_sheets_path
|
||||
|
||||
expect(page).to have_css(".signature_sheet", count: 3)
|
||||
expect(page).to have_css(".signature_sheet", count: 3)
|
||||
|
||||
SignatureSheet.all.each do |signature_sheet|
|
||||
expect(page).to have_content signature_sheet.name
|
||||
SignatureSheet.all.each do |signature_sheet|
|
||||
expect(page).to have_content signature_sheet.name
|
||||
end
|
||||
end
|
||||
|
||||
scenario 'Orders signature_sheets by created_at DESC' do
|
||||
signature_sheet1 = create(:signature_sheet)
|
||||
signature_sheet2 = create(:signature_sheet)
|
||||
signature_sheet3 = create(:signature_sheet)
|
||||
|
||||
visit admin_signature_sheets_path
|
||||
|
||||
expect(signature_sheet3.name).to appear_before(signature_sheet2.name)
|
||||
expect(signature_sheet2.name).to appear_before(signature_sheet1.name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -78,7 +91,7 @@ feature 'Signature sheets' do
|
||||
|
||||
expect(page).to have_content "Citizen proposal #{proposal.id}"
|
||||
expect(page).to have_content "12345678Z, 123A, 123B"
|
||||
expect(page).to have_content signature_sheet.created_at.strftime("%d %b %H:%M")
|
||||
expect(page).to have_content signature_sheet.created_at.strftime("%B %d, %Y %H:%M")
|
||||
expect(page).to have_content user.name
|
||||
|
||||
within("#document_count") do
|
||||
|
||||
70
spec/features/admin/system_emails_spec.rb
Normal file
70
spec/features/admin/system_emails_spec.rb
Normal file
@@ -0,0 +1,70 @@
|
||||
require 'rails_helper'
|
||||
|
||||
feature "System Emails" do
|
||||
|
||||
background do
|
||||
admin = create(:administrator)
|
||||
login_as(admin.user)
|
||||
end
|
||||
|
||||
context "Index" do
|
||||
scenario "Lists all system emails with correct actions" do
|
||||
visit admin_system_emails_path
|
||||
|
||||
within('#proposal_notification_digest') do
|
||||
expect(page).to have_link('View')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "View" do
|
||||
scenario "#proposal_notification_digest" do
|
||||
proposal_a = create(:proposal, title: 'Proposal A')
|
||||
proposal_b = create(:proposal, title: 'Proposal B')
|
||||
proposal_notification_a = create(:proposal_notification, proposal: proposal_a,
|
||||
title: 'Proposal A Title',
|
||||
body: 'Proposal A Notification Body')
|
||||
proposal_notification_b = create(:proposal_notification, proposal: proposal_b,
|
||||
title: 'Proposal B Title',
|
||||
body: 'Proposal B Notification Body')
|
||||
create(:notification, notifiable: proposal_notification_a)
|
||||
create(:notification, notifiable: proposal_notification_b)
|
||||
|
||||
visit admin_system_email_view_path('proposal_notification_digest')
|
||||
|
||||
expect(page).to have_content('Proposal notifications in')
|
||||
expect(page).to have_link('Proposal A Title', href: proposal_url(proposal_a,
|
||||
anchor: 'tab-notifications'))
|
||||
expect(page).to have_link('Proposal B Title', href: proposal_url(proposal_b,
|
||||
anchor: 'tab-notifications'))
|
||||
expect(page).to have_content('Proposal A Notification Body')
|
||||
expect(page).to have_content('Proposal B Notification Body')
|
||||
end
|
||||
end
|
||||
|
||||
context "Preview Pending" do
|
||||
scenario "#proposal_notification_digest" do
|
||||
proposal_a = create(:proposal, title: 'Proposal A')
|
||||
proposal_b = create(:proposal, title: 'Proposal B')
|
||||
proposal_notification_a = create(:proposal_notification, proposal: proposal_a,
|
||||
title: 'Proposal A Title',
|
||||
body: 'Proposal A Notification Body')
|
||||
proposal_notification_b = create(:proposal_notification, proposal: proposal_b,
|
||||
title: 'Proposal B Title',
|
||||
body: 'Proposal B Notification Body')
|
||||
create(:notification, notifiable: proposal_notification_a, emailed_at: nil)
|
||||
create(:notification, notifiable: proposal_notification_b, emailed_at: nil)
|
||||
|
||||
visit admin_system_email_preview_pending_path('proposal_notification_digest')
|
||||
|
||||
expect(page).to have_content('This is the content pending to be sent')
|
||||
expect(page).to have_link('Proposal A', href: proposal_url(proposal_a))
|
||||
expect(page).to have_link('Proposal B', href: proposal_url(proposal_b))
|
||||
expect(page).to have_link('Proposal A Title', href: proposal_url(proposal_a,
|
||||
anchor: 'tab-notifications'))
|
||||
expect(page).to have_link('Proposal B Title', href: proposal_url(proposal_b,
|
||||
anchor: 'tab-notifications'))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -379,6 +379,58 @@ feature 'Budgets' do
|
||||
expect(page).to have_link "See investments not selected for balloting phase"
|
||||
end
|
||||
|
||||
scenario "Take into account headings with the same name from a different budget" do
|
||||
group1 = create(:budget_group, budget: budget, name: "New York")
|
||||
heading1 = create(:budget_heading, group: group1, name: "Brooklyn")
|
||||
heading2 = create(:budget_heading, group: group1, name: "Queens")
|
||||
|
||||
budget2 = create(:budget)
|
||||
group2 = create(:budget_group, budget: budget2, name: "New York")
|
||||
heading3 = create(:budget_heading, group: group2, name: "Brooklyn")
|
||||
heading4 = create(:budget_heading, group: group2, name: "Queens")
|
||||
|
||||
visit budget_path(budget)
|
||||
click_link "New York"
|
||||
|
||||
expect(page).to have_css("#budget_heading_#{heading1.id}")
|
||||
expect(page).to have_css("#budget_heading_#{heading2.id}")
|
||||
|
||||
expect(page).to_not have_css("#budget_heading_#{heading3.id}")
|
||||
expect(page).to_not have_css("#budget_heading_#{heading4.id}")
|
||||
end
|
||||
|
||||
scenario "See results button is showed if the budget has finished for all users" do
|
||||
user = create(:user)
|
||||
admin = create(:administrator)
|
||||
budget = create(:budget, :finished)
|
||||
|
||||
login_as(user)
|
||||
visit budget_path(budget)
|
||||
expect(page).to have_link "See results"
|
||||
|
||||
logout
|
||||
|
||||
login_as(admin.user)
|
||||
visit budget_path(budget)
|
||||
expect(page).to have_link "See results"
|
||||
end
|
||||
|
||||
scenario "See results button isn't showed if the budget hasn't finished for all users" do
|
||||
user = create(:user)
|
||||
admin = create(:administrator)
|
||||
budget = create(:budget, :balloting)
|
||||
|
||||
login_as(user)
|
||||
visit budget_path(budget)
|
||||
expect(page).not_to have_link "See results"
|
||||
|
||||
logout
|
||||
|
||||
login_as(admin.user)
|
||||
visit budget_path(budget)
|
||||
expect(page).not_to have_link "See results"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "In Drafting phase" do
|
||||
|
||||
@@ -1081,6 +1081,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("Local government is not competent in this matter")
|
||||
end
|
||||
|
||||
scenario "Show milestones", :js do
|
||||
user = create(:user)
|
||||
investment = create(:budget_investment)
|
||||
|
||||
@@ -306,14 +306,14 @@ feature 'Emails' do
|
||||
expect(email).to have_body_text(notification1.notifiable.body)
|
||||
expect(email).to have_body_text(proposal1.author.name)
|
||||
|
||||
expect(email).to have_body_text(/#{notification_path(notification1)}/)
|
||||
expect(email).to have_body_text(/#{proposal_path(proposal1, anchor: 'tab-notifications')}/)
|
||||
expect(email).to have_body_text(/#{proposal_path(proposal1, anchor: 'comments')}/)
|
||||
expect(email).to have_body_text(/#{proposal_path(proposal1, anchor: 'social-share')}/)
|
||||
|
||||
expect(email).to have_body_text(proposal2.title)
|
||||
expect(email).to have_body_text(notification2.notifiable.title)
|
||||
expect(email).to have_body_text(notification2.notifiable.body)
|
||||
expect(email).to have_body_text(/#{notification_path(notification2)}/)
|
||||
expect(email).to have_body_text(/#{proposal_path(proposal2, anchor: 'tab-notifications')}/)
|
||||
expect(email).to have_body_text(/#{proposal_path(proposal2, anchor: 'comments')}/)
|
||||
expect(email).to have_body_text(/#{proposal_path(proposal2, anchor: 'social-share')}/)
|
||||
expect(email).to have_body_text(proposal2.author.name)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -128,4 +128,58 @@ feature "Notifications" do
|
||||
expect(page).to_not have_css("#notifications")
|
||||
end
|
||||
|
||||
scenario "Notification's notifiable model no longer includes Notifiable module" do
|
||||
create(:notification, notifiable: create(:spending_proposal), user: user)
|
||||
create(:notification, notifiable: create(:poll_question), user: user)
|
||||
|
||||
click_notifications_icon
|
||||
expect(page).to have_content('This resource is not available anymore.', count: 2)
|
||||
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
|
||||
|
||||
91
spec/models/admin_notification_spec.rb
Normal file
91
spec/models/admin_notification_spec.rb
Normal 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
|
||||
@@ -308,6 +308,30 @@ describe Budget::Investment do
|
||||
end
|
||||
end
|
||||
|
||||
describe "#by_budget" do
|
||||
|
||||
it "returns investments scoped by budget" do
|
||||
budget1 = create(:budget)
|
||||
budget2 = create(:budget)
|
||||
|
||||
group1 = create(:budget_group, budget: budget1)
|
||||
group2 = create(:budget_group, budget: budget2)
|
||||
|
||||
heading1 = create(:budget_heading, group: group1)
|
||||
heading2 = create(:budget_heading, group: group2)
|
||||
|
||||
investment1 = create(:budget_investment, heading: heading1)
|
||||
investment2 = create(:budget_investment, heading: heading1)
|
||||
investment3 = create(:budget_investment, heading: heading2)
|
||||
|
||||
investments_by_budget = Budget::Investment.by_budget(budget1)
|
||||
|
||||
expect(investments_by_budget).to include investment1
|
||||
expect(investments_by_budget).to include investment2
|
||||
expect(investments_by_budget).to_not include investment3
|
||||
end
|
||||
end
|
||||
|
||||
describe "#by_admin" do
|
||||
it "returns investments assigned to specific administrator" do
|
||||
investment1 = create(:budget_investment, administrator_id: 33)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user