career_builder 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/career_builder.gemspec +7 -8
- data/lib/career_builder.rb +0 -6
- data/lib/career_builder/client.rb +15 -22
- data/lib/career_builder/{requests → client}/advanced_resume_search.rb +8 -9
- data/lib/career_builder/client/authentication.rb +30 -0
- data/lib/career_builder/{requests → client}/get_resume.rb +8 -9
- data/lib/career_builder/client/request.rb +76 -0
- data/lib/career_builder/client/resume_actions_remaining_today.rb +16 -0
- data/lib/career_builder/resume/lazy_collection.rb +3 -8
- data/spec/career_builder/resume/lazy_collection_spec.rb +6 -2
- metadata +10 -11
- data/lib/career_builder/request.rb +0 -82
- data/lib/career_builder/request/authenticated.rb +0 -23
- data/lib/career_builder/requests/authentication.rb +0 -25
- data/lib/career_builder/requests/resume_actions_remaining_today.rb +0 -21
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.2.0
|
data/career_builder.gemspec
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{career_builder}
|
|
8
|
-
s.version = "0.
|
|
8
|
+
s.version = "0.2.0"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Michael Guterl"]
|
|
12
|
-
s.date = %q{2011-
|
|
12
|
+
s.date = %q{2011-03-31}
|
|
13
13
|
s.description = %q{Ruby wrapper for the CareerBuilder V2 HTTP XML API}
|
|
14
14
|
s.email = %q{mguterl@gmail.com}
|
|
15
15
|
s.extra_rdoc_files = [
|
|
@@ -39,13 +39,12 @@ Gem::Specification.new do |s|
|
|
|
39
39
|
"lib/career_builder/api/shift_preference.rb",
|
|
40
40
|
"lib/career_builder/api/word_document.rb",
|
|
41
41
|
"lib/career_builder/client.rb",
|
|
42
|
+
"lib/career_builder/client/advanced_resume_search.rb",
|
|
43
|
+
"lib/career_builder/client/authentication.rb",
|
|
44
|
+
"lib/career_builder/client/get_resume.rb",
|
|
45
|
+
"lib/career_builder/client/request.rb",
|
|
46
|
+
"lib/career_builder/client/resume_actions_remaining_today.rb",
|
|
42
47
|
"lib/career_builder/errors.rb",
|
|
43
|
-
"lib/career_builder/request.rb",
|
|
44
|
-
"lib/career_builder/request/authenticated.rb",
|
|
45
|
-
"lib/career_builder/requests/advanced_resume_search.rb",
|
|
46
|
-
"lib/career_builder/requests/authentication.rb",
|
|
47
|
-
"lib/career_builder/requests/get_resume.rb",
|
|
48
|
-
"lib/career_builder/requests/resume_actions_remaining_today.rb",
|
|
49
48
|
"lib/career_builder/resume.rb",
|
|
50
49
|
"lib/career_builder/resume/lazy_collection.rb",
|
|
51
50
|
"spec/career_builder/client_spec.rb",
|
data/lib/career_builder.rb
CHANGED
|
@@ -30,10 +30,4 @@ require 'career_builder/api/word_document'
|
|
|
30
30
|
require 'career_builder/api/resume'
|
|
31
31
|
require 'career_builder/resume'
|
|
32
32
|
require 'career_builder/resume/lazy_collection'
|
|
33
|
-
require 'career_builder/request'
|
|
34
|
-
require 'career_builder/request/authenticated'
|
|
35
|
-
require 'career_builder/requests/authentication'
|
|
36
|
-
require 'career_builder/requests/advanced_resume_search'
|
|
37
|
-
require 'career_builder/requests/get_resume'
|
|
38
|
-
require 'career_builder/requests/resume_actions_remaining_today'
|
|
39
33
|
require 'career_builder/client'
|
|
@@ -1,37 +1,30 @@
|
|
|
1
|
+
require 'career_builder/client/authentication'
|
|
2
|
+
require 'career_builder/client/request'
|
|
3
|
+
require 'career_builder/client/advanced_resume_search'
|
|
4
|
+
require 'career_builder/client/get_resume'
|
|
5
|
+
require 'career_builder/client/resume_actions_remaining_today'
|
|
6
|
+
|
|
1
7
|
module CareerBuilder
|
|
2
8
|
|
|
3
9
|
class Client
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
include Authentication
|
|
12
|
+
include Request
|
|
13
|
+
include AdvancedResumeSearch
|
|
14
|
+
include GetResume
|
|
15
|
+
include ResumeActionsRemainingToday
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
@session_token = Requests::Authentication.new(self, :email => email, :password => password).perform
|
|
13
|
-
end
|
|
17
|
+
attr_reader :email, :password
|
|
14
18
|
|
|
15
|
-
def
|
|
16
|
-
|
|
19
|
+
def initialize(email, password, options = {})
|
|
20
|
+
@email, @password = email, password
|
|
21
|
+
@debug = options.fetch(:debug) { false }
|
|
17
22
|
end
|
|
18
23
|
|
|
19
24
|
def resumes(options = {})
|
|
20
25
|
Resume::LazyCollection.new(self, options)
|
|
21
26
|
end
|
|
22
27
|
|
|
23
|
-
def advanced_resume_search(options = {})
|
|
24
|
-
Requests::AdvancedResumeSearch.new(self, options).perform
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def get_resume(options = {})
|
|
28
|
-
Requests::GetResume.new(self, options).perform
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def resume_actions_remaining_today(options = {})
|
|
32
|
-
Requests::ResumeActionsRemainingToday.new(self, options).perform
|
|
33
|
-
end
|
|
34
|
-
|
|
35
28
|
end
|
|
36
29
|
|
|
37
30
|
end
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
module CareerBuilder
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class AdvancedResumeSearch < Request::Authenticated
|
|
2
|
+
class Client
|
|
3
|
+
module AdvancedResumeSearch
|
|
6
4
|
|
|
7
5
|
# List of valid options available at:
|
|
8
6
|
# http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch_ValidFields
|
|
@@ -27,15 +25,16 @@ module CareerBuilder
|
|
|
27
25
|
:rsadid, :cb_minimum_experience,
|
|
28
26
|
:cb_maximum_experience].freeze
|
|
29
27
|
|
|
30
|
-
def
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
def advanced_resume_search(options = {})
|
|
29
|
+
unless (invalid_options = options.keys - VALID_OPTIONS).empty?
|
|
30
|
+
raise ArgumentError, "Invalid options #{invalid_options}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
response = auth_request("V2_AdvancedResumeSearch", options)
|
|
33
34
|
|
|
34
35
|
API::ResumeSearch.parse(response)
|
|
35
36
|
end
|
|
36
37
|
|
|
37
38
|
end
|
|
38
|
-
|
|
39
39
|
end
|
|
40
|
-
|
|
41
40
|
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module CareerBuilder
|
|
2
|
+
class Client
|
|
3
|
+
module Authentication
|
|
4
|
+
|
|
5
|
+
def session_token
|
|
6
|
+
@session_token
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def authenticate
|
|
10
|
+
response = request("BeginSessionV2", 'Email' => email, 'Password' => password)
|
|
11
|
+
|
|
12
|
+
packet = Nokogiri::XML(response)
|
|
13
|
+
|
|
14
|
+
if session_token = packet.search("//SessionToken")
|
|
15
|
+
session_token_text = session_token.text
|
|
16
|
+
if session_token_text == "Invalid"
|
|
17
|
+
@session_token = nil
|
|
18
|
+
else
|
|
19
|
+
@session_token = session_token_text
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def authenticated?
|
|
25
|
+
!session_token.nil?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
module CareerBuilder
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class GetResume < Request::Authenticated
|
|
2
|
+
class Client
|
|
3
|
+
module GetResume
|
|
6
4
|
|
|
7
5
|
VALID_OPTIONS = [:resume_id, :cust_acct_code, :get_word_doc_if_available].freeze
|
|
8
6
|
|
|
9
|
-
def
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
def get_resume(options = {})
|
|
8
|
+
unless (invalid_options = options.keys - VALID_OPTIONS).empty?
|
|
9
|
+
raise ArgumentError, "Invalid options #{invalid_options}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
response = auth_request("V2_GetResume", options)
|
|
12
13
|
|
|
13
14
|
if response =~ /ResumeID/ # valid response
|
|
14
15
|
API::Resume.parse(response, :single => true)
|
|
@@ -18,7 +19,5 @@ module CareerBuilder
|
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
end
|
|
21
|
-
|
|
22
22
|
end
|
|
23
|
-
|
|
24
23
|
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module CareerBuilder
|
|
2
|
+
class Client
|
|
3
|
+
module Request
|
|
4
|
+
|
|
5
|
+
RESUME_SERVICE_ENDPOINT_URL = 'http://ws.careerbuilder.com/resumes/resumes.asmx'
|
|
6
|
+
|
|
7
|
+
def auth_request(meth, options = {})
|
|
8
|
+
if !authenticated? && !authenticate
|
|
9
|
+
raise InvalidCredentials
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
options.merge!(:session_token => session_token)
|
|
13
|
+
|
|
14
|
+
request meth, options
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def request(meth, options = {})
|
|
18
|
+
uri = URI.parse(RESUME_SERVICE_ENDPOINT_URL + "/#{meth}")
|
|
19
|
+
|
|
20
|
+
options_as_xml = transform_options_to_xml(options)
|
|
21
|
+
|
|
22
|
+
form_data = { 'Packet' => "<Packet>#{options_as_xml}</Packet>" }
|
|
23
|
+
|
|
24
|
+
req = Net::HTTP::Post.new(uri.path)
|
|
25
|
+
req.form_data = form_data
|
|
26
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
27
|
+
http.set_debug_output $stderr if @debug
|
|
28
|
+
response = http.start { |http|
|
|
29
|
+
http.request(req)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
parse_terrible_response(response)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def parse_terrible_response(response)
|
|
36
|
+
xml_body = Nokogiri::XML(response.body) # not sure why I have to do it this way
|
|
37
|
+
inner_xml = xml_body.children.first
|
|
38
|
+
inner_xml.text
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
CUSTOM_KEY_TRANSFORMS = {
|
|
42
|
+
:resume_id => "ResumeID",
|
|
43
|
+
:account_did => "AccountDID"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
def transform_key(key)
|
|
47
|
+
if custom_transform = CUSTOM_KEY_TRANSFORMS[key]
|
|
48
|
+
custom_transform
|
|
49
|
+
else
|
|
50
|
+
key.to_s.camelize
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def transform_key_value_to_tag(key, value)
|
|
55
|
+
"<#{transform_key(key)}>#{value}</#{transform_key(key)}>"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def transform_options_to_xml(options)
|
|
59
|
+
elements = []
|
|
60
|
+
|
|
61
|
+
# let's make sure SessionToken is always at the top of the request
|
|
62
|
+
if session_key = options.delete(:session_token)
|
|
63
|
+
elements << transform_key_value_to_tag(:session_token, session_token)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
options.sort_by { |k, v| k.to_s }.each do |key, value|
|
|
67
|
+
elements << transform_key_value_to_tag(key, value)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
elements.join
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module CareerBuilder
|
|
2
|
+
class Client
|
|
3
|
+
module ResumeActionsRemainingToday
|
|
4
|
+
|
|
5
|
+
VALID_OPTIONS = [:account_did]
|
|
6
|
+
|
|
7
|
+
def resume_actions_remaining_today(options = {})
|
|
8
|
+
response = auth_request("V2_ResumeActionsRemainingToday", options)
|
|
9
|
+
|
|
10
|
+
doc = Nokogiri::XML(response)
|
|
11
|
+
doc.xpath("//Packet").text.to_i
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -12,25 +12,20 @@ module CareerBuilder
|
|
|
12
12
|
def each
|
|
13
13
|
current_page = search_options[:page] || 1
|
|
14
14
|
|
|
15
|
-
search = client.advanced_resume_search(search_options.merge(:page_number => current_page))
|
|
15
|
+
search = client.advanced_resume_search(search_options.merge(:page_number => current_page, :rows_per_page => 500))
|
|
16
16
|
|
|
17
17
|
results = search.results
|
|
18
|
-
hits = search.hits
|
|
19
|
-
max_page = search.max_page
|
|
20
18
|
|
|
21
19
|
loop do
|
|
22
|
-
|
|
23
20
|
results.each do |resume|
|
|
24
21
|
yield Resume.new(client, resume)
|
|
25
22
|
end
|
|
26
23
|
|
|
27
24
|
current_page += 1
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
search = client.advanced_resume_search(search_options.merge(:page_number => current_page))
|
|
26
|
+
search = client.advanced_resume_search(search_options.merge(:page_number => current_page, :rows_per_page => 500))
|
|
32
27
|
results = search.results
|
|
33
|
-
|
|
28
|
+
break if results.empty?
|
|
34
29
|
end
|
|
35
30
|
end
|
|
36
31
|
|
|
@@ -5,8 +5,12 @@ describe CareerBuilder::Resume::LazyCollection do
|
|
|
5
5
|
describe "#each" do
|
|
6
6
|
|
|
7
7
|
before do
|
|
8
|
-
stub_request(:post, "http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch").with(:body => 'Packet=%3cPacket%3e%3cSessionToken%3e42%3c%2fSessionToken%3e%3cKeywords%3eRuby%3c%2fKeywords%3e%3cPageNumber%3e1%3c%2fPageNumber%3e%3c%2fPacket%3e').to_return(:body => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<string xmlns=\"http://ws.careerbuilder.com/resumes/\"><Packet><Errors /><PageNumber>1</PageNumber><SearchTime>06/25/2010 12:03:14</SearchTime><FirstRec>1</FirstRec><LastRec>100</LastRec><Hits>4</Hits><MaxPage>2</MaxPage><Results><ResumeResultItem_V3><ContactEmail>Rhd4G067G4JVTLW99H7_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com</ContactEmail><ContactName>Rebecca Bernard</ContactName><HomeLocation>US-OH-Milford</HomeLocation><LastUpdate>2010/5/13</LastUpdate><ResumeTitle>BERNARD_SYSTEMS_ENGINEER</ResumeTitle><JobTitle>BERNARD_SYSTEMS_ENGINEER</JobTitle><RecentEmployer>TATA CONSULTANCY SERVICES</RecentEmployer><RecentJobTitle>CONSULTANCY SERVICES- Systems Engineer</RecentJobTitle><RecentPay>0</RecentPay><ResumeID>Rhd4G067G4JVTLW99H7</ResumeID><UserDID>U7X86R61VVKS4FWS03T</UserDID><ContactEmailMD5>139013c2fa2b945bdc340f8a698b009e</ContactEmailMD5></ResumeResultItem_V3><ResumeResultItem_V3><ContactEmail>Rhe7TZ764LHG1GQTPSM_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com</ContactEmail><ContactName>chris grader</ContactName><HomeLocation>US-OH-Milford</HomeLocation><LastUpdate>2010/6/4</LastUpdate><ResumeTitle>Chris Grader resume</ResumeTitle><JobTitle>Chris Grader resume</JobTitle><RecentEmployer>Millennial Medical, Inc</RecentEmployer><RecentJobTitle>Regional Sales Manager/Midwest Distributor</RecentJobTitle><RecentPay>0</RecentPay><ResumeID>Rhe7TZ764LHG1GQTPSM</ResumeID><UserDID>U346V1MKGCHPGCF9S8</UserDID><ContactEmailMD5>cfba57bf848b78211d99348cf0f90879</ContactEmailMD5></ResumeResultItem_V3><ResumeResultItem_V3><ContactEmail>RH52G867678F7GH02Q3_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com</ContactEmail><ContactName>Jeffrey Davis</ContactName><HomeLocation>US-OH-Goshen</HomeLocation><LastUpdate>2010/5/23</LastUpdate><ResumeTitle>Warehouse Distribution Specialist</ResumeTitle><JobTitle>Warehouse Distribution Specialist</JobTitle><RecentEmployer>OWENS &amp; MINOR</RecentEmployer><RecentJobTitle>Warehouse Lead Supervisor</RecentJobTitle><RecentPay>35776</RecentPay><ResumeID>RH52G867678F7GH02Q3</ResumeID><UserDID>U1C29V68M3YM95SP0XK</UserDID><ContactEmailMD5>e814ebaa93aae5c3719e27d26d5af917</ContactEmailMD5></ResumeResultItem_V3></Results></Packet></string>")
|
|
9
|
-
stub_request(:post, "http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch").with(:body => 'Packet=%3cPacket%3e%3cSessionToken%3e42%3c%2fSessionToken%3e%3cKeywords%3eRuby%3c%2fKeywords%3e%3cPageNumber%3e2%3c%2fPageNumber%3e%3c%2fPacket%3e').to_return(:body => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<string xmlns=\"http://ws.careerbuilder.com/resumes/\"><Packet><Errors/><PageNumber>2</PageNumber><SearchTime>06/25/2010 12:03:14</SearchTime><FirstRec>1</FirstRec><LastRec>100</LastRec><Hits>4</Hits><MaxPage>2</MaxPage><Results><ResumeResultItem_V3><ContactEmail>Rhd4G067G4JVTLW99H7_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com</ContactEmail><ContactName>Michael Guterl</ContactName><HomeLocation>US-OH-Loveland</HomeLocation><LastUpdate>2010/5/13</LastUpdate><ResumeTitle>BERNARD_SYSTEMS_ENGINEER</ResumeTitle><JobTitle>BERNARD_SYSTEMS_ENGINEER</JobTitle><RecentEmployer>TATA CONSULTANCY SERVICES</RecentEmployer><RecentJobTitle>CONSULTANCY SERVICES- Systems Engineer</RecentJobTitle><RecentPay>0</RecentPay><ResumeID>RD52G867678F7GH0123</ResumeID><UserDID>U7X86R61VVKS4FWS03T</UserDID><ContactEmailMD5>139013c2fa2b945bdc340f8a698b009e</ContactEmailMD5></ResumeResultItem_V3></Results></Packet></string>")
|
|
8
|
+
stub_request(:post, "http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch").with(:body => 'Packet=%3cPacket%3e%3cSessionToken%3e42%3c%2fSessionToken%3e%3cKeywords%3eRuby%3c%2fKeywords%3e%3cPageNumber%3e1%3c%2fPageNumber%3e%3cRowsPerPage%3e500%3c%2fRowsPerPage%3e%3c%2fPacket%3e').to_return(:body => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<string xmlns=\"http://ws.careerbuilder.com/resumes/\"><Packet><Errors /><PageNumber>1</PageNumber><SearchTime>06/25/2010 12:03:14</SearchTime><FirstRec>1</FirstRec><LastRec>100</LastRec><Hits>4</Hits><MaxPage>2</MaxPage><Results><ResumeResultItem_V3><ContactEmail>Rhd4G067G4JVTLW99H7_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com</ContactEmail><ContactName>Rebecca Bernard</ContactName><HomeLocation>US-OH-Milford</HomeLocation><LastUpdate>2010/5/13</LastUpdate><ResumeTitle>BERNARD_SYSTEMS_ENGINEER</ResumeTitle><JobTitle>BERNARD_SYSTEMS_ENGINEER</JobTitle><RecentEmployer>TATA CONSULTANCY SERVICES</RecentEmployer><RecentJobTitle>CONSULTANCY SERVICES- Systems Engineer</RecentJobTitle><RecentPay>0</RecentPay><ResumeID>Rhd4G067G4JVTLW99H7</ResumeID><UserDID>U7X86R61VVKS4FWS03T</UserDID><ContactEmailMD5>139013c2fa2b945bdc340f8a698b009e</ContactEmailMD5></ResumeResultItem_V3><ResumeResultItem_V3><ContactEmail>Rhe7TZ764LHG1GQTPSM_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com</ContactEmail><ContactName>chris grader</ContactName><HomeLocation>US-OH-Milford</HomeLocation><LastUpdate>2010/6/4</LastUpdate><ResumeTitle>Chris Grader resume</ResumeTitle><JobTitle>Chris Grader resume</JobTitle><RecentEmployer>Millennial Medical, Inc</RecentEmployer><RecentJobTitle>Regional Sales Manager/Midwest Distributor</RecentJobTitle><RecentPay>0</RecentPay><ResumeID>Rhe7TZ764LHG1GQTPSM</ResumeID><UserDID>U346V1MKGCHPGCF9S8</UserDID><ContactEmailMD5>cfba57bf848b78211d99348cf0f90879</ContactEmailMD5></ResumeResultItem_V3><ResumeResultItem_V3><ContactEmail>RH52G867678F7GH02Q3_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com</ContactEmail><ContactName>Jeffrey Davis</ContactName><HomeLocation>US-OH-Goshen</HomeLocation><LastUpdate>2010/5/23</LastUpdate><ResumeTitle>Warehouse Distribution Specialist</ResumeTitle><JobTitle>Warehouse Distribution Specialist</JobTitle><RecentEmployer>OWENS &amp; MINOR</RecentEmployer><RecentJobTitle>Warehouse Lead Supervisor</RecentJobTitle><RecentPay>35776</RecentPay><ResumeID>RH52G867678F7GH02Q3</ResumeID><UserDID>U1C29V68M3YM95SP0XK</UserDID><ContactEmailMD5>e814ebaa93aae5c3719e27d26d5af917</ContactEmailMD5></ResumeResultItem_V3></Results></Packet></string>")
|
|
9
|
+
stub_request(:post, "http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch").with(:body => 'Packet=%3cPacket%3e%3cSessionToken%3e42%3c%2fSessionToken%3e%3cKeywords%3eRuby%3c%2fKeywords%3e%3cPageNumber%3e2%3c%2fPageNumber%3e%3cRowsPerPage%3e500%3c%2fRowsPerPage%3e%3c%2fPacket%3e').to_return(:body => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<string xmlns=\"http://ws.careerbuilder.com/resumes/\"><Packet><Errors/><PageNumber>2</PageNumber><SearchTime>06/25/2010 12:03:14</SearchTime><FirstRec>1</FirstRec><LastRec>100</LastRec><Hits>4</Hits><MaxPage>2</MaxPage><Results><ResumeResultItem_V3><ContactEmail>Rhd4G067G4JVTLW99H7_A7C14Q67VKG000YBSCR~CBWS^U7A3LY6YY46V1MT0RJK@resume.cbdr.com</ContactEmail><ContactName>Michael Guterl</ContactName><HomeLocation>US-OH-Loveland</HomeLocation><LastUpdate>2010/5/13</LastUpdate><ResumeTitle>BERNARD_SYSTEMS_ENGINEER</ResumeTitle><JobTitle>BERNARD_SYSTEMS_ENGINEER</JobTitle><RecentEmployer>TATA CONSULTANCY SERVICES</RecentEmployer><RecentJobTitle>CONSULTANCY SERVICES- Systems Engineer</RecentJobTitle><RecentPay>0</RecentPay><ResumeID>RD52G867678F7GH0123</ResumeID><UserDID>U7X86R61VVKS4FWS03T</UserDID><ContactEmailMD5>139013c2fa2b945bdc340f8a698b009e</ContactEmailMD5></ResumeResultItem_V3></Results></Packet></string>")
|
|
10
|
+
stub_request(:post, "http://ws.careerbuilder.com/resumes/resumes.asmx/V2_AdvancedResumeSearch").
|
|
11
|
+
with(:body => "Packet=%3cPacket%3e%3cSessionToken%3e42%3c%2fSessionToken%3e%3cKeywords%3eRuby%3c%2fKeywords%3e%3cPageNumber%3e3%3c%2fPageNumber%3e%3cRowsPerPage%3e500%3c%2fRowsPerPage%3e%3c%2fPacket%3e").
|
|
12
|
+
to_return(:body => "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<string xmlns=\"http://ws.careerbuilder.com/resumes/\"><Packet><Errors/><PageNumber>2</PageNumber><SearchTime>06/25/2010 12:03:14</SearchTime><FirstRec>1</FirstRec><LastRec>100</LastRec><Hits>4</Hits><MaxPage>2</MaxPage><Results></Results></Packet></string>")
|
|
13
|
+
|
|
10
14
|
@client = CareerBuilder::Client.new("valid_email", "valid_password")
|
|
11
15
|
@client.stub(:session_token).and_return(42)
|
|
12
16
|
@client.stub(:authenticate).and_return(true)
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: career_builder
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 23
|
|
5
5
|
prerelease: false
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
version: 0.
|
|
8
|
+
- 2
|
|
9
|
+
- 0
|
|
10
|
+
version: 0.2.0
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- Michael Guterl
|
|
@@ -15,7 +15,7 @@ autorequire:
|
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2011-
|
|
18
|
+
date: 2011-03-31 00:00:00 -04:00
|
|
19
19
|
default_executable:
|
|
20
20
|
dependencies:
|
|
21
21
|
- !ruby/object:Gem::Dependency
|
|
@@ -166,13 +166,12 @@ files:
|
|
|
166
166
|
- lib/career_builder/api/shift_preference.rb
|
|
167
167
|
- lib/career_builder/api/word_document.rb
|
|
168
168
|
- lib/career_builder/client.rb
|
|
169
|
+
- lib/career_builder/client/advanced_resume_search.rb
|
|
170
|
+
- lib/career_builder/client/authentication.rb
|
|
171
|
+
- lib/career_builder/client/get_resume.rb
|
|
172
|
+
- lib/career_builder/client/request.rb
|
|
173
|
+
- lib/career_builder/client/resume_actions_remaining_today.rb
|
|
169
174
|
- lib/career_builder/errors.rb
|
|
170
|
-
- lib/career_builder/request.rb
|
|
171
|
-
- lib/career_builder/request/authenticated.rb
|
|
172
|
-
- lib/career_builder/requests/advanced_resume_search.rb
|
|
173
|
-
- lib/career_builder/requests/authentication.rb
|
|
174
|
-
- lib/career_builder/requests/get_resume.rb
|
|
175
|
-
- lib/career_builder/requests/resume_actions_remaining_today.rb
|
|
176
175
|
- lib/career_builder/resume.rb
|
|
177
176
|
- lib/career_builder/resume/lazy_collection.rb
|
|
178
177
|
- spec/career_builder/client_spec.rb
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
module CareerBuilder
|
|
2
|
-
|
|
3
|
-
class Request
|
|
4
|
-
|
|
5
|
-
RESUME_SERVICE_ENDPOINT_URL = 'http://ws.careerbuilder.com/resumes/resumes.asmx'
|
|
6
|
-
|
|
7
|
-
attr_reader :options, :client
|
|
8
|
-
|
|
9
|
-
def initialize(client, options = {})
|
|
10
|
-
@client, @options = client, options
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def perform
|
|
14
|
-
validate_options if defined?(self.class.const_get(:VALID_OPTIONS))
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
private
|
|
18
|
-
|
|
19
|
-
def validate_options
|
|
20
|
-
raise ArgumentError, "Invalid options #{invalid_options}" unless valid_options?
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def invalid_options
|
|
24
|
-
(options.keys - self.class.const_get(:VALID_OPTIONS))
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def valid_options?
|
|
28
|
-
invalid_options.empty?
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def session_token
|
|
32
|
-
client.session_token
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def parse_terrible_response(response)
|
|
36
|
-
xml_body = Nokogiri::XML(response.body) # not sure why I have to do it this way
|
|
37
|
-
inner_xml = xml_body.children.first
|
|
38
|
-
inner_xml.text
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
CUSTOM_KEY_TRANSFORMS = {
|
|
42
|
-
:resume_id => "ResumeID",
|
|
43
|
-
:account_did => "AccountDID"
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
def transform_key(key)
|
|
47
|
-
if custom_transform = CUSTOM_KEY_TRANSFORMS[key]
|
|
48
|
-
custom_transform
|
|
49
|
-
else
|
|
50
|
-
key.to_s.camelize
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def transform_key_value_to_tag(key, value)
|
|
55
|
-
"<#{transform_key(key)}>#{value}</#{transform_key(key)}>"
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def transform_options_to_xml(options)
|
|
59
|
-
elements = []
|
|
60
|
-
|
|
61
|
-
# let's make sure SessionToken is always at the top of the request
|
|
62
|
-
if session_key = options.delete(:session_token)
|
|
63
|
-
elements << transform_key_value_to_tag(:session_token, session_token)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
options.sort_by { |k, v| k.to_s }.each do |key, value|
|
|
67
|
-
elements << transform_key_value_to_tag(key, value)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
elements.join
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def perform_request(method, packet_contents)
|
|
74
|
-
parse_terrible_response Net::HTTP.post_form(URI.parse(RESUME_SERVICE_ENDPOINT_URL + "/#{method}"), 'Packet' => "<Packet>#{packet_contents}</Packet>")
|
|
75
|
-
rescue Errno::ECONNRESET
|
|
76
|
-
warn "The connection was reset, retrying"
|
|
77
|
-
retry
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
end
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
module CareerBuilder
|
|
2
|
-
|
|
3
|
-
class Request::Authenticated < Request
|
|
4
|
-
|
|
5
|
-
def perform
|
|
6
|
-
super
|
|
7
|
-
require_authentication
|
|
8
|
-
options.merge!(:session_token => session_token) unless options.has_key?(:session_token)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
private
|
|
12
|
-
|
|
13
|
-
def require_authentication
|
|
14
|
-
if !client.authenticated?
|
|
15
|
-
unless client.authenticate
|
|
16
|
-
raise InvalidCredentials
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
module CareerBuilder
|
|
2
|
-
|
|
3
|
-
module Requests
|
|
4
|
-
|
|
5
|
-
class Authentication < Request
|
|
6
|
-
|
|
7
|
-
def perform
|
|
8
|
-
response = perform_request("BeginSessionV2", "<Email>#{options[:email]}</Email><Password>#{options[:password]}</Password>")
|
|
9
|
-
packet = Nokogiri::XML(response)
|
|
10
|
-
|
|
11
|
-
if session_token = packet.search("//SessionToken")
|
|
12
|
-
session_token_text = session_token.text
|
|
13
|
-
if session_token_text == "Invalid"
|
|
14
|
-
return nil
|
|
15
|
-
else
|
|
16
|
-
return session_token_text
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
module CareerBuilder
|
|
2
|
-
|
|
3
|
-
module Requests
|
|
4
|
-
|
|
5
|
-
class ResumeActionsRemainingToday < Request::Authenticated
|
|
6
|
-
|
|
7
|
-
VALID_OPTIONS = [:account_did]
|
|
8
|
-
|
|
9
|
-
def perform
|
|
10
|
-
super
|
|
11
|
-
response = perform_request("V2_ResumeActionsRemainingToday", transform_options_to_xml(options))
|
|
12
|
-
|
|
13
|
-
doc = Nokogiri::XML(response)
|
|
14
|
-
doc.xpath("//Packet").text.to_i
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
end
|