rpx_now 0.5.10

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/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::Post.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 < RuntimeError; 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
Binary file
data/rpx_now.gemspec ADDED
@@ -0,0 +1,62 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rpx_now}
8
+ s.version = "0.5.10"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Grosser"]
12
+ s.date = %q{2009-10-06}
13
+ s.email = %q{grosser.michael@gmail.com}
14
+ s.extra_rdoc_files = [
15
+ "README.markdown"
16
+ ]
17
+ s.files = [
18
+ "CHANGELOG",
19
+ "MIGRATION",
20
+ "README.markdown",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "certs/ssl_cert.pem",
24
+ "init.rb",
25
+ "lib/rpx_now.rb",
26
+ "lib/rpx_now/contacts_collection.rb",
27
+ "lib/rpx_now/user_integration.rb",
28
+ "lib/rpx_now/user_proxy.rb",
29
+ "pkg/rpx_now-0.5.10.gem",
30
+ "rpx_now.gemspec",
31
+ "spec/fixtures/get_contacts_response.json",
32
+ "spec/rpx_now/contacts_collection_spec.rb",
33
+ "spec/rpx_now/user_proxy_spec.rb",
34
+ "spec/rpx_now_spec.rb",
35
+ "spec/spec_helper.rb"
36
+ ]
37
+ s.homepage = %q{http://github.com/grosser/rpx_now}
38
+ s.rdoc_options = ["--charset=UTF-8"]
39
+ s.require_paths = ["lib"]
40
+ s.rubyforge_project = %q{rpx-now}
41
+ s.rubygems_version = %q{1.3.5}
42
+ s.summary = %q{Helper to simplify RPX Now user login/creation}
43
+ s.test_files = [
44
+ "spec/rpx_now_spec.rb",
45
+ "spec/rpx_now/contacts_collection_spec.rb",
46
+ "spec/rpx_now/user_proxy_spec.rb",
47
+ "spec/spec_helper.rb"
48
+ ]
49
+
50
+ if s.respond_to? :specification_version then
51
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
52
+ s.specification_version = 3
53
+
54
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
55
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
56
+ else
57
+ s.add_dependency(%q<activesupport>, [">= 0"])
58
+ end
59
+ else
60
+ s.add_dependency(%q<activesupport>, [">= 0"])
61
+ end
62
+ 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