maily_herald 0.0.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +10 -4
  3. data/.rspec +5 -0
  4. data/Gemfile +1 -12
  5. data/Gemfile.lock +129 -82
  6. data/Guardfile +25 -0
  7. data/LICENSE +10 -0
  8. data/README.md +346 -0
  9. data/Rakefile +5 -0
  10. data/app/controllers/maily_herald/tokens_controller.rb +11 -0
  11. data/app/helpers/maily_herald/tokens_helper.rb +17 -0
  12. data/app/mailers/maily_herald/mailer.rb +91 -0
  13. data/app/models/maily_herald/dispatch.rb +76 -0
  14. data/app/models/maily_herald/list.rb +99 -0
  15. data/app/models/maily_herald/log.rb +67 -0
  16. data/app/models/maily_herald/mailing.rb +139 -7
  17. data/app/models/maily_herald/one_time_mailing.rb +26 -0
  18. data/app/models/maily_herald/periodical_mailing.rb +145 -0
  19. data/app/models/maily_herald/sequence.rb +169 -2
  20. data/app/models/maily_herald/sequence_mailing.rb +71 -0
  21. data/app/models/maily_herald/subscription.rb +67 -0
  22. data/bin/maily_herald +16 -0
  23. data/config/database.yml +5 -0
  24. data/config/locales/en.yml +6 -11
  25. data/config/routes.rb +10 -0
  26. data/config/spring.rb +1 -0
  27. data/db/migrate/20150205120443_create_maily_herald_tables.rb +53 -0
  28. data/db/migrate_legacy/20130711124555_create_maily_herald_tables.rb +67 -0
  29. data/db/migrate_legacy/20140612101023_create_lists.rb +33 -0
  30. data/lib/generators/maily_herald/install_generator.rb +3 -3
  31. data/lib/generators/templates/README +2 -0
  32. data/lib/generators/templates/maily_herald.rb +1 -0
  33. data/lib/maily_herald.rb +345 -23
  34. data/lib/maily_herald/autonaming.rb +34 -0
  35. data/lib/maily_herald/capistrano.rb +5 -0
  36. data/lib/maily_herald/capistrano/tasks.cap +67 -0
  37. data/lib/maily_herald/capistrano/tasks2.rb +20 -0
  38. data/lib/maily_herald/cli.rb +293 -0
  39. data/lib/maily_herald/condition_evaluator.rb +82 -0
  40. data/lib/maily_herald/config.rb +5 -0
  41. data/lib/maily_herald/context.rb +223 -77
  42. data/lib/maily_herald/engine.rb +17 -0
  43. data/lib/maily_herald/logging.rb +90 -0
  44. data/lib/maily_herald/manager.rb +53 -0
  45. data/lib/maily_herald/model_extensions.rb +15 -0
  46. data/lib/maily_herald/template_renderer.rb +16 -0
  47. data/lib/maily_herald/utils.rb +78 -5
  48. data/lib/maily_herald/version.rb +1 -1
  49. data/maily_herald.gemspec +17 -9
  50. data/spec/controllers/maily_herald/tokens_controller_spec.rb +81 -0
  51. data/spec/dummy/Guardfile +35 -0
  52. data/spec/dummy/app/mailers/test_mailer.rb +11 -0
  53. data/spec/dummy/app/models/product.rb +2 -0
  54. data/spec/dummy/app/models/user.rb +4 -0
  55. data/spec/dummy/app/views/test_mailer/sample_mail.text.erb +1 -0
  56. data/spec/dummy/bin/rails +10 -0
  57. data/spec/dummy/bin/rake +7 -0
  58. data/spec/dummy/bin/rspec +7 -0
  59. data/spec/dummy/bin/spring +18 -0
  60. data/spec/dummy/config/application.rb +1 -1
  61. data/spec/dummy/config/environments/development.rb +1 -0
  62. data/spec/dummy/config/environments/test.rb +1 -0
  63. data/spec/dummy/config/initializers/maily_herald.rb +103 -0
  64. data/spec/dummy/config/locales/maily_herald.en.yml +28 -0
  65. data/spec/dummy/db/migrate/20130723074347_create_users.rb +18 -0
  66. data/spec/dummy/db/schema.rb +82 -0
  67. data/spec/factories/products.rb +5 -0
  68. data/spec/factories/users.rb +11 -0
  69. data/spec/lib/context_spec.rb +41 -0
  70. data/spec/lib/maily_herald_spec.rb +32 -0
  71. data/spec/lib/utils_spec.rb +48 -0
  72. data/spec/mailers/maily_herald/mailer_spec.rb +38 -0
  73. data/spec/models/maily_herald/list_spec.rb +64 -0
  74. data/spec/models/maily_herald/log_spec.rb +36 -0
  75. data/spec/models/maily_herald/mailing_spec.rb +34 -0
  76. data/spec/models/maily_herald/one_time_mailing_spec.rb +112 -0
  77. data/spec/models/maily_herald/periodical_mailing_spec.rb +339 -0
  78. data/spec/models/maily_herald/sequence_mailing_spec.rb +18 -0
  79. data/spec/models/maily_herald/sequence_spec.rb +429 -0
  80. data/spec/models/maily_herald/subscription_spec.rb +32 -0
  81. data/spec/spec_helper.rb +31 -11
  82. metadata +199 -54
  83. data/MIT-LICENSE +0 -20
  84. data/README.rdoc +0 -3
  85. data/app/assets/images/maily_herald/.gitkeep +0 -0
  86. data/app/assets/javascripts/maily_herald/application.js +0 -15
  87. data/app/assets/stylesheets/maily_herald/application.css +0 -13
  88. data/app/helpers/maily_herald/application_helper.rb +0 -4
  89. data/app/helpers/maily_herald_helper.rb +0 -9
  90. data/app/models/maily_herald/mailing_record.rb +0 -6
  91. data/app/views/layouts/maily_herald/application.html.erb +0 -14
  92. data/db/migrate/20130711124555_create_maily_herald_tables.rb +0 -38
  93. data/lib/maily_herald/worker.rb +0 -15
@@ -0,0 +1,28 @@
1
+ en:
2
+ activerecord:
3
+ attributes:
4
+ one_time_mailing:
5
+ name: Name
6
+ context_name: Context
7
+ sequence: Sequence
8
+ conditions: Conditions
9
+ title: Title
10
+ from: Sender
11
+ relative_delay: Delay
12
+ template: Template
13
+ periodical_mailing:
14
+ name: Name
15
+ context_name: Context
16
+ sequence: Sequence
17
+ conditions: Conditions
18
+ title: Title
19
+ from: Sender
20
+ relative_delay: Delay
21
+ template: Template
22
+ sequence:
23
+ name: Name
24
+ context_name: Context
25
+ mode: Mode
26
+ start: Start date
27
+ start_var: Start variable (evaluated)
28
+ period: Period
@@ -0,0 +1,18 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def change
3
+ create_table :users do |t|
4
+ t.string :name
5
+ t.string :email
6
+ t.boolean :weekly_notifications, default: true
7
+ t.boolean :active, default: true
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ create_table :products do |t|
13
+ t.string :name
14
+
15
+ t.timestamps
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended to check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(:version => 20150205120443) do
15
+
16
+ create_table "maily_herald_dispatches", :force => true do |t|
17
+ t.string "type", :null => false
18
+ t.integer "sequence_id"
19
+ t.integer "list_id", :null => false
20
+ t.text "conditions"
21
+ t.text "start_at"
22
+ t.string "mailer_name"
23
+ t.string "name", :null => false
24
+ t.string "title"
25
+ t.string "subject"
26
+ t.string "from"
27
+ t.string "state", :default => "disabled"
28
+ t.text "template"
29
+ t.integer "absolute_delay"
30
+ t.integer "period"
31
+ t.boolean "override_subscription"
32
+ t.datetime "created_at", :null => false
33
+ t.datetime "updated_at", :null => false
34
+ end
35
+
36
+ add_index "maily_herald_dispatches", ["name"], :name => "index_maily_herald_dispatches_on_name", :unique => true
37
+
38
+ create_table "maily_herald_lists", :force => true do |t|
39
+ t.string "name", :null => false
40
+ t.string "title"
41
+ t.string "context_name"
42
+ end
43
+
44
+ create_table "maily_herald_logs", :force => true do |t|
45
+ t.integer "entity_id", :null => false
46
+ t.string "entity_type", :null => false
47
+ t.string "entity_email"
48
+ t.integer "mailing_id"
49
+ t.string "status", :null => false
50
+ t.text "data"
51
+ t.datetime "processing_at"
52
+ end
53
+
54
+ create_table "maily_herald_subscriptions", :force => true do |t|
55
+ t.integer "entity_id", :null => false
56
+ t.integer "list_id", :null => false
57
+ t.string "entity_type", :null => false
58
+ t.string "token", :null => false
59
+ t.text "settings"
60
+ t.text "data"
61
+ t.boolean "active", :default => false, :null => false
62
+ t.datetime "delivered_at"
63
+ t.datetime "created_at", :null => false
64
+ t.datetime "updated_at", :null => false
65
+ end
66
+
67
+ create_table "products", :force => true do |t|
68
+ t.string "name"
69
+ t.datetime "created_at", :null => false
70
+ t.datetime "updated_at", :null => false
71
+ end
72
+
73
+ create_table "users", :force => true do |t|
74
+ t.string "name"
75
+ t.string "email"
76
+ t.boolean "weekly_notifications", :default => true
77
+ t.boolean "active", :default => true
78
+ t.datetime "created_at", :null => false
79
+ t.datetime "updated_at", :null => false
80
+ end
81
+
82
+ end
@@ -0,0 +1,5 @@
1
+ FactoryGirl.define do
2
+ factory :product do
3
+ sequence(:name) {|n| "Product #{n}"}
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ FactoryGirl.define do
2
+ factory :user do
3
+ sequence(:name) {|n| "John #{n}"}
4
+ sequence(:email) {|n| "john#{n}@doe.com"}
5
+ active true
6
+
7
+ factory :inactive_user do
8
+ active false
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe MailyHerald::Context do
4
+ describe "setup" do
5
+ before(:each) do
6
+ @user = FactoryGirl.create :user
7
+ @mailing = MailyHerald.one_time_mailing :test_mailing
8
+ @list = @mailing.list
9
+ @context = @list.context
10
+ end
11
+
12
+ describe "with subscription" do
13
+ before(:each) do
14
+ @list.subscribe! @user
15
+ @subscription = @mailing.subscription_for @user
16
+ @drop = @context.drop_for @user, @subscription
17
+ end
18
+
19
+ it "should get valid context" do
20
+ @context.should be_a(MailyHerald::Context)
21
+ end
22
+
23
+ it "should resolve attributes properly" do
24
+ @drop["user"].should be_a(MailyHerald::Context::Drop)
25
+ @drop["user"]["name"].should eq(@user.name)
26
+ @drop["user"]["properties"]["prop1"].should eq(@user.name[0])
27
+ end
28
+
29
+ it "should resolve subscription attributes properly" do
30
+ @drop["subscription"].should be_a(MailyHerald::Subscription)
31
+ end
32
+ end
33
+ end
34
+
35
+ it "should handle both destination procs and strings" do
36
+ @user = FactoryGirl.create :user
37
+ context = MailyHerald.context :all_users
38
+ context.destination_for(@user).should eq(@user.email)
39
+ context.destination_attribute.should be_nil
40
+ end
41
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe MailyHerald do
4
+ describe "setup" do
5
+ before(:each) do
6
+ @user = FactoryGirl.create :user
7
+ end
8
+
9
+ it "should extend context entity models" do
10
+ MailyHerald.context(:all_users).model.name.should eq(User.name)
11
+ User.included_modules.should include(MailyHerald::ModelExtensions)
12
+
13
+ @user.should respond_to(:maily_herald_subscriptions)
14
+
15
+ @user.maily_herald_subscriptions.length.should be_zero
16
+ end
17
+
18
+ it "should create mailings from initializer" do
19
+ mailing = MailyHerald.one_time_mailing(:test_mailing)
20
+ mailing.should be_a MailyHerald::Mailing
21
+ mailing.should_not be_a_new_record
22
+ end
23
+
24
+ it "should create sequences from initializer" do
25
+ sequence = MailyHerald.sequence(:newsletters)
26
+ sequence.should be_a MailyHerald::Sequence
27
+ sequence.should_not be_a_new_record
28
+
29
+ sequence.mailings.length.should eq(3)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe MailyHerald::Utils do
4
+ describe MailyHerald::Utils::MarkupEvaluator do
5
+ before(:each) do
6
+ @mailing = MailyHerald.one_time_mailing :test_mailing
7
+ @user = FactoryGirl.create :user
8
+ @list = @mailing.list
9
+ @list.subscribe!(@user)
10
+ @subscription = @mailing.subscription_for(@user)
11
+ @evaluator = MailyHerald::Utils::MarkupEvaluator.new(@list.context.drop_for(@user, @subscription))
12
+ end
13
+
14
+ it "should validate syntax" do
15
+ @mailing.conditions = "foo bar"
16
+ expect {@evaluator.evaluate_conditions(@mailing.conditions)}.to raise_error(Liquid::Error)
17
+ expect {MailyHerald::Utils::MarkupEvaluator.test_conditions(@mailing.conditions)}.to raise_error(Liquid::Error)
18
+ end
19
+
20
+ pending "should validate numerical conditions" do
21
+ @mailing.conditions = "(2 * 3) - 1"
22
+ @evaluator.evaluate_conditions(@mailing.conditions).should be_falsy
23
+ expect {@mailing.test_conditions}.not_to raise_error(Liquid::Error)
24
+
25
+ @mailing.conditions = "2 == 3"
26
+ @evaluator.evaluate_conditions(@mailing.conditions).should be_falsy
27
+ expect {@mailing.test_conditions}.not_to raise_error(Liquid::Error)
28
+
29
+ @mailing.conditions = "1 * 2 + 3"
30
+ @evaluator.evaluate_conditions(@mailing.conditions).should be_truthy
31
+ expect {@mailing.test_conditions}.not_to raise_error(Liquid::Error)
32
+ end
33
+
34
+ it "should provide model conditions syntax validation" do
35
+ @mailing.conditions = "foo bar"
36
+ @mailing.should_not be_valid
37
+ end
38
+
39
+ it "should evaluate attributes" do
40
+ expect(@evaluator.evaluate_variable("user.created_at")).to eq(@user.created_at)
41
+ end
42
+
43
+ it "should evaluate attributes without subscription" do
44
+ @evaluator = MailyHerald::Utils::MarkupEvaluator.new(@list.context.drop_for(@user, nil))
45
+ expect(@evaluator.evaluate_variable("user.created_at")).to eq(@user.created_at)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe MailyHerald::Mailer do
4
+ before(:each) do
5
+ @entity = FactoryGirl.create :user
6
+ @mailing = MailyHerald.dispatch(:sample_mail)
7
+ @list = @mailing.list
8
+ end
9
+
10
+ describe "without subscription" do
11
+ it "should not deliver" do
12
+ MailyHerald::Log.delivered.count.should eq(0)
13
+
14
+ TestMailer.sample_mail(@entity).deliver
15
+
16
+ MailyHerald::Log.delivered.count.should eq(0)
17
+ end
18
+ end
19
+
20
+ describe "with subscription" do
21
+ before(:each) do
22
+ @list.subscribe! @entity
23
+ end
24
+
25
+ it "should deliver" do
26
+ MailyHerald::Log.delivered.count.should eq(0)
27
+
28
+ TestMailer.sample_mail(@entity).deliver
29
+
30
+ MailyHerald::Log.delivered.count.should eq(1)
31
+ end
32
+ end
33
+
34
+ # missing mailers are how handled silently (bypassing Maily)
35
+ #it "should handle missing mailer" do
36
+ #expect { TestMailer.sample_mail_error(@entity).deliver }.to raise_error
37
+ #end
38
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe MailyHerald::List do
4
+ before(:each) do
5
+ @entity = FactoryGirl.create :user
6
+ @product = FactoryGirl.create :product
7
+
8
+ @list = MailyHerald.list(:generic_list)
9
+ @list2 = MailyHerald::List.new
10
+ @list2.context_name = :all_users
11
+ @list2.name = "another_list"
12
+
13
+ expect(@list).to be_kind_of(MailyHerald::List)
14
+ expect(@list2.save).to be_truthy
15
+ end
16
+
17
+ after(:each) do
18
+ @list2.destroy
19
+ end
20
+
21
+ it "should handle subscripions" do
22
+ expect(@list.subscribed?(@entity)).to be_falsy
23
+ expect(@list.subscribe!(@entity)).to be_kind_of(MailyHerald::Subscription)
24
+ expect(@list.subscribed?(@entity)).to be_truthy
25
+ expect(@list.unsubscribe!(@entity)).to be_kind_of(MailyHerald::Subscription)
26
+ expect(@list.subscribed?(@entity)).to be_falsy
27
+ end
28
+
29
+ it "should not allow other models" do
30
+ @list.subscribe! @entity
31
+ expect(@list.subscribed?(@entity)).to be_truthy
32
+ expect{@list.subscribe! @product}.to raise_error(ActiveRecord::RecordInvalid)
33
+ end
34
+
35
+ it "should return valid subscribers" do
36
+ expect(@list.subscribers).to be_empty
37
+ expect(@list2.subscribers).to be_empty
38
+
39
+ expect(@list.subscribe!(@entity)).to be_kind_of(MailyHerald::Subscription)
40
+ expect(@list.subscribers.first).to eq(@entity)
41
+ expect(@list.potential_subscribers).to be_empty
42
+ expect(@list2.subscribers).to be_empty
43
+ expect(@list2.potential_subscribers.first).to eq(@entity)
44
+ end
45
+
46
+ it "should fetch all logs for list" do
47
+ @list.subscribe!(@entity)
48
+ expect(@list.subscribers.first).to eq(@entity)
49
+
50
+ @mailing = MailyHerald.one_time_mailing(:test_mailing)
51
+ @mailing.run
52
+
53
+ expect(@list.logs).to include(@mailing.logs.first)
54
+ end
55
+
56
+ it "should be lockable" do
57
+ @list = MailyHerald.list :locked_list
58
+ expect(@list).to be_locked
59
+ expect(@list.save).to be_falsy
60
+ expect(@list.errors.messages).to include(:base)
61
+ @list.destroy
62
+ expect(@list).not_to be_destroyed
63
+ end
64
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe MailyHerald::Log do
4
+ before(:each) do
5
+ @mailing = MailyHerald.periodical_mailing(:weekly_summary)
6
+ @entity = FactoryGirl.create :user
7
+ end
8
+
9
+ describe "Associations" do
10
+ it "should have proper scopes" do
11
+ log = MailyHerald::Log.create_for @mailing, @entity, {status: :delivered}
12
+ log.should be_valid
13
+ log.entity.should eq(@entity)
14
+ log.mailing.should eq(@mailing)
15
+
16
+ MailyHerald::Log.for_entity(@entity).should include(log)
17
+ MailyHerald::Log.for_mailing(@mailing).should include(log)
18
+
19
+ MailyHerald::Log.for_entity(@entity).for_mailing(@mailing).last.should eq(log)
20
+ end
21
+ end
22
+
23
+ it "should have proper scopes" do
24
+ log1 = MailyHerald::Log.create_for @mailing, @entity, {status: :delivered}
25
+ log2 = MailyHerald::Log.create_for @mailing, @entity, {status: :delivered}
26
+ expect(MailyHerald::Log.count).to eq(2)
27
+
28
+ log1.update_attribute(:status, :skipped)
29
+ MailyHerald::Log.count.should eq(2)
30
+ MailyHerald::Log.skipped.count.should eq(1)
31
+
32
+ log1.update_attribute(:status, :error)
33
+ MailyHerald::Log.count.should eq(2)
34
+ MailyHerald::Log.error.count.should eq(1)
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe MailyHerald::Mailing do
4
+ describe "Validations" do
5
+ it "should validate template syntax" do
6
+ @mailing = MailyHerald.one_time_mailing :test_mailing
7
+ @mailing.should be_valid
8
+ @mailing.template = "foo {{ bar"
9
+ @mailing.should_not be_valid
10
+ @mailing.errors.messages.keys.should include(:template)
11
+ @mailing.errors.messages[:template].should_not be_empty
12
+ end
13
+
14
+ it "should validate conditions syntax" do
15
+ @mailing = MailyHerald.one_time_mailing :test_mailing
16
+ @mailing.should be_valid
17
+ @mailing.conditions = "foo {{ bar"
18
+ @mailing.should_not be_valid
19
+ @mailing.errors.messages.keys.should include(:conditions)
20
+ @mailing.errors.messages[:conditions].should_not be_empty
21
+ end
22
+ end
23
+
24
+ describe "Locking" do
25
+ it "should produce valiadtion errors" do
26
+ @mailing = MailyHerald.dispatch :locked_mailing
27
+ expect(@mailing).to be_locked
28
+ expect(@mailing.save).to be_falsy
29
+ expect(@mailing.errors.messages).to include(:base)
30
+ @mailing.destroy
31
+ expect(@mailing).not_to be_destroyed
32
+ end
33
+ end
34
+ end