dm_newsletter 4.2.1.5
Sign up to get free protection for your applications and to get access to all the features.
- 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 %>
|