ink_file_picker 0.0.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 +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +76 -0
- data/Rakefile +1 -0
- data/ink_file_picker.gemspec +27 -0
- data/lib/ink_file_picker/assignable.rb +21 -0
- data/lib/ink_file_picker/client.rb +183 -0
- data/lib/ink_file_picker/configuration.rb +32 -0
- data/lib/ink_file_picker/errors.rb +36 -0
- data/lib/ink_file_picker/file_handle.rb +32 -0
- data/lib/ink_file_picker/policy.rb +50 -0
- data/lib/ink_file_picker/response.rb +23 -0
- data/lib/ink_file_picker/url_builder.rb +20 -0
- data/lib/ink_file_picker/version.rb +3 -0
- data/lib/ink_file_picker.rb +25 -0
- data/spec/fixtures/skalar.png +0 -0
- data/spec/ink_file_picker/client_spec.rb +410 -0
- data/spec/ink_file_picker/configuration_spec.rb +23 -0
- data/spec/ink_file_picker/file_handle_spec.rb +28 -0
- data/spec/ink_file_picker/policy_spec.rb +30 -0
- data/spec/ink_file_picker_spec.rb +14 -0
- data/spec/spec_helper.rb +6 -0
- metadata +150 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d22df05e49b4463a633bb87fbb978dae55653c9f
|
4
|
+
data.tar.gz: 590c40f9b6e7f1ff9f0d2669a29e68d7f6a9f64d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ee4b1ade5cb8f4ab41017a119384cc75029d13f11d338b9262096e3238c88ccc40cae29f6c0db0ecd39d077f666e5c7c5b4410ea6b1b972e53b2b3269f8422b8
|
7
|
+
data.tar.gz: d22c324c7ad0b417bdb0e32883c7190f00c3571ed9d68dd4e1bb0ec3c671b4096aa18b8821ff3613e1d6b8ff4cdc3877bcb1cb1cbe9627fc2245d7625dfa6e50
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Thorbjørn Hermansen
|
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,76 @@
|
|
1
|
+
# InkFilePicker
|
2
|
+
|
3
|
+
Ruby API client for Ink File Picker (known as filepicker.io).
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'ink_file_picker'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install ink_file_picker
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
This client mirrors part of File Picker's JavaScript API.
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
### Creating a client
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
# Create a client which will sign URLs. You may drop secret if you have
|
33
|
+
# not enabled this feature in your developer portal for your application.
|
34
|
+
client = InkFilePicker.client(key: 'you-api-key', secret: 'your-secret')
|
35
|
+
```
|
36
|
+
|
37
|
+
### Storing a file
|
38
|
+
```ruby
|
39
|
+
response = client.store_file file_or_path, content_type
|
40
|
+
response = client.store_url 'http://www.example.com/img.jpg'
|
41
|
+
```
|
42
|
+
|
43
|
+
### Removing a file
|
44
|
+
```ruby
|
45
|
+
response = client.remove url_or_handle_name
|
46
|
+
```
|
47
|
+
|
48
|
+
### Read operations
|
49
|
+
```ruby
|
50
|
+
url = client.convert_url url_or_handle_name, w: 100, h: 100
|
51
|
+
url = client.convert_url url_or_handle_name, {w: 100, h: 100}, expiry: 10.minutes.from_now.to_i
|
52
|
+
|
53
|
+
# Adds policy and signature, if secret given when client was created.
|
54
|
+
url = client.retrieve_url url_or_handle_name
|
55
|
+
url = client.retrieve_url url_or_handle_name, expiry: 10.minutes.from_now.to_i
|
56
|
+
|
57
|
+
|
58
|
+
# Get simple stat on a file, like the Javascript client
|
59
|
+
stat = client.stat url_or_handle_name
|
60
|
+
|
61
|
+
dimentions = client.stat url_or_handle_name, {width: true, height: true}
|
62
|
+
```
|
63
|
+
|
64
|
+
### Errors
|
65
|
+
|
66
|
+
When making requests to the API errors may occur. `InkFilePicker::ClientError` or `InkFilePicker::ServerError` will
|
67
|
+
be raised if we are getting 4xx or 5xx responses back from File Picker. All errors inherits from `InkFilePicker::Error`.
|
68
|
+
|
69
|
+
|
70
|
+
## Contributing
|
71
|
+
|
72
|
+
1. Fork it (https://github.com/Skalar/ink_file_picker/fork)
|
73
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
74
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
75
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
76
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ink_file_picker/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ink_file_picker"
|
8
|
+
spec.version = InkFilePicker::VERSION
|
9
|
+
spec.authors = ["Thorbjørn Hermansen"]
|
10
|
+
spec.email = ["thhermansen@gmail.com"]
|
11
|
+
spec.summary = %q{Client for Ink File Picker}
|
12
|
+
#spec.description = %q{TODO: Write a longer description. Optional.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "activesupport", ">= 3.2.14", "< 5"
|
22
|
+
spec.add_dependency "faraday", "~> 0.9.0"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rspec", "~> 2.14.1"
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module InkFilePicker
|
2
|
+
module Assignable
|
3
|
+
|
4
|
+
def []=(name, value)
|
5
|
+
public_send "#{name}=", value
|
6
|
+
end
|
7
|
+
|
8
|
+
def [](name)
|
9
|
+
public_send name
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def assign(attributes)
|
16
|
+
attributes.each_pair do |name, value|
|
17
|
+
self[name] = value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require "faraday"
|
2
|
+
|
3
|
+
module InkFilePicker
|
4
|
+
class Client
|
5
|
+
attr_accessor :configuration
|
6
|
+
|
7
|
+
def initialize(configuration)
|
8
|
+
self.configuration = Configuration.new configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
# Public: Store a file from given URL.
|
13
|
+
#
|
14
|
+
# url - URL to resource
|
15
|
+
# policy_attributes - If you use security policies you may send in for instance {expire: 10.minutes.from_now} here
|
16
|
+
#
|
17
|
+
# Returns a hash representing the response where you can read for instance 'url'
|
18
|
+
def store_url(url, policy_attributes = {})
|
19
|
+
params = {key: configuration.key}
|
20
|
+
|
21
|
+
add_policy_to params, from: policy_attributes, ensure_included: {call: 'store'}
|
22
|
+
|
23
|
+
response = http_connection.post configuration.store_path do |request|
|
24
|
+
request.params = params
|
25
|
+
request.body = {url: url}
|
26
|
+
end
|
27
|
+
|
28
|
+
wrap_response_or_fail_unless_success! response
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public: Store a file from given local file or path.
|
32
|
+
#
|
33
|
+
# file_or_path - File or path to file
|
34
|
+
# content_type - The file's content type
|
35
|
+
# filename - The file's name, optional
|
36
|
+
# policy_attributes - If you use security policies you may send in for instance {expire: 10.minutes.from_now} here
|
37
|
+
#
|
38
|
+
# Returns a hash representing the response where you can read for instance 'url'
|
39
|
+
def store_file(file_or_path, content_type, filename = nil, policy_attributes = {})
|
40
|
+
file_upload = Faraday::UploadIO.new file_or_path, content_type, filename
|
41
|
+
params = {key: configuration.key}
|
42
|
+
|
43
|
+
add_policy_to params, from: policy_attributes, ensure_included: {call: 'store'}
|
44
|
+
|
45
|
+
response = http_connection.post configuration.store_path do |request|
|
46
|
+
request.params = params
|
47
|
+
request.body = {fileUpload: file_upload}
|
48
|
+
end
|
49
|
+
|
50
|
+
wrap_response_or_fail_unless_success! response
|
51
|
+
end
|
52
|
+
|
53
|
+
# Public: Removes a file from file picker.
|
54
|
+
#
|
55
|
+
# handle_or_url - The handle or URL to the file
|
56
|
+
# policy_attributes - If you use security policies you may send in for instance {expire: 10.minutes.from_now} here
|
57
|
+
#
|
58
|
+
# Returns boolean value
|
59
|
+
def remove(handle_or_url, policy_attributes = {})
|
60
|
+
response = http_connection.delete remove_url(handle_or_url, policy_attributes)
|
61
|
+
|
62
|
+
wrap_response_or_fail_unless_success! response
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# Public: Returns short stat for a file
|
67
|
+
#
|
68
|
+
# handle_or_url - The handle or URL to the file
|
69
|
+
# params - Request params, like {width: true, height: true} to get width and height info. May be empty for default response
|
70
|
+
# policy_attributes - If you use security policies you may send in for instance {expire: 10.minutes.from_now} here
|
71
|
+
#
|
72
|
+
# Returns hash of headers returned from file picker or false if request was unsuccessful
|
73
|
+
def stat(handle_or_url, params = {}, policy_attributes = {})
|
74
|
+
response = http_connection.get stat_url(handle_or_url, params, policy_attributes)
|
75
|
+
|
76
|
+
wrap_response_or_fail_unless_success! response
|
77
|
+
end
|
78
|
+
|
79
|
+
# Public: Generates a you can use for removing an asset on file picker.
|
80
|
+
#
|
81
|
+
# handle_or_url - The handle or URL to the file
|
82
|
+
# policy_attributes - If you use security policies you may send in for instance {expire: 10.minutes.from_now} here
|
83
|
+
#
|
84
|
+
# Returns a URL to the converted image
|
85
|
+
def remove_url(handle_or_url, policy_attributes = {})
|
86
|
+
generate_url handle_or_url, {key: configuration.key}, policy_attributes, call: 'remove'
|
87
|
+
end
|
88
|
+
|
89
|
+
# Public: Generates a convert URL for given file.
|
90
|
+
#
|
91
|
+
# handle_or_url - The handle or URL to the file
|
92
|
+
# params - Convert params, like {w: 100, h:100}
|
93
|
+
# policy_attributes - If you use security policies you may send in for instance {expire: 10.minutes.from_now} here
|
94
|
+
#
|
95
|
+
# Returns a URL to the converted image
|
96
|
+
def convert_url(handle_or_url, params = {}, policy_attributes = {})
|
97
|
+
generate_url handle_or_url, params, policy_attributes, call: 'convert', url_action: 'convert'
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# Public: Generates a URL for a given file
|
102
|
+
#
|
103
|
+
# handle_or_url - The handle or URL to the file
|
104
|
+
# params - Params to be added as get params, like {cache: true}
|
105
|
+
# policy_attributes - If you use security policies you may send in for instance {expire: 10.minutes.from_now} here
|
106
|
+
#
|
107
|
+
# This method is not that usefull unless you have enabled security policy
|
108
|
+
#
|
109
|
+
# Returns a URL to the image
|
110
|
+
def retrieve_url(handle_or_url, params = {}, policy_attributes = {})
|
111
|
+
generate_url handle_or_url, params, policy_attributes, call: 'read'
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
# Public: Generates a stat URL for a given file
|
116
|
+
#
|
117
|
+
# handle_or_url - The handle or URL to the file
|
118
|
+
# policy_attributes - If you use security policies you may send in for instance {expire: 10.minutes.from_now} here
|
119
|
+
#
|
120
|
+
# Returns a URL to the image you can do a HEAD request to in order to get stats
|
121
|
+
def stat_url(handle_or_url, params, policy_attributes = {})
|
122
|
+
generate_url handle_or_url, params, policy_attributes, call: 'stat', url_action: 'metadata'
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
# Public: Creates a policy with default configuration set in this client.
|
130
|
+
#
|
131
|
+
# Returns Policy object
|
132
|
+
def policy(attributes)
|
133
|
+
attributes.reverse_merge!(
|
134
|
+
secret: configuration.secret,
|
135
|
+
expiry: Time.now.to_i + configuration.default_expiry
|
136
|
+
)
|
137
|
+
|
138
|
+
Policy.new attributes
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
|
145
|
+
def http_connection
|
146
|
+
@http_connection ||= Faraday.new(url: configuration.filepicker_url) do |builder|
|
147
|
+
builder.request :multipart
|
148
|
+
builder.request :url_encoded
|
149
|
+
builder.adapter configuration.http_adapter || Faraday.default_adapter
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def generate_url(handle_or_url, params, policy_attributes, options)
|
157
|
+
file_handle = FileHandle.new handle_or_url, configuration.cdn_url
|
158
|
+
|
159
|
+
add_policy_to params, from: policy_attributes, ensure_included: {handle: file_handle.handle, call: options[:call]}
|
160
|
+
|
161
|
+
url = UrlBuilder.new(file_url: file_handle.url, action: options[:url_action], params: params).to_s
|
162
|
+
end
|
163
|
+
|
164
|
+
def add_policy_to(params, options = {})
|
165
|
+
policy_attributes = (options[:from] || {}).merge options[:ensure_included]
|
166
|
+
params.merge! policy(policy_attributes)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Private: Inspects response for error and raise a InkFilePicker error if client/server error.
|
170
|
+
def wrap_response_or_fail_unless_success!(response)
|
171
|
+
case response.status
|
172
|
+
when 200...300
|
173
|
+
Response.new response
|
174
|
+
when 400...500
|
175
|
+
fail ClientError.new response.body, response
|
176
|
+
when 500...600
|
177
|
+
fail ServerError.new response.body, response
|
178
|
+
else
|
179
|
+
fail Error, "Response was neither a success, nor within http status 400...600. Response was: '#{response.inspect}'."
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module InkFilePicker
|
2
|
+
class Configuration
|
3
|
+
include Assignable
|
4
|
+
|
5
|
+
API_DEFAULTS = {
|
6
|
+
secret: nil,
|
7
|
+
default_expiry: 600, # in 10 hours
|
8
|
+
cdn_url: 'https://www.filepicker.io/api/file/',
|
9
|
+
filepicker_url: 'https://www.filepicker.io',
|
10
|
+
store_path: '/api/store/S3',
|
11
|
+
http_adapter: :net_http
|
12
|
+
}
|
13
|
+
|
14
|
+
attr_accessor :key, :secret, :default_expiry, :cdn_url, :filepicker_url, :store_path, :http_adapter
|
15
|
+
|
16
|
+
def initialize(attributes = {})
|
17
|
+
assign API_DEFAULTS
|
18
|
+
assign attributes
|
19
|
+
|
20
|
+
verify!
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def verify!
|
27
|
+
if key.blank?
|
28
|
+
fail ArgumentError, "An API key must be provided"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module InkFilePicker
|
2
|
+
module ErrorWithOriginal
|
3
|
+
attr_reader :msg, :related
|
4
|
+
|
5
|
+
def initialize(msg, related)
|
6
|
+
@msg = msg
|
7
|
+
@related = related
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"#{self.class.name}: Message: '#{msg}'. Related object: '#{related.inspect}'."
|
12
|
+
end
|
13
|
+
alias inspect to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# Public: Base class for errors related to InkFilePicker.
|
18
|
+
class Error < StandardError
|
19
|
+
end
|
20
|
+
|
21
|
+
# Public: Got a request error back trying to do a request
|
22
|
+
#
|
23
|
+
# This includes wire errors like timeouts etc, and server errors
|
24
|
+
# like 5xx. Inspect error_or_response for more information.
|
25
|
+
#
|
26
|
+
class ServerError < Error
|
27
|
+
include ErrorWithOriginal
|
28
|
+
end
|
29
|
+
|
30
|
+
# Public: Got an error where the client seems to be doing something wrong
|
31
|
+
#
|
32
|
+
# These errors mainly comes from http 4xx errors.
|
33
|
+
class ClientError < Error
|
34
|
+
include ErrorWithOriginal
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module InkFilePicker
|
4
|
+
# Public: Simple class for working with file URL and file handles.
|
5
|
+
#
|
6
|
+
# Does conversions like url to handle and from a handle to url
|
7
|
+
class FileHandle
|
8
|
+
attr_accessor :handle, :url, :cdn_url
|
9
|
+
|
10
|
+
def initialize(handle_or_url, cdn_url)
|
11
|
+
self.cdn_url = cdn_url
|
12
|
+
self.handle = extract_handle handle_or_url
|
13
|
+
self.url = build_url_from_handle
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def build_url_from_handle
|
21
|
+
joins_with = cdn_url.ends_with?('/') ? '' : '/'
|
22
|
+
[cdn_url, handle].join joins_with
|
23
|
+
end
|
24
|
+
|
25
|
+
def extract_handle(handle_or_url)
|
26
|
+
uri = URI.parse handle_or_url
|
27
|
+
uri.path.split('/').last
|
28
|
+
rescue URI::InvalidURIError
|
29
|
+
handle_or_url
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module InkFilePicker
|
5
|
+
class Policy
|
6
|
+
include Assignable
|
7
|
+
|
8
|
+
POLICY_ATTRIBUTES = %w[expiry call handle max_size min_size path container].freeze
|
9
|
+
|
10
|
+
attr_accessor :secret, *POLICY_ATTRIBUTES
|
11
|
+
|
12
|
+
def initialize(attributes)
|
13
|
+
assign attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
def policy
|
19
|
+
Base64.urlsafe_encode64 policy_json
|
20
|
+
end
|
21
|
+
|
22
|
+
def signature
|
23
|
+
OpenSSL::HMAC.hexdigest 'sha256', secret, policy
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def to_hash
|
28
|
+
return {} if secret.blank?
|
29
|
+
|
30
|
+
{
|
31
|
+
policy: policy,
|
32
|
+
signature: signature
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
def policy_json
|
39
|
+
out = {}
|
40
|
+
|
41
|
+
POLICY_ATTRIBUTES.each do |attr_name|
|
42
|
+
if value = self[attr_name] and value.present?
|
43
|
+
out[attr_name] = value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
out.to_json
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module InkFilePicker
|
2
|
+
# Public: Simple decorator class for response.
|
3
|
+
#
|
4
|
+
# Decorates the response with hash like access to the
|
5
|
+
# parsed body, which is expected to be JSON.
|
6
|
+
class Response
|
7
|
+
attr_reader :http_response
|
8
|
+
|
9
|
+
delegate :success?, to: :http_response
|
10
|
+
|
11
|
+
def initialize(http_response)
|
12
|
+
@http_response = http_response
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
parsed_body[key.to_s]
|
17
|
+
end
|
18
|
+
|
19
|
+
def parsed_body
|
20
|
+
@parsed_body ||= JSON.parse http_response.body
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module InkFilePicker
|
2
|
+
# Public: Takes a file url, adds action to the path (if any), and includes params.
|
3
|
+
class UrlBuilder
|
4
|
+
include Assignable
|
5
|
+
|
6
|
+
attr_accessor :file_url, :action, :params
|
7
|
+
|
8
|
+
def initialize(attributes = {})
|
9
|
+
assign attributes
|
10
|
+
end
|
11
|
+
|
12
|
+
def url
|
13
|
+
url = [file_url, action].compact.join '/'
|
14
|
+
url = [url, params.to_param].join '?' if params.any?
|
15
|
+
|
16
|
+
url
|
17
|
+
end
|
18
|
+
alias to_s url
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "ink_file_picker/version"
|
2
|
+
|
3
|
+
require "active_support/all"
|
4
|
+
require "ink_file_picker/errors"
|
5
|
+
|
6
|
+
module InkFilePicker
|
7
|
+
extend ActiveSupport::Autoload
|
8
|
+
|
9
|
+
autoload :Assignable
|
10
|
+
autoload :Configuration
|
11
|
+
autoload :FileHandle
|
12
|
+
autoload :UrlBuilder
|
13
|
+
autoload :Response
|
14
|
+
autoload :Client
|
15
|
+
autoload :Policy
|
16
|
+
|
17
|
+
# Public: Creates a new Ink File Picker Client.
|
18
|
+
#
|
19
|
+
# configuration - configuration for the client with an API key
|
20
|
+
#
|
21
|
+
# Returns InkFilePicker::Client
|
22
|
+
def self.client(configuration)
|
23
|
+
Client.new configuration
|
24
|
+
end
|
25
|
+
end
|
Binary file
|
@@ -0,0 +1,410 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe InkFilePicker::Client do
|
4
|
+
let(:attributes) do
|
5
|
+
{
|
6
|
+
key: 'key',
|
7
|
+
secret: '6U5CWAU57NAHDC2ICXQKMXYZ4Q',
|
8
|
+
http_adapter: :test
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
subject { described_class.new attributes }
|
13
|
+
|
14
|
+
describe "#store_url" do
|
15
|
+
let(:url) { 'https://s3.amazonaws.com/test.jpg' }
|
16
|
+
let(:response) { '{"url": "https://www.filepicker.io/api/file/WmFxB2aSe20SGT2kzSsr", "size": 234, "type": "image/jpeg", "filename": "test.jpg", "key": "WmFxB2aSe20SGT2kzSsr_test.jpg"}' }
|
17
|
+
|
18
|
+
context "without secret" do
|
19
|
+
before { subject.configuration.secret = nil }
|
20
|
+
|
21
|
+
it "posts to filepicker" do
|
22
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
23
|
+
stub.post(subject.configuration.store_path + '?key=key', {url: url}) { [200, {}, response] }
|
24
|
+
end
|
25
|
+
|
26
|
+
stubbed_connection = Faraday.new do |builder|
|
27
|
+
builder.adapter :test, stubs
|
28
|
+
end
|
29
|
+
|
30
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
31
|
+
|
32
|
+
response = subject.store_url url
|
33
|
+
|
34
|
+
stubs.verify_stubbed_calls
|
35
|
+
expect(response['url']).to eq 'https://www.filepicker.io/api/file/WmFxB2aSe20SGT2kzSsr'
|
36
|
+
expect(response[:url]).to eq 'https://www.filepicker.io/api/file/WmFxB2aSe20SGT2kzSsr'
|
37
|
+
expect(response.http_response).to be_a Faraday::Response
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "with secret" do
|
42
|
+
it "includes policy and signature" do
|
43
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
44
|
+
store_path = subject.configuration.store_path + '?key=key&policy=eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJzdG9yZSJ9&signature=60cb43bb945543d7fdbd2662ae21d5c53e28529720263619cfebc3509e820807'
|
45
|
+
stub.post(store_path, {url: url}) { [200, {}, response] }
|
46
|
+
end
|
47
|
+
|
48
|
+
stubbed_connection = Faraday.new do |builder|
|
49
|
+
builder.adapter :test, stubs
|
50
|
+
end
|
51
|
+
|
52
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
53
|
+
|
54
|
+
response = subject.store_url url, expiry: 1394363896
|
55
|
+
|
56
|
+
stubs.verify_stubbed_calls
|
57
|
+
expect(response['url']).to eq 'https://www.filepicker.io/api/file/WmFxB2aSe20SGT2kzSsr'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "handles client errors correctly" do
|
61
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
62
|
+
store_path = subject.configuration.store_path + '?key=key&policy=eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJzdG9yZSJ9&signature=60cb43bb945543d7fdbd2662ae21d5c53e28529720263619cfebc3509e820807'
|
63
|
+
stub.post(store_path, {url: url}) { [403, {}, '[uuid=AF614DF7F9594A87] This action has been secured by the developer of this website. Error: The signature was not valid'] }
|
64
|
+
end
|
65
|
+
|
66
|
+
stubbed_connection = Faraday.new do |builder|
|
67
|
+
builder.adapter :test, stubs
|
68
|
+
end
|
69
|
+
|
70
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
71
|
+
|
72
|
+
expect { subject.store_url url, expiry: 1394363896 }.to raise_error InkFilePicker::ClientError
|
73
|
+
end
|
74
|
+
|
75
|
+
it "handles server errors correctly" do
|
76
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
77
|
+
store_path = subject.configuration.store_path + '?key=key&policy=eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJzdG9yZSJ9&signature=60cb43bb945543d7fdbd2662ae21d5c53e28529720263619cfebc3509e820807'
|
78
|
+
stub.post(store_path, {url: url}) { [502, {}, 'Bad Gateway'] }
|
79
|
+
end
|
80
|
+
|
81
|
+
stubbed_connection = Faraday.new do |builder|
|
82
|
+
builder.adapter :test, stubs
|
83
|
+
end
|
84
|
+
|
85
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
86
|
+
|
87
|
+
expect { subject.store_url url, expiry: 1394363896 }.to raise_error InkFilePicker::ServerError
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#store_file" do
|
93
|
+
let(:path) { File.join(File.dirname(__FILE__), '../fixtures', 'skalar.png') }
|
94
|
+
let(:file) { File.open path }
|
95
|
+
let!(:file_upload) { Faraday::UploadIO.new file, 'image/png' }
|
96
|
+
let(:response) { '{"url": "https://www.filepicker.io/api/file/WmFxB2aSe20SGT2kzSsr", "size": 234, "type": "image/jpeg", "filename": "test.jpg", "key": "WmFxB2aSe20SGT2kzSsr_test.jpg"}' }
|
97
|
+
|
98
|
+
context "without secret" do
|
99
|
+
before { subject.configuration.secret = nil }
|
100
|
+
|
101
|
+
it "uploads the given file as file" do
|
102
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
103
|
+
stub.post(subject.configuration.store_path + '?key=key', {fileUpload: file_upload}) { [200, {}, response] }
|
104
|
+
end
|
105
|
+
|
106
|
+
stubbed_connection = Faraday.new do |builder|
|
107
|
+
builder.adapter :test, stubs
|
108
|
+
end
|
109
|
+
|
110
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
111
|
+
Faraday::UploadIO.stub(:new).and_return file_upload # Need same object, so request equals the stub
|
112
|
+
|
113
|
+
response = subject.store_file file, 'image/png'
|
114
|
+
|
115
|
+
stubs.verify_stubbed_calls
|
116
|
+
expect(response['url']).to eq 'https://www.filepicker.io/api/file/WmFxB2aSe20SGT2kzSsr'
|
117
|
+
end
|
118
|
+
|
119
|
+
it "uploads the given file as path" do
|
120
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
121
|
+
stub.post(subject.configuration.store_path + '?key=key', {fileUpload: file_upload}) { [200, {}, response] }
|
122
|
+
end
|
123
|
+
|
124
|
+
stubbed_connection = Faraday.new do |builder|
|
125
|
+
builder.adapter :test, stubs
|
126
|
+
end
|
127
|
+
|
128
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
129
|
+
Faraday::UploadIO.stub(:new).and_return file_upload # Need same object, so request equals the stub
|
130
|
+
|
131
|
+
response = subject.store_file path, 'image/png'
|
132
|
+
|
133
|
+
stubs.verify_stubbed_calls
|
134
|
+
expect(response['url']).to eq 'https://www.filepicker.io/api/file/WmFxB2aSe20SGT2kzSsr'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context "with secret" do
|
139
|
+
it "uploads the given file as file" do
|
140
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
141
|
+
stub.post(subject.configuration.store_path + '?key=key&policy=eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJzdG9yZSJ9&signature=60cb43bb945543d7fdbd2662ae21d5c53e28529720263619cfebc3509e820807', {fileUpload: file_upload}) { [200, {}, response] }
|
142
|
+
end
|
143
|
+
|
144
|
+
stubbed_connection = Faraday.new do |builder|
|
145
|
+
builder.adapter :test, stubs
|
146
|
+
end
|
147
|
+
|
148
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
149
|
+
Faraday::UploadIO.stub(:new).and_return file_upload # Need same object, so request equals the stub
|
150
|
+
|
151
|
+
response = subject.store_file file, 'image/png', nil, expiry: 1394363896
|
152
|
+
|
153
|
+
stubs.verify_stubbed_calls
|
154
|
+
expect(response['url']).to eq 'https://www.filepicker.io/api/file/WmFxB2aSe20SGT2kzSsr'
|
155
|
+
end
|
156
|
+
|
157
|
+
it "handles client errors correctly" do
|
158
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
159
|
+
store_path = subject.configuration.store_path + '?key=key&policy=eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJzdG9yZSJ9&signature=60cb43bb945543d7fdbd2662ae21d5c53e28529720263619cfebc3509e820807'
|
160
|
+
stub.post(store_path) { [403, {}, '[uuid=AF614DF7F9594A87] This action has been secured by the developer of this website. Error: The signature was not valid'] }
|
161
|
+
end
|
162
|
+
|
163
|
+
stubbed_connection = Faraday.new do |builder|
|
164
|
+
builder.adapter :test, stubs
|
165
|
+
end
|
166
|
+
|
167
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
168
|
+
|
169
|
+
expect { subject.store_file file, 'image/png', nil, expiry: 1394363896 }.to raise_error InkFilePicker::ClientError
|
170
|
+
end
|
171
|
+
|
172
|
+
it "handles server errors correctly" do
|
173
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
174
|
+
store_path = subject.configuration.store_path + '?key=key&policy=eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJzdG9yZSJ9&signature=60cb43bb945543d7fdbd2662ae21d5c53e28529720263619cfebc3509e820807'
|
175
|
+
stub.post(store_path) { [502, {}, 'Bad Gateway'] }
|
176
|
+
end
|
177
|
+
|
178
|
+
stubbed_connection = Faraday.new do |builder|
|
179
|
+
builder.adapter :test, stubs
|
180
|
+
end
|
181
|
+
|
182
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
183
|
+
|
184
|
+
expect { subject.store_file file, 'image/png', nil, expiry: 1394363896 }.to raise_error InkFilePicker::ServerError
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "#remove" do
|
190
|
+
let(:file_url) { 'https://www.filepicker.io/api/file/WmFxB2aSe20SGT2kzSsr' }
|
191
|
+
|
192
|
+
context "without secret" do
|
193
|
+
before { subject.configuration.secret = nil }
|
194
|
+
|
195
|
+
it "makes a delete request with url" do
|
196
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
197
|
+
stub.delete(file_url + '?key=key') { [200, {}, 'success'] }
|
198
|
+
end
|
199
|
+
|
200
|
+
stubbed_connection = Faraday.new do |builder|
|
201
|
+
builder.adapter :test, stubs
|
202
|
+
end
|
203
|
+
|
204
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
205
|
+
|
206
|
+
response = subject.remove file_url
|
207
|
+
|
208
|
+
stubs.verify_stubbed_calls
|
209
|
+
expect(response).to be_true
|
210
|
+
end
|
211
|
+
|
212
|
+
it "makes delete request with file handle name" do
|
213
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
214
|
+
stub.delete(file_url + '?key=key') { [200, {}, 'success'] }
|
215
|
+
end
|
216
|
+
|
217
|
+
stubbed_connection = Faraday.new do |builder|
|
218
|
+
builder.adapter :test, stubs
|
219
|
+
end
|
220
|
+
|
221
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
222
|
+
|
223
|
+
response = subject.remove 'WmFxB2aSe20SGT2kzSsr'
|
224
|
+
|
225
|
+
stubs.verify_stubbed_calls
|
226
|
+
expect(response).to be_true
|
227
|
+
end
|
228
|
+
|
229
|
+
it "handles server errors correctly" do
|
230
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
231
|
+
stub.delete(file_url + '?key=key') { [502, {}, 'Bad Gateway'] }
|
232
|
+
end
|
233
|
+
|
234
|
+
stubbed_connection = Faraday.new do |builder|
|
235
|
+
builder.adapter :test, stubs
|
236
|
+
end
|
237
|
+
|
238
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
239
|
+
|
240
|
+
expect { subject.remove 'WmFxB2aSe20SGT2kzSsr' }.to raise_error InkFilePicker::ServerError
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context "with secret" do
|
245
|
+
it "includes policy and signature" do
|
246
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
247
|
+
stub.delete(file_url + '?key=key&policy=eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJyZW1vdmUiLCJoYW5kbGUiOiJXbUZ4QjJhU2UyMFNHVDJrelNzciJ9&signature=a557d55a680892235619ff0bec6c7254fbb8088e53a53d923b4fad1d39df3955') { [200, {}, 'success'] }
|
248
|
+
end
|
249
|
+
|
250
|
+
stubbed_connection = Faraday.new do |builder|
|
251
|
+
builder.adapter :test, stubs
|
252
|
+
end
|
253
|
+
|
254
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
255
|
+
|
256
|
+
response = subject.remove file_url, expiry: 1394363896
|
257
|
+
|
258
|
+
stubs.verify_stubbed_calls
|
259
|
+
expect(response).to be_true
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "#stat" do
|
265
|
+
let(:file_url) { 'https://www.filepicker.io/api/file/WmFxB2aSe20SGT2kzSsr' }
|
266
|
+
|
267
|
+
it "handles server errors correctly" do
|
268
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
269
|
+
stub.get(file_url + '/metadata') { [502, {}, 'Bad Gateway'] }
|
270
|
+
end
|
271
|
+
|
272
|
+
stubbed_connection = Faraday.new do |builder|
|
273
|
+
builder.adapter :test, stubs
|
274
|
+
end
|
275
|
+
|
276
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
277
|
+
|
278
|
+
expect { subject.stat 'WmFxB2aSe20SGT2kzSsr' }.to raise_error InkFilePicker::ServerError
|
279
|
+
end
|
280
|
+
|
281
|
+
context "with secret" do
|
282
|
+
it "includes policy and signature" do
|
283
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
284
|
+
stub.get(file_url + '/metadata' + '?policy=eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJzdGF0IiwiaGFuZGxlIjoiV21GeEIyYVNlMjBTR1Qya3pTc3IifQ%3D%3D&signature=d70d11f59750903c628f4e35ecc15ef504d71b1ed104c653fe57b2231a7d667c') do
|
285
|
+
[200, {}, '{"mimetype": "image/jpeg", "uploaded": 13.0}']
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
stubbed_connection = Faraday.new do |builder|
|
290
|
+
builder.adapter :test, stubs
|
291
|
+
end
|
292
|
+
|
293
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
294
|
+
|
295
|
+
response = subject.stat file_url, {}, expiry: 1394363896
|
296
|
+
|
297
|
+
stubs.verify_stubbed_calls
|
298
|
+
expect(response['uploaded']).to eq 13.0
|
299
|
+
end
|
300
|
+
|
301
|
+
it "forwards get params" do
|
302
|
+
stubs = Faraday::Adapter::Test::Stubs.new do |stub|
|
303
|
+
stub.get(file_url + '/metadata' + '?heigth=true&policy=eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJzdGF0IiwiaGFuZGxlIjoiV21GeEIyYVNlMjBTR1Qya3pTc3IifQ%3D%3D&signature=d70d11f59750903c628f4e35ecc15ef504d71b1ed104c653fe57b2231a7d667c&width=true') do
|
304
|
+
[200, {}, '{"width": 100, "height": 100}']
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
stubbed_connection = Faraday.new do |builder|
|
309
|
+
builder.adapter :test, stubs
|
310
|
+
end
|
311
|
+
|
312
|
+
subject.stub(:http_connection).and_return stubbed_connection
|
313
|
+
|
314
|
+
response = subject.stat file_url, {width: true, heigth: true}, expiry: 1394363896
|
315
|
+
|
316
|
+
stubs.verify_stubbed_calls
|
317
|
+
expect(response['width']).to eq 100
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "#convert_url" do
|
323
|
+
let(:handle) { 'PHqJHHWpRAGUsIfyx0og' }
|
324
|
+
let(:url) { "https://www.filepicker.io/api/file/#{handle}" }
|
325
|
+
|
326
|
+
context "without secret" do
|
327
|
+
before { subject.configuration.secret = nil }
|
328
|
+
|
329
|
+
it "builds expected convert URL when given a URL" do
|
330
|
+
expect(subject.convert_url url, w: 300, h: 200).to eq 'https://www.filepicker.io/api/file/PHqJHHWpRAGUsIfyx0og/convert?h=200&w=300'
|
331
|
+
end
|
332
|
+
|
333
|
+
it "builds expected convert URL when given a handle" do
|
334
|
+
expect(subject.convert_url handle, w: 300, h: 200).to eq 'https://www.filepicker.io/api/file/PHqJHHWpRAGUsIfyx0og/convert?h=200&w=300'
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
context "with secret" do
|
339
|
+
it "builds expected convert URL when given a URL" do
|
340
|
+
expect(subject.convert_url url, {w: 300, h: 200}, expiry: 1394363896).to eq 'https://www.filepicker.io/api/file/PHqJHHWpRAGUsIfyx0og/convert?h=200&policy=eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJjb252ZXJ0IiwiaGFuZGxlIjoiUEhxSkhIV3BSQUdVc0lmeXgwb2cifQ%3D%3D&signature=b370d4ae604c7917c169fe5b10a6274683bb82056c7b80993a7601d486b89d22&w=300'
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
describe "#retrieve_url" do
|
346
|
+
let(:handle) { 'PHqJHHWpRAGUsIfyx0og' }
|
347
|
+
let(:url) { "https://www.filepicker.io/api/file/#{handle}" }
|
348
|
+
|
349
|
+
context "without secret" do
|
350
|
+
before { subject.configuration.secret = nil }
|
351
|
+
|
352
|
+
it "builds expected retrieve URL when given a URL" do
|
353
|
+
expect(subject.retrieve_url url).to eq 'https://www.filepicker.io/api/file/PHqJHHWpRAGUsIfyx0og'
|
354
|
+
end
|
355
|
+
|
356
|
+
it "builds expected retrieve URL when given a handle" do
|
357
|
+
expect(subject.retrieve_url handle).to eq 'https://www.filepicker.io/api/file/PHqJHHWpRAGUsIfyx0og'
|
358
|
+
end
|
359
|
+
|
360
|
+
it "can include params like cache set to true" do
|
361
|
+
expect(subject.retrieve_url handle, cache: true).to eq 'https://www.filepicker.io/api/file/PHqJHHWpRAGUsIfyx0og?cache=true'
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
context "with secret" do
|
366
|
+
it "builds expected retrieve URL when given a URL" do
|
367
|
+
expect(subject.retrieve_url url, {}, expiry: 1394363896).to eq 'https://www.filepicker.io/api/file/PHqJHHWpRAGUsIfyx0og?policy=eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJyZWFkIiwiaGFuZGxlIjoiUEhxSkhIV3BSQUdVc0lmeXgwb2cifQ%3D%3D&signature=6bba22df7390a44a13329d2f2ca8317c48317fe6612b21f957670969a074f778'
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
|
373
|
+
|
374
|
+
describe "#configuration" do
|
375
|
+
it "has key set" do
|
376
|
+
expect(subject.configuration.key).to eq 'key'
|
377
|
+
end
|
378
|
+
|
379
|
+
it "has secret set" do
|
380
|
+
expect(subject.configuration.secret).to eq '6U5CWAU57NAHDC2ICXQKMXYZ4Q'
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
describe "#policy" do
|
385
|
+
let(:policy_attributes) { {call: 'read'} }
|
386
|
+
let(:policy) { double }
|
387
|
+
|
388
|
+
describe "expiry" do
|
389
|
+
context "is given" do
|
390
|
+
it "uses given value" do
|
391
|
+
InkFilePicker::Policy.should_receive(:new).with(hash_including(call: 'read', expiry: 60)).and_return policy
|
392
|
+
|
393
|
+
expect(subject.policy policy_attributes.merge(expiry: 60)).to eq policy
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
context "not given" do
|
398
|
+
before { Time.stub_chain(:now, :to_i).and_return 1 }
|
399
|
+
|
400
|
+
it "uses default_expiry from config" do
|
401
|
+
subject.configuration.stub(:default_expiry).and_return 600
|
402
|
+
|
403
|
+
InkFilePicker::Policy.should_receive(:new).with(hash_including(call: 'read', expiry: 601)).and_return policy
|
404
|
+
|
405
|
+
expect(subject.policy policy_attributes).to eq policy
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe InkFilePicker::Configuration do
|
4
|
+
let(:attributes) do
|
5
|
+
{
|
6
|
+
key: 'key',
|
7
|
+
secret: 'secret'
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { described_class.new attributes }
|
12
|
+
|
13
|
+
its(:key) { should eq 'key' }
|
14
|
+
its(:secret) { should eq 'secret' }
|
15
|
+
its(:default_expiry) { should eq 600 }
|
16
|
+
its(:cdn_url) { should eq 'https://www.filepicker.io/api/file/' }
|
17
|
+
|
18
|
+
describe "#initialize" do
|
19
|
+
it "fails when no key is given" do
|
20
|
+
expect { described_class.new }.to raise_error ArgumentError
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe InkFilePicker::FileHandle do
|
4
|
+
let(:cdn_url) { 'https://www.filepicker.io/api/file/' }
|
5
|
+
let(:handle) { 'PHqJHHWpRAGUsIfyx0og' }
|
6
|
+
let(:url) { "https://www.filepicker.io/api/file/#{handle}" }
|
7
|
+
|
8
|
+
|
9
|
+
describe "#url" do
|
10
|
+
it "url passes through if the cdn url is the same as given URL" do
|
11
|
+
expect(described_class.new(url, cdn_url).url).to eq url
|
12
|
+
end
|
13
|
+
|
14
|
+
it "builds a file URL given only a file handle" do
|
15
|
+
expect(described_class.new(handle, cdn_url).url).to eq url
|
16
|
+
end
|
17
|
+
|
18
|
+
it "ensures that we use CDN" do
|
19
|
+
expect(described_class.new(url, 'http://cdn.com/').url).to eq "http://cdn.com/#{handle}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "handle" do
|
24
|
+
it "returns expected handle from URL" do
|
25
|
+
expect(described_class.new(url, cdn_url).handle).to eq handle
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe InkFilePicker::Policy do
|
4
|
+
let(:secret) { '6U5CWAU57NAHDC2ICXQKMXYZ4Q' }
|
5
|
+
|
6
|
+
subject do
|
7
|
+
described_class.new(
|
8
|
+
secret: secret,
|
9
|
+
call: 'read',
|
10
|
+
expiry: 1394363896
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
its(:policy) { should eq 'eyJleHBpcnkiOjEzOTQzNjM4OTYsImNhbGwiOiJyZWFkIn0=' }
|
15
|
+
its(:signature) { should eq '4c50ca71d9e123274a01eb00a7facd52069e07c2e9312517f55bf1b94447792e' }
|
16
|
+
|
17
|
+
describe "#to_hash" do
|
18
|
+
it "contains policy and signature when secret is given" do
|
19
|
+
expect(subject.to_hash).to eq({
|
20
|
+
policy: subject.policy,
|
21
|
+
signature: subject.signature
|
22
|
+
})
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns an empty hash when no secret is given" do
|
26
|
+
subject.secret = nil
|
27
|
+
expect(subject.to_hash).to eq({})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe InkFilePicker do
|
4
|
+
describe ".client" do
|
5
|
+
it "takes given arguments and initializes a client" do
|
6
|
+
client = double
|
7
|
+
attributes = {some: 'attributes'}
|
8
|
+
|
9
|
+
InkFilePicker::Client.should_receive(:new).with(attributes).and_return client
|
10
|
+
|
11
|
+
expect(described_class.client(attributes)).to eq client
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ink_file_picker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thorbjørn Hermansen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.2.14
|
20
|
+
- - <
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.14
|
30
|
+
- - <
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: faraday
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ~>
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.9.0
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.9.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: bundler
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.5'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '1.5'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rake
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rspec
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ~>
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 2.14.1
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ~>
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 2.14.1
|
89
|
+
description:
|
90
|
+
email:
|
91
|
+
- thhermansen@gmail.com
|
92
|
+
executables: []
|
93
|
+
extensions: []
|
94
|
+
extra_rdoc_files: []
|
95
|
+
files:
|
96
|
+
- .gitignore
|
97
|
+
- Gemfile
|
98
|
+
- LICENSE.txt
|
99
|
+
- README.md
|
100
|
+
- Rakefile
|
101
|
+
- ink_file_picker.gemspec
|
102
|
+
- lib/ink_file_picker.rb
|
103
|
+
- lib/ink_file_picker/assignable.rb
|
104
|
+
- lib/ink_file_picker/client.rb
|
105
|
+
- lib/ink_file_picker/configuration.rb
|
106
|
+
- lib/ink_file_picker/errors.rb
|
107
|
+
- lib/ink_file_picker/file_handle.rb
|
108
|
+
- lib/ink_file_picker/policy.rb
|
109
|
+
- lib/ink_file_picker/response.rb
|
110
|
+
- lib/ink_file_picker/url_builder.rb
|
111
|
+
- lib/ink_file_picker/version.rb
|
112
|
+
- spec/fixtures/skalar.png
|
113
|
+
- spec/ink_file_picker/client_spec.rb
|
114
|
+
- spec/ink_file_picker/configuration_spec.rb
|
115
|
+
- spec/ink_file_picker/file_handle_spec.rb
|
116
|
+
- spec/ink_file_picker/policy_spec.rb
|
117
|
+
- spec/ink_file_picker_spec.rb
|
118
|
+
- spec/spec_helper.rb
|
119
|
+
homepage: ''
|
120
|
+
licenses:
|
121
|
+
- MIT
|
122
|
+
metadata: {}
|
123
|
+
post_install_message:
|
124
|
+
rdoc_options: []
|
125
|
+
require_paths:
|
126
|
+
- lib
|
127
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
requirements: []
|
138
|
+
rubyforge_project:
|
139
|
+
rubygems_version: 2.0.0
|
140
|
+
signing_key:
|
141
|
+
specification_version: 4
|
142
|
+
summary: Client for Ink File Picker
|
143
|
+
test_files:
|
144
|
+
- spec/fixtures/skalar.png
|
145
|
+
- spec/ink_file_picker/client_spec.rb
|
146
|
+
- spec/ink_file_picker/configuration_spec.rb
|
147
|
+
- spec/ink_file_picker/file_handle_spec.rb
|
148
|
+
- spec/ink_file_picker/policy_spec.rb
|
149
|
+
- spec/ink_file_picker_spec.rb
|
150
|
+
- spec/spec_helper.rb
|