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.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -1
  3. data/.rspec +1 -0
  4. data/.travis.yml +19 -5
  5. data/CHANGELOG.md +12 -30
  6. data/README.md +149 -72
  7. data/Rakefile +1 -1
  8. data/UPGRADE_NOTES.md +36 -0
  9. data/lib/uploadcare.rb +16 -22
  10. data/lib/uploadcare/api.rb +3 -1
  11. data/lib/uploadcare/api/file_list_api.rb +15 -4
  12. data/lib/uploadcare/api/file_storage_api.rb +34 -0
  13. data/lib/uploadcare/api/group_list_api.rb +13 -4
  14. data/lib/uploadcare/api/raw_api.rb +10 -16
  15. data/lib/uploadcare/api/uploading_api.rb +45 -84
  16. data/lib/uploadcare/api/uploading_api/upload_params.rb +72 -0
  17. data/lib/uploadcare/api/validators/file_list_options_validator.rb +73 -0
  18. data/lib/uploadcare/api/validators/group_list_options_validator.rb +49 -0
  19. data/lib/uploadcare/resources/file_list.rb +6 -33
  20. data/lib/uploadcare/resources/group_list.rb +6 -23
  21. data/lib/uploadcare/resources/resource_list.rb +83 -0
  22. data/lib/uploadcare/rest/connections/api_connection.rb +25 -3
  23. data/lib/uploadcare/rest/connections/upload_connection.rb +3 -2
  24. data/lib/uploadcare/version.rb +1 -1
  25. data/spec/api/file_list_api_spec.rb +95 -0
  26. data/spec/api/file_storage_api_spec.rb +88 -0
  27. data/spec/api/group_list_api_spec.rb +59 -0
  28. data/spec/api/raw_api_spec.rb +12 -12
  29. data/spec/api/uploading_api/upload_params_spec.rb +99 -0
  30. data/spec/api/uploading_api_spec.rb +59 -0
  31. data/spec/resources/file_list_spec.rb +13 -52
  32. data/spec/resources/file_spec.rb +6 -3
  33. data/spec/resources/group_list_spec.rb +15 -20
  34. data/spec/rest/api_connection_spec.rb +1 -1
  35. data/spec/shared/resource_list.rb +188 -0
  36. data/spec/spec_helper.rb +11 -1
  37. data/spec/uploadcare_spec.rb +9 -32
  38. data/spec/utils/parser_spec.rb +34 -36
  39. data/uploadcare-ruby.gemspec +7 -6
  40. metadata +52 -37
  41. data/lib/uploadcare/utils/user_agent.rb +0 -44
  42. data/spec/uploading/uploading_multiple_spec.rb +0 -43
  43. data/spec/uploading/uploading_spec.rb +0 -40
  44. data/spec/utils/user_agent_spec.rb +0 -46
@@ -2,36 +2,30 @@ require 'faraday'
2
2
  require 'json'
3
3
  require 'ostruct'
4
4
 
5
- require 'uploadcare/api'
6
- require 'uploadcare/version'
5
+ require_relative 'uploadcare/api'
6
+ require_relative 'uploadcare/version'
7
7
 
8
8
  module Uploadcare
9
9
  DEFAULT_SETTINGS = {
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.3',
16
- cache_files: true,
17
- auth_scheme: :secure
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
- warn '[DEPRECATION] `Uploadcare::user_agent` method is deprecated and will be removed in version 3.0'
26
- UserAgent.new.call(options)
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
@@ -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
- def file_list page=1
4
- data = get '/files/', {page: page}
5
- list = Uploadcare::Api::FileList.new self, data
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
- def group_list from=nil, limit=nil
4
- data = get '/groups/', {from: from, limit: limit}.reject{|_,v| v.nil?}
5
- list = Uploadcare::Api::GroupList.new self, data
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
- # basic request method
14
- def request method = :get, path = "/files/", params = {}
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 path= "/files/", params={}
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 path= "/files/", params={}
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 path= "/files/", params={}
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 path= "/files/", params={}
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
- require "uri"
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 url uploading
7
- def upload object
8
- # if object is file - uploading it as file
9
- if object.kind_of?(File)
10
- upload_file(object)
11
-
12
- # if a string - try to upload as url
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.new "you should give File object, array of files or valid url string"
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
- def upload_files files
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
- files.each_with_index do |file, i|
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
- # upload file to servise
43
- def upload_file file
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
- #upload from url
61
- def upload_url url
62
- uri = URI.parse(url)
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
- raise ArgumentError.new(response['error']) if response['status'] == 'error'
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
- def get_token url
100
- response = @upload_connection.send :post, '/from_url/', { source_url: url, pub_key: @options[:public_key] }
101
- token = response.body["token"]
102
- end
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
- def extract_mime_type file
106
- types = MIME::Types.of(file.path)
107
- types[0].content_type
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