layer-ruby 0.4.1 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6b2e92f9be129ac6265ff24ab73852387a9e438a
4
- data.tar.gz: 1f3911782934d15e49f0feeb3964357acd28873c
3
+ metadata.gz: 78be9a887246783d87ee5441bb6d713d7d11e0e9
4
+ data.tar.gz: c96c5872a9539077b4c86abc8fcda78bace25fcf
5
5
  SHA512:
6
- metadata.gz: 57229aa42c27f78cef0f959c68d24299792cee2803142cfa304bab995a9c1268decd4b055abae6d8ed5c49ce014139de36129c9ba3c21d31a9d375a1266c0d46
7
- data.tar.gz: 9681349bdb101b4ec80219bcc69990454353b8c9b9f72c33896e9673f555c7f932a5128655fe773a2131f7df060775aedc61700999338d35b2e7985ded664203
6
+ metadata.gz: 7d02be7b2d37304b8d8e18f4ebc8afba4b697c9272ef357e7bee0244f642294553565a09f59482fd04e1ea260c0ee90250b012bef36e7509aedc39d3eceb457b
7
+ data.tar.gz: f5ca37c2018d18ab8052b2b9df63e15b24d9e396cd92a504b8ac6a5b6ca5391987259969f5f8b7e790d91a960c88eaacd81af5992e904c76dcdf9f98a6d952ed
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ .env
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in layer-ruby.gemspec
4
4
  gemspec
5
+
6
+ gem 'dotenv', '~> 2.0'
7
+ gem 'layer-identity_token', '~> 0.0'
8
+ gem 'guard-rspec', '~> 4.5'
9
+ gem 'guard-yard', '~> 2.1'
data/Guardfile CHANGED
@@ -14,3 +14,7 @@ guard :rspec, cmd: "bundle exec rspec" do
14
14
  ruby = dsl.ruby
15
15
  dsl.watch_spec_files_for(ruby.lib_files)
16
16
  end
17
+
18
+ guard 'yard', :cli => '--reload' do
19
+ watch(%r{lib/.+\.rb})
20
+ end
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
- # Layer Platform API
1
+ # Ruby Client for Layer
2
2
 
3
- [![Build Status](https://travis-ci.org/benedikt/layer-ruby.svg)](https://travis-ci.org/benedikt/layer-ruby)
3
+ [![Build Status](https://travis-ci.org/benedikt/layer-ruby.svg?branch=master)](https://travis-ci.org/benedikt/layer-ruby)
4
4
  [![Gem Version](https://badge.fury.io/rb/layer-ruby.svg)](http://badge.fury.io/rb/layer-ruby)
5
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/gems/layer-ruby)
5
6
 
6
- Ruby bindings for the [Layer Platform API](https://developer.layer.com/docs/platform).
7
+ Ruby client for the [Layer Platform API](https://developer.layer.com/docs/platform) and [Layer Client REST API](https://developer.layer.com/docs/client/rest).
7
8
 
8
9
  ## Installation
9
10
 
@@ -23,11 +24,11 @@ Or install it yourself as:
23
24
 
24
25
  ## Usage
25
26
 
26
- Please refer to the [Layer Platform API documentation](https://developer.layer.com/docs/platform) for details about the required payloads and responses.
27
+ Please refer to the [Layer Platform API documentation](https://developer.layer.com/docs/platform) and [Layer Client REST API documentation](https://developer.layer.com/docs/client/rest) for details about the required payloads and responses.
27
28
 
28
29
  ### Configuration
29
30
 
30
- To use interact with the Layer Platform API, you need your Layer APP ID as well as a Layer Platform API Token. The gem reads both values from the `LAYER_APP_ID` and `LAYER_PLATFORM_TOKEN` environment variables. Alternatively you can specify the values by configuring the `Layer::Client` like this:
31
+ To use the Layer Platform API, you need your Layer APP ID as well as a Layer Platform API Token. The gem reads both values from the `LAYER_APP_ID` and `LAYER_PLATFORM_TOKEN` environment variables. Alternatively you can specify the values by configuring the `Layer::Client` like this:
31
32
 
32
33
  ```ruby
33
34
  Layer::Client.configure do |config|
@@ -36,70 +37,34 @@ Layer::Client.configure do |config|
36
37
  end
37
38
  ```
38
39
 
39
- ### Creating Conversations
40
-
41
- ```ruby
42
- conversation = Layer::Conversation.create({ participants: ['1', '2'] })
43
- ```
44
-
45
- ### Retrieving Conversations
46
-
47
- To retrieve a existing conversation, just use `Conversation.find` passing it the conversation id:
48
-
49
- ```ruby
50
- conversation = Layer::Conversation.find('CONVERSATION_ID_HERE')
51
- ```
52
-
53
- ### Updating Conversations
40
+ ### Using the gem with multiple applications at once
54
41
 
55
- To update a conversation, just update the conversation's attributes and call `save`.
42
+ It's possible to create a new instance of `Layer::Client` and passing both the app id and the token to the initializer:
56
43
 
57
44
  ```ruby
58
- conversation = Layer::Conversation.find('CONVERSATION_ID_HERE')
59
- conversation.participants << 3
60
- conversation.metadata[:foo] = 'bar'
61
- conversation.save
45
+ client = Layer::Client.new('YOUR_APP_ID_HERE', 'YOUR_PLATFORM_TOKEN_HERE')
62
46
  ```
63
47
 
48
+ The client will not use any global configuration. You can pass the client as a second parameter to any operations (`create`, `find`) described above.
64
49
 
65
- ### Sending Messages
66
-
67
- In order to send messages, you first have to load (or create) a Conversation. Afterwards you can send a message to the conversation like this:
68
-
69
- ```ruby
70
- conversation = Layer::Conversation.find('CONVERSATION_ID_HERE')
71
- conversation.messages.create({ sender: { name: 'Server' }, parts: [{ body: 'Hello!', mime_type: 'text/plain' }]})
72
- ```
73
-
74
- ### Sending Announcements
50
+ ### Using the Layer Client REST API
75
51
 
76
- You can send a announcements like this:
52
+ To use the Layer Client REST API, you need a way to generate identitiy tokens. You might want to use the [layer-identity_token](https://github.com/dreimannzelt/layer-identity_token) gem for that. Using this gem, you can create a new client using the REST API like this:
77
53
 
78
54
  ```ruby
79
- Layer::Announcement.create({ recipients: 'everyone', sender: { name: 'Server' }, parts: [{ body: 'Hello!', mime_type: 'text/plain' }]})
55
+ client = Layer::Client.authenticate { |nonce| Layer::IdentityToken.new('user_id_here', nonce) }
80
56
  ```
81
57
 
82
- ### Managing block lists
83
-
84
- Managing block lists is also possible:
58
+ Afterwards, pass the client as an additional argument to the resource's methods:
85
59
 
86
60
  ```ruby
87
- user = Layer::User.find('user_id')
88
- user.blocks.all # Returns a list of blocks
89
- user.blocks.create({ user_id: 'other_user' }) # Adds the other user to the block list
90
- user.blocks.delete('other_user') # Removes the other user from the block list
91
- user.blocks.all.first.delete # Removes the first entry from the block list
61
+ # Finds all conversations of the authenticated user
62
+ Layer::Conversation.all(client)
92
63
  ```
93
64
 
94
- ### Using the gem with multiple applications at once
65
+ ### Documentation
95
66
 
96
- It's possible to create a new instance of `Layer::Client` and passing both the app id and the token to the initializer:
97
-
98
- ```ruby
99
- client = Layer::Client.new('YOUR_APP_ID_HERE', 'YOUR_PLATFORM_TOKEN_HERE')
100
- ```
101
-
102
- The client will not use any global configuration. You can pass the client as a second parameter to any operations (`create`, `find`) described above.
67
+ Please refer to [the full documentation](http://rubydoc.info/gems/layer-ruby) for details on how to use Announcements, Block Lists, Conversations, Messages, Rich Content, and WebHooks.
103
68
 
104
69
  ## Development
105
70
 
data/layer-ruby.gemspec CHANGED
@@ -23,6 +23,6 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.10"
25
25
  spec.add_development_dependency "rake", "~> 10.0"
26
- spec.add_development_dependency "rspec"
27
- spec.add_development_dependency "guard-rspec"
26
+ spec.add_development_dependency "rspec", "~> 3.3"
27
+ spec.add_development_dependency "yard", "~> 0.8"
28
28
  end
data/lib/layer.rb CHANGED
@@ -1,14 +1,31 @@
1
1
  require 'layer/version'
2
+ require 'layer/exceptions'
2
3
  require 'layer/client'
3
4
  require 'layer/patch'
4
5
  require 'layer/operations'
5
6
  require 'layer/resource'
7
+ require 'layer/resource_collection'
6
8
  require 'layer/relation_proxy'
7
9
  require 'layer/conversation'
10
+ require 'layer/content'
8
11
  require 'layer/message'
9
12
  require 'layer/user'
10
13
  require 'layer/block'
11
14
  require 'layer/announcement'
15
+ require 'layer/webhook'
16
+
17
+
18
+ # @!macro [new] platform-api
19
+ # @note This is only available via the Platform API.
20
+
21
+ # @!macro [new] rest-api
22
+ # @note This is only available via the REST API.
23
+ # @see file:README.md#label-Using+the+Layer+Client+REST+API Using the Client REST API
24
+
25
+ # @!macro [new] various-apis
26
+ # @note This is available in both the REST and the Platform API. Please refer to the respective documentation to see which methods are available.
27
+ # @see file:README.md#label-Using+the+Layer+Client+REST+API Using the Client REST API
12
28
 
13
29
  module Layer
30
+
14
31
  end
@@ -1,11 +1,17 @@
1
1
  module Layer
2
+ # @example
3
+ # Layer::Announcement.create({ recipients: 'everyone', sender: { name: 'Server' }, parts: [{ body: 'Hello!', mime_type: 'text/plain' }]})
4
+ #
5
+ # @see https://developer.layer.com/docs/platform#send-an-announcement Layer Platform API Documentation about announcements
6
+ # @!macro platform-api
2
7
  class Announcement < Resource
3
8
  include Operations::Create
4
9
 
10
+ # @!parse extend Layer::Operations::Create::ClassMethods
11
+
5
12
  def sent_at
6
13
  Time.parse(attributes['sent_at'])
7
14
  end
8
15
 
9
16
  end
10
17
  end
11
-
data/lib/layer/block.rb CHANGED
@@ -1,5 +1,19 @@
1
1
  module Layer
2
+ # Managing block lists is also possible:
3
+ #
4
+ # @example
5
+ # user = Layer::User.find('user_id')
6
+ # user.blocks.all # Returns a list of blocks
7
+ # user.blocks.create({ user_id: 'other_user' }) # Adds the other user to the block list
8
+ # user.blocks.delete('other_user') # Removes the other user from the block list
9
+ # user.blocks.all.first.delete # Removes the first entry from the block list
10
+ #
11
+ # @see https://developer.layer.com/docs/platform#block-users Layer Platform API Documentation about block lists
12
+ # @!macro platform-api
2
13
  class Block < Resource
3
14
  include Operations::Delete
15
+
16
+ # @!parse extend Layer::Operations::Delete::ClassMethods
17
+
4
18
  end
5
19
  end
data/lib/layer/client.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'rest-client'
2
2
  require 'securerandom'
3
3
 
4
+ require 'layer/client/platform'
5
+ require 'layer/client/rest'
6
+
4
7
  module Layer
5
8
  class Client
6
9
  class << self
@@ -21,13 +24,10 @@ module Layer
21
24
  def normalize_id(id)
22
25
  id.to_s.split('/').last
23
26
  end
24
- end
25
27
 
26
- attr_reader :app_id, :token
27
-
28
- def initialize(app_id = self.class.app_id, token = self.class.token)
29
- @app_id = self.class.normalize_id(app_id)
30
- @token = token
28
+ def authenticate(app_id = self.app_id, &block)
29
+ Layer::Client::REST.new(app_id, &block)
30
+ end
31
31
  end
32
32
 
33
33
  def get(*args)
@@ -63,10 +63,9 @@ module Layer
63
63
  private
64
64
 
65
65
  def request(method, url, payload = {}, headers = {})
66
- url = "https://api.layer.com/apps/#{app_id}#{url}" unless url.start_with?('https://api.layer.com')
66
+ url = "https://api.layer.com#{url}" unless url.start_with?('https://api.layer.com')
67
67
 
68
68
  headers = {
69
- 'Authorization' => "Bearer #{token}",
70
69
  'Accept' => 'application/vnd.layer+json; version=1.0',
71
70
  'Content-Type' => 'application/json',
72
71
  'If-None-Match' => SecureRandom.uuid
@@ -76,6 +75,8 @@ module Layer
76
75
 
77
76
  response = RestClient::Request.execute(method: method, url: url, payload: payload, headers: headers)
78
77
  response.empty? ? nil : JSON.parse(response)
78
+ rescue RestClient::Exception
79
+ raise Layer::Exceptions::Exceptions.build_exception($!)
79
80
  end
80
81
 
81
82
  end
@@ -0,0 +1,22 @@
1
+ module Layer
2
+ class Client
3
+ class Platform < Layer::Client
4
+
5
+ attr_reader :app_id, :token
6
+
7
+ def initialize(app_id = self.class.app_id, token = self.class.token)
8
+ @app_id = self.class.normalize_id(app_id)
9
+ @token = token
10
+ end
11
+
12
+ private
13
+
14
+ def request(method, url, payload = {}, headers = {})
15
+ url = "https://api.layer.com/apps/#{app_id}#{url}" unless url.start_with?('https://api.layer.com')
16
+ headers['Authorization'] ||= "Bearer #{token}"
17
+
18
+ super
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,41 @@
1
+ module Layer
2
+ class Client
3
+ class REST < Layer::Client
4
+
5
+ def self.authenticate(app_id, nonce = nil)
6
+ client = Layer::Client.new
7
+
8
+ nonce ||= client.post('/nonces')['nonce']
9
+
10
+ identity_token = yield(nonce)
11
+
12
+ response = client.post('/sessions', { identity_token: identity_token, app_id: app_id })
13
+ response['session_token']
14
+ end
15
+
16
+ attr_reader :token, :app_id, :block
17
+
18
+ def initialize(app_id = self.class.app_id, &block)
19
+ @app_id = self.class.normalize_id(app_id)
20
+ @block = block
21
+ authenticate
22
+ end
23
+
24
+ private
25
+
26
+ def request(method, url, payload = {}, headers = {})
27
+ url = "https://api.layer.com#{url}" unless url.start_with?('https://api.layer.com')
28
+ headers['Authorization'] ||= "Layer session-token=\"#{token}\""
29
+
30
+ super
31
+ rescue Layer::Exceptions::Exceptions::AuthenticationRequired => exception
32
+ authenticate(exception.response_json['data']['nonce'])
33
+ retry
34
+ end
35
+
36
+ def authenticate(nonce = nil)
37
+ @token = self.class.authenticate(app_id, nonce, &block)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,50 @@
1
+ module Layer
2
+ # @example
3
+ # content = Layer::Content.create('image/png', File.open('photo.png'))
4
+ #
5
+ # message = Layer::Message.create({
6
+ # sender: { name: 'Server' },
7
+ # parts: [
8
+ # { body: content.to_json, mime_type: content.mime_type }
9
+ # ]
10
+ # })
11
+ #
12
+ # @see https://developer.layer.com/docs/client/rest#rich-content Layer REST API documentation about rich content
13
+ # @!macro rest-api
14
+ class Content < Resource
15
+ include Operations::Create
16
+ include Operations::Find
17
+
18
+ # @!parse extend Layer::Operations::Create::ClassMethods
19
+ # @!parse extend Layer::Operations::Find::ClassMethods
20
+
21
+ def self.create(mime_type, file, client = self.client)
22
+ response = client.post(url, {}, headers = {
23
+ 'Upload-Content-Type' => mime_type,
24
+ 'Upload-Content-Length' => file.size
25
+ })
26
+
27
+ attributes = response.merge('size' => file.size)
28
+
29
+ from_response(attributes, client).tap do |content|
30
+ content.upload(file)
31
+ end
32
+ end
33
+
34
+ def self.url
35
+ '/content'
36
+ end
37
+
38
+ def upload(file)
39
+ RestClient.put(upload_url, file)
40
+ end
41
+
42
+ def url
43
+ attributes['refresh_url'] || "#{self.class.url}/#{Layer::Client.normalize_id(id)}"
44
+ end
45
+
46
+ def to_json(*args)
47
+ { id: id, size: size }.to_json(*args)
48
+ end
49
+ end
50
+ end
@@ -1,20 +1,82 @@
1
1
  module Layer
2
+ # @example Creating a new conversation
3
+ # conversation = Layer::Conversation.create({ participants: ['1', '2'] })
4
+ #
5
+ # @example Finding an existing conversation
6
+ # conversation = Layer::Conversation.find('CONVERSATION_ID_HERE')
7
+ #
8
+ # @example Updating an existing conversation
9
+ # conversation = Layer::Conversation.find('CONVERSATION_ID_HERE')
10
+ # conversation.participants << 3
11
+ # conversation.metadata[:foo] = 'bar'
12
+ # conversation.save
13
+ #
14
+ # @see https://developer.layer.com/docs/platform#retrieving-conversations Layer Platform API Documentation about conversations
15
+ # @see https://developer.layer.com/docs/client/rest#conversations Layer REST API Documentation about conversations
16
+ # @!macro various-apis
2
17
  class Conversation < Resource
3
18
  include Operations::Find
19
+ include Operations::Paginate
4
20
  include Operations::Create
21
+ include Operations::Delete
5
22
  include Operations::Patch
6
23
 
24
+ # @!parse extend Layer::Operations::Find::ClassMethods
25
+ # @!parse extend Layer::Operations::Paginate::ClassMethods
26
+ # @!parse extend Layer::Operations::Create::ClassMethods
27
+ # @!parse extend Layer::Operations::Delete::ClassMethods
28
+
29
+ # Destroys the conversation with the given id for all participants
30
+ #
31
+ # @param [String] id of the conversation to destroy
32
+ # @!macro rest-api
33
+ def self.destroy(id, client = self.client)
34
+ id = Layer::Client.normalize_id(id)
35
+ client.delete("#{url}/#{id}", {}, { params: { destroy: true } })
36
+ end
37
+
38
+ # Returns the converations messages
39
+ #
40
+ # @return [Layer::RelationProxy] the conversation's messages
41
+ # @!macro various-apis
7
42
  def messages
8
- RelationProxy.new(self, Message, [Operations::Create])
43
+ RelationProxy.new(self, Message, [Operations::Create, Operations::Paginate, Operations::Find])
44
+ end
45
+
46
+ # Returns the conversations metadata
47
+ #
48
+ # @return [Layer::Patch::Hash] the metadata hash
49
+ def metadata
50
+ attributes['metadata'] ||= {}
9
51
  end
10
52
 
53
+ # Returns the conversations metadata
54
+ #
55
+ # @return [Layer::Patch::Array] the participants array
56
+ def participants
57
+ attributes['participants'] ||= []
58
+ end
59
+
60
+ # Whether the conversation is distinct
61
+ #
62
+ # @return [Boolean] whether the conversation is distinct
11
63
  def distinct?
12
64
  attributes['distinct']
13
65
  end
14
66
 
67
+ # Returns the time the conversation was created at
68
+ #
69
+ # @return [Time] the time the conversation was created at
15
70
  def created_at
16
71
  Time.parse(attributes['created_at'])
17
72
  end
18
73
 
74
+ # Destroys the conversation for all participants
75
+ #
76
+ # @!macro rest-api
77
+ def destroy
78
+ client.delete(url, {}, { params: { destroy: true } })
79
+ end
80
+
19
81
  end
20
82
  end
@@ -0,0 +1,52 @@
1
+ module Layer
2
+ module Exceptions
3
+
4
+ def self.build_exception(original_exception)
5
+ identifier = JSON.parse(original_exception.http_body)['id']
6
+ identifier.gsub!(/(?:_|(\/)|^)([a-z\d]*)/i) { $2.capitalize }
7
+
8
+ exception = const_get(identifier) rescue Exception
9
+ exception.new(original_exception)
10
+ rescue
11
+ original_exception
12
+ end
13
+
14
+ class Exception < RuntimeError
15
+ attr_reader :original_exception
16
+
17
+ def initialize(original_exception = nil)
18
+ @original_exception = original_exception
19
+ end
20
+
21
+ def message
22
+ "#{original_exception.message}\n\n#{JSON.pretty_generate(response_json)}\n\n"
23
+ end
24
+
25
+ def response_json
26
+ JSON.parse(original_exception.http_body)
27
+ end
28
+ end
29
+
30
+ class ClientException < Exception; end
31
+ class ServiceUnavailable < ClientException; end
32
+ class InvalidAppId< ClientException; end
33
+ class InvalidRequestId < ClientException; end
34
+ class AuthenticationRequired < ClientException; end
35
+ class AppSuspended < ClientException; end
36
+ class UserSuspended < ClientException; end
37
+ class RateLimitExceeded < ClientException; end
38
+ class RequestTimeout < ClientException; end
39
+ class InvalidOperation < ClientException; end
40
+ class InvalidRequest < ClientException; end
41
+ class InvalidEndpoint < ClientException; end
42
+ class InvalidHeader < ClientException; end
43
+
44
+ class ResourceException < Exception; end
45
+ class AccessDenied < ResourceException; end
46
+ class NotFound < ResourceException; end
47
+ class ObjectDeleted < ResourceException; end
48
+ class MissingProperty < ResourceException; end
49
+ class InvalidProperty < ResourceException; end
50
+ class Conflict < ResourceException; end
51
+ end
52
+ end
data/lib/layer/message.rb CHANGED
@@ -1,13 +1,51 @@
1
1
  module Layer
2
+ # @example Sending messages
3
+ # conversation = Layer::Conversation.find('CONVERSATION_ID_HERE')
4
+ # conversation.messages.create({ sender: { name: 'Server' }, parts: [{ body: 'Hello!', mime_type: 'text/plain' }]})
5
+ #
6
+ # @see https://developer.layer.com/docs/platform#send-a-message Layer Platform API Documentation about messages
7
+ # @see https://developer.layer.com/docs/client/rest#messages Layer REST API Documentation about messages
8
+ # @see Layer::Content Sending rich content using Layer::Content
9
+ #
10
+ # @!macro various-apis
2
11
  class Message < Resource
12
+ include Operations::Find
3
13
 
14
+ # @!parse extend Layer::Operations::Find::ClassMethods
15
+
16
+ # Returns the conversation this message belongs to
17
+ #
18
+ # @return [Layer::Conversation] the message's conversation
4
19
  def conversation
5
20
  Conversation.from_response(attributes['conversation'], client)
6
21
  end
7
22
 
23
+ # Returns the time the message was sent at
24
+ #
25
+ # @return [Time] the time the message was sent at
8
26
  def sent_at
9
27
  Time.parse(attributes['sent_at'])
10
28
  end
11
29
 
30
+ # Marks the message as read by the current user
31
+ #
32
+ # @!macro rest-api
33
+ def read!
34
+ client.post(receipts_url, { type: 'read' })
35
+ end
36
+
37
+ # Marks the message as delivered to the current user
38
+ # @!macro rest-api
39
+ def delivered!
40
+ client.post(receipts_url, { type: 'delivery' })
41
+ end
42
+
43
+ # The endpoint to send read and delivered receipts to
44
+ #
45
+ # @return [String] the url of the endpoint
46
+ # @!macro rest-api
47
+ def receipts_url
48
+ attributes['receipts_url'] || "#{url}/receipts"
49
+ end
12
50
  end
13
51
  end
@@ -1,5 +1,6 @@
1
1
  require 'layer/operations/create'
2
2
  require 'layer/operations/find'
3
3
  require 'layer/operations/list'
4
+ require 'layer/operations/paginate'
4
5
  require 'layer/operations/delete'
5
6
  require 'layer/operations/patch'
@@ -3,12 +3,19 @@ module Layer
3
3
  module Create
4
4
 
5
5
  module ClassMethods
6
+ # Creates the resource with the given attributes
7
+ #
8
+ # @param attributes [Hash] the resource's attributes
9
+ # @param client [Layer::Client] the client to use to make this request
10
+ # @return [Layer::Resource] the created resource
11
+ # @raise [Layer::Exceptions::Exception] a subclass of Layer::Exceptions::Exception describing the error
6
12
  def create(attributes = {}, client = self.client)
7
13
  response = client.post(url, attributes)
8
14
  from_response(response, client)
9
15
  end
10
16
  end
11
17
 
18
+ # @!visibility private
12
19
  def self.included(base)
13
20
  base.extend(ClassMethods)
14
21
  end
@@ -3,16 +3,25 @@ module Layer
3
3
  module Delete
4
4
 
5
5
  module ClassMethods
6
+ # Deletes the resource with the given id
7
+ #
8
+ # @param id [String] the resource's id
9
+ # @param client [Layer::Client] the client to use to make this request
10
+ # @raise [Layer::Exceptions::Exception] a subclass of Layer::Exceptions::Exception describing the error
6
11
  def delete(id, client = self.client)
7
12
  id = Layer::Client.normalize_id(id)
8
13
  client.delete("#{url}/#{id}")
9
14
  end
10
15
  end
11
16
 
17
+ # @!visibility private
12
18
  def self.included(base)
13
19
  base.extend(ClassMethods)
14
20
  end
15
21
 
22
+ # Deletes the resource
23
+ #
24
+ # @raise [Layer::Exceptions::Exception] a subclass of Layer::Exceptions::Exception describing the error
16
25
  def delete
17
26
  client.delete(url)
18
27
  end
@@ -3,6 +3,12 @@ module Layer
3
3
  module Find
4
4
 
5
5
  module ClassMethods
6
+ # Finds the resource with the given id
7
+ #
8
+ # @param id [String] the resource's id
9
+ # @param client [Layer::Client] the client to use to make this request
10
+ # @return [Layer::Resource] the found resource
11
+ # @raise [Layer::Exceptions::Exception] a subclass of Layer::Exceptions::Exception describing the error
6
12
  def find(id, client = self.client)
7
13
  id = Layer::Client.normalize_id(id)
8
14
  response = client.get("#{url}/#{id}")
@@ -10,10 +16,15 @@ module Layer
10
16
  end
11
17
  end
12
18
 
19
+ # @!visibility private
13
20
  def self.included(base)
14
21
  base.extend(ClassMethods)
15
22
  end
16
23
 
24
+ # Reloads the resource
25
+ #
26
+ # @return [Layer::Resource] the resource itself
27
+ # @raise [Layer::Exceptions::Exception] a subclass of Layer::Exceptions::Exception describing the error
17
28
  def reload
18
29
  self.attributes = client.get(url)
19
30
  self
@@ -3,12 +3,18 @@ module Layer
3
3
  module List
4
4
 
5
5
  module ClassMethods
6
+ # Finds all resources
7
+ #
8
+ # @param client [Layer::Client] the client to use to make this request
9
+ # @return [Enumerable] the found resources
10
+ # @raise [Layer::Exceptions::Exception] a subclass of Layer::Exceptions::Exception describing the error
6
11
  def all(client = self.client)
7
12
  response = client.get(url)
8
13
  response.map { |attributes| from_response(attributes, client) }
9
14
  end
10
15
  end
11
16
 
17
+ # @!visibility private
12
18
  def self.included(base)
13
19
  base.extend(ClassMethods)
14
20
  end
@@ -0,0 +1,23 @@
1
+ module Layer
2
+ module Operations
3
+ module Paginate
4
+
5
+ module ClassMethods
6
+ # Finds all resources from a paginated endpoint
7
+ #
8
+ # @param client [Layer::Client] the client to use to make this request
9
+ # @return [Layer::ResourceCollection] the found resources
10
+ # @raise [Layer::Exceptions::Exception] a subclass of Layer::Exceptions::Exception describing the error
11
+ def all(client = self.client)
12
+ Layer::ResourceCollection.new(self, client)
13
+ end
14
+ end
15
+
16
+ # @!visibility private
17
+ def self.included(base)
18
+ base.extend(ClassMethods)
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -2,12 +2,20 @@ module Layer
2
2
  module Operations
3
3
  module Patch
4
4
 
5
+ # Creates the resource with the given attributes
6
+ #
7
+ # @return [Boolean] whether saving was successful
8
+ # @raise [Layer::Exceptions::Exception] a subclass of Layer::Exceptions::Exception describing the error
5
9
  def save
6
10
  client.patch(url, patch.operations)
7
11
  patch.reset
8
12
  true
9
13
  end
10
14
 
15
+ # Updates the resource's attributes to the given ones
16
+ #
17
+ # @param [Hash] attributes the new attributes
18
+ # @return [Layer::Patch::Hash] the resources new attributes
11
19
  def attributes=(attributes)
12
20
  @attributes = Layer::Patch::Hash.new(patch, attributes)
13
21
  end
@@ -10,7 +10,7 @@ module Layer
10
10
 
11
11
  def []=(key, value)
12
12
  patch.set(key, value)
13
- super
13
+ super(key, wrap(key, value))
14
14
  end
15
15
  alias :store :[]=
16
16
 
@@ -7,7 +7,7 @@ module Layer
7
7
  @resource_type = resource_type
8
8
  @base = base
9
9
 
10
- operations.each { |operation| singleton_class.include(operation::ClassMethods) }
10
+ operations.each { |operation| singleton_class.send(:include, operation::ClassMethods) }
11
11
 
12
12
  instance_eval(&block) if block_given?
13
13
  end
@@ -17,7 +17,7 @@ module Layer
17
17
  end
18
18
 
19
19
  def client
20
- @client ||= Client.new
20
+ @client ||= Client::Platform.new
21
21
  end
22
22
  end
23
23
 
@@ -29,7 +29,7 @@ module Layer
29
29
  end
30
30
 
31
31
  def url
32
- attributes['url']
32
+ attributes['url'] || (id && "#{self.class.url}/#{Layer::Client.normalize_id(id)}")
33
33
  end
34
34
 
35
35
  def id
@@ -37,13 +37,18 @@ module Layer
37
37
  end
38
38
 
39
39
  def respond_to_missing?(method, include_private = false)
40
- attributes.has_key?(method.to_s) || super
40
+ attribute = method.to_s.sub(/=$/, '')
41
+
42
+ attributes.has_key?(attribute) || super
41
43
  end
42
44
 
43
45
  private
44
46
 
45
47
  def method_missing(method, *args, &block)
46
- if attributes.has_key?(method.to_s)
48
+ if method.to_s =~ /=$/
49
+ attribute = method.to_s.sub(/=$/, '')
50
+ attributes[attribute] = args.first
51
+ elsif attributes.has_key?(method.to_s)
47
52
  attributes[method.to_s]
48
53
  else
49
54
  super
@@ -0,0 +1,30 @@
1
+ module Layer
2
+ class ResourceCollection < Enumerator
3
+
4
+ def initialize(resource, client)
5
+ @resource = resource
6
+ @client = client
7
+ @params = { page_size: 100 }
8
+
9
+ super() do |yielder|
10
+ while response = next_page
11
+ response.map do |attributes|
12
+ yielder << resource.from_response(attributes, client)
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :resource, :client, :params
21
+
22
+ def next_page
23
+ response = client.get(resource.url, {}, { params: params })
24
+ return nil if response.empty?
25
+ params[:from_id] = Layer::Client.normalize_id(response.last['id'])
26
+ response
27
+ end
28
+
29
+ end
30
+ end
data/lib/layer/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Layer
2
- VERSION = '0.4.1'
2
+ VERSION = '0.5.0'
3
3
  end
@@ -0,0 +1,59 @@
1
+ module Layer
2
+ # @example
3
+ # webhook = Layer::Webhook.create({
4
+ # target_config: { foo: :bar },
5
+ # secret: 'my-secret',
6
+ # event_types: ['message.sent'],
7
+ # target_url: 'http://example.com/layer/webhook'
8
+ # })
9
+ # @see https://gist.github.com/vtrehan/9ef1e16db5e74305ddf3 Layer Webhook documentation (Prerelease)
10
+ # @note This feature is still in beta at Layer. Please contact Layer to enable webhooks for your account.
11
+ #
12
+ # @!macro platform-api
13
+ class Webhook < Resource
14
+ include Operations::Find
15
+ include Operations::List
16
+ include Operations::Create
17
+ include Operations::Delete
18
+
19
+ # @!parse extend Layer::Operations::Find::ClassMethods
20
+ # @!parse extend Layer::Operations::List::ClassMethods
21
+ # @!parse extend Layer::Operations::Create::ClassMethods
22
+ # @!parse extend Layer::Operations::Delete::ClassMethods
23
+
24
+ # Activate this webhook
25
+ def activate!
26
+ client.post("#{url}/activate")
27
+ end
28
+
29
+ # Deactivate this webhook
30
+ def deactivate!
31
+ client.post("#{url}/deactivate")
32
+ end
33
+
34
+ # Check if this webhook is unverified
35
+ # @return [Boolean] whether the webhook is unverified
36
+ def unverified?
37
+ status == 'unverified'
38
+ end
39
+
40
+ # Check if this webhook is active
41
+ # @return [Boolean] whether the webhook is active
42
+ def active?
43
+ status == 'active'
44
+ end
45
+
46
+ # Check if this webhook is inactive
47
+ # @return [Boolean] whether the webhook is inactive
48
+ def inactive?
49
+ status == 'inactive'
50
+ end
51
+
52
+ # Returns the time the webhook was created at
53
+ # @return [Time] the time the webhook was created at
54
+ def created_at
55
+ Time.parse(attributes['created_at'])
56
+ end
57
+
58
+ end
59
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: layer-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benedikt Deicke
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-07-29 00:00:00.000000000 Z
11
+ date: 2015-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -56,30 +56,30 @@ dependencies:
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '3.3'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '3.3'
69
69
  - !ruby/object:Gem::Dependency
70
- name: guard-rspec
70
+ name: yard
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '0.8'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '0.8'
83
83
  description: Ruby bindings for the Layer Platform API
84
84
  email:
85
85
  - benedikt@benediktdeicke.com
@@ -103,13 +103,18 @@ files:
103
103
  - lib/layer/announcement.rb
104
104
  - lib/layer/block.rb
105
105
  - lib/layer/client.rb
106
+ - lib/layer/client/platform.rb
107
+ - lib/layer/client/rest.rb
108
+ - lib/layer/content.rb
106
109
  - lib/layer/conversation.rb
110
+ - lib/layer/exceptions.rb
107
111
  - lib/layer/message.rb
108
112
  - lib/layer/operations.rb
109
113
  - lib/layer/operations/create.rb
110
114
  - lib/layer/operations/delete.rb
111
115
  - lib/layer/operations/find.rb
112
116
  - lib/layer/operations/list.rb
117
+ - lib/layer/operations/paginate.rb
113
118
  - lib/layer/operations/patch.rb
114
119
  - lib/layer/patch.rb
115
120
  - lib/layer/patch/array.rb
@@ -117,9 +122,11 @@ files:
117
122
  - lib/layer/patch/hash.rb
118
123
  - lib/layer/relation_proxy.rb
119
124
  - lib/layer/resource.rb
125
+ - lib/layer/resource_collection.rb
120
126
  - lib/layer/ruby.rb
121
127
  - lib/layer/user.rb
122
128
  - lib/layer/version.rb
129
+ - lib/layer/webhook.rb
123
130
  homepage: https://github.com/benedikt/layer-ruby
124
131
  licenses:
125
132
  - MIT