WIP facebook friends widget
[shapado:cantonics-shapado.git] / lib / multiauth_support.rb
1 module MultiauthSupport
2   extend ActiveSupport::Concern
3
4   included do
5     field :using_openid, :type => Boolean, :default => false
6     field :openid_email
7
8     field :twitter_handle, :type => String
9     field :twitter_oauth_token, :type => String
10     field :twitter_oauth_secret, :type => String
11
12     field :facebook_id,               :type => String
13     field :facebook_token,            :type => String
14     field :facebook_profile,          :type => String
15
16     field :twitter_token,             :type => String
17     field :twitter_secret,            :type => String
18     field :twitter_login,             :type => String
19
20
21     field :github_id, :type => String
22     field :github_login, :type => String
23
24     field :auth_keys, :type => Array, :default => []
25     field :user_info, :type => Hash, :default => {}
26   end
27
28   module ClassMethods
29     def authenticate(fields)
30       puts "FIELDS #{fields.inspect}"
31
32       provider = fields["provider"]
33
34       if fields["uid"] =~ %r{google\.com/accounts/o8/} && fields["user_info"]["email"]
35         fields["uid"] = "http://google_id_#{fields["user_info"]["email"]}" # normalize for subdomains
36       end
37
38       auth_key = "#{provider}_#{fields["uid"]}"
39
40       user = User.where({:auth_keys => auth_key}).first
41       if user.nil?
42         user = User.new(:auth_keys => [auth_key])
43
44         puts ">>>>>>> #{provider} #{fields["user_info"].inspect}"
45
46         user.user_info[provider] = fields["user_info"]
47
48         if user.email.blank?
49           user.email = user.user_info[provider]["email"]
50         end
51
52         user.send("handle_#{provider}", fields) if user.respond_to?("handle_#{provider}", true)
53
54         if user.login.blank?
55           if user.email.blank?
56             user.login = user.user_info[provider]["nickname"] || user.user_info[provider]["login"] || user.user_info[provider]["name"] || "#{provider}_#{rand(100)}#{rand(100)}#{rand(100)}"
57           else
58             user.login = user.email.split("@").first.downcase.gsub(".","")
59           end
60         end
61
62         if !user.valid? && !user.errors.on(:login).empty?
63           user.login = user.login + "_#{rand(100)}#{rand(100)}#{rand(100)}"
64         end
65
66         return false if !user.save
67       end
68
69       user
70     end
71   end # ClassMethods
72
73   module InstanceMethods
74     def connect(fields)
75       provider = fields["provider"]
76       if fields["uid"] =~ %r{google\.com/accounts/o8/} && fields["user_info"]["email"]
77         fields["uid"] = "http://google_id_#{fields["user_info"]["email"]}" # normalize for subdomains
78       end
79
80       auth_key = "#{provider}_#{fields["uid"]}"
81       user = User.only(:id).where({:auth_keys => auth_key}).first
82       if user.present? && user.id != self.id
83         self.push(:"user_info.#{provider}" => fields["user_info"])
84
85         user.destroy if merge_user(user)
86       end
87
88       user.send("handle_#{provider}", fields) if user.respond_to?("handle_#{provider}", true)
89
90       self.push_uniq(:auth_keys => auth_key)
91     end
92
93     def merge_user(user)
94       [Question, Answer, Badge, UserStat].each do |m|
95         m.override({:user_id => user.id}, {:user_id => self.id})
96       end
97       user
98     end
99
100     def password_required?
101       return false if self[:using_openid] || self[:facebook_id].present? || self[:github_id].present?
102
103       (encrypted_password.blank? || !password.blank?)
104     end
105
106     def twitter_client
107       if self.twitter_secret.present? && self.twitter_token.present? && (config = Multiauth.providers["Twitter"])
108         TwitterOAuth::Client.new(
109           :consumer_key => config["id"],
110           :consumer_secret => config["token"],
111           :token => self.twitter_token,
112           :secret => self.twitter_secret
113         )
114       end
115     end
116
117     def facebook_client(property = 'friends')
118       response = open(URI.encode("https://graph.facebook.com/#{self.facebook_id}/#{property}?access_token=#{self.facebook_token}")).read
119       JSON.parse(response)
120     end
121
122     private
123     # {"provider"=>"facebook", "uid"=>"4332432432432", "credentials"=>{"token"=>"432432432432432"},
124     # "user_info"=>{"nickname"=>"profile.php?id=4332432432432", "first_name"=>"My", "last_name"=>"Name", "name"=>"My Name", "urls"=>{"Facebook"=>"http://www.facebook.com/profile.php?id=4332432432432", "Website"=>nil}},
125     # "extra"=>{"user_hash"=>{"id"=>"4332432432432", "name"=>"My Name", "first_name"=>"My", "last_name"=>"Name", "link"=>"http://www.facebook.com/profile.php?id=4332432432432", "birthday"=>"06/15/1980", "gender"=>"male", "email"=>"my email", "timezone"=>-5, "locale"=>"en_US", "updated_time"=>"2010-04-01T07:27:28+0000"}}}
126     def handle_facebook(fields)
127       uinfo = fields["extra"]["user_hash"]
128       self.facebook_id = fields["uid"]
129       self.facebook_token = fields["credentials"]["token"]
130       self.facebook_profile = fields["user_info"]["urls"]["Facebook"]
131
132       if self.email.blank?
133         self.email = uinfo["email"]
134       end
135     end
136
137     # {"provider"=>"twitter", "uid"=>"user id", "credentials"=>{"token"=>"token", "secret"=>"secret"},
138     # "extra"=>{"access_token"=>token_object, "user_hash"=>{"description"=>"desc", "screen_name"=>"nick", "geo_enabled"=>false, "profile_sidebar_border_color"=>"87bc44", "status"=>{}}},
139     # "user_info"=>{"nickname"=>"nick", "name"=>"My Name", "location"=>"Here", "image"=>"http://a0.twimg.com/profile_images/path.png", "description"=>"desc", "urls"=>{"Website"=>nil}}}
140     def handle_twitter(fields)
141       self.twitter_token = fields["credentials"]["token"]
142       self.twitter_secret = fields["credentials"]["secret"]
143       self.twitter_login = fields["user_info"]["nickname"]
144
145       self.login.blank? && self.login = fields["user_info"]["nickname"]
146     end
147   end # InstanceMethods
148 end