Skip to content

Commit

Permalink
Feature 78649336 - web interface for mailer
Browse files Browse the repository at this point in the history
configure privileged users in Settings
  • Loading branch information
erpe committed Oct 13, 2014
1 parent e211e5a commit 1af41b5
Show file tree
Hide file tree
Showing 39 changed files with 1,047 additions and 3 deletions.
10 changes: 10 additions & 0 deletions app/controllers/application_controller.rb
Expand Up @@ -29,6 +29,16 @@ def after_sign_in_path_for(resource)
request.env['omniauth.origin'] || session[:previous_url] || root_path
end

# see Settings.yml for privileged user
#
def check_privileged
raise ::AgileVentures::AccessDenied.new(current_user, request) unless current_user.is_privileged?
end

rescue_from ::AgileVentures::AccessDenied do |exception|
render file: "#{Rails.root}/public/403.html", status: 403, layout: false
end

private

def request_path_blacklisted?
Expand Down
78 changes: 78 additions & 0 deletions app/controllers/newsletters_controller.rb
@@ -0,0 +1,78 @@
class NewslettersController < ApplicationController
before_action :set_newsletter, only: [:show, :edit, :update, :destroy]

# before-filter defined in application_controller
before_action :check_privileged, only: [:new, :create, :update, :edit, :destroy]

# GET /newsletters
# GET /newsletters.json
def index
@newsletters = Newsletter.all.order('sent_at DESC')
end

# GET /newsletters/1
# GET /newsletters/1.json
def show
end

# GET /newsletters/new
def new
@newsletter = Newsletter.new
end

# GET /newsletters/1/edit
def edit
end

# POST /newsletters
# POST /newsletters.json
def create
@newsletter = Newsletter.new(newsletter_params)

respond_to do |format|
if @newsletter.save
format.html { redirect_to @newsletter, notice: 'Newsletter was successfully created.' }
format.json { render :show, status: :created, location: @newsletter }
else
format.html { render :new }
format.json { render json: @newsletter.errors, status: :unprocessable_entity }
end
end
end

# PATCH/PUT /newsletters/1
# PATCH/PUT /newsletters/1.json
def update
respond_to do |format|
if @newsletter.update(newsletter_params)
format.html { redirect_to @newsletter, notice: 'Newsletter was successfully updated.' }
format.json { render :show, status: :ok, location: @newsletter }
else
format.html { render :edit }
format.json { render json: @newsletter.errors, status: :unprocessable_entity }
end
end
end

# DELETE /newsletters/1
# DELETE /newsletters/1.json
def destroy
@newsletter.destroy
respond_to do |format|
format.html { redirect_to newsletters_url, notice: 'Newsletter was successfully destroyed.' }
format.json { head :no_content }
end
end

private
# Use callbacks to share common setup or constraints between actions.
def set_newsletter
@newsletter = Newsletter.find(params[:id])
end

# Never trust parameters from the scary internet, only allow the white list through.
def newsletter_params
params.require(:newsletter).permit(:title, :body, :subject, :do_send)
end

end
4 changes: 4 additions & 0 deletions app/helpers/application_helper.rb
Expand Up @@ -16,6 +16,10 @@ def resource_name
:user
end

def privileged_visitor?
current_user && current_user.is_privileged?
end

def static_page_path(page)
"/#{StaticPage.url_for_me(page)}"
end
Expand Down
61 changes: 61 additions & 0 deletions app/jobs/send_newsletter.rb
@@ -0,0 +1,61 @@
module SendNewsletter

def self.run
job = Job.new
job.execute
end

class Job

def initialize
@newsletter = Newsletter.unsent.take
end

def execute
if @newsletter
return nil if setup_potential_recipients.empty?
last_user = process_recipients
clean_up(last_user)
else
return nil
end
true
end

private

def setup_potential_recipients
users = User.mail_receiver.order('id ASC').where('id >?', @newsletter.last_user_id)
@total_recipients = users.size
@users = users.limit(Newsletter.chunk_size)
end

def select_receiver
puts "selecting recipients"

end

# returnes last user processed
#
def process_recipients
last_user = nil
@users.each do |user|
Mailer.send_newsletter(user, @newsletter).deliver
last_user = user
end
last_user
end

def clean_up(last_user)
if @total_recipients <= Newsletter.chunk_size
@newsletter.update_attributes( was_sent: true,
last_user_id: last_user.id,
sent_at: Time.now )
else
@newsletter.update_attribute(:last_user_id, last_user.id)
end
end
end


end
6 changes: 6 additions & 0 deletions app/mailers/mailer.rb
Expand Up @@ -12,4 +12,10 @@ def hire_me_form(user, hire_me_form)
subject = ['message from', @form[:name]].join(' ')
mail(to: @user.email, reply_to: @form[:email], from: @form[:email], subject: subject)
end

def send_newsletter(user, newsletter)
@user = user
@newsletter = newsletter
mail(to: user.email, subject: newsletter.subject)
end
end
41 changes: 41 additions & 0 deletions app/models/newsletter.rb
@@ -0,0 +1,41 @@
class Newsletter < ActiveRecord::Base
validates :subject, :title, :body, presence: true
after_save :send_mailings, if: :instantly_sendable?
before_create :init_last_user_id
scope :unsent, -> { where(do_send: true, was_sent: false) }
scope :in_process, -> {
where('do_send = ? AND was_sent = ? AND last_user_id > ?', true, false, 0)
}

cattr_reader :send_as
cattr_reader :chunk_size

# sent via sendGrid - there is a limit 200 mailings/day
# so we can not send it at once but have to split in chunks
# to be send out by heroku scheduler
#
@@send_as = Settings.newsletter.send_as
@@chunk_size = Settings.newsletter.chunk_size

private

def send_mailings
_last_user = nil
User.mail_receiver.order('id ASC').find_in_batches(batch_size: 100).each do |group|
group.each do |user|
Mailer.send_newsletter(user, self).deliver
_last_user = user
end
end
update_attributes(was_sent: true, sent_at: Time.now, last_user_id: _last_user.id)
end

def instantly_sendable?
do_send == true && was_sent == false && self.send_as == :instant
end

def init_last_user_id
self.last_user_id = 0
end

end
6 changes: 5 additions & 1 deletion app/models/user.rb
Expand Up @@ -34,6 +34,7 @@ class User < ActiveRecord::Base
has_many :status

accepts_nested_attributes_for :status
scope :mail_receiver, -> { where(receive_mailings: true) }

self.per_page = 30

Expand Down Expand Up @@ -83,6 +84,10 @@ def gravatar_url(options={})
end
end

def is_privileged?
Settings.privileged_users.include?(email)
end

def self.search(params)
where(display_profile: true)
.order(:created_at)
Expand All @@ -102,5 +107,4 @@ def online?
def send_slack_invite
SlackInviteJob.new.async.perform(email)
end

end
4 changes: 4 additions & 0 deletions app/presenters/users/user_presenter.rb
Expand Up @@ -71,5 +71,9 @@ def status
def status?
user.status.count > 0
end

def can_create_newsletter?
Settings.privileged_users.include?(user.email)
end

end
19 changes: 19 additions & 0 deletions app/views/mailer/send_newsletter.html.erb
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
</head>
<body>
<h3><%= @newsletter.title %></h3>

<%= simple_format(@newsletter.body) %>

<p>
<strong>The AgileVentures.org Team</strong>
<br/>
<small>You are receiving this email because you registered
at <a href="http://www.agileventures.org/">www.agileventures.org</a>. If you wish to be removed from this mailing list, adjust your profile settings at <a href="http://www.agileventures.org">www.agileventures.org</a>.
</small>
</p>
</body>
</html>
10 changes: 10 additions & 0 deletions app/views/mailer/send_newsletter.text.erb
@@ -0,0 +1,10 @@
Hi <%= @user.display_name %>,

<%= @newsletter.title %>
====================================================================================

<%= @newsletter.body %>

--
You are receiving this email because you registered at http://www.agileventures.org. If you wish to be removed from this mailing list, adjust your profile settings as http://www.agileventures.org.

39 changes: 39 additions & 0 deletions app/views/newsletters/_form.html.erb
@@ -0,0 +1,39 @@
<%= form_for(@newsletter) do |f| %>
<% if @newsletter.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@newsletter.errors.count, "error") %> prohibited this newsletter from being saved:</h2>

<ul>
<% @newsletter.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>

<div class='form-group'>
<%= f.label :subject %>
<%= f.text_field :subject, class: 'form-control', required: true, placeholder: 'the subject as described in RFC 2822' %>
</div>
<div class='form-group'>
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control', required: true, placeholder: 'A friendly Title' %>
</div>
<div class="form-group">
<%= f.label :body %>
<%= f.text_area :body, rows: 25, class: 'form-control', required: true, placeholder: 'Here your content - right now just simple_format' %>
</div>
<% unless @newsletter.was_sent %>
<div class='form-group'>
<%= f.label :do_send do %>
<%= f.check_box :do_send %> &nbsp; Start send this Newsletter now
<% end %>
<p class='help-text'>
When you check this check-box, the newsletter will be sent immediately after save - otherwise its kind of a draft...
</p>
</div>
<% end %>
<div class="form-actions">
<%= f.submit "#{@newsletter.new_record? ? 'Create' : 'Update'}", class: 'btn btn-primary'%>
</div>
<% end %>
6 changes: 6 additions & 0 deletions app/views/newsletters/edit.html.erb
@@ -0,0 +1,6 @@
<h1>Editing newsletter</h1>

<%= render 'form' %>
<%= link_to 'Show', @newsletter %> |
<%= link_to 'Back', newsletters_path %>
29 changes: 29 additions & 0 deletions app/views/newsletters/index.html.erb
@@ -0,0 +1,29 @@
<h1>Listing newsletters</h1>

<table class='table table-striped table-hover'>
<thead>
<tr>
<th>Subject</th>
<th>Title</th>
<th>Sent at</th>
<th colspan="3"></th>
</tr>
</thead>

<tbody>
<% @newsletters.each do |newsletter| %>
<tr class=<%= 'warning' unless newsletter.was_sent? %>>
<td><%= truncate(newsletter.subject, length: 20 ) %></td>
<td><%= truncate(newsletter.title, length: 20) %></td>
<td><%= l(newsletter.sent_at, format: :short) if newsletter.sent_at %></td>
<td><%= link_to 'Show', newsletter %></td>
<td><%= link_to 'Edit', edit_newsletter_path(newsletter) if privileged_visitor? %></td>
<td><%= link_to 'Destroy', newsletter, method: :delete, data: { confirm: 'Are you sure?' } if privileged_visitor? %></td>
</tr>
<% end %>
</tbody>
</table>

<br>

<%= link_to 'New Newsletter', new_newsletter_path if privileged_visitor? %>
5 changes: 5 additions & 0 deletions app/views/newsletters/new.html.erb
@@ -0,0 +1,5 @@
<h1>Create a new Newsletter</h1>

<%= render 'form' %>
<%= link_to 'Back', newsletters_path %>

0 comments on commit 1af41b5

Please sign in to comment.