markbates-apn_on_rails 0.0.1.20090723180641 → 0.1.1.20090724152309

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/README CHANGED
@@ -1,16 +1,17 @@
1
- APN on Rails
2
- (Apple Push Notifications on Rails)
3
- =====================
1
+ =APN on Rails (Apple Push Notifications on Rails)
2
+
3
+ APN on Rails is a Ruby on Rails gem that allows you to easily add Apple Push Notification (iPhone)
4
+ support to your Rails application.
5
+
6
+ ==Acknowledgements:
4
7
 
5
- Acknowledgements
6
- ----------------
7
8
  This gem is a re-write of a plugin that was written by Fabien Penso and Sam Soffes.
8
9
  Their plugin was a great start, but it just didn't quite reach the level I hoped it would.
9
10
  I've re-written, as a gem, added a ton of tests, and I would like to think that I made it
10
11
  a little nicer and easier to use.
11
12
 
12
- Converting Your Certificate
13
- ---------------------------
13
+ ==Converting Your Certificate:
14
+
14
15
  Once you have the certificate from Apple for your application, export your key
15
16
  and the apple certificate as p12 files. Here is a quick walkthrough on how to do this:
16
17
 
@@ -26,28 +27,38 @@ Put 'apple_push_notification_production.pem' in config/
26
27
 
27
28
  If you are using a development certificate, then change the name to apple_push_notification_development.pem instead.
28
29
 
29
- Installing
30
- ----------
30
+ ==Installing:
31
+
32
+ ===Stable (RubyForge):
31
33
 
32
- From RubyForge:
33
34
  $ sudo gem install apn_on_rails
34
35
 
35
- Or, if you like to live on the edge:
36
+ ===Edge (GitHub):
37
+
36
38
  $ sudo gem install markbates-apn_on_rails --source=http://gems.github.com
37
-
38
- Then you just add the following require, wherever it makes sense to you:
39
- require 'apn_on_rails'
39
+
40
+ ===Rails Gem Management:
40
41
 
41
42
  If you like to use the built in Rails gem management:
43
+
42
44
  config.gem 'apn_on_rails'
43
45
 
44
46
  Or, if you like to live on the edge:
47
+
45
48
  config.gem 'markbates-apn_on_rails', :lib => 'apn_on_rails', :source => 'http://gems.github.com'
46
-
47
- Setup
48
- -----
49
- Once you have the gem installed you need to add the following to your Rakefile so you can use the
49
+
50
+ ==Setup and Configuration:
51
+
52
+ Once you have the gem installed via your favorite gem installation, you need to require it so you can
53
+ start to use it:
54
+
55
+ Add the following require, wherever it makes sense to you:
56
+
57
+ require 'apn_on_rails'
58
+
59
+ You also need to add the following to your Rakefile so you can use the
50
60
  Rake tasks that ship with APN on Rails:
61
+
51
62
  begin
52
63
  require 'apn_on_rails_tasks'
53
64
  rescue MissingSourceFile => e
@@ -55,22 +66,38 @@ Rake tasks that ship with APN on Rails:
55
66
  end
56
67
 
57
68
  Now, to create the tables you need for APN on Rails, run the following task:
69
+
58
70
  $ rake apn:db:migrate
59
71
 
72
+ APN on Rails uses the Configatron gem, http://github.com/markbates/configatron/tree/master,
73
+ to configure itself. APN on Rails has the following default configurations that you change as you
74
+ see fit:
75
+
76
+ configatron.apn.passphrase # => ''
77
+ configatron.apn.port # => 2195
78
+ configatron.apn.host # => 'gateway.sandbox.push.apple.com'
79
+ configatron.apn.cert #=> File.join(RAILS_ROOT, 'config', 'apple_push_notification_development.pem')
80
+
81
+ # production:
82
+ configatron.apn.host # => 'gateway.push.apple.com'
83
+ configatron.apn.cert #=> File.join(RAILS_ROOT, 'config', 'apple_push_notification_production.pem')
84
+
60
85
  That's it, now you're ready to start creating notifications.
61
86
 
62
- Example
63
- -------
87
+ ==Example:
88
+
89
+ $ ./script/console
90
+ >> device = APN::Device.create(:token => "XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX")
91
+ >> notification = APN::Notification.new
92
+ >> notification.device = device
93
+ >> notification.badge = 5
94
+ >> notification.sound = true
95
+ >> notification.alert = "foobar"
96
+ >> notification.save
97
+ >> APN::Notification.send_notifications
64
98
 
65
- *Note: the spaces in `device_token` are optional.*
99
+ You can also run the following Rake task to send your notifications:
66
100
 
67
- $ ./script/console
68
- >> a = ApplePushNotification.new
69
- >> a.device_token = "XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX"
70
- >> a.badge = 5
71
- >> a.sound = true
72
- >> a.alert = "foobar"
73
- >> a.send_notification
74
- => nil
101
+ $ rake apn:notifications:deliver
75
102
 
76
- Copyright (c) 2009 Fabien Penso. Released under the MIT license. Modified by [Sam Soffes](http://samsoff.es).
103
+ Released under the MIT license.
@@ -22,13 +22,14 @@ if rails_env == 'production'
22
22
  configatron.apn.set_default(:cert, File.join(rails_root, 'config', 'apple_push_notification_production.pem'))
23
23
  end
24
24
 
25
- module APN
25
+ module APN # :nodoc:
26
26
 
27
- module Errors
27
+ module Errors # :nodoc:
28
28
 
29
+ # Raised when a notification message to Apple is longer than 256 bytes.
29
30
  class ExceededMessageSizeError < StandardError
30
31
 
31
- def initialize(message)
32
+ def initialize(message) # :nodoc:
32
33
  super("The maximum size allowed for a notification payload is 256 bytes: '#{message}'")
33
34
  end
34
35
 
@@ -1,3 +1,8 @@
1
+ # Represents an iPhone (or other APN enabled device).
2
+ # An APN::Device can have many APN::Notification.
3
+ #
4
+ # Example:
5
+ # Device.create(:token => '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz')
1
6
  class APN::Device < ActiveRecord::Base
2
7
  set_table_name 'apn_devices'
3
8
 
@@ -6,6 +11,8 @@ class APN::Device < ActiveRecord::Base
6
11
  validates_uniqueness_of :token
7
12
  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}$/
8
13
 
14
+ # Stores the token (Apple's device ID) of the iPhone (device).
15
+ #
9
16
  # If the token comes in like this:
10
17
  # '<5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz>'
11
18
  # Then the '<' and '>' will be stripped off.
@@ -1,9 +1,31 @@
1
+ # Represents the message you wish to send.
2
+ # An APN::Notification belongs to an APN::Device.
3
+ #
4
+ # Example:
5
+ # apn = APN::Notification.new
6
+ # apn.badge = 5
7
+ # apn.sound = 'my_sound.aiff'
8
+ # apn.alert = 'Hello!'
9
+ # apn.device = APN::Device.find(1)
10
+ # apn.save
11
+ #
12
+ # To deliver call the following method:
13
+ # APN::Notification.send_notifications
14
+ #
15
+ # As each APN::Notification is sent the <tt>sent_at</tt> column will be timestamped,
16
+ # so as to not be sent again.
1
17
  class APN::Notification < ActiveRecord::Base
2
18
  include ::ActionView::Helpers::TextHelper
19
+ extend ::ActionView::Helpers::TextHelper
20
+
3
21
  set_table_name 'apn_notifications'
4
22
 
5
23
  belongs_to :device, :class_name => 'APN::Device'
6
24
 
25
+ # Stores the text alert message you want to send to the device.
26
+ #
27
+ # If the message is over 150 characters long it will get truncated
28
+ # to 150 characters with a <tt>...</tt>
7
29
  def alert=(message)
8
30
  if !message.blank? && message.size > 150
9
31
  message = truncate(message, :length => 150)
@@ -53,25 +75,37 @@ class APN::Notification < ActiveRecord::Base
53
75
 
54
76
  class << self
55
77
 
56
- def send_notifications(notifications)
57
- cert = File.read(configatron.apn.cert)
58
- ctx = OpenSSL::SSL::SSLContext.new
59
- ctx.key = OpenSSL::PKey::RSA.new(cert, configatron.apn.passphrase)
60
- ctx.cert = OpenSSL::X509::Certificate.new(cert)
78
+ # Opens a connection to the Apple APN server and attempts to batch deliver
79
+ # an Array of notifications.
80
+ #
81
+ # This method expects an Array of APN::Notifications. If no parameter is passed
82
+ # in then it will use the following:
83
+ # APN::Notification.all(:conditions => {:sent_at => nil})
84
+ #
85
+ # As each APN::Notification is sent the <tt>sent_at</tt> column will be timestamped,
86
+ # so as to not be sent again.
87
+ def send_notifications(notifications = APN::Notification.all(:conditions => {:sent_at => nil}))
88
+ unless notifications.nil? || notifications.empty?
89
+ logger.info "APN: Attempting to deliver #{pluralize(notifications.size, 'notification')}."
90
+ cert = File.read(configatron.apn.cert)
91
+ ctx = OpenSSL::SSL::SSLContext.new
92
+ ctx.key = OpenSSL::PKey::RSA.new(cert, configatron.apn.passphrase)
93
+ ctx.cert = OpenSSL::X509::Certificate.new(cert)
61
94
 
62
- s = TCPSocket.new(configatron.apn.host, configatron.apn.port)
63
- ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
64
- ssl.sync = true
65
- ssl.connect
95
+ s = TCPSocket.new(configatron.apn.host, configatron.apn.port)
96
+ ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
97
+ ssl.sync = true
98
+ ssl.connect
66
99
 
67
- notifications.each do |noty|
68
- ssl.write(noty.message_for_sending)
69
- noty.sent_at = Time.now
70
- noty.save
71
- end
100
+ notifications.each do |noty|
101
+ ssl.write(noty.message_for_sending)
102
+ noty.sent_at = Time.now
103
+ noty.save
104
+ end
72
105
 
73
- ssl.close
74
- s.close
106
+ ssl.close
107
+ s.close
108
+ end
75
109
  end
76
110
 
77
111
  end # class << self
@@ -1,4 +1,4 @@
1
- class CreateApnDevices < ActiveRecord::Migration
1
+ class CreateApnDevices < ActiveRecord::Migratio # :nodoc:
2
2
  def self.up
3
3
  create_table :apn_devices do |t|
4
4
  t.text :token, :size => 71, :null => false
@@ -1,4 +1,4 @@
1
- class CreateApnNotifications < ActiveRecord::Migration
1
+ class CreateApnNotifications < ActiveRecord::Migration # :nodoc:
2
2
 
3
3
  def self.up
4
4
 
@@ -4,12 +4,7 @@ namespace :apn do
4
4
 
5
5
  desc "Deliver all unsent APN notifications."
6
6
  task :deliver => [:environment] do
7
- notifications = APN::Notification.all(:conditions => {:sent_at => nil})
8
- unless notifications.empty?
9
- include ActionView::Helpers::TextHelper
10
- RAILS_DEFAULT_LOGGER.info "APN: Attempting to deliver #{pluralize(notifications.size, 'notification')}."
11
- APN::Notification.send_notifications(notifications)
12
- end
7
+ APN::Notification.send_notifications
13
8
  end
14
9
 
15
10
  end # notifications
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markbates-apn_on_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.20090723180641
4
+ version: 0.1.1.20090724152309
5
5
  platform: ruby
6
6
  authors:
7
7
  - markbates
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-23 00:00:00 -07:00
12
+ date: 2009-07-24 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -35,7 +35,6 @@ files:
35
35
  - lib/apn_on_rails/apn_on_rails.rb
36
36
  - lib/apn_on_rails/app/models/apn/device.rb
37
37
  - lib/apn_on_rails/app/models/apn/notification.rb
38
- - lib/apn_on_rails/app/models/apple_push_notification.rb
39
38
  - lib/apn_on_rails/db/migrate/20090723132058_create_apn_devices.rb
40
39
  - lib/apn_on_rails/db/migrate/20090723132059_create_apn_notifications.rb
41
40
  - lib/apn_on_rails/tasks/apn.rake
@@ -1,94 +0,0 @@
1
- # #
2
- # # Fabien Penso <fabien.penso@conovae.com>
3
- # # April 6th, 2009.
4
- # #
5
- #
6
- # require 'socket'
7
- # require 'openssl'
8
- #
9
- # class ApplePushNotification < ActiveRecord::Base
10
- #
11
- # HOST = "gateway.sandbox.push.apple.com"
12
- # PATH = '/'
13
- # PORT = 2195
14
- # path = File.join(RAILS_ROOT, 'config', 'apple_push_notification_development.pem')
15
- # CERT = File.read(path) if File.exists?(path)
16
- # PASSPHRASE = "foobar"
17
- # CACERT = File.expand_path(File.dirname(__FILE__) + "certs/ca.gateway.sandbox.push.apple.com.crt")
18
- # USERAGENT = 'Mozilla/5.0 (apple_push_notification Ruby on Rails 0.1)'
19
- #
20
- # # attr_accessor :paylod, :sound, :badge, :alert, :appdata
21
- # attr_accessible :device_token
22
- #
23
- # # validates_uniqueness_of :device_token
24
- #
25
- # # def send_notification
26
- # #
27
- # # ctx = OpenSSL::SSL::SSLContext.new
28
- # # ctx.key = OpenSSL::PKey::RSA.new(CERT, PASSPHRASE)
29
- # # ctx.cert = OpenSSL::X509::Certificate.new(CERT)
30
- # #
31
- # # s = TCPSocket.new(HOST, PORT)
32
- # # ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
33
- # # ssl.sync = true
34
- # # ssl.connect
35
- # #
36
- # # ssl.write(self.apn_message_for_sending)
37
- # #
38
- # # ssl.close
39
- # # s.close
40
- # #
41
- # # rescue SocketError => error
42
- # # raise "Error while sending notifications: #{error}"
43
- # # end
44
- #
45
- # def self.send_notifications(notifications)
46
- # ctx = OpenSSL::SSL::SSLContext.new
47
- # ctx.key = OpenSSL::PKey::RSA.new(CERT, PASSPHRASE)
48
- # ctx.cert = OpenSSL::X509::Certificate.new(CERT)
49
- #
50
- # s = TCPSocket.new(HOST, PORT)
51
- # ssl = OpenSSL::SSL::SSLSocket.new(s, ctx)
52
- # ssl.sync = true
53
- # ssl.connect
54
- #
55
- # for notif in notifications do
56
- # ssl.write(notif.apn_message_for_sending)
57
- # notif.sent_at = Time.now
58
- # notif.save
59
- # end
60
- #
61
- # ssl.close
62
- # s.close
63
- # rescue SocketError => error
64
- # raise "Error while sending notifications: #{error}"
65
- # end
66
- #
67
- # def to_apple_json
68
- # logger.debug "Sending #{self.apple_hash.to_json}"
69
- # self.apple_hash.to_json
70
- # end
71
- #
72
- # def apn_message_for_sending
73
- # json = self.to_apple_json
74
- # message = "\0\0 #{self.device_token_hexa}\0#{json.length.chr}#{json}"
75
- # raise "The maximum size allowed for a notification payload is 256 bytes." if message.size.to_i > 256
76
- # message
77
- # end
78
- #
79
- # def device_token_hexa
80
- # [self.device_token.delete(' ')].pack('H*')
81
- # end
82
- #
83
- # def apple_hash
84
- # result = {}
85
- # result['aps'] = {}
86
- # result['aps']['alert'] = alert if alert
87
- # result['aps']['badge'] = badge.to_i if badge
88
- # result['aps']['sound'] = sound if sound and sound.is_a? String
89
- # result['aps']['sound'] = "1.aiff" if sound and sound.is_a?(TrueClass)
90
- # result.merge appdata if appdata
91
- #
92
- # result
93
- # end
94
- # end