uploadcare-ruby 1.2.2 → 2.0.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 +5 -5
- data/.gitignore +1 -1
- data/.rspec +1 -0
- data/.travis.yml +19 -5
- data/CHANGELOG.md +12 -30
- data/README.md +149 -72
- data/Rakefile +1 -1
- data/UPGRADE_NOTES.md +36 -0
- data/lib/uploadcare.rb +16 -22
- data/lib/uploadcare/api.rb +3 -1
- data/lib/uploadcare/api/file_list_api.rb +15 -4
- data/lib/uploadcare/api/file_storage_api.rb +34 -0
- data/lib/uploadcare/api/group_list_api.rb +13 -4
- data/lib/uploadcare/api/raw_api.rb +10 -16
- data/lib/uploadcare/api/uploading_api.rb +45 -84
- data/lib/uploadcare/api/uploading_api/upload_params.rb +72 -0
- data/lib/uploadcare/api/validators/file_list_options_validator.rb +73 -0
- data/lib/uploadcare/api/validators/group_list_options_validator.rb +49 -0
- data/lib/uploadcare/resources/file_list.rb +6 -33
- data/lib/uploadcare/resources/group_list.rb +6 -23
- data/lib/uploadcare/resources/resource_list.rb +83 -0
- data/lib/uploadcare/rest/connections/api_connection.rb +25 -3
- data/lib/uploadcare/rest/connections/upload_connection.rb +3 -2
- data/lib/uploadcare/version.rb +1 -1
- data/spec/api/file_list_api_spec.rb +95 -0
- data/spec/api/file_storage_api_spec.rb +88 -0
- data/spec/api/group_list_api_spec.rb +59 -0
- data/spec/api/raw_api_spec.rb +12 -12
- data/spec/api/uploading_api/upload_params_spec.rb +99 -0
- data/spec/api/uploading_api_spec.rb +59 -0
- data/spec/resources/file_list_spec.rb +13 -52
- data/spec/resources/file_spec.rb +6 -3
- data/spec/resources/group_list_spec.rb +15 -20
- data/spec/rest/api_connection_spec.rb +1 -1
- data/spec/shared/resource_list.rb +188 -0
- data/spec/spec_helper.rb +11 -1
- data/spec/uploadcare_spec.rb +9 -32
- data/spec/utils/parser_spec.rb +34 -36
- data/uploadcare-ruby.gemspec +7 -6
- metadata +52 -37
- data/lib/uploadcare/utils/user_agent.rb +0 -44
- data/spec/uploading/uploading_multiple_spec.rb +0 -43
- data/spec/uploading/uploading_spec.rb +0 -40
- data/spec/utils/user_agent_spec.rb +0 -46
data/lib/uploadcare.rb
CHANGED
@@ -2,36 +2,30 @@ require 'faraday'
|
|
2
2
|
require 'json'
|
3
3
|
require 'ostruct'
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
require_relative 'uploadcare/api'
|
6
|
+
require_relative 'uploadcare/version'
|
7
7
|
|
8
8
|
module Uploadcare
|
9
9
|
DEFAULT_SETTINGS = {
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
10
|
+
public_key: 'demopublickey',
|
11
|
+
private_key: 'demoprivatekey',
|
12
|
+
upload_url_base: 'https://upload.uploadcare.com',
|
13
|
+
api_url_base: 'https://api.uploadcare.com',
|
14
|
+
static_url_base: 'https://ucarecdn.com',
|
15
|
+
api_version: '0.5',
|
16
|
+
cache_files: true,
|
17
|
+
autostore: :auto,
|
18
|
+
auth_scheme: :secure,
|
19
|
+
}
|
20
|
+
|
21
|
+
USER_AGENT = "uploadcare-ruby/#{Gem.ruby_version}/#{Uploadcare::VERSION}"
|
19
22
|
|
20
23
|
def self.default_settings
|
21
24
|
DEFAULT_SETTINGS
|
22
25
|
end
|
23
26
|
|
24
27
|
def self.user_agent(options={})
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.const_missing(name)
|
30
|
-
if name == :USER_AGENT
|
31
|
-
warn '[DEPRECATION] `Uploadcare::USER_AGENT` constant is deprecated and will be removed in version 3.0'
|
32
|
-
"uploadcare-ruby/#{Gem.ruby_version}/#{Uploadcare::VERSION}"
|
33
|
-
else
|
34
|
-
super
|
35
|
-
end
|
28
|
+
return options[:user_agent].to_s if options[:user_agent]
|
29
|
+
[USER_AGENT, options[:public_key]].join('/')
|
36
30
|
end
|
37
31
|
end
|
data/lib/uploadcare/api.rb
CHANGED
@@ -5,6 +5,7 @@ Dir[File.dirname(__FILE__) + '/errors/*.rb'].each {|file| require file }
|
|
5
5
|
Dir[File.dirname(__FILE__) + '/rest/middlewares/*.rb'].each {|file| require file }
|
6
6
|
Dir[File.dirname(__FILE__) + '/rest/connections/*.rb'].each {|file| require file }
|
7
7
|
Dir[File.dirname(__FILE__) + '/rest/auth/*.rb'].sort.each {|file| require file }
|
8
|
+
Dir[File.dirname(__FILE__) + '/api/validators/*.rb'].each {|file| require file }
|
8
9
|
Dir[File.dirname(__FILE__) + '/api/*.rb'].each {|file| require file }
|
9
10
|
Dir[File.dirname(__FILE__) + '/resources/*.rb'].each {|file| require file }
|
10
11
|
|
@@ -20,5 +21,6 @@ module Uploadcare
|
|
20
21
|
include Uploadcare::FileListApi
|
21
22
|
include Uploadcare::GroupApi
|
22
23
|
include Uploadcare::GroupListApi
|
24
|
+
include Uploadcare::FileStorageApi
|
23
25
|
end
|
24
|
-
end
|
26
|
+
end
|
@@ -1,8 +1,19 @@
|
|
1
1
|
module Uploadcare
|
2
2
|
module FileListApi
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# Available options:
|
4
|
+
#
|
5
|
+
# limit -- a number of objects retrieved per request. Default: 100
|
6
|
+
# ordering -- sorting order of files in a list. Default: datetime_uploaded
|
7
|
+
# from -- a starting point for filtering files.
|
8
|
+
# stored -- true to include only stored files, false to exclude.
|
9
|
+
# removed -- true to include only removed files, false to exclude. Default: false
|
10
|
+
#
|
11
|
+
# Documentation: http://uploadcare.com/documentation/rest/#file-files
|
12
|
+
def file_list options={}
|
13
|
+
Validators::FileListOptionsValidator.new(options).validate
|
14
|
+
|
15
|
+
data = get '/files/', options
|
16
|
+
Uploadcare::Api::FileList.new self, data, options
|
6
17
|
end
|
7
18
|
end
|
8
|
-
end
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Uploadcare
|
2
|
+
module FileStorageApi
|
3
|
+
MAX_BATCH_SIZE = 100
|
4
|
+
UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
|
5
|
+
|
6
|
+
def store_files(objects)
|
7
|
+
if objects.size > MAX_BATCH_SIZE
|
8
|
+
raise ArgumentError, "Up to #{MAX_BATCH_SIZE} files are supported per request, #{objects.size} given"
|
9
|
+
end
|
10
|
+
|
11
|
+
put "/files/storage/", to_uuids(objects)
|
12
|
+
end
|
13
|
+
|
14
|
+
def delete_files(objects)
|
15
|
+
if objects.size > MAX_BATCH_SIZE
|
16
|
+
raise ArgumentError, "Up to #{MAX_BATCH_SIZE} files are supported per request, #{objects.size} given"
|
17
|
+
end
|
18
|
+
|
19
|
+
delete "/files/storage/", to_uuids(objects)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def to_uuids(objects)
|
25
|
+
objects.map do |object|
|
26
|
+
case object
|
27
|
+
when Uploadcare::Api::File then object.uuid
|
28
|
+
when UUID_REGEX then object
|
29
|
+
else raise(ArgumentError, "Unable to convert object to uuid: #{object}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,8 +1,17 @@
|
|
1
1
|
module Uploadcare
|
2
2
|
module GroupListApi
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# Available options:
|
4
|
+
#
|
5
|
+
# limit -- a number of objects retrieved per request. Default: 100
|
6
|
+
# ordering -- sorting order of groups in a list. Default: datetime_creataed
|
7
|
+
# from -- a starting point for filtering groups.
|
8
|
+
#
|
9
|
+
# Documentation: http://uploadcare.com/documentation/rest/#group-groups
|
10
|
+
def group_list options={}
|
11
|
+
Validators::GroupListOptionsValidator.new(options).validate
|
12
|
+
|
13
|
+
data = get '/groups/', options
|
14
|
+
list = Uploadcare::Api::GroupList.new self, data, options
|
6
15
|
end
|
7
16
|
end
|
8
|
-
end
|
17
|
+
end
|
@@ -2,43 +2,37 @@ require 'json'
|
|
2
2
|
|
3
3
|
module Uploadcare
|
4
4
|
module RawApi
|
5
|
-
|
6
|
-
def initialize options={}
|
5
|
+
def initialize(options = {})
|
7
6
|
@options = Uploadcare::default_settings.merge(options)
|
8
7
|
@api_connection = Uploadcare::Connections::ApiConnection.new(@options)
|
9
8
|
@upload_connection = Uploadcare::Connections::UploadConnection.new(@options)
|
10
9
|
end
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
response = @api_connection.send method, path, params
|
11
|
+
# basic request method
|
12
|
+
def request(method = :get, path = '/files/', params = {})
|
13
|
+
response = @api_connection.send method, path, params
|
16
14
|
response.body
|
17
15
|
end
|
18
16
|
alias_method :api_request, :request
|
19
17
|
|
20
|
-
|
21
18
|
# request with GET verb
|
22
|
-
def get
|
19
|
+
def get(path = '/files/', params = {})
|
23
20
|
request :get, path, params
|
24
21
|
end
|
25
22
|
|
26
|
-
|
27
23
|
# request with POST verb
|
28
|
-
def post
|
29
|
-
request :post, path, params
|
24
|
+
def post(path = '/files/', params = {})
|
25
|
+
request :post, path, params
|
30
26
|
end
|
31
27
|
|
32
|
-
|
33
28
|
# request with PUT verb
|
34
|
-
def put
|
29
|
+
def put(path = '/files/', params = {})
|
35
30
|
request :put, path, params
|
36
31
|
end
|
37
32
|
|
38
|
-
|
39
33
|
# request with DELETE verb
|
40
|
-
def delete
|
34
|
+
def delete(path = '/files/', params = {})
|
41
35
|
request :delete, path, params
|
42
36
|
end
|
43
37
|
end
|
44
|
-
end
|
38
|
+
end
|
@@ -1,110 +1,71 @@
|
|
1
|
-
|
2
|
-
require 'mime/types'
|
1
|
+
require_relative 'uploading_api/upload_params'
|
3
2
|
|
4
3
|
module Uploadcare
|
5
4
|
module UploadingApi
|
6
|
-
# intelegent guess for file or
|
7
|
-
def upload
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
elsif object.kind_of?(String)
|
14
|
-
upload_url(object)
|
15
|
-
|
16
|
-
# array of files
|
17
|
-
elsif object.kind_of?(Array)
|
18
|
-
upload_files(object)
|
19
|
-
|
5
|
+
# intelegent guess for file or URL uploading
|
6
|
+
def upload(object, options = {})
|
7
|
+
case object
|
8
|
+
when File then upload_file(object, options)
|
9
|
+
when Array then upload_files(object, options)
|
10
|
+
# if object is a string, try to upload it as an URL
|
11
|
+
when String then upload_url(object, options)
|
20
12
|
else
|
21
|
-
raise ArgumentError
|
13
|
+
raise ArgumentError, "Expected `object` to be an Uploadcare::Api::File, "\
|
14
|
+
"an Array or a valid URL string, received: `#{object}`"
|
22
15
|
end
|
23
16
|
end
|
24
17
|
|
18
|
+
# Upload multiple files
|
19
|
+
def upload_files(files, options = {})
|
20
|
+
data = upload_params(options).for_file_upload(files)
|
25
21
|
|
26
|
-
|
27
|
-
raise ArgumentError.new "one or more of given files is not actually files" if files.select {|f| !f.kind_of?(File)}.any?
|
28
|
-
|
29
|
-
data = {UPLOADCARE_PUB_KEY: @options[:public_key]}
|
22
|
+
response = @upload_connection.post('/base/', data)
|
30
23
|
|
31
|
-
|
32
|
-
data["file[#{i}]"] = build_upload_io(file)
|
33
|
-
end
|
34
|
-
|
35
|
-
response = @upload_connection.send :post, '/base/', data
|
36
|
-
uuids = response.body
|
37
|
-
|
38
|
-
files = uuids.values.map! {|f| Uploadcare::Api::File.new self, f }
|
24
|
+
response.body.values.map! { |f| Uploadcare::Api::File.new(self, f) }
|
39
25
|
end
|
40
26
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
raise ArgumentError.new 'expecting File object' unless file.kind_of?(File)
|
45
|
-
|
46
|
-
response = @upload_connection.send :post, '/base/', {
|
47
|
-
UPLOADCARE_PUB_KEY: @options[:public_key],
|
48
|
-
file: build_upload_io(file)
|
49
|
-
}
|
50
|
-
|
51
|
-
uuid = response.body["file"]
|
52
|
-
|
53
|
-
Uploadcare::Api::File.new self, uuid
|
27
|
+
# Upload single file
|
28
|
+
def upload_file(file, options = {})
|
29
|
+
upload_files([file], options).first
|
54
30
|
end
|
55
|
-
|
56
|
-
# create file is the same as uplaod file
|
57
31
|
alias_method :create_file, :upload_file
|
58
32
|
|
33
|
+
# Upload from an URL
|
34
|
+
def upload_url(url, options = {})
|
35
|
+
params = upload_params(options).for_url_upload(url)
|
36
|
+
token = request_file_upload(params)
|
59
37
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
raise ArgumentError.new 'invalid url was given' unless uri.kind_of?(URI::HTTP)
|
65
|
-
|
66
|
-
token = get_token(url)
|
67
|
-
|
68
|
-
while !['success', 'error'].include?((response = get_status_response(token))['status'])
|
69
|
-
sleep 0.5
|
38
|
+
upload_status = poll_upload_result(token)
|
39
|
+
if upload_status['status'] == 'error'
|
40
|
+
raise ArgumentError.new(upload_status['error'])
|
70
41
|
end
|
71
|
-
|
72
|
-
|
73
|
-
uuid = response['file_id']
|
74
|
-
Uploadcare::Api::File.new self, uuid
|
42
|
+
|
43
|
+
Uploadcare::Api::File.new(self, upload_status['file_id'])
|
75
44
|
end
|
76
45
|
alias_method :upload_from_url, :upload_url
|
77
46
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
protected
|
82
|
-
# DEPRECATRED but still works
|
83
|
-
def upload_request method, path, params = {}
|
84
|
-
response = @upload_connection.send method, path, params
|
85
|
-
end
|
86
|
-
|
87
|
-
def build_upload_io file
|
88
|
-
Faraday::UploadIO.new file.path, extract_mime_type(file)
|
89
|
-
end
|
90
|
-
|
91
|
-
|
92
47
|
private
|
93
|
-
def get_status_response token
|
94
|
-
response = @upload_connection.send :post, '/from_url/status/', {token: token}
|
95
|
-
response.body
|
96
|
-
end
|
97
|
-
|
98
48
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
49
|
+
def get_status_response(token)
|
50
|
+
response = @upload_connection.post('/from_url/status/', {token: token})
|
51
|
+
response.body
|
52
|
+
end
|
103
53
|
|
54
|
+
def request_file_upload(upload_params)
|
55
|
+
response = @upload_connection.post('/from_url/', upload_params)
|
56
|
+
token = response.body['token']
|
57
|
+
end
|
104
58
|
|
105
|
-
|
106
|
-
|
107
|
-
|
59
|
+
def poll_upload_result(token)
|
60
|
+
while true
|
61
|
+
response = get_status_response(token)
|
62
|
+
break(response) if ['success', 'error'].include?(response['status'])
|
63
|
+
sleep 0.5
|
108
64
|
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def upload_params(request_options)
|
68
|
+
UploadParams.new(@options, request_options)
|
69
|
+
end
|
109
70
|
end
|
110
71
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'mime/types'
|
3
|
+
|
4
|
+
module Uploadcare
|
5
|
+
module UploadingApi
|
6
|
+
class UploadParams
|
7
|
+
def initialize(global_options, request_options)
|
8
|
+
@global_options = global_options
|
9
|
+
@request_options = request_options
|
10
|
+
end
|
11
|
+
|
12
|
+
def for_url_upload(url)
|
13
|
+
{
|
14
|
+
source_url: parse_url(url),
|
15
|
+
pub_key: public_key,
|
16
|
+
store: store
|
17
|
+
}.reject { |k, v| v.nil? }
|
18
|
+
end
|
19
|
+
|
20
|
+
def for_file_upload(files)
|
21
|
+
{
|
22
|
+
UPLOADCARE_PUB_KEY: public_key,
|
23
|
+
UPLOADCARE_STORE: store
|
24
|
+
}.reject { |k, v| v.nil? }.merge(file_params(files))
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :global_options, :request_options
|
30
|
+
|
31
|
+
def public_key
|
32
|
+
global_options[:public_key]
|
33
|
+
end
|
34
|
+
|
35
|
+
def store
|
36
|
+
mapping = { true => 1, false => 0, auto: 'auto' }
|
37
|
+
|
38
|
+
global_value = global_options[:autostore]
|
39
|
+
per_request_value = request_options[:store]
|
40
|
+
|
41
|
+
mapping[per_request_value] || mapping[global_value]
|
42
|
+
end
|
43
|
+
|
44
|
+
def file_params(files)
|
45
|
+
Hash[files.map.with_index { |file, i| ["file[#{i}]", build_upload_io(file)] }]
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_url(url)
|
49
|
+
uri = URI.parse(url)
|
50
|
+
|
51
|
+
unless uri.is_a?(URI::HTTP) # will also be true for https
|
52
|
+
raise ArgumentError, 'invalid url was given'
|
53
|
+
end
|
54
|
+
|
55
|
+
uri
|
56
|
+
end
|
57
|
+
|
58
|
+
def build_upload_io(file)
|
59
|
+
unless file.is_a?(File)
|
60
|
+
raise ArgumentError, "expected File object, #{file} given"
|
61
|
+
end
|
62
|
+
|
63
|
+
Faraday::UploadIO.new file.path, extract_mime_type(file)
|
64
|
+
end
|
65
|
+
|
66
|
+
def extract_mime_type file
|
67
|
+
types = MIME::Types.of(file.path)
|
68
|
+
types[0].content_type
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Uploadcare
|
2
|
+
module Validators
|
3
|
+
|
4
|
+
class FileListOptionsValidator
|
5
|
+
SUPPORTED_KEYS = [:from, :ordering, :limit, :stored, :removed]
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate
|
12
|
+
check_for_unsupported_keys(@options)
|
13
|
+
|
14
|
+
validate_limit(@options[:limit])
|
15
|
+
validate_stored(@options[:stored])
|
16
|
+
validate_removed(@options[:removed])
|
17
|
+
validate_ordering_and_from(@options[:ordering], @options[:from])
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def check_for_unsupported_keys(options)
|
23
|
+
unsupported_keys = options.keys.reject{|k,_| SUPPORTED_KEYS.include?(k)}
|
24
|
+
error("Unknown options: #{unsupported_keys}") if unsupported_keys.any?
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate_ordering_and_from(ordering, from)
|
28
|
+
case ordering
|
29
|
+
when nil, /^-?datetime_uploaded$/
|
30
|
+
validate_from_as_date(from)
|
31
|
+
when /^-?size$/
|
32
|
+
validate_from_as_size(from)
|
33
|
+
else
|
34
|
+
error("Unknown value for :ordering option: #{ordering.inspect}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate_from_as_date(from)
|
39
|
+
return if from.nil? || from.to_s =~ /^\d{4}-\d{2}-\d{2}T\d{2}.*/
|
40
|
+
error(":from value should be a DateTime or an iso8601 string when "\
|
41
|
+
"ordering is `datetime_uploaded` or `-datetime_uploaded`, "\
|
42
|
+
"#{from.inspect} given")
|
43
|
+
end
|
44
|
+
|
45
|
+
def validate_from_as_size(from)
|
46
|
+
return if from.nil? || (from.is_a?(Integer) && from >= 0)
|
47
|
+
error(":from value should be a positive integer when ordering is "\
|
48
|
+
"`size` or `-size`, #{from.inspect} given")
|
49
|
+
end
|
50
|
+
|
51
|
+
def validate_limit(limit)
|
52
|
+
return if limit.nil? || (limit.is_a?(Integer) && (1..1000).include?(limit))
|
53
|
+
error(":limit should be a positive integer from 1 to 1000, "\
|
54
|
+
"#{limit.inspect} given")
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_stored(stored)
|
58
|
+
return if [nil, true, false].include?(stored)
|
59
|
+
error(":stored can be true or false, #{stored.inspect} given")
|
60
|
+
end
|
61
|
+
|
62
|
+
def validate_removed(removed)
|
63
|
+
return if [nil, true, false].include?(removed)
|
64
|
+
error(":removed can be true or false, #{removed.inspect} given")
|
65
|
+
end
|
66
|
+
|
67
|
+
def error(message)
|
68
|
+
raise ArgumentError, message
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|