jackdempsey-rpx_now 0.5.8

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,23 @@
1
+ 0.5.0
2
+ ----
3
+ * ApiError is raised when API KEY was invalid (before did only return nil)
4
+ * ServerError is now seperated into ApiError and ServiceUnavailableError
5
+
6
+ 0.4.2
7
+ ----
8
+ * default IDs are strings, not integers, since RPX supports both
9
+ * Added username field to standart parameters
10
+
11
+ 0.4
12
+ ----
13
+ * The RPXNow.api_version= can be set globally
14
+ * Most methods now support :api_version=>'123', so you can specify the api_version on each call
15
+ * Added support for unobtrusive code generation. This will make the gem play nicely with developers creating unobtrusive pages with frameworks such as jQuery;
16
+ * The RPXNOW JSON responses are now parsed by Florian Frank JSON gem (http://json.rubyforge.org/);
17
+ * Removed the dependency of ActiveSupport. However, if present, ActiveSupport will be used due to its convenience methods Array#to_query and Hash#to_query.
18
+ * Added support for multiple versions of the widget. By default, everything will point to version 2;
19
+ * The specs have been updated.
20
+
21
+ 0.3
22
+ ----
23
+ * RPXNow::ServerError will be thrown when something is invalid/goes wrong, so watch out (not for invalid tokens in user_data)...
data/MIGRATION ADDED
@@ -0,0 +1,9 @@
1
+ class AddIdentifierToUsers < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :users, :identifier, :string
4
+ end
5
+
6
+ def self.down
7
+ remove_column :users, :identifier
8
+ end
9
+ end
data/README.markdown ADDED
@@ -0,0 +1,113 @@
1
+ Problem
2
+ =======
3
+ - OpenID is complex, limited and hard to use for users
4
+ - Facebook / Twitter / Myspace / Google / MS-LiveId / AOL connections require different libraries and knowledge
5
+ - Multiple heterogenouse providers are hard to map to a single user
6
+
7
+ Solution
8
+ ========
9
+ - Use [RPX](http://rpxnow.com) for universal and usable user login
10
+ - Use view/controller helpers for easy integration
11
+
12
+ ![Single Interface for all providers](https://rpxnow.com/images/how_diagram.png)
13
+ ![Visitors choose from providers they already have](https://rpxnow.com/images/6providers.png?2)
14
+
15
+ Usage
16
+ =====
17
+ - Get an API key @ [RPX](http://rpxnow.com)
18
+ - run [MIGRATION](http://github.com/grosser/rpx_now/raw/master/MIGRATION)
19
+ - Build login view
20
+ - Communicate with RPX API in controller to create or login User
21
+ - for more advanced features have a look at the [RPX API Docs](https://rpxnow.com/docs)
22
+
23
+ Install
24
+ =======
25
+ - As Rails plugin: `script/plugin install git://github.com/grosser/rpx_now.git `
26
+ - As gem: `sudo gem install grosser-rpx_now --source http://gems.github.com/`
27
+
28
+ Examples
29
+ ========
30
+
31
+ View
32
+ ----
33
+ #'mywebsite' is your subdomain/realm on RPX
34
+ <%=RPXNow.embed_code('mywebsite',rpx_token_sessions_url)%>
35
+ OR
36
+ <%=RPXNow.popup_code('Login here...','mywebsite',rpx_token_sessions_url,:language=>'de')%>
37
+
38
+ `popup_code` can also be called with `:unobstrusive=>true`
39
+
40
+ Environment
41
+ -----------
42
+ Rails::Initializer.run do |config|
43
+ config.gem "grosser-rpx_now", :lib => "rpx_now", :source => "http://gems.github.com/"
44
+ ...
45
+ end
46
+ RPXNow.api_key = "YOU RPX API KEY"
47
+
48
+ Controller
49
+ ----------
50
+ # user_data
51
+ # found: {:name=>'John Doe', :username => 'john', :email=>'john@doe.com', :identifier=>'blug.google.com/openid/dsdfsdfs3f3'}
52
+ # not found: nil (can happen with e.g. invalid tokens)
53
+ def rpx_token
54
+ raise "hackers?" unless data = RPXNow.user_data(params[:token])
55
+ self.current_user = User.find_by_identifier(data[:identifier]) || User.create!(data)
56
+ redirect_to '/'
57
+ end
58
+
59
+ # raw request processing
60
+ RPXNow.user_data(params[:token]){|raw| {:email=>raw['profile']['verifiedEmail']} }
61
+
62
+ # raw request with extended parameters (most users and APIs do not supply them)
63
+ RPXNow.user_data(params[:token], :extended=>'true'){|raw| ...have a look at the RPX API DOCS...}
64
+
65
+ Advanced
66
+ --------
67
+ ###Versions
68
+ RPXNow.api_version = 2
69
+
70
+ ###Mappings
71
+ You can map your primary keys (e.g. user.id) to identifiers, so that
72
+ users can login to the same account with multiple identifiers.
73
+ RPXNow.map(identifier, primary_key) #add a mapping
74
+ RPXNow.unmap(identifier, primary_key) #remove a mapping
75
+ RPXNow.mappings(primary_key) # [identifier1,identifier2,...]
76
+ RPXNow.all_mappings # [["1",['google.com/dsdas','yahoo.com/asdas']], ["2",[...]], ... ]
77
+
78
+ After a primary key is mapped to an identifier, when a user logs in with this identifier,
79
+ `RPXNow.user_data` will contain his `primaryKey` as `:id`.
80
+ A identifyer can only belong to one user (in doubt the last one it was mapped to)
81
+
82
+ ###User integration (e.g. ActiveRecord)
83
+ class User < ActiveRecord::Base
84
+ include RPXNow::UserIntegration
85
+ end
86
+
87
+ user.rpx.identifiers == RPXNow.mappings(user.id)
88
+ user.rpx.map(identifier) == RPXNow.map(identifier, user.id)
89
+ user.rpx.unmap(identifier) == RPXNow.unmap(identifier, user.id)
90
+
91
+ ###Contacts (PRX Pro)
92
+ Retrieve all contacts for a given user:
93
+ RPXNow.contacts(identifier).each {|c| puts "#{c['displayName']}: #{c['emails']}}
94
+
95
+ ###Status updates (PRX Pro)
96
+ Send a status update to provider (a tweet/facebook-status/...) :
97
+ RPXNow.set_status(identifier, "I just registered at yourdomain.com ...")
98
+
99
+ TODO
100
+ ====
101
+ - add provider / credentials helpers ?
102
+
103
+ Author
104
+ ======
105
+ ###Contributors
106
+ - [Amunds](http://github.com/Amunds)
107
+ - [DBA](http://github.com/DBA)
108
+ - [dbalatero](http://github.com/dbalatero)
109
+ - [jackdempsey](http://jackndempsey.blogspot.com/)
110
+
111
+ [Michael Grosser](http://pragmatig.wordpress.com)
112
+ grosser.michael@gmail.com
113
+ Hereby placed under public domain, do what you want, just do not hold me accountable...
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'echoe'
3
+
4
+ desc "Run all specs in spec directory"
5
+ task :default do |t|
6
+ options = "--colour --format progress --loadby --reverse"
7
+ files = FileList['spec/**/*_spec.rb']
8
+ system("spec #{options} #{files}")
9
+ end
10
+
11
+ #Gemspec
12
+ begin
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gem|
15
+ project_name = 'rpx_now'
16
+ gem.name = project_name
17
+ gem.summary = "Helper to simplify RPX Now user login/creation"
18
+ gem.email = "grosser.michael@gmail.com"
19
+ gem.homepage = "http://github.com/grosser/#{project_name}"
20
+ gem.authors = ["Michael Grosser"]
21
+ gem.add_dependency ['activesupport']
22
+ gem.files = ['**/*']
23
+ end
24
+ rescue LoadError
25
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
26
+ end
27
+
28
+ task :update_gemspec => [:manifest, :build_gemspec]
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 5
3
+ :patch: 8
4
+ :major: 0
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ #Needed to load rpx_now when used as Rails plugin
2
+ require 'rpx_now'
data/lib/rpx_now.rb ADDED
@@ -0,0 +1,198 @@
1
+ require 'json'
2
+ require 'rpx_now/contacts_collection'
3
+ require 'rpx_now/user_integration'
4
+ require 'rpx_now/user_proxy'
5
+
6
+ module RPXNow
7
+ extend self
8
+
9
+ HOST = 'rpxnow.com'
10
+ SSL_CERT = File.join(File.dirname(__FILE__), '..', 'certs', 'ssl_cert.pem')
11
+
12
+ attr_accessor :api_key
13
+ attr_accessor :api_version
14
+ self.api_version = 2
15
+
16
+ # retrieve the users data, or return nil when nothing could be read/token was invalid
17
+ # or data was not found
18
+ def user_data(token, *args)
19
+ api_key, version, options = extract_key_version_and_options!(args)
20
+ options = {:token=>token,:apiKey=>api_key}.merge options
21
+
22
+ begin
23
+ data = secure_json_post("/api/v#{version}/auth_info", options)
24
+ rescue ServerError
25
+ return nil if $!.to_s=~/Data not found/
26
+ raise
27
+ end
28
+ if block_given? then yield(data) else read_user_data_from_response(data) end
29
+ end
30
+
31
+ # set the users status
32
+ def set_status(identifier, status, *args)
33
+ api_key, version, options = extract_key_version_and_options!(args)
34
+ options = {:identifier => identifier, :status => status, :apiKey => api_key}.merge options
35
+
36
+ begin
37
+ data = secure_json_post("/api/v#{version}/set_status", options)
38
+ rescue ServerError
39
+ return nil if $!.to_s=~/Data not found/
40
+ raise
41
+ end
42
+ end
43
+
44
+ # maps an identifier to an primary-key (e.g. user.id)
45
+ def map(identifier, primary_key, *args)
46
+ api_key, version, options = extract_key_version_and_options!(args)
47
+ options = {:identifier=>identifier,:primaryKey=>primary_key,:apiKey=>api_key}.merge options
48
+ secure_json_post("/api/v#{version}/map", options)
49
+ end
50
+
51
+ # un-maps an identifier to an primary-key (e.g. user.id)
52
+ def unmap(identifier, primary_key, *args)
53
+ api_key, version, options = extract_key_version_and_options!(args)
54
+ options = {:identifier=>identifier,:primaryKey=>primary_key,:apiKey=>api_key}.merge options
55
+ secure_json_post("/api/v#{version}/unmap", options)
56
+ end
57
+
58
+ # returns an array of identifiers which are mapped to one of your primary-keys (e.g. user.id)
59
+ def mappings(primary_key, *args)
60
+ api_key, version, options = extract_key_version_and_options!(args)
61
+ options = {:primaryKey=>primary_key,:apiKey=>api_key}.merge options
62
+ data = secure_json_post("/api/v#{version}/mappings", options)
63
+ data['identifiers']
64
+ end
65
+
66
+ def all_mappings(*args)
67
+ api_key, version, options = extract_key_version_and_options!(args)
68
+ data = secure_json_post("/api/v#{version}/all_mappings", {:apiKey => api_key}.merge(options))
69
+ data['mappings']
70
+ end
71
+
72
+ def contacts(identifier, *args)
73
+ api_key, version, options = extract_key_version_and_options!(args)
74
+ options = {:apiKey => api_key, :identifier=> identifier}.merge(options)
75
+ data = secure_json_post("/api/v#{version}/get_contacts", options)
76
+ RPXNow::ContactsCollection.new(data['response'])
77
+ end
78
+ alias get_contacts contacts
79
+
80
+ def embed_code(subdomain,url,options={})
81
+ options = {:width => '400', :height => '240', :language => 'en'}.merge(options)
82
+ <<EOF
83
+ <iframe src="https://#{subdomain}.#{HOST}/openid/embed?token_url=#{url}&language_preference=#{options[:language]}"
84
+ scrolling="no" frameBorder="no" style="width:#{options[:width]}px;height:#{options[:height]}px;">
85
+ </iframe>
86
+ EOF
87
+ end
88
+
89
+ def popup_code(text, subdomain, url, options = {})
90
+ if options[:unobtrusive]
91
+ unobtrusive_popup_code(text, subdomain, url, options)
92
+ else
93
+ obtrusive_popup_code(text, subdomain, url, options)
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def unobtrusive_popup_code(text, subdomain, url, options={})
100
+ version = extract_version! options
101
+ "<a class=\"rpxnow\" href=\"https://#{subdomain}.#{HOST}/openid/v#{version}/signin?token_url=#{url}\">#{text}</a>"
102
+ end
103
+
104
+ def obtrusive_popup_code(text, subdomain, url, options = {})
105
+ version = extract_version! options
106
+ <<EOF
107
+ <a class="rpxnow" onclick="return false;" href="https://#{subdomain}.#{HOST}/openid/v#{version}/signin?token_url=#{url}">
108
+ #{text}
109
+ </a>
110
+ <script src="https://#{HOST}/openid/v#{version}/widget" type="text/javascript"></script>
111
+ <script type="text/javascript">
112
+ //<![CDATA[
113
+ RPXNOW.token_url = "#{url}";
114
+
115
+ RPXNOW.realm = "#{subdomain}";
116
+ RPXNOW.overlay = true;
117
+ RPXNOW.language_preference = '#{options[:language]||'en'}';
118
+ //]]>
119
+ </script>
120
+ EOF
121
+ end
122
+
123
+ def extract_key_version_and_options!(args)
124
+ key, options = extract_key_and_options(args)
125
+ version = extract_version! options
126
+ [key, version, options]
127
+ end
128
+
129
+ # [API_KEY,{options}] or
130
+ # [{options}] or
131
+ # []
132
+ def extract_key_and_options(args)
133
+ if args.length == 2
134
+ [args[0],args[1]]
135
+ elsif args.length==1
136
+ if args[0].is_a? Hash then [@api_key,args[0]] else [args[0],{}] end
137
+ else
138
+ raise "NO Api Key found!" unless @api_key
139
+ [@api_key,{}]
140
+ end
141
+ end
142
+
143
+ def extract_version!(options)
144
+ options.delete(:api_version) || api_version
145
+ end
146
+
147
+ def read_user_data_from_response(response)
148
+ user_data = response['profile']
149
+ data = {}
150
+ data[:identifier] = user_data['identifier']
151
+ data[:email] = user_data['verifiedEmail'] || user_data['email']
152
+ data[:username] = user_data['preferredUsername'] || data[:email].to_s.sub(/@.*/,'')
153
+ data[:name] = user_data['displayName'] || data[:username]
154
+ data[:id] = user_data['primaryKey'] unless user_data['primaryKey'].to_s.empty?
155
+ data
156
+ end
157
+
158
+ def secure_json_post(path, data)
159
+ parse_response(post(path,data))
160
+ end
161
+
162
+ def post(path, data)
163
+ require 'net/http'
164
+ require 'net/https'
165
+ request = Net::HTTP::Get.new(path)
166
+ request.form_data = data.map{|k,v| [k.to_s,v]}#symbol keys -> string because of ruby 1.9.x bug http://redmine.ruby-lang.org/issues/show/1351
167
+ make_request(request)
168
+ end
169
+
170
+ def make_request(request)
171
+ http = Net::HTTP.new(HOST, 443)
172
+ http.use_ssl = true
173
+ http.ca_file = SSL_CERT
174
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
175
+ http.verify_depth = 5
176
+ http.request(request)
177
+ end
178
+
179
+ def parse_response(response)
180
+ if response.code.to_i >= 400
181
+ raise ServiceUnavailableError, "The RPX service is temporarily unavailable. (4XX)"
182
+ else
183
+ result = JSON.parse(response.body)
184
+ return result unless result['err']
185
+
186
+ code = result['err']['code']
187
+ if code == -1
188
+ raise ServiceUnavailableError, "The RPX service is temporarily unavailable."
189
+ else
190
+ raise ApiError, "Got error: #{result['err']['msg']} (code: #{code}), HTTP status: #{response.code}"
191
+ end
192
+ end
193
+ end
194
+
195
+ class ServerError < Exception; end #backwards compatibility / catch all
196
+ class ApiError < ServerError; end
197
+ class ServiceUnavailableError < ServerError; end
198
+ end
@@ -0,0 +1,19 @@
1
+ module RPXNow
2
+ class ContactsCollection < Array
3
+ def initialize(list)
4
+ @raw = list
5
+ @additional_info = list.reject{|k,v|k=='entry'}
6
+ list['entry'].each{|item| self << parse_data(item)}
7
+ end
8
+
9
+ def additional_info;@additional_info;end
10
+ def raw;@raw;end
11
+
12
+ private
13
+
14
+ def parse_data(entry)
15
+ entry['emails'] = entry['emails'].map{|email| email['value']}
16
+ entry
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ module RPXNow
2
+ module UserIntegration
3
+ def rpx
4
+ RPXNow::UserProxy.new(id)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ module RPXNow
2
+ class UserProxy
3
+ def initialize(id)
4
+ @id = id
5
+ end
6
+
7
+ def identifiers
8
+ RPXNow.mappings(@id)
9
+ end
10
+
11
+ def map(identifier)
12
+ RPXNow.map(identifier, @id)
13
+ end
14
+
15
+ def unmap(identifier)
16
+ RPXNow.unmap(identifier, @id)
17
+ end
18
+ end
19
+ end
data/rpx_now.gemspec ADDED
@@ -0,0 +1,56 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{rpx_now}
5
+ s.version = "0.5.8"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Michael Grosser"]
9
+ s.date = %q{2009-06-21}
10
+ s.email = %q{grosser.michael@gmail.com}
11
+ s.extra_rdoc_files = [
12
+ "README.markdown"
13
+ ]
14
+ s.files = [
15
+ "CHANGELOG",
16
+ "MIGRATION",
17
+ "README.markdown",
18
+ "Rakefile",
19
+ "VERSION.yml",
20
+ "init.rb",
21
+ "lib/rpx_now.rb",
22
+ "lib/rpx_now/contacts_collection.rb",
23
+ "lib/rpx_now/user_integration.rb",
24
+ "lib/rpx_now/user_proxy.rb",
25
+ "rpx_now.gemspec",
26
+ "spec/fixtures/get_contacts_response.json",
27
+ "spec/rpx_now/contacts_collection_spec.rb",
28
+ "spec/rpx_now/user_proxy_spec.rb",
29
+ "spec/rpx_now_spec.rb",
30
+ "spec/spec_helper.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/grosser/rpx_now}
33
+ s.rdoc_options = ["--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.5}
36
+ s.summary = %q{Helper to simplify RPX Now user login/creation}
37
+ s.test_files = [
38
+ "spec/rpx_now_spec.rb",
39
+ "spec/rpx_now/contacts_collection_spec.rb",
40
+ "spec/rpx_now/user_proxy_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+
44
+ if s.respond_to? :specification_version then
45
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
50
+ else
51
+ s.add_dependency(%q<activesupport>, [">= 0"])
52
+ end
53
+ else
54
+ s.add_dependency(%q<activesupport>, [">= 0"])
55
+ end
56
+ end
@@ -0,0 +1,58 @@
1
+ {
2
+ "response": {
3
+ "itemsPerPage": 5,
4
+ "totalResults": 5,
5
+ "entry": [
6
+ {
7
+ "displayName": "Bob Johnson",
8
+ "emails": [
9
+ {
10
+ "type": "other",
11
+ "value": "bob@example.com"
12
+ }
13
+ ]
14
+ },
15
+ {
16
+ "displayName": "Cindy Smith",
17
+ "emails": [
18
+ {
19
+ "type": "other",
20
+ "value": "cindy.smith@example.com"
21
+ }
22
+ ]
23
+ },
24
+ {
25
+ "displayName": "Fred Williams",
26
+ "emails": [
27
+ {
28
+ "type": "other",
29
+ "value": "fred.williams@example.com"
30
+ },
31
+ {
32
+ "type": "other",
33
+ "value": "fred@example.com"
34
+ }
35
+ ]
36
+ },
37
+ {
38
+ "emails": [
39
+ {
40
+ "type": "other",
41
+ "value": "j.lewis@example.com"
42
+ }
43
+ ]
44
+ },
45
+ {
46
+ "displayName": "Mary Jones",
47
+ "emails": [
48
+ {
49
+ "type": "other",
50
+ "value": "mary.jones@example.com"
51
+ }
52
+ ]
53
+ }
54
+ ],
55
+ "startIndex": 1
56
+ },
57
+ "stat": "ok"
58
+ }
@@ -0,0 +1,32 @@
1
+ require File.expand_path("../spec_helper", File.dirname(__FILE__))
2
+
3
+ describe RPXNow::ContactsCollection do
4
+ before do
5
+ data = JSON.parse(File.read('spec/fixtures/get_contacts_response.json'))['response']
6
+ @collection = RPXNow::ContactsCollection.new(data)
7
+ end
8
+
9
+ it "behaves like an array" do
10
+ @collection.size.should == 5
11
+ @collection[0] = "1"
12
+ @collection[0].should == "1"
13
+ end
14
+
15
+ it "parses entry to items" do
16
+ @collection[0]['displayName'].should == "Bob Johnson"
17
+ end
18
+
19
+ it "parses emails to list" do
20
+ @collection[0]['emails'].should == ["bob@example.com"]
21
+ end
22
+
23
+ it "parses emails to list with multiple emails" do
24
+ @collection[2]['emails'].should == ["fred.williams@example.com","fred@example.com"]
25
+ end
26
+
27
+ it "holds additional_info" do
28
+ @collection.additional_info['startIndex'].should == 1
29
+ @collection.additional_info['itemsPerPage'].should == 5
30
+ @collection.additional_info['totalResults'].should == 5
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ require File.expand_path("../spec_helper", File.dirname(__FILE__))
2
+
3
+ class User
4
+ include RPXNow::UserIntegration
5
+
6
+ def id
7
+ 5
8
+ end
9
+ end
10
+
11
+ describe RPXNow::UserProxy do
12
+ before do
13
+ RPXNow.unmap('http://test.myopenid.com', 5)
14
+ end
15
+
16
+ it "has identifiers" do
17
+ RPXNow.map('http://test.myopenid.com', 5)
18
+ User.new.rpx.identifiers.should == ['http://test.myopenid.com']
19
+ end
20
+
21
+ it "can map" do
22
+ User.new.rpx.map('http://test.myopenid.com')
23
+ User.new.rpx.identifiers.should == ['http://test.myopenid.com']
24
+ end
25
+
26
+ it "can unmap" do
27
+ RPXNow.map('http://test.myopenid.com', 5)
28
+ User.new.rpx.unmap('http://test.myopenid.com')
29
+ User.new.rpx.identifiers.should == []
30
+ end
31
+ end
@@ -0,0 +1,278 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+
3
+ describe RPXNow do
4
+ describe :api_key= do
5
+ it "stores the api key, so i do not have to supply everytime" do
6
+ RPXNow.api_key='XX'
7
+ RPXNow.expects(:post).with{|x,data|data[:apiKey]=='XX'}.returns mock(:code=>'200', :body=>%Q({"stat":"ok"}))
8
+ RPXNow.mappings(1)
9
+ end
10
+ end
11
+
12
+ describe :api_version= do
13
+ it "can be set to a api_version globally" do
14
+ RPXNow.api_version = 5
15
+ RPXNow.popup_code('x','y','z').should =~ %r(/openid/v5/signin)
16
+ end
17
+ end
18
+
19
+ describe :embed_code do
20
+ it "contains the subdomain" do
21
+ RPXNow.embed_code('xxx','my_url').should =~ /xxx/
22
+ end
23
+
24
+ it "contains the url" do
25
+ RPXNow.embed_code('xxx','my_url').should =~ /token_url=my_url/
26
+ end
27
+
28
+ it "defaults to English" do
29
+ RPXNow.embed_code('xxx', 'my_url').should =~ /language_preference=en/
30
+ end
31
+
32
+ it "has a changeable language" do
33
+ RPXNow.embed_code('xxx', 'my_url', :language => 'es').should =~ /language_preference=es/
34
+ end
35
+
36
+ it "defaults to 400px width" do
37
+ RPXNow.embed_code('xxx', 'my_url').should =~ /width:400px;/
38
+ end
39
+
40
+ it "has a changeable width" do
41
+ RPXNow.embed_code('xxx', 'my_url', :width => '300').should =~ /width:300px;/
42
+ end
43
+
44
+ it "defaults to 240px height" do
45
+ RPXNow.embed_code('xxx', 'my_url').should =~ /height:240px;/
46
+ end
47
+
48
+ it "has a changeable height" do
49
+ RPXNow.embed_code('xxx', 'my_url', :height => '500').should =~ /height:500px;/
50
+ end
51
+ end
52
+
53
+ describe :popup_code do
54
+ it "defaults to obtrusive output" do
55
+ RPXNow.popup_code('sign on', 'subdomain', 'http://fake.domain.com/').should =~ /script src=/
56
+ end
57
+
58
+ it "can build an unobtrusive widget with specific version" do
59
+ expected = %Q(<a class="rpxnow" href="https://subdomain.rpxnow.com/openid/v300/signin?token_url=http://fake.domain.com/">sign on</a>)
60
+ RPXNow.popup_code('sign on', 'subdomain', 'http://fake.domain.com/', { :unobtrusive => true, :api_version => 300 }).should == expected
61
+ end
62
+
63
+ it "allows to specify the version of the widget" do
64
+ RPXNow.popup_code('x','y','z', :api_version => 300).should =~ %r(/openid/v300/signin)
65
+ end
66
+
67
+ it "defaults to widget version 2" do
68
+ RPXNow.popup_code('x','y','z').should =~ %r(/openid/v2/signin)
69
+ end
70
+
71
+ it "defaults to english" do
72
+ RPXNow.popup_code('x','y','z').should =~ /RPXNOW.language_preference = 'en'/
73
+ end
74
+
75
+ it "has a changeable language" do
76
+ RPXNow.popup_code('x','y','z',:language=>'de').should =~ /RPXNOW.language_preference = 'de'/
77
+ end
78
+ end
79
+
80
+ describe :user_data do
81
+ before do
82
+ @response_body = %Q({"profile":{"verifiedEmail":"grosser.michael@googlemail.com","displayName":"Michael Grosser","preferredUsername":"grosser.michael","identifier":"https:\/\/www.google.com\/accounts\/o8\/id?id=AItOawmaOlyYezg_WfbgP_qjaUyHjmqZD9qNIVM","email":"grosser.michael@gmail.com"},"stat":"ok"})
83
+ @fake_user_data = {'profile'=>{}}
84
+ end
85
+
86
+ def fake_response
87
+ mock(:code=>"200",:body=>@response_body)
88
+ end
89
+
90
+ it "raises ApiError when used with an invalid token" do
91
+ lambda{
92
+ RPXNow.user_data('xxxx')
93
+ }.should raise_error(RPXNow::ApiError)
94
+ end
95
+
96
+ it "is empty when used with an unknown token" do
97
+ RPXNow.user_data('60d8c6374f4e9d290a7b55f39da7cc6435aef3d3').should == nil
98
+ end
99
+
100
+ it "parses JSON response to user data" do
101
+ RPXNow.expects(:post).returns fake_response
102
+ RPXNow.user_data('').should == {:name=>'Michael Grosser',:email=>'grosser.michael@googlemail.com',:identifier=>"https://www.google.com/accounts/o8/id?id=AItOawmaOlyYezg_WfbgP_qjaUyHjmqZD9qNIVM", :username => 'grosser.michael'}
103
+ end
104
+
105
+ it "adds a :id when primaryKey was returned" do
106
+ @response_body.sub!(%Q("verifiedEmail"), %Q("primaryKey":"2","verifiedEmail"))
107
+ RPXNow.expects(:post).returns fake_response
108
+ RPXNow.user_data('')[:id].should == '2'
109
+ end
110
+
111
+ it "handles primaryKeys that are not numeric" do
112
+ @response_body.sub!(%Q("verifiedEmail"), %Q("primaryKey":"dbalatero","verifiedEmail"))
113
+ RPXNow.expects(:post).returns fake_response
114
+ RPXNow.user_data('')[:id].should == 'dbalatero'
115
+ end
116
+
117
+ it "hands JSON response to supplied block" do
118
+ RPXNow.expects(:post).returns mock(:code=>'200',:body=>%Q({"x":"1","stat":"ok"}))
119
+ response = nil
120
+ RPXNow.user_data(''){|data| response = data}
121
+ response.should == {"x" => "1", "stat" => "ok"}
122
+ end
123
+
124
+ it "returns what the supplied block returned" do
125
+ RPXNow.expects(:post).returns mock(:code=>'200',:body=>%Q({"x":"1","stat":"ok"}))
126
+ RPXNow.user_data(''){|data| "x"}.should == 'x'
127
+ end
128
+
129
+ it "can send additional parameters" do
130
+ RPXNow.expects(:post).with{|url,data|
131
+ data[:extended].should == 'true'
132
+ }.returns fake_response
133
+ RPXNow.user_data('',:extended=>'true')
134
+ end
135
+
136
+ it "works with api key as 2nd parameter (backwards compatibility)" do
137
+ RPXNow.expects(:secure_json_post).with('/api/v2/auth_info', :apiKey=>'THE KEY', :token=>'id').returns @fake_user_data
138
+ RPXNow.user_data('id', 'THE KEY')
139
+ RPXNow.api_key.should == API_KEY
140
+ end
141
+
142
+ it "works with api key as 2nd parameter and options (backwards compatibility)" do
143
+ RPXNow.expects(:secure_json_post).with('/api/v2/auth_info', :apiKey=>'THE KEY', :extended=>'abc', :token=>'id' ).returns @fake_user_data
144
+ RPXNow.user_data('id', 'THE KEY', :extended=>'abc')
145
+ RPXNow.api_key.should == API_KEY
146
+ end
147
+
148
+ it "works with api version as option (backwards compatibility)" do
149
+ RPXNow.expects(:secure_json_post).with('/api/v123/auth_info', :apiKey=>API_KEY, :token=>'id', :extended=>'abc').returns @fake_user_data
150
+ RPXNow.user_data('id', :extended=>'abc', :api_version=>123)
151
+ RPXNow.api_version.should == API_VERSION
152
+ end
153
+ end
154
+
155
+ describe :set_status do
156
+ before do
157
+ @response_body = %Q({ "stat": "ok" })
158
+ end
159
+
160
+ def fake_response
161
+ mock(:code=>"200",:body=>@response_body)
162
+ end
163
+
164
+ it "parses JSON response to result hash" do
165
+ RPXNow.expects(:post).returns fake_response
166
+ RPXNow.set_status('identifier', 'Chillen...').should == {'stat' => 'ok'}
167
+ end
168
+ end
169
+
170
+ describe :read_user_data_from_response do
171
+ it "reads secondary names" do
172
+ RPXNow.send(:read_user_data_from_response,{'profile'=>{'preferredUsername'=>'1'}})[:name].should == '1'
173
+ end
174
+
175
+ it "parses email when no name is found" do
176
+ RPXNow.send(:read_user_data_from_response,{'profile'=>{'email'=>'1@xxx.com'}})[:name].should == '1'
177
+ end
178
+ end
179
+
180
+ describe :contacts do
181
+ it "finds all contacts" do
182
+ response = JSON.parse(File.read('spec/fixtures/get_contacts_response.json'))
183
+ RPXNow.expects(:secure_json_post).with('/api/v2/get_contacts',:identifier=>'xx', :apiKey=>API_KEY).returns response
184
+ RPXNow.contacts('xx').size.should == 5
185
+ end
186
+ end
187
+
188
+ describe :parse_response do
189
+ it "parses json when status is ok" do
190
+ response = mock(:code=>'200', :body=>%Q({"stat":"ok","data":"xx"}))
191
+ RPXNow.send(:parse_response, response)['data'].should == "xx"
192
+ end
193
+
194
+ it "raises when there is a communication error" do
195
+ response = stub(:code=>'200', :body=>%Q({"err":"wtf","stat":"ok"}))
196
+ lambda{
197
+ RPXNow.send(:parse_response,response)
198
+ }.should raise_error(RPXNow::ApiError)
199
+ end
200
+
201
+ it "raises when service has downtime" do
202
+ response = stub(:code=>'200', :body=>%Q({"err":{"code":-1},"stat":"ok"}))
203
+ lambda{
204
+ RPXNow.send(:parse_response,response)
205
+ }.should raise_error(RPXNow::ServiceUnavailableError)
206
+ end
207
+
208
+ it "raises when service is down" do
209
+ response = stub(:code=>'400',:body=>%Q({"stat":"err"}))
210
+ lambda{
211
+ RPXNow.send(:parse_response,response)
212
+ }.should raise_error(RPXNow::ServiceUnavailableError)
213
+ end
214
+ end
215
+
216
+ describe :mappings do
217
+ it "parses JSON response to unmap data" do
218
+ RPXNow.expects(:post).returns mock(:code=>'200',:body=>%Q({"stat":"ok", "identifiers": ["http://test.myopenid.com/"]}))
219
+ RPXNow.mappings(1, "x").should == ["http://test.myopenid.com/"]
220
+ end
221
+ end
222
+
223
+ describe :map do
224
+ it "adds a mapping" do
225
+ RPXNow.expects(:post).returns mock(:code=>'200',:body=>%Q({"stat":"ok"}))
226
+ RPXNow.map('http://test.myopenid.com',1, API_KEY)
227
+ end
228
+ end
229
+
230
+ describe :unmap do
231
+ it "unmaps a indentifier" do
232
+ RPXNow.expects(:post).returns mock(:code=>'200',:body=>%Q({"stat":"ok"}))
233
+ RPXNow.unmap('http://test.myopenid.com', 1, "x")
234
+ end
235
+
236
+ it "can be called with a specific version" do
237
+ RPXNow.expects(:secure_json_post).with{|a,b|a == "/api/v300/unmap"}
238
+ RPXNow.unmap('http://test.myopenid.com', 1, :api_key=>'xxx', :api_version=>300)
239
+ end
240
+ end
241
+
242
+ describe :mapping_integration do
243
+ before do
244
+ @k1 = 'http://test.myopenid.com'
245
+ RPXNow.unmap(@k1, 1)
246
+ @k2 = 'http://test-2.myopenid.com'
247
+ RPXNow.unmap(@k2, 1)
248
+ end
249
+
250
+ it "has no mappings when nothing was mapped" do
251
+ RPXNow.mappings(1).should == []
252
+ end
253
+
254
+ it "unmaps mapped keys" do
255
+ RPXNow.map(@k2, 1)
256
+ RPXNow.unmap(@k2, 1)
257
+ RPXNow.mappings(1).should == []
258
+ end
259
+
260
+ it "maps keys to a primary key and then retrieves them" do
261
+ RPXNow.map(@k1, 1)
262
+ RPXNow.map(@k2, 1)
263
+ RPXNow.mappings(1).sort.should == [@k2,@k1]
264
+ end
265
+
266
+ it "does not add duplicate mappings" do
267
+ RPXNow.map(@k1, 1)
268
+ RPXNow.map(@k1, 1)
269
+ RPXNow.mappings(1).should == [@k1]
270
+ end
271
+
272
+ it "finds all mappings" do
273
+ RPXNow.map(@k1, 1)
274
+ RPXNow.map(@k2, 2)
275
+ RPXNow.all_mappings.sort.should == [["1", ["http://test.myopenid.com"]], ["2", ["http://test-2.myopenid.com"]]]
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,20 @@
1
+ # ---- requirements
2
+ require 'rubygems'
3
+ require 'spec'
4
+ require 'mocha'
5
+
6
+ $LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
7
+
8
+ # ---- setup environment/plugin
9
+ require File.expand_path("../init", File.dirname(__FILE__))
10
+ API_KEY = '4b339169026742245b754fa338b9b0aebbd0a733'
11
+ API_VERSION = RPXNow.api_version
12
+
13
+ # ---- rspec
14
+ Spec::Runner.configure do |config|
15
+ config.mock_with :mocha
16
+ config.before :each do
17
+ RPXNow.api_key = API_KEY
18
+ RPXNow.api_version = API_VERSION
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jackdempsey-rpx_now
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.8
5
+ platform: ruby
6
+ authors:
7
+ - Michael Grosser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-21 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: grosser.michael@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.markdown
33
+ files:
34
+ - CHANGELOG
35
+ - MIGRATION
36
+ - README.markdown
37
+ - Rakefile
38
+ - VERSION.yml
39
+ - init.rb
40
+ - lib/rpx_now.rb
41
+ - lib/rpx_now/contacts_collection.rb
42
+ - lib/rpx_now/user_integration.rb
43
+ - lib/rpx_now/user_proxy.rb
44
+ - rpx_now.gemspec
45
+ - spec/fixtures/get_contacts_response.json
46
+ - spec/rpx_now/contacts_collection_spec.rb
47
+ - spec/rpx_now/user_proxy_spec.rb
48
+ - spec/rpx_now_spec.rb
49
+ - spec/spec_helper.rb
50
+ has_rdoc: false
51
+ homepage: http://github.com/grosser/rpx_now
52
+ licenses:
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.5
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Helper to simplify RPX Now user login/creation
77
+ test_files:
78
+ - spec/rpx_now_spec.rb
79
+ - spec/rpx_now/contacts_collection_spec.rb
80
+ - spec/rpx_now/user_proxy_spec.rb
81
+ - spec/spec_helper.rb