dm_newsletter 4.2.1.5
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +33 -0
- data/Rakefile +30 -0
- data/app/assets/stylesheets/dm_newsletter/application.css +13 -0
- data/app/controllers/dm_newsletter/admin/admin_controller.rb +16 -0
- data/app/controllers/dm_newsletter/admin/newsletters_controller.rb +81 -0
- data/app/controllers/dm_newsletter/application_controller.rb +3 -0
- data/app/controllers/dm_newsletter/newsletters_controller.rb +50 -0
- data/app/helpers/dm_newsletter/newsletters_helper.rb +8 -0
- data/app/models/dm_newsletter/concerns/ability.rb +37 -0
- data/app/models/dm_newsletter/permitted_params.rb +20 -0
- data/app/models/mailchimp_newsletter.rb +217 -0
- data/app/models/mailchimp_newsletter_subscriber.rb +43 -0
- data/app/models/newsletter.rb +46 -0
- data/app/models/newsletter_subscriber.rb +257 -0
- data/app/models/standard_newsletter.rb +19 -0
- data/app/views/dm_newsletter/admin/newsletters/_form.html.erb +17 -0
- data/app/views/dm_newsletter/admin/newsletters/edit.html.erb +2 -0
- data/app/views/dm_newsletter/admin/newsletters/index.html.erb +32 -0
- data/app/views/dm_newsletter/admin/newsletters/new.html.erb +2 -0
- data/app/views/dm_newsletter/admin/newsletters/show.html.erb +46 -0
- data/config/locales/nms.cs.yml +15 -0
- data/config/locales/nms.de.yml +15 -0
- data/config/locales/nms.en.yml +15 -0
- data/config/locales/nms.fi.yml +15 -0
- data/config/locales/nms.ja.yml +15 -0
- data/config/routes.rb +15 -0
- data/db/20130730120724_create_subscribers.rb +32 -0
- data/db/migrate/20130729075442_create_newsletter.rb +24 -0
- data/lib/dm_newsletter.rb +4 -0
- data/lib/dm_newsletter/engine.rb +8 -0
- data/lib/tasks/dm_newsletter_tasks.rake +4 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/ability.rb +12 -0
- data/spec/dummy/app/models/user.rb +6 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +26 -0
- data/spec/dummy/config/boot.rb +5 -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 +82 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +12 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20141114170927_add_globalize_countries.dm_core.rb +50 -0
- data/spec/dummy/db/migrate/20141114170928_devise_create_users.dm_core.rb +46 -0
- data/spec/dummy/db/migrate/20141114170929_add_user_fields.dm_core.rb +14 -0
- data/spec/dummy/db/migrate/20141114170930_rolify_create_roles.dm_core.rb +20 -0
- data/spec/dummy/db/migrate/20141114170931_add_last_access.dm_core.rb +10 -0
- data/spec/dummy/db/migrate/20141114170932_create_versions.dm_core.rb +19 -0
- data/spec/dummy/db/migrate/20141114170933_add_object_changes_column_to_versions.dm_core.rb +12 -0
- data/spec/dummy/db/migrate/20141114170934_create_dm_core_accounts.dm_core.rb +13 -0
- data/spec/dummy/db/migrate/20141114170935_add_account_to_users.dm_core.rb +9 -0
- data/spec/dummy/db/migrate/20141114170936_create_preferences.dm_core.rb +13 -0
- data/spec/dummy/db/migrate/20141114170937_create_comments.dm_core.rb +22 -0
- data/spec/dummy/db/migrate/20141114170938_add_activity.dm_core.rb +21 -0
- data/spec/dummy/db/migrate/20141114170939_add_type_to_comments.dm_core.rb +9 -0
- data/spec/dummy/db/migrate/20141114170940_add_category.dm_core.rb +28 -0
- data/spec/dummy/db/migrate/20141114170941_create_email_table.dm_core.rb +26 -0
- data/spec/dummy/db/migrate/20141114170942_add_user_profile.dm_core.rb +46 -0
- data/spec/dummy/db/migrate/20141114170943_add_profile_email.dm_core.rb +14 -0
- data/spec/dummy/db/migrate/20141114170944_create_payment_history.dm_core.rb +37 -0
- data/spec/dummy/db/migrate/20141114170945_change_anchor_field.dm_core.rb +10 -0
- data/spec/dummy/db/migrate/20141114170946_create_user_site_profile.dm_core.rb +27 -0
- data/spec/dummy/db/migrate/20141114170947_add_avatar.dm_core.rb +12 -0
- data/spec/dummy/db/migrate/20141114170948_add_notify_to_payment_history.dm_core.rb +8 -0
- data/spec/dummy/db/migrate/20141114170949_acts_as_votable_migration.dm_core.rb +28 -0
- data/spec/dummy/db/migrate/20141114170950_add_user_site_profile_uuid.dm_core.rb +19 -0
- data/spec/dummy/db/migrate/20141114170951_add_invoice_id.dm_core.rb +7 -0
- data/spec/dummy/db/migrate/20141114170952_acts_as_follower_migration.dm_core.rb +18 -0
- data/spec/dummy/db/migrate/20141114170953_rename_invoice_id.dm_core.rb +12 -0
- data/spec/dummy/db/migrate/20141114170954_add_core_addresses.dm_core.rb +18 -0
- data/spec/dummy/db/migrate/20141114170955_papertrail_increase_column.dm_core.rb +9 -0
- data/spec/dummy/db/migrate/20141114170956_acts_as_taggable_on_migration.dm_core.rb +32 -0
- data/spec/dummy/db/migrate/20141114170957_add_missing_unique_indices.dm_core.rb +23 -0
- data/spec/dummy/db/migrate/20141114170958_add_taggings_counter_cache_to_tags.dm_core.rb +16 -0
- data/spec/dummy/db/migrate/20141114170959_create_custom_fields.dm_core.rb +40 -0
- data/spec/dummy/db/migrate/20141114170960_add_missing_taggable_index.dm_core.rb +11 -0
- data/spec/dummy/db/migrate/20141119112030_create_cms.dm_cms.rb +92 -0
- data/spec/dummy/db/migrate/20141119112031_add_account_to_cms.dm_cms.rb +11 -0
- data/spec/dummy/db/migrate/20141119112032_create_blog.dm_cms.rb +62 -0
- data/spec/dummy/db/migrate/20141119112033_add_notification_sent.dm_cms.rb +6 -0
- data/spec/dummy/db/migrate/20141119112034_add_blog_comment.dm_cms.rb +8 -0
- data/spec/dummy/db/migrate/20141119112035_add_blog_image.dm_cms.rb +6 -0
- data/spec/dummy/db/migrate/20141119112036_rename_snippet_slug.dm_cms.rb +14 -0
- data/spec/dummy/db/migrate/20141119112037_add_requires_subscription_blog.dm_cms.rb +8 -0
- data/spec/dummy/db/migrate/20141119112038_add_pages_ranked_model.dm_cms.rb +23 -0
- data/spec/dummy/db/migrate/20141119112039_add_blog_owner.dm_cms.rb +7 -0
- data/spec/dummy/db/migrate/20141119112040_create_media_files.dm_cms.rb +30 -0
- data/spec/dummy/db/migrate/20141119112041_add_cmspage_summary.dm_cms.rb +7 -0
- data/spec/dummy/db/migrate/20141119112042_add_blog_image_email_header.dm_cms.rb +6 -0
- data/spec/dummy/db/migrate/20141119112043_add_header_image.dm_cms.rb +10 -0
- data/spec/dummy/db/migrate/20160128145239_add_favored_locale.dm_core.rb +17 -0
- data/spec/dummy/db/migrate/20160128145240_update_papertrail_v4.dm_core.rb +41 -0
- data/spec/dummy/db/schema.rb +593 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/accounts.rb +9 -0
- data/spec/factories/user_profiles.rb +10 -0
- data/spec/factories/users.rb +19 -0
- data/spec/models/newsletter_spec.rb +9 -0
- data/spec/rails_helper.rb +70 -0
- data/spec/spec_helper.rb +85 -0
- data/spec/support/accounts.rb +17 -0
- data/spec/support/devise.rb +44 -0
- data/spec/support/fix_locale.rb +57 -0
- metadata +296 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
class MailchimpNewsletterSubscriber < NewsletterSubscriber
|
|
2
|
+
|
|
3
|
+
attr_accessor :member_info_data, :email, :euid, :subscribed, :grouping_id, :groups
|
|
4
|
+
|
|
5
|
+
# is subscriber interested in the named group?
|
|
6
|
+
#------------------------------------------------------------------------------
|
|
7
|
+
def interest_group?(name)
|
|
8
|
+
group = self.groups.detect {|group| group['name'] == name} if self.groups
|
|
9
|
+
return (group ? group['interested'] : false)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
#------------------------------------------------------------------------------
|
|
13
|
+
def subscribed?
|
|
14
|
+
subscribed
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Instantiate a new subscriber based on data from a Mailchimp query like
|
|
18
|
+
# member_info. Does nothing with the database at this time.
|
|
19
|
+
#------------------------------------------------------------------------------
|
|
20
|
+
def self.new_from_mailchimp(attributes = {})
|
|
21
|
+
obj = MailchimpNewsletterSubscriber.new
|
|
22
|
+
obj.member_info_data = attributes
|
|
23
|
+
obj.subscribed = attributes['status'] == 'subscribed' ? true : false
|
|
24
|
+
obj.email = attributes['email']
|
|
25
|
+
obj.euid = attributes['euid']
|
|
26
|
+
obj.grouping_id = attributes['merges']['GROUPINGS'] ? attributes['merges']['GROUPINGS'][0]['id'] : nil
|
|
27
|
+
obj.groups = attributes['merges']['GROUPINGS'] ? attributes['merges']['GROUPINGS'][0]['groups'] : nil
|
|
28
|
+
return obj
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Query for the subscriber info.
|
|
32
|
+
#------------------------------------------------------------------------------
|
|
33
|
+
def self.subscriber_info(newsletter, email)
|
|
34
|
+
api = MailchimpNewsletter.api
|
|
35
|
+
subscriber = api.lists.member_info(id: newsletter.mc_id, emails: [email: email])
|
|
36
|
+
if subscriber['success_count'] == 1
|
|
37
|
+
return MailchimpNewsletterSubscriber.new_from_mailchimp(subscriber['data'][0])
|
|
38
|
+
else
|
|
39
|
+
return nil
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#------------------------------------------------------------------------------
|
|
2
|
+
class Newsletter < ActiveRecord::Base
|
|
3
|
+
|
|
4
|
+
self.table_name = 'email_newsletters'
|
|
5
|
+
|
|
6
|
+
# [todo] has_many :newsletter_subscribers, :dependent => :destroy
|
|
7
|
+
|
|
8
|
+
validates_uniqueness_of :token
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
default_scope { where(account_id: Account.current.id) }
|
|
12
|
+
before_create :generate_token
|
|
13
|
+
|
|
14
|
+
#------------------------------------------------------------------------------
|
|
15
|
+
def subscribe(user_or_email, options = {FNAME: '', LNAME: ''})
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
#------------------------------------------------------------------------------
|
|
19
|
+
def update_list_stats
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#------------------------------------------------------------------------------
|
|
23
|
+
def map_error_to_msg(code)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Find the newsletter associated with the token
|
|
27
|
+
#------------------------------------------------------------------------------
|
|
28
|
+
def self.find_newsletter(token, options = {})
|
|
29
|
+
Newsletter.find_by_token(token)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
#------------------------------------------------------------------------------
|
|
33
|
+
def self.signup_information(token, options = {})
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
protected
|
|
37
|
+
|
|
38
|
+
#------------------------------------------------------------------------------
|
|
39
|
+
def generate_token
|
|
40
|
+
self.token = loop do
|
|
41
|
+
random_token = SecureRandom.hex(10)
|
|
42
|
+
break random_token unless Newsletter.where(token: random_token).exists?
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# [todo] currently not saving subscriber info in database, only working with a
|
|
2
|
+
# temporary object. Look at caching/syncing subscriber info for performance
|
|
3
|
+
#------------------------------------------------------------------------------
|
|
4
|
+
class NewsletterSubscriber #< ActiveRecord::Base
|
|
5
|
+
|
|
6
|
+
=begin
|
|
7
|
+
belongs_to :newsletter
|
|
8
|
+
|
|
9
|
+
validates_presence_of :email
|
|
10
|
+
validates_presence_of :firstname, :if => Proc.new { |sub| sub.newsletter.require_name}
|
|
11
|
+
validates_presence_of :lastname, :if => Proc.new { |sub| sub.newsletter.require_name}
|
|
12
|
+
validates_presence_of :country, :if => Proc.new { |sub| sub.newsletter.require_country}
|
|
13
|
+
|
|
14
|
+
default_scope { where(account_id: Account.current.id) }
|
|
15
|
+
|
|
16
|
+
#------------------------------------------------------------------------------
|
|
17
|
+
# protect admin values from being assigned via a malicious form
|
|
18
|
+
# attr_accessible makes everything protected except those listed
|
|
19
|
+
# attr_protected makes everything accessible except those listed
|
|
20
|
+
#------------------------------------------------------------------------------
|
|
21
|
+
scope :subscribed, :conditions => ["process_state = ?", 'subscribed']
|
|
22
|
+
scope :unsubscribed, :conditions => ["process_state = ?", 'unubscribed']
|
|
23
|
+
scope :unconfirmed, :conditions => ["process_state = ?", 'unconfirmed']
|
|
24
|
+
scope :not_reminded, :conditions => ["process_state = ? AND reminded_on IS NULL", 'unconfirmed']
|
|
25
|
+
|
|
26
|
+
attr_protected :subscribedate, :confirmed, :confrimdate, :unsubscribed,
|
|
27
|
+
:unsubscribedate, :confirmcode, :subscribeip,
|
|
28
|
+
:confirmationemail, :confirmationreply
|
|
29
|
+
|
|
30
|
+
belongs_to :country
|
|
31
|
+
|
|
32
|
+
#--- tie the subscriber_id to a student record
|
|
33
|
+
belongs_to :subscriber, :class_name => 'Student', :foreign_key => 'subscriber_id'
|
|
34
|
+
|
|
35
|
+
#=== validation rules
|
|
36
|
+
|
|
37
|
+
validates_length_of :firstname, :maximum => 50
|
|
38
|
+
validates_length_of :lastname, :maximum => 50
|
|
39
|
+
validates_length_of :email, :maximum => 60
|
|
40
|
+
|
|
41
|
+
validates_email_veracity_of :email, :on => :create
|
|
42
|
+
|
|
43
|
+
#--- define how the state machine works
|
|
44
|
+
acts_as_state_machine :initial => :unconfirmed, :column => :process_state
|
|
45
|
+
state :unconfirmed, :after => Proc.new { |o| o.update_attribute(:processed_on, Time.now) }
|
|
46
|
+
state :subscribed, :after => Proc.new { |o| o.update_attribute(:processed_on, Time.now) }
|
|
47
|
+
state :unsubscribed, :after => Proc.new { |o| o.update_attribute(:processed_on, Time.now) }
|
|
48
|
+
state :bounced, :after => Proc.new { |o| o.update_attribute(:processed_on, Time.now) }
|
|
49
|
+
|
|
50
|
+
#------------------------------------------------------------------------------
|
|
51
|
+
event :unconfirm do
|
|
52
|
+
transitions :from => :subscribed, :to => :unconfirmed
|
|
53
|
+
transitions :from => :unsubscribed, :to => :unconfirmed
|
|
54
|
+
transitions :from => :bounced, :to => :unconfirmed
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
#------------------------------------------------------------------------------
|
|
58
|
+
event :subscribe do
|
|
59
|
+
transitions :from => :unconfirmed, :to => :subscribed
|
|
60
|
+
transitions :from => :unsubscribed, :to => :subscribed
|
|
61
|
+
transitions :from => :bounced, :to => :subscribed
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
#------------------------------------------------------------------------------
|
|
65
|
+
event :unsubscribe do
|
|
66
|
+
transitions :from => :unconfirmed, :to => :unsubscribed
|
|
67
|
+
transitions :from => :subscribed, :to => :unsubscribed
|
|
68
|
+
transitions :from => :bounced, :to => :unsubscribed
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
#------------------------------------------------------------------------------
|
|
72
|
+
event :bounce do
|
|
73
|
+
transitions :from => :unconfirmed, :to => :bounced
|
|
74
|
+
transitions :from => :subscribed, :to => :bounced
|
|
75
|
+
transitions :from => :unsubscribed, :to => :bounced
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Takes either a Hash of values or an object that responds to the proper values
|
|
79
|
+
#------------------------------------------------------------------------------
|
|
80
|
+
def initialize(subscriber = nil, options = {:subscriber_id => nil})
|
|
81
|
+
if subscriber.nil? || subscriber.is_a?(Hash)
|
|
82
|
+
super(subscriber)
|
|
83
|
+
else
|
|
84
|
+
super(:firstname => subscriber.firstname, :lastname => subscriber.lastname,
|
|
85
|
+
:email => subscriber.email, :country => subscriber.country,
|
|
86
|
+
:subscriber_id => options[:subscriber_id])
|
|
87
|
+
end
|
|
88
|
+
write_attribute(:subscribeip, options[:remote_ip])
|
|
89
|
+
write_attribute(:confirmcode, generate_confirmation_code())
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# find if there is an existing subscription
|
|
93
|
+
#------------------------------------------------------------------------------
|
|
94
|
+
def self.find_existing_subscription(newsletter_id, subscriber_id = nil, email = nil)
|
|
95
|
+
if subscriber_id
|
|
96
|
+
#--- look for a specific subscriber_id
|
|
97
|
+
subscriber = NewsletterSubscriber.find_by_subscriber_id_and_newsletter_id(subscriber_id, newsletter_id)
|
|
98
|
+
else
|
|
99
|
+
#--- look for a specific email address
|
|
100
|
+
subscriber = NewsletterSubscriber.find_by_email_and_newsletter_id(email, newsletter_id)
|
|
101
|
+
end
|
|
102
|
+
return subscriber
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
#------------------------------------------------------------------------------
|
|
106
|
+
def self.find_existing_subscription_is_subscribed(newsletter_id, subscriber_id = nil, email = nil)
|
|
107
|
+
subscriber = NewsletterSubscriber.find_existing_subscription(newsletter_id, subscriber_id, email)
|
|
108
|
+
return subscriber ? subscriber.is_subscribed? : false
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Return a reference to the actual subscriber data (like name and email).
|
|
112
|
+
#------------------------------------------------------------------------------
|
|
113
|
+
def subscriber_data
|
|
114
|
+
subscriber_id.nil? ? self : subscriber
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
#------------------------------------------------------------------------------
|
|
118
|
+
def country_name
|
|
119
|
+
self.country.english_name
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
#------------------------------------------------------------------------------
|
|
123
|
+
def full_name
|
|
124
|
+
name = firstname.capitalize + " " + lastname.capitalize
|
|
125
|
+
return name.blank? ? email : name
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Given a subscriber, update the information in this record with that from the
|
|
129
|
+
# subscriber info. If there is a subscriber_id, then don't update the record.
|
|
130
|
+
#------------------------------------------------------------------------------
|
|
131
|
+
def update_subscription(subscriber)
|
|
132
|
+
unless subscriber.nil?
|
|
133
|
+
update_attributes(:firstname => subscriber.firstname, :lastname => subscriber.lastname,
|
|
134
|
+
:email => subscriber.email, :country => subscriber.country)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
#------------------------------------------------------------------------------
|
|
139
|
+
def hard_bounce
|
|
140
|
+
increment!(:hard_bounces)
|
|
141
|
+
bounce! if hard_bounces >= 1
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
#------------------------------------------------------------------------------
|
|
145
|
+
def soft_bounce
|
|
146
|
+
increment!(:soft_bounces)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
#------------------------------------------------------------------------------
|
|
150
|
+
def is_subscribed?
|
|
151
|
+
process_state == 'subscribed'
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
#------------------------------------------------------------------------------
|
|
155
|
+
def is_unsubscribed?
|
|
156
|
+
process_state == 'unsubscribed'
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
#------------------------------------------------------------------------------
|
|
160
|
+
def is_unconfirmed?
|
|
161
|
+
process_state == 'unconfirmed'
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
#------------------------------------------------------------------------------
|
|
165
|
+
def is_bounced?
|
|
166
|
+
process_state == 'bounced'
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
#------------------------------------------------------------------------------
|
|
170
|
+
def generate_confirmation_code()
|
|
171
|
+
hashed(Time.now.to_i.to_s + rand.to_s)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
#------------------------------------------------------------------------------
|
|
175
|
+
def hashed(str)
|
|
176
|
+
return Digest::SHA1.hexdigest("guruparampara--#{str}--")[0..39]
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
#------------------------------------------------------------------------------
|
|
180
|
+
def update_confirmationemail(email)
|
|
181
|
+
update_attribute(:confirmationemail, email)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# This trys to keep information indicating that the user actually
|
|
185
|
+
# did click on the activation link in the email. We will track the
|
|
186
|
+
# ipaddress and the uri that was requested.
|
|
187
|
+
#------------------------------------------------------------------------------
|
|
188
|
+
def update_confirmationreply(request_obj)
|
|
189
|
+
info = "Remote IP: " + request_obj.remote_ip + " URI: " + request_obj.url
|
|
190
|
+
update_attribute(:confirmationreply, info)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Set everything back to a pre confirmed state
|
|
194
|
+
#------------------------------------------------------------------------------
|
|
195
|
+
def reset_confirmation
|
|
196
|
+
update_attribute(:confirmcode, generate_confirmation_code)
|
|
197
|
+
update_attribute(:confirmationemail, nil)
|
|
198
|
+
update_attribute(:confirmationreply, nil)
|
|
199
|
+
update_attribute(:hard_bounces, 0)
|
|
200
|
+
update_attribute(:soft_bounces, 0)
|
|
201
|
+
unconfirm!
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
#------------------------------------------------------------------------------
|
|
205
|
+
def send_confirmation
|
|
206
|
+
email = NewsletterSubscriberMailer.signup(self, confirm_subscription_url, confirm_unsubscribe_url).deliver_now
|
|
207
|
+
update_confirmationemail(email.to_s)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
#------------------------------------------------------------------------------
|
|
211
|
+
def resend_confirmation
|
|
212
|
+
email = NewsletterSubscriberMailer.reconfirm(self, confirm_subscription_url, confirm_unsubscribe_url).deliver_now
|
|
213
|
+
update_confirmationemail(email.to_s)
|
|
214
|
+
update_attribute(:reminded_on, Time.now)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
#------------------------------------------------------------------------------
|
|
218
|
+
def confirm_subscription_url
|
|
219
|
+
confirm_url = newsletter.account.preferred(:system_main_site) + "/#{I18n.locale}" + Hanuman::Application.config.confirm_subscription_url
|
|
220
|
+
confirm_url += "?subid=#{self.id}&code=#{self.confirmcode}"
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
#------------------------------------------------------------------------------
|
|
224
|
+
def confirm_unsubscribe_url
|
|
225
|
+
confirm_url = newsletter.account.preferred(:system_main_site) + "/#{I18n.locale}" + Hanuman::Application.config.confirm_unsubscription_url
|
|
226
|
+
confirm_url += "?subid=#{self.id}&code=#{self.confirmcode}"
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Return the number of items specified, in particular the number of items in
|
|
230
|
+
# a particular state
|
|
231
|
+
#------------------------------------------------------------------------------
|
|
232
|
+
def self.number_of(state, options = {})
|
|
233
|
+
#--- must be wanting to count the process states
|
|
234
|
+
if options[:date]
|
|
235
|
+
count(:conditions => "process_state = '#{state.to_s}' AND date(created_on) = '#{options[:date]}'")
|
|
236
|
+
elsif options[:before_date]
|
|
237
|
+
count(:conditions => "process_state = '#{state.to_s}' AND date(created_on) <= '#{options[:before_date]}'")
|
|
238
|
+
else
|
|
239
|
+
count(:conditions => "process_state = '#{state.to_s}'")
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Supported series:
|
|
244
|
+
# :subscribed, :unsubscribed, :unconfirmed, :continents
|
|
245
|
+
#------------------------------------------------------------------------------
|
|
246
|
+
def self.subscribers_chart_series(requested_data = :subscribed, months_ago = 24)
|
|
247
|
+
case requested_data
|
|
248
|
+
when :subscribed, :unsubscribed, :unconfirmed
|
|
249
|
+
months_ago.downto(0).map { |date| number_of(requested_data.to_s, :before_date => date.months.ago.to_date) }.inspect
|
|
250
|
+
when :continents
|
|
251
|
+
joins(:country).where(:process_state => 'subscribed').select('globalize_countries.continent').group('continent').count('continent')
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
=end
|
|
256
|
+
|
|
257
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# This is the standard or "manual" newsletter class - all newsletter subscription
|
|
2
|
+
# funtions are handled internally. This is in case you don't want to use the
|
|
3
|
+
# integration with MailChimp
|
|
4
|
+
#------------------------------------------------------------------------------
|
|
5
|
+
class StandardNewsletter < Newsletter
|
|
6
|
+
|
|
7
|
+
validates_presence_of :name
|
|
8
|
+
|
|
9
|
+
#------------------------------------------------------------------------------
|
|
10
|
+
def self.signup_information(token, options = {})
|
|
11
|
+
#--- [todo] implement
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
#------------------------------------------------------------------------------
|
|
15
|
+
def map_error_to_msg(code)
|
|
16
|
+
#--- [todo] implement
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<% submit_url = (@newsletter.new_record? ? admin_newsletters_path : admin_newsletter_path) %>
|
|
2
|
+
<%= simple_form_for @newsletter, url: submit_url,
|
|
3
|
+
html: { class: 'form-horizontal' }, wrapper: :bs3_horizontal_form, wrapper_mappings: DmAdmin::FormWrapperMappings do |f| %>
|
|
4
|
+
|
|
5
|
+
<%= f.error_notification :message => "Please review the problems below" %>
|
|
6
|
+
|
|
7
|
+
<%= panel header: false do %>
|
|
8
|
+
<% if using_mailchimp? %>
|
|
9
|
+
<%= f.input :mc_id , label: 'List ID', hint: 'MailChimp List ID, in the "Settings -> List Name and Defatuls" setion of a list' %>
|
|
10
|
+
<% else %>
|
|
11
|
+
<%= f.input :name , label: 'Name of Newsletter' %>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<%= submit_or_cancel :cancel_url => admin_newsletters_path %>
|
|
15
|
+
<% end %>
|
|
16
|
+
|
|
17
|
+
<% end %>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<% content_for :content_title_extra do %>
|
|
2
|
+
<%= page_header_buttons do %>
|
|
3
|
+
<%= link_to(icon_label(:new, 'New'), new_admin_newsletter_path, title: 'New Newsletter', class: "btn btn-xs btn-default") %>
|
|
4
|
+
<% end %>
|
|
5
|
+
<% end %>
|
|
6
|
+
|
|
7
|
+
<% if false #using_mailchimp? %>
|
|
8
|
+
<% content_for :sidebar do %>
|
|
9
|
+
<%= link_to 'Sync with Mailchimp', admin_newsletters_synchronize_lists_path, class: "action-button greyish" %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<% end %>
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
<% content_for :content_title, 'Newsletter Dashboard' %>
|
|
15
|
+
|
|
16
|
+
<% @newsletters.in_groups_of(2, false) do |newsletter_row| %>
|
|
17
|
+
<div class="row">
|
|
18
|
+
<% for newsletter in newsletter_row %>
|
|
19
|
+
<div class="col-md-12">
|
|
20
|
+
<% toolbar = toolbar_btn(newsletter.subscribed_count, admin_newsletter_path(newsletter), title: 'Number of subscriptions', class: 'label label-success pull-right') %>
|
|
21
|
+
<%= panel title: link_to(newsletter.name, admin_newsletter_path(newsletter)), toolbar: toolbar do %>
|
|
22
|
+
<ul class="statistics">
|
|
23
|
+
<% total = newsletter.subscribed_count + newsletter.unsubscribed_count + newsletter.cleaned_count %>
|
|
24
|
+
<li><%= stat_block_small label: 'subscribed', number: newsletter.subscribed_count, color_type: :success, percent: total == 0 ? 0 : (100 * newsletter.subscribed_count / total) %></li>
|
|
25
|
+
<li><%= stat_block_small label: 'unsubscribed', number: newsletter.unsubscribed_count, color_type: :danger, percent: total == 0 ? 0 : (100 * newsletter.unsubscribed_count / total) %></li>
|
|
26
|
+
<li><%= stat_block_small label: 'cleaned', number: newsletter.cleaned_count, color_type: :info, percent: total == 0 ? 0 : (100 * newsletter.cleaned_count / total) %></li>
|
|
27
|
+
</ul>
|
|
28
|
+
<% end %>
|
|
29
|
+
</div>
|
|
30
|
+
<% end %>
|
|
31
|
+
</div>
|
|
32
|
+
<% end %>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<% content_for :content_title, "#{@newsletter.name} <small>Newsletter</small>".html_safe %>
|
|
2
|
+
<% content_for :content_title_extra do %>
|
|
3
|
+
<%= page_header_buttons do %>
|
|
4
|
+
<%= link_to(icon_label(:trash, 'Delete'), admin_newsletter_path(@newsletter), method: :delete, class: "btn btn-xs btn-default", data: {confirm: 'Are you sure you wish to delete this newsletter?'}) %>
|
|
5
|
+
<% end %>
|
|
6
|
+
<% end %>
|
|
7
|
+
|
|
8
|
+
<%= panel header: false do %>
|
|
9
|
+
<div class="row">
|
|
10
|
+
<ul class="statistics">
|
|
11
|
+
<% total = @newsletter.subscribed_count + @newsletter.unsubscribed_count + @newsletter.cleaned_count %>
|
|
12
|
+
<li><%= stat_block_small label: 'subscribed', number: @newsletter.subscribed_count, color_type: :success, percent: total == 0 ? 0 : (100 * @newsletter.subscribed_count / total) %></li>
|
|
13
|
+
<li><%= stat_block_small label: 'unsubscribed', number: @newsletter.unsubscribed_count, color_type: :danger, percent: total == 0 ? 0 : (100 * @newsletter.unsubscribed_count / total) %></li>
|
|
14
|
+
<li><%= stat_block_small label: 'cleaned', number: @newsletter.cleaned_count, color_type: :info, percent: total == 0 ? 0 : (100 * @newsletter.cleaned_count / total) %></li>
|
|
15
|
+
</ul>
|
|
16
|
+
<hr>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="row">
|
|
20
|
+
<dl class="dl-horizontal">
|
|
21
|
+
<dt>Subscription Token</dt>
|
|
22
|
+
<dd><%= @newsletter.token %></dd>
|
|
23
|
+
</dl>
|
|
24
|
+
</div>
|
|
25
|
+
<% end %>
|
|
26
|
+
|
|
27
|
+
<%= panel body: false, title: 'Campaign Folders' do %>
|
|
28
|
+
<table class="table table-striped table-bordered">
|
|
29
|
+
<thead>
|
|
30
|
+
<tr>
|
|
31
|
+
<th>Name</th>
|
|
32
|
+
<th width="50">Count</th>
|
|
33
|
+
<th width="100">Folder ID</th>
|
|
34
|
+
</tr>
|
|
35
|
+
</thead>
|
|
36
|
+
<tbody>
|
|
37
|
+
<% @folder_list.each do |folder| %>
|
|
38
|
+
<tr class="item">
|
|
39
|
+
<td><%= folder['name'] %></td>
|
|
40
|
+
<td><%= folder['cnt'] %></td>
|
|
41
|
+
<td><%= folder['folder_id'] %></td>
|
|
42
|
+
</tr>
|
|
43
|
+
<% end %>
|
|
44
|
+
</tbody>
|
|
45
|
+
</table>
|
|
46
|
+
<% end %>
|