arbetsformedlingen 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12c4c0e865fa8cc5a666fbc8089cb02fff2e1e95050e97ee2de84a47728e1aa3
4
- data.tar.gz: 2a44cd44d1c8586067b181d3c2ff5e404cb2abb91d09c566465bb5fda09d6a1f
3
+ metadata.gz: 15dfcdcd827c97239a8d14df13084de7bc96980824b7304efb5ddb4d11d640bd
4
+ data.tar.gz: 56eaa06682c5b5b7b31cf6f0ba21e12a657f1a92bbfa1622530fc1ba4f6fc37b
5
5
  SHA512:
6
- metadata.gz: 887828b878412c4ebfec3130c910f1030e58f15367254298f160addbed4c6f81b4f4df48963cb2045179af5b87573e447fddd2fcd6010a42906e04de71eff1c5
7
- data.tar.gz: de32a1fd18c3de44f1cddf677f20c47f79b96e01d5cc4c797256d11832e777d05ff5974713222574d7101d63ff1b856111a45fd7b029ca81b6cf91d8e86d1590
6
+ metadata.gz: 24713c7b92467e96a039bb6e68a5f91eebdc8e7ccef3288af4844998ce4f28baff1d9d2fa2b982358d1384b69da2970e0e8b66924c9ca6ef2e103ce9afc8e4f3
7
+ data.tar.gz: 790862d6b086c93e9a98cdcca33440a6d742bafcc13360dc1c20bf86d9b000594045f83903c52b25e34f6c114c2036d066bfa213a70786dc59749dc9da43b76a
@@ -0,0 +1,2 @@
1
+ rubocop:
2
+ config_file: .rubocop.yml
@@ -1,6 +1,7 @@
1
1
  sudo: false
2
2
  language: ruby
3
+ cache: bundler
3
4
  rvm:
4
5
  - 2.3.0
5
6
  - 2.5.0
6
- before_install: gem install bundler -v 1.6.1
7
+ before_install: gem install bundler
@@ -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
- * [API Client](#api-client)
14
- * [Post job ad](#post-job-ad)
15
- * [WSOccupation API Client](#wsoccupation-api-client)
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
- ## Installation
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
- :information_source: There is quite a lot of data you can/must send to the API when creating an ad.
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
- ```ruby
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
 
@@ -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)
@@ -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