fedtechjobber 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 764895accee6e01c5f6b7b75767b87ae1e7ae58f
4
+ data.tar.gz: e5cb0eb39f5a691008e8f894dfadfcba9a2b9016
5
+ SHA512:
6
+ metadata.gz: 9a5d5309d3ad4a4e4a10699cf40591678b0f915dab58f03595d584f207cefdf19ae2482c4bdc198039c8e7eb8c3b9842d3d78ba792bc0715471ea4c8017e4c91
7
+ data.tar.gz: 0bb68b86f233c9395f546cc0819795b9a81e5cce48dfc74cd223c55fff7062a205f22f9445f8e4d3ac2754ca934acad9c9c60d4a581cc01518f82656d8e22725
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rest-client'
4
+ gem 'ruby-gmail'
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Craig Schneider - Excella Consulting, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ ## Overview
2
+
3
+ fedtechjobber is a simple command line Ruby program that queries the USAJobs API for open tech federal job postings and generates/emails an HTML report displaying available job data along with any available agency GitHub profiles (via USA.gov's Social Media API - http://registry.usa.gov/accounts?service_id=github). The following (optional) search criteria from USAJobs can be used (https://data.usajobs.gov/Rest):
4
+ * Job title
5
+ * Min salary
6
+ * State
7
+ * Country
8
+ * Min grade
9
+ * Keywords
10
+
11
+ If you want the results emailed:
12
+ * Gmail user id
13
+ * Gmail password
14
+ * To address
15
+
16
+ Credentials are sent via TLS to Google.
17
+
18
+ Tested on Ruby 2.0.
19
+
20
+ ## Install and Execution
21
+
22
+ Install as a Ruby gem.
23
+
24
+ $ gem install fedtechjobber
25
+
26
+ Execution format:
27
+
28
+ $ fedtechjobber -t<title, use single quotes if multiple words> -m<min salary> -s<state> -c<country> -g<min grade> -k<keywords, one or more separated with comma for AND search> -o<keywords, one or more separated with comma for OR search> -u<gmail user id> -p<gmail password> -e<email to address>
29
+
30
+ Example:
31
+
32
+ $ fedtechjobber -t'IT Specialist' -m60000 -c'United States' -opython,ruby,groovy,scala,java -ubob -pbobpasswd -ebob@bob.com
33
+
34
+ Generates a fedtechjobber.html report in the working directory.
35
+
36
+ ## Work from source
37
+ $ gem install bundler
38
+ $ bundle install
39
+
40
+ ## Unit test execution
41
+ $ rake test
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'ci/reporter/rake/minitest'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['lib/*.rb']
8
+ t.verbose = true
9
+ end
data/bin/fedtechjobber ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ $:.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
5
+ require 'fedtechjobber'
6
+ require 'optparse'
7
+ require 'ostruct'
8
+
9
+ # parse command line args
10
+ @args = OpenStruct.new
11
+ OptionParser.new do |opts|
12
+ opts.on('-title') do |t|
13
+ @args.title = t
14
+ end
15
+ opts.on('-min_salary') do |m|
16
+ @args.min_salary = m
17
+ end
18
+ opts.on('-state') do |s|
19
+ @args.state = s
20
+ end
21
+ opts.on('-country') do |c|
22
+ @args.country = c
23
+ end
24
+ opts.on('-grade') do |g|
25
+ @args.min_grade = g
26
+ end
27
+ opts.on('-keyword,keyword,keyword,keyword,keyword', Array) do |k|
28
+ @args.keywords = k
29
+ end
30
+ opts.on('-okeyword,keyword,keyword,keyword,keyword,keyword,keyword', Array) do |o|
31
+ @args.keywords_or = o
32
+ end
33
+ opts.on('-ugmail_usr') do |u|
34
+ @args.gmail_usr = u
35
+ end
36
+ opts.on('-pgmail_pwd') do |p|
37
+ @args.gmail_pwd = p
38
+ end
39
+ opts.on('-email_to_addr') do |e|
40
+ @args.email_to_addr = e
41
+ end
42
+ end.parse!
43
+
44
+ FedTechJobber.new(@args).save_and_email
data/lib/client/api.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'rest_client'
2
+
3
+ module API
4
+
5
+ def get_data(uri, params)
6
+ response = RestClient.get(uri, {accept: :json,params: params})
7
+ end
8
+
9
+ end
@@ -0,0 +1,18 @@
1
+ require 'gmail'
2
+
3
+ module Email
4
+
5
+ def send_email(user, pwd, to)
6
+ Gmail.new(user, pwd) do |gmail|
7
+ gmail.deliver do
8
+ to to
9
+ subject "fedtechjobber - new jobs"
10
+ html_part do
11
+ body '<p>New job info has been sent, see attached report</p>'
12
+ end
13
+ add_file 'fedtechjobber.html'
14
+ end
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,6 @@
1
+ class JobData
2
+
3
+ attr_accessor :id, :title, :agency_name, :agency_sub, :agency_display, :salary, :series_grade, :eligibility, :position, :locations, :url, :dates, :summary, :github_url
4
+
5
+ end
6
+
@@ -0,0 +1,97 @@
1
+ class Request
2
+
3
+ attr_reader :params_arr
4
+
5
+ def initialize(args)
6
+ @jobs = []
7
+ @title = args.title
8
+ @min_salary = args.min_salary
9
+ @state = args.state
10
+ @country = args.country
11
+ @min_grade = args.min_grade
12
+ @keywords = args.keywords
13
+ @keywords_or = args.keywords_or
14
+ @gmail_usr = args.gmail_usr
15
+ @gmail_pwd = args.gmail_pwd
16
+ @email_to_addr = args.email_to_addr
17
+ @params_arr = Array.new
18
+ build_params
19
+
20
+ @usajobs_uri = 'https://data.usajobs.gov/api/jobs'
21
+ @usagov_uri = 'http://registry.usa.gov/accounts.json'
22
+ @usagov_params = {'service_id' => 'github'}
23
+ end
24
+
25
+ def build_params
26
+ params = {}
27
+ unless @title.nil?
28
+ params.merge!('Title' => @title)
29
+ end
30
+ unless @min_salary.nil?
31
+ params.merge!('MinSalary' => @min_salary)
32
+ end
33
+ unless @state.nil?
34
+ params.merge!('CountrySubDivision' => @state)
35
+ end
36
+ unless @country.nil?
37
+ params.merge!('Country' => @country)
38
+ end
39
+ unless @min_grade.nil?
40
+ params.merge!('GradeLow' => @min_grade)
41
+ end
42
+
43
+ build_keywords_params(params)
44
+ end
45
+
46
+ def build_keywords_params(params)
47
+ # only one of keywords or keywords_or is allowed as a param
48
+ if @keywords.nil? && @keywords_or.nil?
49
+ @params_arr << params
50
+ elsif !@keywords.nil?
51
+ keyword = ''
52
+ @keywords.each_with_index do |x,i|
53
+ i == 0 ? keyword = x : keyword << " #{x}"
54
+ end
55
+ params.merge!('Keyword' => keyword)
56
+ @params_arr << params
57
+ elsif !@keywords_or.nil?
58
+ @keywords_or.each do |x|
59
+ new_params = params.clone
60
+ new_params['Keyword'] = x
61
+ @params_arr << new_params
62
+ end
63
+ end
64
+ end
65
+
66
+ def get_jobs
67
+ usagov_response = get_data(@usagov_uri, @usagov_params)
68
+ jobs = []
69
+
70
+ # at the time, keyword OR searches are not supported by usajobs. so need to make multiple calls for each OR keyword.
71
+ # if keyword not provided or only one keyword, there will only be one entry in this array.
72
+ @params_arr.each do |x|
73
+ jobs = Response.new(get_data(@usajobs_uri, x), usagov_response).jobs
74
+ if @jobs.length == 0
75
+ @jobs << jobs
76
+ else
77
+ jobs.each do |x|
78
+ matches = @jobs.select {|job_data| job_data.id == x.id }
79
+ if matches.length == 0
80
+ @jobs << x
81
+ end
82
+ end
83
+ end
84
+ @jobs.flatten!
85
+ end
86
+
87
+ @jobs
88
+ end
89
+
90
+ def email
91
+ unless @gmail_usr.nil? || @gmail_pwd.nil? || @email_to_addr.nil?
92
+ send_email(@gmail_usr, @gmail_pwd, @email_to_addr)
93
+ end
94
+ end
95
+
96
+ end
97
+
@@ -0,0 +1,81 @@
1
+ require 'json'
2
+
3
+ class Response
4
+
5
+ attr_reader :jobs
6
+
7
+ def initialize(usajobs_response, usagov_response)
8
+ @jobs = [] # array of JobData objects
9
+ parse_usajobs(usajobs_response)
10
+ @jobs.uniq!
11
+ parse_usagov(usagov_response)
12
+ end
13
+
14
+ def parse_usajobs(response)
15
+ response_hash = JSON.parse(response)
16
+
17
+ response_hash['JobData'].each do |x|
18
+ job_data = JobData.new
19
+ job_data.id = x['AnnouncementNumber']
20
+ job_data.title = x['JobTitle']
21
+ job_data.agency_name = x['OrganizationName']
22
+ job_data.agency_sub = x['AgencySubElement']
23
+ job_data.agency_display = x['OrganizationName']+' - '+x['AgencySubElement']
24
+ job_data.salary = x['SalaryMin']+' - '+x['SalaryMax']+' '+x['SalaryBasis']
25
+ job_data.series_grade = x['PayPlan']+'-'+x['Series']+'-'+x['Grade']
26
+ job_data.eligibility = x['WhoMayApplyText']
27
+ job_data.position = x['WorkSchedule']+' - '+x['WorkType']
28
+ job_data.locations = x['Locations']
29
+ job_data.url = x['ApplyOnlineURL']
30
+ job_data.dates = x['StartDate']+' - '+x['EndDate']
31
+ job_data.summary = x['JobSummary']
32
+
33
+ @jobs << job_data
34
+ end
35
+
36
+ end
37
+
38
+ def parse_usagov(response)
39
+ response_hash = JSON.parse(response)
40
+
41
+ @jobs.each do |job| # for each job in the result set
42
+
43
+ response_hash['accounts'].each do |acct| # for each github account, see if there's a match
44
+
45
+ acct['agencies'].each do |agency|
46
+
47
+ match_agency(job, acct, agency)
48
+
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def match_agency(job, acct, agency)
55
+ agency_name = job.agency_name
56
+ agency_sub = job.agency_sub
57
+ github_agency_id = agency['agency_id']
58
+ github_agency_name = agency['agency_name']
59
+ github_org_name = acct['organization']
60
+ github_acct = acct['account']
61
+
62
+ if
63
+ github_agency_name.include?(agency_name) ||
64
+ github_agency_name.include?(agency_sub) ||
65
+ github_org_name.include?(agency_name) ||
66
+ github_org_name.include?(agency_sub) ||
67
+ agency_name.include?(github_agency_name) ||
68
+ agency_name.include?(github_org_name) ||
69
+ agency_sub.include?(github_agency_name) ||
70
+ agency_sub.include?(github_org_name) ||
71
+ agency_name.include?(github_agency_id) ||
72
+ agency_sub.include?(github_agency_id) ||
73
+ agency_name.include?(github_acct) ||
74
+ agency_sub.include?(github_acct)
75
+
76
+ job.github_url = acct['service_url']
77
+ end
78
+ end
79
+
80
+ end
81
+
@@ -0,0 +1,134 @@
1
+ module Display
2
+
3
+ # get html output to render
4
+ def get_display()
5
+ %{
6
+ <!doctype html>
7
+ <html>
8
+ <head>
9
+ <title>FedTechJobber Jobs Report</title>
10
+
11
+ <meta name="viewport" content="width=device-width">
12
+
13
+ <style>
14
+ body {
15
+ font-family: Tahoma, Verdana, Arial, sans-serif;
16
+ color: #333;
17
+ background: #ccc;
18
+ }
19
+ article {
20
+ background: #eee;
21
+ padding: 1em;
22
+ }
23
+ @media screen and (min-width: 1020px) {
24
+ article {
25
+ width: 1000px;
26
+ border: 0.2em solid #aaa;
27
+ margin: auto;
28
+ }
29
+ }
30
+ @media screen and (max-width: 1019px) {
31
+ body {
32
+ margin: 0;
33
+ padding: 0;
34
+ }
35
+ }
36
+ article section {
37
+ margin-bottom: 2em;
38
+ }
39
+ h1 {
40
+ font-weight: normal;
41
+ border-bottom: 0.1em solid #aaa;
42
+ padding-bottom: 0.3em;
43
+ position: relative;
44
+ }
45
+ h1 aside {
46
+ font-size: 0.7em;
47
+ float: right;
48
+ }
49
+ h2 {
50
+ font-weight: normal;
51
+ font-size: 1.2em;
52
+ border-bottom: 0.1em solid #aaa;
53
+ padding-bottom: 0.2em;
54
+ }
55
+ text {
56
+ font-weight: normal;
57
+ font-size: .8em;
58
+ padding-bottom: 0.2em;
59
+ }
60
+ div.column {
61
+ display: inline-block;
62
+ margin-right: 3em;
63
+ vertical-align: top;
64
+ }
65
+ .field {
66
+ margin-bottom: 0.2em;
67
+ }
68
+ .field .label {
69
+ font-weight: bold;
70
+ width: 10em;
71
+ text-align: right;
72
+ display: inline-block;
73
+ }
74
+ .field .label:after {
75
+ content: ":";
76
+ }
77
+ .field .val {
78
+ padding-left: 1em;
79
+ }
80
+ div.chart {
81
+ text-align: center;
82
+ }
83
+ div.left-chart {
84
+ text-align: left;
85
+ }
86
+ </style>
87
+
88
+ </head>
89
+
90
+ <body>
91
+ <article>
92
+ <header>
93
+ <h1>
94
+ <b>FedTechJobber Jobs Report:</b>
95
+ <aside>
96
+ <%= @date.strftime('%A, %d %B %Y %T') %>
97
+ </aside>
98
+ </h1>
99
+ </header>
100
+ <section id="jobs">
101
+ <text><b>Search params: </b><%= @request.params_arr %></text><br><br>
102
+ <% @jobs.each do |job| %>
103
+ <h2><b><%= job.title %></b></h2>
104
+ <table width="100%">
105
+ <tr><td width="15%"><text><b>Agency:</b></text></td><td><text><%= job.agency_display %></text></td></tr>
106
+ <tr><td width="15%"><text><b>Salary:</b></text></td><td><text><b><%= job.salary %></b></text></td></tr>
107
+ <tr><td width="15%"><text><b>Series Grade:</b></text></td><td><text><%= job.series_grade %></text></td></tr>
108
+ <tr><td width="15%"><text><b>Eligibility:</b></text></td><td><text><%= job.eligibility %></text></td></tr>
109
+ <tr><td width="15%"><text><b>Position:</b></text></td><td><text><%= job.position %></text></td></tr>
110
+ <tr><td width="15%"><text><b>Location(s):</b></text></td><td><text><%= job.locations %></text></td></tr>
111
+ <tr><td width="15%"><text><b>Full details:</b></text></td><td><text><a href='<%= job.url %>'>click here</a></text></td></tr>
112
+ <tr><td width="15%"><text><b>Posting dates:</b></text></td><td><text><%= job.dates %></text></td></tr>
113
+ <tr><td width="15%"><text><b>Summary:</b></text></td><td><text><%= job.summary %></text></td></tr>
114
+ <tr><td width="15%"><text><b>Public GitHub profile:</b></text></td>
115
+ <td>
116
+ <text>
117
+ <% if job.github_url.nil? %>
118
+ none
119
+ <% else %>
120
+ <a href='<%= job.github_url %>'><%= job.github_url %></a>
121
+ <% end %>
122
+ </text>
123
+ </td>
124
+ </tr>
125
+ </table>
126
+ <br><br>
127
+ <% end %>
128
+ </section>
129
+ </article>
130
+ </body>
131
+ </html>
132
+ }
133
+ end
134
+ end
@@ -0,0 +1,38 @@
1
+ require 'erb'
2
+ require_relative 'client/api'
3
+ require_relative 'client/email'
4
+ require_relative 'data/request'
5
+ require_relative 'data/response'
6
+ require_relative 'data/job_data'
7
+ require_relative 'display/display'
8
+
9
+ include API
10
+ include Email
11
+ include Display
12
+
13
+ class FedTechJobber
14
+ include ERB::Util
15
+ attr_accessor :template, :date, :request, :jobs
16
+
17
+ def initialize(args)
18
+ @request = Request.new(args)
19
+ @template = get_display
20
+ @date = Time.now
21
+ @jobs = @request.get_jobs
22
+ @file = 'fedtechjobber.html'
23
+ end
24
+
25
+ def render
26
+ ERB.new(@template).result(binding)
27
+ end
28
+
29
+ def save_and_email
30
+ File.open(@file, 'w+') do |f|
31
+ f.write(render)
32
+ end
33
+ puts 'Done saving '+@file
34
+ @request.email
35
+ end
36
+
37
+ end
38
+
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fedtechjobber
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Craig Schneider
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: " fedtechjobber is a simple command line utility that queries the
14
+ USAJobs API for open tech federal job \n postings and generates/emails an HTML
15
+ report displaying available job data along with any available agency \n GitHub
16
+ profiles (via USA.gov's Social Media API). \n"
17
+ email:
18
+ - craig.schneider@excella.com
19
+ executables:
20
+ - fedtechjobber
21
+ extensions: []
22
+ extra_rdoc_files: []
23
+ files:
24
+ - Gemfile
25
+ - LICENSE
26
+ - README.md
27
+ - Rakefile
28
+ - bin/fedtechjobber
29
+ - lib/fedtechjobber.rb
30
+ - lib/client/api.rb
31
+ - lib/client/email.rb
32
+ - lib/data/job_data.rb
33
+ - lib/data/request.rb
34
+ - lib/data/response.rb
35
+ - lib/display/display.rb
36
+ homepage: https://github.com/excellaco
37
+ licenses:
38
+ - MIT
39
+ metadata: {}
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubyforge_project:
56
+ rubygems_version: 2.0.3
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: A command line tool to search the USAJobs API for jobs and USA.gov for matching
60
+ GitHub profiles.
61
+ test_files: []