arbetsformedlingen 0.6.0 → 0.7.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 +4 -4
- data/.hound.yml +2 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.md +10 -0
- data/README.md +60 -136
- data/bin/seed +17 -0
- data/examples/post_job_ad.rb +107 -0
- data/lib/arbetsformedlingen.rb +2 -0
- data/lib/arbetsformedlingen/api/base_soap_client.rb +51 -0
- data/lib/arbetsformedlingen/api/client.rb +2 -1
- data/lib/arbetsformedlingen/api/ledigtarbete_client.rb +1 -1
- data/lib/arbetsformedlingen/api/ontology_client.rb +109 -0
- data/lib/arbetsformedlingen/api/request.rb +35 -5
- data/lib/arbetsformedlingen/api/response.rb +4 -1
- data/lib/arbetsformedlingen/api/results/ad_result.rb +8 -0
- data/lib/arbetsformedlingen/api/soap_request.rb +2 -2
- data/lib/arbetsformedlingen/api/taxonomy_client.rb +797 -0
- data/lib/arbetsformedlingen/api/ws_occupation_client.rb +59 -43
- data/lib/arbetsformedlingen/codes/occupation_code.rb +2 -3
- data/lib/arbetsformedlingen/soap_builder.rb +7 -0
- data/lib/arbetsformedlingen/version.rb +2 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15dfcdcd827c97239a8d14df13084de7bc96980824b7304efb5ddb4d11d640bd
|
4
|
+
data.tar.gz: 56eaa06682c5b5b7b31cf6f0ba21e12a657f1a92bbfa1622530fc1ba4f6fc37b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24713c7b92467e96a039bb6e68a5f91eebdc8e7ccef3288af4844998ce4f28baff1d9d2fa2b982358d1384b69da2970e0e8b66924c9ca6ef2e103ce9afc8e4f3
|
7
|
+
data.tar.gz: 790862d6b086c93e9a98cdcca33440a6d742bafcc13360dc1c20bf86d9b000594045f83903c52b25e34f6c114c2036d066bfa213a70786dc59749dc9da43b76a
|
data/.hound.yml
ADDED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
# v0.7.0
|
4
|
+
|
5
|
+
This is a pretty big release that adds support Ontology and Taxonomy APIs and completes WSOccupation :tada:
|
6
|
+
|
7
|
+
* Implement Ontology API
|
8
|
+
* Implement Taxonomy API (84 endpoints!)
|
9
|
+
* Implement remaining WSOccupation API endpoints
|
10
|
+
* Add `Response#uri` method
|
11
|
+
* Improved documentation
|
12
|
+
|
3
13
|
# v0.6.0
|
4
14
|
|
5
15
|
* Return "empty result" object when no results are found
|
data/README.md
CHANGED
@@ -2,36 +2,17 @@
|
|
2
2
|
|
3
3
|
Arbetsförmedlingen API client (Swedish Public Employment Service).
|
4
4
|
|
5
|
-
__Features__
|
6
|
-
* Post job ad (a.k.a Direktöverförda annonser)
|
7
|
-
* Platsannons API Client
|
8
|
-
* WSOccupation SOAP API Client
|
9
|
-
|
10
|
-
|
11
5
|
__Index__
|
12
6
|
* [Installation](#installation)
|
13
|
-
* [
|
14
|
-
* [
|
15
|
-
|
7
|
+
* [Post job ad](#post-job-ad) (a.k.a Direktöverförda annonser)
|
8
|
+
* [API clients for](#api-clients)
|
9
|
+
+ [Platsannonser/Platsbanken](#api-clients)
|
10
|
+
* [Ontology](#ontology-api-client)
|
11
|
+
* [Taxonomy (SOAP)](#taxonomy-api-client)
|
12
|
+
* [WSOccupation (SOAP)](#wsoccupation-api-client)
|
16
13
|
* [RDoc](http://www.rubydoc.info/gems/arbetsformedlingen/).
|
17
14
|
|
18
|
-
##
|
19
|
-
|
20
|
-
Add this line to your application's Gemfile:
|
21
|
-
|
22
|
-
```ruby
|
23
|
-
gem 'arbetsformedlingen'
|
24
|
-
```
|
25
|
-
|
26
|
-
And then execute:
|
27
|
-
|
28
|
-
$ bundle
|
29
|
-
|
30
|
-
Or install it yourself as:
|
31
|
-
|
32
|
-
$ gem install arbetsformedlingen
|
33
|
-
|
34
|
-
## API Client
|
15
|
+
## API Clients
|
35
16
|
|
36
17
|
__Create a client:__
|
37
18
|
|
@@ -63,121 +44,21 @@ end
|
|
63
44
|
|
64
45
|
## Post job ad
|
65
46
|
|
47
|
+
:warning: In order to post live job ads to Arbetsförmedlingen you need to contact them and go through a test procedure. You can find their own documentation and some additional notes [here](https://goo.gl/c5jtBv).
|
48
|
+
|
49
|
+
You can find Arbetsförmedlingens own documentation and some additional notes [here](https://goo.gl/c5jtBv). Note that the documentation provided by Arbetsförmedlingen can be pretty hard to follow.
|
50
|
+
|
51
|
+
__Validation support__
|
52
|
+
All models used to create a job ad include validations. _A lot_ of work was put into finding all the quirks in the API and adding each validation to its corresponding model. I can't recommend using it enough.
|
53
|
+
|
66
54
|
__Complete example creating a packet__
|
67
55
|
|
68
|
-
|
56
|
+
There's a lot of data you can/must send to the API when creating an ad. See files in `lib/arbetsformedlingen/models` for details.
|
69
57
|
|
70
|
-
|
71
|
-
require 'date'
|
72
|
-
require 'arbetsformedlingen'
|
73
|
-
|
74
|
-
include Arbetsformedlingen # just for brevity
|
75
|
-
|
76
|
-
document = Document.new(
|
77
|
-
customer_id: 'XXXYYYZZZ',
|
78
|
-
email: 'a@example.com'
|
79
|
-
)
|
80
|
-
|
81
|
-
company = Company.new(
|
82
|
-
name: 'ACME AB',
|
83
|
-
cin: 'XXYYZZXXYY',
|
84
|
-
description: 'A company description',
|
85
|
-
address: {
|
86
|
-
country_code: 'SE',
|
87
|
-
zip: '11356',
|
88
|
-
municipality: 'Stockholm',
|
89
|
-
street: 'Birger Jarlsgatan 57',
|
90
|
-
city: 'stockholm'
|
91
|
-
}
|
92
|
-
)
|
93
|
-
|
94
|
-
publication = Publication.new(
|
95
|
-
publish_at_date: Date.today,
|
96
|
-
name: 'John Doe',
|
97
|
-
email: 'john@example.com'
|
98
|
-
)
|
99
|
-
|
100
|
-
schedule = Schedule.new(
|
101
|
-
full_time: false,
|
102
|
-
summary: '3 days a week 8.00-17.00',
|
103
|
-
start_date: Date.today,
|
104
|
-
end_date: nil
|
105
|
-
)
|
106
|
-
|
107
|
-
salary = Salary.new(
|
108
|
-
currency: 'SEK',
|
109
|
-
type: :fixed, # :fixed, :fixed_and_commission, :commission
|
110
|
-
summary: 'Your salary will be...'
|
111
|
-
)
|
112
|
-
|
113
|
-
qualifications = []
|
114
|
-
qualifications << Qualification.new(
|
115
|
-
summary: 'A summary', # optional, but recommended field
|
116
|
-
required: true,
|
117
|
-
experience: true,
|
118
|
-
drivers_license: 'B,C1',
|
119
|
-
car: true
|
120
|
-
)
|
121
|
-
|
122
|
-
qualifications << Qualification.new(
|
123
|
-
summary: 'A summary', # optional, but recommended field
|
124
|
-
required: false
|
125
|
-
)
|
126
|
-
|
127
|
-
application_method = ApplicationMethod.new(
|
128
|
-
external: true, # applications are not made through AF
|
129
|
-
url: 'https://example.com',
|
130
|
-
summary: 'Goto our website'
|
131
|
-
)
|
132
|
-
|
133
|
-
position = Position.new(
|
134
|
-
company: company,
|
135
|
-
schedule: schedule,
|
136
|
-
salary: salary,
|
137
|
-
qualifications: qualifications,
|
138
|
-
application_method: application_method,
|
139
|
-
attributes: {
|
140
|
-
title: 'A title',
|
141
|
-
purpose: 'A purpose',
|
142
|
-
address: {
|
143
|
-
country_code: 'SE',
|
144
|
-
zip: '11356',
|
145
|
-
municipality: 'Stockholm',
|
146
|
-
street: 'Birger Jarlsgatan 57',
|
147
|
-
city: 'stockholm'
|
148
|
-
}
|
149
|
-
}
|
150
|
-
)
|
151
|
-
|
152
|
-
packet = Packet.new(
|
153
|
-
publication: publication,
|
154
|
-
document: document,
|
155
|
-
position: position,
|
156
|
-
attributes: {
|
157
|
-
active: true,
|
158
|
-
job_id: 1,
|
159
|
-
number_to_fill: 1,
|
160
|
-
occupation: '4896'
|
161
|
-
}
|
162
|
-
)
|
163
|
-
|
164
|
-
puts "salary.valid?: #{salary.valid?}"
|
165
|
-
puts "schedule.valid?: #{schedule.valid?}"
|
166
|
-
puts "publication.valid?: #{publication.valid?}"
|
167
|
-
puts "document.valid?: #{document.valid?}"
|
168
|
-
puts "company.valid?: #{company.valid?}"
|
169
|
-
puts "application_method.valid?: #{application_method.valid?}"
|
170
|
-
puts "position.valid?: #{position.valid?}"
|
171
|
-
puts "packet.valid?: #{packet.valid?}"
|
172
|
-
|
173
|
-
client = API::Client.new(locale: 'sv')
|
174
|
-
client.create_ad(packet)
|
175
|
-
```
|
58
|
+
[See full example](examples/post_job_ad.rb).
|
176
59
|
|
177
60
|
## WSOccupation API Client
|
178
61
|
|
179
|
-
There is some support for Arbetsförmedlingen's `WSOccupation` SOAP API. See [PR#3](https://github.com/buren/arbetsformedlingen/pull/3).
|
180
|
-
|
181
62
|
```ruby
|
182
63
|
client = Arbetsformedlingen::API::WSOccupationClient.new
|
183
64
|
response = client.occupations
|
@@ -185,7 +66,35 @@ response.xml.css('Name').first.text
|
|
185
66
|
# => "Landskapsarkitekter och landskapsingenjörer"
|
186
67
|
```
|
187
68
|
|
188
|
-
[WSOccupationClient documentation](http://www.rubydoc.info/gems/arbetsformedlingen/Arbetsformedlingen/API/WSOccupationClient).
|
69
|
+
[`WSOccupationClient` documentation](http://www.rubydoc.info/gems/arbetsformedlingen/Arbetsformedlingen/API/WSOccupationClient).
|
70
|
+
|
71
|
+
:link: [Arbetsformedlingen WsOccupation API documentation](https://api.arbetsformedlingen.se/af/v0/Occupation/wsoccupation.asmx)
|
72
|
+
|
73
|
+
## Ontology API Client
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
client = Arbetsformedlingen::API::OntologyClient.new
|
77
|
+
response = client.concepts(filter: 'ruby', type: 'skill')
|
78
|
+
response.json
|
79
|
+
# => [{"uuid"=>"035fc466-605e-5684-a106-a458929f27c6", "name"=>"Ruby", "type"=>"skill"}, ...]
|
80
|
+
```
|
81
|
+
|
82
|
+
[`OntologyClient` documentation](http://www.rubydoc.info/gems/arbetsformedlingen/Arbetsformedlingen/API/WSOccupationClient).
|
83
|
+
|
84
|
+
:link: [Arbetsformedlingen Ontology API documentation](http://ontologi.arbetsformedlingen.se/ontology/v1/?url=swagger.json#/Ontology)
|
85
|
+
|
86
|
+
## Taxonomy API Client
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
client = Arbetsformedlingen::API::TaxonomyClient.new
|
90
|
+
response = client.occupation_names(language_id: 502) # sv language id
|
91
|
+
response.xml.css('OccupationName Term').first.text
|
92
|
+
# => "1:e Fartygsingenjör/1:e Maskinist"
|
93
|
+
```
|
94
|
+
|
95
|
+
[`TaxonomyClient` documentation](http://www.rubydoc.info/gems/arbetsformedlingen/Arbetsformedlingen/API/WSOccupationClient).
|
96
|
+
|
97
|
+
:link: [Arbetsformedlingen TaxonomiService API documentation](http://api.arbetsformedlingen.se/taxonomi/v0/TaxonomiService.asmx)
|
189
98
|
|
190
99
|
## Notes
|
191
100
|
|
@@ -210,6 +119,21 @@ This gem has translated the attribute names in Arbetsförmedlingens (AF) API fro
|
|
210
119
|
| yrkesgrupp | occupational_group |
|
211
120
|
| yrkesnamn | occupation |
|
212
121
|
|
122
|
+
## Installation
|
123
|
+
|
124
|
+
Add this line to your application's Gemfile:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
gem 'arbetsformedlingen'
|
128
|
+
```
|
129
|
+
|
130
|
+
And then execute:
|
131
|
+
|
132
|
+
$ bundle
|
133
|
+
|
134
|
+
Or install it yourself as:
|
135
|
+
|
136
|
+
$ gem install arbetsformedlingen
|
213
137
|
|
214
138
|
## Development
|
215
139
|
|
data/bin/seed
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'arbetsformedlingen'
|
6
|
+
require 'csv'
|
7
|
+
|
8
|
+
SWEDISH_LANGUAGE_ID = 502
|
9
|
+
|
10
|
+
client = Arbetsformedlingen::API::TaxonomyClient.new
|
11
|
+
occupation_name_response = client.occupation_names(language_id: SWEDISH_LANGUAGE_ID)
|
12
|
+
|
13
|
+
CSV.open(Arbetsformedlingen::OccupationCode::DATA_PATH, 'w') do |csv|
|
14
|
+
occupation_name_response.xml.css('OccupationName').each do |node|
|
15
|
+
csv << [node.css('OccupationNameID').text, node.css('Term').text]
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'arbetsformedlingen'
|
5
|
+
|
6
|
+
AF = Arbetsformedlingen # for brevity
|
7
|
+
|
8
|
+
document = AF::Document.new(
|
9
|
+
customer_id: 'XXXYYYZZZ',
|
10
|
+
email: 'a@example.com'
|
11
|
+
)
|
12
|
+
|
13
|
+
company = AF::Company.new(
|
14
|
+
name: 'ACME AB',
|
15
|
+
cin: 'XXYYZZXXYY',
|
16
|
+
description: 'A company description',
|
17
|
+
address: {
|
18
|
+
country_code: 'SE',
|
19
|
+
zip: '11356',
|
20
|
+
municipality: 'Stockholm',
|
21
|
+
street: 'Birger Jarlsgatan 57',
|
22
|
+
city: 'stockholm',
|
23
|
+
}
|
24
|
+
)
|
25
|
+
|
26
|
+
publication = AF::Publication.new(
|
27
|
+
publish_at: Date.today,
|
28
|
+
unpublish_at: Date.today + 21,
|
29
|
+
name: 'John Doe',
|
30
|
+
email: 'john@example.com'
|
31
|
+
)
|
32
|
+
|
33
|
+
schedule = AF::Schedule.new(
|
34
|
+
full_time: false,
|
35
|
+
summary: '3 days a week 8.00-17.00',
|
36
|
+
start_date: Date.today,
|
37
|
+
end_date: nil
|
38
|
+
)
|
39
|
+
|
40
|
+
salary = AF::Salary.new(
|
41
|
+
currency: 'SEK',
|
42
|
+
type: :fixed, # :fixed, :fixed_and_commission, :commission
|
43
|
+
summary: 'Your salary will be...'
|
44
|
+
)
|
45
|
+
|
46
|
+
qualifications = []
|
47
|
+
qualifications << AF::Qualification.new(
|
48
|
+
summary: 'A summary', # optional, but recommended field
|
49
|
+
required: true,
|
50
|
+
experience: true,
|
51
|
+
drivers_license: 'B,C1',
|
52
|
+
car: true
|
53
|
+
)
|
54
|
+
|
55
|
+
qualifications << AF::Qualification.new(
|
56
|
+
summary: 'A summary', # optional, but recommended field
|
57
|
+
required: false
|
58
|
+
)
|
59
|
+
|
60
|
+
application_method = AF::ApplicationMethod.new(
|
61
|
+
external: true, # applications are not made through AF
|
62
|
+
url: 'https://example.com',
|
63
|
+
summary: 'Goto our website'
|
64
|
+
)
|
65
|
+
|
66
|
+
position = AF::Position.new(
|
67
|
+
company: company,
|
68
|
+
schedule: schedule,
|
69
|
+
salary: salary,
|
70
|
+
qualifications: qualifications,
|
71
|
+
application_method: application_method,
|
72
|
+
attributes: {
|
73
|
+
title: 'A title',
|
74
|
+
purpose: 'A purpose',
|
75
|
+
address: {
|
76
|
+
country_code: 'SE',
|
77
|
+
zip: '11356',
|
78
|
+
municipality: 'Stockholm',
|
79
|
+
street: 'Birger Jarlsgatan 57',
|
80
|
+
city: 'stockholm',
|
81
|
+
},
|
82
|
+
}
|
83
|
+
)
|
84
|
+
|
85
|
+
packet = AF::Packet.new(
|
86
|
+
publication: publication,
|
87
|
+
document: document,
|
88
|
+
position: position,
|
89
|
+
attributes: {
|
90
|
+
active: true,
|
91
|
+
job_id: 1,
|
92
|
+
number_to_fill: 1,
|
93
|
+
occupation: '4896',
|
94
|
+
}
|
95
|
+
)
|
96
|
+
|
97
|
+
puts "salary.valid?: #{salary.valid?}"
|
98
|
+
puts "schedule.valid?: #{schedule.valid?}"
|
99
|
+
puts "publication.valid?: #{publication.valid?}"
|
100
|
+
puts "document.valid?: #{document.valid?}"
|
101
|
+
puts "company.valid?: #{company.valid?}"
|
102
|
+
puts "application_method.valid?: #{application_method.valid?}"
|
103
|
+
puts "position.valid?: #{position.valid?}"
|
104
|
+
puts "packet.valid?: #{packet.valid?}"
|
105
|
+
|
106
|
+
client = API::AF::Client.new(locale: 'sv')
|
107
|
+
client.create_ad(packet)
|
data/lib/arbetsformedlingen.rb
CHANGED
@@ -32,7 +32,9 @@ require 'arbetsformedlingen/models/packet'
|
|
32
32
|
|
33
33
|
# API Client
|
34
34
|
require 'arbetsformedlingen/api/client'
|
35
|
+
require 'arbetsformedlingen/api/ontology_client'
|
35
36
|
require 'arbetsformedlingen/api/ws_occupation_client'
|
37
|
+
require 'arbetsformedlingen/api/taxonomy_client'
|
36
38
|
|
37
39
|
module Arbetsformedlingen
|
38
40
|
class << self
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'arbetsformedlingen/soap_builder'
|
4
|
+
require 'arbetsformedlingen/api/soap_request'
|
5
|
+
|
6
|
+
module Arbetsformedlingen
|
7
|
+
module API
|
8
|
+
# Base client for SOAP clients
|
9
|
+
class BaseSOAPClient
|
10
|
+
attr_reader :request, :namespace, :service_url
|
11
|
+
|
12
|
+
# Initialize client
|
13
|
+
def initialize(url, namespace)
|
14
|
+
@service_url = url
|
15
|
+
@namespace = namespace
|
16
|
+
@request = SOAPRequest.new(url)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Perform client request
|
20
|
+
# @param [String] name of the main node
|
21
|
+
# @param args [Hash] optional arguments
|
22
|
+
# @return [Response]
|
23
|
+
def client_request(name, args: {})
|
24
|
+
soap_body = SOAPBuilder.wrap do |body| # rubocop:disable Lint/UnusedBlockArgument
|
25
|
+
# HACK: Work around the XMLBuilder DSL
|
26
|
+
ruby_statements = args.map do |key, value|
|
27
|
+
if value.is_a?(Array)
|
28
|
+
inner_ruby_statements = value.map do |(k, v)|
|
29
|
+
"inode.#{k}('#{v}')"
|
30
|
+
end
|
31
|
+
|
32
|
+
<<~RUBY_EVAL
|
33
|
+
node.#{key} { |inode| #{inner_ruby_statements.join(';')} }
|
34
|
+
RUBY_EVAL
|
35
|
+
else
|
36
|
+
"node.#{key}('#{value}')"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
ruby_xml_builder_code = <<~RUBY_EVAL
|
41
|
+
body.#{name}(xmlns: namespace) { |node| #{ruby_statements.join(';')} }
|
42
|
+
RUBY_EVAL
|
43
|
+
|
44
|
+
instance_eval(ruby_xml_builder_code)
|
45
|
+
end
|
46
|
+
|
47
|
+
request.post(soap_body.to_xml)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|