fedtechjobber 1.0.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.
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: []