msg 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +9 -0
- data/Rakefile +35 -0
- data/app/assets/images/msg/message.png +0 -0
- data/app/assets/images/msg/ping.png +0 -0
- data/app/assets/images/msg/sending.png +0 -0
- data/app/assets/javascripts/lib/jquery.peity.js +261 -0
- data/app/assets/javascripts/msg.js.coffee +6 -0
- data/app/assets/stylesheets/msg.css.sass +218 -0
- data/app/controllers/msg/bounces_controller.rb +67 -0
- data/app/controllers/msg/engine_controller.rb +23 -0
- data/app/controllers/msg/envelopes_controller.rb +22 -0
- data/app/controllers/msg/messages_controller.rb +85 -0
- data/app/controllers/msg/sendings_controller.rb +58 -0
- data/app/helpers/msg/msg_helper.rb +40 -0
- data/app/mailers/msg/devise_mailer.rb +20 -0
- data/app/mailers/msg/msg_mailer.rb +23 -0
- data/app/models/msg/bounce.rb +19 -0
- data/app/models/msg/envelope.rb +56 -0
- data/app/models/msg/message.rb +26 -0
- data/app/models/msg/sending.rb +54 -0
- data/app/views/layouts/msg/default.html.haml +30 -0
- data/app/views/layouts/msg/email.html.haml +10 -0
- data/app/views/msg/bounces/_listing.html.haml +5 -0
- data/app/views/msg/bounces/_report.html.haml +10 -0
- data/app/views/msg/bounces/index.html.haml +5 -0
- data/app/views/msg/devise_mailer/confirmation_instructions.en.html.haml +1 -0
- data/app/views/msg/devise_mailer/reset_password_instructions.en.html.haml +1 -0
- data/app/views/msg/envelopes/_listing.html.haml +5 -0
- data/app/views/msg/messages/_action_menu.html.haml +10 -0
- data/app/views/msg/messages/_form.html.haml +38 -0
- data/app/views/msg/messages/_instructions.html.haml +28 -0
- data/app/views/msg/messages/_message.html.haml +11 -0
- data/app/views/msg/messages/_saved_messages.html.haml +2 -0
- data/app/views/msg/messages/_transactional_messages.html.haml +3 -0
- data/app/views/msg/messages/edit.html.haml +7 -0
- data/app/views/msg/messages/index.html.haml +23 -0
- data/app/views/msg/messages/new.html.haml +7 -0
- data/app/views/msg/messages/preview.html.haml +4 -0
- data/app/views/msg/messages/show.html.haml +25 -0
- data/app/views/msg/msg_mailer/message_in_envelope.html.haml +2 -0
- data/app/views/msg/sendings/_form.html.haml +45 -0
- data/app/views/msg/sendings/_listing.html.haml +17 -0
- data/app/views/msg/sendings/_report.html.haml +8 -0
- data/app/views/msg/sendings/_sending.html.haml +22 -0
- data/app/views/msg/sendings/_sendings.html.haml +2 -0
- data/app/views/msg/sendings/index.html.haml +8 -0
- data/app/views/msg/sendings/new.html.haml +9 -0
- data/app/views/msg/sendings/review.html.haml +2 -0
- data/app/views/msg/sendings/show.html.haml +50 -0
- data/app/views/msg/shared/_toolbar.html.haml +17 -0
- data/config/cucumber.yml +8 -0
- data/config/locales/en.yml +76 -0
- data/config/routes.rb +26 -0
- data/db/migrate/20130320141926_msg_data.rb +54 -0
- data/db/migrate/20130327134754_sending_circumstances.rb +6 -0
- data/lib/msg.rb +88 -0
- data/lib/msg/engine.rb +23 -0
- data/lib/msg/receivers.rb +64 -0
- data/lib/msg/version.rb +3 -0
- data/lib/tasks/cucumber.rake +65 -0
- data/lib/tasks/msg_tasks.rake +4 -0
- data/spec/controllers/msg/bounces_controller_spec.rb +48 -0
- data/spec/controllers/msg/envelopes_controller_spec.rb +22 -0
- data/spec/controllers/msg/messages_controller_spec.rb +9 -0
- data/spec/controllers/msg/sendings_controller_spec.rb +47 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/user.rb +14 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +59 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +41 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/devise.rb +285 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +9 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/2013032210540_users.rb +49 -0
- data/spec/dummy/db/migrate/20130326093048_msg_data.msg.rb +55 -0
- data/spec/dummy/db/schema.rb +96 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +143 -0
- data/spec/dummy/log/test.log +1022 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/factories/msg/bounces.rb +9 -0
- data/spec/factories/msg/envelopes.rb +10 -0
- data/spec/factories/msg/messages.rb +10 -0
- data/spec/factories/msg/sendings.rb +7 -0
- data/spec/factories/users.rb +11 -0
- data/spec/helpers/msg/msg_helper_spec.rb +17 -0
- data/spec/lib/msg_spec.rb +15 -0
- data/spec/mailers/msg/devise_mailer_spec.rb +21 -0
- data/spec/mailers/msg/msg_mailer_spec.rb +36 -0
- data/spec/models/msg/bounce_spec.rb +19 -0
- data/spec/models/msg/envelope_spec.rb +62 -0
- data/spec/models/msg/message_spec.rb +19 -0
- data/spec/models/msg/sending_spec.rb +10 -0
- data/spec/routing/sendings_routing_spec.rb +31 -0
- data/spec/spec_helper.rb +70 -0
- metadata +446 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module Msg
|
4
|
+
class BouncesController < Msg::EngineController
|
5
|
+
respond_to :json
|
6
|
+
|
7
|
+
# this is pinged from Amazon SNS with a JSON body something like this:
|
8
|
+
#
|
9
|
+
# {
|
10
|
+
# "notificationType":"Bounce",
|
11
|
+
# "bounce":{
|
12
|
+
# "bounceType":"Permanent",
|
13
|
+
# "reportingMTA":"dns; email.example.com",
|
14
|
+
# "bouncedRecipients":[
|
15
|
+
# {
|
16
|
+
# "emailAddress":"username@example.com",
|
17
|
+
# "status":"5.1.1",
|
18
|
+
# "action":"failed",
|
19
|
+
# "diagnosticCode":"smtp; 550 5.1.1 <username@example.com>... User"
|
20
|
+
# }
|
21
|
+
# ],
|
22
|
+
# "bounceSubType":"General",
|
23
|
+
# "timestamp":"2012-06-19T01:07:52.000Z",
|
24
|
+
# "feedbackId":"00000138111222aa-33322211-cccc-cccc-cccc-ddddaaaa068a-000000"
|
25
|
+
# },
|
26
|
+
# "mail":{
|
27
|
+
# "timestamp":"2012-06-19T01:05:45.000Z",
|
28
|
+
# "source":"sender@example.com",
|
29
|
+
# "messageId":"00000138111222aa-33322211-cccc-cccc-cccc-ddddaaaa0680-000000",
|
30
|
+
# "destination":[
|
31
|
+
# "username@example.com"
|
32
|
+
# ]
|
33
|
+
# }
|
34
|
+
# }
|
35
|
+
#
|
36
|
+
#
|
37
|
+
# When the subscription is first set up they will also POST us a SubscriptionConfirmation,
|
38
|
+
# upon which we have to GET the given url to confirm that we can follow orders.
|
39
|
+
#
|
40
|
+
def create
|
41
|
+
if request.headers['x-amz-sns-message-type'] == 'SubscriptionConfirmation'
|
42
|
+
response = HTTParty.get(params['SubscribeURL'])
|
43
|
+
head :ok
|
44
|
+
|
45
|
+
else
|
46
|
+
mail = params['Message']['mail']
|
47
|
+
bounce = params['Message']['bounce']
|
48
|
+
if envelope = Msg::Envelope.find_by_email_id(mail['messageId'])
|
49
|
+
envelope.bounces.create({
|
50
|
+
:bounce_type => bounce['bounceType'],
|
51
|
+
:bounce_subtype => bounce['bounceSubType'],
|
52
|
+
:reporter => bounce['reportingMTA'],
|
53
|
+
:raw_message => JSON.dump(bounce)
|
54
|
+
})
|
55
|
+
end
|
56
|
+
head :ok
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
protected
|
61
|
+
|
62
|
+
def build_bounce
|
63
|
+
@bounce = Msg::Bounce.new(params[:bounce])
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Msg
|
2
|
+
class EngineController < ::ApplicationController
|
3
|
+
|
4
|
+
before_filter :authenticate_user!
|
5
|
+
before_filter :require_admin!
|
6
|
+
layout :no_layout_if_pjax
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
def require_admin!
|
11
|
+
raise Msg::PermissionDenied unless current_user.admin?
|
12
|
+
end
|
13
|
+
|
14
|
+
def no_layout_if_pjax
|
15
|
+
if request.headers['X-PJAX']
|
16
|
+
false
|
17
|
+
else
|
18
|
+
Msg.layout
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Msg
|
2
|
+
class EnvelopesController < Msg::EngineController
|
3
|
+
respond_to :png
|
4
|
+
skip_before_filter :authenticate_user!, :only => [:show]
|
5
|
+
skip_before_filter :require_admin!, :only => [:show]
|
6
|
+
before_filter :get_envelope, :only => [:show]
|
7
|
+
|
8
|
+
# envelopes#show is pinged when a message is opened.
|
9
|
+
#
|
10
|
+
def show
|
11
|
+
@envelope.open!
|
12
|
+
redirect_to view_context.image_path('msg/ping.png')
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def get_envelope
|
18
|
+
@envelope = Msg::Envelope.find(params[:id])
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Msg
|
2
|
+
class MessagesController < Msg::EngineController
|
3
|
+
respond_to :html, :js
|
4
|
+
|
5
|
+
before_filter :get_message, :only => [:show, :edit, :update, :destroy, :preview]
|
6
|
+
before_filter :build_message, :only => [:new, :create]
|
7
|
+
before_filter :get_transactional_messages, :only => [:index, :transactional]
|
8
|
+
before_filter :get_saved_messages, :only => [:index, :saved]
|
9
|
+
before_filter :get_receiver, :only => [:show, :preview]
|
10
|
+
|
11
|
+
def index
|
12
|
+
respond_with @saved_messages, @transactional_messages
|
13
|
+
end
|
14
|
+
|
15
|
+
def saved
|
16
|
+
respond_with @saved_messages
|
17
|
+
end
|
18
|
+
|
19
|
+
def transactional
|
20
|
+
respond_with @transactional_messages
|
21
|
+
end
|
22
|
+
|
23
|
+
def show
|
24
|
+
respond_with @message
|
25
|
+
end
|
26
|
+
|
27
|
+
def preview
|
28
|
+
respond_with @message, :layout => Msg.email_layout
|
29
|
+
end
|
30
|
+
|
31
|
+
def new
|
32
|
+
respond_with @message
|
33
|
+
end
|
34
|
+
|
35
|
+
def create
|
36
|
+
@message.update_attributes(params[:message])
|
37
|
+
respond_with @message
|
38
|
+
end
|
39
|
+
|
40
|
+
def edit
|
41
|
+
respond_with @message
|
42
|
+
end
|
43
|
+
|
44
|
+
def update
|
45
|
+
@message.update_attributes(params[:message])
|
46
|
+
respond_with @message
|
47
|
+
end
|
48
|
+
|
49
|
+
def destroy
|
50
|
+
@message.destroy
|
51
|
+
head :ok
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def build_message
|
57
|
+
@message = Msg::Message.new(params[:message])
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_message
|
61
|
+
@message = Msg::Message.find(params[:id])
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_transactional_messages
|
65
|
+
@transactional_messages = Msg::Message.transactional
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_saved_messages
|
69
|
+
@show = params[:show] || 10
|
70
|
+
@page = params[:page] || 1
|
71
|
+
@saved_messages = Msg::Message.saved.page(@page).per(@show)
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_receiver
|
75
|
+
klass = params[:receiver_type] || Msg.receiving_classes.first
|
76
|
+
if id = params[:receiver_id]
|
77
|
+
@receiver = klass.classify.constantize.find(id)
|
78
|
+
else
|
79
|
+
@receiver = klass.classify.constantize.first
|
80
|
+
end
|
81
|
+
raise ActiveRecord::RecordNotFound, "Cannot find a valid receiver for whom to preview message." unless @receiver
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Msg
|
2
|
+
class SendingsController < Msg::EngineController
|
3
|
+
respond_to :html, :js
|
4
|
+
|
5
|
+
before_filter :get_message, :only => [:new, :create]
|
6
|
+
before_filter :get_sending, :only => [:show, :review]
|
7
|
+
before_filter :build_sending, :only => [:new, :create]
|
8
|
+
before_filter :get_sendings, :only => [:index]
|
9
|
+
|
10
|
+
def index
|
11
|
+
respond_with @sendings do |format|
|
12
|
+
format.js { render :partial => "report"}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def show
|
17
|
+
respond_with @sending
|
18
|
+
end
|
19
|
+
|
20
|
+
def review
|
21
|
+
respond_with @sending, :layout => Msg.email_layout
|
22
|
+
end
|
23
|
+
|
24
|
+
def new
|
25
|
+
respond_with @sending
|
26
|
+
end
|
27
|
+
|
28
|
+
def create
|
29
|
+
@sending.update_attributes(params[:sending])
|
30
|
+
respond_with @sending
|
31
|
+
end
|
32
|
+
|
33
|
+
def destroy
|
34
|
+
@sending.destroy
|
35
|
+
head :ok
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def get_message
|
41
|
+
@message = Msg::Message.find(params[:message_id])
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_sending
|
45
|
+
@sending = @message.sendings.build
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_sending
|
49
|
+
@sending = Msg::Sending.find(params[:id])
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_sendings
|
53
|
+
@show = params[:show] || 10
|
54
|
+
@page = params[:page] || 1
|
55
|
+
@sendings = Msg::Sending.order("created_at DESC").page(@page).per(@show)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Msg
|
2
|
+
module MsgHelper
|
3
|
+
def shorten(text, length=64)
|
4
|
+
length = length[:length] if length.is_a?(Hash)
|
5
|
+
truncate(strip_tags(text), {:length => length, :separator => " "})
|
6
|
+
end
|
7
|
+
|
8
|
+
def action_menulink(thing, html_options={})
|
9
|
+
classname = thing.class.to_s.downcase.underscore.split('/').last
|
10
|
+
html_options.reverse_merge!({
|
11
|
+
:class => "",
|
12
|
+
:data => {:menu => "#{classname}_#{thing.id}"}
|
13
|
+
})
|
14
|
+
html_options[:class] << " menu"
|
15
|
+
link_to t(:edit), "#", html_options if editable?(thing)
|
16
|
+
end
|
17
|
+
|
18
|
+
def action_menu(thing, locals={})
|
19
|
+
if editable?(thing)
|
20
|
+
type = thing.class.to_s.downcase.underscore
|
21
|
+
classname = type.split('/').last
|
22
|
+
locals[classname.to_sym] = thing
|
23
|
+
render :partial => "#{type.pluralize}/action_menu", :locals => locals
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def visible?(thing)
|
28
|
+
admin? || privileged? || current_user.can_see?(thing)
|
29
|
+
end
|
30
|
+
|
31
|
+
def editable?(thing)
|
32
|
+
admin? || current_user == thing.created_by
|
33
|
+
end
|
34
|
+
|
35
|
+
def deletable?(thing)
|
36
|
+
admin? || current_user == thing.created_by
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Msg
|
2
|
+
class DeviseMailer < Devise::Mailer
|
3
|
+
default from: Msg.default_from_address, :bcc => Msg.email_bcc
|
4
|
+
layout Msg.email_layout
|
5
|
+
|
6
|
+
def confirmation_instructions(receiver, opts={})
|
7
|
+
@message = Msg::Message.find_by_function('confirmation_instructions')
|
8
|
+
@contents = @message.render_for(receiver)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def reset_password_instructions(receiver, opts={})
|
13
|
+
@message = Msg::Message.find_by_function('reset_password_instructions')
|
14
|
+
@contents = @message.render_for(receiver)
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Msg
|
2
|
+
class MsgMailer < ActionMailer::Base
|
3
|
+
default from: Msg.default_from, :bcc => Msg.email_bcc
|
4
|
+
layout Msg.email_layout
|
5
|
+
|
6
|
+
# we send all messages through SES and use SNS to notify of bounces, so all the
|
7
|
+
# return-path and VERP and other gubbins that we would normally need can be omitted
|
8
|
+
#
|
9
|
+
def message_in_envelope(envelope)
|
10
|
+
headers['Message-ID'] = envelope.email_id
|
11
|
+
@envelope = envelope
|
12
|
+
@message = envelope.message
|
13
|
+
@receiver = envelope.receiver
|
14
|
+
@contents = envelope.contents
|
15
|
+
mail({
|
16
|
+
:to => %{"#{@receiver.name}" <#{@receiver.email}>},
|
17
|
+
:from => envelope.from_address,
|
18
|
+
:subject => envelope.subject
|
19
|
+
})
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Msg
|
2
|
+
class Bounce < ActiveRecord::Base
|
3
|
+
attr_accessible :envelope, :bounce_type, :bounce_subtype, :raw_message, :reporter
|
4
|
+
belongs_to :envelope
|
5
|
+
validates :envelope, :presence => true
|
6
|
+
|
7
|
+
scope :fatal, where(:bounce_type => "Permanent")
|
8
|
+
scope :transient, where(:bounce_type => "Transient")
|
9
|
+
|
10
|
+
def fatal?
|
11
|
+
bounce_type == 'Permanent'
|
12
|
+
end
|
13
|
+
|
14
|
+
def transient?
|
15
|
+
bounce_type == 'Transient'
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Msg
|
2
|
+
class Envelope < ActiveRecord::Base
|
3
|
+
attr_accessible :receiver, :sending
|
4
|
+
|
5
|
+
belongs_to :sending
|
6
|
+
belongs_to :receiver, :polymorphic => true
|
7
|
+
has_many :bounces
|
8
|
+
|
9
|
+
validates :receiver, :presence => true
|
10
|
+
validates :sending, :presence => true
|
11
|
+
after_create :send_email
|
12
|
+
|
13
|
+
scope :opened, where("opened_at IS NOT NULL")
|
14
|
+
|
15
|
+
scope :bounced, select("msg_envelopes.*")
|
16
|
+
.joins("INNER JOIN msg_bounces as mb ON mb.envelope_id = msg_envelopes.id")
|
17
|
+
.having("count(mb.id) > 0")
|
18
|
+
|
19
|
+
def message
|
20
|
+
sending.message
|
21
|
+
end
|
22
|
+
|
23
|
+
def open!
|
24
|
+
update_column(:opened_at, Time.now)
|
25
|
+
end
|
26
|
+
|
27
|
+
def status
|
28
|
+
if opened_at?
|
29
|
+
"read"
|
30
|
+
elsif bounces.any?
|
31
|
+
"bounced"
|
32
|
+
else
|
33
|
+
"unread"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def send_email
|
40
|
+
# Record sending parameters for later reference. The message or receiver properties might change after this is sent.
|
41
|
+
self.email_id = "#{self.id}@#{Msg.sending_domain}"
|
42
|
+
self.subject = message.subject
|
43
|
+
self.from_address = message.from
|
44
|
+
self.to_address = receiver.email
|
45
|
+
# render the message for our receiver
|
46
|
+
self.contents = message.render_for(receiver)
|
47
|
+
# send it
|
48
|
+
Msg::MsgMailer.message_in_envelope(self).deliver
|
49
|
+
# note sending time
|
50
|
+
self.sent_at = Time.now
|
51
|
+
# and save our changes
|
52
|
+
self.save!
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'mustache'
|
2
|
+
|
3
|
+
module Msg
|
4
|
+
class Message < ActiveRecord::Base
|
5
|
+
attr_accessible :subject, :body, :function, :description, :transactional, :saved, :from_name, :from_address
|
6
|
+
|
7
|
+
has_many :sendings
|
8
|
+
belongs_to :created_by, :class_name => Msg.user_class
|
9
|
+
|
10
|
+
scope :transactional, where(:transactional => true)
|
11
|
+
scope :saved, where(:saved => true, :transactional => false)
|
12
|
+
scope :unsaved, where(:saved => false)
|
13
|
+
|
14
|
+
def from
|
15
|
+
name = from_name? ? from_name : Msg.default_from_name
|
16
|
+
address = from_address? ? from_address : Msg.default_from_address
|
17
|
+
"#{name} <#{address}>"
|
18
|
+
end
|
19
|
+
|
20
|
+
def render_for(receiver)
|
21
|
+
values = receiver.for_email.reverse_merge(Msg.email_values)
|
22
|
+
Mustache.render(body, values)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|