Skip to content

Instantly share code, notes, and snippets.

@roseleaf
Created August 9, 2013 23:26
Show Gist options
  • Save roseleaf/6198165 to your computer and use it in GitHub Desktop.
Save roseleaf/6198165 to your computer and use it in GitHub Desktop.
This script solves the complex problem of setting all phone numbers on "real" user profiles to direct_line, while disabling direct lines on all "dummy" profiles that have the same number. working around the issue of direct lines being unique, and of each user being required to have at least one valid "identity" (such as a direct_line phone numbe…
# This script solves the complex problem of setting all phone numbers on
# "real" user profiles to direct_line, while disabling direct lines on all
# "dummy" profiles that have the same number. working around the issue of
# direct lines being unique, and of each user being required to have at least
# one valid "identity" (such as a direct_line phone number or an email address)
# by: 1) finding all users who do not have profiles but who do have phone
# numbers and setting their emails to dummy values associated with those
# numbers in order to un-set the "direct_line" property on their numbers.
# 2) setting aside all users that do have profiles and setting their numbers
# to direct_line.
# ASSUMPTION: the account does not use Twitter/Google/Facebook user auth. Modify
# the criteria for setting of the user_profile flag on ln. 105 if this is not the case.
# PREPARATION: the acount's API limit should be raised by setting it to 'import mode'
# prior to running this script to minimize http induced exceptions
# This script is to be run in your terminal/command line shell.
# cd into this folder, and type "ruby enable_direct_lines.rb > out.txt" to run.
require 'open-uri'
require 'httparty'
require 'thread'
# Pool's been done http://burgestrand.se/code/ruby-thread-pool/
class Pool
def initialize(size)
@size = size
@jobs = Queue.new
@pool = Array.new(@size) do |i|
Thread.new do
Thread.current[:id] = i
catch(:exit) do
loop do
job, args = @jobs.pop
job.call(*args)
end
end
end
end
end
def schedule(*args, &block)
@jobs << [block, args]
end
def shutdown
@size.times do
schedule { throw :exit }
end
@pool.map(&:join)
end
end
class PhoneSetter
include HTTParty
# un-comment to enable http output :
# debug_output $stdout
base_uri ''
attr_accessor :auth, :options
def initialize(u, p)
@auth = { :username => u + '/token', :password => p }
@options = {}
end
MAX_ATTEMPTS = 4
def get_users()
@options.merge!({ basic_auth: @auth })
allUsers = []
userBatch = self.class.get("/users.json", options)
pageCount = 0
while userBatch.count > 0
userBatch = self.class.get("/users.json?page=#{pageCount}", @options)
allUsers.concat userBatch
pageCount += 1
end
puts "+++++++++"
puts allUsers.count
puts "+++++++++"
divide_processes(allUsers)
end
def divide_processes(allUsers)
users_with_profiles = []
p = Pool.new(5)
allUsers.each_with_index do |user, i|
num_attempts = 0
p.schedule do
begin
if user.class != Hash
user = user.parsed_response
end
user_id = user['id']
user_phone = user['phone']
user_email = user['email']
if user.has_key? 'profile_flag'
puts "updating user profile #{user_id} with #{user_phone}"
update_phone( user_id, user_phone, 1)
elsif user_phone
if user_email
if !user_email.include? "email.com"
user["profile_flag"] = true
puts "found user with profile, #{user}"
users_with_profiles << user
puts "right now uwp is a #{users_with_profiles.class}"
end
else
puts "found user #{user_id} with no profile. updating email."
update_email( user_id, user_phone)
end
end
rescue
puts "Exception Found:"
puts $!, $@
if num_attempts <= MAX_ATTEMPTS
sleep(60)
puts "retrying now..."
retry
else
raise
end
rescue Exception
puts $!, $@
end
end
end
at_exit do
p.shutdown
puts "divide_processes has completed an iteration."
puts "users with profiles: #{users_with_profiles.count} which is a #{users_with_profiles.class}"
if users_with_profiles.count > 0
divide_processes( users_with_profiles )
end
end
end
def update_email( user_id, phone_number)
email_options = { body: { identity: { type: "email", value: "#{phone_number}@email.com", primary: true }}, basic_auth: @auth, headers: { 'ContentType' => 'application/json'} }
self.class.post("/api/v2/users/#{user_id}/identities.json", email_options)
update_phone( user_id, phone_number, 0 )
end
def update_phone( user_id, user_phone, val)
user_options = { body: "number=#{user_phone}&direct_line=#{val}", basic_auth: @auth, headers: { 'ContentType' => 'application/x-www-form-urlencoded'}}
puts "updated phone for: #{user_id}"
self.class.post("/users/#{user_id}/update_number", user_options)
end
end
class PhoneClient
def run
puts ""
puts "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~"
puts "Welcome to the Zendesk PhoneSetter Command Line Interface!"
puts "~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~"
puts ""
puts "Enter your zendesk username:"
username = gets.chomp
puts "Enter your zendesk API token:"
token = gets.chomp
attachmentGetter = PhoneSetter.new(username, token)
puts "One last thing. Please enter your Zendesk subdomain:"
subdomain = gets.chomp
puts "thank you"
newUrl = "https://#{subdomain}.zendesk.com/"
PhoneSetter.base_uri newUrl
attachmentGetter.get_users
puts "Done! Your users have been updated. Goodbye."
end
end
# You can use the default prompt-based interface above or,
# alternatively, you can un-comment the below and put in your
# credentials to run instantly during testing:
# class PhoneClient
# def run
# username = _AGENT_EMAIL_HERE_
# token = _ACCT_TOKEN_HERE_
# attachmentGetter = PhoneSetter.new(username, token)
# subdomain = _SUBDOMAIN_HERE_
# puts "thank you"
# newUrl = "https://#{subdomain}.zendesk.com/"
# PhoneSetter.base_uri newUrl
# attachmentGetter.get_users
# end
# end
myCLient = PhoneClient.new
myCLient.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment