icasework 0.1.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 +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
|