arbetsformedlingen 0.2.0 → 0.3.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/.gitignore +2 -0
- data/README.md +65 -7
- data/arbetsformedlingen.gemspec +2 -0
- data/lib/arbetsformedlingen.rb +5 -7
- data/lib/arbetsformedlingen/api/client.rb +175 -0
- data/lib/arbetsformedlingen/api/ledigtarbete_client.rb +30 -0
- data/lib/arbetsformedlingen/api/matchning_client.rb +127 -0
- data/lib/arbetsformedlingen/api/request.rb +47 -0
- data/lib/arbetsformedlingen/api/results/ad_result.rb +91 -0
- data/lib/arbetsformedlingen/api/results/matchning_result.rb +44 -0
- data/lib/arbetsformedlingen/api/results/soklista_result.rb +26 -0
- data/lib/arbetsformedlingen/api/values/ad_result_values.rb +70 -0
- data/lib/arbetsformedlingen/api/values/create_ad_page.rb +40 -0
- data/lib/arbetsformedlingen/api/values/matchning_result_values.rb +50 -0
- data/lib/arbetsformedlingen/api/values/soklista_values.rb +33 -0
- data/lib/arbetsformedlingen/key_struct.rb +13 -0
- data/lib/arbetsformedlingen/models/dry/predicates.rb +2 -0
- data/lib/arbetsformedlingen/models/packet.rb +5 -0
- data/lib/arbetsformedlingen/{output_builder.rb → models/packet_xml_builder.rb} +6 -4
- data/lib/arbetsformedlingen/version.rb +1 -1
- metadata +43 -5
- data/lib/arbetsformedlingen/client.rb +0 -25
- data/lib/arbetsformedlingen/response.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7974cf075a4b0845cf00e7c16a66f8d3112bdd3
|
4
|
+
data.tar.gz: a45d7d95bc4209c97f730f5f0711eff9f648fc7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dcf06f2e719fc148022bf3bf18e66d029228e9c26ec657c6e6255a3f84b3a9a50bd1f4fac8f694dd9b3a047dab183d7d7a0c91b9424a168d444397b30e02ed8c
|
7
|
+
data.tar.gz: 34e13510b301ab04d176db5381144af159814c200fbc1e4d03725c0de1a17b0c55ab3065044b83e1edf7a63d4327e55cfe54e929601f56b4173fac3550e3f36b
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,16 @@
|
|
1
|
-
# Arbetsförmedlingen
|
1
|
+
# Arbetsförmedlingen [](https://travis-ci.org/buren/arbetsformedlingen)
|
2
2
|
|
3
|
-
|
3
|
+
Arbetsförmedlingen API client (Swedish Public Employment Service).
|
4
|
+
|
5
|
+
__Features__
|
6
|
+
* Post job ad (a.k.a Direktöverförda annonser)
|
7
|
+
* Platsannons API Client
|
8
|
+
|
9
|
+
|
10
|
+
__Index__
|
11
|
+
* [Installation](#installation)
|
12
|
+
* [API usage](#api-usage)
|
13
|
+
* [Post ad usage](#post-ad-usage)
|
4
14
|
|
5
15
|
## Installation
|
6
16
|
|
@@ -18,15 +28,47 @@ Or install it yourself as:
|
|
18
28
|
|
19
29
|
$ gem install arbetsformedlingen
|
20
30
|
|
21
|
-
##
|
31
|
+
## API usage
|
32
|
+
|
33
|
+
__Create a client:__
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
client = Arbetsformedlingen::API::Client.new(locale: 'en')
|
37
|
+
```
|
38
|
+
|
39
|
+
__Fetch all ads containing specified keyword:__
|
40
|
+
```ruby
|
41
|
+
ads = client.ads(keywords: 'ruby')
|
42
|
+
ads.map(&:title)
|
43
|
+
```
|
44
|
+
|
45
|
+
__Fetch one ad:__
|
46
|
+
```ruby
|
47
|
+
ad = client.ad(id: 7408089)
|
48
|
+
ad.title
|
49
|
+
ad.occupation
|
50
|
+
ad.application.last_application_at
|
51
|
+
```
|
52
|
+
|
53
|
+
__Fetch countries in area:__
|
54
|
+
```ruby
|
55
|
+
countries = client.countries(area_id: 2)
|
56
|
+
countries.map do |country|
|
57
|
+
"#{country.name} has #{country.total_vacancies} total vacancies."
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
## Post ad usage
|
22
62
|
|
23
|
-
__Complete
|
63
|
+
__Complete example creating a packet__
|
64
|
+
|
65
|
+
:information_source: There is quite a lot of data you can/must send to the API when creating an ad.
|
24
66
|
|
25
67
|
```ruby
|
26
68
|
require 'date'
|
27
69
|
require 'arbetsformedlingen'
|
28
70
|
|
29
|
-
include Arbetsformedlingen
|
71
|
+
include Arbetsformedlingen # just for brevity
|
30
72
|
|
31
73
|
document = Document.new(
|
32
74
|
customer_id: 'XXXYYYZZZ',
|
@@ -125,8 +167,8 @@ puts "application_method.valid?: #{application_method.valid?}"
|
|
125
167
|
puts "position.valid?: #{position.valid?}"
|
126
168
|
puts "packet.valid?: #{packet.valid?}"
|
127
169
|
|
128
|
-
|
129
|
-
|
170
|
+
client = API::Client.new(locale: 'sv')
|
171
|
+
client.create_ad(packet)
|
130
172
|
```
|
131
173
|
|
132
174
|
## Arbetsförmedlingen TaxonomyService
|
@@ -135,6 +177,22 @@ Some requests had to be made to Arbetsförmedlingens TaxonomyService in order to
|
|
135
177
|
|
136
178
|
[](https://app.getpostman.com/run-collection/9a27ec2518c1005f8aea)
|
137
179
|
|
180
|
+
## Terms translation table
|
181
|
+
|
182
|
+
This gem has translated the attribute names in Arbetsförmedlingens (AF) API from Swedish to English. You can find the translations below.
|
183
|
+
|
184
|
+
| AF Term | Gem term |
|
185
|
+
|--------------------- |--------------------|
|
186
|
+
| landområde/värdsdel | areas |
|
187
|
+
| kommun | municipality |
|
188
|
+
| län | counties |
|
189
|
+
| län2 | counties2 |
|
190
|
+
| yrkesområde | occupational_fields |
|
191
|
+
| yrkesgrupp | occupational_group |
|
192
|
+
| yrkesgrupp | occupational_group |
|
193
|
+
| yrkesnamn | occupation |
|
194
|
+
|
195
|
+
|
138
196
|
## Development
|
139
197
|
|
140
198
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/arbetsformedlingen.gemspec
CHANGED
@@ -29,5 +29,7 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.add_development_dependency 'bundler', '~> 1.14'
|
30
30
|
spec.add_development_dependency 'rake', '~> 10.0'
|
31
31
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
32
|
+
spec.add_development_dependency 'webmock', '~> 3.1'
|
33
|
+
spec.add_development_dependency 'vcr', '~> 3.0'
|
32
34
|
spec.add_development_dependency 'byebug'
|
33
35
|
end
|
data/lib/arbetsformedlingen.rb
CHANGED
@@ -7,6 +7,8 @@ require 'dry-types'
|
|
7
7
|
|
8
8
|
require 'arbetsformedlingen/version'
|
9
9
|
|
10
|
+
require 'arbetsformedlingen/key_struct'
|
11
|
+
|
10
12
|
require 'arbetsformedlingen/codes/country_code'
|
11
13
|
require 'arbetsformedlingen/codes/drivers_license_code'
|
12
14
|
require 'arbetsformedlingen/codes/experience_required_code'
|
@@ -17,9 +19,6 @@ require 'arbetsformedlingen/codes/salary_type_code'
|
|
17
19
|
require 'arbetsformedlingen/models/dry/types'
|
18
20
|
require 'arbetsformedlingen/models/dry/predicates'
|
19
21
|
|
20
|
-
require 'arbetsformedlingen/output_builder'
|
21
|
-
require 'arbetsformedlingen/client'
|
22
|
-
|
23
22
|
require 'arbetsformedlingen/models/model'
|
24
23
|
require 'arbetsformedlingen/models/document'
|
25
24
|
require 'arbetsformedlingen/models/company'
|
@@ -31,11 +30,10 @@ require 'arbetsformedlingen/models/schedule'
|
|
31
30
|
require 'arbetsformedlingen/models/application_method'
|
32
31
|
require 'arbetsformedlingen/models/packet'
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
Client.post_job(OutputBuilder.new(packet).to_xml)
|
37
|
-
end
|
33
|
+
# API Client
|
34
|
+
require 'arbetsformedlingen/api/client'
|
38
35
|
|
36
|
+
module Arbetsformedlingen
|
39
37
|
class << self
|
40
38
|
attr_accessor :config
|
41
39
|
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require 'arbetsformedlingen/api/request'
|
6
|
+
|
7
|
+
require 'arbetsformedlingen/api/results/ad_result'
|
8
|
+
require 'arbetsformedlingen/api/results/matchning_result'
|
9
|
+
require 'arbetsformedlingen/api/results/soklista_result'
|
10
|
+
|
11
|
+
# Sub-clients
|
12
|
+
require 'arbetsformedlingen/api/matchning_client'
|
13
|
+
require 'arbetsformedlingen/api/ledigtarbete_client'
|
14
|
+
|
15
|
+
module Arbetsformedlingen
|
16
|
+
module API
|
17
|
+
class Client
|
18
|
+
BASE_URL = 'http://api.arbetsformedlingen.se/af/v0/platsannonser/'.freeze
|
19
|
+
|
20
|
+
attr_reader :request, :locale
|
21
|
+
|
22
|
+
def initialize(locale: 'sv')
|
23
|
+
@request = Request.new(base_url: BASE_URL, locale: locale)
|
24
|
+
@locale = locale
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get version of API
|
28
|
+
# @return [String] the version of the API.
|
29
|
+
# @example Get API version
|
30
|
+
# client.version
|
31
|
+
def version
|
32
|
+
request.get('version').body
|
33
|
+
end
|
34
|
+
|
35
|
+
# Post ad to API (ad => annons)
|
36
|
+
# @return [AdResult] the result.
|
37
|
+
# @param [Arbetsformedlingen::Packet] Packet object.
|
38
|
+
# @example Post ad
|
39
|
+
# client.ad(packet)
|
40
|
+
def create_ad(packet)
|
41
|
+
client = LedigtarbeteClient.new
|
42
|
+
client.create_ad(packet)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Fetch ad from API (ad => annons)
|
46
|
+
# @return [AdResult] the result.
|
47
|
+
# @param id [String] Ad ID.
|
48
|
+
# @example Get ad
|
49
|
+
# client.ad(id: id)
|
50
|
+
def ad(id:)
|
51
|
+
response = request.get(id)
|
52
|
+
|
53
|
+
AdResult.build(response.json)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Fetch areas from API (areas => landområde/värdsdel)
|
57
|
+
# @return [MatchningResult] the result.
|
58
|
+
# @see MatchningClient#ads
|
59
|
+
# @see MatchningResult#build
|
60
|
+
def ads(**args)
|
61
|
+
client = MatchningClient.new(request: request)
|
62
|
+
client.ads(**args)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Fetch areas from API (areas => landområde/värdsdel)
|
66
|
+
# @return [AdResult] the result.
|
67
|
+
# @example Get areas
|
68
|
+
# client.areas
|
69
|
+
def areas
|
70
|
+
response = request.get('soklista/omrade')
|
71
|
+
|
72
|
+
SoklistaResult.build(response.json)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Fetch counties from API (countries => land)
|
76
|
+
# @return [AdResult] the result.
|
77
|
+
# @param area_id [String] Area ID.
|
78
|
+
# @example Get countries within area
|
79
|
+
# client.countries(area_id: id)
|
80
|
+
def countries(area_id:)
|
81
|
+
query = { omradeid: area_id }
|
82
|
+
response = request.get('soklista/land', query: query)
|
83
|
+
|
84
|
+
SoklistaResult.build(response.json)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Fetch municipalities from API (municipality => kommun)
|
88
|
+
# @return [AdResult] the result.
|
89
|
+
# @param county_id [String] County ID.
|
90
|
+
# @example Get counties
|
91
|
+
# client.counties
|
92
|
+
def municipalities(county_id: nil)
|
93
|
+
# NOTE: Due to a quirck in the API the lanid-param
|
94
|
+
# *must* be present though it *can* be nil
|
95
|
+
query = { lanid: county_id }
|
96
|
+
response = request.get('soklista/kommuner', query: query)
|
97
|
+
|
98
|
+
SoklistaResult.build(response.json)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Fetch counties from API (county => län)
|
102
|
+
# @return [AdResult] the result.
|
103
|
+
# @example Get counties
|
104
|
+
# client.counties
|
105
|
+
def counties
|
106
|
+
response = request.get('soklista/lan')
|
107
|
+
|
108
|
+
SoklistaResult.build(response.json)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Fetch counties2 from API (county2 => län2)
|
112
|
+
# @return [AdResult] the result.
|
113
|
+
# @example Get counties2
|
114
|
+
# client.counties2
|
115
|
+
def counties2
|
116
|
+
response = request.get('soklista/lan2')
|
117
|
+
|
118
|
+
SoklistaResult.build(response.json)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Fetch occupational fields from API (occupational_fields => yrkesområde)
|
122
|
+
# @return [AdResult] the result.
|
123
|
+
# @example Get occupational fields
|
124
|
+
# client.occupational_field
|
125
|
+
def occupational_fields
|
126
|
+
response = request.get('soklista/yrkesomraden')
|
127
|
+
|
128
|
+
SoklistaResult.build(response.json)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Fetch occupational group from API (occupational_group => yrkesgrupp)
|
132
|
+
# @return [AdResult] the result.
|
133
|
+
# @param occupational_field_id [String] Occupational field ID.
|
134
|
+
# @example Get all occupational group
|
135
|
+
# client.occupational_group
|
136
|
+
# @example Get occupational group within occupational field
|
137
|
+
# client.occupational_group(occupational_field_id: id)
|
138
|
+
def occupational_group(occupational_field_id: nil)
|
139
|
+
# NOTE: Due to a quirck in the API the yrkesomradeid-param
|
140
|
+
# *must* be present though it *can* be nil
|
141
|
+
query = { yrkesomradeid: occupational_field_id }
|
142
|
+
response = request.get('soklista/yrkesgrupper', query: query)
|
143
|
+
|
144
|
+
SoklistaResult.build(response.json)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Fetch occupation from API (occupation => yrkesnamn)
|
148
|
+
# @return [AdResult] the result.
|
149
|
+
# @param name [String] Name of the occupation.
|
150
|
+
# @example Get occupation
|
151
|
+
# client.occupation(name: 'Marknadskommunikatör')
|
152
|
+
def occupation(name:)
|
153
|
+
response = request.get("soklista/yrken/#{URI.encode(name)}")
|
154
|
+
|
155
|
+
SoklistaResult.build(response.json)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Fetch occupations from API (occupation => yrkesnamn)
|
159
|
+
# @return [AdResult] the result.
|
160
|
+
# @param occupational_group_id [String] Occupational group ID.
|
161
|
+
# @example Get stats of available positions for all occupations
|
162
|
+
# client.occupations
|
163
|
+
# @example Get stats of available positions for some occupations
|
164
|
+
# client.occupations(occupational_group_id: id)
|
165
|
+
def occupations(occupational_group_id: nil)
|
166
|
+
# NOTE: Due to a quirck in the API the yrkesgruppid-param
|
167
|
+
# *must* be present though it *can* be nil
|
168
|
+
query = { yrkesgruppid: occupational_group_id }
|
169
|
+
response = request.get('soklista/yrken', query: query)
|
170
|
+
|
171
|
+
SoklistaResult.build(response.json)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'arbetsformedlingen/api/request'
|
2
|
+
require 'arbetsformedlingen/api/values/create_ad_page'
|
3
|
+
|
4
|
+
module Arbetsformedlingen
|
5
|
+
module API
|
6
|
+
class LedigtarbeteClient
|
7
|
+
BASE_URL = 'http://api.arbetsformedlingen.se/ledigtarbete'.freeze
|
8
|
+
|
9
|
+
HEADERS = {
|
10
|
+
'Content-type' => 'text/xml'
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
# Post ad to API
|
14
|
+
# @param [Arbetsformedlingen::Packet, #to_xml] the data to be sent
|
15
|
+
# @return [Values::CreateAdPage] the API result
|
16
|
+
def create_ad(packet)
|
17
|
+
xml = packet.to_xml
|
18
|
+
|
19
|
+
url = if Arbetsformedlingen.config.test
|
20
|
+
'apiledigtarbete/test/hrxml'
|
21
|
+
else
|
22
|
+
'apiledigtarbete/hrxml'
|
23
|
+
end
|
24
|
+
|
25
|
+
response = HTTParty.post("#{BASE_URL}/#{url}", body: xml, headers: HEADERS)
|
26
|
+
Values::CreateAdPage.new(response, xml)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'time'
|
3
|
+
require 'arbetsformedlingen/api/request'
|
4
|
+
require 'arbetsformedlingen/api/results/matchning_result'
|
5
|
+
|
6
|
+
module Arbetsformedlingen
|
7
|
+
module API
|
8
|
+
class MatchningClient
|
9
|
+
attr_reader :request
|
10
|
+
|
11
|
+
def initialize(request: Request.new)
|
12
|
+
@request = request
|
13
|
+
end
|
14
|
+
|
15
|
+
# Find matching ads from API
|
16
|
+
# @return [MatchningResult] the result.
|
17
|
+
# @param area_id [String] Area ID.
|
18
|
+
# @param county_id [String] County ID.
|
19
|
+
# @param municipality_id [String] Municipality ID.
|
20
|
+
# @param occupation_id [String] Occupation ID.
|
21
|
+
# @param keywords [String] Keywords.
|
22
|
+
# @param page [Integer] Page ID.
|
23
|
+
# @param page_size [Integer] Page size ID.
|
24
|
+
# @param occupation_group_id [String] Occupation_group ID.
|
25
|
+
# @param employment_type [String] Employment type ID.
|
26
|
+
# @param occupation_field_id [String] Occupation field ID.
|
27
|
+
# @param published_after [Time, Date, String] Published after ID (ISO8601 format: YYYY-MM-DDThh:mm:ssTZD).
|
28
|
+
# @param organization_number [String] Organization_number ID.
|
29
|
+
# @example Get ads within county
|
30
|
+
# client.ads(county: id)
|
31
|
+
# @example Get ads within municipality
|
32
|
+
# client.ads(municipality: id)
|
33
|
+
# @example Get ads with keyword
|
34
|
+
# client.ads(keywrods: 'ruby')
|
35
|
+
# @example Get ads with keyword on page 3 and with a page size of 10
|
36
|
+
# client.ads(keywrods: 'ruby', page: 3, page_size: 10)
|
37
|
+
# @example Get ads with keyword and organsiation numer
|
38
|
+
# client.ads(keywrods: 'ruby', organization_number: org_no)
|
39
|
+
def ads(
|
40
|
+
# one of these must be present
|
41
|
+
county_id: nil,
|
42
|
+
municipality_id: nil,
|
43
|
+
occupation_id: nil,
|
44
|
+
keywords: nil,
|
45
|
+
# optional
|
46
|
+
page: 1,
|
47
|
+
page_size: 30,
|
48
|
+
area_id: nil,
|
49
|
+
occupation_group_id: nil,
|
50
|
+
employment_type: nil,
|
51
|
+
occupation_field_id: nil,
|
52
|
+
published_after: nil,
|
53
|
+
organization_number: nil
|
54
|
+
)
|
55
|
+
|
56
|
+
one_of_required = [county_id, municipality_id, occupation_id, keywords]
|
57
|
+
if one_of_required.all?(&:nil?)
|
58
|
+
error_message = 'One of: county_id, municipality_id, occupation_id, keywords is required'
|
59
|
+
raise ArgumentError, error_message
|
60
|
+
end
|
61
|
+
|
62
|
+
# TODO: Should we validate the IDs passed? What if they're invalid? Do we crash?
|
63
|
+
|
64
|
+
query = {
|
65
|
+
lanid: county_id,
|
66
|
+
kommunid: municipality_id,
|
67
|
+
yrkesid: occupation_id,
|
68
|
+
nyckelord: santize_keywords_query(keywords),
|
69
|
+
sida: page,
|
70
|
+
antalrader: page_size,
|
71
|
+
omradeid: area_id,
|
72
|
+
yrkesgruppid: occupation_group_id,
|
73
|
+
anstallningstyp: santize_employment_type_query(employment_type),
|
74
|
+
yrkesomradeid: occupation_field_id,
|
75
|
+
sokdatum: normalize_date_to_iso8601(published_after),
|
76
|
+
organisationsnummer: organization_number
|
77
|
+
}
|
78
|
+
|
79
|
+
response = request.get('matchning', query: query)
|
80
|
+
|
81
|
+
MatchningResult.build(response.json)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# @raise [ArgumentError] raises error if passed invalid value
|
87
|
+
def normalize_date_to_iso8601(date_time_or_string)
|
88
|
+
return unless date_time_or_string
|
89
|
+
|
90
|
+
time = date_time_or_string
|
91
|
+
time = time.to_time if time.is_a?(Date)
|
92
|
+
time = Time.parse(time) if time.is_a?(String)
|
93
|
+
|
94
|
+
time.iso8601
|
95
|
+
end
|
96
|
+
|
97
|
+
def santize_employment_type_query(employment_type)
|
98
|
+
# Sökkriterier anställningstyp.
|
99
|
+
# Värdena ska ligga mellan 1 och 3.
|
100
|
+
# 1 är XXX (EJ DOKUMENTERAT)
|
101
|
+
# 2 är somarjobb / feriejobb
|
102
|
+
# 3 är utlandsjobb
|
103
|
+
|
104
|
+
# TODO: The question is what we do if an invalid parameter is passed
|
105
|
+
# should we crash?
|
106
|
+
|
107
|
+
employment_type
|
108
|
+
end
|
109
|
+
|
110
|
+
def santize_keywords_query(keywords)
|
111
|
+
#
|
112
|
+
# Sökord kan separeras eller kombineras med något av följande exempel:
|
113
|
+
# mellanslag (” ”)
|
114
|
+
#
|
115
|
+
# [Example]
|
116
|
+
# /matchning?nyckelord="bagare""test"
|
117
|
+
# /matchning?nyckelord="bagare"OR"test" /matchning?nyckelord="automatisk"AND"test"
|
118
|
+
|
119
|
+
# Valid characters
|
120
|
+
# abcdefghijklmnopqrstuvwxyzåäö0123456789: ,.-"
|
121
|
+
|
122
|
+
# TODO: What do we do if invalid characters are passed? Crash?
|
123
|
+
keywords
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Arbetsformedlingen
|
6
|
+
module API
|
7
|
+
class Request
|
8
|
+
Response = KeyStruct.new(:code, :body, :json)
|
9
|
+
|
10
|
+
HEADERS = {
|
11
|
+
'Content-Type' => 'application/json',
|
12
|
+
'Accept-Language' => 'sv'
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
attr_reader :locale, :base_url
|
16
|
+
|
17
|
+
def initialize(base_url: '', locale: 'sv')
|
18
|
+
@base_url = base_url
|
19
|
+
@locale = locale
|
20
|
+
end
|
21
|
+
|
22
|
+
def get(url, query: {})
|
23
|
+
uri = URI("#{base_url}#{url}?#{URI.encode_www_form(query.to_a)}")
|
24
|
+
|
25
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
26
|
+
|
27
|
+
request = Net::HTTP::Get.new(uri)
|
28
|
+
request['Content-Type'] = HEADERS['Content-Type']
|
29
|
+
request['Accept-Language'] = locale
|
30
|
+
|
31
|
+
response = http.request(request)
|
32
|
+
|
33
|
+
Response.new(
|
34
|
+
code: response.code,
|
35
|
+
body: response.read_body,
|
36
|
+
json: parse_json(response.read_body)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_json(string)
|
41
|
+
JSON.parse(string.to_s)
|
42
|
+
rescue JSON::ParserError => _e
|
43
|
+
{}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'arbetsformedlingen/api/values/ad_result_values'
|
2
|
+
|
3
|
+
module Arbetsformedlingen
|
4
|
+
module API
|
5
|
+
module AdResult
|
6
|
+
def self.build(response_data)
|
7
|
+
data = response_data.fetch('platsannons')
|
8
|
+
|
9
|
+
ad_data = data.fetch('annons')
|
10
|
+
|
11
|
+
Values::Ad.new(
|
12
|
+
id: ad_data.fetch('annonsid'),
|
13
|
+
url: ad_data.fetch('platsannonsUrl'),
|
14
|
+
title: ad_data.fetch('annonsrubrik'),
|
15
|
+
body: ad_data.fetch('annonstext'),
|
16
|
+
occupation: ad_data.fetch('yrkesbenamning'),
|
17
|
+
occupation_id: ad_data.fetch('yrkesid'),
|
18
|
+
published_at: ad_data.fetch('publiceraddatum'),
|
19
|
+
total_vacancies: ad_data.fetch('antal_platser'),
|
20
|
+
municipalities: ad_data.fetch('kommunnamn'),
|
21
|
+
municipality_id: ad_data.fetch('kommunkod'),
|
22
|
+
total_vacancies_with_visa: ad_data.fetch('antalplatserVisa'),
|
23
|
+
employment_type: ad_data.fetch('anstallningstyp'),
|
24
|
+
terms: build_terms(data.fetch('villkor')),
|
25
|
+
application: build_application(data.fetch('ansokan')),
|
26
|
+
workplace: build_workplace(data.fetch('arbetsplats')),
|
27
|
+
requirements: build_requirements(data.fetch('krav'))
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.build_terms(data)
|
32
|
+
Values::Terms.new(
|
33
|
+
duration: data.fetch('varaktighet'),
|
34
|
+
working_hours: data.fetch('arbetstid'),
|
35
|
+
working_hours_description: data.fetch('arbetstidvaraktighet'),
|
36
|
+
salary_type: data.fetch('lonetyp'),
|
37
|
+
salary_form: data.fetch('loneform')
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.build_application(data)
|
42
|
+
Values::Application.new(
|
43
|
+
reference: data.fetch('referens'),
|
44
|
+
application_url: data.fetch('webbplats'),
|
45
|
+
email: data['epostadress'],
|
46
|
+
last_application_at: data.fetch('sista_ansokningsdag'),
|
47
|
+
application_comment: data.fetch('ovrigt_om_ansokan')
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.build_workplace(data)
|
52
|
+
Values::Workplace.new(
|
53
|
+
name: data.fetch('arbetsplatsnamn'),
|
54
|
+
postal: build_postal(data),
|
55
|
+
country: data.fetch('land'),
|
56
|
+
visit_address: data.fetch('besoksadress'),
|
57
|
+
logotype_url: data.fetch('logotypurl'),
|
58
|
+
website: data.fetch('hemsida'),
|
59
|
+
contacts: (
|
60
|
+
data.dig('kontaktpersonlista', 'kontaktpersonlista') || []
|
61
|
+
).map do |contact_data|
|
62
|
+
build_workplace_contacts(contact_data)
|
63
|
+
end
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.build_postal(data)
|
68
|
+
Values::Postal.new(
|
69
|
+
code: data.fetch('postnummer'),
|
70
|
+
address: data.fetch('postadress'),
|
71
|
+
city: data.fetch('postort'),
|
72
|
+
country: data.fetch('postland')
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.build_workplace_contacts(data)
|
77
|
+
Values::Contact.new(
|
78
|
+
name: data['namn'],
|
79
|
+
title: data['titel'],
|
80
|
+
phone: data['telefonnummer']
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.build_requirements(data)
|
85
|
+
Values::Requirements.new(
|
86
|
+
own_car: data.fetch('egenbil')
|
87
|
+
)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'arbetsformedlingen/api/values/matchning_result_values'
|
2
|
+
|
3
|
+
module Arbetsformedlingen
|
4
|
+
module API
|
5
|
+
module MatchningResult
|
6
|
+
def self.build(response_data)
|
7
|
+
data = response_data.fetch('matchningslista')
|
8
|
+
|
9
|
+
Values::MatchningPage.new(
|
10
|
+
list_name: 'annonser',
|
11
|
+
total_ads: data.fetch('antal_platsannonser'),
|
12
|
+
total_ads_exact: data.fetch('antal_platsannonser_exakta'),
|
13
|
+
total_ads_nearby: data.fetch('antal_platsannonser_narliggande'),
|
14
|
+
total_vacancies_on_page: data.fetch('antal_platserTotal'),
|
15
|
+
total_pages: data.fetch('antal_sidor'),
|
16
|
+
raw_data: response_data,
|
17
|
+
data: data.fetch('matchningdata').map { |ad_data| build_ad_result(ad_data) }
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.build_ad_result(ad_data)
|
22
|
+
Values::MatchningAd.new(
|
23
|
+
id: ad_data.fetch('annonsid'),
|
24
|
+
title: ad_data.fetch('annonsrubrik'),
|
25
|
+
occupation: ad_data.fetch('yrkesbenamning'),
|
26
|
+
occupation_id: ad_data.fetch('yrkesbenamningId'),
|
27
|
+
company: ad_data.fetch('arbetsplatsnamn'),
|
28
|
+
municipalities: ad_data.fetch('kommunnamn'),
|
29
|
+
municipality_id: ad_data.fetch('kommunkod'),
|
30
|
+
published_at: ad_data.fetch('publiceraddatum'),
|
31
|
+
last_application_at: ad_data.fetch('sista_ansokningsdag'),
|
32
|
+
url: ad_data.fetch('annonsurl'),
|
33
|
+
relevance: ad_data.fetch('relevans'),
|
34
|
+
total_vacancies: ad_data.fetch('antalplatser'),
|
35
|
+
total_vacancies_with_visa: ad_data.fetch('antalPlatserVisa'),
|
36
|
+
duration_id: ad_data.fetch('varaktighetId'),
|
37
|
+
counties: ad_data.fetch('lan'),
|
38
|
+
country_id: ad_data.fetch('lanid'),
|
39
|
+
employment_type: ad_data.fetch('anstallningstyp')
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'arbetsformedlingen/api/values/soklista_values'
|
2
|
+
|
3
|
+
module Arbetsformedlingen
|
4
|
+
module API
|
5
|
+
module SoklistaResult
|
6
|
+
def self.build(response_data)
|
7
|
+
data = response_data.fetch('soklista')
|
8
|
+
|
9
|
+
Values::SoklistaPage.new(
|
10
|
+
list_name: data.fetch('listnamn'),
|
11
|
+
total_ads: data.fetch('totalt_antal_platsannonser'),
|
12
|
+
total_vacancies: data.fetch('totalt_antal_ledigajobb'),
|
13
|
+
raw_data: response_data,
|
14
|
+
data: data.fetch('sokdata').map do |result|
|
15
|
+
Values::SoklistaResult.new(
|
16
|
+
id: result.fetch('id'),
|
17
|
+
name: result.fetch('namn'),
|
18
|
+
total_ads: result.fetch('antal_platsannonser'),
|
19
|
+
total_vacancies: result.fetch('antal_ledigajobb')
|
20
|
+
)
|
21
|
+
end
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Arbetsformedlingen
|
2
|
+
module API
|
3
|
+
module Values
|
4
|
+
Ad = KeyStruct.new(
|
5
|
+
:id,
|
6
|
+
:url,
|
7
|
+
:title,
|
8
|
+
:body,
|
9
|
+
:occupation,
|
10
|
+
:occupation_id,
|
11
|
+
:published_at,
|
12
|
+
:total_vacancies,
|
13
|
+
:municipalities,
|
14
|
+
:municipality_id,
|
15
|
+
:total_vacancies_with_visa,
|
16
|
+
:employment_type,
|
17
|
+
:terms,
|
18
|
+
:application,
|
19
|
+
:workplace,
|
20
|
+
:requirements
|
21
|
+
)
|
22
|
+
class Ad
|
23
|
+
def to_h
|
24
|
+
hash = super.to_h
|
25
|
+
hash[:terms] = hash[:terms].to_h
|
26
|
+
hash[:application] = hash[:application].to_h
|
27
|
+
hash[:workplace] = hash[:workplace].to_h
|
28
|
+
hash[:requirements] = hash[:requirements].to_h
|
29
|
+
hash
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Terms = KeyStruct.new(
|
34
|
+
:duration,
|
35
|
+
:working_hours,
|
36
|
+
:working_hours_description,
|
37
|
+
:salary_type,
|
38
|
+
:salary_form
|
39
|
+
)
|
40
|
+
|
41
|
+
Application = KeyStruct.new(
|
42
|
+
:reference,
|
43
|
+
:application_url,
|
44
|
+
:email,
|
45
|
+
:last_application_at,
|
46
|
+
:application_comment
|
47
|
+
)
|
48
|
+
|
49
|
+
Workplace = KeyStruct.new(
|
50
|
+
:name,
|
51
|
+
:postal,
|
52
|
+
:country,
|
53
|
+
:visit_address,
|
54
|
+
:logotype_url,
|
55
|
+
:website,
|
56
|
+
:contacts
|
57
|
+
)
|
58
|
+
class Workplace
|
59
|
+
def to_h
|
60
|
+
data = super.to_h
|
61
|
+
data[:postal] = data[:postal].to_h
|
62
|
+
data
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Postal = KeyStruct.new(:code, :address, :city, :country)
|
67
|
+
Requirements = KeyStruct.new(:own_car)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Arbetsformedlingen
|
2
|
+
module API
|
3
|
+
module Values
|
4
|
+
class CreateAdPage
|
5
|
+
ResponseMessage = KeyStruct.new(:detail, :error_code)
|
6
|
+
|
7
|
+
attr_reader :code, :messages, :body, :request_body
|
8
|
+
|
9
|
+
def initialize(httparty_response, request_boby)
|
10
|
+
@code = httparty_response.code
|
11
|
+
@body = httparty_response.body
|
12
|
+
@request_body = request_body
|
13
|
+
@valid = @code == 202
|
14
|
+
@messages = build_messages(httparty_response.to_a)
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid?
|
18
|
+
@valid
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_messages(messages)
|
24
|
+
messages.map do |message|
|
25
|
+
# HTTParty returns an array if there is only one key-value pair in the response
|
26
|
+
# so we need to check for it here and normalize
|
27
|
+
if message.is_a?(Array)
|
28
|
+
ResponseMessage.new(detail: message.last, error_code: nil)
|
29
|
+
else
|
30
|
+
error_code = message['ErrorCode']
|
31
|
+
@valid = false if error_code
|
32
|
+
|
33
|
+
ResponseMessage.new(detail: message['Message'], error_code: error_code)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Arbetsformedlingen
|
2
|
+
module API
|
3
|
+
module Values
|
4
|
+
MatchningPage = KeyStruct.new(
|
5
|
+
:list_name,
|
6
|
+
:total_ads,
|
7
|
+
:total_ads_exact,
|
8
|
+
:total_ads_nearby,
|
9
|
+
:total_vacancies_on_page,
|
10
|
+
:total_places_total,
|
11
|
+
:total_pages,
|
12
|
+
:data,
|
13
|
+
:raw_data
|
14
|
+
)
|
15
|
+
class MatchningPage
|
16
|
+
include Enumerable
|
17
|
+
|
18
|
+
def each(&block)
|
19
|
+
data.each(&block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_h
|
23
|
+
hash = super.to_h
|
24
|
+
hash[:data].map!(&:to_h)
|
25
|
+
hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
MatchningAd = KeyStruct.new(
|
30
|
+
:id,
|
31
|
+
:title,
|
32
|
+
:occupation,
|
33
|
+
:occupation_id,
|
34
|
+
:company,
|
35
|
+
:municipalities,
|
36
|
+
:municipality_id,
|
37
|
+
:published_at,
|
38
|
+
:last_application_at,
|
39
|
+
:url,
|
40
|
+
:relevance,
|
41
|
+
:total_vacancies,
|
42
|
+
:total_vacancies_with_visa,
|
43
|
+
:duration_id,
|
44
|
+
:counties,
|
45
|
+
:country_id,
|
46
|
+
:employment_type
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Arbetsformedlingen
|
2
|
+
module API
|
3
|
+
module Values
|
4
|
+
SoklistaPage = KeyStruct.new(
|
5
|
+
:list_name,
|
6
|
+
:total_ads,
|
7
|
+
:total_vacancies,
|
8
|
+
:data,
|
9
|
+
:raw_data
|
10
|
+
)
|
11
|
+
class SoklistaPage
|
12
|
+
include Enumerable
|
13
|
+
|
14
|
+
def each(&block)
|
15
|
+
data.each(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_h
|
19
|
+
hash = super.to_h
|
20
|
+
hash[:data].map!(&:to_h)
|
21
|
+
hash
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
SoklistaResult = KeyStruct.new(
|
26
|
+
:id,
|
27
|
+
:name,
|
28
|
+
:total_ads,
|
29
|
+
:total_vacancies
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Arbetsformedlingen
|
2
|
+
class KeyStruct < Struct
|
3
|
+
def initialize(**keyword_args)
|
4
|
+
keyword_args.each do |key, value|
|
5
|
+
if members.include?(key)
|
6
|
+
self[key] = value
|
7
|
+
else
|
8
|
+
raise ArgumentError, "Unknown key struct member: #{key}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'builder'
|
2
|
+
require 'arbetsformedlingen/models/packet_xml_builder'
|
2
3
|
|
3
4
|
module Arbetsformedlingen
|
4
5
|
PacketSchema = Dry::Validation.Form do
|
@@ -35,5 +36,9 @@ module Arbetsformedlingen
|
|
35
36
|
hash[:position] = @position.to_h
|
36
37
|
hash
|
37
38
|
end
|
39
|
+
|
40
|
+
def to_xml
|
41
|
+
PacketXMLBuilder.new(self).to_xml
|
42
|
+
end
|
38
43
|
end
|
39
44
|
end
|
@@ -1,15 +1,17 @@
|
|
1
1
|
require 'builder'
|
2
2
|
|
3
3
|
module Arbetsformedlingen
|
4
|
-
class
|
4
|
+
class PacketXMLBuilder
|
5
5
|
def initialize(packet)
|
6
6
|
@packet = packet
|
7
7
|
end
|
8
8
|
|
9
9
|
def to_xml
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
@xml ||= begin
|
11
|
+
# TODO: Set option so that åäö isn't encoded
|
12
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
13
|
+
append_envelope(builder, @packet.to_h)
|
14
|
+
end
|
13
15
|
end
|
14
16
|
|
15
17
|
private
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arbetsformedlingen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jacob Burenstam
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -94,6 +94,34 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '3.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.1'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.1'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: vcr
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '3.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '3.0'
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: byebug
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -130,13 +158,24 @@ files:
|
|
130
158
|
- data/municipality-codes.csv
|
131
159
|
- data/occupation-codes.csv
|
132
160
|
- lib/arbetsformedlingen.rb
|
133
|
-
- lib/arbetsformedlingen/client.rb
|
161
|
+
- lib/arbetsformedlingen/api/client.rb
|
162
|
+
- lib/arbetsformedlingen/api/ledigtarbete_client.rb
|
163
|
+
- lib/arbetsformedlingen/api/matchning_client.rb
|
164
|
+
- lib/arbetsformedlingen/api/request.rb
|
165
|
+
- lib/arbetsformedlingen/api/results/ad_result.rb
|
166
|
+
- lib/arbetsformedlingen/api/results/matchning_result.rb
|
167
|
+
- lib/arbetsformedlingen/api/results/soklista_result.rb
|
168
|
+
- lib/arbetsformedlingen/api/values/ad_result_values.rb
|
169
|
+
- lib/arbetsformedlingen/api/values/create_ad_page.rb
|
170
|
+
- lib/arbetsformedlingen/api/values/matchning_result_values.rb
|
171
|
+
- lib/arbetsformedlingen/api/values/soklista_values.rb
|
134
172
|
- lib/arbetsformedlingen/codes/country_code.rb
|
135
173
|
- lib/arbetsformedlingen/codes/drivers_license_code.rb
|
136
174
|
- lib/arbetsformedlingen/codes/experience_required_code.rb
|
137
175
|
- lib/arbetsformedlingen/codes/municipality_code.rb
|
138
176
|
- lib/arbetsformedlingen/codes/occupation_code.rb
|
139
177
|
- lib/arbetsformedlingen/codes/salary_type_code.rb
|
178
|
+
- lib/arbetsformedlingen/key_struct.rb
|
140
179
|
- lib/arbetsformedlingen/models/application_method.rb
|
141
180
|
- lib/arbetsformedlingen/models/company.rb
|
142
181
|
- lib/arbetsformedlingen/models/document.rb
|
@@ -144,13 +183,12 @@ files:
|
|
144
183
|
- lib/arbetsformedlingen/models/dry/types.rb
|
145
184
|
- lib/arbetsformedlingen/models/model.rb
|
146
185
|
- lib/arbetsformedlingen/models/packet.rb
|
186
|
+
- lib/arbetsformedlingen/models/packet_xml_builder.rb
|
147
187
|
- lib/arbetsformedlingen/models/position.rb
|
148
188
|
- lib/arbetsformedlingen/models/publication.rb
|
149
189
|
- lib/arbetsformedlingen/models/qualification.rb
|
150
190
|
- lib/arbetsformedlingen/models/salary.rb
|
151
191
|
- lib/arbetsformedlingen/models/schedule.rb
|
152
|
-
- lib/arbetsformedlingen/output_builder.rb
|
153
|
-
- lib/arbetsformedlingen/response.rb
|
154
192
|
- lib/arbetsformedlingen/version.rb
|
155
193
|
homepage: https://github.com/buren/arbetsformedlingen
|
156
194
|
licenses:
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'arbetsformedlingen/response'
|
2
|
-
|
3
|
-
module Arbetsformedlingen
|
4
|
-
class Client
|
5
|
-
BASE_URL = 'http://api.arbetsformedlingen.se/ledigtarbete'.freeze
|
6
|
-
ROUTES = {
|
7
|
-
post_job_url: "#{BASE_URL}/apiledigtarbete/hrxml",
|
8
|
-
test_post_job_url: "#{BASE_URL}/apiledigtarbete/test/hrxml"
|
9
|
-
}.freeze
|
10
|
-
|
11
|
-
HEADERS = {
|
12
|
-
'Content-type' => 'text/xml'
|
13
|
-
}.freeze
|
14
|
-
|
15
|
-
def self.post_job(xml)
|
16
|
-
response = HTTParty.post(post_job_url, body: xml, headers: HEADERS)
|
17
|
-
Response.new(response, xml)
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.post_job_url
|
21
|
-
return ROUTES.fetch(:test_post_job_url) if Arbetsformedlingen.config.test
|
22
|
-
ROUTES.fetch(:post_job_url)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Arbetsformedlingen
|
2
|
-
class Response
|
3
|
-
attr_reader :code, :messages, :body, :request_body
|
4
|
-
|
5
|
-
def initialize(httparty_response, request_boby)
|
6
|
-
@code = httparty_response.code
|
7
|
-
@body = httparty_response.body
|
8
|
-
@request_body = request_body
|
9
|
-
@valid = @code == 202
|
10
|
-
@messages = build_messages(httparty_response.to_a)
|
11
|
-
end
|
12
|
-
|
13
|
-
def valid?
|
14
|
-
@valid
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def build_messages(messages)
|
20
|
-
messages.map do |message|
|
21
|
-
# HTTParty returns an array if there is only one key-value pair in the response
|
22
|
-
# so we need to check for it here and normalize
|
23
|
-
if message.is_a?(Array)
|
24
|
-
{ message: message.last, error_code: nil }
|
25
|
-
else
|
26
|
-
error_code = message['ErrorCode']
|
27
|
-
@valid = false if error_code
|
28
|
-
|
29
|
-
{ message: message['Message'], error_code: error_code }
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|