mailee 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/VERSION +1 -1
  2. data/app/.gitignore +4 -0
  3. data/app/Gemfile +30 -0
  4. data/app/Gemfile.lock +73 -0
  5. data/app/README +256 -0
  6. data/app/Rakefile +7 -0
  7. data/app/app/controllers/application_controller.rb +3 -0
  8. data/app/app/helpers/application_helper.rb +2 -0
  9. data/app/app/mailers/foo.rb +12 -0
  10. data/app/app/views/foo/bar.html.erb +3 -0
  11. data/app/app/views/foo/baz.text.erb +3 -0
  12. data/app/app/views/layouts/application.html.erb +14 -0
  13. data/app/config.ru +4 -0
  14. data/app/config/application.rb +42 -0
  15. data/app/config/boot.rb +13 -0
  16. data/app/config/database.yml +22 -0
  17. data/app/config/environment.rb +5 -0
  18. data/app/config/environments/development.rb +28 -0
  19. data/app/config/environments/production.rb +49 -0
  20. data/app/config/environments/test.rb +35 -0
  21. data/app/config/initializers/backtrace_silencers.rb +7 -0
  22. data/app/config/initializers/inflections.rb +10 -0
  23. data/app/config/initializers/mailee.rb +1 -0
  24. data/app/config/initializers/mime_types.rb +5 -0
  25. data/app/config/initializers/secret_token.rb +7 -0
  26. data/app/config/initializers/session_store.rb +8 -0
  27. data/app/config/locales/en.yml +8 -0
  28. data/app/config/routes.rb +58 -0
  29. data/app/db/seeds.rb +7 -0
  30. data/app/doc/README_FOR_APP +2 -0
  31. data/app/lib/tasks/.gitkeep +0 -0
  32. data/app/public/404.html +26 -0
  33. data/app/public/422.html +26 -0
  34. data/app/public/500.html +26 -0
  35. data/app/public/favicon.ico +0 -0
  36. data/app/public/images/rails.png +0 -0
  37. data/app/public/index.html +239 -0
  38. data/app/public/javascripts/application.js +2 -0
  39. data/app/public/javascripts/controls.js +965 -0
  40. data/app/public/javascripts/dragdrop.js +974 -0
  41. data/app/public/javascripts/effects.js +1123 -0
  42. data/app/public/javascripts/prototype.js +6001 -0
  43. data/app/public/javascripts/rails.js +175 -0
  44. data/app/public/robots.txt +5 -0
  45. data/app/public/stylesheets/.gitkeep +0 -0
  46. data/app/script/rails +6 -0
  47. data/app/test.rb +1 -0
  48. data/app/test/functional/foo_test.rb +20 -0
  49. data/app/test/performance/browsing_test.rb +9 -0
  50. data/app/test/test_helper.rb +13 -0
  51. data/app/vendor/plugins/.gitkeep +0 -0
  52. data/lib/mailee.rb +112 -4
  53. data/mailee.gemspec +52 -2
  54. metadata +55 -5
@@ -0,0 +1,175 @@
1
+ (function() {
2
+ // Technique from Juriy Zaytsev
3
+ // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
4
+ function isEventSupported(eventName) {
5
+ var el = document.createElement('div');
6
+ eventName = 'on' + eventName;
7
+ var isSupported = (eventName in el);
8
+ if (!isSupported) {
9
+ el.setAttribute(eventName, 'return;');
10
+ isSupported = typeof el[eventName] == 'function';
11
+ }
12
+ el = null;
13
+ return isSupported;
14
+ }
15
+
16
+ function isForm(element) {
17
+ return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
18
+ }
19
+
20
+ function isInput(element) {
21
+ if (Object.isElement(element)) {
22
+ var name = element.nodeName.toUpperCase()
23
+ return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
24
+ }
25
+ else return false
26
+ }
27
+
28
+ var submitBubbles = isEventSupported('submit'),
29
+ changeBubbles = isEventSupported('change')
30
+
31
+ if (!submitBubbles || !changeBubbles) {
32
+ // augment the Event.Handler class to observe custom events when needed
33
+ Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
34
+ function(init, element, eventName, selector, callback) {
35
+ init(element, eventName, selector, callback)
36
+ // is the handler being attached to an element that doesn't support this event?
37
+ if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
38
+ (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
39
+ // "submit" => "emulated:submit"
40
+ this.eventName = 'emulated:' + this.eventName
41
+ }
42
+ }
43
+ )
44
+ }
45
+
46
+ if (!submitBubbles) {
47
+ // discover forms on the page by observing focus events which always bubble
48
+ document.on('focusin', 'form', function(focusEvent, form) {
49
+ // special handler for the real "submit" event (one-time operation)
50
+ if (!form.retrieve('emulated:submit')) {
51
+ form.on('submit', function(submitEvent) {
52
+ var emulated = form.fire('emulated:submit', submitEvent, true)
53
+ // if custom event received preventDefault, cancel the real one too
54
+ if (emulated.returnValue === false) submitEvent.preventDefault()
55
+ })
56
+ form.store('emulated:submit', true)
57
+ }
58
+ })
59
+ }
60
+
61
+ if (!changeBubbles) {
62
+ // discover form inputs on the page
63
+ document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
64
+ // special handler for real "change" events
65
+ if (!input.retrieve('emulated:change')) {
66
+ input.on('change', function(changeEvent) {
67
+ input.fire('emulated:change', changeEvent, true)
68
+ })
69
+ input.store('emulated:change', true)
70
+ }
71
+ })
72
+ }
73
+
74
+ function handleRemote(element) {
75
+ var method, url, params;
76
+
77
+ var event = element.fire("ajax:before");
78
+ if (event.stopped) return false;
79
+
80
+ if (element.tagName.toLowerCase() === 'form') {
81
+ method = element.readAttribute('method') || 'post';
82
+ url = element.readAttribute('action');
83
+ params = element.serialize();
84
+ } else {
85
+ method = element.readAttribute('data-method') || 'get';
86
+ url = element.readAttribute('href');
87
+ params = {};
88
+ }
89
+
90
+ new Ajax.Request(url, {
91
+ method: method,
92
+ parameters: params,
93
+ evalScripts: true,
94
+
95
+ onComplete: function(request) { element.fire("ajax:complete", request); },
96
+ onSuccess: function(request) { element.fire("ajax:success", request); },
97
+ onFailure: function(request) { element.fire("ajax:failure", request); }
98
+ });
99
+
100
+ element.fire("ajax:after");
101
+ }
102
+
103
+ function handleMethod(element) {
104
+ var method = element.readAttribute('data-method'),
105
+ url = element.readAttribute('href'),
106
+ csrf_param = $$('meta[name=csrf-param]')[0],
107
+ csrf_token = $$('meta[name=csrf-token]')[0];
108
+
109
+ var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
110
+ element.parentNode.insert(form);
111
+
112
+ if (method !== 'post') {
113
+ var field = new Element('input', { type: 'hidden', name: '_method', value: method });
114
+ form.insert(field);
115
+ }
116
+
117
+ if (csrf_param) {
118
+ var param = csrf_param.readAttribute('content'),
119
+ token = csrf_token.readAttribute('content'),
120
+ field = new Element('input', { type: 'hidden', name: param, value: token });
121
+ form.insert(field);
122
+ }
123
+
124
+ form.submit();
125
+ }
126
+
127
+
128
+ document.on("click", "*[data-confirm]", function(event, element) {
129
+ var message = element.readAttribute('data-confirm');
130
+ if (!confirm(message)) event.stop();
131
+ });
132
+
133
+ document.on("click", "a[data-remote]", function(event, element) {
134
+ if (event.stopped) return;
135
+ handleRemote(element);
136
+ event.stop();
137
+ });
138
+
139
+ document.on("click", "a[data-method]", function(event, element) {
140
+ if (event.stopped) return;
141
+ handleMethod(element);
142
+ event.stop();
143
+ });
144
+
145
+ document.on("submit", function(event) {
146
+ var element = event.findElement(),
147
+ message = element.readAttribute('data-confirm');
148
+ if (message && !confirm(message)) {
149
+ event.stop();
150
+ return false;
151
+ }
152
+
153
+ var inputs = element.select("input[type=submit][data-disable-with]");
154
+ inputs.each(function(input) {
155
+ input.disabled = true;
156
+ input.writeAttribute('data-original-value', input.value);
157
+ input.value = input.readAttribute('data-disable-with');
158
+ });
159
+
160
+ var element = event.findElement("form[data-remote]");
161
+ if (element) {
162
+ handleRemote(element);
163
+ event.stop();
164
+ }
165
+ });
166
+
167
+ document.on("ajax:after", "form", function(event, element) {
168
+ var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
169
+ inputs.each(function(input) {
170
+ input.value = input.readAttribute('data-original-value');
171
+ input.removeAttribute('data-original-value');
172
+ input.disabled = false;
173
+ });
174
+ });
175
+ })();
@@ -0,0 +1,5 @@
1
+ # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
2
+ #
3
+ # To ban all spiders from the entire site uncomment the next two lines:
4
+ # User-Agent: *
5
+ # Disallow: /
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby1.8
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1 @@
1
+ Foo.bar.deliver
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ class FooTest < ActionMailer::TestCase
4
+ test "bar" do
5
+ mail = Foo.bar
6
+ assert_equal "Bar", mail.subject
7
+ assert_equal ["to@example.org"], mail.to
8
+ assert_equal ["from@example.com"], mail.from
9
+ assert_match "Hi", mail.body.encoded
10
+ end
11
+
12
+ test "baz" do
13
+ mail = Foo.baz
14
+ assert_equal "Baz", mail.subject
15
+ assert_equal ["to@example.org"], mail.to
16
+ assert_equal ["from@example.com"], mail.from
17
+ assert_match "Hi", mail.body.encoded
18
+ end
19
+
20
+ end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+ require 'rails/performance_test_help'
3
+
4
+ # Profiling results for each test method are written to tmp/performance.
5
+ class BrowsingTest < ActionDispatch::PerformanceTest
6
+ def test_homepage
7
+ get '/'
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path('../../config/environment', __FILE__)
3
+ require 'rails/test_help'
4
+
5
+ class ActiveSupport::TestCase
6
+ # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
7
+ #
8
+ # Note: You'll currently still have to declare fixtures explicitly in integration tests
9
+ # -- they do not yet inherit this setting
10
+ fixtures :all
11
+
12
+ # Add more helper methods to be used by all tests here...
13
+ end
File without changes
@@ -1,8 +1,26 @@
1
1
  require 'active_resource'
2
2
  module Mailee
3
+
4
+ # The Config class is used to set your api url.
5
+ # You can do it in your applications.rb or in a initializar.
6
+ # It's simple:
7
+ #
8
+ # Mailee::Config.site = "http://your.mailee.api.url"
3
9
  class Config < ActiveResource::Base
4
- # O self.site tem q ser configurado no environment!
5
10
  end
11
+
12
+ # The Contact class gives you default access to your contacts (all,
13
+ # first, create, update, destroy) plus some facilities, like searching
14
+ # contacts by email, keyword (a smart search), signature (name & email)
15
+ # and internal id.
16
+ #
17
+ # Also, you can subscribe contacts to lists and unsubscribe. In Mailee
18
+ # unsubscribing a contact is radical: it will be unsubscribed from ALL
19
+ # lists FOREVER. House rules.
20
+ #
21
+ # If you use mailee gem to sync a model, it will always set the internal_id
22
+ # to your "local" model id and then search based on it to update de remote
23
+ # record.
6
24
  class Contact < Config
7
25
  def self.find_by_internal_id iid
8
26
  find(:first, :params => {:internal_id => iid})
@@ -21,32 +39,119 @@ module Mailee
21
39
  put(:subscribe, :list => {:name => list})
22
40
  end
23
41
  end
42
+
43
+ # The List class gives you default access to your lists (all, first, create, update, destroy)
24
44
  class List < Config
25
45
  end
46
+
47
+ # The Template class gives you default access to your templates (all, first, create, update, destroy)
26
48
  class Template < Config
27
49
  end
50
+
51
+ # The Quick class allows you to import contacts to mailee just like
52
+ # in the interface
53
+ #
54
+ # USAGE:
55
+ #
56
+ # # Emails only
57
+ # Mailee::Quick.import("witt@cambridge.uk dick@princeton.edu")
58
+ #
59
+ # # Names and emails (needs line breaks)
60
+ # Mailee::Quick.import("witt@cambridge.uk, Wittgenstein\ndick@princeton.edu, Rorty")
61
+ #
62
+ # # Signatures (gmail style)
63
+ # Mailee::Quick.import('"Wittgenstein" <witt@cambridge.uk>,
64
+ # "Rorty" <dick@princeton.edu.us>')
28
65
  class Quick < Config
29
66
  self.collection_name = "quick"
30
67
  def self.import contacts
31
68
  create :contacts => contacts
32
69
  end
33
70
  end
71
+
72
+ # The Message class is where the fun happens.
73
+ #
74
+ # USAGE:
75
+ #
76
+ # # Creating a message (still a draft):
77
+ # message = Mailee::Message.create :title => "TITLE", :subject => "SUBJ", :from_name => "NAME", :from_email => "your@email.com", :html => "<h1>Hello</h1>", :list_id => 666
78
+ # # Sending tests. 33, 44 and 55 are contact's ids.
79
+ # message.test([33,44,55]).should_not be nil
80
+ # # Sending the message now ...
81
+ # message.ready
82
+ # # ... or sending the message 10 days from now
83
+ # message.ready(10.days.from_now)
34
84
  class Message < Config
35
85
  def test contacts
36
86
  put(:test, :contacts => contacts)
37
87
  end
38
88
  def ready date=nil, hour=0
39
- if date && date.is_a?(Date)
40
- put(:ready, :when => 'after', :date => date.strftime("%d/%m/%Y"), :hour => hour)
89
+ if date && date.is_a?(Date) && date > Time.now
90
+ put(:ready, :when => 'after', :after => {:date => date.strftime("%d/%m/%Y"), :hour => date.strftime('%H')})
41
91
  else
42
92
  put(:ready, :when => 'now')
43
93
  end
44
94
  end
45
95
  end
96
+
97
+ # The Report class is still beta. It can return the results of a
98
+ # message - total deliveries, accesses and returns. There are also
99
+ # methods for getting accesses, unsubscribes and returns in "real time".
46
100
  class Report < Config
47
101
  end
48
102
 
103
+ # The Mailer class is responsible for making the mailee gem ActionMailer
104
+ # compatible.
105
+ #
106
+ # USAGE:
107
+ #
108
+ # If you want to use Mailee to send all your systems emails, simply
109
+ # configure the environment (dev or prod) like this:
110
+ #
111
+ # config.action_mailer.delivery_method = Mailee::Mailer
112
+ #
113
+ # But if you wanna send just a certain mailer with Mailee, add
114
+ # "send_with_mailee" on a per mailer basis
115
+ #
116
+ # class Notifications < ActionMailer::Base
117
+ # send_with_mailee
118
+ # end
119
+ #
120
+ # One important thing, is to add the sender's name to the default "from" in
121
+ # your mailer, this way:
122
+ #
123
+ # default :from => "Your name <your@email.com.br>"
124
+ #
125
+ # And don't forget to config your domain SPF!
126
+ class Mailer
127
+
128
+ def initialize config
129
+ end
130
+ def deliver! mail
131
+ from_name = mail.header['from'].to_s.scan(/(.+?) <.+?>$/).to_s
132
+ message = Mailee::Message.create :title => mail.subject, :subject => mail.subject, :from_name => from_name, :from_email => mail.from.first, :emails => mail.to.join(' '), :html => mail.body.to_s
133
+ message.ready(mail.date)
134
+ self
135
+ end
136
+ end
137
+
138
+ module Send
139
+
140
+ def self.included(base) # :nodoc:
141
+ base.extend ClassMethods
142
+ end
143
+
144
+ module ClassMethods
145
+ def send_with_mailee
146
+ puts "1"
147
+ self.delivery_method = Mailee::Mailer
148
+ end
149
+ end
150
+
151
+ end
152
+
49
153
  module Sync
154
+
50
155
  def self.included(base) # :nodoc:
51
156
  base.extend ClassMethods
52
157
  end
@@ -75,9 +180,11 @@ module Mailee
75
180
  def syncd?
76
181
  self.included_modules.include?(InstanceMethods)
77
182
  end
183
+
78
184
  end
79
185
 
80
186
  module InstanceMethods #:nodoc:
187
+
81
188
  def self.included(base) # :nodoc:
82
189
  base.extend ClassMethods
83
190
  end
@@ -169,4 +276,5 @@ module Mailee
169
276
  end
170
277
  end
171
278
  end
172
- ActiveRecord::Base.send(:include, Mailee::Sync) if defined?(ActiveRecord)
279
+ ActiveRecord::Base.send(:include, Mailee::Sync) if defined?(ActiveRecord)
280
+ ActionMailer::Base.send(:include, Mailee::Send) if defined?(ActionMailer)
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mailee}
8
- s.version = "0.2.1"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Juan Maiz"]
12
- s.date = %q{2010-10-06}
12
+ s.date = %q{2010-10-07}
13
13
  s.description = %q{Permite sincronizar automaticamente seus modelos com o Mailee.me, inclusive com gerenciamento de optin.}
14
14
  s.email = %q{suporte@mailee.me}
15
15
  s.extra_rdoc_files = [
@@ -24,6 +24,56 @@ Gem::Specification.new do |s|
24
24
  "README.rdoc",
25
25
  "Rakefile",
26
26
  "VERSION",
27
+ "app/.gitignore",
28
+ "app/Gemfile",
29
+ "app/Gemfile.lock",
30
+ "app/README",
31
+ "app/Rakefile",
32
+ "app/app/controllers/application_controller.rb",
33
+ "app/app/helpers/application_helper.rb",
34
+ "app/app/mailers/foo.rb",
35
+ "app/app/views/foo/bar.html.erb",
36
+ "app/app/views/foo/baz.text.erb",
37
+ "app/app/views/layouts/application.html.erb",
38
+ "app/config.ru",
39
+ "app/config/application.rb",
40
+ "app/config/boot.rb",
41
+ "app/config/database.yml",
42
+ "app/config/environment.rb",
43
+ "app/config/environments/development.rb",
44
+ "app/config/environments/production.rb",
45
+ "app/config/environments/test.rb",
46
+ "app/config/initializers/backtrace_silencers.rb",
47
+ "app/config/initializers/inflections.rb",
48
+ "app/config/initializers/mailee.rb",
49
+ "app/config/initializers/mime_types.rb",
50
+ "app/config/initializers/secret_token.rb",
51
+ "app/config/initializers/session_store.rb",
52
+ "app/config/locales/en.yml",
53
+ "app/config/routes.rb",
54
+ "app/db/seeds.rb",
55
+ "app/doc/README_FOR_APP",
56
+ "app/lib/tasks/.gitkeep",
57
+ "app/public/404.html",
58
+ "app/public/422.html",
59
+ "app/public/500.html",
60
+ "app/public/favicon.ico",
61
+ "app/public/images/rails.png",
62
+ "app/public/index.html",
63
+ "app/public/javascripts/application.js",
64
+ "app/public/javascripts/controls.js",
65
+ "app/public/javascripts/dragdrop.js",
66
+ "app/public/javascripts/effects.js",
67
+ "app/public/javascripts/prototype.js",
68
+ "app/public/javascripts/rails.js",
69
+ "app/public/robots.txt",
70
+ "app/public/stylesheets/.gitkeep",
71
+ "app/script/rails",
72
+ "app/test.rb",
73
+ "app/test/functional/foo_test.rb",
74
+ "app/test/performance/browsing_test.rb",
75
+ "app/test/test_helper.rb",
76
+ "app/vendor/plugins/.gitkeep",
27
77
  "init.rb",
28
78
  "install.rb",
29
79
  "lib/mailee.rb",