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,54 @@
|
|
1
|
+
module Msg
|
2
|
+
class Sending < ActiveRecord::Base
|
3
|
+
attr_accessible :message_id, :envelopes_attributes
|
4
|
+
|
5
|
+
belongs_to :message
|
6
|
+
belongs_to :created_by, :class_name => Msg.user_class
|
7
|
+
has_many :envelopes, :dependent => :destroy
|
8
|
+
|
9
|
+
def receivers=(receivers)
|
10
|
+
receivers.each do |rec|
|
11
|
+
self.envelopes.build(:receiver => rec, :sending => self)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def statistics
|
16
|
+
sent = envelopes.count || 0
|
17
|
+
bounced = envelopes.bounced.count || 0
|
18
|
+
read = envelopes.opened.count || 0
|
19
|
+
unread = sent-read-bounced
|
20
|
+
[unread, read, bounced]
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.add_receiver_hooks(klass, options)
|
24
|
+
key = klass.to_s.underscore
|
25
|
+
|
26
|
+
define_method :"#{key}_group" do
|
27
|
+
self.receiving_group if self.receiving_class == key
|
28
|
+
end
|
29
|
+
|
30
|
+
# class_group= is called from the SendingsController and given the _name_ of a messaging group,
|
31
|
+
# we get the designated proc from the class messaging rules, then call it to get an array of receivers
|
32
|
+
#
|
33
|
+
define_method :"#{key}_group=" do |name|
|
34
|
+
self.receiving_class = key
|
35
|
+
self.receiving_group = name
|
36
|
+
self.receivers = klass.messaging_groups[name.to_sym].call unless name == 'selected'
|
37
|
+
end
|
38
|
+
attr_accessible :"#{key}_group"
|
39
|
+
|
40
|
+
define_method :"#{key}_receiver_ids" do
|
41
|
+
self.envelopes.map(&:receiver_id) if self.receiving_class == key
|
42
|
+
end
|
43
|
+
attr_accessible :"#{key}_receiver_ids"
|
44
|
+
|
45
|
+
# class_receiver_ids= is called from the SendingsController and given a list of receiver ids of this class.
|
46
|
+
# they are instantiated and passed to receivers=
|
47
|
+
#
|
48
|
+
define_method :"#{key}_receiver_ids=" do |ids|
|
49
|
+
self.receivers = klass.find(ids)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
!!!
|
2
|
+
%html{:lang => 'en'}
|
3
|
+
%head
|
4
|
+
%title
|
5
|
+
- if content_for?(:pagetitle)
|
6
|
+
= yield :pagetitle
|
7
|
+
\|
|
8
|
+
= t(:msg)
|
9
|
+
|
10
|
+
= stylesheet_link_tag "msg"
|
11
|
+
= javascript_include_tag "msg"
|
12
|
+
= content_for :head
|
13
|
+
= csrf_meta_tags
|
14
|
+
|
15
|
+
%body
|
16
|
+
#header
|
17
|
+
%p.warning
|
18
|
+
= t :please_set_layout
|
19
|
+
|
20
|
+
#page
|
21
|
+
#content
|
22
|
+
= yield
|
23
|
+
#margin
|
24
|
+
= content_for :margin
|
25
|
+
|
26
|
+
#flashes
|
27
|
+
%p.notice= notice
|
28
|
+
%p.alert= alert
|
29
|
+
|
30
|
+
#mask
|
@@ -0,0 +1,10 @@
|
|
1
|
+
- bounces ||= @bounces || Msg::Bounce.order('created_at DESC').limit(5)
|
2
|
+
|
3
|
+
#bouncebox{:data => {:refreshable => true, :url => msg.bounces_path(:format => :js)}}
|
4
|
+
- if bounces.any?
|
5
|
+
%h3
|
6
|
+
= link_to t(:bounce_report), msg.bounces_url
|
7
|
+
|
8
|
+
%ul.bounces
|
9
|
+
= render :partial => "msg/bounces/listing", :collection => bounces
|
10
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
= sanitize(@contents.html_safe, :tags => Msg.tags_allowed_in_email, :attributes => Msg.attributes_allowed_in_email)
|
@@ -0,0 +1 @@
|
|
1
|
+
= sanitize(@contents.html_safe, :tags => Msg.tags_allowed_in_email, :attributes => Msg.attributes_allowed_in_email)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
- if editable?(message)
|
2
|
+
.menu{:data => {:for => "message_#{message.id}"}}
|
3
|
+
%ul.actions
|
4
|
+
%li
|
5
|
+
= link_to t(:edit_message), msg.edit_message_url(message), :class => 'edit', :data => {:action => "popup", :affected => "#message_#{message.id}, #sentbox", :group => "messages"}
|
6
|
+
%li
|
7
|
+
= link_to t(:preview_and_send), msg.message_url(message), :class => "edit", :data => {:action => "popup", :affected => "#sentbox", :group => "messages"}
|
8
|
+
- unless message.transactional?
|
9
|
+
%li
|
10
|
+
= link_to t(:delete_message), msg.message_url(message), :method => 'delete', :class => 'delete', :data => {:action => "remove", :removed => "#message_#{message.id}", :confirm => t(:confirm_delete_message, :subject => message.subject)}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
= form_for @message, :html => {:class => 'edit message', :remote => true, :data => {:type => :html}} do |f|
|
2
|
+
%p.subject
|
3
|
+
= f.text_field :subject, :class => 'name', :placeholder => t(:message_subject)
|
4
|
+
|
5
|
+
%p.sender.messagedetail
|
6
|
+
= f.text_field :from_name, :class => 'from_name', :placeholder => t(:from) + ": " + Msg.default_from_name
|
7
|
+
= f.text_field :from_address, :class => 'from_address', :placeholder => Msg.default_from_address
|
8
|
+
|
9
|
+
%p.function.messagedetail
|
10
|
+
%span.transactional_detail
|
11
|
+
= f.text_field :function, :class => "function", :placeholder => t(:message_function)
|
12
|
+
= f.check_box :transactional, :data => {:action => "reveal", :affected => ".transactional_detail", :converse => ".saved"}
|
13
|
+
= f.label :transactional, t(:transactional_message)
|
14
|
+
%span.formnote
|
15
|
+
= t :transactional_message_note
|
16
|
+
|
17
|
+
.messagebody.wysihtml#e1
|
18
|
+
%p.show_details
|
19
|
+
= link_to t(:more_detail), "#", :class => "expander", :data => {:action => "toggle", :affected => ".messagedetail"}
|
20
|
+
|
21
|
+
= render "msg/messages/instructions"
|
22
|
+
.toolbar#t1
|
23
|
+
= render 'msg/shared/toolbar'
|
24
|
+
= f.text_area :body, :id => 'd1', :class => "body"
|
25
|
+
|
26
|
+
%p.saved
|
27
|
+
= f.check_box :saved, :data => {:action => "reveal", :affected => ".saved_detail"}
|
28
|
+
= f.label :saved, t(:save_for_reuse)
|
29
|
+
%span.formnote
|
30
|
+
= t :saved_note
|
31
|
+
%span.saved_detail
|
32
|
+
= f.text_field :description, :class => "description", :placeholder => t(:message_description)
|
33
|
+
|
34
|
+
.buttons
|
35
|
+
= f.submit t(:save_and_preview)
|
36
|
+
= t :or
|
37
|
+
= link_to t(:cancel), "/", :class => 'cancel'
|
38
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
.instructions
|
2
|
+
%p
|
3
|
+
Use double braces to insert these computed values into each message:
|
4
|
+
%ul
|
5
|
+
%li
|
6
|
+
%strong
|
7
|
+
{{formal_name}}
|
8
|
+
the recipient's full name and title
|
9
|
+
%li
|
10
|
+
%strong
|
11
|
+
{{informal_name}}
|
12
|
+
forename, if we know it, or full name without title
|
13
|
+
%li
|
14
|
+
%strong
|
15
|
+
{{email}}
|
16
|
+
the receiving email address
|
17
|
+
%li
|
18
|
+
%strong
|
19
|
+
{{sign_in_url}}
|
20
|
+
the address of the login page
|
21
|
+
%li
|
22
|
+
%strong
|
23
|
+
{{confirmation_url}}
|
24
|
+
a confirmation address for use in invitations
|
25
|
+
%li
|
26
|
+
%strong
|
27
|
+
{{password_reset_url}}
|
28
|
+
a reset address for use in reminder messages
|
@@ -0,0 +1,11 @@
|
|
1
|
+
- message ||= @message
|
2
|
+
|
3
|
+
.message{:id => "message_#{message.id}", :data => {:refreshable => true, :url => message_path(message, :format => :js)} }
|
4
|
+
%h2.name
|
5
|
+
= link_to shorten(message.subject, 54), msg.message_url(message), :class => "message", :data => {:action => "popup", :affected => "#sentbox", :group => "messages"}
|
6
|
+
= action_menulink(message)
|
7
|
+
= action_menu(message)
|
8
|
+
%p.description
|
9
|
+
= message.description
|
10
|
+
%p.excerpt
|
11
|
+
= shorten(message.body, 128)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#messages
|
2
|
+
|
3
|
+
%p.action
|
4
|
+
= link_to t(:create_message), msg.new_message_url, :class => "add", :data => {:action => "popup", :affected => "#saved_messages"}
|
5
|
+
|
6
|
+
%h2.section
|
7
|
+
= t :transactional_messages
|
8
|
+
|
9
|
+
= render "msg/messages/transactional_messages"
|
10
|
+
|
11
|
+
%h2.section
|
12
|
+
= t :saved_messages
|
13
|
+
%span.action
|
14
|
+
= link_to t(:create_message), msg.new_message_url, :class => "add minimal", :data => {:action => "popup", :affected => "#saved_messages"}
|
15
|
+
= render "msg/messages/saved_messages"
|
16
|
+
|
17
|
+
|
18
|
+
-content_for :margin do
|
19
|
+
= render :partial => "msg/bounces/report"
|
20
|
+
= render :partial => "msg/sendings/report"
|
21
|
+
|
22
|
+
-content_for :title do
|
23
|
+
= t :messages
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#preview_message
|
2
|
+
.header
|
3
|
+
= link_to "X", '#', :class => "closer", :data => {:action => "close"}
|
4
|
+
%h2
|
5
|
+
= t :preview_message
|
6
|
+
.headers
|
7
|
+
%p
|
8
|
+
%span.field
|
9
|
+
= t(:subject).titlecase + ":"
|
10
|
+
%strong
|
11
|
+
= @message.subject
|
12
|
+
%p
|
13
|
+
%span.field
|
14
|
+
= t(:to).titlecase + ":"
|
15
|
+
%strong
|
16
|
+
= @receiver.email
|
17
|
+
%p
|
18
|
+
%span.field
|
19
|
+
= t(:from).titlecase + ":"
|
20
|
+
%strong
|
21
|
+
= @message.from
|
22
|
+
|
23
|
+
- sending = @message.sendings.build
|
24
|
+
= render :partial => "msg/sendings/form", :locals => {:sending => sending}
|
25
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
- sending ||= @sending
|
2
|
+
- message ||= @message
|
3
|
+
- receiver ||= @receiver
|
4
|
+
- klasses = Msg.receiving_classes
|
5
|
+
|
6
|
+
= form_for [message, sending], :as => :sending do |f|
|
7
|
+
|
8
|
+
.receivers
|
9
|
+
- klasses.each do |klass|
|
10
|
+
- key = klass.underscore
|
11
|
+
|
12
|
+
%h3
|
13
|
+
= t(:send_to)
|
14
|
+
= t("msg.#{key}") unless klasses.length == 1
|
15
|
+
|
16
|
+
%ul.choose_group
|
17
|
+
- klass.constantize.messaging_groups.each_pair do |name, proc|
|
18
|
+
- count = proc.call.count
|
19
|
+
%li.group
|
20
|
+
= f.radio_button "#{key}_group", name, :data => {:action => "reveal", :converse => "ul.choose_receivers"}, :disabled => count == 0
|
21
|
+
%label{:for => "sending_#{key}_group_#{name}"}
|
22
|
+
= t("msg.groups.#{name}")
|
23
|
+
%span.note
|
24
|
+
= t(:receiver_count, :count => count)
|
25
|
+
|
26
|
+
%li.group
|
27
|
+
= f.radio_button "#{key}_group", :selected, :data => {:action => "reveal", :affected => "ul.choose_receivers"}
|
28
|
+
%label{:for => "sending_#{key}_group_selected"}
|
29
|
+
= t("msg.groups.selected")
|
30
|
+
|
31
|
+
%ul.choose_receivers
|
32
|
+
- klass.constantize.order('name ASC').each do |rec|
|
33
|
+
%li.receiver
|
34
|
+
= check_box_tag "sending[#{key}_receiver_ids][]", rec.id, false, :id => "sending_#{key}_receiver_ids_#{rec.id}"
|
35
|
+
%label{:for => "sending_#{key}_receiver_ids_#{rec.id}"}
|
36
|
+
= rec.name
|
37
|
+
|
38
|
+
// #todo: update the preview on selection, and add a control to page through the selected group of people
|
39
|
+
%iframe.body{:src => msg.preview_message_url(message, :receiver_type => receiver.class.to_s.downcase.underscore.to_s, :receiver_id => receiver.id)}
|
40
|
+
|
41
|
+
.buttons
|
42
|
+
= f.submit t(:send_message)
|
43
|
+
= t :or
|
44
|
+
= link_to t(:close), "/", :class => 'cancel'
|
45
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
- sending ||= listing
|
2
|
+
- receiver_count = sending.envelopes.count
|
3
|
+
|
4
|
+
%li.sending
|
5
|
+
%a{:href => msg.sending_url(sending)}
|
6
|
+
%span.pie{:data => {:diameter => 16}}<
|
7
|
+
= sending.statistics.join(',')
|
8
|
+
= shorten(sending.message.subject, 36)
|
9
|
+
- if sending.receiving_group
|
10
|
+
= t(:sent_to)
|
11
|
+
= t("msg.groups.#{sending.receiving_group}")
|
12
|
+
= t(:receiver_count, :count => sending.envelopes.count)
|
13
|
+
|
14
|
+
- else
|
15
|
+
= t(:sent_to_count, :count => sending.envelopes.count)
|
16
|
+
= t(:at)
|
17
|
+
= l(sending.created_at, :format => :natural_with_date)
|
@@ -0,0 +1,8 @@
|
|
1
|
+
- sendings ||= @sendings || Msg::Sending.order('created_at DESC').limit(5)
|
2
|
+
|
3
|
+
#sentbox{:data => {:refreshable => true, :url => msg.sendings_path(:format => :js, :show => 5)}}
|
4
|
+
%h3
|
5
|
+
= link_to t(:sent_report), msg.sendings_url
|
6
|
+
|
7
|
+
%ul.sendings
|
8
|
+
= render :partial => "msg/sendings/listing", :collection => sendings
|
@@ -0,0 +1,22 @@
|
|
1
|
+
- sending ||= @sending
|
2
|
+
|
3
|
+
.sending{:id => "sending_#{sending.id}", :data => {:refreshable => true, :url => sending_path(sending, :format => :js)} }
|
4
|
+
%h2.name
|
5
|
+
%span.pie{:data => {:diameter => 20}}<
|
6
|
+
= sending.statistics.join(',')
|
7
|
+
= link_to shorten(sending.message.subject, 54), msg.sending_url(sending)
|
8
|
+
|
9
|
+
%p.description
|
10
|
+
- if sending.receiving_group
|
11
|
+
= t(:sent_to)
|
12
|
+
= t("msg.groups.#{sending.receiving_group}")
|
13
|
+
= t(:receiver_count, :count => sending.envelopes.count)
|
14
|
+
- else
|
15
|
+
= t(:sent)
|
16
|
+
= t(:at)
|
17
|
+
= l(sending.created_at, :format => :natural_with_date)
|
18
|
+
|
19
|
+
%p.responses
|
20
|
+
= t(:sent_count, :count => sending.envelopes.count) + '.'
|
21
|
+
= t(:opened_count, :count => sending.envelopes.opened.count) + '.'
|
22
|
+
= t(:bounced_count, :count => sending.envelopes.bounced.count) + '.'
|