simple_facebook_connect 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/MIT-LICENSE +20 -0
- data/README.md +115 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/app/controllers/simple_facebook_connect/connect_controller.rb +59 -0
- data/app/views/shared/_facebook_connect_button.html.erb +15 -0
- data/config/simple_facebook_connect_routes.rb +4 -0
- data/generators/simple_facebook_connect_features/simple_facebook_connect_features_generator.rb +14 -0
- data/generators/simple_facebook_connect_features/templates/facebook_auth_getsession.xml +9 -0
- data/generators/simple_facebook_connect_features/templates/facebook_connect.feature +27 -0
- data/generators/simple_facebook_connect_features/templates/facebook_connect_steps.rb +19 -0
- data/generators/simple_facebook_connect_features/templates/facebook_connect_stubs.rb +43 -0
- data/generators/simple_facebook_connect_features/templates/facebook_users_getinfo.xml +119 -0
- data/generators/simple_facebook_connect_migration/simple_facebook_connect_migration_generator.rb +13 -0
- data/generators/simple_facebook_connect_migration/templates/migration.rb +17 -0
- data/init.rb +35 -0
- data/lib/simple_facebook_connect/controller_extension.rb +11 -0
- data/lib/simple_facebook_connect/extensions/routes.rb +13 -0
- data/lib/simple_facebook_connect/parser.rb +163 -0
- data/lib/simple_facebook_connect/service.rb +34 -0
- data/lib/simple_facebook_connect/session.rb +73 -0
- data/lib/simple_facebook_connect/user.rb +28 -0
- data/lib/simple_facebook_connect/user_extension.rb +21 -0
- data/lib/simple_facebook_connect.rb +14 -0
- data/rails/init.rb +1 -0
- data/simple_facebook_connect.gemspec +71 -0
- data/spec/fixtures/facebook.auth.getSession/default.xml +9 -0
- data/spec/fixtures/facebook.users.getInfo/default.xml +119 -0
- data/spec/lib/simple_facebook_connect/parser_spec.rb +12 -0
- data/spec/lib/simple_facebook_connect/user_extension_spec.rb +16 -0
- data/spec/lib/simple_facebook_connect/user_spec.rb +37 -0
- data/spec/spec_helper.rb +30 -0
- metadata +91 -0
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
|
3
|
+
module SimpleFacebookConnect
|
4
|
+
|
5
|
+
class FacebookApiError < StandardError; end
|
6
|
+
|
7
|
+
class Parser
|
8
|
+
|
9
|
+
module REXMLElementExtensions
|
10
|
+
def text_value
|
11
|
+
self.children.first.to_s.strip
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
::REXML::Element.__send__(:include, REXMLElementExtensions)
|
16
|
+
|
17
|
+
def self.parse(method, data)
|
18
|
+
Errors.process(data)
|
19
|
+
parser = PARSERS[method]
|
20
|
+
parser.process(
|
21
|
+
data
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.array_of(response_element, element_name)
|
26
|
+
values_to_return = []
|
27
|
+
response_element.elements.each(element_name) do |element|
|
28
|
+
values_to_return << yield(element)
|
29
|
+
end
|
30
|
+
values_to_return
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.array_of_text_values(response_element, element_name)
|
34
|
+
array_of(response_element, element_name) do |element|
|
35
|
+
element.text_value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.array_of_hashes(response_element, element_name)
|
40
|
+
array_of(response_element, element_name) do |element|
|
41
|
+
hashinate(element)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.element(name, data)
|
46
|
+
data = data.body rescue data # either data or an HTTP response
|
47
|
+
doc = REXML::Document.new(data)
|
48
|
+
doc.elements.each(name) do |element|
|
49
|
+
return element
|
50
|
+
end
|
51
|
+
raise "Element #{name} not found in #{data}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.hash_or_value_for(element)
|
55
|
+
if element.children.size == 1 && element.children.first.kind_of?(REXML::Text)
|
56
|
+
element.text_value
|
57
|
+
else
|
58
|
+
hashinate(element)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.hashinate(response_element)
|
63
|
+
response_element.children.reject{|c| c.kind_of? REXML::Text}.inject({}) do |hash, child|
|
64
|
+
# If the node hasn't any child, and is not a list, we want empty strings, not empty hashes,
|
65
|
+
# except if attributes['nil'] == true
|
66
|
+
hash[child.name] =
|
67
|
+
if (child.attributes['nil'] == 'true')
|
68
|
+
nil
|
69
|
+
elsif (child.children.size == 1 && child.children.first.kind_of?(REXML::Text)) || (child.children.size == 0 && child.attributes['list'] != 'true')
|
70
|
+
anonymous_field_from(child, hash) || child.text_value
|
71
|
+
elsif child.attributes['list'] == 'true'
|
72
|
+
child.children.reject{|c| c.kind_of? REXML::Text}.map { |subchild| hash_or_value_for(subchild)}
|
73
|
+
else
|
74
|
+
child.children.reject{|c| c.kind_of? REXML::Text}.inject({}) do |subhash, subchild|
|
75
|
+
subhash[subchild.name] = hash_or_value_for(subchild)
|
76
|
+
subhash
|
77
|
+
end
|
78
|
+
end #if (child.attributes)
|
79
|
+
hash
|
80
|
+
end #do |hash, child|
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.booleanize(response)
|
84
|
+
response == "1" ? true : false
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.anonymous_field_from(child, hash)
|
88
|
+
if child.name == 'anon'
|
89
|
+
(hash[child.name] || []) << child.text_value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class RevokeAuthorization < self
|
94
|
+
def self.process(data)
|
95
|
+
booleanize(data)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class CreateToken < self
|
100
|
+
def self.process(data)
|
101
|
+
element('auth_createToken_response', data).text_value
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
class RegisterUsers < self
|
106
|
+
def self.process(data)
|
107
|
+
array_of_text_values(element("connect_registerUsers_response", data), "connect_registerUsers_response_elt")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class GetSession < self
|
112
|
+
def self.process(data)
|
113
|
+
hashinate(element('auth_getSession_response', data))
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class UserInfo < self
|
118
|
+
def self.process(data)
|
119
|
+
array_of_hashes(element('users_getInfo_response', data), 'user')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
class UserStandardInfo < self
|
124
|
+
def self.process(data)
|
125
|
+
array_of_hashes(element('users_getStandardInfo_response', data), 'standard_user_info')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class GetLoggedInUser < self
|
130
|
+
def self.process(data)
|
131
|
+
Integer(element('users_getLoggedInUser_response', data).text_value)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class ProfileInfo < self
|
136
|
+
def self.process(data)
|
137
|
+
hashinate(element('profile_getInfo_response info_fields', data))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class Errors < self
|
142
|
+
def self.process(data)
|
143
|
+
response_element = element('error_response', data) rescue nil
|
144
|
+
if response_element
|
145
|
+
hash = hashinate(response_element)
|
146
|
+
raise FacebookApiError, hash['error_msg']
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
PARSERS = {
|
153
|
+
'facebook.auth.revokeAuthorization' => RevokeAuthorization,
|
154
|
+
'facebook.auth.createToken' => CreateToken,
|
155
|
+
'facebook.auth.getSession' => GetSession,
|
156
|
+
'facebook.connect.registerUsers' => RegisterUsers,
|
157
|
+
'facebook.users.getInfo' => UserInfo,
|
158
|
+
'facebook.users.getStandardInfo' => UserStandardInfo,
|
159
|
+
'facebook.profile.getInfo' => ProfileInfo
|
160
|
+
}
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module SimpleFacebookConnect
|
4
|
+
|
5
|
+
class Service
|
6
|
+
def initialize(api_base, api_path, api_key)
|
7
|
+
@api_base = api_base
|
8
|
+
@api_path = api_path
|
9
|
+
@api_key = api_key
|
10
|
+
end
|
11
|
+
|
12
|
+
def post(params)
|
13
|
+
attempt = 0
|
14
|
+
Parser.parse(params[:method], post_form(url,params) )
|
15
|
+
rescue Errno::ECONNRESET, EOFError
|
16
|
+
if attempt == 0
|
17
|
+
attempt += 1
|
18
|
+
retry
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def post_form(url,params)
|
23
|
+
Net::HTTP.post_form(url, params.stringify_keys)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def url(base = nil)
|
28
|
+
base ||= @api_base
|
29
|
+
URI.parse('http://'+ base + @api_path)
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module SimpleFacebookConnect
|
2
|
+
|
3
|
+
class Session
|
4
|
+
API_SERVER_BASE_URL = "api.facebook.com"
|
5
|
+
API_PATH_REST = "/restserver.php"
|
6
|
+
WWW_SERVER_BASE_URL = "www.facebook.com"
|
7
|
+
WWW_PATH_LOGIN = "/login.php"
|
8
|
+
|
9
|
+
attr_accessor :auth_token
|
10
|
+
attr_reader :session_key
|
11
|
+
|
12
|
+
|
13
|
+
def initialize(api_key, secret_key)
|
14
|
+
@api_key = api_key
|
15
|
+
@secret_key = secret_key
|
16
|
+
@session_key = nil
|
17
|
+
@uid = nil
|
18
|
+
@auth_token = nil
|
19
|
+
@secret_from_session = nil
|
20
|
+
@expires = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def login_url(options={})
|
24
|
+
"http://#{WWW_SERVER_BASE_URL}#{WWW_PATH_LOGIN}?api_key=#{@api_key}&v=1.0"
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def secure!
|
29
|
+
response = post 'facebook.auth.getSession', :auth_token => auth_token
|
30
|
+
@session_key = response['session_key']
|
31
|
+
@uid = response['uid'].to_i
|
32
|
+
@expires = response['expires'].to_i
|
33
|
+
@secret_from_session = response['secret']
|
34
|
+
end
|
35
|
+
|
36
|
+
def user
|
37
|
+
@user ||= User.new(uid, self)
|
38
|
+
end
|
39
|
+
|
40
|
+
def post(method, params = {}, use_session_key = true, &proc)
|
41
|
+
add_facebook_params(params, method)
|
42
|
+
use_session_key && @session_key && params[:session_key] ||= @session_key
|
43
|
+
final_params = params.merge(:sig => signature_for(params))
|
44
|
+
result = service.post(final_params)
|
45
|
+
result = yield result if block_given?
|
46
|
+
result
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def add_facebook_params(hash, method)
|
51
|
+
hash[:method] = method
|
52
|
+
hash[:api_key] = @api_key
|
53
|
+
hash[:call_id] = Time.now.to_f.to_s unless method == 'facebook.auth.getSession'
|
54
|
+
hash[:v] = "1.0"
|
55
|
+
end
|
56
|
+
|
57
|
+
def service
|
58
|
+
@service ||= Service.new(API_SERVER_BASE_URL, API_PATH_REST, @api_key)
|
59
|
+
end
|
60
|
+
|
61
|
+
def uid
|
62
|
+
@uid || (secure!; @uid)
|
63
|
+
end
|
64
|
+
|
65
|
+
def signature_for(params)
|
66
|
+
raw_string = params.inject([]) do |collection, pair|
|
67
|
+
collection << pair.join("=")
|
68
|
+
collection
|
69
|
+
end.sort.join
|
70
|
+
Digest::MD5.hexdigest([raw_string, @secret_key].join)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module SimpleFacebookConnect
|
2
|
+
|
3
|
+
class User
|
4
|
+
|
5
|
+
FIELDS = [:uid, :hometown_location, :first_name, :last_name, :current_location, :pic, :locale, :email_hashes, :about_me, :interests]
|
6
|
+
attr_reader(*FIELDS)
|
7
|
+
attr_reader :session
|
8
|
+
|
9
|
+
def initialize(uid, session)
|
10
|
+
@uid = uid
|
11
|
+
@session = session
|
12
|
+
populate
|
13
|
+
end
|
14
|
+
|
15
|
+
def populate
|
16
|
+
@session.post('facebook.users.getInfo', :fields => coma_seperated_fields, :uids => uid) do |response|
|
17
|
+
FIELDS.each do |field|
|
18
|
+
instance_variable_set(:"@#{field}", response.first[field.to_s])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def coma_seperated_fields
|
24
|
+
FIELDS.join(',')
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
require 'digest/md5'
|
3
|
+
|
4
|
+
module SimpleFacebookConnect
|
5
|
+
module UserExtension
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.class_eval do
|
9
|
+
before_save :build_email_hash, :if => :email_changed?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def build_email_hash
|
16
|
+
str = email.strip.downcase
|
17
|
+
self.email_hash = "#{Zlib.crc32(str)}_#{Digest::MD5.hexdigest(str)}"
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'simple_facebook_connect/parser'
|
4
|
+
require 'simple_facebook_connect/service'
|
5
|
+
require 'simple_facebook_connect/session'
|
6
|
+
require 'simple_facebook_connect/user'
|
7
|
+
require 'simple_facebook_connect/user_extension'
|
8
|
+
require 'simple_facebook_connect/controller_extension'
|
9
|
+
|
10
|
+
module SimpleFacebookConnect
|
11
|
+
class << self
|
12
|
+
attr_accessor :api_key, :secret_key
|
13
|
+
end
|
14
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../init'
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{simple_facebook_connect}
|
5
|
+
s.version = "0.0.5"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Alexander Lang", "Frank Pr\303\266\303\237dorf"]
|
9
|
+
s.date = %q{2009-07-22}
|
10
|
+
s.email = %q{alex@upstream-berlin.com}
|
11
|
+
s.extra_rdoc_files = [
|
12
|
+
"README.md"
|
13
|
+
]
|
14
|
+
s.files = [
|
15
|
+
".gitignore",
|
16
|
+
"MIT-LICENSE",
|
17
|
+
"README.md",
|
18
|
+
"Rakefile",
|
19
|
+
"VERSION",
|
20
|
+
"app/controllers/simple_facebook_connect/connect_controller.rb",
|
21
|
+
"app/views/shared/_facebook_connect_button.html.erb",
|
22
|
+
"config/simple_facebook_connect_routes.rb",
|
23
|
+
"generators/simple_facebook_connect_features/simple_facebook_connect_features_generator.rb",
|
24
|
+
"generators/simple_facebook_connect_features/templates/facebook_auth_getsession.xml",
|
25
|
+
"generators/simple_facebook_connect_features/templates/facebook_connect.feature",
|
26
|
+
"generators/simple_facebook_connect_features/templates/facebook_connect_steps.rb",
|
27
|
+
"generators/simple_facebook_connect_features/templates/facebook_connect_stubs.rb",
|
28
|
+
"generators/simple_facebook_connect_features/templates/facebook_users_getinfo.xml",
|
29
|
+
"generators/simple_facebook_connect_migration/simple_facebook_connect_migration_generator.rb",
|
30
|
+
"generators/simple_facebook_connect_migration/templates/migration.rb",
|
31
|
+
"init.rb",
|
32
|
+
"lib/simple_facebook_connect.rb",
|
33
|
+
"lib/simple_facebook_connect/controller_extension.rb",
|
34
|
+
"lib/simple_facebook_connect/extensions/routes.rb",
|
35
|
+
"lib/simple_facebook_connect/parser.rb",
|
36
|
+
"lib/simple_facebook_connect/service.rb",
|
37
|
+
"lib/simple_facebook_connect/session.rb",
|
38
|
+
"lib/simple_facebook_connect/user.rb",
|
39
|
+
"lib/simple_facebook_connect/user_extension.rb",
|
40
|
+
"rails/init.rb",
|
41
|
+
"simple_facebook_connect.gemspec",
|
42
|
+
"spec/fixtures/facebook.auth.getSession/default.xml",
|
43
|
+
"spec/fixtures/facebook.users.getInfo/default.xml",
|
44
|
+
"spec/lib/simple_facebook_connect/parser_spec.rb",
|
45
|
+
"spec/lib/simple_facebook_connect/user_extension_spec.rb",
|
46
|
+
"spec/lib/simple_facebook_connect/user_spec.rb",
|
47
|
+
"spec/spec_helper.rb"
|
48
|
+
]
|
49
|
+
s.has_rdoc = true
|
50
|
+
s.homepage = %q{http://github.com/upstream/simple_facebook_connect}
|
51
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
52
|
+
s.require_paths = ["lib"]
|
53
|
+
s.rubygems_version = %q{1.3.1}
|
54
|
+
s.summary = %q{This plugin adds the ability to sign in/sign up using facebook connect to your Rails application.}
|
55
|
+
s.test_files = [
|
56
|
+
"spec/lib/simple_facebook_connect/parser_spec.rb",
|
57
|
+
"spec/lib/simple_facebook_connect/user_extension_spec.rb",
|
58
|
+
"spec/lib/simple_facebook_connect/user_spec.rb",
|
59
|
+
"spec/spec_helper.rb"
|
60
|
+
]
|
61
|
+
|
62
|
+
if s.respond_to? :specification_version then
|
63
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
64
|
+
s.specification_version = 2
|
65
|
+
|
66
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
67
|
+
else
|
68
|
+
end
|
69
|
+
else
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<auth_getSession_response
|
3
|
+
xmlns="http://api.facebook.com/1.0/"
|
4
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
5
|
+
xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">
|
6
|
+
<session_key>5f34e11bfb97c762e439e6a5-8055</session_key>
|
7
|
+
<uid>8055</uid>
|
8
|
+
<expires>1173309298</expires>
|
9
|
+
</auth_getSession_response>
|
@@ -0,0 +1,119 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<users_getInfo_response xmlns="http://api.facebook.com/1.0/"
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
4
|
+
xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd" list="true">
|
5
|
+
<user>
|
6
|
+
<uid>8055</uid>
|
7
|
+
<about_me>This field perpetuates the glorification of the ego. Also, it has a character limit.</about_me>
|
8
|
+
<activities>Here: facebook, etc. There: Glee Club, a capella, teaching.</activities>
|
9
|
+
<affiliations list="true">
|
10
|
+
<affiliation>
|
11
|
+
<nid>50453093</nid>
|
12
|
+
<name>Facebook Developers</name>
|
13
|
+
<type>work</type>
|
14
|
+
<status/>
|
15
|
+
<year/>
|
16
|
+
</affiliation>
|
17
|
+
</affiliations>
|
18
|
+
<birthday>November 3</birthday>
|
19
|
+
<books>The Brothers K, GEB, Ken Wilber, Zen and the Art, Fitzgerald, The Emporer's New Mind, The Wonderful Story of Henry Sugar</books>
|
20
|
+
<current_location>
|
21
|
+
<city>Palo Alto</city>
|
22
|
+
<state>California</state>
|
23
|
+
<country>United States</country>
|
24
|
+
<zip>94303</zip>
|
25
|
+
</current_location>
|
26
|
+
<education_history list="true">
|
27
|
+
<education_info>
|
28
|
+
<name>Harvard</name>
|
29
|
+
<year>2003</year>
|
30
|
+
<concentrations list="true">
|
31
|
+
<concentration>Applied Mathematics</concentration>
|
32
|
+
<concentration>Computer Science</concentration>
|
33
|
+
</concentrations>
|
34
|
+
</education_info>
|
35
|
+
</education_history>
|
36
|
+
<email_hashes list="true">
|
37
|
+
<email_hash_elt>2781152470_9f9c29692798573d8c76eaaf053a1911</email_hash_elt>
|
38
|
+
</email_hashes>
|
39
|
+
<family list="true">
|
40
|
+
<family_elt list="true">
|
41
|
+
<family_elt_elt>mother</family_elt_elt>
|
42
|
+
<family_elt_elt>1394244902</family_elt_elt>
|
43
|
+
</family_elt>
|
44
|
+
<family_elt list="true">
|
45
|
+
<family_elt_elt>sister</family_elt_elt>
|
46
|
+
<family_elt_elt>48703107</family_elt_elt>
|
47
|
+
</family_elt>
|
48
|
+
<family_elt list="true">
|
49
|
+
<family_elt_elt>brother</family_elt_elt>
|
50
|
+
<family_elt_elt>1078767258</family_elt_elt>
|
51
|
+
</family_elt>
|
52
|
+
<family_elt list="true">
|
53
|
+
<family_elt_elt>brother</family_elt_elt>
|
54
|
+
<family_elt_elt>John Doe</family_elt_elt>
|
55
|
+
<family_elt_elt/>
|
56
|
+
</family_elt>
|
57
|
+
</family>
|
58
|
+
<first_name>Dave</first_name>
|
59
|
+
<hometown_location>
|
60
|
+
<city>York</city>
|
61
|
+
<state>Pennsylvania</state>
|
62
|
+
<country>United States</country>
|
63
|
+
</hometown_location>
|
64
|
+
<hs_info>
|
65
|
+
<hs1_name>Central York High School</hs1_name>
|
66
|
+
<hs2_name/>
|
67
|
+
<grad_year>1999</grad_year>
|
68
|
+
<hs1_id>21846</hs1_id>
|
69
|
+
<hs2_id>0</hs2_id>
|
70
|
+
</hs_info>
|
71
|
+
<is_app_user>1</is_app_user>
|
72
|
+
<has_added_app>1</has_added_app>
|
73
|
+
<interests>coffee, computers, the funny, architecture, code breaking,snowboarding, philosophy, soccer, talking to strangers</interests>
|
74
|
+
<last_name>Fetterman</last_name>
|
75
|
+
<locale>en_US</locale>
|
76
|
+
<meeting_for list="true">
|
77
|
+
<seeking>Friendship</seeking>
|
78
|
+
</meeting_for>
|
79
|
+
<meeting_sex list="true">
|
80
|
+
<sex>female</sex>
|
81
|
+
</meeting_sex>
|
82
|
+
<movies>Tommy Boy, Billy Madison, Fight Club, Dirty Work, Meet the Parents, My Blue Heaven, Office Space </movies>
|
83
|
+
<music>New Found Glory, Daft Punk, Weezer, The Crystal Method, Rage, the KLF, Green Day, Live, Coldplay, Panic at the Disco, Family Force 5</music>
|
84
|
+
<name>Dave Fetterman</name>
|
85
|
+
<notes_count>0</notes_count>
|
86
|
+
<pic>http://photos-055.facebook.com/ip007/profile3/1271/65/s8055_39735.jpg</pic>
|
87
|
+
<pic_big>http://photos-055.facebook.com/ip007/profile3/1271/65/n8055_39735.jpg</pic_big>
|
88
|
+
<pic_small>http://photos-055.facebook.com/ip007/profile3/1271/65/t8055_39735.jpg</pic_small>
|
89
|
+
<pic_square>http://photos-055.facebook.com/ip007/profile3/1271/65/q8055_39735.jpg</pic_square>
|
90
|
+
<political>Moderate</political>
|
91
|
+
<profile_update_time>1170414620</profile_update_time>
|
92
|
+
<quotes/>
|
93
|
+
<relationship_status>In a Relationship</relationship_status>
|
94
|
+
<religion/>
|
95
|
+
<sex>male</sex>
|
96
|
+
<significant_other_id xsi:nil="true"/>
|
97
|
+
<status>
|
98
|
+
<message>Fast Company, November issue, page 84</message>
|
99
|
+
<time>1193075616</time>
|
100
|
+
</status>
|
101
|
+
<timezone>-8</timezone>
|
102
|
+
<tv>cf. Bob Trahan</tv>
|
103
|
+
<wall_count>121</wall_count>
|
104
|
+
<work_history list="true">
|
105
|
+
<work_info>
|
106
|
+
<location>
|
107
|
+
<city>Palo Alto</city>
|
108
|
+
<state>CA</state>
|
109
|
+
<country>United States</country>
|
110
|
+
</location>
|
111
|
+
<company_name>Facebook</company_name>
|
112
|
+
<position>Software Engineer</position>
|
113
|
+
<description>Tech Lead, Facebook Platform</description>
|
114
|
+
<start_date>2006-01</start_date>
|
115
|
+
<end_date/>
|
116
|
+
</work_info>
|
117
|
+
</work_history>
|
118
|
+
</user>
|
119
|
+
</users_getInfo_response>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe SimpleFacebookConnect::Parser, 'parse' do
|
4
|
+
it "should parse getInfo xml response" do
|
5
|
+
result = SimpleFacebookConnect::Parser.parse('facebook.users.getInfo', File.read(File.dirname(__FILE__) + '/../../fixtures/facebook.users.getInfo/default.xml'))
|
6
|
+
result.should == parsed_array
|
7
|
+
end
|
8
|
+
|
9
|
+
def parsed_array
|
10
|
+
[{"uid"=>"8055", "about_me"=>"This field perpetuates the glorification of the ego. Also, it has a character limit.", "activities"=>"Here: facebook, etc. There: Glee Club, a capella, teaching.", "affiliations"=>[{"nid"=>"50453093", "name"=>"Facebook Developers", "type"=>"work", "status"=>"", "year"=>""}], "birthday"=>"November 3", "books"=>"The Brothers K, GEB, Ken Wilber, Zen and the Art, Fitzgerald, The Emporer's New Mind, The Wonderful Story of Henry Sugar", "current_location"=>{"city"=>"Palo Alto", "state"=>"California", "country"=>"United States", "zip"=>"94303"}, "education_history"=>[{"name"=>"Harvard", "year"=>"2003", "concentrations"=>["Applied Mathematics", "Computer Science"]}], "email_hashes"=>["2781152470_9f9c29692798573d8c76eaaf053a1911"], "family"=>[{"family_elt_elt"=>"1394244902"}, {"family_elt_elt"=>"48703107"}, {"family_elt_elt"=>"1078767258"}, {"family_elt_elt"=>""}], "first_name"=>"Dave", "hometown_location"=>{"city"=>"York", "state"=>"Pennsylvania", "country"=>"United States"}, "hs_info"=>{"hs1_name"=>"Central York High School", "hs2_name"=>{}, "grad_year"=>"1999", "hs1_id"=>"21846", "hs2_id"=>"0"}, "is_app_user"=>"1", "has_added_app"=>"1", "interests"=>"coffee, computers, the funny, architecture, code breaking,snowboarding, philosophy, soccer, talking to strangers", "last_name"=>"Fetterman", "locale"=>"en_US", "meeting_for"=>["Friendship"], "meeting_sex"=>["female"], "movies"=>"Tommy Boy, Billy Madison, Fight Club, Dirty Work, Meet the Parents, My Blue Heaven, Office Space", "music"=>"New Found Glory, Daft Punk, Weezer, The Crystal Method, Rage, the KLF, Green Day, Live, Coldplay, Panic at the Disco, Family Force 5", "name"=>"Dave Fetterman", "notes_count"=>"0", "pic"=>"http://photos-055.facebook.com/ip007/profile3/1271/65/s8055_39735.jpg", "pic_big"=>"http://photos-055.facebook.com/ip007/profile3/1271/65/n8055_39735.jpg", "pic_small"=>"http://photos-055.facebook.com/ip007/profile3/1271/65/t8055_39735.jpg", "pic_square"=>"http://photos-055.facebook.com/ip007/profile3/1271/65/q8055_39735.jpg", "political"=>"Moderate", "profile_update_time"=>"1170414620", "quotes"=>"", "relationship_status"=>"In a Relationship", "religion"=>"", "sex"=>"male", "significant_other_id"=>nil, "status"=>{"message"=>"Fast Company, November issue, page 84", "time"=>"1193075616"}, "timezone"=>"-8", "tv"=>"cf. Bob Trahan", "wall_count"=>"121", "work_history"=>[{"location"=>{"city"=>"Palo Alto", "state"=>"CA", "country"=>"United States"}, "company_name"=>"Facebook", "position"=>"Software Engineer", "description"=>"Tech Lead, Facebook Platform", "start_date"=>"2006-01", "end_date"=>""}]}]
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe SimpleFacebookConnect::UserExtension, 'email=' do
|
4
|
+
class User < ActiveRecord::Base
|
5
|
+
include SimpleFacebookConnect::UserExtension
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should set the email hash" do
|
10
|
+
user = User.new
|
11
|
+
user.email = 'joe@doe.com'
|
12
|
+
user.save!
|
13
|
+
user.email_hash.should == '3404385302_68ef883c573edb5d26365e8f20156eec'
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe SimpleFacebookConnect::User, 'initialize' do
|
4
|
+
before(:each) do
|
5
|
+
@session = stub 'session', :post => nil
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should send a remote call to facebook" do
|
9
|
+
@session.should_receive(:post).with('facebook.users.getInfo', :fields => 'uid,hometown_location,first_name,last_name,current_location,pic,locale,email_hashes,about_me,interests', :uids => 8055)
|
10
|
+
SimpleFacebookConnect::User.new(8055, @session)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should populate the user attributes" do
|
14
|
+
@session.stub!(:post).and_yield(user_info_response)
|
15
|
+
user = SimpleFacebookConnect::User.new(8055, @session)
|
16
|
+
user.email_hashes.should == ["2781152470_9f9c29692798573d8c76eaaf053a1911"]
|
17
|
+
user.uid.should == '8055'
|
18
|
+
user.hometown_location.should == {"city"=>"York", "state"=>"Pennsylvania", "country"=>"United States"}
|
19
|
+
user.first_name.should == 'Dave'
|
20
|
+
user.last_name.should == 'Fetterman'
|
21
|
+
user.current_location.should == {"city"=>"Palo Alto", "state"=>"California", "country"=>"United States", "zip"=>"94303"}
|
22
|
+
user.pic.should == 'http://photos-055.facebook.com/ip007/profile3/1271/65/s8055_39735.jpg'
|
23
|
+
user.locale.should == 'en_US'
|
24
|
+
user.about_me.should == 'This field perpetuates the glorification of the ego. Also, it has a character limit.'
|
25
|
+
user.interests.should == 'snowboarding, philosophy, soccer, talking to strangers'
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should expose the session" do
|
29
|
+
user = SimpleFacebookConnect::User.new(8055, @session)
|
30
|
+
user.session.should == @session
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def user_info_response
|
35
|
+
[{"uid"=>"8055", "about_me"=>"This field perpetuates the glorification of the ego. Also, it has a character limit.", "activities"=>"Here: facebook, etc. There: Glee Club, a capella, teaching.", "affiliations"=>[{"nid"=>"50453093", "name"=>"Facebook Developers", "type"=>"work", "status"=>"", "year"=>""}], "birthday"=>"November 3", "books"=>"The Brothers K, GEB, Ken Wilber, Zen and the Art, Fitzgerald, The Emporer's New Mind, The Wonderful Story of Henry Sugar", "current_location"=>{"city"=>"Palo Alto", "state"=>"California", "country"=>"United States", "zip"=>"94303"}, "education_history"=>[{"name"=>"Harvard", "year"=>"2003", "concentrations"=>["Applied Mathematics", "Computer Science"]}], "email_hashes"=>["2781152470_9f9c29692798573d8c76eaaf053a1911"], "family"=>[{"family_elt_elt"=>"1394244902"}, {"family_elt_elt"=>"48703107"}, {"family_elt_elt"=>"1078767258"}, {"family_elt_elt"=>""}], "first_name"=>"Dave", "hometown_location"=>{"city"=>"York", "state"=>"Pennsylvania", "country"=>"United States"}, "hs_info"=>{"hs1_name"=>"Central York High School", "hs2_name"=>{}, "grad_year"=>"1999", "hs1_id"=>"21846", "hs2_id"=>"0"}, "is_app_user"=>"1", "has_added_app"=>"1", "interests"=>"snowboarding, philosophy, soccer, talking to strangers", "last_name"=>"Fetterman", "locale"=>"en_US", "meeting_for"=>["Friendship"], "meeting_sex"=>["female"], "movies"=>"Tommy Boy, Billy Madison, Fight Club, Dirty Work, Meet the Parents, My Blue Heaven, Office Space", "music"=>"New Found Glory, Daft Punk, Weezer, The Crystal Method, Rage, the KLF, Green Day, Live, Coldplay, Panic at the Disco, Family Force 5", "name"=>"Dave Fetterman", "notes_count"=>"0", "pic"=>"http://photos-055.facebook.com/ip007/profile3/1271/65/s8055_39735.jpg", "pic_big"=>"http://photos-055.facebook.com/ip007/profile3/1271/65/n8055_39735.jpg", "pic_small"=>"http://photos-055.facebook.com/ip007/profile3/1271/65/t8055_39735.jpg", "pic_square"=>"http://photos-055.facebook.com/ip007/profile3/1271/65/q8055_39735.jpg", "political"=>"Moderate", "profile_update_time"=>"1170414620", "quotes"=>"", "relationship_status"=>"In a Relationship", "religion"=>"", "sex"=>"male", "significant_other_id"=>nil, "status"=>{"message"=>"Fast Company, November issue, page 84", "time"=>"1193075616"}, "timezone"=>"-8", "tv"=>"cf. Bob Trahan", "wall_count"=>"121", "work_history"=>[{"location"=>{"city"=>"Palo Alto", "state"=>"CA", "country"=>"United States"}, "company_name"=>"Facebook", "position"=>"Software Engineer", "description"=>"Tech Lead, Facebook Platform", "start_date"=>"2006-01", "end_date"=>""}]}]
|
36
|
+
end
|
37
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
__DIR__ = File.dirname __FILE__
|
2
|
+
$LOAD_PATH.unshift __DIR__ + '/../lib'
|
3
|
+
|
4
|
+
require 'simple_facebook_connect'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'rubygems'
|
7
|
+
Gem::RubyGemsVersion.inspect # without this the activerecord gem doesn't load on ruby 1.9 #WTF
|
8
|
+
require 'sqlite3'
|
9
|
+
gem 'activerecord'
|
10
|
+
require 'activerecord'
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
FileUtils.rm_rf __DIR__ + '/../test.sqlite3'
|
15
|
+
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => File.join(__DIR__, '..', 'test.sqlite3')
|
16
|
+
|
17
|
+
# migrate
|
18
|
+
|
19
|
+
class CreateUsers < ActiveRecord::Migration
|
20
|
+
def self.up
|
21
|
+
create_table :users do |t|
|
22
|
+
t.string :email
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
require __DIR__ + '/../generators/simple_facebook_connect_migration/templates/migration'
|
28
|
+
|
29
|
+
CreateUsers.up
|
30
|
+
AddFacebookConnect.up
|