goodguide-accounts 1.0.0
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/Gemfile +6 -0
- data/goodguide-accounts.gemspec +16 -0
- data/lib/goodguide/accounts/base.rb +264 -0
- data/lib/goodguide/accounts/issue_preferences.rb +15 -0
- data/lib/goodguide/accounts/profile.rb +47 -0
- data/lib/goodguide/accounts/version.rb +5 -0
- data/lib/goodguide/accounts.rb +13 -0
- data/lib/oauth2_error.rb +5 -0
- metadata +87 -0
data/Gemfile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require './lib/goodguide/accounts/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "goodguide-accounts"
|
5
|
+
s.version = GoodGuide::Accounts::VERSION
|
6
|
+
s.authors = ["Jay Adkisson", "Ryan Aipperspach"]
|
7
|
+
s.email = ["jay@goodguide.com", "ryan@goodguide.com"]
|
8
|
+
s.summary = "GoodGuide Accounts API gem"
|
9
|
+
s.description = "Gem to access the GoodGuide Accounts API"
|
10
|
+
s.homepage = "http://www.goodguide.com"
|
11
|
+
s.rubyforge_project = "goodguide"
|
12
|
+
s.files = Dir['Gemfile', 'goodguide-accounts.gemspec', 'lib/**/*.rb']
|
13
|
+
|
14
|
+
s.add_dependency('oauth2', '~> 0.5.0.rc1')
|
15
|
+
s.add_dependency('i18n')
|
16
|
+
end
|
@@ -0,0 +1,264 @@
|
|
1
|
+
require File.expand_path('issue_preferences', File.dirname(__FILE__))
|
2
|
+
|
3
|
+
module GoodGuide
|
4
|
+
module Accounts
|
5
|
+
class Base
|
6
|
+
include IssuePreferences
|
7
|
+
include Profile
|
8
|
+
|
9
|
+
NotAuthenticatedError = Class.new(StandardError)
|
10
|
+
|
11
|
+
class << self
|
12
|
+
#####
|
13
|
+
# How the auth flow works:
|
14
|
+
#
|
15
|
+
# 1. Redirect the user-agent to Account.authorize_url
|
16
|
+
# 2. After authentication, the user will be redirected
|
17
|
+
# to your pre-configured authorization endpoint,
|
18
|
+
# (e.g. /sessions/authorize), with ?code=...
|
19
|
+
# 3. Do something like this:
|
20
|
+
#
|
21
|
+
# def authorize
|
22
|
+
# # get the code from the params
|
23
|
+
# code = params[:code]
|
24
|
+
# # exchange it with the oauth2 server for an
|
25
|
+
# # access token
|
26
|
+
# credentials = User.authorize(code)
|
27
|
+
# # store credentials
|
28
|
+
# # (a hash of access_token, refresh_token, and expires_at)
|
29
|
+
# # in the session
|
30
|
+
# session[:credentials] = credentials
|
31
|
+
# # and send them on their way
|
32
|
+
# redirect_to session[:redirect] || '/'
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# 4. To get the current user, do something like this:
|
36
|
+
#
|
37
|
+
# def current_user
|
38
|
+
# User.authenticate(session[:credentials])
|
39
|
+
# end
|
40
|
+
def authenticate(credentials, opts={})
|
41
|
+
new({:credentials => credentials}.merge(opts))
|
42
|
+
end
|
43
|
+
|
44
|
+
# returns a credentials hash
|
45
|
+
# given an authorization code
|
46
|
+
def authorize(code, options={})
|
47
|
+
access_token = client.auth_code.get_token(code, {
|
48
|
+
:redirect_uri => config[:redirect_uri]
|
49
|
+
}.merge(options))
|
50
|
+
|
51
|
+
# return a credentials hash
|
52
|
+
{
|
53
|
+
:access_token => access_token.token,
|
54
|
+
:refresh_token => access_token.refresh_token,
|
55
|
+
:expires_at => access_token.expires_at
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def authorize_url(opts={})
|
60
|
+
client.auth_code.authorize_url(opts)
|
61
|
+
end
|
62
|
+
|
63
|
+
def logout_url(opts={})
|
64
|
+
url = config[:site] + "/sessions/clear"
|
65
|
+
url += "?redirect=#{CGI.escape(opts[:redirect])}" if opts[:redirect]
|
66
|
+
url
|
67
|
+
end
|
68
|
+
|
69
|
+
def config=(conf)
|
70
|
+
# In the absence of #symbolize_keys...
|
71
|
+
conf = conf.dup
|
72
|
+
conf.keys.each do |k|
|
73
|
+
conf[k.to_sym] = conf.delete(k)
|
74
|
+
end
|
75
|
+
|
76
|
+
@config = default_config.merge(conf)
|
77
|
+
end
|
78
|
+
|
79
|
+
def config
|
80
|
+
return @config if instance_variable_defined? :@config
|
81
|
+
|
82
|
+
yaml = YAML.load_file('config/goodguide_accounts.yml')
|
83
|
+
|
84
|
+
self.config = env && yaml.key?(env) ? yaml[env] : yaml
|
85
|
+
|
86
|
+
@config
|
87
|
+
end
|
88
|
+
|
89
|
+
def client
|
90
|
+
@client ||= begin
|
91
|
+
my_config = config.dup
|
92
|
+
|
93
|
+
if my_config[:site]
|
94
|
+
my_config[:site] += '/api/account'
|
95
|
+
end
|
96
|
+
|
97
|
+
OAuth2::Client.new(
|
98
|
+
my_config.delete(:identifier), my_config.delete(:secret),
|
99
|
+
my_config.merge(:ssl => {:verify => false})
|
100
|
+
)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
def default_config
|
106
|
+
{
|
107
|
+
:authorize_url => '/oauth2/authorize',
|
108
|
+
:token_url => '/oauth2/token',
|
109
|
+
:site => 'https://accounts.goodguide.com'
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def env
|
114
|
+
return @env if instance_variable_defined? :@env
|
115
|
+
|
116
|
+
@env = ENV['ACCOUNTS_ENV'] || if defined?(Rails) and Rails.respond_to? :env
|
117
|
+
Rails.env
|
118
|
+
elsif defined?(RAILS_ENV)
|
119
|
+
RAILS_ENV
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
attr_reader :client
|
125
|
+
attr_reader :access_token
|
126
|
+
attr_reader :refresh_token
|
127
|
+
attr_reader :id
|
128
|
+
def initialize(opts={})
|
129
|
+
opts = opts.dup
|
130
|
+
|
131
|
+
credentials = opts.delete(:credentials) || {}
|
132
|
+
@expires_at = credentials[:expires_at]
|
133
|
+
@access_token = credentials[:access_token]
|
134
|
+
@refresh_token = credentials[:refresh_token]
|
135
|
+
|
136
|
+
opts.each do |k, v|
|
137
|
+
instance_variable_set("@#{k}", v)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def update_credentials(opts = {})
|
142
|
+
@expires_at = opts[:expires_at]
|
143
|
+
@access_token = opts[:access_token]
|
144
|
+
@refresh_token = opts[:refresh_token]
|
145
|
+
|
146
|
+
self
|
147
|
+
end
|
148
|
+
|
149
|
+
def base_body_options
|
150
|
+
opts = {}
|
151
|
+
opts[:bearer_token] = access_token if authorized?
|
152
|
+
opts
|
153
|
+
end
|
154
|
+
|
155
|
+
def refreshable?
|
156
|
+
refresh_token
|
157
|
+
end
|
158
|
+
|
159
|
+
def authorized?
|
160
|
+
authenticated? or refreshable?
|
161
|
+
end
|
162
|
+
|
163
|
+
def authenticated?
|
164
|
+
!!(access_token and not expired?)
|
165
|
+
end
|
166
|
+
|
167
|
+
def profile?
|
168
|
+
profile.present?
|
169
|
+
end
|
170
|
+
|
171
|
+
def guest?
|
172
|
+
not authorized? #and not profile?
|
173
|
+
end
|
174
|
+
|
175
|
+
def real?
|
176
|
+
not guest?
|
177
|
+
end
|
178
|
+
|
179
|
+
def needs_refresh?
|
180
|
+
authorized? and not authenticated?
|
181
|
+
end
|
182
|
+
|
183
|
+
def expires_at
|
184
|
+
Time.at(@expires_at || 0)
|
185
|
+
end
|
186
|
+
|
187
|
+
def expires_in
|
188
|
+
(expires_at - Time.now).to_i
|
189
|
+
end
|
190
|
+
|
191
|
+
def expired?
|
192
|
+
expires_in <= 0
|
193
|
+
end
|
194
|
+
|
195
|
+
def endpoint
|
196
|
+
if authorized?
|
197
|
+
'/account'
|
198
|
+
elsif profile?
|
199
|
+
"/accounts/#{id}"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def credentials
|
204
|
+
{
|
205
|
+
:expires_at => expires_at,
|
206
|
+
:access_token => access_token,
|
207
|
+
:refresh_token => refresh_token
|
208
|
+
}
|
209
|
+
end
|
210
|
+
|
211
|
+
def refresh!
|
212
|
+
if refreshable?
|
213
|
+
@connection = connection.refresh!
|
214
|
+
update_credentials(
|
215
|
+
:expires_at => connection.expires_at,
|
216
|
+
:refresh_token => connection.refresh_token,
|
217
|
+
:access_token => connection.token
|
218
|
+
)
|
219
|
+
end
|
220
|
+
rescue OAuth2::Error
|
221
|
+
$!.response
|
222
|
+
end
|
223
|
+
|
224
|
+
def connection
|
225
|
+
@connection ||= begin
|
226
|
+
if authorized?
|
227
|
+
OAuth2::AccessToken.new(self.class.client, access_token, credentials)
|
228
|
+
else
|
229
|
+
self.class.client
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def endpoint
|
235
|
+
if authorized?
|
236
|
+
'/api/account'
|
237
|
+
else
|
238
|
+
"/api/accounts/#{id}"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# delegate http methods to the connection
|
243
|
+
%w(get put post delete head).each do |verb|
|
244
|
+
define_method(verb) do |*args|
|
245
|
+
request(verb, *args)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def request(verb, path, opts={})
|
250
|
+
path = "/#{path}" if path.is_a? Symbol
|
251
|
+
|
252
|
+
unless opts.key?(:body) || opts.key?(:headers)
|
253
|
+
opts = { :body => opts }
|
254
|
+
end
|
255
|
+
|
256
|
+
JSON.load(connection.request(verb.to_sym, endpoint + path, opts).body)
|
257
|
+
end
|
258
|
+
|
259
|
+
def profile
|
260
|
+
@profile ||= guest? ? {} : get('/')['account']
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module GoodGuide
|
2
|
+
module Accounts
|
3
|
+
module IssuePreferences
|
4
|
+
|
5
|
+
def issue_preferences
|
6
|
+
@issue_preferences ||= get(:issue_preferences)['issue_preferences']
|
7
|
+
end
|
8
|
+
|
9
|
+
def update_issue_preferences(prefs)
|
10
|
+
@issue_preferences = nil
|
11
|
+
put(:issue_preferences, :issue_preferences => prefs)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module GoodGuide
|
2
|
+
module Accounts
|
3
|
+
module Profile
|
4
|
+
def with_profile(default = nil, &block)
|
5
|
+
profile? ? yield(profile) : default
|
6
|
+
end
|
7
|
+
|
8
|
+
def identifier
|
9
|
+
with_profile do |profile|
|
10
|
+
profile['identifier']
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def given_name
|
15
|
+
with_profile do |profile|
|
16
|
+
name = profile["name"]["givenName"] ||
|
17
|
+
profile["displayName"] ||
|
18
|
+
profile["name"]["formatted"]
|
19
|
+
|
20
|
+
!name.blank? ? name.strip : "GoodGuide User"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def full_name
|
25
|
+
with_profile do |profile|
|
26
|
+
name = profile["name"]["formatted"]
|
27
|
+
|
28
|
+
!name.blank? ? name.strip : "GoodGuide User"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def profile_picture(size = nil)
|
33
|
+
with_profile do |profile|
|
34
|
+
photo = profile["photo"]
|
35
|
+
photo.gsub!("=large", "=#{size}") if facebook? and size.present?
|
36
|
+
photo
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def facebook?
|
41
|
+
with_profile(false) do |profile|
|
42
|
+
profile["identifier"] && profile["identifier"].include?("facebook.com")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
require 'oauth2'
|
3
|
+
|
4
|
+
module GoodGuide
|
5
|
+
module Accounts
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require File.expand_path('../oauth2_error', File.dirname(__FILE__))
|
10
|
+
require File.expand_path('accounts/version', File.dirname(__FILE__))
|
11
|
+
require File.expand_path('accounts/issue_preferences', File.dirname(__FILE__))
|
12
|
+
require File.expand_path('accounts/profile', File.dirname(__FILE__))
|
13
|
+
require File.expand_path('accounts/base', File.dirname(__FILE__))
|
data/lib/oauth2_error.rb
ADDED
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: goodguide-accounts
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 1.0.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jay Adkisson
|
9
|
+
- Ryan Aipperspach
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2011-08-05 00:00:00 -07:00
|
15
|
+
default_executable:
|
16
|
+
dependencies:
|
17
|
+
- !ruby/object:Gem::Dependency
|
18
|
+
name: oauth2
|
19
|
+
prerelease: false
|
20
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
21
|
+
none: false
|
22
|
+
requirements:
|
23
|
+
- - ~>
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 0.5.0.rc1
|
26
|
+
type: :runtime
|
27
|
+
version_requirements: *id001
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: i18n
|
30
|
+
prerelease: false
|
31
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
32
|
+
none: false
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: "0"
|
37
|
+
type: :runtime
|
38
|
+
version_requirements: *id002
|
39
|
+
description: Gem to access the GoodGuide Accounts API
|
40
|
+
email:
|
41
|
+
- jay@goodguide.com
|
42
|
+
- ryan@goodguide.com
|
43
|
+
executables: []
|
44
|
+
|
45
|
+
extensions: []
|
46
|
+
|
47
|
+
extra_rdoc_files: []
|
48
|
+
|
49
|
+
files:
|
50
|
+
- Gemfile
|
51
|
+
- goodguide-accounts.gemspec
|
52
|
+
- lib/goodguide/accounts/issue_preferences.rb
|
53
|
+
- lib/goodguide/accounts/base.rb
|
54
|
+
- lib/goodguide/accounts/profile.rb
|
55
|
+
- lib/goodguide/accounts/version.rb
|
56
|
+
- lib/goodguide/accounts.rb
|
57
|
+
- lib/oauth2_error.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://www.goodguide.com
|
60
|
+
licenses: []
|
61
|
+
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: "0"
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: "0"
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project: goodguide
|
82
|
+
rubygems_version: 1.5.2
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: GoodGuide Accounts API gem
|
86
|
+
test_files: []
|
87
|
+
|