Merge pull request #2462 from consul/admin-newsletter-emails

Admin newsletter emails
This commit is contained in:
María Checa
2018-02-20 16:17:37 +01:00
committed by GitHub
31 changed files with 791 additions and 39 deletions

View File

@@ -75,6 +75,7 @@
//= require sortable
//= require table_sortable
//= require investment_report_alert
//= require send_newsletter_alert
var initialize_modules = function() {
App.Comments.initialize();
@@ -117,6 +118,7 @@ var initialize_modules = function() {
App.Sortable.initialize();
App.TableSortable.initialize();
App.InvestmentReportAlert.initialize();
App.SendNewsletterAlert.initialize();
};
$(function(){

View File

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

View File

@@ -10,6 +10,7 @@
// 08. CMS
// 09. Map
// 10. Budgets
// 11. Newsletters
//
// 01. Global styles
@@ -1092,3 +1093,24 @@ table {
}
}
}
// 11. Newsletters
// -----------------
.newsletter-body-content {
table,
tbody,
tr,
th,
td {
border: 0;
&:nth-child(even),
&:nth-child(even) td:last-child,
&:nth-child(odd) td:last-child,
&:hover {
background: none;
}
}
}

View File

@@ -1,6 +1,47 @@
class Admin::NewslettersController < Admin::BaseController
def index
@newsletters = Newsletter.all
end
def show
@newsletter = Newsletter.find(params[:id])
end
def new
@newsletter = Newsletter.new
end
def create
@newsletter = Newsletter.new(newsletter_params)
if @newsletter.save
notice = t("admin.newsletters.create_success")
redirect_to [:admin, @newsletter], notice: notice
else
render :new
end
end
def edit
@newsletter = Newsletter.find(params[:id])
end
def update
@newsletter = Newsletter.find(params[:id])
if @newsletter.update(newsletter_params)
redirect_to [:admin, @newsletter], notice: t("admin.newsletters.update_success")
else
render :edit
end
end
def destroy
@newsletter = Newsletter.find(params[:id])
@newsletter.destroy
redirect_to admin_newsletters_path, notice: t("admin.newsletters.delete_success")
end
def users
@@ -9,4 +50,20 @@ class Admin::NewslettersController < Admin::BaseController
send_file(File.join(zip.path), type: 'application/zip')
end
def deliver
@newsletter = Newsletter.find(params[:id])
Mailer.newsletter(@newsletter).deliver_later
@newsletter.update(sent_at: Time.current)
redirect_to [:admin, @newsletter], notice: t("admin.newsletters.send_success")
end
private
def newsletter_params
newsletter_params = params.require(:newsletter)
.permit(:subject, :segment_recipient, :from, :body)
newsletter_params.merge(segment_recipient: newsletter_params[:segment_recipient].to_i)
end
end

View File

@@ -126,6 +126,15 @@ class Mailer < ApplicationMailer
end
end
def newsletter(newsletter)
@newsletter = newsletter
@email_to = newsletter.list_of_recipients
@email_to.map(&:email).uniq.each do |recipient|
mail(to: recipient, from: @newsletter.from, subject: @newsletter.subject)
end
end
private
def with_user(user, &block)

View File

@@ -82,6 +82,8 @@ module Abilities
can [:create], Document
can [:create, :destroy], DirectUpload
can [:deliver], Newsletter, hidden_at: nil
end
end
end

23
app/models/newsletter.rb Normal file
View File

@@ -0,0 +1,23 @@
class Newsletter < ActiveRecord::Base
enum segment_recipient: { all_users: 1,
proposal_authors: 2,
investment_authors: 3,
feasible_and_undecided_investment_authors: 4,
selected_investment_authors: 5,
winner_investment_authors: 6 }
validates :subject, presence: true
validates :segment_recipient, presence: true
validates :from, presence: true
validates :body, presence: true
validates_format_of :from, :with => /@/
def list_of_recipients
UserSegments.send(segment_recipient)
end
def draft?
sent_at.nil?
end
end

View File

@@ -199,11 +199,16 @@
</li>
<% end %>
<li <%= "class=active" if controller_name == "newsletter" %>>
<%= link_to admin_newsletters_path do %>
<li class="section-title">
<a href="#">
<span class="icon-zip"></span>
<%= t("admin.menu.newsletter") %>
<% end %>
<strong><%= t("admin.menu.emails") %></strong>
</a>
<ul id="emails_menu" <%= "class=is-active" if controller_name == "newsletters" %>>
<li <%= "class=active" if controller_name == "newsletters" %>>
<%= link_to t("admin.menu.newsletters"), admin_newsletters_path %>
</li>
</ul>
</li>
</ul>
</div>

View File

@@ -0,0 +1,14 @@
<%= form_for [:admin, @newsletter] do |f| %>
<%= render 'shared/errors', resource: @newsletter %>
<%= f.select :segment_recipient, options_for_select(Newsletter.segment_recipients
.collect { |k,v| [t("admin.segment_recipient.#{k}"), v] },
@newsletter[:segment_recipient]) %>
<%= f.text_field :subject %>
<%= f.text_field :from %>
<%= f.cktext_area :body, ckeditor: { language: I18n.locale } %>
<div class="margin-top">
<%= f.submit class: "button success" %>
</div>
<% end %>

View File

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

View File

@@ -1,3 +1,47 @@
<h2><%= t("admin.newsletters.index.title") %></h2>
<h2 class="inline-block"><%= t("admin.newsletters.index.title") %></h2>
<%= link_to t("admin.newsletters.index.new_newsletter"), new_admin_newsletter_path,
class: "button float-right" %>
<%= link_to t("admin.newsletters.index.button"), users_admin_newsletters_path, class: "button" %>
<% if @newsletters.any? %>
<table id="newsletters">
<thead>
<tr>
<th><%= t("admin.newsletters.index.subject") %></th>
<th><%= t("admin.newsletters.index.segment_recipient") %></th>
<th><%= t("admin.newsletters.index.sent") %></th>
<th class="small-5 text-right"><%= t("admin.newsletters.index.actions") %></th>
</tr>
</thead>
<tbody>
<% @newsletters.order(created_at: :desc).each do |newsletter| %>
<tr id="<%= dom_id(newsletter) %>" class="newsletter">
<td>
<%= newsletter.subject %>
</td>
<td>
<%= t("admin.segment_recipient.#{newsletter.segment_recipient}") %>
</td>
<td>
<% if newsletter.draft? %>
<%= t("admin.newsletters.index.draft") %>
<% else %>
<%= l newsletter.sent_at.to_date %>
<% end %>
</td>
<td class="text-right">
<%= link_to t("admin.newsletters.index.edit"), edit_admin_newsletter_path(newsletter),
method: :get, class: "button hollow" %>
<%= link_to t("admin.newsletters.index.delete"), admin_newsletter_path(newsletter),
method: :delete, class: "button hollow alert" %>
<%= link_to t("admin.newsletters.index.preview"), admin_newsletter_path(newsletter),
class: "button" %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<div data-alert class="callout primary margin-top clear">
<%= t("admin.newsletters.index.empty_newsletters") %>
</div>
<% end %>

View File

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

View File

@@ -0,0 +1,51 @@
<%= back_link_to %>
<h2><%= t("admin.newsletters.show.title") %></h2>
<%- recipients_count = @newsletter.list_of_recipients.count %>
<div class="small-12 column">
<div class="callout highlight">
<div class="row">
<div class="small-12 medium-4 column">
<strong><%= t("admin.newsletters.show.sent_at") %></strong><br>
<% if @newsletter.draft? %>
<%= t("admin.newsletters.index.draft") %>
<% else %>
<%= l @newsletter.sent_at.to_date %>
<% end %>
</div>
<div class="small-12 medium-4 column">
<strong><%= t("admin.newsletters.show.from") %></strong><br>
<%= @newsletter.from %>
</div>
<div class="small-12 medium-4 column">
<strong><%= t("admin.newsletters.show.subject") %></strong><br>
<%= @newsletter.subject %>
</div>
</div>
<div class="row">
<div class="small-12 column">
<strong><%= t("admin.newsletters.show.segment_recipient") %></strong><br>
<%= t("admin.segment_recipient.#{@newsletter.segment_recipient}") %>
<%= t("admin.newsletters.show.affected_users", n: recipients_count) %>
</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/mailer/newsletter.html.erb", layout: '/app/views/layouts/mailer.html.erb' %>
</div>
</div>
<% if @newsletter.draft? %>
<%= link_to t("admin.newsletters.show.send"), deliver_admin_newsletter_path(@newsletter),
"data-alert": t("admin.newsletters.show.send_alert", n: recipients_count),
method: :post,
id: "js-send-newsletter-alert",
class: "button success" %>
<% end %>

View File

@@ -0,0 +1,5 @@
<td style="padding-bottom: 20px; padding-left: 10px;">
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;line-height: 24px;">
<%= safe_html_with_links @newsletter.body.html_safe %>
</p>
</td>

View File

@@ -37,6 +37,9 @@ en:
manager:
one: "Manager"
other: "Managers"
newsletter:
one: "Newsletter"
other: "Newsletters"
vote:
one: "Vote"
other: "Votes"
@@ -234,6 +237,11 @@ en:
poll/question/answer/video:
title: Title
url: External video
newsletter:
segment_recipient: Recipients
subject: Subject
from: From
body: Email content
errors:
models:
user:

View File

@@ -465,7 +465,8 @@ en:
administrators: Administrators
managers: Managers
moderators: Moderators
newsletter: Newsletters
emails: Sending of emails
newsletters: Newsletters
valuators: Valuators
poll_officers: Poll officers
polls: Polls
@@ -514,10 +515,45 @@ en:
delete: Delete
search:
title: 'Moderators: User search'
segment_recipient:
all_users: All users
proposal_authors: Proposal authors
investment_authors: Investment authors in the current budget
feasible_and_undecided_investment_authors: Authors of feasible or undecided investments in the current budget
selected_investment_authors: Authors of selected investments in the current budget
winner_investment_authors: Authors of winner investments in the current budget
newsletters:
create_success: Newsletter created successfully
update_success: Newsletter updated successfully
send_success: Newsletter sent successfully
delete_success: Newsletter deleted successfully
index:
title: Newsletters
button: Download zip with users list
new_newsletter: New newsletter
subject: Subject
segment_recipient: Recipients
sent: Sent
actions: Actions
draft: Draft
edit: Edit
delete: Delete
preview: Preview
empty_newsletters: There are no newsletters to show
new:
title: New newsletter
edit:
title: Edit newsletter
show:
title: Newsletter preview
send: Send
affected_users: (%{n} affected users)
sent_at: Sent at
subject: Subject
segment_recipient: Recipients
from: From
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?
valuators:
index:
title: Valuators

View File

@@ -37,6 +37,9 @@ es:
manager:
one: "Gestor"
other: "Gestores"
newsletter:
one: "Newsletter"
other: "Newsletters"
vote:
one: "Voto"
other: "Votos"
@@ -230,6 +233,11 @@ es:
poll/question/answer/video:
title: Título
url: Vídeo externo
newsletter:
segment_recipient: Destinatarios
subject: Asunto
from: Enviado por
body: Contenido del email
errors:
models:
user:

View File

@@ -464,7 +464,8 @@ es:
administrators: Administradores
managers: Gestores
moderators: Moderadores
newsletter: Envío de Newsletters
emails: Envío de emails
newsletters: Newsletters
valuators: Evaluadores
poll_officers: Presidentes de mesa
polls: Votaciones
@@ -513,10 +514,45 @@ es:
delete: Borrar
search:
title: 'Moderadores: Búsqueda de usuarios'
segment_recipient:
all_users: Todos los usuarios
proposal_authors: Usuarios autores de propuestas
investment_authors: Usuarios autores de proyectos de gasto en los actuales presupuestos
feasible_and_undecided_investment_authors: Usuarios autores de proyectos de gasto viables o sin decidir en los actuales presupuestos
selected_investment_authors: Usuarios autores de proyectos de gasto seleccionadas en los actuales presupuestos
winner_investment_authors: Usuarios autores de proyectos de gasto ganadoras en los actuales presupuestos
newsletters:
create_success: Newsletter creada correctamente
update_success: Newsletter actualizada correctamente
send_success: Newsletter enviada correctamente
delete_success: Newsletter borrada correctamente
index:
title: Envío de newsletters
button: Descargar zip con lista de usuarios
new_newsletter: Crear newsletter
subject: Asunto
segment_recipient: Destinatarios
sent: Enviado
actions: Acciones
draft: Borrador
edit: Editar
delete: Borrar
preview: Previsualizar
empty_newsletters: No hay newsletters para mostrar
new:
title: Nueva newsletter
edit:
title: Editar newsletter
show:
title: Vista previa de newsletter
send: Enviar
affected_users: (%{n} usuarios afectados)
sent_at: Enviado
subject: Asunto
segment_recipient: Destinatarios
from: Enviado por
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?
valuators:
index:
title: Evaluadores

View File

@@ -142,7 +142,10 @@ namespace :admin do
resource :activity, controller: :activity, only: :show
resources :newsletters, only: :index do
resources :newsletters do
member do
post :deliver
end
get :users, on: :collection
end

View File

@@ -828,4 +828,6 @@ section "Creating legislation processes" do
end
end
require_relative 'dev_seeds/newsletters'
log "All dev seeds created successfuly 👍"

View File

@@ -0,0 +1,17 @@
section "Creating Newsletters" do
newsletter_body = [
"We choose to go to the moon in this decade and do the other things, not because they are easy, but because they are hard, because that goal will serve to organize and measure the best of our energies and skills, because that challenge is one that we are willing to accept, one we are unwilling to postpone, and one which we intend to win.",
"Spaceflights cannot be stopped. This is not the work of any one man or even a group of men. It is a historical process which mankind is carrying out in accordance with the natural laws of human development.",
"Many say exploration is part of our destiny, but its actually our duty to future generations and their quest to ensure the survival of the human species."
]
5.times do |n|
Newsletter.create!(
subject: "Newsletter subject #{n}",
segment_recipient: Newsletter.segment_recipients.values.sample,
from: 'no-reply@consul.dev',
body: newsletter_body.sample,
sent_at: [Time.now, nil].sample
)
end
end

View File

@@ -0,0 +1,13 @@
class CreateNewsletters < ActiveRecord::Migration
def change
create_table :newsletters do |t|
t.string :subject
t.integer :segment_recipient
t.string :from
t.text :body
t.date :sent_at, default: nil
t.timestamps null: false
end
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180129190950) do
ActiveRecord::Schema.define(version: 20180205170054) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -624,6 +624,16 @@ ActiveRecord::Schema.define(version: 20180129190950) do
add_index "moderators", ["user_id"], name: "index_moderators_on_user_id", using: :btree
create_table "newsletters", force: :cascade do |t|
t.string "subject"
t.integer "segment_recipient"
t.string "from"
t.text "body"
t.date "sent_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "notifications", force: :cascade do |t|
t.integer "user_id"
t.integer "notifiable_id"

42
lib/user_segments.rb Normal file
View File

@@ -0,0 +1,42 @@
class UserSegments
def self.all_users
User.newsletter.active
end
def self.proposal_authors
author_ids = Proposal.not_archived.not_retired.pluck(:author_id).uniq
author_ids(author_ids)
end
def self.investment_authors
author_ids = current_budget_investments.pluck(:author_id).uniq
author_ids(author_ids)
end
def self.feasible_and_undecided_investment_authors
author_ids = current_budget_investments.where(feasibility: %w(feasible undecided))
.pluck(:author_id).uniq
author_ids(author_ids)
end
def self.selected_investment_authors
author_ids = current_budget_investments.selected.pluck(:author_id).uniq
author_ids(author_ids)
end
def self.winner_investment_authors
author_ids = current_budget_investments.winners.pluck(:author_id).uniq
author_ids(author_ids)
end
private
def self.current_budget_investments
Budget.current.investments
end
def self.author_ids(author_ids)
all_users.where(id: author_ids)
end
end

View File

@@ -943,4 +943,11 @@ LOREM_IPSUM
factory :related_content do
end
factory :newsletter do
sequence(:subject) { |n| "Subject #{n}" }
segment_recipient [1, 2, 3, 4, 5, 6].sample
sequence(:from) { |n| "noreply#{n}@consul.dev" }
sequence(:body) { |n| "Body #{n}" }
end
end

View File

@@ -0,0 +1,129 @@
require 'rails_helper'
feature "Admin newsletter emails" do
background do
admin = create(:administrator)
login_as(admin.user)
create(:budget)
end
scenario "Show" do
newsletter = create(:newsletter, subject: "This is a subject",
segment_recipient: 1,
from: "no-reply@consul.dev",
body: "This is a body")
visit admin_newsletter_path(newsletter)
expect(page).to have_content "This is a subject"
expect(page).to have_content I18n.t("admin.segment_recipient.#{newsletter.segment_recipient}")
expect(page).to have_content "no-reply@consul.dev"
expect(page).to have_content "This is a body"
end
scenario "Index" do
3.times { create(:newsletter) }
visit admin_newsletters_path
expect(page).to have_css(".newsletter", count: 3)
Newsletter.all.each do |newsletter|
within("#newsletter_#{newsletter.id}") do
expect(page).to have_content newsletter.subject
expect(page).to have_content I18n.t("admin.segment_recipient.#{newsletter.segment_recipient}")
end
end
end
scenario "Create" do
visit admin_newsletters_path
click_link "New newsletter"
fill_in_newsletter_form(subject: "This is a subject",
segment_recipient: "Proposal authors",
body: "This is a body" )
click_button "Create Newsletter"
expect(page).to have_content "Newsletter created successfully"
expect(page).to have_content "This is a subject"
expect(page).to have_content "Proposal authors"
expect(page).to have_content "no-reply@consul.dev"
expect(page).to have_content "This is a body"
end
scenario "Update" do
newsletter = create(:newsletter)
visit admin_newsletters_path
within("#newsletter_#{newsletter.id}") do
click_link "Edit"
end
fill_in_newsletter_form(subject: "This is a subject",
segment_recipient: "Investment authors in the current budget",
body: "This is a body" )
click_button "Update Newsletter"
expect(page).to have_content "Newsletter updated successfully"
expect(page).to have_content "This is a subject"
expect(page).to have_content "Investment authors in the current budget"
expect(page).to have_content "no-reply@consul.dev"
expect(page).to have_content "This is a body"
end
scenario "Destroy" do
newsletter = create(:newsletter)
visit admin_newsletters_path
within("#newsletter_#{newsletter.id}") do
click_link "Delete"
end
expect(page).to have_content "Newsletter deleted successfully"
expect(page).to have_css(".newsletter", count: 0)
end
scenario 'Errors on create' do
visit new_admin_newsletter_path
click_button "Create Newsletter"
expect(page).to have_content error_message
end
scenario "Errors on update" do
newsletter = create(:newsletter)
visit edit_admin_newsletter_path(newsletter)
fill_in "newsletter_subject", with: ""
click_button "Update Newsletter"
expect(page).to have_content error_message
end
scenario "Send newsletter email", :js do
newsletter = create(:newsletter)
visit admin_newsletter_path(newsletter)
click_link "Send"
total_users = newsletter.list_of_recipients.count
page.accept_confirm("Are you sure you want to send this newsletter to #{total_users} users?")
expect(page).to have_content "Newsletter sent successfully"
end
scenario "Select list of users to send newsletter" do
Newsletter.segment_recipients.each_key do |user_group|
visit new_admin_newsletter_path
fill_in_newsletter_form
select I18n.t("admin.segment_recipient.#{user_group}"), from: 'newsletter_segment_recipient'
click_button "Create Newsletter"
expect(page).to have_content(I18n.t("admin.segment_recipient.#{user_group}"))
end
end
end

View File

@@ -1,26 +0,0 @@
require 'rails_helper'
feature 'Admin newsletters emails' do
let(:download_button_text) { 'Download zip with users list' }
background do
@admin = create(:administrator)
@newsletter_user = create(:user, newsletter: true)
@non_newsletter_user = create(:user, newsletter: false)
login_as(@admin.user)
visit admin_newsletters_path
end
scenario 'Index' do
expect(page).to have_content download_button_text
end
scenario 'Download newsletter email zip' do
click_link download_button_text
downloaded_file_content = Zip::InputStream.open(StringIO.new(page.body)).get_next_entry.get_input_stream {|is| is.read }
expect(downloaded_file_content).to include(@admin.user.email, @newsletter_user.email)
expect(downloaded_file_content).not_to include(@non_newsletter_user.email)
end
end

View File

@@ -491,6 +491,32 @@ feature 'Emails' do
end
context "Newsletter" do
scenario "Send newsletter email to selected users" do
admin = create(:administrator)
login_as(admin.user)
visit new_admin_newsletter_path
fill_in_newsletter_form
click_button "Create Newsletter"
expect(page).to have_content "Newsletter created successfully"
click_link "Send"
UserSegments.send(Newsletter.first.segment_recipient).each do |user|
expect(unread_emails_for(user.email).count).to eq 1
end
email = open_last_email
expect(email).to have_subject('This is a different subject')
expect(email).to deliver_from('no-reply@consul.dev')
expect(email.body.encoded).to include('This is a different body')
end
end
context "Users without email" do
scenario "should not receive emails" do
user = create(:user, :verified, email_on_comment: true)
@@ -504,5 +530,6 @@ feature 'Emails' do
expect { open_last_email }.to raise_error "No email has been sent!"
end
end
end

View File

@@ -0,0 +1,153 @@
require 'rails_helper'
describe UserSegments do
let(:user1) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
describe "#all_users" do
it "returns all active users with newsletter enabled" do
active_user1 = create(:user, newsletter: true)
active_user2 = create(:user, newsletter: true)
active_user3 = create(:user, newsletter: false)
erased_user = create(:user, erased_at: Time.current)
expect(described_class.all_users).to include active_user1
expect(described_class.all_users).to include active_user2
expect(described_class.all_users).not_to include active_user3
expect(described_class.all_users).not_to include erased_user
end
end
describe "#proposal_authors" do
it "returns users that have created a proposal" do
proposal = create(:proposal, author: user1)
proposal_authors = described_class.proposal_authors
expect(proposal_authors).to include user1
expect(proposal_authors).not_to include user2
end
it "does not return duplicated users" do
proposal1 = create(:proposal, author: user1)
proposal2 = create(:proposal, author: user1)
proposal_authors = described_class.proposal_authors
expect(proposal_authors).to contain_exactly(user1)
end
end
describe "#investment_authors" do
it "returns users that have created a budget investment" do
investment = create(:budget_investment, author: user1)
budget = create(:budget)
investment.update(budget: budget)
investment_authors = described_class.investment_authors
expect(investment_authors).to include user1
expect(investment_authors).not_to include user2
end
it "does not return duplicated users" do
investment1 = create(:budget_investment, author: user1)
investment2 = create(:budget_investment, author: user1)
budget = create(:budget)
investment1.update(budget: budget)
investment2.update(budget: budget)
investment_authors = described_class.investment_authors
expect(investment_authors).to contain_exactly(user1)
end
end
describe "#feasible_and_undecided_investment_authors" do
it "returns authors of a feasible or an undecided budget investment" do
feasible_investment = create(:budget_investment, :feasible, author: user1)
undecided_investment = create(:budget_investment, :undecided, author: user2)
unfeasible_investment = create(:budget_investment, :unfeasible, author: user3)
budget = create(:budget)
feasible_investment.update(budget: budget)
undecided_investment.update(budget: budget)
unfeasible_investment.update(budget: budget)
investment_authors = described_class.feasible_and_undecided_investment_authors
expect(investment_authors).to include user1
expect(investment_authors).to include user2
expect(investment_authors).not_to include user3
end
it "does not return duplicated users" do
feasible_investment = create(:budget_investment, :feasible, author: user1)
undecided_investment = create(:budget_investment, :undecided, author: user1)
budget = create(:budget)
feasible_investment.update(budget: budget)
undecided_investment.update(budget: budget)
investment_authors = described_class.feasible_and_undecided_investment_authors
expect(investment_authors).to contain_exactly(user1)
end
end
describe "#selected_investment_authors" do
it "returns authors of selected budget investments" do
selected_investment = create(:budget_investment, :selected, author: user1)
unselected_investment = create(:budget_investment, :unselected, author: user2)
budget = create(:budget)
selected_investment.update(budget: budget)
unselected_investment.update(budget: budget)
investment_authors = described_class.selected_investment_authors
expect(investment_authors).to include user1
expect(investment_authors).not_to include user2
end
it "does not return duplicated users" do
selected_investment1 = create(:budget_investment, :selected, author: user1)
selected_investment2 = create(:budget_investment, :selected, author: user1)
budget = create(:budget)
selected_investment1.update(budget: budget)
selected_investment2.update(budget: budget)
investment_authors = described_class.selected_investment_authors
expect(investment_authors).to contain_exactly(user1)
end
end
describe "#winner_investment_authors" do
it "returns authors of winner budget investments" do
winner_investment = create(:budget_investment, :winner, author: user1)
selected_investment = create(:budget_investment, :selected, author: user2)
budget = create(:budget)
winner_investment.update(budget: budget)
selected_investment.update(budget: budget)
investment_authors = described_class.winner_investment_authors
expect(investment_authors).to include user1
expect(investment_authors).not_to include user2
end
it "does not return duplicated users" do
winner_investment1 = create(:budget_investment, :winner, author: user1)
winner_investment2 = create(:budget_investment, :winner, author: user1)
budget = create(:budget)
winner_investment1.update(budget: budget)
winner_investment2.update(budget: budget)
investment_authors = described_class.winner_investment_authors
expect(investment_authors).to contain_exactly(user1)
end
end
describe "#current_budget_investments" do
it "only returns investments from the current budget" do
investment1 = create(:budget_investment, author: create(:user))
investment2 = create(:budget_investment, author: create(:user))
budget = create(:budget)
investment1.update(budget: budget)
current_budget_investments = described_class.current_budget_investments
expect(current_budget_investments).to include investment1
expect(current_budget_investments).not_to include investment2
end
end
end

View File

@@ -0,0 +1,34 @@
require 'rails_helper'
describe Newsletter do
let(:newsletter) { build(:newsletter) }
it "is valid" do
expect(newsletter).to be_valid
end
it 'is not valid without a subject' do
newsletter.subject = nil
expect(newsletter).not_to be_valid
end
it 'is not valid without a segment_recipient' do
newsletter.segment_recipient = nil
expect(newsletter).not_to be_valid
end
it 'is not valid without a from' do
newsletter.from = nil
expect(newsletter).not_to be_valid
end
it 'is not valid without a body' do
newsletter.body = nil
expect(newsletter).not_to be_valid
end
it 'validates from attribute email format' do
newsletter.from = "this_is_not_an_email"
expect(newsletter).not_to be_valid
end
end

View File

@@ -363,4 +363,11 @@ module CommonActions
end
end
def fill_in_newsletter_form(options = {})
fill_in "newsletter_subject", with: (options[:subject] || "This is a different subject")
select (options[:segment_recipient] || 'All users'), from: 'newsletter_segment_recipient'
fill_in "newsletter_from", with: (options[:from] || "no-reply@consul.dev")
fill_in "newsletter_body", with: (options[:body] || "This is a different body")
end
end