apn_on_rails 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -13,4 +13,5 @@ build/*
13
13
  .svn
14
14
  profile
15
15
  spec/active_record/test.db
16
- .bundle
16
+ .bundle
17
+ **/.svn
data/Gemfile CHANGED
@@ -8,8 +8,9 @@ gem 'configatron'
8
8
  # Add dependencies to develop your gem here.
9
9
  # Include everything needed to run rake, tests, features, etc.
10
10
  group :development do
11
+ gem 'autotest'
11
12
  gem 'sqlite3-ruby'
12
- gem "rspec", ">= 2.0.0.beta.19"
13
+ gem "rspec", ">= 2.0.0"
13
14
  gem "bundler", ">= 1.0.0.rc.5"
14
15
  gem "jeweler", "~> 1.5.0.pre2"
15
16
  gem "rcov", ">= 0"
@@ -7,6 +7,7 @@ GEM
7
7
  activerecord (2.3.9)
8
8
  activesupport (= 2.3.9)
9
9
  activesupport (2.3.9)
10
+ autotest (4.3.2)
10
11
  configatron (2.6.4)
11
12
  yamler (>= 0.1.0)
12
13
  diff-lcs (1.1.2)
@@ -18,16 +19,16 @@ GEM
18
19
  rack (1.1.0)
19
20
  rake (0.8.7)
20
21
  rcov (0.9.9)
21
- rspec (2.0.0.rc)
22
- rspec-core (= 2.0.0.rc)
23
- rspec-expectations (= 2.0.0.rc)
24
- rspec-mocks (= 2.0.0.rc)
25
- rspec-core (2.0.0.rc)
26
- rspec-expectations (2.0.0.rc)
22
+ rspec (2.0.1)
23
+ rspec-core (~> 2.0.1)
24
+ rspec-expectations (~> 2.0.1)
25
+ rspec-mocks (~> 2.0.1)
26
+ rspec-core (2.0.1)
27
+ rspec-expectations (2.0.1)
27
28
  diff-lcs (>= 1.1.2)
28
- rspec-mocks (2.0.0.rc)
29
- rspec-core (= 2.0.0.rc)
30
- rspec-expectations (= 2.0.0.rc)
29
+ rspec-mocks (2.0.1)
30
+ rspec-core (~> 2.0.1)
31
+ rspec-expectations (~> 2.0.1)
31
32
  sqlite3-ruby (1.3.1)
32
33
  yamler (0.1.0)
33
34
 
@@ -37,9 +38,10 @@ PLATFORMS
37
38
  DEPENDENCIES
38
39
  actionpack (~> 2.3.8)
39
40
  activerecord (~> 2.3.8)
41
+ autotest
40
42
  bundler (>= 1.0.0.rc.5)
41
43
  configatron
42
44
  jeweler (~> 1.5.0.pre2)
43
45
  rcov
44
- rspec (>= 2.0.0.beta.19)
46
+ rspec (>= 2.0.0)
45
47
  sqlite3-ruby
data/README CHANGED
@@ -4,7 +4,7 @@ APN on Rails is a Ruby on Rails gem that allows you to easily add Apple Push Not
4
4
  support to your Rails application.
5
5
 
6
6
  It supports:
7
- * Multiple iPhone apps managed from the same Rails application
7
+ * Multiple iPhone apps managed from the same Rails application as well as a legacy default "app" with certs stored in config
8
8
  * Individual notifications and group notifications
9
9
  * Alerts, badges, sounds, and custom properties in notifications
10
10
  * Pull notifications
@@ -14,13 +14,16 @@ It supports:
14
14
  Multiple iPhone Apps: In previous versions of this gem a single Rails application was set up to
15
15
  manage push notifications for a single iPhone app. In many cases it is useful to have a single Rails
16
16
  app manage push notifications for multiple iPhone apps. With the addition of an APN::App model, this
17
- is now possible. The certificates are now stored on instances of APN::APP and all devices are associated
18
- with a particular app.
17
+ is now possible. The certificates are now stored on instances of APN::App and devices are intended to be associated
18
+ with a particular app. For compatibility with existing implementations it is still possible to create devices that
19
+ are not associated with an APN::App and to send individual notifications to them using the certs stored in the
20
+ config directory.
19
21
 
20
22
  Individual and Group Notifications: Previous versions of this gem treated each notification individually
21
23
  and did not provide a built-in way to send a broadcast notification to a group of devices. Group notifications
22
24
  are now built into the gem. A group notification is associated with a group of devices and shares its
23
- contents across the entire group of devices.
25
+ contents across the entire group of devices. (Group notifications are only available for groups of devices associated
26
+ with an APN::App)
24
27
 
25
28
  Notification Content Areas: Notifications may contain alerts, badges, sounds, and custom properties.
26
29
 
@@ -28,7 +31,14 @@ Pull Notifications: This version of the gem supports an alternative notification
28
31
  on pulls from client devices and does not interact with the Apple Push Notification servers. This feature
29
32
  may be used entirely independently of the push notification features. Pull notifications may be
30
33
  created for an app. A client app can query for the most recent pull notification available since a
31
- given date to retrieve any notifications waiting for it.
34
+ given date to retrieve any notifications waiting for it.
35
+
36
+ ==Version 0.4.1 Notes
37
+
38
+ * Backwards compatibility. 0.4.0 required a manual upgrade to associate existing and new devices with an APN::App model. This version allows continued use of devices that are associated with a default "app" that stores its certificates in the config directory. This ought to allow upgrade to this version without code changes.
39
+ * Batched finds. Finds on the APN::Device model that can return large numbers of records have been batched to limit memory impact.
40
+ * Custom properties migration. At a pre-0.4.0 version the custom_properties attribute was added to the migration template that created the notifications table. This introduced a potential problem for gem users who had previously run this migration. The custom_properties alteration to the apn_notifications table has been moved to its own migration and should work regardless of whether your apn_notifications table already has a custom_properties attribute.
41
+ * last_registered_at changed to work intuitively. The last_registered_at attribute of devices was being updated only on creation potentially causing a bug in which a device that opts out of APNs and then opts back in before apn_on_rails received feedback about it might miss a period of APNs that it should receive.
32
42
 
33
43
  ==Acknowledgements:
34
44
 
@@ -105,9 +115,9 @@ Now, to create the tables you need for APN on Rails, run the following task:
105
115
 
106
116
  APN on Rails uses the Configatron gem, http://github.com/markbates/configatron/tree/master,
107
117
  to configure itself. (With the change to multi-app support, the certifications are stored in the
108
- database rather than in the config directory. These configurations remain for now.)
109
- APN on Rails has the following default configurations that you change as you
110
- see fit:
118
+ database rather than in the config directory, however, it is still possible to use the default "app" and the certificates
119
+ stored in the config directory. For this setup, the following configurations apply.)
120
+ APN on Rails has the following default configurations that you change as you see fit:
111
121
 
112
122
  # development (delivery):
113
123
  configatron.apn.passphrase # => ''
@@ -142,7 +152,7 @@ That way you ensure you have the latest version of the database tables needed.
142
152
  ==Example (assuming you have created an app and stored your keys on it):
143
153
 
144
154
  $ ./script/console
145
- >> app = APN::App.find(:first)
155
+ >> app = APN::App.create(:name => "My App", :apn_dev_cert => "PASTE YOUR DEV CERT HERE", :apn_prod_cert => "PASTE YOUR PROD CERT HERE")
146
156
  >> device = APN::Device.create(:token => "XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX",:app_id => app.id)
147
157
  >> notification = APN::Notification.new
148
158
  >> notification.device = device
@@ -4,7 +4,7 @@ APN on Rails is a Ruby on Rails gem that allows you to easily add Apple Push Not
4
4
  support to your Rails application.
5
5
 
6
6
  It supports:
7
- * Multiple iPhone apps managed from the same Rails application
7
+ * Multiple iPhone apps managed from the same Rails application as well as a legacy default "app" with certs stored in config
8
8
  * Individual notifications and group notifications
9
9
  * Alerts, badges, sounds, and custom properties in notifications
10
10
  * Pull notifications
@@ -14,13 +14,16 @@ h2. Feature Descriptions
14
14
  Multiple iPhone Apps: In previous versions of this gem a single Rails application was set up to
15
15
  manage push notifications for a single iPhone app. In many cases it is useful to have a single Rails
16
16
  app manage push notifications for multiple iPhone apps. With the addition of an APN::App model, this
17
- is now possible. The certificates are now stored on instances of APN::APP and all devices are associated
18
- with a particular app.
17
+ is now possible. The certificates are now stored on instances of APN::App and all devices are intended to be associated
18
+ with a particular app. For compatibility with existing implementations it is still possible to create devices that
19
+ are not associated with an APN::App and to send individual notifications to them using the certs stored in the
20
+ config directory.
19
21
 
20
22
  Individual and Group Notifications: Previous versions of this gem treated each notification individually
21
23
  and did not provide a built-in way to send a broadcast notification to a group of devices. Group notifications
22
24
  are now built into the gem. A group notification is associated with a group of devices and shares its
23
- contents across the entire group of devices.
25
+ contents across the entire group of devices. (Group notifications are only available for groups of devices associated
26
+ with an APN::App)
24
27
 
25
28
  Notification Content Areas: Notifications may contain alerts, badges, sounds, and custom properties.
26
29
 
@@ -30,6 +33,13 @@ may be used entirely independently of the push notification features. Pull noti
30
33
  created for an app. A client app can query for the most recent pull notification available since a
31
34
  given date to retrieve any notifications waiting for it.
32
35
 
36
+ h2. Version 0.4.1 Notes
37
+
38
+ * Backwards compatibility. 0.4.0 required a manual upgrade to associate existing and new devices with an APN::App model. This version allows continued use of devices that are associated with a default "app" that stores its certificates in the config directory. This ought to allow upgrade to this version without code changes.
39
+ * Batched finds. Finds on the APN::Device model that can return large numbers of records have been batched to limit memory impact.
40
+ * Custom properties migration. At a pre-0.4.0 version the custom_properties attribute was added to the migration template that created the notifications table. This introduced a potential problem for gem users who had previously run this migration. The custom_properties alteration to the apn_notifications table has been moved to its own migration and should work regardless of whether your apn_notifications table already has a custom_properties attribute.
41
+ * last_registered_at changed to work intuitively. The last_registered_at attribute of devices was being updated only on creation potentially causing a bug in which a device that opts out of APNs and then opts back in before apn_on_rails received feedback about it might miss a period of APNs that it should receive.
42
+
33
43
  h2. Acknowledgements:
34
44
 
35
45
  From Mark Bates:
@@ -121,7 +131,8 @@ Now, to create the tables you need for APN on Rails, run the following task:
121
131
 
122
132
  APN on Rails uses the Configatron gem, http://github.com/markbates/configatron/tree/master,
123
133
  to configure itself. (With the change to multi-app support, the certifications are stored in the
124
- database rather than in the config directory. These configurations remain for now.)
134
+ database rather than in the config directory, however, it is still possible to use the default "app" and the certificates
135
+ stored in the config directory. For this setup, the following configurations apply.)
125
136
  APN on Rails has the following default configurations that you change as you
126
137
  see fit:
127
138
 
@@ -166,7 +177,7 @@ h2. Example (assuming you have created an app and stored your keys on it):
166
177
 
167
178
  <pre><code>
168
179
  $ ./script/console
169
- >> app = APN::App.find(:first)
180
+ >> app = APN::App.create(:name => "My App", :apn_dev_cert => "PASTE YOUR DEV CERT HERE", :apn_prod_cert => "PASTE YOUR PROD CERT HERE")
170
181
  >> device = APN::Device.create(:token => "XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX",:app_id => app.id)
171
182
  >> notification = APN::Notification.new
172
183
  >> notification.device = device
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.4.1
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{apn_on_rails}
8
- s.version = "0.3.1"
8
+ s.version = "0.4.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["markbates", "Rebecca Nesson"]
12
- s.date = %q{2010-10-06}
12
+ s.date = %q{2010-11-09}
13
13
  s.description = %q{APN on Rails is a Ruby on Rails gem that allows you to
14
14
  easily add Apple Push Notification (iPhone) support to your Rails application.
15
15
  }
@@ -22,6 +22,7 @@ easily add Apple Push Notification (iPhone) support to your Rails application.
22
22
  s.files = [
23
23
  ".gitignore",
24
24
  ".rspec",
25
+ ".specification",
25
26
  "Gemfile",
26
27
  "Gemfile.lock",
27
28
  "LICENSE",
@@ -30,28 +31,50 @@ easily add Apple Push Notification (iPhone) support to your Rails application.
30
31
  "Rakefile",
31
32
  "VERSION",
32
33
  "apn_on_rails.gemspec",
34
+ "autotest/discover.rb",
33
35
  "generators/apn_migrations_generator.rb",
34
36
  "generators/templates/apn_migrations/001_create_apn_devices.rb",
35
37
  "generators/templates/apn_migrations/002_create_apn_notifications.rb",
36
38
  "generators/templates/apn_migrations/003_alter_apn_devices.rb",
39
+ "generators/templates/apn_migrations/004_create_apn_apps.rb",
40
+ "generators/templates/apn_migrations/005_create_groups.rb",
41
+ "generators/templates/apn_migrations/006_alter_apn_groups.rb",
42
+ "generators/templates/apn_migrations/007_create_device_groups.rb",
43
+ "generators/templates/apn_migrations/008_create_apn_group_notifications.rb",
44
+ "generators/templates/apn_migrations/009_create_pull_notifications.rb",
45
+ "generators/templates/apn_migrations/010_alter_apn_notifications.rb",
46
+ "generators/templates/apn_migrations/011_make_device_token_index_nonunique.rb",
37
47
  "lib/apn_on_rails.rb",
38
48
  "lib/apn_on_rails/apn_on_rails.rb",
49
+ "lib/apn_on_rails/app/models/apn/app.rb",
39
50
  "lib/apn_on_rails/app/models/apn/base.rb",
40
51
  "lib/apn_on_rails/app/models/apn/device.rb",
52
+ "lib/apn_on_rails/app/models/apn/device_grouping.rb",
53
+ "lib/apn_on_rails/app/models/apn/group.rb",
54
+ "lib/apn_on_rails/app/models/apn/group_notification.rb",
41
55
  "lib/apn_on_rails/app/models/apn/notification.rb",
56
+ "lib/apn_on_rails/app/models/apn/pull_notification.rb",
42
57
  "lib/apn_on_rails/libs/connection.rb",
43
58
  "lib/apn_on_rails/libs/feedback.rb",
44
59
  "lib/apn_on_rails/tasks/apn.rake",
45
60
  "lib/apn_on_rails/tasks/db.rake",
46
61
  "lib/apn_on_rails_tasks.rb",
47
62
  "spec/active_record/setup_ar.rb",
63
+ "spec/apn_on_rails/app/models/apn/app_spec.rb",
48
64
  "spec/apn_on_rails/app/models/apn/device_spec.rb",
65
+ "spec/apn_on_rails/app/models/apn/group_notification_spec.rb",
49
66
  "spec/apn_on_rails/app/models/apn/notification_spec.rb",
67
+ "spec/apn_on_rails/app/models/apn/pull_notification_spec.rb",
50
68
  "spec/apn_on_rails/libs/connection_spec.rb",
51
69
  "spec/apn_on_rails/libs/feedback_spec.rb",
52
70
  "spec/extensions/string.rb",
71
+ "spec/factories/app_factory.rb",
53
72
  "spec/factories/device_factory.rb",
73
+ "spec/factories/device_grouping_factory.rb",
74
+ "spec/factories/group_factory.rb",
75
+ "spec/factories/group_notification_factory.rb",
54
76
  "spec/factories/notification_factory.rb",
77
+ "spec/factories/pull_notification_factory.rb",
55
78
  "spec/fixtures/hexa.bin",
56
79
  "spec/fixtures/message_for_sending.bin",
57
80
  "spec/rails_root/config/apple_push_notification_development.pem",
@@ -63,13 +86,21 @@ easily add Apple Push Notification (iPhone) support to your Rails application.
63
86
  s.summary = %q{Apple Push Notifications on Rails}
64
87
  s.test_files = [
65
88
  "spec/active_record/setup_ar.rb",
89
+ "spec/apn_on_rails/app/models/apn/app_spec.rb",
66
90
  "spec/apn_on_rails/app/models/apn/device_spec.rb",
91
+ "spec/apn_on_rails/app/models/apn/group_notification_spec.rb",
67
92
  "spec/apn_on_rails/app/models/apn/notification_spec.rb",
93
+ "spec/apn_on_rails/app/models/apn/pull_notification_spec.rb",
68
94
  "spec/apn_on_rails/libs/connection_spec.rb",
69
95
  "spec/apn_on_rails/libs/feedback_spec.rb",
70
96
  "spec/extensions/string.rb",
97
+ "spec/factories/app_factory.rb",
71
98
  "spec/factories/device_factory.rb",
99
+ "spec/factories/device_grouping_factory.rb",
100
+ "spec/factories/group_factory.rb",
101
+ "spec/factories/group_notification_factory.rb",
72
102
  "spec/factories/notification_factory.rb",
103
+ "spec/factories/pull_notification_factory.rb",
73
104
  "spec/spec_helper.rb"
74
105
  ]
75
106
 
@@ -79,8 +110,9 @@ easily add Apple Push Notification (iPhone) support to your Rails application.
79
110
 
80
111
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
81
112
  s.add_runtime_dependency(%q<configatron>, [">= 0"])
113
+ s.add_development_dependency(%q<autotest>, [">= 0"])
82
114
  s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
83
- s.add_development_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
115
+ s.add_development_dependency(%q<rspec>, [">= 2.0.0"])
84
116
  s.add_development_dependency(%q<bundler>, [">= 1.0.0.rc.5"])
85
117
  s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre2"])
86
118
  s.add_development_dependency(%q<rcov>, [">= 0"])
@@ -88,8 +120,9 @@ easily add Apple Push Notification (iPhone) support to your Rails application.
88
120
  s.add_development_dependency(%q<activerecord>, ["~> 2.3.8"])
89
121
  else
90
122
  s.add_dependency(%q<configatron>, [">= 0"])
123
+ s.add_dependency(%q<autotest>, [">= 0"])
91
124
  s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
92
- s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
125
+ s.add_dependency(%q<rspec>, [">= 2.0.0"])
93
126
  s.add_dependency(%q<bundler>, [">= 1.0.0.rc.5"])
94
127
  s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre2"])
95
128
  s.add_dependency(%q<rcov>, [">= 0"])
@@ -98,8 +131,9 @@ easily add Apple Push Notification (iPhone) support to your Rails application.
98
131
  end
99
132
  else
100
133
  s.add_dependency(%q<configatron>, [">= 0"])
134
+ s.add_dependency(%q<autotest>, [">= 0"])
101
135
  s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
102
- s.add_dependency(%q<rspec>, [">= 2.0.0.beta.19"])
136
+ s.add_dependency(%q<rspec>, [">= 2.0.0"])
103
137
  s.add_dependency(%q<bundler>, [">= 1.0.0.rc.5"])
104
138
  s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre2"])
105
139
  s.add_dependency(%q<rcov>, [">= 0"])
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
@@ -9,7 +9,6 @@ class CreateApnNotifications < ActiveRecord::Migration # :nodoc:
9
9
  t.string :sound
10
10
  t.string :alert, :size => 150
11
11
  t.integer :badge
12
- t.text :custom_properties
13
12
  t.datetime :sent_at
14
13
  t.timestamps
15
14
  end
@@ -12,7 +12,7 @@ class CreateApnApps < ActiveRecord::Migration # :nodoc:
12
12
  end
13
13
 
14
14
  def self.down
15
- drop_table :apps
15
+ drop_table :apn_apps
16
16
  remove_column :apn_devices, :app_id
17
17
  end
18
- end
18
+ end
@@ -0,0 +1,21 @@
1
+ class AlterApnNotifications < ActiveRecord::Migration # :nodoc:
2
+
3
+ module APN # :nodoc:
4
+ class Notification < ActiveRecord::Base # :nodoc:
5
+ set_table_name 'apn_notifications'
6
+ end
7
+ end
8
+
9
+ def self.up
10
+ unless APN::Notification.column_names.include?("custom_properties")
11
+ add_column :apn_notifications, :custom_properties, :text
12
+ end
13
+ end
14
+
15
+ def self.down
16
+ if APN::Notification.column_names.include?("custom_properties")
17
+ remove_column :apn_notifications, :custom_properties
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,11 @@
1
+ class MakeDeviceTokenIndexNonunique < ActiveRecord::Migration
2
+ def self.up
3
+ remove_index :apn_devices, :column => :token
4
+ add_index :apn_devices, :token
5
+ end
6
+
7
+ def self.down
8
+ remove_index :apn_devices, :column => :token
9
+ add_index :apn_devices, :token, :unique => true
10
+ end
11
+ end
@@ -23,15 +23,7 @@ class APN::App < APN::Base
23
23
  raise APN::Errors::MissingCertificateError.new
24
24
  return
25
25
  end
26
- unless self.unsent_notifications.nil? || self.unsent_notifications.empty?
27
- APN::Connection.open_for_delivery({:cert => self.cert}) do |conn, sock|
28
- unsent_notifications.each do |noty|
29
- conn.write(noty.message_for_sending)
30
- noty.sent_at = Time.now
31
- noty.save
32
- end
33
- end
34
- end
26
+ APN::App.send_notifications_for_cert(self.cert, self.id)
35
27
  end
36
28
 
37
29
  def self.send_notifications
@@ -39,6 +31,32 @@ class APN::App < APN::Base
39
31
  apps.each do |app|
40
32
  app.send_notifications
41
33
  end
34
+ global_cert = File.read(configatron.apn.cert)
35
+ if global_cert
36
+ send_notifications_for_cert(global_cert, nil)
37
+ end
38
+ end
39
+
40
+ def self.send_notifications_for_cert(the_cert, app_id)
41
+ # unless self.unsent_notifications.nil? || self.unsent_notifications.empty?
42
+ if (app_id == nil)
43
+ conditions = "app_id is null"
44
+ else
45
+ conditions = ["app_id = ?", app_id]
46
+ end
47
+ begin
48
+ APN::Connection.open_for_delivery({:cert => the_cert}) do |conn, sock|
49
+ APN::Device.find_each(:conditions => conditions) do |dev|
50
+ dev.unsent_notifications.each do |noty|
51
+ conn.write(noty.message_for_sending)
52
+ noty.sent_at = Time.now
53
+ noty.save
54
+ end
55
+ end
56
+ end
57
+ rescue
58
+ end
59
+ # end
42
60
  end
43
61
 
44
62
  def send_group_notifications
@@ -49,8 +67,7 @@ class APN::App < APN::Base
49
67
  unless self.unsent_group_notifications.nil? || self.unsent_group_notifications.empty?
50
68
  APN::Connection.open_for_delivery({:cert => self.cert}) do |conn, sock|
51
69
  unsent_group_notifications.each do |gnoty|
52
- puts "number of devices is #{gnoty.devices.size}"
53
- gnoty.devices.each do |device|
70
+ gnoty.devices.find_each do |device|
54
71
  conn.write(gnoty.message_for_sending(device))
55
72
  end
56
73
  gnoty.sent_at = Time.now
@@ -67,7 +84,7 @@ class APN::App < APN::Base
67
84
  end
68
85
  unless gnoty.nil?
69
86
  APN::Connection.open_for_delivery({:cert => self.cert}) do |conn, sock|
70
- gnoty.devices.each do |device|
87
+ gnoty.devices.find_each do |device|
71
88
  conn.write(gnoty.message_for_sending(device))
72
89
  end
73
90
  gnoty.sent_at = Time.now
@@ -98,11 +115,7 @@ class APN::App < APN::Base
98
115
  raise APN::Errors::MissingCertificateError.new
99
116
  return
100
117
  end
101
- APN::Feedback.devices(self.cert).each do |device|
102
- if device.last_registered_at < device.feedback_at
103
- device.destroy
104
- end
105
- end
118
+ APN::App.process_devices_for_cert(self.cert)
106
119
  end # process_devices
107
120
 
108
121
  def self.process_devices
@@ -110,6 +123,22 @@ class APN::App < APN::Base
110
123
  apps.each do |app|
111
124
  app.process_devices
112
125
  end
126
+ global_cert = File.read(configatron.apn.cert)
127
+ if global_cert
128
+ APN::App.process_devices_for_cert(global_cert)
129
+ end
130
+ end
131
+
132
+ def self.process_devices_for_cert(the_cert)
133
+ puts "in APN::App.process_devices_for_cert"
134
+ APN::Feedback.devices(the_cert).each do |device|
135
+ if device.last_registered_at < device.feedback_at
136
+ puts "device #{device.id} -> #{device.last_registered_at} < #{device.feedback_at}"
137
+ device.destroy
138
+ else
139
+ puts "device #{device.id} -> #{device.last_registered_at} not < #{device.feedback_at}"
140
+ end
141
+ end
113
142
  end
114
143
 
115
144
  end
@@ -17,7 +17,7 @@ class APN::Device < APN::Base
17
17
  validates_uniqueness_of :token, :scope => :app_id
18
18
  validates_format_of :token, :with => /^[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}$/
19
19
 
20
- before_save :set_last_registered_at
20
+ before_create :set_last_registered_at
21
21
 
22
22
  # The <tt>feedback_at</tt> accessor is set when the
23
23
  # device is marked as potentially disconnected from your
@@ -42,9 +42,8 @@ class APN::Device < APN::Base
42
42
  [self.token.delete(' ')].pack('H*')
43
43
  end
44
44
 
45
- private
46
45
  def set_last_registered_at
47
- self.last_registered_at = Time.now if self.last_registered_at.nil?
46
+ self.last_registered_at = Time.now #if self.last_registered_at.nil?
48
47
  end
49
48
 
50
49
  end
@@ -10,27 +10,59 @@ describe APN::App do
10
10
  device = DeviceFactory.create({:app_id => app.id})
11
11
  notifications = [NotificationFactory.create({:device_id => device.id}),
12
12
  NotificationFactory.create({:device_id => device.id})]
13
- notifications.each_with_index do |notify, i|
14
- notify.stub(:message_for_sending).and_return("message-#{i}")
15
- notify.should_receive(:sent_at=).with(instance_of(Time))
16
- notify.should_receive(:save)
17
- end
18
-
19
- APN::App.should_receive(:all).and_return([app])
20
- app.should_receive(:unsent_notifications).at_least(:once).and_return(notifications)
13
+
14
+ notifications.each_with_index do |notify, i|
15
+ notify.stub(:message_for_sending).and_return("message-#{i}")
16
+ notify.should_receive(:sent_at=).with(instance_of(Time))
17
+ notify.should_receive(:save)
18
+ end
19
+
20
+ APN::App.should_receive(:all).once.and_return([app])
21
21
  app.should_receive(:cert).twice.and_return(app.apn_dev_cert)
22
22
 
23
+ APN::Device.should_receive(:find_each).twice.and_yield(device)
24
+
25
+ device.should_receive(:unsent_notifications).and_return(notifications,[])
26
+
27
+
23
28
  ssl_mock = mock('ssl_mock')
24
29
  ssl_mock.should_receive(:write).with('message-0')
25
30
  ssl_mock.should_receive(:write).with('message-1')
26
- APN::Connection.should_receive(:open_for_delivery).and_yield(ssl_mock, nil)
27
-
31
+ APN::Connection.should_receive(:open_for_delivery).twice.and_yield(ssl_mock, nil)
28
32
  APN::App.send_notifications
29
33
 
30
34
  end
31
35
 
32
36
  end
33
37
 
38
+ describe 'send_notifications_not_associated_with_an_app' do
39
+
40
+ it 'should send unsent notifications that are associated with devices that are not with any app' do
41
+ RAILS_ENV = 'staging'
42
+ device = DeviceFactory.create
43
+ device.app_id = nil
44
+ device.save
45
+ APN::App.all.each { |a| a.destroy }
46
+ notifications = [NotificationFactory.create({:device_id => device.id}),
47
+ NotificationFactory.create({:device_id => device.id})]
48
+
49
+ notifications.each_with_index do |notify, i|
50
+ notify.stub(:message_for_sending).and_return("message-#{i}")
51
+ notify.should_receive(:sent_at=).with(instance_of(Time))
52
+ notify.should_receive(:save)
53
+ end
54
+
55
+ APN::Device.should_receive(:find_each).and_yield(device)
56
+ device.should_receive(:unsent_notifications).and_return(notifications)
57
+
58
+ ssl_mock = mock('ssl_mock')
59
+ ssl_mock.should_receive(:write).with('message-0')
60
+ ssl_mock.should_receive(:write).with('message-1')
61
+ APN::Connection.should_receive(:open_for_delivery).and_yield(ssl_mock, nil)
62
+ APN::App.send_notifications
63
+ end
64
+ end
65
+
34
66
  describe 'send_group_notifications' do
35
67
 
36
68
  it 'should send the unsent group notifications' do
@@ -133,7 +165,12 @@ describe APN::App do
133
165
  app = AppFactory.create
134
166
  devices = [DeviceFactory.create(:app_id => app.id, :last_registered_at => 1.week.ago, :feedback_at => Time.now),
135
167
  DeviceFactory.create(:app_id => app.id, :last_registered_at => 1.week.from_now, :feedback_at => Time.now)]
136
- APN::Feedback.should_receive(:devices).and_return(devices)
168
+ puts "device ids are #{devices[0].id} and #{devices[1].id}"
169
+ devices[0].last_registered_at = 1.week.ago
170
+ devices[0].save
171
+ devices[1].last_registered_at = 1.week.from_now
172
+ devices[1].save
173
+ APN::Feedback.should_receive(:devices).twice.and_return(devices)
137
174
  APN::App.should_receive(:all).and_return([app])
138
175
  app.should_receive(:cert).twice.and_return(app.apn_dev_cert)
139
176
  lambda {
@@ -143,6 +180,21 @@ describe APN::App do
143
180
 
144
181
  end
145
182
 
183
+ describe 'process_devices for global app' do
184
+
185
+ it 'should destroy devices that have a last_registered_at date that is before the feedback_at date that have no app' do
186
+ device = DeviceFactory.create(:app_id => nil, :last_registered_at => 1.week.ago, :feedback_at => Time.now)
187
+ device.app_id = nil
188
+ device.last_registered_at = 1.week.ago
189
+ device.save
190
+ APN::Feedback.should_receive(:devices).and_return([device])
191
+ APN::App.should_receive(:all).and_return([])
192
+ lambda {
193
+ APN::App.process_devices
194
+ }.should change(APN::Device, :count).by(-1)
195
+ end
196
+ end
197
+
146
198
  describe 'nil cert when processing devices' do
147
199
 
148
200
  it 'should raise an exception for processing devices for an app with no cert' do
@@ -40,19 +40,19 @@ describe APN::Device do
40
40
 
41
41
  end
42
42
 
43
- describe 'before_save' do
43
+ describe 'before_create' do
44
44
 
45
- it 'should set the last_registered_at date to Time.now if nil' do
45
+ it 'should set the last_registered_at date to Time.now' do
46
46
  time = Time.now
47
47
  Time.stub(:now).and_return(time)
48
48
  device = DeviceFactory.create
49
49
  device.last_registered_at.should_not be_nil
50
50
  device.last_registered_at.to_s.should == time.to_s
51
51
 
52
- ago = 1.week.ago
53
- device = DeviceFactory.create(:last_registered_at => ago)
54
- device.last_registered_at.should_not be_nil
55
- device.last_registered_at.to_s.should == ago.to_s
52
+ # ago = 1.week.ago
53
+ # device = DeviceFactory.create(:last_registered_at => ago)
54
+ # device.last_registered_at.should_not be_nil
55
+ # device.last_registered_at.to_s.should == ago.to_s
56
56
  end
57
57
 
58
58
  end
@@ -9,9 +9,9 @@ module AppFactory
9
9
  end
10
10
 
11
11
  def create(options = {})
12
- device = AppFactory.new(options)
13
- device.save
14
- return device
12
+ app = AppFactory.new(options)
13
+ app.save
14
+ return app
15
15
  end
16
16
 
17
17
  def random_cert
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apn_on_rails
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 13
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 4
9
- - 0
10
- version: 0.4.0
9
+ - 1
10
+ version: 0.4.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - markbates
@@ -16,14 +16,13 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-10-07 00:00:00 -04:00
19
+ date: 2010-11-09 00:00:00 -05:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
23
- type: :runtime
24
- prerelease: false
25
23
  name: configatron
26
- version_requirements: &id001 !ruby/object:Gem::Requirement
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
27
26
  none: false
28
27
  requirements:
29
28
  - - ">="
@@ -32,12 +31,12 @@ dependencies:
32
31
  segments:
33
32
  - 0
34
33
  version: "0"
35
- requirement: *id001
34
+ type: :runtime
35
+ version_requirements: *id001
36
36
  - !ruby/object:Gem::Dependency
37
- type: :development
37
+ name: autotest
38
38
  prerelease: false
39
- name: sqlite3-ruby
40
- version_requirements: &id002 !ruby/object:Gem::Requirement
39
+ requirement: &id002 !ruby/object:Gem::Requirement
41
40
  none: false
42
41
  requirements:
43
42
  - - ">="
@@ -46,30 +45,42 @@ dependencies:
46
45
  segments:
47
46
  - 0
48
47
  version: "0"
49
- requirement: *id002
50
- - !ruby/object:Gem::Dependency
51
48
  type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: sqlite3-ruby
52
52
  prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ type: :development
63
+ version_requirements: *id003
64
+ - !ruby/object:Gem::Dependency
53
65
  name: rspec
54
- version_requirements: &id003 !ruby/object:Gem::Requirement
66
+ prerelease: false
67
+ requirement: &id004 !ruby/object:Gem::Requirement
55
68
  none: false
56
69
  requirements:
57
70
  - - ">="
58
71
  - !ruby/object:Gem::Version
59
- hash: 62196421
72
+ hash: 15
60
73
  segments:
61
74
  - 2
62
75
  - 0
63
76
  - 0
64
- - beta
65
- - 19
66
- version: 2.0.0.beta.19
67
- requirement: *id003
68
- - !ruby/object:Gem::Dependency
77
+ version: 2.0.0
69
78
  type: :development
70
- prerelease: false
79
+ version_requirements: *id004
80
+ - !ruby/object:Gem::Dependency
71
81
  name: bundler
72
- version_requirements: &id004 !ruby/object:Gem::Requirement
82
+ prerelease: false
83
+ requirement: &id005 !ruby/object:Gem::Requirement
73
84
  none: false
74
85
  requirements:
75
86
  - - ">="
@@ -82,12 +93,12 @@ dependencies:
82
93
  - rc
83
94
  - 5
84
95
  version: 1.0.0.rc.5
85
- requirement: *id004
86
- - !ruby/object:Gem::Dependency
87
96
  type: :development
88
- prerelease: false
97
+ version_requirements: *id005
98
+ - !ruby/object:Gem::Dependency
89
99
  name: jeweler
90
- version_requirements: &id005 !ruby/object:Gem::Requirement
100
+ prerelease: false
101
+ requirement: &id006 !ruby/object:Gem::Requirement
91
102
  none: false
92
103
  requirements:
93
104
  - - ~>
@@ -99,12 +110,12 @@ dependencies:
99
110
  - 0
100
111
  - pre2
101
112
  version: 1.5.0.pre2
102
- requirement: *id005
103
- - !ruby/object:Gem::Dependency
104
113
  type: :development
105
- prerelease: false
114
+ version_requirements: *id006
115
+ - !ruby/object:Gem::Dependency
106
116
  name: rcov
107
- version_requirements: &id006 !ruby/object:Gem::Requirement
117
+ prerelease: false
118
+ requirement: &id007 !ruby/object:Gem::Requirement
108
119
  none: false
109
120
  requirements:
110
121
  - - ">="
@@ -113,12 +124,12 @@ dependencies:
113
124
  segments:
114
125
  - 0
115
126
  version: "0"
116
- requirement: *id006
117
- - !ruby/object:Gem::Dependency
118
127
  type: :development
119
- prerelease: false
128
+ version_requirements: *id007
129
+ - !ruby/object:Gem::Dependency
120
130
  name: actionpack
121
- version_requirements: &id007 !ruby/object:Gem::Requirement
131
+ prerelease: false
132
+ requirement: &id008 !ruby/object:Gem::Requirement
122
133
  none: false
123
134
  requirements:
124
135
  - - ~>
@@ -129,12 +140,12 @@ dependencies:
129
140
  - 3
130
141
  - 8
131
142
  version: 2.3.8
132
- requirement: *id007
133
- - !ruby/object:Gem::Dependency
134
143
  type: :development
135
- prerelease: false
144
+ version_requirements: *id008
145
+ - !ruby/object:Gem::Dependency
136
146
  name: activerecord
137
- version_requirements: &id008 !ruby/object:Gem::Requirement
147
+ prerelease: false
148
+ requirement: &id009 !ruby/object:Gem::Requirement
138
149
  none: false
139
150
  requirements:
140
151
  - - ~>
@@ -145,7 +156,8 @@ dependencies:
145
156
  - 3
146
157
  - 8
147
158
  version: 2.3.8
148
- requirement: *id008
159
+ type: :development
160
+ version_requirements: *id009
149
161
  description: |
150
162
  APN on Rails is a Ruby on Rails gem that allows you to
151
163
  easily add Apple Push Notification (iPhone) support to your Rails application.
@@ -171,6 +183,7 @@ files:
171
183
  - Rakefile
172
184
  - VERSION
173
185
  - apn_on_rails.gemspec
186
+ - autotest/discover.rb
174
187
  - generators/apn_migrations_generator.rb
175
188
  - generators/templates/apn_migrations/001_create_apn_devices.rb
176
189
  - generators/templates/apn_migrations/002_create_apn_notifications.rb
@@ -181,6 +194,8 @@ files:
181
194
  - generators/templates/apn_migrations/007_create_device_groups.rb
182
195
  - generators/templates/apn_migrations/008_create_apn_group_notifications.rb
183
196
  - generators/templates/apn_migrations/009_create_pull_notifications.rb
197
+ - generators/templates/apn_migrations/010_alter_apn_notifications.rb
198
+ - generators/templates/apn_migrations/011_make_device_token_index_nonunique.rb
184
199
  - lib/apn_on_rails.rb
185
200
  - lib/apn_on_rails/apn_on_rails.rb
186
201
  - lib/apn_on_rails/app/models/apn/app.rb