rack-push-notification 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,36 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rack-push-notification (0.0.1)
5
+ rack (~> 1.4)
6
+ rack-contrib (~> 1.1.0)
7
+ sequel (~> 3.37.0)
8
+ sinatra (~> 1.3.2)
9
+ sinatra-param (~> 0.1.1)
10
+
11
+ GEM
12
+ remote: http://rubygems.org/
13
+ specs:
14
+ rack (1.4.1)
15
+ rack-contrib (1.1.0)
16
+ rack (>= 0.9.1)
17
+ rack-protection (1.2.0)
18
+ rack
19
+ rake (0.9.2.2)
20
+ rspec (0.6.4)
21
+ sequel (3.37.0)
22
+ sinatra (1.3.3)
23
+ rack (~> 1.3, >= 1.3.6)
24
+ rack-protection (~> 1.2)
25
+ tilt (~> 1.3, >= 1.3.3)
26
+ sinatra-param (0.1.1)
27
+ sinatra (~> 1.3)
28
+ tilt (1.3.3)
29
+
30
+ PLATFORMS
31
+ ruby
32
+
33
+ DEPENDENCIES
34
+ rack-push-notification!
35
+ rake (~> 0.9.2)
36
+ rspec (~> 0.6.1)
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012 Mattt Thompson (http://mattt.me/)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ Rack::PushNotification
2
+ ======================
3
+ **An extensible, Rack-mountable webservice for managing push notification information**
4
+
5
+ There is misconception that managing push notification information is a difficult problem. It's really not.
6
+
7
+ This library is generates a `/devices` API endpoint, that can be used by iOS apps to register and unregister for push notifications.
8
+
9
+ ## Example Record
10
+
11
+ <table>
12
+ <tr><td><tt>token</tt></td><td>"ce8be627 2e43e855 16033e24 b4c28922 0eeda487 9c477160 b2545e95 b68b5969"</td></tr>
13
+ <tr><td><tt>alias</tt></td><td>mattt@heroku.com</td></tr>
14
+ <tr><td><tt>badge</tt></td><td>0</td></tr>
15
+ <tr><td><tt>locale</tt></td><td>en_US</td></tr>
16
+ <tr><td><tt>language</tt></td><td>en</td></tr>
17
+ <tr><td><tt>timezone</tt></td><td>America/Los_Angeles</td></tr>
18
+ <tr><td><tt>ip_address</tt></td><td>0.0.0.0</td></tr>
19
+ <tr><td><tt>lat</tt></td><td>37.7716</td></tr>
20
+ <tr><td><tt>lng</tt></td><td>-122.4137</td></tr>
21
+ <tr><td><tt>tags</tt></td><td><tt>["iPhone OS 6.0", "v1.0", "iPhone"]</tt></td></tr>
22
+ </table>
23
+
24
+ Each device has a `token`, which uniquely identifies the app installation on a particular device. This token can be associated with an `alias`, which can be a domain-specific piece of identifying information, such as a username or e-mail address. A running `badge` count is used to keep track of the badge count to show on the app icon.
25
+
26
+ A device's `locale` & `language` can be used to localize outgoing communications to that particular user. Having `timezone` information gives you the ability to schedule messages for an exact time of day, to ensure maximum impact (and minimum annoyance). `ip_address` as well as `lat` and `lng` allows you to specifically target users according to their geographic location.
27
+
28
+ > It is recommended that you use `Rack::PushNotification` in conjunction with some sort of Rack authentication middleware, so that the registration endpoints are not accessible without some form of credentials.
29
+
30
+ ## Example Usage
31
+
32
+ Rack::PushNotification can be run as Rack middleware or as a single web application. All that is required is a connection to a Postgres database.
33
+
34
+ ### config.ru
35
+
36
+ ```ruby
37
+ require 'bundler'
38
+ Bundler.require
39
+
40
+ DB = Sequel.connect(ENV['DATABASE_URL'])
41
+
42
+ run Rack::PushNotification
43
+ ```
44
+
45
+ An example application can be found in the `/example` directory of this repository.
46
+
47
+ ## iOS Client Library
48
+
49
+ To get the full benefit of `Rack::PushNotification`, use the [Orbiter](https://github.com/mattt/Orbiter) library to register for Push Notifications on iOS.
50
+
51
+ ```objective-c
52
+ #import "Orbiter.h"
53
+
54
+ - (void)application:(UIApplication *)application
55
+ didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
56
+ {
57
+ NSURL *serverURL = [NSURL URLWithString:@"http://raging-notification-3556.herokuapp.com/"]
58
+ Orbiter *orbiter = [[Orbiter alloc] initWithBaseURL:serverURL credential:nil];
59
+ [orbiter registerDeviceToken:deviceToken withAlias:nil success:^(id responseObject) {
60
+ NSLog(@"Registration Success: %@", responseObject);
61
+ } failure:^(NSError *error) {
62
+ NSLog(@"Registration Error: %@", error);
63
+ }];
64
+ }
65
+ ```
66
+
67
+ ## Contact
68
+
69
+ Mattt Thompson
70
+
71
+ - http://github.com/mattt
72
+ - http://twitter.com/mattt
73
+ - m@mattt.me
74
+
75
+ ## License
76
+
77
+ Rack::PushNotification is available under the MIT license. See the LICENSE file for more info.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler"
2
+ Bundler.setup
3
+
4
+ gemspec = eval(File.read("rack-push-notification.gemspec"))
5
+
6
+ task :build => "#{gemspec.full_name}.gem"
7
+
8
+ file "#{gemspec.full_name}.gem" => gemspec.files + ["rack-push-notification.gemspec"] do
9
+ system "gem build rack-push-notification.gemspec"
10
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ module PushNotification
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1,134 @@
1
+ require 'rack'
2
+ require 'rack/contrib'
3
+
4
+ require 'sinatra/base'
5
+ require 'sinatra/param'
6
+
7
+ require 'sequel'
8
+
9
+ require 'rack/push-notification/version'
10
+
11
+ Sequel.extension(:pg_array)
12
+
13
+ module Rack::PushNotification
14
+ end
15
+
16
+ module Rack
17
+ def self.PushNotification(options = {})
18
+ klass = Rack::PushNotification.const_set("Device", Class.new(Sequel::Model))
19
+ klass.dataset = :devices
20
+
21
+ klass.class_eval do
22
+ self.strict_param_setting = false
23
+ self.raise_on_save_failure = false
24
+
25
+ plugin :json_serializer, naked: true, except: :id
26
+ plugin :validation_helpers
27
+ plugin :timestamps, force: true
28
+ plugin :schema
29
+
30
+ set_schema do
31
+ primary_key :id
32
+
33
+ column :token, :varchar, null: false, unique: true
34
+ column :alias, :varchar
35
+ column :badge, :int4, null: false, default: 0
36
+ column :locale, :varchar
37
+ column :language, :varchar
38
+ column :timezone, :varchar, null: false, default: 'UTC'
39
+ column :ip_address, :inet
40
+ column :lat, :float8
41
+ column :lng, :float8
42
+ column :tags, :'text[]'
43
+
44
+ index :token
45
+ index :alias
46
+ index [:lat, :lng]
47
+ end
48
+
49
+ create_table unless table_exists?
50
+
51
+ def before_validation
52
+ normalize_token!
53
+ end
54
+
55
+ private
56
+
57
+ def normalize_token!
58
+ self.token = self.token.strip.gsub(/[<\s>]/, '')
59
+ end
60
+ end
61
+
62
+ app = Class.new(Sinatra::Base) do
63
+ use Rack::PostBodyContentTypeParser
64
+ helpers Sinatra::Param
65
+
66
+ disable :raise_errors, :show_exceptions
67
+
68
+ before do
69
+ content_type :json
70
+ end
71
+
72
+ get '/devices/?' do
73
+ param :languages, Array
74
+ param :tags, Array
75
+
76
+ @devices = klass.dataset
77
+ [:alias, :badge, :locale, :languages, :timezone, :tags].each do |attribute|
78
+ @devices = @devices.filter(attribute => params[attribute]) if params[attribute]
79
+ end
80
+
81
+ @devices.to_json
82
+ end
83
+
84
+ put '/devices/:token/?' do
85
+ param :languages, Array
86
+ param :tags, Array
87
+
88
+ @record = klass.new(params)
89
+ @record.tags = nil
90
+ if @record.save
91
+ status 201
92
+ @record.to_json
93
+ else
94
+ status 406
95
+ {errors: @record.errors}.to_json
96
+ end
97
+ end
98
+
99
+ get '/devices/:token/?' do
100
+ @record = klass.find(token: params[:token])
101
+ if @record
102
+ @record.to_json
103
+ else
104
+ status 404
105
+ end
106
+ end
107
+
108
+ delete '/devices/:token/?' do
109
+ @record = klass.find(token: params[:token]) or halt 404
110
+ if @record.destroy
111
+ status 200
112
+ else
113
+ status 406
114
+ {errors: record.errors}.to_json
115
+ end
116
+ end
117
+ end
118
+
119
+ return app
120
+ end
121
+
122
+ module PushNotification
123
+ class << self
124
+ def new(options = {})
125
+ @app ||= ::Rack::PushNotification()
126
+ end
127
+
128
+ def call(*args)
129
+ @app ||= ::Rack::PushNotification()
130
+ @app.call(*args)
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rack/push-notification"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rack-push-notification"
7
+ s.authors = ["Mattt Thompson"]
8
+ s.email = "m@mattt.me"
9
+ s.homepage = "http://mattt.me"
10
+ s.version = Rack::PushNotification::VERSION
11
+ s.platform = Gem::Platform::RUBY
12
+ s.summary = "Rack::PushNotification"
13
+ s.description = "Generate a REST API for registering and querying push notification device tokens."
14
+ s.add_development_dependency "rspec", "~> 0.6.1"
15
+ s.add_development_dependency "rake", "~> 0.9.2"
16
+
17
+ s.add_dependency "rack", "~> 1.4"
18
+ s.add_dependency "rack-contrib", "~> 1.1.0"
19
+ s.add_dependency "sinatra", "~> 1.3.2"
20
+ s.add_dependency "sinatra-param", "~> 0.1.1"
21
+ s.add_dependency "sequel", "~> 3.37.0"
22
+
23
+ s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|example|log|pkg|script|spec|test|vendor)/ }
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-push-notification
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mattt Thompson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.6.1
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.6.1
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.9.2
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.9.2
46
+ - !ruby/object:Gem::Dependency
47
+ name: rack
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.4'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.4'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rack-contrib
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 1.1.0
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 1.1.0
78
+ - !ruby/object:Gem::Dependency
79
+ name: sinatra
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 1.3.2
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 1.3.2
94
+ - !ruby/object:Gem::Dependency
95
+ name: sinatra-param
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 0.1.1
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 0.1.1
110
+ - !ruby/object:Gem::Dependency
111
+ name: sequel
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 3.37.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: 3.37.0
126
+ description: Generate a REST API for registering and querying push notification device
127
+ tokens.
128
+ email: m@mattt.me
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ./Gemfile
134
+ - ./Gemfile.lock
135
+ - ./lib/rack/push-notification/version.rb
136
+ - ./lib/rack/push-notification.rb
137
+ - ./LICENSE
138
+ - ./rack-push-notification.gemspec
139
+ - ./Rakefile
140
+ - ./README.md
141
+ homepage: http://mattt.me
142
+ licenses: []
143
+ post_install_message:
144
+ rdoc_options: []
145
+ require_paths:
146
+ - lib
147
+ required_ruby_version: !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ! '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ segments:
154
+ - 0
155
+ hash: 1277678436408848925
156
+ required_rubygems_version: !ruby/object:Gem::Requirement
157
+ none: false
158
+ requirements:
159
+ - - ! '>='
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ segments:
163
+ - 0
164
+ hash: 1277678436408848925
165
+ requirements: []
166
+ rubyforge_project:
167
+ rubygems_version: 1.8.24
168
+ signing_key:
169
+ specification_version: 3
170
+ summary: Rack::PushNotification
171
+ test_files: []