Skip to content

Instantly share code, notes, and snippets.

@leafmind
Created October 17, 2012 09:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leafmind/3904653 to your computer and use it in GitHub Desktop.
Save leafmind/3904653 to your computer and use it in GitHub Desktop.
Models samples with built-in integrations
# Mechanize based Altergeo integration
# -*- encoding : utf-8 -*-
class Altergeo::Places
PER_PAGE = 3
EXPANDED_DISTANCE = 10000
def self.find_by_query(altergeo_user, query = '', page = 1)
options = { :query => query, :limit => PER_PAGE, :offset => PER_PAGE * (page - 1) }
response = make_request(altergeo_user, options)
response ||= make_request(altergeo_user, options.merge(:distance => EXPANDED_DISTANCE))
if response.respond_to?(:xpath)
total_pages = response.xpath('//count').first.content.to_i
places = response.xpath('//place').map do |place|
OpenStruct.new(
:place_id => place.at_xpath('id').content,
:title => place.at_xpath('title').content,
:street => place.at_xpath('street').content
)
end
Altergeo::Collection.new(places, PER_PAGE, total_pages, page)
end
end
private
def self.make_request(altergeo_user, options)
add_coordinates!(altergeo_user, options)
Altergeo::Client.post(Settings.altergeo.places, user(altergeo_user), options)
end
def self.add_coordinates!(altergeo_user, options)
return unless altergeo_user
coordinates = altergeo_user.coordinates
if coordinates
options[:lat] = coordinates.lat
options[:lng] = coordinates.lng
end
end
def self.user(altergeo_user)
if altergeo_user
{ :email => altergeo_user.email, :password => altergeo_user.password }
else
Hash.new
end
end
end
########################################
# Mechanize based Altergeo integration
# -*- encoding : utf-8 -*-
class Altergeo::User < ActiveRecord::Base
self.table_name = :altergeo_users
belongs_to :user, :class_name => "BhUser", :primary_key => "user_id"
def self.authorize(params, current_user)
return unless params
email = params[:email]
password = params[:password]
if Altergeo::Client.post(Settings.altergeo.login_url, params)
find_or_create_by_email(email, :password => password, :user => current_user)
end
end
def coordinates
Slot::MsisdnCoordinates.new(user.msisdn).read if user
end
end
###################################
# Mechanize based Altergeo integration
# -*- encoding : utf-8 -*-
class Altergeo::Client
class << self
def get(uri, params, options = {})
prepare agent.get(uri, options, headers(params))
rescue Mechanize::ResponseCodeError => e
handle(e)
end
def post(uri, params, options = {})
prepare agent.post(uri, options, headers(params))
rescue Mechanize::ResponseCodeError => e
handle(e)
end
private
def handle(exception)
%w{403 401}.include?(exception.response_code).blank?
end
def prepare(response)
Nokogiri::XML(response.body)
end
def headers(params)
{
"Authorization" => 'Basic ' + ["#{params[:email]}:#{params[:password]}"].pack('m').delete("\r\n"),
}
end
def agent
@mechanize ||= Mechanize.new do |a|
a.log = Logger.new('log/mechanize.log')
a.user_agent_alias = 'Windows Mozilla'
end
end
end
end
##############################################
# Nokogiri based LJ integration
# -*- encoding : utf-8 -*-
class Livejournal::FriendsFeed
include Livejournal::Mixin
LIMIT = 3
POST_LINK_PATTERN = /http:\/\/([^.]+)\.livejournal.com\/[\d]+\.html$/
URL = 'http://%s.livejournal.com/friends'
def initialize(livejournal_user)
raise ArgumentError unless livejournal_user.respond_to?(:nickname)
@nickname = livejournal_user.nickname
end
def all(limit = LIMIT)
safe do
doc = Nokogiri::HTML(open(URL % @nickname))
return [] unless doc.respond_to?(:css)
doc.css('a').
find_all { |link| post_link?(link) }.
take(limit).
map { |link|
fetch_post_from_page(link['href'])
}
end
end
private
def post_link?(link)
link['href'] =~ POST_LINK_PATTERN
end
def fetch_post_from_page(url)
nickname = (url =~ POST_LINK_PATTERN; $1)
mobile_link = link_to_mobile(nickname, url)
doc = Nokogiri::HTML(open(mobile_link))
return {} unless doc.respond_to?(:css)
{
:nickname => nickname,
:title => Sanitize.clean(doc.at_css('.l .item-header').content),
:link => mobile_link
}
end
end
###################################
# OmniAuth based facebook integration
require_dependency 'user/acts_as_forum_user'
class User < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
include ActsAsForumUser
include Mailboxer::Models::Messageable
module Types
COURSE_MANAGER = 'CourseManager'
MENTOR = 'Mentor'
STUDENT = 'Student'
SUPERADMIN = 'SuperAdmin'
TEACHER = 'Teacher'
TUTOR = 'Tutor'
ALL = [COURSE_MANAGER, MENTOR, STUDENT, SUPERADMIN, TEACHER, TUTOR].freeze
end
acts_as_messageable
# Dimensions and type names match Facebook's dimensions convetion
has_attached_file :avatar, :default_url => "/assets/default_:style_avatar.jpg", :styles => {:small => '50', :normal => '100', :large => '200'}
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :confirmable,
:omniauthable
scope :without, lambda{ |user| user ? {:conditions => ["users.id != ?", user.id]} : {} }
# Reason why we can't just use :validatable Devise plugin - http://jessewolgamott.com/blog/2011/12/08/the-one-where-devise-validations-are-customized/
validates_presence_of :email
validates_uniqueness_of :email, :allow_blank => true, :if => :email_changed?
validates_format_of :email, :with => Devise.email_regexp, :allow_blank => true, :if => :email_changed?
validates :first_name, :presence => true, :if => :profile_data_required?
validates :last_name, :presence => true, :if => :profile_data_required?
validates_presence_of :password, :if => :password_required?
validates_confirmation_of :password, :if => :password_required?
validates_length_of :password, :within => Devise.password_length, :allow_blank => true
validates_uniqueness_of :email
validates :type, :inclusion => Types::ALL
def profile_data_required?
!new_record?
end
# Checks whether a password is needed or not. For validations only.
# Passwords are always required if it's a new record, or if the password
# or confirmation are being set somewhere.
def password_required?
return false if !persisted? && has_connected_facebook_account?
!persisted? || !password.nil? || !password_confirmation.nil?
end
def has_connected_facebook_account?
uid.present?
end
# taken from https://github.com/ging/social_stream/blob/12eca97a22a34fb44abd9341c6d25ad14c975c8e/base/app/models/actor.rb#L589
#
# Returns [Integer]
def unread_messages_count
mailbox.inbox(:unread => true).count(:id, :distinct => true)
end
def to_param
"#{id}-#{full_name.parameterize}"
end
def has_access_to_rails_admin?
User::Types::ALL.reject { |role| role == User::Types::STUDENT }.include?(type)
end
def avatar_path(type)
raise "unknow type: #{type}" unless %w(small normal large).include?(type.to_s)
if has_connected_facebook_account? && !avatar?
facebook_avatar_url(type)
else
avatar(type.to_sym)
end
end
def facebook_avatar_url(type)
"http://graph.facebook.com/#{uid.to_s}/picture?type=#{type.to_s}"
end
def full_name
"#{first_name} #{last_name}"
end
alias_method :name, :full_name # required by Messageable
alias_method :to_s, :full_name # required by Forem
# Returning the email address of the model if an email should be sent for this object (Message or Notification).
# If no mail has to be sent, return nil.
def mailboxer_email(object)
email
end
def self.teacher_or_mentor
User.where 'type IN ("Teacher", "Mentor")'
end
# Find or create user based on Facebook Auth payload
# this method is called in omniauth callback action
#
# @param payload - request.env["omniauth.auth"] object that is passed from controller
# @param current_user - current logged in user(if present)
#
# Returns [User]
def self.find_or_create_from_facebook(payload, current_user)
if current_user.present?
current_user.update_attributes(:provider => payload.provider, :uid => payload.uid)
current_user
else
find_from(payload) || create_from(payload)
end
end
# Devise RegistrationsController by default calls "User.new_with_session" before building a resource.
# This means that, if we need to copy data from session whenever a user is initialized before sign up,
# we just need to implement new_with_session in our model.
#
# @see https://github.com/plataformatec/devise/wiki/OmniAuth%3A-Overview
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
user.email = data["email"] if user.email.blank?
end
end
end
private
def self.find_from(payload)
where(:provider => payload.provider, :uid => payload.uid).first
end
def self.create_from(payload)
user = new(:first_name => payload.extra.raw_info.first_name,
:last_name => payload.extra.raw_info.last_name,
:provider => payload.provider,
:uid => payload.uid,
:email => payload.info.email)
user.skip_confirmation!
user.save
user
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment