career_builder 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|