icasework 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/dependabot.yml +8 -0
- data/.github/workflows/ci.yml +31 -0
- data/.github/workflows/rubocop.yml +21 -0
- data/.gitignore +11 -0
- data/.rubocop.yml +40 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +131 -0
- data/LICENSE.txt +21 -0
- data/README.md +44 -0
- data/Rakefile +10 -0
- data/bin/bundle +114 -0
- data/bin/console +16 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/bin/setup +8 -0
- data/icasework.gemspec +40 -0
- data/lib/icasework/case.rb +101 -0
- data/lib/icasework/classification.rb +15 -0
- data/lib/icasework/document.rb +59 -0
- data/lib/icasework/errors.rb +18 -0
- data/lib/icasework/lazy_hash.rb +35 -0
- data/lib/icasework/resource/curl.rb +34 -0
- data/lib/icasework/resource/data.rb +63 -0
- data/lib/icasework/resource/payload.rb +50 -0
- data/lib/icasework/resource.rb +120 -0
- data/lib/icasework/token/bearer.rb +37 -0
- data/lib/icasework/token/jwt.rb +40 -0
- data/lib/icasework/version.rb +5 -0
- data/lib/icasework/xml_converter.rb +21 -0
- data/lib/icasework.rb +52 -0
- metadata +149 -0
data/icasework.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/icasework/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'icasework'
|
7
|
+
spec.version = Icasework::VERSION
|
8
|
+
spec.authors = ['mySociety']
|
9
|
+
spec.email = ['hello@mysociety.org']
|
10
|
+
|
11
|
+
spec.summary = 'Ruby library for the iCasework API.'
|
12
|
+
spec.description = 'iCasework is a case management software that enables ' \
|
13
|
+
'organisations of all sizes to do a better job of case management'
|
14
|
+
spec.homepage = 'https://github.com/mysociety/icasework-ruby/'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
|
17
|
+
|
18
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
19
|
+
|
20
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
21
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
22
|
+
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added
|
25
|
+
# into git.
|
26
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
27
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
28
|
+
f.match(%r{^(test|spec|features)/})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
spec.bindir = 'exe'
|
32
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
33
|
+
spec.require_paths = ['lib']
|
34
|
+
|
35
|
+
spec.add_dependency 'activesupport', '>= 4.0.0'
|
36
|
+
spec.add_dependency 'jwt', '~> 2.2.0'
|
37
|
+
spec.add_dependency 'nokogiri', '~> 1.0'
|
38
|
+
spec.add_dependency 'pdf-reader', '~> 2.4.0'
|
39
|
+
spec.add_dependency 'rest-client', '~> 2.1.0'
|
40
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/hash/deep_merge'
|
4
|
+
|
5
|
+
module Icasework
|
6
|
+
##
|
7
|
+
# A Ruby representation of a case in iCasework
|
8
|
+
#
|
9
|
+
class Case
|
10
|
+
class << self
|
11
|
+
def where(params)
|
12
|
+
cases = Icasework::Resource.get_cases(params).data[:cases]
|
13
|
+
return [] unless cases
|
14
|
+
|
15
|
+
cases[:case].map { |data| new(case_data(data)) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def create(params)
|
19
|
+
data = Icasework::Resource.create_case(params).data[:createcaseresponse]
|
20
|
+
return nil unless data
|
21
|
+
|
22
|
+
new(case_details: { case_id: data[:caseid] })
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def case_data(data)
|
28
|
+
{
|
29
|
+
case_details: case_details_data(data),
|
30
|
+
case_status: case_status_data(data),
|
31
|
+
case_status_receipt: case_status_receipt_data(data),
|
32
|
+
attributes: data[:attributes],
|
33
|
+
classifications: [data[:classifications][:classification]].flatten,
|
34
|
+
documents: [data[:documents][:document]].flatten
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def case_details_data(data)
|
39
|
+
{ case_id: data[:case_id], case_type: data[:type],
|
40
|
+
case_label: data[:label] }
|
41
|
+
end
|
42
|
+
|
43
|
+
def case_status_receipt_data(data)
|
44
|
+
{ method: data[:request_method], time_created: data[:request_date] }
|
45
|
+
end
|
46
|
+
|
47
|
+
def case_status_data(data)
|
48
|
+
{ status: data[:status] }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize(hash)
|
53
|
+
@hash = LazyHash.new(hash) do
|
54
|
+
load_additional_data!
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def case_id
|
59
|
+
self[:case_details][:case_id]
|
60
|
+
end
|
61
|
+
|
62
|
+
def [](key)
|
63
|
+
@hash[key]
|
64
|
+
end
|
65
|
+
|
66
|
+
def classifications
|
67
|
+
@hash[:classifications].map { |c| Classification.new(c) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def documents
|
71
|
+
@hash[:documents].map { |d| Document.new(d) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_h
|
75
|
+
@hash.to_h
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def load_additional_data!
|
81
|
+
return @hash if @loaded
|
82
|
+
|
83
|
+
@loaded = true
|
84
|
+
@hash.deep_merge!(fetch_additional_data)
|
85
|
+
end
|
86
|
+
|
87
|
+
def fetch_additional_data
|
88
|
+
@fetch_additional_data ||= begin
|
89
|
+
cases = Icasework::Resource.get_case_details(
|
90
|
+
case_id: case_id
|
91
|
+
).data[:cases]
|
92
|
+
|
93
|
+
if cases
|
94
|
+
cases[:case]
|
95
|
+
else
|
96
|
+
{}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Icasework
|
4
|
+
##
|
5
|
+
# A Ruby representation of a classification in iCasework
|
6
|
+
#
|
7
|
+
class Classification
|
8
|
+
attr_reader :group, :title
|
9
|
+
|
10
|
+
def initialize(attributes)
|
11
|
+
@group = attributes[:group]
|
12
|
+
@title = attributes[:__content__]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pdf/reader'
|
4
|
+
|
5
|
+
module Icasework
|
6
|
+
##
|
7
|
+
# A Ruby representation of a document in iCasework
|
8
|
+
#
|
9
|
+
class Document
|
10
|
+
class << self
|
11
|
+
def where(params)
|
12
|
+
documents = Icasework::Resource.get_case_documents(params).
|
13
|
+
data[:documents]
|
14
|
+
return [] unless documents
|
15
|
+
|
16
|
+
[documents[:document]].flatten.map do |attributes|
|
17
|
+
new(attributes)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def find(document_id: nil, **params)
|
22
|
+
documents = where(params)
|
23
|
+
return documents unless document_id
|
24
|
+
|
25
|
+
documents.find { |d| d.attributes[:id] == document_id }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :attributes, :url
|
30
|
+
|
31
|
+
def initialize(attributes)
|
32
|
+
@attributes = attributes
|
33
|
+
@url = attributes[:__content__]
|
34
|
+
end
|
35
|
+
|
36
|
+
def pdf?
|
37
|
+
attributes[:type] == 'application/pdf'
|
38
|
+
end
|
39
|
+
|
40
|
+
def pdf_contents
|
41
|
+
return unless pdf?
|
42
|
+
|
43
|
+
PDF::Reader.open(pdf_file) do |reader|
|
44
|
+
reader.pages.map(&:text).join
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def pdf_file
|
51
|
+
raw = RestClient::Request.execute(
|
52
|
+
method: :get,
|
53
|
+
url: url,
|
54
|
+
raw_response: true
|
55
|
+
)
|
56
|
+
raw.file
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Icasework
|
4
|
+
##
|
5
|
+
# An API authentication error
|
6
|
+
#
|
7
|
+
AuthenticationError = Class.new(RuntimeError)
|
8
|
+
|
9
|
+
##
|
10
|
+
# A request error
|
11
|
+
#
|
12
|
+
RequestError = Class.new(RuntimeError)
|
13
|
+
|
14
|
+
##
|
15
|
+
# A response error
|
16
|
+
#
|
17
|
+
ResponseError = Class.new(RuntimeError)
|
18
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'delegate'
|
4
|
+
|
5
|
+
module Icasework
|
6
|
+
##
|
7
|
+
# A hash which will attempt to lazy load a value from given block when the key
|
8
|
+
# is missing.
|
9
|
+
#
|
10
|
+
class LazyHash < SimpleDelegator
|
11
|
+
def initialize(hash, key = nil, &block)
|
12
|
+
@hash = hash
|
13
|
+
@key = key
|
14
|
+
@block = block
|
15
|
+
|
16
|
+
@hash.default_proc = proc do |h, k|
|
17
|
+
new_hash = @block.call
|
18
|
+
new_hash = new_hash[@key] if @key
|
19
|
+
h[k] = new_hash.fetch(k)
|
20
|
+
end
|
21
|
+
|
22
|
+
super(@hash)
|
23
|
+
end
|
24
|
+
|
25
|
+
def [](key)
|
26
|
+
value = @hash[key]
|
27
|
+
case value
|
28
|
+
when Hash
|
29
|
+
LazyHash.new(value, key, &@block)
|
30
|
+
else
|
31
|
+
value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Icasework
|
4
|
+
class Resource
|
5
|
+
##
|
6
|
+
# Method to output a Icasework::Resource instance as a curl command:
|
7
|
+
#
|
8
|
+
module Curl
|
9
|
+
def to_curl
|
10
|
+
"curl #{curl_params}#{curl_auth}'#{url}'"
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def curl_auth
|
16
|
+
auth_header = headers[:authorization]
|
17
|
+
"-H 'Authorization: #{auth_header}' " if auth_header
|
18
|
+
end
|
19
|
+
|
20
|
+
def curl_params
|
21
|
+
case method
|
22
|
+
when :get
|
23
|
+
return '-X GET ' if payload[:params].empty?
|
24
|
+
|
25
|
+
"-G -d '#{URI.encode_www_form(payload[:params])}' "
|
26
|
+
when :post
|
27
|
+
return '-X POST ' if payload.empty?
|
28
|
+
|
29
|
+
"-X POST -d '#{URI.encode_www_form(payload)}' "
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Icasework
|
4
|
+
class Resource
|
5
|
+
##
|
6
|
+
# Converts data returned from the iCasework API into a more "Ruby like" hash
|
7
|
+
#
|
8
|
+
module Data
|
9
|
+
class << self
|
10
|
+
def process(data)
|
11
|
+
case data
|
12
|
+
when Hash
|
13
|
+
convert_keys(array_keys_to_array(flat_keys_to_nested(data)))
|
14
|
+
when Array
|
15
|
+
data.map { |d| process(d) }
|
16
|
+
else
|
17
|
+
data
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# converts: { 'foo.bar': 'baz' }
|
24
|
+
# into { foo: { bar: 'baz' } }
|
25
|
+
def flat_keys_to_nested(hash)
|
26
|
+
hash.each_with_object({}) do |(key, value), all|
|
27
|
+
key_parts = key.to_s.split('.')
|
28
|
+
leaf = key_parts[0...-1].inject(all) { |h, k| h[k] ||= {} }
|
29
|
+
leaf[key_parts.last] = process(value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# converts: { 'n1': 'foo', 'n2': 'bar' }
|
34
|
+
# into: { n: ['foo', 'bar'] }
|
35
|
+
def array_keys_to_array(hash)
|
36
|
+
hash.each_with_object({}) do |(key, value), all|
|
37
|
+
if key.to_s =~ /^(.*)\d+$/
|
38
|
+
key = Regexp.last_match(1)
|
39
|
+
all[key] ||= []
|
40
|
+
all[key] << process(value)
|
41
|
+
else
|
42
|
+
all[key] = process(value)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# converts: 'FooBar'
|
48
|
+
# into: :foo_bar
|
49
|
+
def convert_keys(hash)
|
50
|
+
hash.each_with_object({}) do |(key, value), all|
|
51
|
+
converted_key = key.gsub(/([a-z\d])?([A-Z])/) do
|
52
|
+
first = Regexp.last_match(1)
|
53
|
+
second = Regexp.last_match(2)
|
54
|
+
"#{"#{first}_" if first}#{second.downcase}"
|
55
|
+
end
|
56
|
+
|
57
|
+
all[converted_key.to_sym] = process(value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Icasework
|
4
|
+
class Resource
|
5
|
+
##
|
6
|
+
# Converts payload for iCasework API endpoints into a flat/titlecase keys
|
7
|
+
#
|
8
|
+
module Payload
|
9
|
+
class << self
|
10
|
+
def process(data)
|
11
|
+
case data
|
12
|
+
when Hash
|
13
|
+
nested_to_flat_keys(convert_keys(data))
|
14
|
+
else
|
15
|
+
data
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# converts { 'foo' => { 'bar' => 'baz' } }
|
22
|
+
# into: { 'foo.bar' => 'baz' }
|
23
|
+
def nested_to_flat_keys(hash, key = [])
|
24
|
+
return { key.join('.') => process(hash) } unless hash.is_a?(Hash)
|
25
|
+
|
26
|
+
hash.inject({}) do |h, v|
|
27
|
+
h.merge!(nested_to_flat_keys(v[-1], key + [v[0]]))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# converts: :foo_bar
|
32
|
+
# into: 'FooBar'
|
33
|
+
def convert_keys(hash)
|
34
|
+
hash.each_with_object({}) do |(key, value), all|
|
35
|
+
converted_key = key if valid_keys.include?(key.to_s)
|
36
|
+
converted_key ||= key.to_s.gsub(/(?:^|_)([a-z])/i) do
|
37
|
+
Regexp.last_match(1).upcase
|
38
|
+
end
|
39
|
+
|
40
|
+
all[converted_key.to_s] = process(value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def valid_keys
|
45
|
+
%w[db fromseq toseq grant_type assertion access_token]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rest_client'
|
4
|
+
|
5
|
+
module Icasework
|
6
|
+
##
|
7
|
+
# API Endpoints for configured database
|
8
|
+
#
|
9
|
+
class Resource
|
10
|
+
class << self
|
11
|
+
def token(payload = {})
|
12
|
+
new(:post, 'token', payload, authorised: false, format: nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_cases(payload = {})
|
16
|
+
new(:get, 'getcases', payload, subdomain: 'uatportal')
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_case_attribute(payload = {})
|
20
|
+
new(:get, 'getcaseattribute', payload)
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_case_details(payload = {})
|
24
|
+
new(:get, 'getcasedetails', payload)
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_case_documents(payload = {})
|
28
|
+
new(:get, 'getcasedocuments', payload)
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_case(payload = {})
|
32
|
+
new(:post, 'createcase', payload)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
require 'icasework/resource/curl'
|
37
|
+
include Curl
|
38
|
+
|
39
|
+
attr_reader :method
|
40
|
+
|
41
|
+
def initialize(method, path, payload, **options)
|
42
|
+
@method = method
|
43
|
+
@path = path
|
44
|
+
@payload = payload
|
45
|
+
@options = options
|
46
|
+
end
|
47
|
+
|
48
|
+
def url
|
49
|
+
if Icasework.production?
|
50
|
+
"https://#{Icasework.account}.icasework.com/#{@path}"
|
51
|
+
else
|
52
|
+
subdomain = @options.fetch(:subdomain, 'uat')
|
53
|
+
"https://#{subdomain}.icasework.com/#{@path}?db=#{Icasework.account}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def headers
|
58
|
+
return {} unless authorised?
|
59
|
+
|
60
|
+
headers = {}
|
61
|
+
headers[:authorization] = "Bearer #{Icasework::Token::Bearer.generate}"
|
62
|
+
headers
|
63
|
+
end
|
64
|
+
|
65
|
+
def payload
|
66
|
+
return @payload if @payload_parsed
|
67
|
+
|
68
|
+
@payload[:format] = format if format
|
69
|
+
|
70
|
+
@payload = Payload.process(@payload)
|
71
|
+
@payload = { params: @payload } if method == :get
|
72
|
+
|
73
|
+
@payload_parsed = true
|
74
|
+
@payload
|
75
|
+
end
|
76
|
+
|
77
|
+
def data
|
78
|
+
response
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def authorised?
|
84
|
+
@options.fetch(:authorised, true)
|
85
|
+
end
|
86
|
+
|
87
|
+
def format
|
88
|
+
@options.fetch(:format, 'xml')
|
89
|
+
end
|
90
|
+
|
91
|
+
def resource
|
92
|
+
RestClient::Resource.new(url, headers: headers)
|
93
|
+
end
|
94
|
+
|
95
|
+
def response
|
96
|
+
resource.public_send(method, payload, &parser)
|
97
|
+
rescue RestClient::Exception => e
|
98
|
+
raise RequestError, e.message
|
99
|
+
end
|
100
|
+
|
101
|
+
def parser
|
102
|
+
lambda do |response, _request, _result|
|
103
|
+
Data.process(parse_format(response))
|
104
|
+
rescue JSON::ParserError
|
105
|
+
raise ResponseError, "JSON invalid (#{response.body[0...100]})"
|
106
|
+
rescue REXML::ParseException
|
107
|
+
raise ResponseError, "XML invalid (#{response.body[0...100]})"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def parse_format(response)
|
112
|
+
case format
|
113
|
+
when 'xml'
|
114
|
+
XMLConverter.new(response.body).to_h
|
115
|
+
else
|
116
|
+
JSON.parse(response.body)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Icasework
|
4
|
+
module Token
|
5
|
+
##
|
6
|
+
# Generate access token for Bearer authorisation header
|
7
|
+
#
|
8
|
+
class Bearer
|
9
|
+
class << self
|
10
|
+
def generate
|
11
|
+
new Icasework::Resource.token(payload).data
|
12
|
+
rescue RequestError, ResponseError => e
|
13
|
+
raise AuthenticationError, e.message
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def payload
|
19
|
+
{
|
20
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
21
|
+
assertion: Icasework::Token::JWT.generate
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(data)
|
27
|
+
@access_token = data.fetch(:access_token)
|
28
|
+
@token_type = data.fetch(:token_type)
|
29
|
+
@expires_in = data.fetch(:expires_in)
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
@access_token
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'jwt'
|
4
|
+
|
5
|
+
module Icasework
|
6
|
+
module Token
|
7
|
+
##
|
8
|
+
# Generate JSON web token for OAuth API authentication
|
9
|
+
#
|
10
|
+
class JWT
|
11
|
+
class << self
|
12
|
+
def generate
|
13
|
+
new ::JWT.encode(payload, Icasework.secret_key, 'HS256')
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def payload
|
19
|
+
{
|
20
|
+
iss: Icasework.api_key,
|
21
|
+
aud: Icasework::Resource.token.url,
|
22
|
+
iat: Time.now.to_i
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(token)
|
28
|
+
@token = token
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
@token
|
33
|
+
end
|
34
|
+
|
35
|
+
def ==(other)
|
36
|
+
@token == other
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/hash/conversions'
|
4
|
+
|
5
|
+
module Icasework
|
6
|
+
##
|
7
|
+
# A patched version of ActiveSupport's XML converter which includes XML tag
|
8
|
+
# attributes
|
9
|
+
#
|
10
|
+
# Credit: https://stackoverflow.com/a/29431089
|
11
|
+
#
|
12
|
+
class XMLConverter < ActiveSupport::XMLConverter
|
13
|
+
private
|
14
|
+
|
15
|
+
def become_content?(value)
|
16
|
+
value['type'] == 'file' ||
|
17
|
+
(value['__content__'] &&
|
18
|
+
(value.keys.size == 1 && value['__content__'].present?))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/icasework.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'icasework/version'
|
4
|
+
|
5
|
+
##
|
6
|
+
# This module is the main entry point of the Gem
|
7
|
+
#
|
8
|
+
module Icasework
|
9
|
+
require 'icasework/case'
|
10
|
+
require 'icasework/classification'
|
11
|
+
require 'icasework/document'
|
12
|
+
require 'icasework/errors'
|
13
|
+
require 'icasework/lazy_hash'
|
14
|
+
require 'icasework/resource'
|
15
|
+
require 'icasework/resource/data'
|
16
|
+
require 'icasework/resource/payload'
|
17
|
+
require 'icasework/token/jwt'
|
18
|
+
require 'icasework/token/bearer'
|
19
|
+
require 'icasework/xml_converter'
|
20
|
+
|
21
|
+
ConfigurationError = Class.new(StandardError)
|
22
|
+
|
23
|
+
class << self
|
24
|
+
attr_writer :account, :api_key, :secret_key
|
25
|
+
|
26
|
+
def account
|
27
|
+
@account || raise(
|
28
|
+
ConfigurationError, 'Icasework.account not configured'
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def api_key
|
33
|
+
@api_key || raise(
|
34
|
+
ConfigurationError, 'Icasework.api_key not configured'
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def secret_key
|
39
|
+
@secret_key || raise(
|
40
|
+
ConfigurationError, 'Icasework.secret_key not configured'
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
def env=(env)
|
45
|
+
@production = (env == 'production')
|
46
|
+
end
|
47
|
+
|
48
|
+
def production?
|
49
|
+
@production || false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|