girlscout 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de5ee14889bf953e416b87030e72390494e1d054d3741bda1583cdafdb233577
4
- data.tar.gz: 7b462a2aedf9b630ceee7c602e42fa81015218b005afc3242f2c85b22e30a48d
3
+ metadata.gz: e813cb84802b26b3db2298227a8414b2a14de4a6bec0b5538f6163d2ad6ae1d1
4
+ data.tar.gz: 5b1737b3c525b5193711848eaddd19056dfff7a77c7ab63fddc3f7b4765d99de
5
5
  SHA512:
6
- metadata.gz: a4871a86d2ef4c2bb7952966553c90b79f36ab1a2467e9da120bea156a5c30ac08c23f609ce5fd27426d6f434aac9cc96c7ace9998fa6cefaebfca8011cea58a
7
- data.tar.gz: ad3eac246d498eedf109bbb024c28b97982215055d1e31b247e92a6df08462ccbc08d8d2c6114fc24ee4a94c90cb21c0cace29c9be9f249b1f47167dae7ab1e7
6
+ metadata.gz: e8f78b1ae310eeba7b0ecfc15e075e07edf297e778eb93eeef67ef83792b0e4d7afd304802d2bf4054ed172c851fd611d90fdb24370c0744a42df3226109df35
7
+ data.tar.gz: f2b7e5ac9f9702f8b26d49aa90592580b9817cba14dbf075b8ba031871da55b03a2e2b8652bdd9f0a51c44ee89054ddaab9569ced48dff732b072306d1720e96
data/lib/girlscout.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'excon'
4
4
 
5
+ require 'girlscout/version'
5
6
  require 'girlscout/resource'
6
7
  require 'girlscout/config'
7
8
 
@@ -10,6 +11,7 @@ require 'girlscout/concerns/has_resource'
10
11
  require 'girlscout/object'
11
12
  require 'girlscout/error'
12
13
 
14
+ require 'girlscout/access_token'
13
15
  require 'girlscout/list'
14
16
  require 'girlscout/folder'
15
17
  require 'girlscout/mailbox'
@@ -18,4 +20,3 @@ require 'girlscout/attachment'
18
20
  require 'girlscout/thread'
19
21
  require 'girlscout/customer'
20
22
  require 'girlscout/user'
21
- require 'girlscout/search'
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GirlScout
4
+ class AccessToken
5
+ include GirlScout::Concerns::HasAttributes
6
+
7
+ attr_reader :expires_at
8
+
9
+ class << self
10
+ def refresh
11
+ response = Excon.post(
12
+ "#{Config.api_prefix}/oauth2/token",
13
+ body: credential,
14
+ headers: { 'Content-Type' => 'application/x-www-form-urlencoded' }
15
+ )
16
+ raise GirlScout::Error, JSON.parse(response.body) if response.status >= 400
17
+
18
+ new(JSON.parse(response.body))
19
+ end
20
+
21
+ private
22
+
23
+ def credential
24
+ URI.encode_www_form(
25
+ client_id: Config.client_id,
26
+ client_secret: Config.client_secret,
27
+ grant_type: 'client_credentials'
28
+ )
29
+ end
30
+ end
31
+
32
+ def initialize(attr = {})
33
+ @attributes = normalize_attributes(attr)
34
+ @expires_at = Time.now + expires_in
35
+ end
36
+
37
+ def expired?
38
+ @expires_at.to_i <= Time.now.to_i
39
+ end
40
+
41
+ def to_s
42
+ access_token
43
+ end
44
+ end
45
+ end
@@ -13,23 +13,19 @@ module GirlScout
13
13
  @resource ||= build_resource
14
14
  end
15
15
 
16
- def resource_path
17
- return self.class.resource_path if self.class.respond_to?(:resource_path)
18
- @path
19
- end
20
-
21
16
  def resource_url
22
- "#{GirlScout::Config.api_prefix}#{@path}"
17
+ "#{GirlScout::Config.api_prefix}#{@endpoint}"
23
18
  end
24
19
 
25
20
  def endpoint(path)
26
- @path = path
21
+ @endpoint = path
27
22
  end
28
23
 
29
24
  private
30
25
 
31
26
  def build_resource
32
27
  return self.class.resource if self.class.respond_to?(:resource)
28
+
33
29
  Resource.new(url: resource_url)
34
30
  end
35
31
  end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GirlScout
4
- DEFAULT_API_PREFIX = 'https://api.helpscout.net/v1'
4
+ DEFAULT_API_PREFIX = 'https://api.helpscout.net/v2'
5
5
 
6
6
  class Config
7
7
  class << self
8
- attr_accessor :api_key
8
+ attr_accessor :client_id, :client_secret
9
9
  attr_writer :api_prefix
10
10
 
11
11
  def api_prefix
@@ -13,7 +13,8 @@ module GirlScout
13
13
  end
14
14
 
15
15
  def reset!
16
- @api_key = nil
16
+ @client_id = nil
17
+ @client_secret = nil
17
18
  @api_prefix = DEFAULT_API_PREFIX
18
19
  end
19
20
  end
@@ -6,35 +6,56 @@ module GirlScout
6
6
 
7
7
  class << self
8
8
  def find(id)
9
- Conversation.new(resource["/#{id}"].get['item'])
9
+ Conversation.new(resource["/#{id}"].get)
10
+ end
11
+
12
+ def list(query = {})
13
+ List.new(resource.get(query: query), Conversation)
10
14
  end
11
15
 
12
16
  def create(attributes)
13
17
  attributes = attributes.as_json if attributes.respond_to?(:as_json)
14
- attributes['reload'] ||= true
15
- Conversation.new(resource.post(payload: attributes)['item'])
18
+ resource.post(payload: attributes)
16
19
  end
17
20
  end
18
21
 
19
22
  def customer
20
- @customer ||= Customer.new(self['customer'] || {})
23
+ @customer ||= Customer.new(self['customer'] || self['primary_customer'] || {})
21
24
  end
22
25
 
23
26
  def threads
24
- @threads ||= (self['threads'] || []).map { |attr| Thread.new(attr) }
27
+ # `threads` is a number in response but must be an array in request payload.
28
+ @threads ||= begin
29
+ if self['threads'].is_a?(Array)
30
+ (self['threads'] || []).map { |attr| Thread.new(attr) }
31
+ else
32
+ List.new(threads_resouce.get, Thread)
33
+ end
34
+ end
25
35
  end
26
36
 
27
37
  def mailbox
28
- @mailbox ||= Mailbox.new(self['mailbox'] || {})
38
+ @mailbox ||= begin
39
+ if self['mailbox'].is_a?(Hash)
40
+ Mailbox.new(self['mailbox'] || {})
41
+ else
42
+ Mailbox.new(Resource.new(url: self['Links']['mailbox']['href']).get)
43
+ end
44
+ end
29
45
  end
30
46
 
31
47
  def as_json
32
- # TODO: Test
33
- json = super.dup
48
+ json = super
34
49
  json['customer'] = customer.as_json if key?('customer')
35
50
  json['threads'] = threads.map(&:as_json) if key?('threads')
36
51
  json['mailbox'] = mailbox.as_json if key?('mailbox')
37
52
  json
38
53
  end
54
+
55
+ private
56
+
57
+ def threads_resouce
58
+ @threads_resouce ||= Resource.new(url: self['Links']['threads']['href'])
59
+ end
39
60
  end
40
61
  end
@@ -5,19 +5,13 @@ module GirlScout
5
5
  endpoint '/customers'
6
6
 
7
7
  class << self
8
- def all
9
- List.new(resource.get, Customer)
10
- end
11
-
12
8
  def find(id)
13
- Customer.new(resource["/#{id}"].get['item'])
9
+ Customer.new(resource["/#{id}"].get)
14
10
  end
15
- end
16
11
 
17
- def as_json
18
- json = super
19
- json['type'] = 'customer'
20
- json
12
+ def list(query = {})
13
+ List.new(resource.get(query: query), Customer)
14
+ end
21
15
  end
22
16
  end
23
17
  end
@@ -6,7 +6,7 @@ module GirlScout
6
6
 
7
7
  def initialize(attr = {})
8
8
  @attributes = normalize_attributes(attr)
9
- super @attributes['error']
9
+ super @attributes['message']
10
10
  end
11
11
  end
12
12
  end
@@ -14,7 +14,7 @@ module GirlScout
14
14
  end
15
15
 
16
16
  def items
17
- @items ||= (@attributes['items'] || []).map do |attr|
17
+ @items ||= (embedded_items || []).map do |attr|
18
18
  @item_class.new(attr)
19
19
  end
20
20
  end
@@ -26,5 +26,11 @@ module GirlScout
26
26
  def each(&block)
27
27
  items.each(&block)
28
28
  end
29
+
30
+ private
31
+
32
+ def embedded_items
33
+ @embedded_items ||= @attributes['Embedded'].values[0]
34
+ end
29
35
  end
30
36
  end
@@ -5,47 +5,17 @@ module GirlScout
5
5
  endpoint '/mailboxes'
6
6
 
7
7
  class << self
8
- def all
9
- List.new(resource.get, Mailbox)
8
+ def find(id)
9
+ Mailbox.new(resource["/#{id}"].get)
10
10
  end
11
11
 
12
- def find(id)
13
- Mailbox.new(resource["/#{id}"].get['item'])
12
+ def list
13
+ List.new(resource.get, Mailbox)
14
14
  end
15
15
  end
16
16
 
17
17
  def folders
18
- @folders ||= List.new(folder_resource.get, Folder)
19
- end
20
-
21
- def conversations
22
- @conversations ||= List.new(conversation_resource.get, Conversation)
23
- end
24
-
25
- def users
26
- @users ||= List.new(user_resource.get, User)
27
- end
28
-
29
- def customers
30
- @customers ||= List.new(customer_resource.get, Customer)
31
- end
32
-
33
- protected
34
-
35
- def folder_resource
36
- @folder_resource ||= resource["/#{id}/folders"]
37
- end
38
-
39
- def conversation_resource
40
- @conversation_resource ||= resource["/#{id}/conversations"]
41
- end
42
-
43
- def user_resource
44
- @user_resource ||= resource["/#{id}/users"]
45
- end
46
-
47
- def customer_resource
48
- @customer_resource ||= resource["/#{id}/customers"]
18
+ @folders ||= List.new(resource["/#{id}/folders"].get, Folder)
49
19
  end
50
20
  end
51
21
  end
@@ -6,12 +6,11 @@ module GirlScout
6
6
  class Resource
7
7
  METHODS = %i[get put post patch delete].freeze
8
8
 
9
+ attr_accessor :url
10
+
9
11
  def initialize(url: '')
10
12
  @url = url
11
- end
12
-
13
- def url
14
- "#{@url}.json"
13
+ @access_token = AccessToken.refresh
15
14
  end
16
15
 
17
16
  def [](path)
@@ -21,25 +20,41 @@ module GirlScout
21
20
  METHODS.each do |method|
22
21
  define_method(method) do |payload: nil, query: nil|
23
22
  options = { method: method }
24
- if payload
25
- options[:body] = JSON.generate(payload)
26
- options[:headers] ||= {}
27
- options[:headers]['Content-Type'] = 'application/json'
28
- end
29
- options[:query] = query if query
23
+ options[:headers] = {
24
+ 'Content-Type' => 'application/json; charset=UTF-8',
25
+ 'Authorization' => "Bearer #{access_token}"
26
+ }
27
+ options[:body] = JSON.generate(payload) if payload
28
+ options[:query] = URI.encode_www_form(query) if query
30
29
 
31
30
  request(options)
32
31
  end
33
32
  end
34
33
 
34
+ private
35
+
36
+ def access_token
37
+ @access_token = AccessToken.refresh if @access_token&.expired?
38
+ @access_token
39
+ end
40
+
35
41
  def request(options = {})
36
- auth = { user: Config.api_key, password: 'X' }
37
- response = Excon.new(url, auth).request(options)
38
- if response.status >= 400 && response.status < 600
39
- raise GirlScout::Error, JSON.parse(response.body)
42
+ response = Excon.new(@url).request(options)
43
+ case response.status
44
+ when 200
45
+ JSON.parse(response.body)
46
+ when 201
47
+ response.headers['Resource-ID']
48
+ else
49
+ raise GirlScout::Error, message: error_message(response.body), code: response.status
40
50
  end
51
+ end
41
52
 
42
- JSON.parse(response.body)
53
+ def error_message(body)
54
+ body = JSON.parse(body)
55
+ body['message'] || body['error_description']
56
+ rescue JSON::ParserError
57
+ body
43
58
  end
44
59
  end
45
60
  end
@@ -3,27 +3,18 @@
3
3
  module GirlScout
4
4
  class Thread < GirlScout::Object
5
5
  def attachments
6
- @attachments ||= (self['attachments'] || []).map do |attr|
6
+ @attachments ||= (self['Embedded']['attachments'] || []).map do |attr|
7
7
  Attachment.new(attr)
8
8
  end
9
9
  end
10
10
 
11
- def created_by
12
- @created_by = nil unless defined? @created_by
13
- return @created_by if @created_by
14
-
15
- attr = @attributes['createdBy']
16
- creator_type = begin
17
- "GirlScout::#{attr['type'].capitalize}".constantize
18
- rescue StandardError
19
- User
20
- end
21
- @created_by ||= creator_type.new(attr)
11
+ def customer
12
+ @customer ||= Customer.new(self['customer'] || {})
22
13
  end
23
14
 
24
15
  def as_json
25
16
  json = super
26
- json['createdBy'] = created_by.as_json if key?('created_by')
17
+ json['customer'] = customer.as_json if key?('customer')
27
18
  json
28
19
  end
29
20
  end
@@ -5,12 +5,12 @@ module GirlScout
5
5
  endpoint '/users'
6
6
 
7
7
  class << self
8
- def all
9
- List.new(resource.get, User)
8
+ def find(id)
9
+ User.new(resource["/#{id}"].get)
10
10
  end
11
11
 
12
- def find(id)
13
- User.new(resource["/#{id}"].get['item'])
12
+ def list(query = {})
13
+ List.new(resource.get(query: query), User)
14
14
  end
15
15
 
16
16
  def me
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GirlScout
4
+ VERSION = '0.5.0'
5
+ end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: girlscout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
- - Chakrit Wichian
7
+ - Phureewat Aphibansri <phureewat@omise.co>
8
+ - Chakrit Wichian <chakrit@omise.co>
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2015-12-16 00:00:00.000000000 Z
12
+ date: 2019-07-05 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: excon
@@ -30,28 +31,28 @@ dependencies:
30
31
  requirements:
31
32
  - - ">="
32
33
  - !ruby/object:Gem::Version
33
- version: '2.1'
34
+ version: '1.8'
34
35
  type: :runtime
35
36
  prerelease: false
36
37
  version_requirements: !ruby/object:Gem::Requirement
37
38
  requirements:
38
39
  - - ">="
39
40
  - !ruby/object:Gem::Version
40
- version: '2.1'
41
+ version: '1.8'
41
42
  - !ruby/object:Gem::Dependency
42
43
  name: bundler
43
44
  requirement: !ruby/object:Gem::Requirement
44
45
  requirements:
45
46
  - - "~>"
46
47
  - !ruby/object:Gem::Version
47
- version: '1.16'
48
+ version: '2.0'
48
49
  type: :development
49
50
  prerelease: false
50
51
  version_requirements: !ruby/object:Gem::Requirement
51
52
  requirements:
52
53
  - - "~>"
53
54
  - !ruby/object:Gem::Version
54
- version: '1.16'
55
+ version: '2.0'
55
56
  - !ruby/object:Gem::Dependency
56
57
  name: guard
57
58
  requirement: !ruby/object:Gem::Requirement
@@ -170,21 +171,22 @@ dependencies:
170
171
  requirements:
171
172
  - - "~>"
172
173
  - !ruby/object:Gem::Version
173
- version: '4.0'
174
+ version: '5.0'
174
175
  type: :development
175
176
  prerelease: false
176
177
  version_requirements: !ruby/object:Gem::Requirement
177
178
  requirements:
178
179
  - - "~>"
179
180
  - !ruby/object:Gem::Version
180
- version: '4.0'
181
- description: Provides integration with HelpScout REST API.
182
- email: chakrit@omise.co
181
+ version: '5.0'
182
+ description: Provides integration with HelpScout REST API v2
183
+ email:
183
184
  executables: []
184
185
  extensions: []
185
186
  extra_rdoc_files: []
186
187
  files:
187
188
  - lib/girlscout.rb
189
+ - lib/girlscout/access_token.rb
188
190
  - lib/girlscout/attachment.rb
189
191
  - lib/girlscout/concerns/has_attributes.rb
190
192
  - lib/girlscout/concerns/has_resource.rb
@@ -197,10 +199,10 @@ files:
197
199
  - lib/girlscout/mailbox.rb
198
200
  - lib/girlscout/object.rb
199
201
  - lib/girlscout/resource.rb
200
- - lib/girlscout/search.rb
201
202
  - lib/girlscout/thread.rb
202
203
  - lib/girlscout/user.rb
203
- homepage: https://www.omise.co
204
+ - lib/girlscout/version.rb
205
+ homepage: https://github.com/omise/girlscout
204
206
  licenses:
205
207
  - MIT
206
208
  metadata: {}
@@ -220,8 +222,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
220
222
  version: '0'
221
223
  requirements: []
222
224
  rubyforge_project:
223
- rubygems_version: 2.7.7
225
+ rubygems_version: 2.7.6
224
226
  signing_key:
225
227
  specification_version: 4
226
- summary: Integrate your support tooling with HelpScout API.
228
+ summary: Integrate your support tooling with HelpScout API v2
227
229
  test_files: []
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GirlScout
4
- class Search < GirlScout::Object
5
- endpoint '/search'
6
-
7
- class << self
8
- def conversations(query)
9
- search(Conversation, query)
10
- end
11
-
12
- def customers(query)
13
- search(Customer, query)
14
- end
15
-
16
- private
17
-
18
- def search(klass, query)
19
- result = resource[klass.resource_path].get(query: { query: query })
20
- List.new(result, klass)
21
- end
22
- end
23
- end
24
- end