gwong-apn_on_rails 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.rspec +2 -0
- data/.specification +80 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +47 -0
- data/LICENSE +21 -0
- data/README +179 -0
- data/README.textile +209 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/apn_on_rails.gemspec +144 -0
- data/autotest/discover.rb +1 -0
- data/generators/apn_migrations_generator.rb +31 -0
- data/generators/templates/apn_migrations/001_create_apn_devices.rb +13 -0
- data/generators/templates/apn_migrations/002_create_apn_notifications.rb +23 -0
- data/generators/templates/apn_migrations/003_alter_apn_devices.rb +25 -0
- data/generators/templates/apn_migrations/004_create_apn_apps.rb +18 -0
- data/generators/templates/apn_migrations/005_create_groups.rb +23 -0
- data/generators/templates/apn_migrations/006_alter_apn_groups.rb +11 -0
- data/generators/templates/apn_migrations/007_create_device_groups.rb +27 -0
- data/generators/templates/apn_migrations/008_create_apn_group_notifications.rb +23 -0
- data/generators/templates/apn_migrations/009_create_pull_notifications.rb +16 -0
- data/generators/templates/apn_migrations/010_alter_apn_notifications.rb +21 -0
- data/generators/templates/apn_migrations/011_make_device_token_index_nonunique.rb +11 -0
- data/generators/templates/apn_migrations/012_add_launch_notification_to_apn_pull_notifications.rb +9 -0
- data/lib/apn_on_rails.rb +4 -0
- data/lib/apn_on_rails/apn_on_rails.rb +81 -0
- data/lib/apn_on_rails/app/models/apn/app.rb +150 -0
- data/lib/apn_on_rails/app/models/apn/base.rb +9 -0
- data/lib/apn_on_rails/app/models/apn/device.rb +49 -0
- data/lib/apn_on_rails/app/models/apn/device_grouping.rb +16 -0
- data/lib/apn_on_rails/app/models/apn/group.rb +12 -0
- data/lib/apn_on_rails/app/models/apn/group_notification.rb +79 -0
- data/lib/apn_on_rails/app/models/apn/notification.rb +93 -0
- data/lib/apn_on_rails/app/models/apn/pull_notification.rb +28 -0
- data/lib/apn_on_rails/libs/connection.rb +70 -0
- data/lib/apn_on_rails/libs/feedback.rb +39 -0
- data/lib/apn_on_rails/tasks/apn.rake +30 -0
- data/lib/apn_on_rails/tasks/db.rake +19 -0
- data/lib/apn_on_rails_tasks.rb +3 -0
- data/spec/active_record/setup_ar.rb +19 -0
- data/spec/apn_on_rails/app/models/apn/app_spec.rb +226 -0
- data/spec/apn_on_rails/app/models/apn/device_spec.rb +60 -0
- data/spec/apn_on_rails/app/models/apn/group_notification_spec.rb +66 -0
- data/spec/apn_on_rails/app/models/apn/notification_spec.rb +71 -0
- data/spec/apn_on_rails/app/models/apn/pull_notification_spec.rb +100 -0
- data/spec/apn_on_rails/libs/connection_spec.rb +40 -0
- data/spec/apn_on_rails/libs/feedback_spec.rb +43 -0
- data/spec/extensions/string.rb +10 -0
- data/spec/factories/app_factory.rb +27 -0
- data/spec/factories/device_factory.rb +29 -0
- data/spec/factories/device_grouping_factory.rb +22 -0
- data/spec/factories/group_factory.rb +27 -0
- data/spec/factories/group_notification_factory.rb +22 -0
- data/spec/factories/notification_factory.rb +22 -0
- data/spec/factories/pull_notification_factory.rb +22 -0
- data/spec/fixtures/hexa.bin +1 -0
- data/spec/fixtures/message_for_sending.bin +0 -0
- data/spec/rails_root/config/apple_push_notification_development.pem +19 -0
- data/spec/spec_helper.rb +55 -0
- metadata +282 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe APN::GroupNotification do
|
4
|
+
|
5
|
+
describe 'alert' do
|
6
|
+
|
7
|
+
it 'should trim the message to 150 characters' do
|
8
|
+
noty = APN::GroupNotification.new
|
9
|
+
noty.alert = 'a' * 200
|
10
|
+
noty.alert.should == ('a' * 147) + '...'
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'apple_hash' do
|
16
|
+
|
17
|
+
it 'should return a hash of the appropriate params for Apple' do
|
18
|
+
noty = APN::GroupNotification.first
|
19
|
+
noty.apple_hash.should == {"aps" => {"badge" => 5, "sound" => "my_sound.aiff", "alert" => "Hello!"},"typ" => "1"}
|
20
|
+
noty.custom_properties = nil
|
21
|
+
noty.apple_hash.should == {"aps" => {"badge" => 5, "sound" => "my_sound.aiff", "alert" => "Hello!"}}
|
22
|
+
noty.badge = nil
|
23
|
+
noty.apple_hash.should == {"aps" => {"sound" => "my_sound.aiff", "alert" => "Hello!"}}
|
24
|
+
noty.alert = nil
|
25
|
+
noty.apple_hash.should == {"aps" => {"sound" => "my_sound.aiff"}}
|
26
|
+
noty.sound = nil
|
27
|
+
noty.apple_hash.should == {"aps" => {}}
|
28
|
+
noty.sound = true
|
29
|
+
noty.apple_hash.should == {"aps" => {"sound" => "1.aiff"}}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'to_apple_json' do
|
35
|
+
|
36
|
+
it 'should return the necessary JSON for Apple' do
|
37
|
+
noty = APN::GroupNotification.first
|
38
|
+
noty.to_apple_json.should == %{{"typ":"1","aps":{"badge":5,"sound":"my_sound.aiff","alert":"Hello!"}}}
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'message_for_sending' do
|
44
|
+
|
45
|
+
it 'should create a binary message to be sent to Apple' do
|
46
|
+
noty = APN::GroupNotification.first
|
47
|
+
noty.custom_properties = nil
|
48
|
+
device = DeviceFactory.new(:token => '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz')
|
49
|
+
noty.message_for_sending(device).should == fixture_value('message_for_sending.bin')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should raise an APN::Errors::ExceededMessageSizeError if the message is too big' do
|
53
|
+
app = AppFactory.create
|
54
|
+
device = DeviceFactory.create({:app_id => app.id})
|
55
|
+
group = GroupFactory.create({:app_id => app.id})
|
56
|
+
device_grouping = DeviceGroupingFactory.create({:group_id => group.id,:device_id => device.id})
|
57
|
+
noty = GroupNotificationFactory.new(:group_id => group.id, :sound => true, :badge => nil)
|
58
|
+
noty.send(:write_attribute, 'alert', 'a' * 183)
|
59
|
+
lambda {
|
60
|
+
noty.message_for_sending(device)
|
61
|
+
}.should raise_error(APN::Errors::ExceededMessageSizeError)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe APN::Notification do
|
4
|
+
|
5
|
+
describe 'alert' do
|
6
|
+
|
7
|
+
it 'should trim the message to 150 characters' do
|
8
|
+
noty = APN::Notification.new
|
9
|
+
noty.alert = 'a' * 200
|
10
|
+
noty.alert.should == ('a' * 147) + '...'
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'apple_hash' do
|
16
|
+
|
17
|
+
it 'should return a hash of the appropriate params for Apple' do
|
18
|
+
noty = APN::Notification.first
|
19
|
+
noty.apple_hash.should == {"aps" => {"badge" => 5, "sound" => "my_sound.aiff", "alert" => "Hello!"},"typ" => "1"}
|
20
|
+
noty.custom_properties = nil
|
21
|
+
noty.apple_hash.should == {"aps" => {"badge" => 5, "sound" => "my_sound.aiff", "alert" => "Hello!"}}
|
22
|
+
noty.badge = nil
|
23
|
+
noty.apple_hash.should == {"aps" => {"sound" => "my_sound.aiff", "alert" => "Hello!"}}
|
24
|
+
noty.alert = nil
|
25
|
+
noty.apple_hash.should == {"aps" => {"sound" => "my_sound.aiff"}}
|
26
|
+
noty.sound = nil
|
27
|
+
noty.apple_hash.should == {"aps" => {}}
|
28
|
+
noty.sound = true
|
29
|
+
noty.apple_hash.should == {"aps" => {"sound" => "1.aiff"}}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'to_apple_json' do
|
35
|
+
|
36
|
+
it 'should return the necessary JSON for Apple' do
|
37
|
+
noty = APN::Notification.first
|
38
|
+
noty.to_apple_json.should == %{{"typ":"1","aps":{"badge":5,"sound":"my_sound.aiff","alert":"Hello!"}}}
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'message_for_sending' do
|
44
|
+
|
45
|
+
it 'should create a binary message to be sent to Apple' do
|
46
|
+
noty = APN::Notification.first
|
47
|
+
noty.custom_properties = nil
|
48
|
+
noty.device = DeviceFactory.new(:token => '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz')
|
49
|
+
noty.message_for_sending.should == fixture_value('message_for_sending.bin')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should raise an APN::Errors::ExceededMessageSizeError if the message is too big' do
|
53
|
+
noty = NotificationFactory.new(:device_id => DeviceFactory.create, :sound => true, :badge => nil)
|
54
|
+
noty.send(:write_attribute, 'alert', 'a' * 183)
|
55
|
+
lambda {
|
56
|
+
noty.message_for_sending
|
57
|
+
}.should raise_error(APN::Errors::ExceededMessageSizeError)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'send_notifications' do
|
63
|
+
|
64
|
+
it 'should warn the user the method is deprecated and call the corresponding method on APN::App' do
|
65
|
+
ActiveSupport::Deprecation.should_receive(:warn)
|
66
|
+
APN::App.should_receive(:send_notifications)
|
67
|
+
APN::Notification.send_notifications
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe APN::PullNotification do
|
4
|
+
|
5
|
+
describe 'latest_since_when_already_seen_latest' do
|
6
|
+
|
7
|
+
it 'should return nothing because since date is after the latest pull notification' do
|
8
|
+
app = APN::App.first
|
9
|
+
noty1 = PullNotificationFactory.create({:app_id => app.id})
|
10
|
+
noty1.created_at = Time.now - 1.week
|
11
|
+
noty1.save
|
12
|
+
APN::PullNotification.latest_since(app.id,Time.now).should == nil
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'latest_since_when_have_not_seen_latest' do
|
18
|
+
|
19
|
+
it 'should return the most recent pull notification because it has not yet been seen' do
|
20
|
+
app = APN::App.first
|
21
|
+
noty1 = PullNotificationFactory.create({:app_id => app.id})
|
22
|
+
noty1.created_at = Time.now + 1.week
|
23
|
+
noty1.save
|
24
|
+
latest = APN::PullNotification.latest_since(app.id,Time.now - 1.week)
|
25
|
+
puts "latest is #{latest}"
|
26
|
+
latest.should == noty1
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'latest_since_with_no_date_when_there_is_no_launch_notification' do
|
32
|
+
it 'should return the most recent pull notification because no date is given' do
|
33
|
+
app = APN::App.first
|
34
|
+
noty1 = APN::PullNotification.find(:first, :order => "created_at DESC")
|
35
|
+
APN::PullNotification.latest_since(app.id).should == noty1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'latest_since_with_no_date_when_there_is_a_launch_notification' do
|
40
|
+
it 'should return the launch notification even though there is a more recent notification' do
|
41
|
+
app = APN::App.first
|
42
|
+
noty_launch = PullNotificationFactory.create({:app_id => app.id, :launch_notification => true})
|
43
|
+
noty_launch.created_at = Time.now - 1.week
|
44
|
+
noty_launch.save
|
45
|
+
noty_nonlaunch = PullNotificationFactory.create({:app_id => app.id})
|
46
|
+
APN::PullNotification.latest_since(app.id).should == noty_launch
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'older_non_launch_noty_with_newer_launch_noty' do
|
51
|
+
it 'should return the older non launch notification even though a newer launch notification exists' do
|
52
|
+
APN::PullNotification.all.each { |n| n.destroy }
|
53
|
+
app = APN::App.first
|
54
|
+
noty_launch = PullNotificationFactory.create({:app_id => app.id, :launch_notification => true})
|
55
|
+
puts "noty_launch id is #{noty_launch.id}"
|
56
|
+
noty_nonlaunch = PullNotificationFactory.create({:app_id => app.id})
|
57
|
+
noty_nonlaunch.created_at = Time.now - 1.week
|
58
|
+
noty_nonlaunch.save
|
59
|
+
puts "noty_nonlaunch id is #{noty_nonlaunch.id}"
|
60
|
+
APN::PullNotification.latest_since(app.id, Time.now - 2.weeks).should == noty_nonlaunch
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'all_since_date_with_date_given' do
|
65
|
+
it 'should return all the non-launch notifications after the given date but not the ones before it' do
|
66
|
+
APN::PullNotification.all.each { |n| n.destroy }
|
67
|
+
app = APN::App.first
|
68
|
+
noty_launch = PullNotificationFactory.create({:app_id => app.id, :launch_notification => true})
|
69
|
+
noty_launch.created_at = Time.now - 2.weeks
|
70
|
+
noty_launch.save
|
71
|
+
old_noty = PullNotificationFactory.create({:app_id => app.id})
|
72
|
+
old_noty.created_at = Time.now - 2.weeks
|
73
|
+
old_noty.save
|
74
|
+
new_noty_one = PullNotificationFactory.create({:app_id => app.id})
|
75
|
+
new_noty_one.created_at = Time.now - 1.day
|
76
|
+
new_noty_one.save
|
77
|
+
new_noty_two = PullNotificationFactory.create({:app_id => app.id})
|
78
|
+
APN::PullNotification.all_since(app.id, Time.now - 1.week).should == [new_noty_two,new_noty_one]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'all_since_with_no_since_date_given' do
|
83
|
+
it 'should return all of the non-launch notifications' do
|
84
|
+
APN::PullNotification.all.each { |n| n.destroy }
|
85
|
+
app = APN::App.first
|
86
|
+
noty_launch = PullNotificationFactory.create({:app_id => app.id, :launch_notification => true})
|
87
|
+
noty_launch.created_at = Time.now - 2.weeks
|
88
|
+
noty_launch.save
|
89
|
+
old_noty = PullNotificationFactory.create({:app_id => app.id})
|
90
|
+
old_noty.created_at = Time.now - 2.weeks
|
91
|
+
old_noty.save
|
92
|
+
new_noty_one = PullNotificationFactory.create({:app_id => app.id})
|
93
|
+
new_noty_one.created_at = Time.now - 1.day
|
94
|
+
new_noty_one.save
|
95
|
+
new_noty_two = PullNotificationFactory.create({:app_id => app.id})
|
96
|
+
APN::PullNotification.all_since(app.id, Time.now - 3.weeks).should == [new_noty_two,new_noty_one,old_noty]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe APN::Connection do
|
4
|
+
|
5
|
+
describe 'open_for_delivery' do
|
6
|
+
|
7
|
+
it 'should create a connection to Apple, yield it, and then close' do
|
8
|
+
rsa_mock = mock('rsa_mock')
|
9
|
+
OpenSSL::PKey::RSA.should_receive(:new).and_return(rsa_mock)
|
10
|
+
|
11
|
+
cert_mock = mock('cert_mock')
|
12
|
+
OpenSSL::X509::Certificate.should_receive(:new).and_return(cert_mock)
|
13
|
+
|
14
|
+
ctx_mock = mock('ctx_mock')
|
15
|
+
ctx_mock.should_receive(:key=).with(rsa_mock)
|
16
|
+
ctx_mock.should_receive(:cert=).with(cert_mock)
|
17
|
+
OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ctx_mock)
|
18
|
+
|
19
|
+
tcp_mock = mock('tcp_mock')
|
20
|
+
tcp_mock.should_receive(:close)
|
21
|
+
TCPSocket.should_receive(:new).with('gateway.sandbox.push.apple.com', 2195).and_return(tcp_mock)
|
22
|
+
|
23
|
+
ssl_mock = mock('ssl_mock')
|
24
|
+
ssl_mock.should_receive(:sync=).with(true)
|
25
|
+
ssl_mock.should_receive(:connect)
|
26
|
+
ssl_mock.should_receive(:write).with('message-0')
|
27
|
+
ssl_mock.should_receive(:write).with('message-1')
|
28
|
+
ssl_mock.should_receive(:close)
|
29
|
+
OpenSSL::SSL::SSLSocket.should_receive(:new).with(tcp_mock, ctx_mock).and_return(ssl_mock)
|
30
|
+
|
31
|
+
APN::Connection.open_for_delivery do |conn, sock|
|
32
|
+
conn.write('message-0')
|
33
|
+
conn.write('message-1')
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe APN::Feedback do
|
4
|
+
|
5
|
+
describe 'devices' do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@time = Time.now
|
9
|
+
@device = DeviceFactory.create
|
10
|
+
@cert = mock('cert_mock')
|
11
|
+
|
12
|
+
@data_mock = mock('data_mock')
|
13
|
+
@data_mock.should_receive(:unpack).with('N1n1H140').and_return([@time.to_i, 12388, @device.token.delete(' ')])
|
14
|
+
|
15
|
+
@ssl_mock = mock('ssl_mock')
|
16
|
+
@ssl_mock.should_receive(:read).with(38).twice.and_return(@data_mock, nil)
|
17
|
+
@sock_mock = mock('sock_mock')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should an Array of devices that need to be processed' do
|
21
|
+
APN::Connection.should_receive(:open_for_feedback).and_yield(@ssl_mock, @sock_mock)
|
22
|
+
|
23
|
+
devices = APN::Feedback.devices(@cert)
|
24
|
+
devices.size.should == 1
|
25
|
+
r_device = devices.first
|
26
|
+
r_device.token.should == @device.token
|
27
|
+
r_device.feedback_at.to_s.should == @time.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should yield up each device' do
|
31
|
+
APN::Connection.should_receive(:open_for_feedback).and_yield(@ssl_mock, @sock_mock)
|
32
|
+
lambda {
|
33
|
+
APN::Feedback.devices(@cert) do |r_device|
|
34
|
+
r_device.token.should == @device.token
|
35
|
+
r_device.feedback_at.to_s.should == @time.to_s
|
36
|
+
raise BlockRan.new
|
37
|
+
end
|
38
|
+
}.should raise_error(BlockRan)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
def self.randomize(length = 10)
|
4
|
+
chars = ("A".."H").to_a + ("J".."N").to_a + ("P".."T").to_a + ("W".."Z").to_a + ("3".."9").to_a
|
5
|
+
newpass = ""
|
6
|
+
1.upto(length) { |i| newpass << chars[rand(chars.size-1)] }
|
7
|
+
return newpass.upcase
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module AppFactory
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def new(options = {})
|
6
|
+
options = {:apn_dev_cert => AppFactory.random_cert,
|
7
|
+
:apn_prod_cert => AppFactory.random_cert}.merge(options)
|
8
|
+
return APN::App.new(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(options = {})
|
12
|
+
app = AppFactory.new(options)
|
13
|
+
app.save
|
14
|
+
return app
|
15
|
+
end
|
16
|
+
|
17
|
+
def random_cert
|
18
|
+
tok = []
|
19
|
+
tok << String.randomize(50)
|
20
|
+
tok.join('').downcase
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
AppFactory.create
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module DeviceFactory
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def new(options = {})
|
6
|
+
app = APN::App.first
|
7
|
+
options = {:token => DeviceFactory.random_token, :app_id => app.id}.merge(options)
|
8
|
+
return APN::Device.new(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(options = {})
|
12
|
+
device = DeviceFactory.new(options)
|
13
|
+
device.save
|
14
|
+
return device
|
15
|
+
end
|
16
|
+
|
17
|
+
def random_token
|
18
|
+
tok = []
|
19
|
+
8.times do
|
20
|
+
tok << String.randomize(8)
|
21
|
+
end
|
22
|
+
tok.join(' ').downcase
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
DeviceFactory.create
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module DeviceGroupingFactory
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def new(options = {})
|
6
|
+
device = APN::Device.first
|
7
|
+
group = APN::Group.first
|
8
|
+
options = {:device_id => device.id, :group_id => group.id}.merge(options)
|
9
|
+
return APN::DeviceGrouping.new(options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def create(options = {})
|
13
|
+
device_grouping = DeviceGroupingFactory.new(options)
|
14
|
+
device_grouping.save
|
15
|
+
return device_grouping
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
DeviceGroupingFactory.create
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module GroupFactory
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
def new(options = {})
|
6
|
+
app = APN::App.first
|
7
|
+
options = {:app_id => app.id, :name => GroupFactory.random_name}.merge(options)
|
8
|
+
return APN::Group.new(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(options = {})
|
12
|
+
group = GroupFactory.new(options)
|
13
|
+
group.save
|
14
|
+
return group
|
15
|
+
end
|
16
|
+
|
17
|
+
def random_name
|
18
|
+
tok = []
|
19
|
+
tok << String.randomize(8)
|
20
|
+
tok.join(' ').downcase
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
GroupFactory.create
|