arbetsformedlingen 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://travis-ci.org/buren/arbetsformedlingen.svg?branch=master)](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
|
[![Postman](https://run.pstmn.io/button.svg)](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
|