ios_push_notifications 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+ 0.5 (February 07, 2010)
2
+ Tests green without 2 methods. Need to mock certificates.
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,60 @@
1
+ IosPushNotifications
2
+ ====================
3
+
4
+ == What is ios_push_notifications
5
+ Nicely documented Push Notification gem for rails 3 applications, has generators for migrations and an initializer with configuration. Well documented and tested.... compared to other shitty forks out there >_>
6
+ == Install
7
+
8
+ gem install ios_push_notifications
9
+
10
+ == Rails 3
11
+
12
+ To use ios_push_notifications with Rails 3 you will need to include it in your Gemfile.
13
+
14
+ group :development do
15
+ gem "ios_push_notifications"
16
+ end
17
+
18
+ == Usage
19
+ * rails g iospn : Will name the migration files (iospn_devices and iospn_notifications) combined with the initializer
20
+
21
+ == Configuration
22
+ TODO
23
+
24
+ == Usage
25
+ TODO
26
+ device = IOSPN::Device.find_or_create_by_token("params[:device_token]")
27
+
28
+ notification = IOSPN::Notification.new
29
+ notification.device = device
30
+ notification.badge = 5
31
+ notification.sound = true
32
+ notification.alert = "text..."
33
+ notification.save
34
+ IOSPN::Notification.send_notifications
35
+ == Rake Tasks
36
+ TODO
37
+
38
+ == Certificates
39
+ TODO
40
+
41
+ Copyright (c) 2011 [name of plugin creator]
42
+
43
+ Permission is hereby granted, free of charge, to any person obtaining
44
+ a copy of this software and associated documentation files (the
45
+ "Software"), to deal in the Software without restriction, including
46
+ without limitation the rights to use, copy, modify, merge, publish,
47
+ distribute, sublicense, and/or sell copies of the Software, and to
48
+ permit persons to whom the Software is furnished to do so, subject to
49
+ the following conditions:
50
+
51
+ The above copyright notice and this permission notice shall be
52
+ included in all copies or substantial portions of the Software.
53
+
54
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
55
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
56
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
57
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
58
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
59
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
60
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the ios_push_notifications plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the ios_push_notifications plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'IosPushNotifications'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
@@ -0,0 +1,30 @@
1
+ require 'rails/generators/base'
2
+ require 'rails/generators/migration'
3
+
4
+ class IosPushNotificationsGenerator < Rails::Generators::Base #:nodoc:
5
+ include Rails::Generators::Migration
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+
9
+ def create_initializer
10
+ template 'initializer.rb', "config/initializers/ios_push_notification.rb"
11
+ end
12
+
13
+ def create_migration
14
+ migration_template 'device_migration.rb', "db/migrate/create_iospn_devices.rb"
15
+ migration_template 'notification_migration.rb', "db/migrate/create_iospn_notifications.rb"
16
+ end
17
+
18
+
19
+ # FIXME: Should be proxied to ActiveRecord::Generators::Base
20
+ # Implement the required interface for Rails::Generators::Migration.
21
+
22
+ def self.next_migration_number(dirname) #:nodoc:
23
+ if ActiveRecord::Base.timestamped_migrations
24
+ Time.now.utc.strftime("%Y%m%d%H%M#{rand 60}")
25
+ else
26
+ "%.3d" % (current_migration_number(dirname) + 1)
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,18 @@
1
+ class CreateIospnDevices < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :iospn_devices do |t|
4
+ t.text :token, :length => 100, :null => false
5
+ t.datetime :last_registered_at
6
+ t.timestamps
7
+ end
8
+ add_index :iospn_devices, :token, :unique => true
9
+ end
10
+
11
+ def self.down
12
+ drop_table :iospn_devices
13
+ end
14
+ end
15
+
16
+
17
+
18
+
@@ -0,0 +1,3 @@
1
+ IOSPN.configure do |c|
2
+ #c.notification[:cert] = File.join(Rails.root,"apple_push_notification_production.pem")
3
+ end
@@ -0,0 +1,25 @@
1
+ class CreateIospnNotifications < ActiveRecord::Migration # :nodoc:
2
+
3
+ def self.up
4
+
5
+ create_table :iospn_notifications do |t|
6
+ t.integer :device_id, :null => false
7
+ t.integer :errors_nb, :default => 0 # used for storing errors from apple feedbacks
8
+ t.string :device_language, :size => 5 # if you don't want to send localized strings
9
+ t.string :sound
10
+ t.string :alert, :size => 150
11
+ t.integer :badge
12
+ t.text :custom_properties
13
+ t.datetime :sent_at
14
+ t.timestamps
15
+ end
16
+
17
+ add_index :iospn_notifications, :device_id
18
+ add_index :iospn_notifications, :sent_at
19
+ end
20
+
21
+ def self.down
22
+ drop_table :iospn_notifications
23
+ end
24
+ end
25
+
@@ -0,0 +1,43 @@
1
+ require "active_record" unless defined?(ActiveRecord)
2
+ require "action_view" unless defined?(ActionView)
3
+
4
+ require "rails" unless defined?(Rails)
5
+
6
+
7
+ require 'socket'
8
+ require 'openssl'
9
+ require "ios_push_notifications/notification"
10
+ require "ios_push_notifications/device"
11
+ require "ios_push_notifications/configuration"
12
+ module IOSPN
13
+ def open_for_delivery(options = {}, &block)
14
+ open(options, &block)
15
+ end
16
+ def open(options = {}, &block)
17
+ options = IOSPN.configuration.notification.merge(options)
18
+ cert = File.read(options[:cert])
19
+ ctx = OpenSSL::SSL::SSLContext.new
20
+ ctx.key = OpenSSL::PKey::RSA.new(cert, options[:passphrase])
21
+ ctx.cert = OpenSSL::X509::Certificate.new(cert)
22
+
23
+ sock = TCPSocket.new(options[:host], options[:port])
24
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
25
+ ssl.sync = true
26
+ ssl.connect
27
+
28
+ yield ssl, sock if block_given?
29
+ ssl.close
30
+ sock.close
31
+ end
32
+
33
+ # Yields up an SSL socket to receive feedback from.
34
+ # The connections are close automatically.
35
+ # Configuration parameters are:
36
+ #
37
+ def open_for_feedback(options = {}, &block)
38
+ options = IOSPN.configuration.feedback.merge(options)
39
+ Notification.open(options, &block)
40
+ end
41
+
42
+
43
+ end
@@ -0,0 +1,32 @@
1
+ module IOSPN
2
+ class Configuration
3
+ attr_accessor :feedback,:notification
4
+
5
+ def initialize
6
+ @feedback = {}
7
+ @notification = {}
8
+ @notification = {:passphrase => '', :port => 2195}
9
+ @feedback = {:passphrase => @notification[:passphrase], :port => 2196}
10
+ if Rails.env.production?
11
+ @notification[:host] = "gateway.push.apple.com"
12
+ @notification[:cert] = File.join(Rails.root, 'config', 'apple_push_notification_production.pem') if Rails.root
13
+ @feedback[:host] = "feedback.push.apple.com"
14
+ @feedback[:cert] = @notification[:cert]
15
+ else
16
+ @notification[:host] = "gateway.sandbox.push.apple.com"
17
+ @notification[:cert] = File.join(Rails.root, 'config', 'apple_push_notification_development.pem') if Rails.root
18
+ @feedback[:host] = "feedback.sandbox.push.apple.com"
19
+ @feedback[:cert] = @notification[:cert]
20
+ end
21
+ end
22
+ end
23
+
24
+ class << self
25
+ attr_accessor :configuration
26
+ end
27
+
28
+ def self.configure
29
+ self.configuration ||= Configuration.new
30
+ yield(configuration)
31
+ end
32
+ end
@@ -0,0 +1,33 @@
1
+ module IOSPN
2
+ class Device < ActiveRecord::Base
3
+ set_table_name "iospn_devices"
4
+ has_many :notifications
5
+ validates_uniqueness_of :token
6
+ 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}$/
7
+ # before_save :set_last_registered_at
8
+ # private
9
+ # def self.set_last_registered_at
10
+ # self.last_registered_at = Time.now if self.last_registered_at.nil?
11
+ # end
12
+
13
+ def save
14
+ self.last_registered_at = Time.now if self.last_registered_at.nil?
15
+ super()
16
+ end
17
+
18
+ def token=(token)
19
+ res = token.scan(/\<(.+)\>/).first
20
+ unless res.nil? || res.empty?
21
+ token = res.first
22
+ end
23
+ write_attribute('token', token)
24
+ end
25
+
26
+
27
+ def to_hex
28
+ [self.token.delete(' ')].pack('H*')
29
+ end
30
+ end
31
+
32
+
33
+ end
@@ -0,0 +1,60 @@
1
+ module IOSPN
2
+ class Notification < ActiveRecord::Base
3
+ set_table_name "iospn_notifications"
4
+ class << self
5
+ include IOSPN
6
+ end
7
+ belongs_to :device
8
+ include ::ActionView::Helpers::TextHelper
9
+
10
+ def alert=(message)
11
+ if !message.blank? && message.size > 150
12
+ message = truncate(message, :length => 150)
13
+ end
14
+ write_attribute(:alert, message)
15
+ end
16
+
17
+ def build_hash_for_push_notification
18
+ result = {}
19
+ result['aps'] = {}
20
+ result['aps']['alert'] = self.alert if self.alert
21
+ result['aps']['badge'] = self.badge.to_i if self.badge
22
+ if self.sound
23
+ result['aps']['sound'] = self.sound if self.sound.is_a?(String) && self.sound
24
+ end
25
+ if self.custom_properties
26
+ self.custom_properties.each do |key,value|
27
+ result["#{key}"] = "#{value}"
28
+ end
29
+ end
30
+ result
31
+ end
32
+
33
+ def build_hash_for_json
34
+ self.build_hash_for_push_notification.to_json
35
+ end
36
+
37
+ def build_message_for_sending
38
+ json = self.build_hash_for_json
39
+ message = "\0\0 #{self.device.to_hex}\0#{json.length.chr}#{json}"
40
+ if message.size.to_i > 256
41
+ return false
42
+ else
43
+ message
44
+ end
45
+ end
46
+
47
+ def self.send_notifications(notifications =Notification.where(:sent_at => nil))
48
+ unless notifications.nil? || notifications.empty?
49
+ open_for_delivery do |conn, sock|
50
+ notifications.each do |noty|
51
+ conn.write(noty.build_message_for_sending)
52
+ noty.sent_at = Time.now
53
+ noty.save
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,11 @@
1
+ -----BEGIN CERTIFICATE REQUEST-----
2
+ MIIBqjCCARMCAQAwPDELMAkGA1UEBhMCU0UxCjAIBgNVBAgTAXMxITAfBgNVBAoT
3
+ GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
4
+ gYkCgYEA0C+d/EP3ra8y//u9C1+tatY1S2YBuTNofSvfEcvTs4KH8lGqt9Lvfd2S
5
+ u7kqWzUFVHbhanG0gHkaF1vKowLImeVch6dvYWxRKahTfnSaw86nyKEYJuljrx2d
6
+ dlzFPPEpp3/SY1h4HIsH4PWYwujGUiAPu1DUXrxhBLmdU5ntTA0CAwEAAaAuMBUG
7
+ CSqGSIb3DQEJAjEIEwZhc2Rhc2QwFQYJKoZIhvcNAQkHMQgTBmFzZGFzZDANBgkq
8
+ hkiG9w0BAQUFAAOBgQAx7EavEK0sf6XdiXRuwman2yLOpDHYWUIZu+2IfBMqUG+C
9
+ I2K0JrMaQzT30giG4S7MQX1WzZLPN20aeiaNXqkNHIHwO4GtjWZCun4L8iNj47em
10
+ EPXyHopUQEjHSW23uJa52wjQhlnwoyrFZ0I11gG18J5DbhSSrny2n2e3EltT5A==
11
+ -----END CERTIFICATE REQUEST-----
data/test/database.yml ADDED
@@ -0,0 +1,22 @@
1
+ # vendor/plugins/yaffle/test/database.yml
2
+ sqlite:
3
+ :adapter: sqlite
4
+ :database: test/ios_push_notifications_plugin.sqlite.db
5
+
6
+ sqlite3:
7
+ :adapter: sqlite3
8
+ :database: test/ios_push_notifications_plugin.sqlite3.db
9
+
10
+ postgresql:
11
+ :adapter: postgresql
12
+ :username: postgres
13
+ :password: postgres
14
+ :database: ios_push_notifications_plugin_test
15
+ :min_messages: ERROR
16
+
17
+ mysql:
18
+ :adapter: mysql
19
+ :host: localhost
20
+ :username: root
21
+ :password: password
22
+ :database: ios_push_notifications_plugin_test
data/test/debug.log ADDED
@@ -0,0 +1,92 @@
1
+ SQL (0.3ms) DROP TABLE iospn_notifications
2
+ SQLite3::SQLException: no such table: iospn_notifications: DROP TABLE iospn_notifications
3
+ SQL (0.3ms) DROP TABLE iospn_notifications
4
+ SQLite3::SQLException: no such table: iospn_notifications: DROP TABLE iospn_notifications
5
+ SQL (0.2ms) select sqlite_version(*)
6
+ SQL (4.0ms) CREATE TABLE "iospn_devices" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "token" text NOT NULL, "last_registered_at" datetime, "created_at" datetime, "updated_at" datetime) 
7
+ SQL (8.2ms) CREATE TABLE "iospn_notifications" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "device_id" integer NOT NULL, "errors_nb" integer DEFAULT 0, "device_language" varchar(255), "sound" varchar(255), "alert" varchar(255), "badge" integer, "custom_properties" text, "sent_at" datetime, "created_at" datetime, "updated_at" datetime)
8
+ SQL (0.3ms)  SELECT name
9
+ FROM sqlite_master
10
+ WHERE type = 'table' AND NOT name = 'sqlite_sequence'
11
+ 
12
+ SQL (1.2ms) CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL)
13
+ SQL (0.1ms) PRAGMA index_list("schema_migrations")
14
+ SQL (1.4ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
15
+ SQL (0.2ms)  SELECT name
16
+ FROM sqlite_master
17
+ WHERE type = 'table' AND NOT name = 'sqlite_sequence'
18
+ 
19
+ SQL (0.1ms) SELECT version FROM "schema_migrations"
20
+ SQL (1.0ms) INSERT INTO "schema_migrations" (version) VALUES ('0')
21
+ SQL (0.3ms) SELECT name
22
+ FROM sqlite_master
23
+ WHERE type = 'table' AND NOT name = 'sqlite_sequence'
24
+
25
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices"."id" FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
26
+ AREL (0.4ms) INSERT INTO "iospn_devices" ("token", "last_registered_at", "created_at", "updated_at") VALUES ('5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz', '2011-02-07 21:26:19.764189', '2011-02-07 21:26:19.820338', '2011-02-07 21:26:19.820338')
27
+ AREL (0.1ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, NULL, NULL, NULL, NULL, NULL, '2011-02-07 21:26:19.822051', '2011-02-07 21:26:19.822051')
28
+ AREL (0.1ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, NULL, NULL, NULL, NULL, NULL, '2011-02-07 21:26:19.823923', '2011-02-07 21:26:19.823923')
29
+ AREL (0.1ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, NULL, NULL, NULL, NULL, NULL, '2011-02-07 21:26:19.824817', '2011-02-07 21:26:19.824817')
30
+ AREL (0.1ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, NULL, NULL, NULL, NULL, NULL, '2011-02-07 21:26:19.825738', '2011-02-07 21:26:19.825738')
31
+ AREL (0.1ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, NULL, NULL, NULL, NULL, NULL, '2011-02-07 21:26:19.826643', '2011-02-07 21:26:19.826643')
32
+ SQL (0.2ms) SELECT COUNT(*) FROM "iospn_notifications" WHERE ("iospn_notifications".device_id = 1)
33
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices"."id" FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
34
+ IOSPN::Device Load (0.2ms) SELECT "iospn_devices"."id" FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
35
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices"."id" FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
36
+ IOSPN::Device Load (0.2ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
37
+ IOSPN::Device Load (0.3ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
38
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
39
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
40
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
41
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
42
+ IOSPN::Device Load (0.2ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
43
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
44
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
45
+ AREL (1.3ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, 'awesome.wav', 'Lorem Ipsum', 7, NULL, NULL, '2011-02-07 21:26:19.885546', '2011-02-07 21:26:19.885546')
46
+ IOSPN::Device Load (0.2ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
47
+ AREL (0.4ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (NULL, 0, NULL, 'awesome.wav', 'Lorem Ipsum', 7, NULL, NULL, '2011-02-07 21:26:19.911904', '2011-02-07 21:26:19.911904')
48
+ SQLite3::ConstraintException: iospn_notifications.device_id may not be NULL: INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (NULL, 0, NULL, 'awesome.wav', 'Lorem Ipsum', 7, NULL, NULL, '2011-02-07 21:26:19.911904', '2011-02-07 21:26:19.911904')
49
+ IOSPN::Device Load (0.2ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
50
+ AREL (0.3ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, 'awesome.wav', 'Lorem Ipsum', 7, NULL, NULL, '2011-02-07 21:26:19.914939', '2011-02-07 21:26:19.914939')
51
+ SQL (0.1ms) SELECT COUNT(*) FROM "iospn_notifications" WHERE ("iospn_notifications"."sent_at" IS NULL)
52
+ SQL (3.5ms) DROP TABLE iospn_notifications
53
+ SQL (1.4ms) DROP TABLE iospn_devices
54
+ SQL (0.2ms) select sqlite_version(*)
55
+ SQL (1.1ms) CREATE TABLE "iospn_devices" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "token" text NOT NULL, "last_registered_at" datetime, "created_at" datetime, "updated_at" datetime)
56
+ SQL (7.5ms) CREATE TABLE "iospn_notifications" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "device_id" integer NOT NULL, "errors_nb" integer DEFAULT 0, "device_language" varchar(255), "sound" varchar(255), "alert" varchar(255), "badge" integer, "custom_properties" text, "sent_at" datetime, "created_at" datetime, "updated_at" datetime) 
57
+ SQL (0.3ms) SELECT name
58
+ FROM sqlite_master
59
+ WHERE type = 'table' AND NOT name = 'sqlite_sequence'
60
+
61
+ SQL (0.1ms) SELECT version FROM "schema_migrations"
62
+ SQL (0.2ms) SELECT name
63
+ FROM sqlite_master
64
+ WHERE type = 'table' AND NOT name = 'sqlite_sequence'
65
+
66
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices"."id" FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
67
+ AREL (0.3ms) INSERT INTO "iospn_devices" ("token", "last_registered_at", "created_at", "updated_at") VALUES ('5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz', '2011-02-07 21:50:54.133692', '2011-02-07 21:50:54.188627', '2011-02-07 21:50:54.188627')
68
+ AREL (0.1ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, NULL, NULL, NULL, NULL, NULL, '2011-02-07 21:50:54.190235', '2011-02-07 21:50:54.190235')
69
+ AREL (0.1ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, NULL, NULL, NULL, NULL, NULL, '2011-02-07 21:50:54.191986', '2011-02-07 21:50:54.191986')
70
+ AREL (0.1ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, NULL, NULL, NULL, NULL, NULL, '2011-02-07 21:50:54.192872', '2011-02-07 21:50:54.192872')
71
+ AREL (0.1ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, NULL, NULL, NULL, NULL, NULL, '2011-02-07 21:50:54.193781', '2011-02-07 21:50:54.193781')
72
+ AREL (0.1ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, NULL, NULL, NULL, NULL, NULL, '2011-02-07 21:50:54.194667', '2011-02-07 21:50:54.194667')
73
+ SQL (0.1ms) SELECT COUNT(*) FROM "iospn_notifications" WHERE ("iospn_notifications".device_id = 1)
74
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices"."id" FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
75
+ IOSPN::Device Load (0.2ms) SELECT "iospn_devices"."id" FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
76
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices"."id" FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
77
+ IOSPN::Device Load (0.2ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
78
+ IOSPN::Device Load (0.2ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
79
+ IOSPN::Device Load (0.2ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
80
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
81
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
82
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
83
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
84
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
85
+ IOSPN::Device Load (0.1ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
86
+ AREL (0.7ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, 'awesome.wav', 'Lorem Ipsum', 7, NULL, NULL, '2011-02-07 21:50:54.250848', '2011-02-07 21:50:54.250848')
87
+ IOSPN::Device Load (0.2ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
88
+ AREL (0.5ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (NULL, 0, NULL, 'awesome.wav', 'Lorem Ipsum', 7, NULL, NULL, '2011-02-07 21:50:54.280836', '2011-02-07 21:50:54.280836')
89
+ SQLite3::ConstraintException: iospn_notifications.device_id may not be NULL: INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (NULL, 0, NULL, 'awesome.wav', 'Lorem Ipsum', 7, NULL, NULL, '2011-02-07 21:50:54.280836', '2011-02-07 21:50:54.280836')
90
+ IOSPN::Device Load (0.2ms) SELECT "iospn_devices".* FROM "iospn_devices" WHERE ("iospn_devices"."token" = '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz') LIMIT 1
91
+ AREL (0.3ms) INSERT INTO "iospn_notifications" ("device_id", "errors_nb", "device_language", "sound", "alert", "badge", "custom_properties", "sent_at", "created_at", "updated_at") VALUES (1, 0, NULL, 'awesome.wav', 'Lorem Ipsum', 7, NULL, NULL, '2011-02-07 21:50:54.284408', '2011-02-07 21:50:54.284408')
92
+ SQL (0.1ms) SELECT COUNT(*) FROM "iospn_notifications" WHERE ("iospn_notifications"."sent_at" IS NULL)
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+ class Device < Test::Unit::TestCase
3
+
4
+ def setup
5
+ @device = IOSPN::Device.new(:token => "5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz")
6
+ end
7
+
8
+ def test_notification_instance
9
+ assert @device
10
+ end
11
+
12
+ def test_notification_token
13
+ token = @device.token
14
+ @device.token = "<#{token}>"
15
+ assert_equal(token, @device.token)
16
+ end
17
+
18
+ def test_registered_at_before_save
19
+ assert(@device.last_registered_at.nil?)
20
+ @device.save
21
+ assert(@device.last_registered_at)
22
+ end
23
+
24
+ def test_has_many_notifications
25
+ 5.times do
26
+ @device.notifications << IOSPN::Notification.new
27
+ end
28
+ @device.save
29
+ assert_equal(@device.notifications.count, 5)
30
+ end
31
+
32
+ def test_unique_token
33
+ @device.save
34
+ bad_device = IOSPN::Device.create(:token => @device.token)
35
+ assert bad_device.errors
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ require 'test_helper'
2
+ class IosPushNotificationsTest < ActiveSupport::TestCase
3
+ end
@@ -0,0 +1,82 @@
1
+ require 'test_helper'
2
+ class Notification < Test::Unit::TestCase
3
+
4
+ def setup
5
+ @notif = IOSPN::Notification.new
6
+ @notif.alert = "Lorem Ipsum"
7
+ @notif.badge = 7
8
+ @notif.sound = "awesome.wav"
9
+ @device = IOSPN::Device.find_or_create_by_token("5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz")
10
+ @notif.device = @device
11
+ end
12
+
13
+ def test_notification_instance
14
+ assert @notif
15
+ end
16
+
17
+
18
+ def test_notification_alert
19
+ message = "Hey man what's up?"
20
+ @notif.alert = message
21
+ assert_equal(@notif.alert, message)
22
+ end
23
+
24
+ def test_existence_of_sound
25
+ assert_equal @notif.sound, "awesome.wav"
26
+
27
+ end
28
+
29
+ def test_notification_truncate_above_150_characters
30
+ long_message = ""
31
+ 160.times { |n| long_message << n}
32
+ @notif.alert = long_message
33
+ assert_equal(150, @notif.alert.length)
34
+ end
35
+
36
+
37
+ def test_notification_badge
38
+ number = 5
39
+ @notif.badge = number
40
+ assert_equal(@notif.badge, number)
41
+ end
42
+
43
+ def test_save_notification_without_device
44
+ @notif.device = nil
45
+ assert_raise(ActiveRecord::StatementInvalid) {@notif.save}
46
+ assert_not_nil @notif.errors
47
+ end
48
+
49
+ def test_save_notification_with_device
50
+ assert(!@notif.device.new_record?)
51
+ assert @notif.save
52
+ end
53
+
54
+ def test_hash_for_push_notification
55
+ hash = @notif.build_hash_for_push_notification
56
+ assert_instance_of(Hash, hash)
57
+ matcher = {'aps' => {'alert' => @notif.alert,
58
+ 'badge' => @notif.badge,
59
+ 'sound' => @notif.sound }}
60
+ assert_equal(matcher, hash)
61
+ end
62
+
63
+ def test_build_hash_for_json
64
+ assert @notif.build_hash_for_json
65
+ end
66
+
67
+ def test_build_message_for_sending
68
+ assert(@notif.device.to_hex, "device.to_hex returns false")
69
+ assert(@notif.build_hash_for_json, "notification.build_hash_to_json returns false")
70
+ json = @notif.build_hash_for_json
71
+ message = "\0\0 #{@notif.device.to_hex}\0#{json.length.chr}#{json}"
72
+ assert_equal(@notif.build_message_for_sending, message)
73
+ end
74
+
75
+ def test_sending_notifications_for_sent_at_nil
76
+ @notif.save
77
+ IOSPN::Notification.send_notifications
78
+ assert(@notif.sent_at, "Notification timestamp was not, has not been sent")
79
+ end
80
+
81
+
82
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,18 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :iospn_devices do |t|
3
+ t.text :token, :length => 100, :null => false
4
+ t.datetime :last_registered_at
5
+ t.timestamps
6
+ end
7
+ create_table :iospn_notifications do |t|
8
+ t.integer :device_id, :null => false
9
+ t.integer :errors_nb, :default => 0 # used for storing errors from apple feedbacks
10
+ t.string :device_language, :size => 5 # if you don't want to send localized strings
11
+ t.string :sound
12
+ t.string :alert, :size => 150
13
+ t.integer :badge
14
+ t.text :custom_properties
15
+ t.datetime :sent_at
16
+ t.timestamps
17
+ end
18
+ end
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require "yaml"
4
+ require "logger"
5
+
6
+ require File.dirname(__FILE__) + '/../init'
7
+ ENV['RAILS_ENV'] = 'test'
8
+
9
+
10
+ def clean_database!
11
+ models = [IOSPN::Notification, IOSPN::Device]
12
+ begin
13
+ models.each do |model|
14
+ ActiveRecord::Base.connection.execute "DROP TABLE #{model.table_name}"
15
+ end
16
+ rescue ActiveRecord::StatementInvalid
17
+ end
18
+ end
19
+
20
+
21
+ def load_schema!
22
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
23
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
24
+
25
+ db_adapter = ENV['DB']
26
+
27
+ # no db passed, try one of these fine config-free DBs before bombing.
28
+ db_adapter ||=
29
+ begin
30
+ require 'rubygems'
31
+ require 'sqlite'
32
+ 'sqlite'
33
+ rescue MissingSourceFile
34
+ begin
35
+ require 'sqlite3'
36
+ 'sqlite3'
37
+ rescue MissingSourceFile
38
+ end
39
+ end
40
+
41
+ if db_adapter.nil?
42
+ raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3."
43
+ end
44
+
45
+ ActiveRecord::Base.establish_connection(config[db_adapter])
46
+
47
+ IOSPN.configure do |c|
48
+ c.notification[:cert] = File.join(Dir.pwd,"test", "apple_push_notification_development.pem")
49
+ end
50
+
51
+
52
+
53
+ clean_database!
54
+ load(File.dirname(__FILE__) + "/schema.rb")
55
+ end
56
+ load_schema!
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ios_push_notifications
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: "0.5"
6
+ platform: ruby
7
+ authors:
8
+ - Seivan Heidari
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-02-07 00:00:00 +01:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rails
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 3.0.0
25
+ type: :development
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3-ruby
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 1.3.1
36
+ type: :development
37
+ version_requirements: *id002
38
+ description: Nicely documented Push Notification gem for rails 3 applications, has generators for migrations and an initializer with configuration. It is well documented and tested.... compared to other shitty forks out there >_>
39
+ email: seivan@kth.se
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - lib/generators/ios_push_notifications_generator.rb
48
+ - lib/generators/templates/device_migration.rb
49
+ - lib/generators/templates/initializer.rb
50
+ - lib/generators/templates/notification_migration.rb
51
+ - lib/ios_push_notifications/configuration.rb
52
+ - lib/ios_push_notifications/device.rb
53
+ - lib/ios_push_notifications/notification.rb
54
+ - lib/ios_push_notifications.rb
55
+ - test/apple_push_notification_development.pem
56
+ - test/database.yml
57
+ - test/debug.log
58
+ - test/device_test.rb
59
+ - test/ios_push_notifications_plugin.sqlite3.db
60
+ - test/ios_push_notifications_test.rb
61
+ - test/notification_test.rb
62
+ - test/schema.rb
63
+ - test/test_helper.rb
64
+ - CHANGELOG
65
+ - Gemfile
66
+ - MIT-LICENSE
67
+ - Rakefile
68
+ - README.rdoc
69
+ has_rdoc: true
70
+ homepage: http://github.com/seivan/ios_push_notifications
71
+ licenses: []
72
+
73
+ post_install_message:
74
+ rdoc_options: []
75
+
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 1.3.4
90
+ requirements: []
91
+
92
+ rubyforge_project: ios_push_notifications
93
+ rubygems_version: 1.5.0
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: Push Notification gem for Rails 3 with proper tests and documentation
97
+ test_files: []
98
+