Skip to content

Instantly share code, notes, and snippets.

@nguyenlocduy
Last active December 16, 2015 01:08
Show Gist options
  • Save nguyenlocduy/5352257 to your computer and use it in GitHub Desktop.
Save nguyenlocduy/5352257 to your computer and use it in GitHub Desktop.
How to integrate SHIFT API (https://shift.com) to your Rails App. You should read SHIFT API Docs to understand the flow before implementing this.
# config/omniauth.rb
# this is OPTIONAL if you want user to login not through SHIFT Website
# Register our provider with the OmniAuth Gem
module OmniAuth
module Strategies
# tell OmniAuth to load our strategy
autoload :Shift, 'shift_strategy'
end
end
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FB_APP'], ENV['FB_SECRET'], {:scope => 'publish_actions, email, user_interests, user_groups, user_likes, publish_stream, offline_access, user_birthday, create_event, manage_pages'}
provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
provider :shift, ENV['SHIFT_APP_ID'], ENV['SHIFT_APP_SECRET'], {}
end
#----------------------------------------------------------------------#
# function: app_install
# summary: when user authenticate through shift website, this is where
# the redirect_uri settings from shift pointed to
# author: Duy
#----------------------------------------------------------------------#
def app_install
# uri
uri = URI.parse("https://shift.com")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
# prepare data
data = {'code' => params["code"],
'client_id' => ENV['SHIFT_APP_ID'],
'client_secret' => ENV['SHIFT_APP_SECRET'],
'grant_type' => 'authorization_code',
'redirect_uri' => ENV['SHIFT_REDIRECT_URL']
}
# grab the path if available
path = params['path'] || '/'
# post request
request = Net::HTTP::Post.new("/v1/oauth2/token")
request.add_field('Content-Type', 'application/json')
request.set_form_data(data)
response = http.request(request)
# get the token from the response
result = JSON(response.body)
@access_token = result["access_token"]
@refresh_token = response["refresh_token"]
# obtain user information and put into a hash
user_uri = URI.parse("https://shift.com/v1/users/me")
user_request = Net::HTTP::Get.new(user_uri.request_uri)
user_request.add_field('Authorization', "Bearer #{@access_token}")
user_response = http.request(user_request)
user_data = JSON(user_response.body)
#send_test_message(@access_token)
shift_check_and_login(user_data, @access_token, path)
end
#----------------------------------------------------------------------#
# function: shift_check_and_login
# summary: prepares data hash for user to sign in
# author: Duy
#----------------------------------------------------------------------#
def shift_check_and_login(user_hash, access_token, path = '/')
auth_hash = {}
data_hash = user_hash["data"][0]
uid = data_hash["id"]
user = User.where("providers.provider" => 'shift', "providers.uid" => uid).first
# provider hash
provider = {"provider" => "shift", "uid" => uid}
# info hash
info = {
"info" => {
'username' => data_hash['username'],
'first_name' => data_hash['first_name'],
'last_name' => data_hash['last_name'],
'email' => data_hash['primary_email']['address'],
'image' => data_hash['images'][0]['sizes']['default']
}
}
# credentials hash
credentials = {
"credentials" => {
"token" => access_token
}
}
# extra info
extra = {
"extra" => {
"title" => data_hash['title'],
"company" => data_hash['company']
}
}
# prepare data
auth_hash = auth_hash.merge(provider)
auth_hash = auth_hash.merge(info)
auth_hash = auth_hash.merge(credentials)
auth_hash = auth_hash.merge(extra)
# authenticate user and redirect to the right path
# this function is customized with your authentication system eg. Devise
authenticate(auth_hash, path)
end
# app/workers/shift_object_creation_worker.rb
# To create an SHIFT Object and Post the message to team feed via background job (Resque)
require "uri"
require "net/https"
require "json"
class ShiftCampaignCreateApi
@queue = :shift_api
def self.perform(campaign_id, access_token)
campaign = Campaign.find(campaign_id)
link = "campaigns/#{ campaign.slug }"
# uri
uri = URI.parse("https://shift.com")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
# create a test object
obj_hash = '{
"url" : "'+link+'",
"type" : "Campaign",
"team" : "'+ENV['SHIFT_TEAM_ID']+'",
"name" : "'+campaign.title+'"
}'
obj_uri = URI.parse("https://shift.com/v1/applications/#{ENV['SHIFT_APP_ID']}/objects")
obj_request = Net::HTTP::Post.new(obj_uri.request_uri)
obj_request.add_field("Content-Type", "application/json")
obj_request.add_field("Authorization", "Bearer #{access_token}")
obj_request.body = obj_hash
obj_response = http.request(obj_request)
obj_result = JSON(obj_response.body)
obj_id = obj_result["data"][0]["id"]
# Send a test message
message_data = '{
"addressed_users": [],'
message_data += '
"text": "Create a new Campaign {0}",'
message_data += '
"addressed_teams": [
"'+ENV['SHIFT_TEAM_ID']+'"
],'
message_data += '
"mentions": [{"type": "appobject", "id": "'+obj_id+'", "name": "'+campaign.title+'"}]
}'
msg_uri = URI.parse("https://shift.com/v1/messages")
msg_request = Net::HTTP::Post.new(msg_uri.request_uri)
msg_request.add_field('Content-Type', 'application/json')
msg_request.add_field('Authorization', "Bearer #{access_token}")
msg_request.body = message_data
msg_response = http.request(msg_request)
end
end
# lib/shift_strategy.rb
# this is OPTIONAL if you want user to login not through SHIFT Website
# creates a omniauth strategry (provider) for OmniAuth
require 'omniauth/strategies/oauth2'
require 'base64'
require 'openssl'
require 'rack/utils'
module OmniAuth
module Strategies
class Shift < OmniAuth::Strategies::OAuth2
class NoAuthorizationCodeError < StandardError; end
option :client_options, {
:site => 'https://shift.com',
:authorize_url => "https://shift.com/v1/oauth2/auth",
:token_url => '/v1/oauth2/token'
}
uid { raw_info['data'][0]['id'] }
info do
prune!({
'username' => raw_info['data'][0]['username'],
'first_name' => raw_info['data'][0]['first_name'],
'last_name' => raw_info['data'][0]['last_name'],
'email' => raw_info['data'][0]['primary_email']['address'],
'image' => raw_info['data'][0]['images'][0]['sizes']['default']
})
end
extra do
hash = {}
hash['raw_info'] = raw_info unless skip_info?
prune! hash
end
def raw_info
@raw_info ||= access_token.get('/v1/users/me').parsed || {}
end
def request_phase
if request.params["access_token"]
url = callback_url
url << "?" unless url.match(/\?/)
url << "&" unless url.match(/[\&\?]$/)
url << query
redirect url
else
super
end
end
# NOTE if we're using code from the signed request
# then FB sets the redirect_uri to '' during the authorize
# phase + it must match during the access_token phase:
# https://github.com/facebook/php-sdk/blob/master/src/base_facebook.php#L348
def callback_url
options[:callback_url] || super
end
private
def prune!(hash)
hash.delete_if do |_, value|
prune!(value) if value.is_a?(Hash)
value.nil? || (value.respond_to?(:empty?) && value.empty?)
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment