layer-ruby 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +5 -0
- data/Guardfile +4 -0
- data/README.md +18 -53
- data/layer-ruby.gemspec +2 -2
- data/lib/layer.rb +17 -0
- data/lib/layer/announcement.rb +7 -1
- data/lib/layer/block.rb +14 -0
- data/lib/layer/client.rb +9 -8
- data/lib/layer/client/platform.rb +22 -0
- data/lib/layer/client/rest.rb +41 -0
- data/lib/layer/content.rb +50 -0
- data/lib/layer/conversation.rb +63 -1
- data/lib/layer/exceptions.rb +52 -0
- data/lib/layer/message.rb +38 -0
- data/lib/layer/operations.rb +1 -0
- data/lib/layer/operations/create.rb +7 -0
- data/lib/layer/operations/delete.rb +9 -0
- data/lib/layer/operations/find.rb +11 -0
- data/lib/layer/operations/list.rb +6 -0
- data/lib/layer/operations/paginate.rb +23 -0
- data/lib/layer/operations/patch.rb +8 -0
- data/lib/layer/patch/hash.rb +1 -1
- data/lib/layer/relation_proxy.rb +1 -1
- data/lib/layer/resource.rb +9 -4
- data/lib/layer/resource_collection.rb +30 -0
- data/lib/layer/version.rb +1 -1
- data/lib/layer/webhook.rb +59 -0
- metadata +18 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78be9a887246783d87ee5441bb6d713d7d11e0e9
|
4
|
+
data.tar.gz: c96c5872a9539077b4c86abc8fcda78bace25fcf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d02be7b2d37304b8d8e18f4ebc8afba4b697c9272ef357e7bee0244f642294553565a09f59482fd04e1ea260c0ee90250b012bef36e7509aedc39d3eceb457b
|
7
|
+
data.tar.gz: f5ca37c2018d18ab8052b2b9df63e15b24d9e396cd92a504b8ac6a5b6ca5391987259969f5f8b7e790d91a960c88eaacd81af5992e904c76dcdf9f98a6d952ed
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Guardfile
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
#
|
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
|
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
|
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
|
-
###
|
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
|
-
|
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
|
-
|
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
|
-
###
|
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
|
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::
|
55
|
+
client = Layer::Client.authenticate { |nonce| Layer::IdentityToken.new('user_id_here', nonce) }
|
80
56
|
```
|
81
57
|
|
82
|
-
|
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
|
-
|
88
|
-
|
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
|
-
###
|
65
|
+
### Documentation
|
95
66
|
|
96
|
-
|
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 "
|
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
|
data/lib/layer/announcement.rb
CHANGED
@@ -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
|
-
|
27
|
-
|
28
|
-
|
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
|
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
|
data/lib/layer/conversation.rb
CHANGED
@@ -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
|
data/lib/layer/operations.rb
CHANGED
@@ -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
|
data/lib/layer/patch/hash.rb
CHANGED
data/lib/layer/relation_proxy.rb
CHANGED
@@ -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
|
10
|
+
operations.each { |operation| singleton_class.send(:include, operation::ClassMethods) }
|
11
11
|
|
12
12
|
instance_eval(&block) if block_given?
|
13
13
|
end
|
data/lib/layer/resource.rb
CHANGED
@@ -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
|
-
|
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
|
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
@@ -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
|
+
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-
|
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: '
|
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: '
|
68
|
+
version: '3.3'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
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
|