dm_newsletter 4.2.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +33 -0
  4. data/Rakefile +30 -0
  5. data/app/assets/stylesheets/dm_newsletter/application.css +13 -0
  6. data/app/controllers/dm_newsletter/admin/admin_controller.rb +16 -0
  7. data/app/controllers/dm_newsletter/admin/newsletters_controller.rb +81 -0
  8. data/app/controllers/dm_newsletter/application_controller.rb +3 -0
  9. data/app/controllers/dm_newsletter/newsletters_controller.rb +50 -0
  10. data/app/helpers/dm_newsletter/newsletters_helper.rb +8 -0
  11. data/app/models/dm_newsletter/concerns/ability.rb +37 -0
  12. data/app/models/dm_newsletter/permitted_params.rb +20 -0
  13. data/app/models/mailchimp_newsletter.rb +217 -0
  14. data/app/models/mailchimp_newsletter_subscriber.rb +43 -0
  15. data/app/models/newsletter.rb +46 -0
  16. data/app/models/newsletter_subscriber.rb +257 -0
  17. data/app/models/standard_newsletter.rb +19 -0
  18. data/app/views/dm_newsletter/admin/newsletters/_form.html.erb +17 -0
  19. data/app/views/dm_newsletter/admin/newsletters/edit.html.erb +2 -0
  20. data/app/views/dm_newsletter/admin/newsletters/index.html.erb +32 -0
  21. data/app/views/dm_newsletter/admin/newsletters/new.html.erb +2 -0
  22. data/app/views/dm_newsletter/admin/newsletters/show.html.erb +46 -0
  23. data/config/locales/nms.cs.yml +15 -0
  24. data/config/locales/nms.de.yml +15 -0
  25. data/config/locales/nms.en.yml +15 -0
  26. data/config/locales/nms.fi.yml +15 -0
  27. data/config/locales/nms.ja.yml +15 -0
  28. data/config/routes.rb +15 -0
  29. data/db/20130730120724_create_subscribers.rb +32 -0
  30. data/db/migrate/20130729075442_create_newsletter.rb +24 -0
  31. data/lib/dm_newsletter.rb +4 -0
  32. data/lib/dm_newsletter/engine.rb +8 -0
  33. data/lib/tasks/dm_newsletter_tasks.rake +4 -0
  34. data/spec/dummy/README.rdoc +28 -0
  35. data/spec/dummy/Rakefile +6 -0
  36. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  37. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  38. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  39. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  40. data/spec/dummy/app/models/ability.rb +12 -0
  41. data/spec/dummy/app/models/user.rb +6 -0
  42. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  43. data/spec/dummy/bin/bundle +3 -0
  44. data/spec/dummy/bin/rails +4 -0
  45. data/spec/dummy/bin/rake +4 -0
  46. data/spec/dummy/config.ru +4 -0
  47. data/spec/dummy/config/application.rb +26 -0
  48. data/spec/dummy/config/boot.rb +5 -0
  49. data/spec/dummy/config/database.yml +25 -0
  50. data/spec/dummy/config/environment.rb +5 -0
  51. data/spec/dummy/config/environments/development.rb +37 -0
  52. data/spec/dummy/config/environments/production.rb +82 -0
  53. data/spec/dummy/config/environments/test.rb +39 -0
  54. data/spec/dummy/config/initializers/assets.rb +8 -0
  55. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  56. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  57. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  58. data/spec/dummy/config/initializers/inflections.rb +16 -0
  59. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  60. data/spec/dummy/config/initializers/session_store.rb +3 -0
  61. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  62. data/spec/dummy/config/locales/en.yml +23 -0
  63. data/spec/dummy/config/routes.rb +12 -0
  64. data/spec/dummy/config/secrets.yml +22 -0
  65. data/spec/dummy/db/development.sqlite3 +0 -0
  66. data/spec/dummy/db/migrate/20141114170927_add_globalize_countries.dm_core.rb +50 -0
  67. data/spec/dummy/db/migrate/20141114170928_devise_create_users.dm_core.rb +46 -0
  68. data/spec/dummy/db/migrate/20141114170929_add_user_fields.dm_core.rb +14 -0
  69. data/spec/dummy/db/migrate/20141114170930_rolify_create_roles.dm_core.rb +20 -0
  70. data/spec/dummy/db/migrate/20141114170931_add_last_access.dm_core.rb +10 -0
  71. data/spec/dummy/db/migrate/20141114170932_create_versions.dm_core.rb +19 -0
  72. data/spec/dummy/db/migrate/20141114170933_add_object_changes_column_to_versions.dm_core.rb +12 -0
  73. data/spec/dummy/db/migrate/20141114170934_create_dm_core_accounts.dm_core.rb +13 -0
  74. data/spec/dummy/db/migrate/20141114170935_add_account_to_users.dm_core.rb +9 -0
  75. data/spec/dummy/db/migrate/20141114170936_create_preferences.dm_core.rb +13 -0
  76. data/spec/dummy/db/migrate/20141114170937_create_comments.dm_core.rb +22 -0
  77. data/spec/dummy/db/migrate/20141114170938_add_activity.dm_core.rb +21 -0
  78. data/spec/dummy/db/migrate/20141114170939_add_type_to_comments.dm_core.rb +9 -0
  79. data/spec/dummy/db/migrate/20141114170940_add_category.dm_core.rb +28 -0
  80. data/spec/dummy/db/migrate/20141114170941_create_email_table.dm_core.rb +26 -0
  81. data/spec/dummy/db/migrate/20141114170942_add_user_profile.dm_core.rb +46 -0
  82. data/spec/dummy/db/migrate/20141114170943_add_profile_email.dm_core.rb +14 -0
  83. data/spec/dummy/db/migrate/20141114170944_create_payment_history.dm_core.rb +37 -0
  84. data/spec/dummy/db/migrate/20141114170945_change_anchor_field.dm_core.rb +10 -0
  85. data/spec/dummy/db/migrate/20141114170946_create_user_site_profile.dm_core.rb +27 -0
  86. data/spec/dummy/db/migrate/20141114170947_add_avatar.dm_core.rb +12 -0
  87. data/spec/dummy/db/migrate/20141114170948_add_notify_to_payment_history.dm_core.rb +8 -0
  88. data/spec/dummy/db/migrate/20141114170949_acts_as_votable_migration.dm_core.rb +28 -0
  89. data/spec/dummy/db/migrate/20141114170950_add_user_site_profile_uuid.dm_core.rb +19 -0
  90. data/spec/dummy/db/migrate/20141114170951_add_invoice_id.dm_core.rb +7 -0
  91. data/spec/dummy/db/migrate/20141114170952_acts_as_follower_migration.dm_core.rb +18 -0
  92. data/spec/dummy/db/migrate/20141114170953_rename_invoice_id.dm_core.rb +12 -0
  93. data/spec/dummy/db/migrate/20141114170954_add_core_addresses.dm_core.rb +18 -0
  94. data/spec/dummy/db/migrate/20141114170955_papertrail_increase_column.dm_core.rb +9 -0
  95. data/spec/dummy/db/migrate/20141114170956_acts_as_taggable_on_migration.dm_core.rb +32 -0
  96. data/spec/dummy/db/migrate/20141114170957_add_missing_unique_indices.dm_core.rb +23 -0
  97. data/spec/dummy/db/migrate/20141114170958_add_taggings_counter_cache_to_tags.dm_core.rb +16 -0
  98. data/spec/dummy/db/migrate/20141114170959_create_custom_fields.dm_core.rb +40 -0
  99. data/spec/dummy/db/migrate/20141114170960_add_missing_taggable_index.dm_core.rb +11 -0
  100. data/spec/dummy/db/migrate/20141119112030_create_cms.dm_cms.rb +92 -0
  101. data/spec/dummy/db/migrate/20141119112031_add_account_to_cms.dm_cms.rb +11 -0
  102. data/spec/dummy/db/migrate/20141119112032_create_blog.dm_cms.rb +62 -0
  103. data/spec/dummy/db/migrate/20141119112033_add_notification_sent.dm_cms.rb +6 -0
  104. data/spec/dummy/db/migrate/20141119112034_add_blog_comment.dm_cms.rb +8 -0
  105. data/spec/dummy/db/migrate/20141119112035_add_blog_image.dm_cms.rb +6 -0
  106. data/spec/dummy/db/migrate/20141119112036_rename_snippet_slug.dm_cms.rb +14 -0
  107. data/spec/dummy/db/migrate/20141119112037_add_requires_subscription_blog.dm_cms.rb +8 -0
  108. data/spec/dummy/db/migrate/20141119112038_add_pages_ranked_model.dm_cms.rb +23 -0
  109. data/spec/dummy/db/migrate/20141119112039_add_blog_owner.dm_cms.rb +7 -0
  110. data/spec/dummy/db/migrate/20141119112040_create_media_files.dm_cms.rb +30 -0
  111. data/spec/dummy/db/migrate/20141119112041_add_cmspage_summary.dm_cms.rb +7 -0
  112. data/spec/dummy/db/migrate/20141119112042_add_blog_image_email_header.dm_cms.rb +6 -0
  113. data/spec/dummy/db/migrate/20141119112043_add_header_image.dm_cms.rb +10 -0
  114. data/spec/dummy/db/migrate/20160128145239_add_favored_locale.dm_core.rb +17 -0
  115. data/spec/dummy/db/migrate/20160128145240_update_papertrail_v4.dm_core.rb +41 -0
  116. data/spec/dummy/db/schema.rb +593 -0
  117. data/spec/dummy/public/404.html +67 -0
  118. data/spec/dummy/public/422.html +67 -0
  119. data/spec/dummy/public/500.html +66 -0
  120. data/spec/dummy/public/favicon.ico +0 -0
  121. data/spec/factories/accounts.rb +9 -0
  122. data/spec/factories/user_profiles.rb +10 -0
  123. data/spec/factories/users.rb +19 -0
  124. data/spec/models/newsletter_spec.rb +9 -0
  125. data/spec/rails_helper.rb +70 -0
  126. data/spec/spec_helper.rb +85 -0
  127. data/spec/support/accounts.rb +17 -0
  128. data/spec/support/devise.rb +44 -0
  129. data/spec/support/fix_locale.rb +57 -0
  130. 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,2 @@
1
+ <% content_for :content_title, "Edit Newsletter <small>#{@newsletter.name}</small>".html_safe %>
2
+ <%= render 'form' %>
@@ -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,2 @@
1
+ <% content_for :content_title, 'New Newsletter' %>
2
+ <%= render 'form' %>
@@ -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 %>