crmp_client 0.2.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/.circleci/config.yml +15 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +19 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +105 -0
- data/README.md +92 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/crmp_client.gemspec +43 -0
- data/lib/crmp_client/api.rb +90 -0
- data/lib/crmp_client/client.rb +120 -0
- data/lib/crmp_client/configuration.rb +19 -0
- data/lib/crmp_client/errors.rb +24 -0
- data/lib/crmp_client/version.rb +5 -0
- data/lib/crmp_client.rb +32 -0
- metadata +227 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f00f15215e094aa226993d13ceba1908ccb109bdc6a04c309bc6c78460091dbf
|
4
|
+
data.tar.gz: 6ffbf58d184ff88233f00e3140f2a3a81a664f46e377b53dcff0d48839346037
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cd3fe2f7db416bc341aa3f11a4c35257ad1d3dec3baefc6ebaf4d36826270f25e911de4f7a98763fdc3589bf5dd22024c499204c94d45f4ff12cab75db010ec9
|
7
|
+
data.tar.gz: a61f35e5e10855fbddeaffaf4000946535171133c3501a6063e8bb17388ef8ab58f4c259590223d7984d12435074aac030677a8299a91fd98eb0e7c8017345ce
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rspec
|
3
|
+
|
4
|
+
AllCops:
|
5
|
+
TargetRubyVersion: 2.4
|
6
|
+
NewCops: enable
|
7
|
+
|
8
|
+
Metrics/BlockLength:
|
9
|
+
Exclude:
|
10
|
+
- 'spec/**/*_spec.rb'
|
11
|
+
|
12
|
+
RSpec/NestedGroups:
|
13
|
+
Max: 4
|
14
|
+
|
15
|
+
RSpec/MultipleExpectations:
|
16
|
+
Max: 3
|
17
|
+
|
18
|
+
RSpec/ExampleLength:
|
19
|
+
Max: 20
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
crmp_client (0.2.0)
|
5
|
+
faraday (~> 2)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
addressable (2.8.0)
|
11
|
+
public_suffix (>= 2.0.2, < 5.0)
|
12
|
+
ast (2.4.2)
|
13
|
+
codecov (0.4.0)
|
14
|
+
simplecov (>= 0.15, < 0.22)
|
15
|
+
coderay (1.1.3)
|
16
|
+
concurrent-ruby (1.1.8)
|
17
|
+
crack (0.4.5)
|
18
|
+
rexml
|
19
|
+
diff-lcs (1.4.4)
|
20
|
+
docile (1.3.5)
|
21
|
+
faker (2.15.1)
|
22
|
+
i18n (>= 1.6, < 2)
|
23
|
+
faraday (2.7.10)
|
24
|
+
faraday-net_http (>= 2.0, < 3.1)
|
25
|
+
ruby2_keywords (>= 0.0.4)
|
26
|
+
faraday-net_http (3.0.2)
|
27
|
+
hashdiff (1.0.1)
|
28
|
+
i18n (1.8.7)
|
29
|
+
concurrent-ruby (~> 1.0)
|
30
|
+
method_source (1.0.0)
|
31
|
+
parallel (1.20.1)
|
32
|
+
parser (3.0.0.0)
|
33
|
+
ast (~> 2.4.1)
|
34
|
+
pry (0.13.1)
|
35
|
+
coderay (~> 1.1)
|
36
|
+
method_source (~> 1.0)
|
37
|
+
public_suffix (4.0.6)
|
38
|
+
rainbow (3.0.0)
|
39
|
+
rake (13.0.3)
|
40
|
+
regexp_parser (2.0.3)
|
41
|
+
rexml (3.2.5)
|
42
|
+
rspec (3.10.0)
|
43
|
+
rspec-core (~> 3.10.0)
|
44
|
+
rspec-expectations (~> 3.10.0)
|
45
|
+
rspec-mocks (~> 3.10.0)
|
46
|
+
rspec-core (3.10.1)
|
47
|
+
rspec-support (~> 3.10.0)
|
48
|
+
rspec-expectations (3.10.1)
|
49
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
50
|
+
rspec-support (~> 3.10.0)
|
51
|
+
rspec-mocks (3.10.1)
|
52
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
53
|
+
rspec-support (~> 3.10.0)
|
54
|
+
rspec-support (3.10.1)
|
55
|
+
rspec_junit_formatter (0.4.1)
|
56
|
+
rspec-core (>= 2, < 4, != 2.12.0)
|
57
|
+
rubocop (1.8.1)
|
58
|
+
parallel (~> 1.10)
|
59
|
+
parser (>= 3.0.0.0)
|
60
|
+
rainbow (>= 2.2.2, < 4.0)
|
61
|
+
regexp_parser (>= 1.8, < 3.0)
|
62
|
+
rexml
|
63
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
64
|
+
ruby-progressbar (~> 1.7)
|
65
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
66
|
+
rubocop-ast (1.4.1)
|
67
|
+
parser (>= 2.7.1.5)
|
68
|
+
rubocop-rspec (2.1.0)
|
69
|
+
rubocop (~> 1.0)
|
70
|
+
rubocop-ast (>= 1.1.0)
|
71
|
+
ruby-progressbar (1.11.0)
|
72
|
+
ruby2_keywords (0.0.5)
|
73
|
+
simplecov (0.21.2)
|
74
|
+
docile (~> 1.1)
|
75
|
+
simplecov-html (~> 0.11)
|
76
|
+
simplecov_json_formatter (~> 0.1)
|
77
|
+
simplecov-html (0.12.3)
|
78
|
+
simplecov_json_formatter (0.1.2)
|
79
|
+
unicode-display_width (2.0.0)
|
80
|
+
webmock (3.11.1)
|
81
|
+
addressable (>= 2.3.6)
|
82
|
+
crack (>= 0.3.2)
|
83
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
84
|
+
yard (0.9.26)
|
85
|
+
|
86
|
+
PLATFORMS
|
87
|
+
ruby
|
88
|
+
x86_64-linux
|
89
|
+
|
90
|
+
DEPENDENCIES
|
91
|
+
bundler (~> 2.1)
|
92
|
+
codecov (>= 0.4)
|
93
|
+
crmp_client!
|
94
|
+
faker (~> 2.15)
|
95
|
+
pry (>= 0.13)
|
96
|
+
rake (>= 13.0)
|
97
|
+
rspec (~> 3.0)
|
98
|
+
rspec_junit_formatter
|
99
|
+
rubocop (~> 1.8)
|
100
|
+
rubocop-rspec (~> 2.1)
|
101
|
+
webmock (~> 3.11)
|
102
|
+
yard (>= 0.9.26)
|
103
|
+
|
104
|
+
BUNDLED WITH
|
105
|
+
2.2.6
|
data/README.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# CrmpClient
|
2
|
+
|
3
|
+
CrmpClient is a Ruby Gem client for easy use of the API exposted by the Crmp application.
|
4
|
+
|
5
|
+
You must have access to a running instance of the Crmp application for this client to be of any use.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'crmp_client'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install crmp_client
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
### Basic Example
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
# Create the client
|
29
|
+
client = CrmpClient.new('https://crmp.my-organisation.org', 'my-api-token')
|
30
|
+
|
31
|
+
# Get all lists in the crmp instance
|
32
|
+
client.lists
|
33
|
+
|
34
|
+
# Iterate through each item in list 1
|
35
|
+
client.each_list_item(1)
|
36
|
+
```
|
37
|
+
|
38
|
+
### Configuring the client
|
39
|
+
|
40
|
+
Rather than passing the base URI and API token directly to `CrmpClient.new`, you can instead configure a default base URI, and default API token.
|
41
|
+
|
42
|
+
You can also override the default logger if desired. In a Rails environment this will automatically default to `Rails.logger`, and in non-rails will default to an instance of `Logger` logging to STDOUT.
|
43
|
+
|
44
|
+
For Rails apps, the recommendation is to configure the Crmp Client within an initializer file:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
# config/initializers/crmp_client.rb
|
48
|
+
|
49
|
+
CrmpClient.configure do |config|
|
50
|
+
config.default_base_uri = 'https://crmp.my-organisation.org'
|
51
|
+
config.default_api_token = 'my-api-token'
|
52
|
+
|
53
|
+
# Override default logger if desired - defaults to `Rails.logger` for Rails apps / `Logger.new($stdout)` for non-Rails
|
54
|
+
# config.logger = Rails.logger
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
If a default Base URI & API token have been configured, then a client can be created without any arguments:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
client = CrmpClient.new
|
62
|
+
```
|
63
|
+
|
64
|
+
However, you may still explicitly pass parameters to override the defaults:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
client = CrmpClient.new('https://crmp-staging.my-organisation.org', 'my-staging-api-token')
|
68
|
+
```
|
69
|
+
|
70
|
+
### Advanced options
|
71
|
+
|
72
|
+
Many of the APIs exposed by this gem return multiple objects - eg. all items in a list, or all areas matching some criteria.
|
73
|
+
|
74
|
+
This client exposes standard ways of getting all objects. For example, `client.lists` would get all lists, while `client.each_list { |list| ... }` would iterate over all lists, performing the given block on each list.
|
75
|
+
|
76
|
+
Sometimes a client may wish to start at a specific offset, of process only a limited number of pages of results - this can be achieved by providing any of the paged API calls with an options hash including the `:page` and/or `:max_pages` options, eg:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
client.lists({ page: 1, max_pages: 1})
|
80
|
+
```
|
81
|
+
|
82
|
+
The above example would start on page 1 (the default is page 0), and return only 1 page of results (by default it will return all pages).
|
83
|
+
|
84
|
+
## Development
|
85
|
+
|
86
|
+
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.
|
87
|
+
|
88
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
89
|
+
|
90
|
+
## Contributing
|
91
|
+
|
92
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/38degrees/crmp_client.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'crmp_client'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/crmp_client.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/crmp_client/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'crmp_client'
|
7
|
+
spec.version = CrmpClient::VERSION
|
8
|
+
spec.authors = ['Andrew Sibley']
|
9
|
+
spec.email = ['andrew.s@38degrees.org.uk']
|
10
|
+
|
11
|
+
spec.summary = 'Ruby client for the 38 Degrees CRMP system.'
|
12
|
+
spec.homepage = 'https://github.com/38degrees/crmp_client'
|
13
|
+
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
|
15
|
+
|
16
|
+
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
17
|
+
# spec.metadata['homepage_uri'] = spec.homepage
|
18
|
+
# spec.metadata['source_code_uri'] = "TODO: Put your gem's public repo URL here."
|
19
|
+
# spec.metadata['changelog_uri'] = "TODO: Put your gem's CHANGELOG.md URL here."
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
25
|
+
end
|
26
|
+
spec.bindir = 'exe'
|
27
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ['lib']
|
29
|
+
|
30
|
+
spec.add_dependency 'faraday', '~> 2'
|
31
|
+
|
32
|
+
spec.add_development_dependency 'bundler', '~> 2.1'
|
33
|
+
spec.add_development_dependency 'codecov', '>= 0.4'
|
34
|
+
spec.add_development_dependency 'faker', '~> 2.15'
|
35
|
+
spec.add_development_dependency 'pry', '>= 0.13'
|
36
|
+
spec.add_development_dependency 'rake', '>= 13.0'
|
37
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
38
|
+
spec.add_development_dependency 'rspec_junit_formatter'
|
39
|
+
spec.add_development_dependency 'rubocop', '~> 1.8'
|
40
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.1'
|
41
|
+
spec.add_development_dependency 'webmock', '~> 3.11'
|
42
|
+
spec.add_development_dependency 'yard', '>= 0.9.26'
|
43
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module CrmpClient
|
7
|
+
# Low-level class for calling the CRMP API. It is not recommended to use this class directly.
|
8
|
+
# The +CrmpClient::Client+ class is designed to be directly used by applications.
|
9
|
+
#
|
10
|
+
# This class provides low-level wrappers for making HTTP calls to the CRMP application.
|
11
|
+
class Api
|
12
|
+
API_VERSION = 'v1'
|
13
|
+
|
14
|
+
def initialize(crmp_base_uri, crmp_api_token)
|
15
|
+
@httpclient = Faraday.new(
|
16
|
+
url: "#{crmp_base_uri.chomp('/')}/api/#{API_VERSION}",
|
17
|
+
headers: {
|
18
|
+
'Content-Type' => 'application/json',
|
19
|
+
'Accept' => 'application/json',
|
20
|
+
'Authorization' => "Token token=#{crmp_api_token}"
|
21
|
+
}
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Helper method used to execute a block on each object returned by an API - particularly useful for paged API
|
26
|
+
# endpoints, as this method handles iterating through all pages.
|
27
|
+
#
|
28
|
+
# This method only keeps a single page of results in-memory at a time.
|
29
|
+
def each_api_call(path, params, options, block)
|
30
|
+
paged_api_call(path, params, options) do |single_page_response|
|
31
|
+
single_page_response['results'].each { |object| block.call(object) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Helper method used to collect all API results into a single array - particularly useful for paged API endpoints
|
36
|
+
# as this method handles iterating through all pages.
|
37
|
+
#
|
38
|
+
# Note that this may result in a large array which consumes a lot of memory.
|
39
|
+
def collect_api_call(path, params, options)
|
40
|
+
all_results = []
|
41
|
+
paged_api_call(path, params, options) do |single_page_response|
|
42
|
+
all_results << single_page_response['results']
|
43
|
+
end
|
44
|
+
all_results.flatten
|
45
|
+
end
|
46
|
+
|
47
|
+
# Helper method used by each_api_call & collect_api_call
|
48
|
+
#
|
49
|
+
# Calls the given `path` with the given `params`, starting with the page number specified in the options hash, and
|
50
|
+
# fetching the maximum number of pages specified in the options hash. Expects a block to be given, which is passed
|
51
|
+
# the response object for each page.
|
52
|
+
#
|
53
|
+
# By default, if no options are provided, this method fetches all pages.
|
54
|
+
#
|
55
|
+
# Although this includes logic for paging, if an endpoint is not paged, CRMP will ignore the `page` param, and
|
56
|
+
# `response['next_page']` will be `nil`, so this logic will work on un-paged endpoints too.
|
57
|
+
def paged_api_call(path, params, options, &block)
|
58
|
+
page = options[:page] || 0
|
59
|
+
max_pages = options[:max_pages]
|
60
|
+
pages_processed = 0
|
61
|
+
|
62
|
+
while page && (max_pages.nil? || pages_processed < max_pages)
|
63
|
+
response = raw_api_call(path, params.merge({ page: page }))
|
64
|
+
block.call(response) # execute the block passed by the calling method
|
65
|
+
pages_processed += 1
|
66
|
+
page = response['next_page'] # will be nil if there are no more pages, or if the API endpoint is un-paged
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Helper method to make a raw API call. Returns the response body, parsed from JSON into a Ruby hash. If the
|
71
|
+
# response status is not 200 (OK) it will raise an error.
|
72
|
+
def raw_api_call(path, params)
|
73
|
+
response = @httpclient.post(path, params.to_json)
|
74
|
+
if response.status == 200
|
75
|
+
parse_response(response)
|
76
|
+
else
|
77
|
+
CrmpClient.configuration.logger.error do
|
78
|
+
"CRMP API Call to #{path} with #{params} failed with status #{response.status}"
|
79
|
+
end
|
80
|
+
raise CrmpClient::HttpError.new(response.status, response.body)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_response(response)
|
85
|
+
JSON.parse(response.body)
|
86
|
+
rescue JSON::ParserError => e
|
87
|
+
raise(CrmpClient::InvalidResponseBodyError, e.message)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CrmpClient
|
4
|
+
# This is the primary class provided by the CrmpClient gem, providing a wrapper to call various Crmp API endpoints.
|
5
|
+
#
|
6
|
+
# This class provides methods which automatically deal with low-level concerns like paging of the Crmp API.
|
7
|
+
class Client
|
8
|
+
def initialize(base_uri, api_token)
|
9
|
+
raise(ArgumentError, 'No base_uri - pass as param or set a default in initializer') unless base_uri
|
10
|
+
raise(ArgumentError, 'No api_token - pass as param or set a default in initializer') unless api_token
|
11
|
+
|
12
|
+
@api = CrmpClient::Api.new(base_uri, api_token)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Non-paged APIs
|
16
|
+
#
|
17
|
+
# These take a unique identifier as a parameter, and return a hash containing the various fields for that object.
|
18
|
+
|
19
|
+
# Get a single Membership object, looking it up using it's unique identifier
|
20
|
+
def membership(identifier)
|
21
|
+
@api.raw_api_call('membership.json', { identifier: identifier })
|
22
|
+
end
|
23
|
+
|
24
|
+
# Paged APIs
|
25
|
+
#
|
26
|
+
# These take variable arguments depending upon the API endpoint, but there are some common features.
|
27
|
+
#
|
28
|
+
# All methods accept an options hash, which allows the calling code to specify a starting page and maximum pages.
|
29
|
+
# To set the starting page, set the `:page` option - this is 0-based and defaults to 0.
|
30
|
+
# To set a maximum number of pages to return from the API, set the `:max_pages` option. By default this is `nil`
|
31
|
+
# which means all pages are returned (aside from any pages skipped by the `:page` option).
|
32
|
+
#
|
33
|
+
# Each CRMP API endpoing has 2 corresponding methods, for example `lists` & `each_list`.
|
34
|
+
# - `lists` returns all matching lists as one array of hash objects. This is useful if you need all objects in
|
35
|
+
# memory at the same time - but note, some of these objects are large & complex, and this could consume a lot of
|
36
|
+
# memory.
|
37
|
+
# - `each_list` expects a block, and executes the block once for each list object returned by the API. This is
|
38
|
+
# recommended if you just want to perform an action with each object as it won't keep all objects in memory.
|
39
|
+
#
|
40
|
+
# For example, you could print out the name of each list using either `lists` or `each_list`, however `each_list`
|
41
|
+
# would generally be preferred for memory efficiency:
|
42
|
+
# - `crmp_client.lists.each { |list| puts "#{list.name}" }`
|
43
|
+
# - `crmp_client.each_list { |list| puts "#{list.name}" }`
|
44
|
+
|
45
|
+
# Get all memberships whose Organisation matches the given `organization_name`, and whose Role matches the given
|
46
|
+
# `role_name`. Both `organization_name` & `role_name` are optional, eg. if `role_name` is omitted then only
|
47
|
+
# `organization_name` is used to search for memberships.
|
48
|
+
def memberships(organization_name, role_name, options = {})
|
49
|
+
@api.collect_api_call('memberships.json', { organization: organization_name, role: role_name }, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Iterate over all memberships whose Organisation matches the given `organization_name`, and whose Role matches the
|
53
|
+
# given `role_name`. Both `organization_name` & `role_name` are optional, eg. if `role_name` is omitted then only
|
54
|
+
# `organization_name` is used to search for memberships.
|
55
|
+
def each_membership(organization_name, role_name, options = {}, &block)
|
56
|
+
@api.each_api_call('memberships.json', { organization: organization_name, role: role_name }, options, block)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Get all all lists
|
60
|
+
def lists(options = {})
|
61
|
+
@api.collect_api_call('lists.json', {}, options).sort_by { |list| list['created_at'] }
|
62
|
+
end
|
63
|
+
|
64
|
+
# Iterate over each list
|
65
|
+
def each_list(options = {}, &block)
|
66
|
+
@api.each_api_call('lists.json', {}, options, block)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get all items which are in a specific list
|
70
|
+
def list_items(list_id, options = {})
|
71
|
+
@api.collect_api_call('list/items.json', { list_id: list_id }, options)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Iterate over all items in a specific list
|
75
|
+
def each_list_item(list_id, options = {}, &block)
|
76
|
+
@api.each_api_call('list/items.json', { list_id: list_id }, options, block)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Get all areas of a specific AreaClassification
|
80
|
+
def areas(area_class, options = {})
|
81
|
+
@api.collect_api_call('areas.json', { area_classification: area_class }, options)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Iterate over all areas of a specific AreaClassification
|
85
|
+
def each_area(area_class, options = {}, &block)
|
86
|
+
@api.each_api_call('areas.json', { area_classification: area_class }, options, block)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Get all areas of a specific AreaClassification, including memberships which represent each area
|
90
|
+
def areas_with_memberships(area_class, options = {})
|
91
|
+
@api.collect_api_call('areas/memberships.json', { area_classification: area_class }, options)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Iterate over all areas of a specific AreaClassification, including memberships which represent each area
|
95
|
+
def each_area_with_memberships(area_class, options = {}, &block)
|
96
|
+
@api.each_api_call('areas/memberships.json', { area_classification: area_class }, options, block)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Get all areas whose AreaClassification matches `contained_area_class`, and which are contained within the given
|
100
|
+
# `containing_area_identifier`. Each area returned will also include a list of all areas which contain it.
|
101
|
+
def area_containments(containing_area_identifier, contained_area_class, options = {})
|
102
|
+
@api.collect_api_call(
|
103
|
+
'areas/containments.json',
|
104
|
+
{ containing_area: containing_area_identifier, contained_area_classification: contained_area_class },
|
105
|
+
options
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Iterate over all areas whose AreaClassification matches `contained_area_class`, and which are contained within the
|
110
|
+
# given `containing_area_identifier`. Each area returned will also include a list of all areas which contain it.
|
111
|
+
def each_area_containment(containing_area_identifier, contained_area_class, options = {}, &block)
|
112
|
+
@api.each_api_call(
|
113
|
+
'areas/containments.json',
|
114
|
+
{ containing_area: containing_area_identifier, contained_area_classification: contained_area_class },
|
115
|
+
options,
|
116
|
+
block
|
117
|
+
)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module CrmpClient
|
6
|
+
# This class acts as a store for global configuration of the CrmpClient gem.
|
7
|
+
#
|
8
|
+
# A singleton instance of this class is created in the top-level +CrmpClient+ module code.
|
9
|
+
class Configuration
|
10
|
+
attr_accessor :default_base_uri, :default_api_token, :logger
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@default_base_uri = nil
|
14
|
+
@default_api_token = nil
|
15
|
+
|
16
|
+
@logger = defined?(Rails.logger) ? Rails.logger : Logger.new($stdout)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CrmpClient
|
4
|
+
# Base class for all CrmpClient errors
|
5
|
+
class CrmpClientError < StandardError; end
|
6
|
+
|
7
|
+
# Class to wrap errors caused by unexpected HTTP status codes
|
8
|
+
class HttpError < CrmpClientError
|
9
|
+
attr_reader :code, :body
|
10
|
+
|
11
|
+
def initialize(code, body)
|
12
|
+
super()
|
13
|
+
@code = code
|
14
|
+
@body = body
|
15
|
+
end
|
16
|
+
|
17
|
+
def message
|
18
|
+
"HTTP code [#{@code}], response cody [#{@body}]"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Error to indicate that the HTTP body in the API response was invalid and could not be processed
|
23
|
+
class InvalidResponseBodyError < CrmpClientError; end
|
24
|
+
end
|
data/lib/crmp_client.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'crmp_client/api'
|
4
|
+
require_relative 'crmp_client/errors'
|
5
|
+
require_relative 'crmp_client/client'
|
6
|
+
require_relative 'crmp_client/configuration'
|
7
|
+
require_relative 'crmp_client/version'
|
8
|
+
|
9
|
+
# The main namespace for CrmpClient.
|
10
|
+
#
|
11
|
+
# It provides methods to configure the gem, and a convenience method to create a new +Client+ object.
|
12
|
+
#
|
13
|
+
module CrmpClient
|
14
|
+
class << self
|
15
|
+
def configuration
|
16
|
+
@configuration ||= Configuration.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure
|
20
|
+
yield(configuration)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return a new Client (which provides all the functionality of this gem), using passed parameters or the
|
24
|
+
# configured defaults.
|
25
|
+
def new(crmp_base_uri = nil, crmp_api_token = nil)
|
26
|
+
base_uri = crmp_base_uri || configuration.default_base_uri
|
27
|
+
api_token = crmp_api_token || configuration.default_api_token
|
28
|
+
|
29
|
+
Client.new(base_uri, api_token)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: crmp_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Sibley
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-08-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: codecov
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.4'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: faker
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.15'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.15'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.13'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.13'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '13.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '13.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec_junit_formatter
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.8'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.8'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop-rspec
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '2.1'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '2.1'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: webmock
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '3.11'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '3.11'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: yard
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 0.9.26
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 0.9.26
|
181
|
+
description:
|
182
|
+
email:
|
183
|
+
- andrew.s@38degrees.org.uk
|
184
|
+
executables: []
|
185
|
+
extensions: []
|
186
|
+
extra_rdoc_files: []
|
187
|
+
files:
|
188
|
+
- ".circleci/config.yml"
|
189
|
+
- ".gitignore"
|
190
|
+
- ".rspec"
|
191
|
+
- ".rubocop.yml"
|
192
|
+
- Gemfile
|
193
|
+
- Gemfile.lock
|
194
|
+
- README.md
|
195
|
+
- Rakefile
|
196
|
+
- bin/console
|
197
|
+
- bin/setup
|
198
|
+
- crmp_client.gemspec
|
199
|
+
- lib/crmp_client.rb
|
200
|
+
- lib/crmp_client/api.rb
|
201
|
+
- lib/crmp_client/client.rb
|
202
|
+
- lib/crmp_client/configuration.rb
|
203
|
+
- lib/crmp_client/errors.rb
|
204
|
+
- lib/crmp_client/version.rb
|
205
|
+
homepage: https://github.com/38degrees/crmp_client
|
206
|
+
licenses: []
|
207
|
+
metadata: {}
|
208
|
+
post_install_message:
|
209
|
+
rdoc_options: []
|
210
|
+
require_paths:
|
211
|
+
- lib
|
212
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
213
|
+
requirements:
|
214
|
+
- - ">="
|
215
|
+
- !ruby/object:Gem::Version
|
216
|
+
version: 2.4.0
|
217
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
218
|
+
requirements:
|
219
|
+
- - ">="
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: '0'
|
222
|
+
requirements: []
|
223
|
+
rubygems_version: 3.3.7
|
224
|
+
signing_key:
|
225
|
+
specification_version: 4
|
226
|
+
summary: Ruby client for the 38 Degrees CRMP system.
|
227
|
+
test_files: []
|