Adds email feature for proposals dashboard
This commit is contained in:
Juan Salvador Pérez García
2018-07-25 13:28:44 +02:00
parent 9b83291b16
commit 8876b285ce
31 changed files with 488 additions and 19 deletions

View File

@@ -10,6 +10,7 @@
@import 'pages';
@import 'proposal';
@import 'proposal-graph';
@import 'dashboard_mailer_preview';
@import 'poll';
@import 'legislation';
@import 'legislation_process';

View File

@@ -0,0 +1,65 @@
@import 'application';
body {
padding-left: 30%;
padding-right: 30%;
p {
text-align: justify;
}
}
header {
background-color: #3700fd;
color: white;
padding: 20pt 20pt 20pt 20pt;
margin-bottom: 0;
border-bottom: 0;
h1 {
font-size: 40pt;
text-align: center;
}
h2 {
font-size: 25pt;
text-align: center;
}
}
.proposal-image {
width: 100%;
}
.mail-body {
color: #838383;
font-size: 18pt;
margin-top: 20pt;
}
.support-link {
display: block;
background-color: #004a84;
color: #ddffff;
text-decoration: none;
border: 1px solid $border;
width: 80%;
margin-left: auto;
margin-right: auto;
font-size: 40pt;
padding: 20pt 20pt 20pt 20pt;
border-radius: 5pt;
text-align: center;
margin-top: 50pt;
margin-bottom: 50pt;
}
.support-link:hover {
color: #ddffffff;
text-decoration: none;
}
.share-title {
font-weight: bold;
font-size: 25pt;
}

View File

@@ -0,0 +1,64 @@
.dashboard-mail-preview {
padding-left: 10%;
padding-right: 10%;
p {
text-align: justify;
}
.header {
background-color: #3700fd;
color: white;
padding: 20pt 20pt 20pt 20pt;
margin-bottom: 0;
border-bottom: 0;
h1 {
font-size: 40pt;
text-align: center;
}
h2 {
font-size: 25pt;
text-align: center;
}
}
.proposal-image {
width: 100%;
}
.mail-body {
color: #838383;
font-size: 18pt;
margin-top: 20pt;
}
.support-link {
display: block;
background-color: #004a84;
color: #ddffff;
text-decoration: none;
border: 1px solid $border;
width: 80%;
margin-left: auto;
margin-right: auto;
font-size: 40pt;
padding: 20pt 20pt 20pt 20pt;
border-radius: 5pt;
text-align: center;
margin-top: 50pt;
margin-bottom: 50pt;
}
.support-link:hover {
color: #ddffffff;
text-decoration: none;
}
.share-title {
font-weight: bold;
font-size: 25pt;
}
}

View File

@@ -1,5 +1,6 @@
class Admin::SettingsController < Admin::BaseController
helper_method :successful_proposal_setting, :successful_proposals, :poll_feature_short_title_setting, :poll_feature_description_setting, :poll_feature_link_setting
helper_method :successful_proposal_setting, :successful_proposals, :poll_feature_short_title_setting, :poll_feature_description_setting,
:poll_feature_link_setting, :email_feature_short_title_setting, :email_feature_description_setting
def index
all_settings = Setting.all.group_by { |s| s.type }
@@ -29,7 +30,7 @@ class Admin::SettingsController < Admin::BaseController
end
def successful_proposal_setting
Setting.find_by(key: 'proposals.successful_proposal_id')
@successful_proposal_setting ||= Setting.find_by(key: 'proposals.successful_proposal_id')
end
def successful_proposals
@@ -37,14 +38,22 @@ class Admin::SettingsController < Admin::BaseController
end
def poll_feature_short_title_setting
Setting.find_by(key: 'proposals.poll_short_title')
@poll_feature_short_title_setting ||= Setting.find_by(key: 'proposals.poll_short_title')
end
def poll_feature_description_setting
Setting.find_by(key: 'proposals.poll_description')
@poll_feature_description_setting ||= Setting.find_by(key: 'proposals.poll_description')
end
def poll_feature_link_setting
Setting.find_by(key: 'proposals.poll_link')
@poll_feature_link_setting ||= Setting.find_by(key: 'proposals.poll_link')
end
def email_feature_short_title_setting
@email_feature_short_title_setting ||= Setting.find_by(key: 'proposals.email_short_title')
end
def email_feature_description_setting
@email_feature_description_setting ||= Setting.find_by(key: 'proposals.email_description')
end
end

View File

@@ -0,0 +1,16 @@
class Dashboard::MailingController < Dashboard::BaseController
def index
authorize! :manage_mailing, proposal
end
def new
authorize! :manage_mailing, proposal
end
def create
authorize! :manage_mailing, proposal
Dashboard::Mailer.forward(proposal).deliver_later
redirect_to new_proposal_dashboard_mailing_path(proposal), flash: { notice: t("dashboard.mailing.create.sent") }
end
end

View File

@@ -31,13 +31,21 @@ module ProposalsDashboardHelper
end
def resources_menu_active?
polls_menu_active? || is_resource_request?
polls_menu_active? || mailing_menu_active? || is_resource_request?
end
def polls_menu_active?
controller_name == 'polls'
end
def mailing_menu(&block)
menu_entry(mailing_menu_active?, &block)
end
def mailing_menu_active?
controller_name == 'mailing'
end
def menu_group(id, active, &block)
html_class = nil
html_class = 'is-active' if active

View File

@@ -0,0 +1,8 @@
class Dashboard::Mailer < ApplicationMailer
layout 'dashboard/mailer'
def forward(proposal)
@proposal = proposal
mail to: proposal.author.email, subject: proposal.title
end
end

View File

@@ -25,6 +25,9 @@ module Abilities
can :manage_polls, Proposal do |proposal|
proposal.author.id == user.id
end
can :manage_mailing, Proposal do |proposal|
proposal.author.id == user.id
end
can :results, Poll do |poll|
poll.related&.author&.id == user.id

View File

@@ -34,7 +34,6 @@
<% end %>
</td>
</tr>
<tr>
<td class="small-12 medium-4">
<strong><%= t("settings.#{poll_feature_description_setting.key}") %></strong>
@@ -52,7 +51,6 @@
<% end %>
</td>
</tr>
<tr>
<td class="small-12 medium-4">
<strong><%= t("settings.#{poll_feature_link_setting.key}") %></strong>
@@ -70,6 +68,39 @@
<% end %>
</td>
</tr>
<tr>
<td class="small-12 medium-4">
<strong><%= t("settings.#{email_feature_short_title_setting.key}") %></strong>
</td>
<td class="small-12 medium-8">
<%= form_for email_feature_short_title_setting,
url: admin_setting_path(email_feature_short_title_setting),
html: { id: "edit_#{dom_id(email_feature_short_title_setting)}"} do |f| %>
<div class="small-12 medium-6 large-9 column">
<%= f.text_field :value, label: false, id: dom_id(email_feature_short_title_setting) %>
</div>
<div class="small-12 medium-6 large-3 column">
<%= f.submit(t('admin.settings.index.update_setting'), class: "button hollow expanded") %>
</div>
<% end %>
</td>
</tr>
<tr>
<td class="small-12 medium-4">
<strong><%= t("settings.#{email_feature_description_setting.key}") %></strong>
</td>
<td class="small-12 medium-8">
<%= form_for email_feature_description_setting,
url: admin_setting_path(email_feature_description_setting),
html: { id: "edit_#{dom_id(email_feature_description_setting)}"} do |f| %>
<div class="small-12 medium-6 large-9 column">
<%= f.cktext_area :value, label: false, id: dom_id(email_feature_description_setting) %>
</div>
<div class="small-12 medium-6 large-3 column">
<%= f.submit(t('admin.settings.index.update_setting'), class: "button hollow expanded") %>
</div>
<% end %>
</td>
</tr>
</tbody>
</table>

View File

@@ -0,0 +1,26 @@
<% if can?(:manage_mailing, proposal) %>
<div class="column">
<div class="card resource-card primary"
data-tooltip title="<%= t("dashboard.resource.request_resource") %>"
data-position="bottom" data-alignment="right">
<div class="card-section">
<p class="text-right">
<i class="fi-pencil resource-icon"></i>
</p>
<h4 class="text-center"><%= t("dashboard.menu.mailing") %></h4>
<p class="text-center">
<%= Setting['proposals.email_short_title'] %>
</p>
</div>
<div class="card-section text-center bottom-container">
<div class="bottom-element text-center">
<%= link_to t("dashboard.resource.request_resource"),
new_proposal_dashboard_mailing_path(proposal.to_param),
class: 'button primary' %>
</div>
</div>
</div>
</div>
<% end %>

View File

@@ -32,6 +32,16 @@
<% end %>
<% end %>
<% if can?(:manage_mailing, proposal) %>
<%= mailing_menu do %>
<%= link_to new_proposal_dashboard_mailing_path(proposal.to_param) do %>
<span data-tooltip title="<%= Setting['proposals.email_short_title'] || t("dashboard.menu.mailing") %>">
<%= t("dashboard.menu.mailing") %>
</span>
<% end %>
<% end %>
<% end %>
<% resources.each do |resource| %>
<li <%= 'class=is-active' if is_request_active(resource.id) %>>
<%= link_to new_request_proposal_dashboard_path(proposal, resource) do %>

View File

@@ -7,6 +7,7 @@
<div class="row small-up-2 medium-up-3 large-up-4">
<%= render 'poll_resource' %>
<%= render 'mailing_resource' %>
<%= render partial: 'resource', collection: active_resources %>
</div>
</div>

View File

@@ -0,0 +1,18 @@
<header>
<h1><%= @proposal.title %></h1>
<h2><%= t("dashboard.mailer.forward.subtitle") %></h2>
</header>
<%= image_tag @proposal.image.attachment.url(:large), class: 'proposal-image' if @proposal.image.present? %>
<div class="mail-body">
<%== t("dashboard.mailer.forward.introduction") %>
<%= link_to t("dashboard.mailer.forward.support_it"), proposal_url(@proposal), class: 'support-link' %>
<%== t("dashboard.mailer.forward.share_info") %>
<p class="share-title"><%= t("dashboard.mailer.forward.share_in") %></p>
<%= render partial: 'shared/social_share', locals: {
title: @proposal.title,
url: proposal_url(@proposal),
description: @proposal.summary
} %>
</div>

View File

@@ -0,0 +1,13 @@
<div class="small-12 medium-3 column">
<% if action_name != 'index' %>
<%= link_to t("dashboard.mailing.mailing_options.preview"),
proposal_dashboard_mailing_index_path(proposal),
class: 'button expanded' %>
<% end %>
<%= link_to t("dashboard.mailing.mailing_options.send", address: current_user.email),
proposal_dashboard_mailing_index_path(proposal),
method: :post,
class: 'button expanded' %>
</div>

View File

@@ -0,0 +1,26 @@
<% content_for :action_title, t("dashboard.mailing.index.title") %>
<div class="row">
<div class="small-12 medium-9 column dashboard-mail-preview">
<div class="header">
<h1><%= proposal.title %></h1>
<h2><%= t("dashboard.mailer.forward.subtitle") %></h2>
</div>
<%= image_tag proposal.image.attachment.url(:large), class: 'proposal-image' if proposal.image.present? %>
<div class="mail-body">
<%== t("dashboard.mailer.forward.introduction") %>
<%= link_to t("dashboard.mailer.forward.support_it"), proposal_url(@proposal), class: 'support-link' %>
<%== t("dashboard.mailer.forward.share_info") %>
<p class="share-title"><%= t("dashboard.mailer.forward.share_in") %></p>
<%= render partial: 'shared/social_share', locals: {
title: @proposal.title,
url: proposal_url(@proposal),
description: @proposal.summary
} %>
</div>
</div>
<%= render 'mailing_options' %>
</div>

View File

@@ -0,0 +1,8 @@
<% content_for :action_title, t("dashboard.mailing.new.title") %>
<div class="row">
<div class="small-12 medium-9 column">
<%== Setting['proposals.email_description'] %>
</div>
<%= render 'mailing_options' %>
</div>

View File

@@ -2,6 +2,12 @@
<div class="row">
<div class="small-12 medium-9 column">
<%== Setting['proposals.poll_description'] %>
<% if @polls.any? %>
<div class="row small-up-2 medium-up-3 large-up-4">
<%= render @polls %>
</div>
<% end %>
</div>
<div class="small-12 medium-3 column">
@@ -19,9 +25,3 @@
class: 'button expanded' %>
</div>
</div>
<% if @polls.any? %>
<div class="row small-up-2 medium-up-3 large-up-4">
<%= render @polls %>
</div>
<% end %>

View File

@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<%= stylesheet_link_tag "dashboard_mailer" %>
</head>
<body>
<%= yield %>
</body>
</html>

View File

@@ -45,6 +45,7 @@ Rails.application.configure do
# config.action_view.raise_on_missing_translations = true
config.cache_store = :dalli_store
config.action_mailer.preview_path = "#{Rails.root}/spec/mailers/previews"
config.after_initialize do
Bullet.enable = true

View File

@@ -15,6 +15,7 @@ Rails.application.config.assets.precompile += %w( stat_graphs.js )
Rails.application.config.assets.precompile += %w( dashboard_graphs.js )
Rails.application.config.assets.precompile += %w( print.css )
Rails.application.config.assets.precompile += %w( ie.css )
Rails.application.config.assets.precompile += %w( dashboard_mailer.css )
# Loads app/assets/images/custom before app/assets/images
images_path = Rails.application.config.assets.paths

View File

@@ -510,6 +510,7 @@ en:
resources: Resources
community: Community
polls: Polls
mailing: E-mail
form:
request: Request
create_request:
@@ -586,6 +587,47 @@ en:
add_answer: Add answer
question_answer_fields:
remove_answer: Remove answer
mailing:
index:
title: E-mail preview
new:
title: E-mail feature
mailing_options:
send: Send to %{address}
preview: Preview
create:
sent: The email has been sent
mailer:
forward:
subtitle: If you support me, we will achieve it.
support_it: Support this proposal
share_in: Share in
introduction:
"<p>Hello!</p>
<p>
I am writing to let you know that I am
participating in Decide Madrid, the platform for
Madrid and Madrid we can decide which city
we want. And for that, I created my own citizen proposal
and now, I'm going to need your support! But do not worry because
It is very simple.
</p>
<p>
You just have to click on the button that you will see below
'Support this proposal' and you can directly inform yourself about
before promoting it. Only the proposals that achieve the
maximum support will be carried out by our City Council,
and I thought that you, I'm sure you help me achieve it!
</p>"
share_info:
"<p>
And if you also do me the great favor of sharing my proposal with
your friends, family and contacts, it would be the bomb! Can
do it next from the social network that you want or from your
email:
</p>"
polls:
all: "All"
no_dates: "no date assigned"

View File

@@ -68,3 +68,5 @@ en:
poll_short_title: Subtitle for polls feature
poll_description: Description for polls feature
poll_link: Additional information link
email_short_title: Subtitle for email feature
email_description: Description for email feature

View File

@@ -510,6 +510,7 @@ es:
resources: Recursos
community: Comunidad
polls: Encuestas
mailing: Correo electrónico
form:
request: Solicitar
create_request:
@@ -586,6 +587,47 @@ es:
add_answer: Añadir respuesta
question_answer_fields:
remove_answer: Borrar respuesta
mailing:
index:
title: Previsualización del correo electrónico
new:
title: Funcionalidad de correo electrónico
mailing_options:
send: Enviar a %{address}
preview: Previsualizar
create:
sent: El e-mail ha sido enviado
mailer:
forward:
subtitle: Si me apoyas, lo conseguiremos.
support_it: Apoyar esta propuesta
share_in: Compartir en
introduction:
<p>¡Hola!</p>
<p>
Te escribo para comunicarte que estoy
participando en Decide Madrid, la plataforma para que
los madrileños y madrileñas podamos decidir qué ciudad
queremos. Y para ello, he creado mi propia propuesta ciudadana
y ahora, ¡voy a necesitar tu apoyo! Pero no te preocupes porque
es muy sencillo.
</p>
<p>
Tan sólo tienes que pinchar en el botón que verás a continuación
'Apoyar esta propuesta' y directamente podrás informarte a cerca de
ella antes de impulsarla. Sólo las propuestas que consigan el
máximo apoyo se llevarán a cabo por parte de nuestro Ayuntamiento,
y he pensado que tú, ¡seguro que me ayudas a lograrlo!
</p>
share_info:
"<p>
Y si además, me haces el gran favor de compartir mi propuesta con
tus amigos, familiares y contactos, ¡ya sería la bomba! Puedes
hacerlo a continuación desde la red social que tú quieras o desde tu
correo electrónico:
</p>"
polls:
all: "Todas"
no_dates: "sin fecha asignada"

View File

@@ -68,3 +68,5 @@ es:
poll_short_title: Subtítulo funcionalidad encuestas
poll_description: Descripción funcionalidad encuestas
poll_link: Enlace información adicional
email_short_title: Subtítulo funcionalidad de correo electrónico
email_description: Descripción funcionalidad de correo electrónico

View File

@@ -22,6 +22,7 @@ resources :proposals do
namespace :dashboard do
resources :polls, except: [:show, :destroy]
resources :mailing, only: [:index, :new, :create]
end
member do

View File

@@ -137,3 +137,5 @@ Setting['proposals.successful_proposal_id'] = nil
Setting['proposals.poll_short_title'] = nil
Setting['proposals.poll_description'] = nil
Setting['proposals.poll_link'] = nil
Setting['proposals.email_short_title'] = nil
Setting['proposals.email_description'] = nil

View File

@@ -15,10 +15,16 @@ namespace :proposal_actions do
desc 'Initialize proposal settings'
task initialize_settings: :environment do
Setting['proposals.successful_proposal_id'] = nil if Setting.find_by(key: 'proposals.successful_proposal_id').nil?
Setting['proposals.poll_short_title'] = nil if Setting.find_by(key: 'proposals.poll_short_title').nil?
Setting['proposals.poll_description'] = nil if Setting.find_by(key: 'proposals.poll_description').nil?
Setting['proposals.poll_link'] = nil if Setting.find_by(key: 'proposals.poll_link').nil?
%w[
proposals.successful_proposal_id
proposals.poll_short_title
proposals.poll_description
proposals.poll_link
proposals.email_short_title
proposals.email_description
].each do |key|
Setting[key] = nil if Setting.find_by(key: key).nil?
end
end
desc 'Simulate successful proposal'

View File

@@ -72,6 +72,7 @@ feature "Proposal's dashboard" do
visit progress_proposal_dashboard_index_path(proposal)
within 'div#available-resources-section' do
expect(page).to have_content('Polls')
expect(page).to have_content('E-mail')
expect(page).to have_content(available.title)
expect(page).to have_content(unavailable.title)
expect(page).to have_content(requested.title)
@@ -99,6 +100,10 @@ feature "Proposal's dashboard" do
expect(page).to have_link('Polls')
end
scenario 'Dashboard has a link to e-mail feature' do
expect(page).to have_link('E-mail')
end
scenario 'Dashboard has a link to resources on main menu' do
feature = create(:dashboard_action, :resource, :active)

View File

@@ -0,0 +1,37 @@
require 'rails_helper'
feature 'Mailing' do
let!(:proposal) { create(:proposal, :draft) }
before do
login_as(proposal.author)
visit new_proposal_dashboard_mailing_path(proposal)
end
scenario 'Has a link to preview the mail' do
expect(page).to have_link('Preview')
end
scenario 'Has a link to send the mail' do
expect(page).to have_link("Send to #{proposal.author.email}")
end
scenario 'User receives feedback after the email is sent' do
click_link "Send to #{proposal.author.email}"
expect(page).to have_content("The email has been sent")
end
scenario 'Preview contains the proposal title' do
click_link 'Preview'
expect(page).to have_content(proposal.title)
end
scenario 'Preview page can send the email as well' do
click_link 'Preview'
expect(page).not_to have_link('Preview')
expect(page).to have_link("Send to #{proposal.author.email}")
end
end

View File

@@ -0,0 +1,6 @@
class DashboardMailerPreview < ActionMailer::Preview
def forward
proposal = Proposal.first
Dashboard::Mailer.forward(proposal)
end
end

View File

@@ -175,6 +175,11 @@ describe Abilities::Common do
it { should be_able_to(:results, poll) }
end
describe 'proposal mailing' do
it { should be_able_to(:manage_mailing, own_proposal) }
it { should_not be_able_to(:manage_mailing, proposal) }
end
describe 'publishing proposals' do
let(:draft_own_proposal) { create(:proposal, :draft, author: user) }