dimelo_ccp_api 0.4.1
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/.gitignore +6 -0
- data/.ruby-version +1 -0
- data/.travis.yml +15 -0
- data/CHANGELOG.md +29 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +59 -0
- data/Rakefile +23 -0
- data/VERSION +1 -0
- data/dimelo_ccp_api.gemspec +26 -0
- data/examples/dimelo_api_test +34 -0
- data/gemfiles/Gemfile.activesupport-3.2.x +5 -0
- data/gemfiles/Gemfile.activesupport-4.0.x +5 -0
- data/gemfiles/Gemfile.activesupport-4.1.x +5 -0
- data/gemfiles/Gemfile.activesupport-head +5 -0
- data/lib/dimelo/ccp/api/basic_object.rb +17 -0
- data/lib/dimelo/ccp/api/client.rb +46 -0
- data/lib/dimelo/ccp/api/common/openable.rb +23 -0
- data/lib/dimelo/ccp/api/common/publishable.rb +23 -0
- data/lib/dimelo/ccp/api/common/starrable.rb +23 -0
- data/lib/dimelo/ccp/api/connection.rb +86 -0
- data/lib/dimelo/ccp/api/error.rb +71 -0
- data/lib/dimelo/ccp/api/lazzy_collection.rb +114 -0
- data/lib/dimelo/ccp/api/model/answer.rb +39 -0
- data/lib/dimelo/ccp/api/model/attachment.rb +44 -0
- data/lib/dimelo/ccp/api/model/category.rb +12 -0
- data/lib/dimelo/ccp/api/model/category_group.rb +12 -0
- data/lib/dimelo/ccp/api/model/feedback.rb +20 -0
- data/lib/dimelo/ccp/api/model/feedback_comment.rb +31 -0
- data/lib/dimelo/ccp/api/model/membership.rb +12 -0
- data/lib/dimelo/ccp/api/model/private_message.rb +8 -0
- data/lib/dimelo/ccp/api/model/question.rb +20 -0
- data/lib/dimelo/ccp/api/model/role.rb +8 -0
- data/lib/dimelo/ccp/api/model/user.rb +37 -0
- data/lib/dimelo/ccp/api/model/webhook.rb +9 -0
- data/lib/dimelo/ccp/api/model.rb +209 -0
- data/lib/dimelo/ccp/api/version.rb +7 -0
- data/lib/dimelo/ccp/api.rb +62 -0
- data/lib/dimelo_ccp_api.rb +1 -0
- data/spec/examples/openable_examples.rb +37 -0
- data/spec/examples/starrable_example.rb +57 -0
- data/spec/fixtures/files/logo.jpg +0 -0
- data/spec/lib/dimelo/ccp/api/client_spec.rb +111 -0
- data/spec/lib/dimelo/ccp/api/connection_spec.rb +129 -0
- data/spec/lib/dimelo/ccp/api/model/attachment_spec.rb +26 -0
- data/spec/lib/dimelo/ccp/api/model/feedback_spec.rb +10 -0
- data/spec/lib/dimelo/ccp/api/model/question_spec.rb +10 -0
- data/spec/lib/dimelo/ccp/api/model_spec.rb +162 -0
- data/spec/spec_helper.rb +7 -0
- metadata +174 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4962e1ddaa81b7ef970c119cbd677c7fc3a59fc1
|
4
|
+
data.tar.gz: 34a481ab52fcea68f15dce8208b0c77b24ae51f2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0ed9b3e676d8ad3f03370e33099b8d93e12f04f6768e49fb067db1689073da37db7deed45f0a9e9fd7af7e3fc4d924bf94baefb1dc479c2349b2a3b337efa233
|
7
|
+
data.tar.gz: c6db38d30585780a991826a384532b8f89a049ed4c8a5f56cfc507b8034c63f1a61df1aebbc8782fe9efb92a3c0cc92bf4a4366a4931924614eb1bdb8d7698ad
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.1
|
data/.travis.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.2
|
4
|
+
- 2.1
|
5
|
+
- 2.0
|
6
|
+
- ruby-head
|
7
|
+
- jruby-head
|
8
|
+
gemfile:
|
9
|
+
- gemfiles/Gemfile.activesupport-3.2.x
|
10
|
+
- gemfiles/Gemfile.activesupport-4.0.x
|
11
|
+
- gemfiles/Gemfile.activesupport-4.1.x
|
12
|
+
- gemfiles/Gemfile.activesupport-edge
|
13
|
+
matrix:
|
14
|
+
allow_failures:
|
15
|
+
- gemfile: gemfiles/Gemfile.activesupport-edge
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# 0.3.3
|
2
|
+
|
3
|
+
Remove warning when attribute is present in api but not defined in model
|
4
|
+
|
5
|
+
# 0.3.2
|
6
|
+
|
7
|
+
Implement webhook as a standard resource instead of crappy built-in stuff
|
8
|
+
|
9
|
+
# 0.3.1
|
10
|
+
|
11
|
+
Add a feature to push a webhook API configuration through API
|
12
|
+
|
13
|
+
# 0.2.2
|
14
|
+
|
15
|
+
Fix handling of validation errors, they now return status 422 and were incorrectely raise.
|
16
|
+
This fix restores the previous behaviour: returning a Dimelo record with AR errors.
|
17
|
+
|
18
|
+
# 0.2.1
|
19
|
+
|
20
|
+
Attempt to fix segfault in model.rb:116 (#inspect)
|
21
|
+
Fix HTTPS spec with github
|
22
|
+
|
23
|
+
# 0.2.0
|
24
|
+
|
25
|
+
Added support for Role + upgrade to Rspec 3
|
26
|
+
|
27
|
+
# 0.0.4
|
28
|
+
|
29
|
+
Support http_options for Client.new to be able to set dedicated timeout
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2006-2014 Dimelo SA
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Dimelo CCP API [](https://travis-ci.org/dimelo/dimelo_ccp_api) [](https://codeclimate.com/github/dimelo/dimelo_ccp_api)
|
2
|
+
|
3
|
+
Ruby client for the Dimelo Customer Community Platform
|
4
|
+
|
5
|
+
This client support most of Dimelo CCP resources, can read and write them, paginates with cursor like interface, supports attachments and supports proper validation and error format.
|
6
|
+
|
7
|
+
This is heavily used internaly at Dimelo.
|
8
|
+
|
9
|
+
# Compatibility
|
10
|
+
|
11
|
+
Compatible and tested with:
|
12
|
+
|
13
|
+
- Ruby 2.0, 2.1, 2.2 and Jruby-head
|
14
|
+
- ActiveSupport 3.0+, 4.0.x and 4.1.x
|
15
|
+
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Gemfile:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem 'dimelo_ccp_api'
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
require 'dimelo_ccp_api'
|
29
|
+
|
30
|
+
|
31
|
+
users_client = Dimelo::CCP::API::Client.new('https://domain-test.api.users.dimelo.com/1.0', 'access_token' => ENV['DIMELO_CCP_TOKEN'])
|
32
|
+
answers_client = Dimelo::CCP::API::Client.new('https://domain-test.api.answers.dimelo.com/1.0', 'access_token' => ENV['DIMELO_CCP_TOKEN'])
|
33
|
+
feedbacks_client = Dimelo::CCP::API::Client.new('https://domain-test.api.ideas.dimelo.com/1.0', 'access_token' => ENV['DIMELO_CCP_TOKEN'])
|
34
|
+
|
35
|
+
user = Dimelo::CCP::User.find(1, users_client)
|
36
|
+
questions = user.questions(answers_client)
|
37
|
+
puts "question count: #{questions.count}"
|
38
|
+
|
39
|
+
questions.each do |question, i|
|
40
|
+
answers = question.answers
|
41
|
+
puts "#{i} of #{questions.count} => answer count: #{answers.count}"
|
42
|
+
answers.each do |answer|
|
43
|
+
answer.question_flow_state = "lol"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
feedbacks = Dimelo::CCP::Feedback.find({ :order => 'updated_at.desc' }, feedbacks_client)
|
48
|
+
puts "feedbacks count: #{feedbacks.count}"
|
49
|
+
puts "feedbacks not by anonymous and superadmin: #{feedbacks.select{|f| f.user_id.present?}.count}"
|
50
|
+
|
51
|
+
```
|
52
|
+
|
53
|
+
## Contributing
|
54
|
+
|
55
|
+
1. Fork it ( http://github.com/dimelo/dimelo_ccp_api/fork )
|
56
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
57
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
58
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
59
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "spec/rake/spectask" # RSpec 1.3
|
6
|
+
|
7
|
+
desc 'Run all specs in spec directory.'
|
8
|
+
Spec::Rake::SpecTask.new(:spec) do |task|
|
9
|
+
task.libs = ['lib', 'spec']
|
10
|
+
task.spec_files = FileList['spec/**/*_spec.rb']
|
11
|
+
end
|
12
|
+
rescue LoadError
|
13
|
+
require "rspec/core/rake_task" # RSpec 2.0
|
14
|
+
|
15
|
+
desc 'Run all specs in spec directory.'
|
16
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
17
|
+
t.rspec_opts = %w{--colour --format progress}
|
18
|
+
t.pattern = 'spec/**/*_spec.rb'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Default: runs specs.'
|
23
|
+
task :default => :spec
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.4.1
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "dimelo/ccp/api/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "dimelo_ccp_api"
|
7
|
+
s.version = Dimelo::CCP::API::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jean Boussier", "Renaud Morvan"]
|
10
|
+
s.email = ["jean.boussier@dimelo.com", "nel@w3fu.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Dimelo CCP v2 API client}
|
13
|
+
s.description = %q{Rest API client for Dimelo CCP v2 plateform}
|
14
|
+
|
15
|
+
s.rubyforge_project = "dimelo_ccp_api"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
s.add_dependency('activesupport', '>= 3.0.0')
|
22
|
+
s.add_dependency('activemodel', '>= 3.0.0')
|
23
|
+
s.add_dependency('faraday')
|
24
|
+
s.add_development_dependency('rake')
|
25
|
+
s.add_development_dependency('rspec', '~> 3.0')
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
|
6
|
+
require 'dimelo_api'
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
unless ENV['DIMELO_API_KEY'].present?
|
10
|
+
puts "Don't forget to set your api key"
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
users_client = Dimelo::CCP::API::Client.new('https://domain-test.api.users.dimelo.com/1.0', 'access_token' => ENV['DIMELO_API_KEY'])
|
16
|
+
answers_client = Dimelo::CCP::API::Client.new('https://domain-test.api.answers.dimelo.com/1.0', 'access_token' => ENV['DIMELO_API_KEY'])
|
17
|
+
feedbacks_client = Dimelo::CCP::API::Client.new('https://domain-test.api.ideas.dimelo.com/1.0', 'access_token' => ENV['DIMELO_API_KEY'])
|
18
|
+
|
19
|
+
user = Dimelo::API::User.find(1, users_client)
|
20
|
+
questions = user.questions(answers_client)
|
21
|
+
puts "question count: #{questions.count}"
|
22
|
+
|
23
|
+
questions.each do |question, i|
|
24
|
+
answers = question.answers
|
25
|
+
puts "#{i} of #{questions.count} => answer count: #{answers.count}"
|
26
|
+
answers.each do |answer|
|
27
|
+
answer.question_flow_state = "lol"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
feedbacks = Dimelo::API::Feedback.find({ :order => 'updated_at.desc' }, feedbacks_client)
|
32
|
+
puts "feedbacks count: #{feedbacks.count}"
|
33
|
+
puts "feedbacks not by anonymous and superadmin: #{feedbacks.select{|f| f.user_id.present?}.count}"
|
34
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Dimelo::CCP
|
2
|
+
module API
|
3
|
+
|
4
|
+
class BasicObject
|
5
|
+
# http://ruby-doc.org/core-1.9/classes/BasicObject.html
|
6
|
+
# http://sequel.heroku.com/2010/03/31/sequelbasicobject-and-ruby-18/
|
7
|
+
KEEP_METHODS = %w(__id__ __send__ instance_eval == equal? initialize method_missing respond_to?)
|
8
|
+
|
9
|
+
def self.remove_methods!
|
10
|
+
m = (private_instance_methods + instance_methods) - KEEP_METHODS
|
11
|
+
m.each{|m| undef_method(m)}
|
12
|
+
end
|
13
|
+
remove_methods!
|
14
|
+
end if not defined?(BasicObject)
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Dimelo::CCP
|
2
|
+
module API
|
3
|
+
class Client
|
4
|
+
|
5
|
+
attr_accessor :base_uri, :default_parameters
|
6
|
+
|
7
|
+
def initialize(base_uri, options={})
|
8
|
+
@base_uri = base_uri.is_a?(URI) ? base_uri : URI.parse(base_uri)
|
9
|
+
options = options.with_indifferent_access
|
10
|
+
@http_options = options.delete(:http_options) || {}
|
11
|
+
@default_parameters = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def check
|
15
|
+
Dimelo::CCP::API.decode_json(transport(:get, 'check'))
|
16
|
+
end
|
17
|
+
|
18
|
+
def config
|
19
|
+
Dimelo::CCP::API.decode_json(transport(:get, 'config'))
|
20
|
+
end
|
21
|
+
|
22
|
+
def transport(method, path, payload={})
|
23
|
+
response = connection.perform(method, path, default_parameters.merge(payload))
|
24
|
+
|
25
|
+
if response.success? or response.status == 422
|
26
|
+
response.body
|
27
|
+
else
|
28
|
+
raise Error.from(method, path, response.status, response.body)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def request_uri(path, params)
|
35
|
+
@base_uri.dup.tap do |uri|
|
36
|
+
uri.path = File.join(uri.path, path).chomp('/')
|
37
|
+
end.request_uri
|
38
|
+
end
|
39
|
+
|
40
|
+
def connection
|
41
|
+
@connection ||= Connection.from_uri(@base_uri, @http_options)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Dimelo::CCP
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
module Openable
|
5
|
+
|
6
|
+
def open
|
7
|
+
path = "#{compute_path(attributes)}/open"
|
8
|
+
response = client.transport(:put, path)
|
9
|
+
self.attributes = Dimelo::CCP::API.decode_json(response)
|
10
|
+
errors.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
def close
|
14
|
+
path = "#{compute_path(attributes)}/close"
|
15
|
+
response = client.transport(:put, path)
|
16
|
+
self.attributes = Dimelo::CCP::API.decode_json(response)
|
17
|
+
errors.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Dimelo::CCP
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
module Publishable
|
5
|
+
|
6
|
+
def publish
|
7
|
+
path = "#{compute_path(attributes)}/publish"
|
8
|
+
response = client.transport(:put, path)
|
9
|
+
self.attributes = Dimelo::CCP::API.decode_json(response)
|
10
|
+
errors.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
def unpublish
|
14
|
+
path = "#{compute_path(attributes)}/unpublish"
|
15
|
+
response = client.transport(:put, path)
|
16
|
+
self.attributes = Dimelo::CCP::API.decode_json(response)
|
17
|
+
errors.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Dimelo::CCP
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
module Starrable
|
5
|
+
|
6
|
+
def star! #use method name with bang to differenciate from #star attribute
|
7
|
+
path = "#{compute_path(attributes)}/star"
|
8
|
+
response = client.transport(:put, path)
|
9
|
+
self.attributes = Dimelo::CCP::API.decode_json(response)
|
10
|
+
errors.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
def unstar!
|
14
|
+
path = "#{compute_path(attributes)}/unstar"
|
15
|
+
response = client.transport(:put, path)
|
16
|
+
self.attributes = Dimelo::CCP::API.decode_json(response)
|
17
|
+
errors.empty?
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
|
3
|
+
module Dimelo::CCP
|
4
|
+
module API
|
5
|
+
class Connection
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def from_uri(uri, options = {})
|
10
|
+
options.merge!(:use_ssl => uri.scheme == 'https')
|
11
|
+
pool[uri_key(uri)] ||= new(uri.to_s, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def uri_key(uri)
|
17
|
+
"#{uri.scheme}://#{uri.host}:#{uri.port}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def pool
|
21
|
+
@pool ||= {}
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(url, options={})
|
27
|
+
@url = url
|
28
|
+
@http_options = options
|
29
|
+
initialize_client
|
30
|
+
end
|
31
|
+
|
32
|
+
def perform(method, uri, payload={})
|
33
|
+
@client.send(method, uri, payload) do |req|
|
34
|
+
req.headers[:accept] = 'application/json'
|
35
|
+
req.headers[:user_agent] = user_agent
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def timeout
|
42
|
+
@http_options[:timeout] || 10
|
43
|
+
end
|
44
|
+
|
45
|
+
def user_agent_details
|
46
|
+
strip_non_ascii(@http_options[:user_agent] || '')
|
47
|
+
end
|
48
|
+
|
49
|
+
def strip_non_ascii(setting, replacement = '')
|
50
|
+
setting.gsub(/\P{ASCII}/, replacement)
|
51
|
+
end
|
52
|
+
|
53
|
+
def user_agent
|
54
|
+
"DimeloAPI/#{Dimelo::CCP::API::VERSION} " \
|
55
|
+
<< (user_agent_details.present? ? "(#{user_agent_details}) " : '') \
|
56
|
+
<< "Faraday/#{Faraday::VERSION} " \
|
57
|
+
<< "Ruby/#{RUBY_VERSION}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def client_options
|
61
|
+
{}.tap do |opts|
|
62
|
+
opts[:request] = request_options
|
63
|
+
opts[:ssl] = ssl_options if @http_options[:use_ssl]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def request_options
|
68
|
+
{ timeout: timeout, open_timeout: timeout }
|
69
|
+
end
|
70
|
+
|
71
|
+
def ssl_options
|
72
|
+
{ verify_mode: OpenSSL::SSL::VERIFY_NONE, verify_depth: 5 }
|
73
|
+
end
|
74
|
+
|
75
|
+
def initialize_client
|
76
|
+
@client = Faraday.new(@url, client_options) do |faraday|
|
77
|
+
faraday.request :multipart
|
78
|
+
faraday.request :url_encoded
|
79
|
+
faraday.adapter Faraday.default_adapter #adapter should be last in the list https://github.com/lostisland/faraday/issues/161
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Dimelo::CCP
|
2
|
+
module API
|
3
|
+
class Error < StandardError
|
4
|
+
attr_accessor :original_exception
|
5
|
+
|
6
|
+
# Public : Return specific Exceptions if defined
|
7
|
+
#
|
8
|
+
# Returns :
|
9
|
+
# - DefinedError descendant exception (DomainNotFoundError,...) if status & name matches declared DefinedError child
|
10
|
+
# - BaseError if status and name does not match any declared Error
|
11
|
+
# - Error if body cannot be json parsed
|
12
|
+
def self.from(method, path, http_status, body)
|
13
|
+
json = Dimelo::CCP::API.decode_json(body).symbolize_keys!
|
14
|
+
name = json.delete(:error)
|
15
|
+
status = json.delete(:status)
|
16
|
+
message = json.delete(:message)
|
17
|
+
|
18
|
+
if klass = DefinedError.descendants.find { |error| error.status == status && error.name == name}
|
19
|
+
klass.new
|
20
|
+
else
|
21
|
+
BaseError.new(name, status, message)
|
22
|
+
end
|
23
|
+
rescue ActiveSupport::JSON.parse_error
|
24
|
+
new("#{method.to_s.upcase} #{path} - #{http_status} #{body}")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class BaseError < StandardError
|
29
|
+
def initialize(name, status, message='')
|
30
|
+
@name = name
|
31
|
+
@status = status
|
32
|
+
@message = message
|
33
|
+
super("error_type:#{name} - status:#{status} - body:#{message}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class DefinedError < StandardError
|
38
|
+
class_attribute :status, :name
|
39
|
+
end
|
40
|
+
|
41
|
+
class DomainNotFoundError < DefinedError
|
42
|
+
self.status = 404
|
43
|
+
self.name = 'domain_not_found'
|
44
|
+
end
|
45
|
+
|
46
|
+
class InvalidAccessTokenError < DefinedError
|
47
|
+
self.status = 403
|
48
|
+
self.name = 'invalid_access_token'
|
49
|
+
end
|
50
|
+
|
51
|
+
class InvalidUserTypeError < DefinedError #happens only on POST /users
|
52
|
+
self.status = 400
|
53
|
+
self.name = 'invalid_user_type'
|
54
|
+
end
|
55
|
+
|
56
|
+
class NotEnabledError < DefinedError
|
57
|
+
self.status = 403
|
58
|
+
self.name = 'api_not_enabled'
|
59
|
+
end
|
60
|
+
|
61
|
+
class NotFoundError < DefinedError
|
62
|
+
self.status = 404
|
63
|
+
self.name = 'not_found'
|
64
|
+
end
|
65
|
+
|
66
|
+
class SslError < DefinedError
|
67
|
+
self.status = 412
|
68
|
+
self.name = 'routing_error'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Dimelo::CCP
|
2
|
+
module API
|
3
|
+
|
4
|
+
class LazzyCollection < BasicObject
|
5
|
+
|
6
|
+
include ::Enumerable
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def new(params, &block)
|
11
|
+
if (params.has_key?(:offset) || params.has_key?('offset'))
|
12
|
+
yield params
|
13
|
+
else
|
14
|
+
instance = super(params, &block)
|
15
|
+
instance.paginator.first.is_a?(Enumerable) ? instance : instance.paginator.first
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :paginator
|
22
|
+
|
23
|
+
def initialize(params={}, &block)
|
24
|
+
@paginator = Paginator.new(params, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](index)
|
28
|
+
paginator.get_item_at(index)
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_a
|
32
|
+
@to_a ||= each
|
33
|
+
end
|
34
|
+
alias :to_ary :to_a
|
35
|
+
|
36
|
+
def respond_to?(method)
|
37
|
+
super || Array.public_instance_methods.include?(method.to_s)
|
38
|
+
end
|
39
|
+
|
40
|
+
def each(&block)
|
41
|
+
index = 0
|
42
|
+
while true
|
43
|
+
item = paginator.get_item_at(index)
|
44
|
+
break if item.nil?
|
45
|
+
yield item if block.present?
|
46
|
+
index += 1
|
47
|
+
end
|
48
|
+
paginator.flatten
|
49
|
+
end
|
50
|
+
|
51
|
+
def inspect
|
52
|
+
"<Dimelo::CCP::API::LazzyCollection instance>"
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
# /!\ Fetch all API, please avoid this behavior
|
58
|
+
def method_missing(name, *args, &block)
|
59
|
+
super unless respond_to?(name)
|
60
|
+
warn %{WARNING: Method '#{name}` called on LazzyCollection object from #{Kernel.caller.first}.
|
61
|
+
All API items might be fetched, so please verify that you are a consenting adult.}
|
62
|
+
self.to_a.send(name, *args, &block)
|
63
|
+
end
|
64
|
+
|
65
|
+
def warn(message)
|
66
|
+
defined?(Rails) ? Rails.logger.warn(message) : STDERR.puts(message)
|
67
|
+
end
|
68
|
+
|
69
|
+
class Paginator
|
70
|
+
|
71
|
+
DEFAULT_PAGE_SIZE = 30
|
72
|
+
|
73
|
+
attr_reader :page_cache
|
74
|
+
|
75
|
+
def initialize(params, &block)
|
76
|
+
@params = params.dup
|
77
|
+
@block = block
|
78
|
+
@page_cache = []
|
79
|
+
end
|
80
|
+
|
81
|
+
def page_size
|
82
|
+
@page_size ||= (@params[:limit] || DEFAULT_PAGE_SIZE).to_i
|
83
|
+
end
|
84
|
+
|
85
|
+
def page_offset(page_index)
|
86
|
+
page_index * page_size
|
87
|
+
end
|
88
|
+
|
89
|
+
def [](index)
|
90
|
+
page_cache[index.to_i] ||= @block.call(params_for_page(index))
|
91
|
+
end
|
92
|
+
|
93
|
+
def params_for_page(index)
|
94
|
+
@params.merge(:offset => page_offset(index.to_i), :limit => page_size)
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_item_at(position)
|
98
|
+
self[position / page_size][position % page_size]
|
99
|
+
end
|
100
|
+
|
101
|
+
def flatten
|
102
|
+
page_cache.flatten(1)
|
103
|
+
end
|
104
|
+
|
105
|
+
def first
|
106
|
+
self[0]
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|