ios_push_notifications 0.5

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/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
+