maily_herald 0.8.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +0 -2
- data/Gemfile.lock +5 -13
- data/README.md +186 -69
- data/app/mailers/maily_herald/mailer.rb +44 -26
- data/app/models/maily_herald/ad_hoc_mailing.rb +109 -0
- data/app/models/maily_herald/dispatch.rb +97 -4
- data/app/models/maily_herald/list.rb +36 -7
- data/app/models/maily_herald/log.rb +79 -0
- data/app/models/maily_herald/mailing.rb +149 -24
- data/app/models/maily_herald/one_time_mailing.rb +114 -9
- data/app/models/maily_herald/periodical_mailing.rb +76 -47
- data/app/models/maily_herald/sequence.rb +57 -18
- data/app/models/maily_herald/sequence_mailing.rb +29 -20
- data/app/models/maily_herald/subscription.rb +23 -2
- data/config/routes.rb +2 -2
- data/lib/maily_herald.rb +57 -18
- data/lib/maily_herald/autonaming.rb +8 -0
- data/lib/maily_herald/context.rb +6 -2
- data/lib/maily_herald/logging.rb +2 -0
- data/lib/maily_herald/manager.rb +15 -31
- data/lib/maily_herald/utils.rb +65 -24
- data/lib/maily_herald/version.rb +1 -1
- data/maily_herald.gemspec +1 -1
- data/spec/controllers/maily_herald/tokens_controller_spec.rb +13 -13
- data/spec/dummy/app/mailers/ad_hoc_mailer.rb +11 -0
- data/spec/dummy/app/mailers/custom_one_time_mailer.rb +11 -0
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/environments/test.rb +1 -1
- data/spec/dummy/config/initializers/maily_herald.rb +3 -69
- data/spec/dummy/config/maily_herald.yml +3 -0
- data/spec/dummy/db/seeds.rb +73 -0
- data/spec/lib/context_spec.rb +7 -7
- data/spec/lib/maily_herald_spec.rb +7 -8
- data/spec/lib/utils_spec.rb +65 -25
- data/spec/mailers/maily_herald/mailer_spec.rb +20 -13
- data/spec/models/maily_herald/ad_hoc_mailing_spec.rb +169 -0
- data/spec/models/maily_herald/list_spec.rb +2 -1
- data/spec/models/maily_herald/log_spec.rb +10 -10
- data/spec/models/maily_herald/mailing_spec.rb +9 -8
- data/spec/models/maily_herald/one_time_mailing_spec.rb +212 -39
- data/spec/models/maily_herald/periodical_mailing_spec.rb +158 -92
- data/spec/models/maily_herald/sequence_mailing_spec.rb +2 -2
- data/spec/models/maily_herald/sequence_spec.rb +152 -139
- data/spec/models/maily_herald/subscription_spec.rb +21 -4
- metadata +17 -8
- data/lib/maily_herald/condition_evaluator.rb +0 -82
- data/lib/maily_herald/config.rb +0 -5
- data/spec/dummy/app/mailers/test_mailer.rb +0 -11
@@ -2,16 +2,16 @@ module MailyHerald
|
|
2
2
|
class Mailer < ActionMailer::Base
|
3
3
|
attr_reader :entity
|
4
4
|
|
5
|
-
def generic entity
|
6
|
-
destination =
|
7
|
-
subject =
|
8
|
-
content =
|
5
|
+
def generic entity
|
6
|
+
destination = @maily_herald_mailing.destination(entity)
|
7
|
+
subject = @maily_herald_mailing.render_subject(entity)
|
8
|
+
content = @maily_herald_mailing.render_template(entity)
|
9
9
|
|
10
10
|
opts = {
|
11
11
|
to: destination,
|
12
12
|
subject: subject
|
13
13
|
}
|
14
|
-
opts[:from] =
|
14
|
+
opts[:from] = @maily_herald_mailing.from if @maily_herald_mailing.from.present?
|
15
15
|
|
16
16
|
mail(opts) do |format|
|
17
17
|
format.text { render text: content }
|
@@ -21,12 +21,22 @@ module MailyHerald
|
|
21
21
|
class << self
|
22
22
|
#TODO make it instance method so we get access to instance attributes
|
23
23
|
def deliver_mail(mail) #:nodoc:
|
24
|
+
unless mail.maily_herald_data
|
25
|
+
MailyHerald.logger.error("Unable to send message. Invalid mailing provided.")
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
24
29
|
mailing = mail.maily_herald_data[:mailing]
|
25
30
|
entity = mail.maily_herald_data[:entity]
|
31
|
+
schedule = mail.maily_herald_data[:schedule]
|
26
32
|
|
33
|
+
if !schedule && mailing.respond_to?(:schedule_delivery_to)
|
34
|
+
# Implicitly create schedule for ad hoc delivery when called using Mailer.foo(entity).deliver syntax
|
35
|
+
schedule = mail.maily_herald_data[:schedule] = mailing.schedule_delivery_to(entity)
|
36
|
+
end
|
27
37
|
|
28
|
-
if
|
29
|
-
mailing.
|
38
|
+
if schedule
|
39
|
+
mailing.send(:deliver_with_mailer, schedule) do
|
30
40
|
ActiveSupport::Notifications.instrument("deliver.action_mailer") do |payload|
|
31
41
|
self.set_payload_for_mail(payload, mail)
|
32
42
|
yield # Let Mail do the delivery actions
|
@@ -34,12 +44,7 @@ module MailyHerald
|
|
34
44
|
mail
|
35
45
|
end
|
36
46
|
else
|
37
|
-
MailyHerald.logger.log_processing(mailing, entity, mail, prefix: "
|
38
|
-
|
39
|
-
ActiveSupport::Notifications.instrument("deliver.action_mailer") do |payload|
|
40
|
-
self.set_payload_for_mail(payload, mail)
|
41
|
-
yield # Let Mail do the delivery actions
|
42
|
-
end
|
47
|
+
MailyHerald.logger.log_processing(mailing, entity, mail, prefix: "Attempt to deliver email without schedule. No mail was sent", level: :debug)
|
43
48
|
end
|
44
49
|
end
|
45
50
|
end
|
@@ -48,9 +53,11 @@ module MailyHerald
|
|
48
53
|
return @_message if @_mail_was_called && headers.blank? && !block
|
49
54
|
|
50
55
|
# Assign instance variables availabe for template
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
if @_message.maily_herald_data
|
57
|
+
@maily_subscription = @_message.maily_herald_data[:subscription]
|
58
|
+
@maily_entity = @_message.maily_herald_data[:entity]
|
59
|
+
@maily_mailing = @_message.maily_herald_data[:mailing]
|
60
|
+
end
|
54
61
|
|
55
62
|
super
|
56
63
|
end
|
@@ -70,20 +77,31 @@ module MailyHerald
|
|
70
77
|
end
|
71
78
|
end
|
72
79
|
|
73
|
-
|
74
|
-
|
80
|
+
if args[1].is_a?(MailyHerald::Log)
|
81
|
+
@maily_herald_schedule = args[1]
|
82
|
+
@maily_herald_mailing = @maily_herald_schedule.mailing
|
83
|
+
@maily_herald_entity = @maily_herald_schedule.entity
|
84
|
+
else
|
85
|
+
@maily_herald_mailing = args[0].to_s == "generic" ? args[2] : MailyHerald.dispatch(args[0])
|
86
|
+
@maily_herald_entity = args[1]
|
87
|
+
end
|
75
88
|
|
76
|
-
@
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
89
|
+
if @maily_herald_mailing
|
90
|
+
@_message.maily_herald_data = {
|
91
|
+
schedule: @maily_herald_schedule,
|
92
|
+
mailing: @maily_herald_mailing,
|
93
|
+
entity: @maily_herald_entity,
|
94
|
+
subscription: @maily_herald_mailing.subscription_for(@maily_herald_entity),
|
95
|
+
}
|
96
|
+
end
|
81
97
|
|
82
98
|
lookup_context.skip_default_locale!
|
83
|
-
super
|
99
|
+
super(args[0], @maily_herald_entity)
|
84
100
|
|
85
|
-
|
86
|
-
|
101
|
+
if @maily_herald_mailing
|
102
|
+
@_message.to = @maily_herald_mailing.destination(@maily_herald_entity) unless @_message.to
|
103
|
+
@_message.from = @maily_herald_mailing.from unless @_message.from
|
104
|
+
end
|
87
105
|
|
88
106
|
@_message
|
89
107
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module MailyHerald
|
2
|
+
class AdHocMailing < Mailing
|
3
|
+
validates :list, presence: true
|
4
|
+
|
5
|
+
# Schedules mailing delivery to all entities in the scope at given `time`.
|
6
|
+
#
|
7
|
+
# This always creates new {MailyHerald::Log} objects of type `schedule`.
|
8
|
+
#
|
9
|
+
# @param time [Time] time of delivery
|
10
|
+
def schedule_delivery_to_all time = Time.now
|
11
|
+
self.list.context.scope_with_subscription(self.list, :outer).each do |entity|
|
12
|
+
MailyHerald.logger.debug "Adding schedule of #{self} ad-hoc for entity ##{entity.id} #{entity}"
|
13
|
+
schedule_delivery_to entity, time
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Schedules mailing delivery to `entity` at given `time`.
|
18
|
+
#
|
19
|
+
# This always creates new {MailyHerald::Log} object of type `schedule`.
|
20
|
+
#
|
21
|
+
# @param entity [ActiveRecord::Base]
|
22
|
+
# @param time [Time] time of delivery
|
23
|
+
def schedule_delivery_to entity, time = Time.now
|
24
|
+
subscribed = self.list.subscribed?(entity)
|
25
|
+
|
26
|
+
if !enabled? || !(self.override_subscription? || subscribed)
|
27
|
+
return
|
28
|
+
end
|
29
|
+
|
30
|
+
log = Log.new
|
31
|
+
log.with_lock do
|
32
|
+
log.set_attributes_for(self, entity, {
|
33
|
+
status: :scheduled,
|
34
|
+
processing_at: time,
|
35
|
+
})
|
36
|
+
log.save!
|
37
|
+
end
|
38
|
+
log
|
39
|
+
end
|
40
|
+
|
41
|
+
# Sends mailing to all subscribed entities who have delivery scheduled.
|
42
|
+
#
|
43
|
+
# Performs actual sending of emails; should be called in background.
|
44
|
+
#
|
45
|
+
# Returns array of {MailyHerald::Log} with actual `Mail::Message` objects stored
|
46
|
+
# in {MailyHerald::Log.mail} attributes.
|
47
|
+
def run
|
48
|
+
# TODO better scope here to exclude schedules for users outside context scope
|
49
|
+
schedules.where("processing_at <= (?)", Time.now).collect do |schedule|
|
50
|
+
if schedule.entity
|
51
|
+
mail = deliver schedule
|
52
|
+
schedule.reload
|
53
|
+
schedule.mail = mail
|
54
|
+
schedule
|
55
|
+
else
|
56
|
+
MailyHerald.logger.log_processing(schedule.mailing, {class: schedule.entity_type, id: schedule.entity_id}, prefix: "Removing schedule for non-existing entity")
|
57
|
+
schedule.destroy
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Sets the delivery schedule for given entity
|
63
|
+
#
|
64
|
+
# New schedule will be created or existing one updated.
|
65
|
+
#
|
66
|
+
# Schedule is {Log} object of type "schedule".
|
67
|
+
def set_schedule_for entity
|
68
|
+
subscribed = self.list.subscribed?(entity)
|
69
|
+
|
70
|
+
if !enabled? || !(self.override_subscription? || subscribed)
|
71
|
+
log = schedule_for(entity)
|
72
|
+
log.try(:destroy)
|
73
|
+
return
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns {Log} object which is the delivery schedule for given entity.
|
78
|
+
def schedule_for entity
|
79
|
+
schedules.for_entity(entity).first
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns collection of all delivery schedules ({Log} collection).
|
83
|
+
def schedules
|
84
|
+
Log.ordered.scheduled.for_mailing(self)
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_s
|
88
|
+
"<AdHocMailing: #{self.title || self.name}>"
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def deliver_with_mailer schedule
|
94
|
+
current_time = Time.now
|
95
|
+
|
96
|
+
schedule.with_lock do
|
97
|
+
# make sure schedule hasn't been processed in the meantime
|
98
|
+
if schedule && schedule.processing_at <= current_time && schedule.scheduled?
|
99
|
+
schedule = super(schedule)
|
100
|
+
if schedule
|
101
|
+
schedule.processing_at = current_time if schedule.processed?
|
102
|
+
schedule.save!
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end if schedule
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -1,11 +1,42 @@
|
|
1
1
|
module MailyHerald
|
2
|
+
# Main dispatch class.
|
3
|
+
#
|
4
|
+
# Inherited by all {Mailing} classes.
|
5
|
+
# Each Dispatch instance need to have associated {List}.
|
6
|
+
# Dispatch can be in one of three states:
|
7
|
+
# - +enabled+
|
8
|
+
# - +disabled+
|
9
|
+
# - +archived+
|
10
|
+
#
|
11
|
+
# @attr [String] type Polymorphic type.
|
12
|
+
# @attr [Fixnum] sequence_id {Sequence} association id.
|
13
|
+
# @attr [Fixnum] list_id {List} association id.
|
14
|
+
# @attr [String] conditions Delivery conditions as Liquid expression.
|
15
|
+
# @attr [String] mailer_name {Mailer} class name.
|
16
|
+
# This refers to {Mailer} used by Dispatch while sending emails.
|
17
|
+
# @attr [String] name Dispatch name.
|
18
|
+
# @attr [String] title Dispatch title.
|
19
|
+
# @attr [String] from Sender email address.
|
20
|
+
# If not provided, action_mailer.default_options[:from} is used.
|
21
|
+
# Valid only for {Mailing}.
|
22
|
+
# @attr [String] state
|
23
|
+
# @attr [String] subject Email subject as Liquid template.
|
24
|
+
# Valid only for {Mailing}.
|
25
|
+
# @attr [String] template Email body template as Liquid template.
|
26
|
+
# Valid only for {Mailing}.
|
27
|
+
# @attr [String] absolute_delay Email delivery delay from beginning of sequence.
|
28
|
+
# Valid only for {SequenceMailing}.
|
29
|
+
# @attr [String] period Email delivery period.
|
30
|
+
# Valid only for {PeriodicalMailing}.
|
31
|
+
# @attr [String] override_subscription Defines whether email should be sent regardless of
|
32
|
+
# entity subscription state.
|
2
33
|
class Dispatch < ActiveRecord::Base
|
3
34
|
belongs_to :list, class_name: "MailyHerald::List"
|
4
35
|
|
5
36
|
validates :list, presence: true
|
6
37
|
validates :state, presence: true, inclusion: {in: [:enabled, :disabled, :archived]}
|
7
38
|
validate do |dispatch|
|
8
|
-
dispatch.errors.add(:base, "Can't change this dispatch because it is locked.") if dispatch.locked?
|
39
|
+
dispatch.errors.add(:base, "Can't change this dispatch because it is locked.") if dispatch.changes.present? && dispatch.locked?
|
9
40
|
end
|
10
41
|
before_destroy do |dispatch|
|
11
42
|
if dispatch.locked?
|
@@ -21,10 +52,52 @@ module MailyHerald
|
|
21
52
|
scope :archived, lambda { where(state: :archived) }
|
22
53
|
scope :not_archived, lambda { where("state != (?)", :archived) }
|
23
54
|
|
24
|
-
scope :
|
55
|
+
scope :ad_hoc_mailing, lambda { where(type: AdHocMailing) }
|
25
56
|
scope :one_time_mailing, lambda { where(type: OneTimeMailing) }
|
26
57
|
scope :periodical_mailing, lambda { where(type: PeriodicalMailing) }
|
58
|
+
scope :sequence, lambda { where(type: Sequence) }
|
59
|
+
|
60
|
+
before_validation do
|
61
|
+
if @start_at_proc
|
62
|
+
self.start_at = "proc"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
after_save do
|
67
|
+
if @start_at_proc
|
68
|
+
MailyHerald.start_at_procs[self.id] = @start_at_proc
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Sets start_at value of {OneTimeMailing}, {PeriodicalMailing} and {SequenceMailing}.
|
73
|
+
#
|
74
|
+
# @param v String with Liquid expression or `Proc` that evaluates to `Time`.
|
75
|
+
def start_at= v
|
76
|
+
if v.respond_to? :call
|
77
|
+
@start_at_proc = v
|
78
|
+
else
|
79
|
+
super(v.is_a?(Time) ? v.to_s : v)
|
80
|
+
end
|
81
|
+
end
|
27
82
|
|
83
|
+
# Returns time as string with Liquid expression or Proc.
|
84
|
+
def start_at
|
85
|
+
@start_at_proc || MailyHerald.start_at_procs[self.id] || read_attribute(:start_at)
|
86
|
+
end
|
87
|
+
|
88
|
+
def has_start_at_proc?
|
89
|
+
!!(@start_at_proc || MailyHerald.start_at_procs[self.id])
|
90
|
+
end
|
91
|
+
|
92
|
+
def start_at_changed?
|
93
|
+
if has_start_at_proc?
|
94
|
+
@start_at_proc != MailyHerald.start_at_procs[self.id]
|
95
|
+
else
|
96
|
+
super
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns dispatch state as symbol
|
28
101
|
def state
|
29
102
|
read_attribute(:state).to_sym
|
30
103
|
end
|
@@ -59,18 +132,38 @@ module MailyHerald
|
|
59
132
|
write_attribute(:state, "archived")
|
60
133
|
end
|
61
134
|
|
135
|
+
# Sets {List} associated with this dispatch
|
136
|
+
#
|
137
|
+
# @param l {List} name or {List} object
|
62
138
|
def list= l
|
63
139
|
l = MailyHerald::List.find_by_name(l.to_s) if l.is_a?(String) || l.is_a?(Symbol)
|
64
140
|
super(l)
|
65
141
|
end
|
66
142
|
|
143
|
+
def subscription_valid? entity
|
144
|
+
self.override_subscription? || self.list.subscribed?(entity)
|
145
|
+
end
|
146
|
+
|
147
|
+
def in_scope? entity
|
148
|
+
self.list.context.scope.exists?(entity)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Checks if dispatch can be sent to given entity.
|
152
|
+
#
|
153
|
+
# Following checks are performed:
|
154
|
+
# - dispatch is enabled,
|
155
|
+
# - subscription is overriden or user is subscribed to dispatch list,
|
156
|
+
# - entity belongs to list {Context} scope.
|
157
|
+
#
|
158
|
+
# @param entity [ActiveRecord::Base] Recipient
|
67
159
|
def processable? entity
|
68
|
-
self.enabled? &&
|
160
|
+
self.enabled? && subscription_valid?(entity) && in_scope?(entity)
|
69
161
|
end
|
70
162
|
|
163
|
+
# Check if dispatch is locked.
|
164
|
+
# @see MailyHerald.dispatch_locked?
|
71
165
|
def locked?
|
72
166
|
MailyHerald.dispatch_locked?(self.name)
|
73
167
|
end
|
74
|
-
|
75
168
|
end
|
76
169
|
end
|
@@ -1,4 +1,13 @@
|
|
1
1
|
module MailyHerald
|
2
|
+
# Represents subscriptions list.
|
3
|
+
#
|
4
|
+
# Entities can be subscribed to lists by creating {Subscription} object for them.
|
5
|
+
#
|
6
|
+
# List have {Context} assigned. Only entities from Context scope can be subscribed to list.
|
7
|
+
#
|
8
|
+
# @attr [String] name
|
9
|
+
# @attr [String] title
|
10
|
+
# @attr [String] context_name Name of the {Context} used by List.
|
2
11
|
class List < ActiveRecord::Base
|
3
12
|
include MailyHerald::Autonaming
|
4
13
|
|
@@ -9,6 +18,8 @@ module MailyHerald
|
|
9
18
|
has_many :dispatches, class_name: "MailyHerald::Dispatch"
|
10
19
|
has_many :subscriptions, class_name: "MailyHerald::Subscription"
|
11
20
|
|
21
|
+
validates :context, presence: true
|
22
|
+
|
12
23
|
validate do |list|
|
13
24
|
list.errors.add(:base, "Can't change this list because it is locked.") if list.locked?
|
14
25
|
end
|
@@ -19,67 +30,85 @@ module MailyHerald
|
|
19
30
|
end
|
20
31
|
end
|
21
32
|
|
33
|
+
# Returns {Context} object associated with List.
|
22
34
|
def context
|
23
35
|
@context ||= MailyHerald.context self.context_name
|
24
36
|
end
|
25
37
|
|
38
|
+
# Subscribes entity to List.
|
39
|
+
#
|
40
|
+
# @param entity [Object] Entity object. Need to be in the {Context} scope.
|
26
41
|
def subscribe! entity
|
27
42
|
s = subscription_for(entity)
|
28
43
|
s ? s.activate! : s = create_subscription_for(entity, true)
|
29
44
|
s
|
30
45
|
end
|
31
46
|
|
47
|
+
# Unsubscribes entity from List.
|
48
|
+
#
|
49
|
+
# @param entity [Object] Entity object.
|
32
50
|
def unsubscribe! entity
|
33
51
|
s = subscription_for(entity)
|
34
52
|
s ? s.deactivate! : s = create_subscription_for(entity, false)
|
35
53
|
s
|
36
54
|
end
|
37
55
|
|
56
|
+
# Checks whether entity is subscribed to List.
|
38
57
|
def subscribed? entity
|
39
|
-
|
58
|
+
s = Subscription.get_from(entity) || subscription_for(entity)
|
59
|
+
s.try(:active?)
|
40
60
|
end
|
41
61
|
|
42
|
-
#
|
62
|
+
# Checks whether entity is not subscribed to List.
|
63
|
+
#
|
64
|
+
# True if user has inactive subscription or never been subscribed.
|
43
65
|
def unsubscribed? entity
|
44
|
-
s = subscription_for(entity)
|
66
|
+
s = Subscription.get_from(entity) || subscription_for(entity)
|
45
67
|
s ? !s.active? : true
|
46
68
|
end
|
47
69
|
|
48
|
-
#
|
70
|
+
# Checks whether entity has been removed from List.
|
71
|
+
#
|
72
|
+
# True only if user was intentionally unsubscribed.
|
49
73
|
def opted_out? entity
|
50
74
|
s = subscription_for(entity)
|
51
75
|
s ? !s.active? : false
|
52
76
|
end
|
53
77
|
|
78
|
+
# Returns subscription for given entity.
|
54
79
|
def subscription_for entity
|
55
80
|
self.subscriptions.for_entity(entity).first
|
56
81
|
end
|
57
82
|
|
83
|
+
# Returns number of List subscribers.
|
58
84
|
def active_subscription_count
|
59
85
|
subscribers.count(:id)
|
60
86
|
end
|
61
87
|
|
62
|
-
# Returns entities within the context's scope with active subscription
|
88
|
+
# Returns entities within the context's scope with active subscription.
|
63
89
|
def subscribers
|
64
90
|
context.scope_with_subscription(self).where("#{Subscription.table_name}.active = (?)", true).where("#{Subscription.table_name}.list_id = (?)", self.id)
|
65
91
|
end
|
66
92
|
|
67
|
-
# Returns entities within the context's scope with inactive subscription
|
93
|
+
# Returns entities within the context's scope with inactive subscription.
|
68
94
|
def opt_outs
|
69
95
|
context.scope_with_subscription(self).where("#{Subscription.table_name}.active = (?)", false).where("#{Subscription.table_name}.list_id = (?)", self.id)
|
70
96
|
end
|
71
97
|
|
72
|
-
# Returns entities within the context's scope without subscription
|
98
|
+
# Returns entities within the context's scope without subscription.
|
73
99
|
def potential_subscribers
|
74
100
|
sq = context.scope_with_subscription(self, :outer).where("#{Subscription.table_name}.list_id = (?)", self.id).pluck("#{context.model.table_name}.id")
|
75
101
|
context.scope.where(context.model.arel_table[:id].not_in(sq))
|
76
102
|
end
|
77
103
|
|
104
|
+
# Returns {Log} objects collection related to this List.
|
78
105
|
def logs
|
79
106
|
#Log.for_mailings(self.dispatches.select("id"))
|
80
107
|
Log.for_mailings(Dispatch.where("sequence_id IN (?) OR list_id = (?)", Sequence.where(list_id: self.id).select("id"), self.id).select("id"))
|
81
108
|
end
|
82
109
|
|
110
|
+
# Check if List is locked.
|
111
|
+
# @see MailyHerald.list_locked?
|
83
112
|
def locked?
|
84
113
|
MailyHerald.list_locked?(self.name)
|
85
114
|
end
|