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 +23 -0
- data/MIGRATION +9 -0
- data/README.markdown +113 -0
- data/Rakefile +28 -0
- data/VERSION.yml +4 -0
- data/init.rb +2 -0
- data/lib/rpx_now.rb +198 -0
- data/lib/rpx_now/contacts_collection.rb +19 -0
- data/lib/rpx_now/user_integration.rb +7 -0
- data/lib/rpx_now/user_proxy.rb +19 -0
- data/rpx_now.gemspec +56 -0
- data/spec/fixtures/get_contacts_response.json +58 -0
- data/spec/rpx_now/contacts_collection_spec.rb +32 -0
- data/spec/rpx_now/user_proxy_spec.rb +31 -0
- data/spec/rpx_now_spec.rb +278 -0
- data/spec/spec_helper.rb +20 -0
- metadata +81 -0
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
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
|
+

|
|
13
|
+

|
|
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
data/init.rb
ADDED
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,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
|
data/spec/spec_helper.rb
ADDED
|
@@ -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
|