simple_facebook_connect 0.0.5

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.
Files changed (34) hide show
  1. data/.gitignore +1 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +115 -0
  4. data/Rakefile +27 -0
  5. data/VERSION +1 -0
  6. data/app/controllers/simple_facebook_connect/connect_controller.rb +59 -0
  7. data/app/views/shared/_facebook_connect_button.html.erb +15 -0
  8. data/config/simple_facebook_connect_routes.rb +4 -0
  9. data/generators/simple_facebook_connect_features/simple_facebook_connect_features_generator.rb +14 -0
  10. data/generators/simple_facebook_connect_features/templates/facebook_auth_getsession.xml +9 -0
  11. data/generators/simple_facebook_connect_features/templates/facebook_connect.feature +27 -0
  12. data/generators/simple_facebook_connect_features/templates/facebook_connect_steps.rb +19 -0
  13. data/generators/simple_facebook_connect_features/templates/facebook_connect_stubs.rb +43 -0
  14. data/generators/simple_facebook_connect_features/templates/facebook_users_getinfo.xml +119 -0
  15. data/generators/simple_facebook_connect_migration/simple_facebook_connect_migration_generator.rb +13 -0
  16. data/generators/simple_facebook_connect_migration/templates/migration.rb +17 -0
  17. data/init.rb +35 -0
  18. data/lib/simple_facebook_connect/controller_extension.rb +11 -0
  19. data/lib/simple_facebook_connect/extensions/routes.rb +13 -0
  20. data/lib/simple_facebook_connect/parser.rb +163 -0
  21. data/lib/simple_facebook_connect/service.rb +34 -0
  22. data/lib/simple_facebook_connect/session.rb +73 -0
  23. data/lib/simple_facebook_connect/user.rb +28 -0
  24. data/lib/simple_facebook_connect/user_extension.rb +21 -0
  25. data/lib/simple_facebook_connect.rb +14 -0
  26. data/rails/init.rb +1 -0
  27. data/simple_facebook_connect.gemspec +71 -0
  28. data/spec/fixtures/facebook.auth.getSession/default.xml +9 -0
  29. data/spec/fixtures/facebook.users.getInfo/default.xml +119 -0
  30. data/spec/lib/simple_facebook_connect/parser_spec.rb +12 -0
  31. data/spec/lib/simple_facebook_connect/user_extension_spec.rb +16 -0
  32. data/spec/lib/simple_facebook_connect/user_spec.rb +37 -0
  33. data/spec/spec_helper.rb +30 -0
  34. 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
@@ -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