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 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