Last active
December 13, 2015 18:39
-
-
Save natarius/4957319 to your computer and use it in GitHub Desktop.
Nice little snipped to get your users friends from Facebook/Twitter and merge/autocomplete them. It will also notify the users that their friends signed up via email or whatever you want to implement. It can group does notifications in batches, to create waves of people who know each other and be notified in a short timespan :) Requires a workin…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# encoding: UTF-8 | |
class Friend | |
include Mongoid::Document | |
include Mongoid::Timestamps | |
field :fb_id | |
field :twitter_id, :type => Integer | |
field :email | |
field :twitter_name | |
field :fb_name | |
field :phone | |
field :first_name | |
field :last_name | |
field :profile_picture | |
field :gender | |
field :birthday, :type => Date | |
field :locale | |
field :website | |
field :timezone, :type => Integer, :default => 0 | |
field :twitter_followers, :type => Integer, :default => 0 | |
field :twitter_following, :type => Integer, :default => 0 | |
field :send_signup_notification, :type => Boolean, :default => false | |
belongs_to :user, index: true | |
index fb_id: 1 | |
index twitter_id: 1 | |
index send_signup_notification: 1 | |
index({user_id: 1, twitter_followers: 1}, {background: true}) | |
def self.import_from_twitter(user, friend_ids) | |
Parallel.map(friend_ids, :in_threads=>(Rails.env.production? ? 4 : 0)).each do |friend_id| | |
begin | |
Twitter.oauth_token = user.twitter_token | |
Twitter.oauth_token_secret = user.twitter_secret | |
twitter_user = Twitter.user(friend_id.to_i) | |
new_friend = user.friends.where(:twitter_id => nil, | |
:website => "/(.*#{twitter_user.url}.*|.*#{twitter_user.screen_name}.*)/i").first | |
new_friend = user.friends.where(:twitter_id => nil, | |
:first_name => "/.*#{TwitterHelper.new.get_first_name(twitter_user.name)}.*/i", | |
:last_name => "/.*#{TwitterHelper.new.get_last_name(twitter_user.name)}.*/i").first if !new_friend | |
new_friend = user.friends.find_or_initialize_by(:twitter_id => friend_id) if !new_friend | |
new_friend.twitter_name = twitter_user.screen_name | |
new_friend.first_name = TwitterHelper.new.get_first_name(twitter_user.name) | |
new_friend.last_name = TwitterHelper.new.get_last_name(twitter_user.name) | |
new_friend.locale = twitter_user.lang | |
new_friend.website = twitter_user.url | |
new_friend.timezone = TwitterHelper.new.translate_utc_offset(twitter_user) | |
new_friend.profile_picture = twitter_user.profile_image_url | |
new_friend.twitter_followers = twitter_user.followers_count.to_i | |
new_friend.twitter_following = twitter_user.friends_count.to_i | |
new_friend.save | |
rescue => e | |
Rails.logger.error "Error importing twitter friend. Msg: #{e}" | |
end | |
end | |
end | |
def self.import_from_facebook(user, friends) | |
Parallel.map(friends, :in_threads=>(Rails.env.production? ? 4 : 0)) do |friend| | |
begin | |
fb_user = FbGraph::User.new(friend.identifier, :access_token => user.fb_token).fetch | |
new_friend = user.friends.where(:fb_id => nil, | |
:website => "/(#{fb_user.website.split("/n").map {|elem| ".*#{elem}.*" }.join '|'})/i").first if !fb_user.website.blank? | |
new_friend = user.friends.where(:fb_id => nil, | |
:first_name => "/.*#{fb_user.first_name}.*/i", | |
:last_name => "/.*#{fb_user.last_name}.*/i").first if !new_friend | |
new_friend = user.friends.find_or_initialize_by(:fb_id => friend.identifier) if !new_friend | |
new_friend.fb_name = fb_user.username | |
new_friend.first_name = fb_user.first_name | |
new_friend.last_name = fb_user.last_name | |
new_friend.email = fb_user.email | |
new_friend.gender = fb_user.gender | |
new_friend.birthday = fb_user.birthday | |
new_friend.locale = fb_user.locale | |
new_friend.website = fb_user.website | |
new_friend.timezone = fb_user.timezone.to_i | |
new_friend.profile_picture = fb_user.picture | |
new_friend.save | |
rescue => e | |
Rails.logger.error "Error importing facebook friend. Msg: #{e}" | |
end | |
end | |
end | |
#instance classes | |
def get_user | |
User.where(:fb_user_id => self.fb_id).first | |
end | |
def get_full_name | |
"#{self.first_name} #{self.last_name}" | |
end | |
def has_account? | |
!self.get_user.nil? | |
end | |
def has_provider?(provider) | |
case provider | |
when "twitter" | |
return !self.fb_id.blank? | |
when "facebook" | |
return !self.twitter_id.blank? | |
else | |
false | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module User::FriendSignupMethods | |
def self.included(base) | |
base.instance_eval do | |
extend ClassMethods | |
has_many :friends, dependent: :destroy | |
after_create :get_friends | |
end | |
end | |
def get_friends | |
Resque.enqueue(GetFriends, self.id) | |
end | |
def import_facebook_friends | |
return if !self.is_fb_connected? | |
begin | |
friends = get_fb_friends(self) | |
Friend.import_from_facebook(self, friends) | |
rescue => e | |
Rails.logger.error "Error importing facebook friends. Msg: #{e}" | |
Rails.logger.error e.backtrace.join("\n") | |
end | |
end | |
def import_twitter_friends | |
return if !self.is_twitter_connected? | |
begin | |
Twitter.oauth_token = self.twitter_token | |
Twitter.oauth_token_secret = self.twitter_secret | |
friend_ids = TwitterHelper.new.get_all_twitter_friends(self) + TwitterHelper.new.get_all_twitter_followers(self) | |
Friend.import_from_twitter(self, friend_ids) | |
rescue => e | |
Rails.logger.error "Error importing twitter friends. Msg: #{e}" | |
end | |
end | |
def notify_friends | |
selected_users = self.get_app_friends(true) | |
batch_size = 2 # group users in batches to create waves | |
if selected_users.size > batch_size | |
Rails.logger.info "Sending notifications because batch size big enough!" | |
selected_users.each do |selected_user| | |
user = selected_user[:user] | |
friend = selected_user[:friend] | |
Resque.enqueue_in(Random.new.rand(1..720).minutes, | |
SendFriendSignupNotification, user.id, self.id, friend.id) | |
end | |
else | |
Rails.logger.info "Not sending notifications because batch size too small!" | |
end | |
end | |
def notify_user_friend_signed_up(friend) | |
result = false | |
begin | |
Rails.logger.info "Sending signup notification to: #{self.name}" | |
UserMailer.friend_signup(self, friend).deliver | |
result = true | |
rescue => e | |
Rails.logger.error "Error notifying user about friend signup. Msg: #{e}" | |
end | |
result | |
end | |
private | |
def get_fb_friends(user) | |
fb_user = FbGraph::User.me(user.fb_token).fetch | |
fb_friends = fb_user.friends | |
fb_subscribers = fb_user.subscribers | |
friends = [] | |
begin | |
fb_friends.each do |fb_friend| | |
friends << fb_friend | |
end | |
end while fb_friends.next.present? && fb_friends = fb_friends.next | |
begin | |
fb_subscribers.each do |fb_subscriber| | |
friends << fb_subscriber | |
end | |
end while fb_subscribers.next.present? && fb_subscribers = fb_subscribers.next | |
friends | |
end | |
def get_app_friends(without_signup_notification = false) | |
selected_users = [] | |
if without_signup_notification | |
selected_friends = self.friends.where(:send_signup_notification => false) | |
else | |
selected_friends = self.friends | |
end | |
users = User.all | |
selected_friends.each do |friend| | |
fb_based_user = users.where(:fb_user_id => friend.fb_id).first if !friend.fb_id.blank? | |
twitter_based_user = users.where(:twitter_id => friend.twitter_id).first if !friend.twitter_id.blank? and !fb_based_user | |
if fb_based_user and fb_based_user.id != self.id | |
selected_users << {:user => fb_based_user, :friend => friend} | |
elsif twitter_based_user and twitter_based_user.id != self.id | |
selected_users << {:user => twitter_based_user, :friend => friend} | |
end | |
end | |
selected_users | |
end | |
module ClassMethods | |
def notify_friends! | |
begin | |
User.all.only(:id).each do |user| | |
Resque.enqueue(FriendSignupNotifier, user.id) | |
end | |
rescue => e | |
Rails.logger.error "Error notifying friends. Msg: #{e}" | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module FriendSignupNotifier | |
@queue = :low | |
def self.perform(user_id) | |
user = User.where(:_id => user_id).first | |
if user | |
user.notify_friends | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
gem 'resque' | |
gem 'resque-scheduler', "~> 2.0.0", :require => 'resque_scheduler' | |
gem 'parallel', "~> 0.5.16" | |
gem 'fb_graph', "~> 2.4.4" | |
gem "twitter" | |
gem 'mongoid' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module GetFriends | |
@queue = :low | |
def self.perform(user_id) | |
user = User.where(:_id => user_id).first | |
if user | |
user.import_twitter_friends | |
user.import_facebook_friends | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module SendFriendSignupNotification | |
@queue = :low | |
def self.perform(receiver_user_id, sender_user_id, receiver_friend_id) | |
receiver_user = User.where(:_id => receiver_user_id).first | |
sender_user = User.where(:_id => sender_user_id).first | |
receiver_friend = Friend.where(:_id => receiver_friend_id).first | |
return if receiver_friend.send_signup_notification or !sender_user.has_quotes? | |
receiver_friend.send_signup_notification = receiver_user.notify_user_friend_signed_up(sender_user) | |
receiver_friend.save | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
include User::FriendSignupMethods |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment