uploadcare-ruby 2.1.1 → 3.1.0.pre.rc1

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 (116) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/gem-push.yml +20 -0
  3. data/.github/workflows/ruby.yml +52 -0
  4. data/.gitignore +13 -6
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +32 -0
  7. data/.yardopts +4 -0
  8. data/CHANGELOG.md +33 -34
  9. data/DEVELOPMENT.md +18 -0
  10. data/Gemfile +2 -0
  11. data/LICENSE +1 -1
  12. data/README.md +369 -546
  13. data/Rakefile +5 -5
  14. data/bin/console +15 -0
  15. data/bin/setup +8 -0
  16. data/lib/uploadcare.rb +36 -26
  17. data/lib/uploadcare/api/api.rb +25 -0
  18. data/lib/uploadcare/client/conversion/base_conversion_client.rb +54 -0
  19. data/lib/uploadcare/client/conversion/document_conversion_client.rb +38 -0
  20. data/lib/uploadcare/client/conversion/video_conversion_client.rb +42 -0
  21. data/lib/uploadcare/client/file_client.rb +44 -0
  22. data/lib/uploadcare/client/file_list_client.rb +46 -0
  23. data/lib/uploadcare/client/group_client.rb +45 -0
  24. data/lib/uploadcare/client/multipart_upload/chunks_client.rb +48 -0
  25. data/lib/uploadcare/client/multipart_upload_client.rb +67 -0
  26. data/lib/uploadcare/client/project_client.rb +18 -0
  27. data/lib/uploadcare/client/rest_client.rb +74 -0
  28. data/lib/uploadcare/client/rest_group_client.rb +23 -0
  29. data/lib/uploadcare/client/upload_client.rb +36 -0
  30. data/lib/uploadcare/client/uploader_client.rb +109 -0
  31. data/lib/uploadcare/client/webhook_client.rb +47 -0
  32. data/lib/uploadcare/concern/error_handler.rb +54 -0
  33. data/lib/uploadcare/concern/throttle_handler.rb +25 -0
  34. data/lib/uploadcare/concern/upload_error_handler.rb +32 -0
  35. data/lib/uploadcare/entity/decorator/paginator.rb +79 -0
  36. data/lib/uploadcare/entity/document_converter.rb +26 -0
  37. data/lib/uploadcare/entity/entity.rb +18 -0
  38. data/lib/uploadcare/entity/file.rb +81 -0
  39. data/lib/uploadcare/entity/file_list.rb +31 -0
  40. data/lib/uploadcare/entity/group.rb +40 -0
  41. data/lib/uploadcare/entity/group_list.rb +24 -0
  42. data/lib/uploadcare/entity/project.rb +13 -0
  43. data/lib/uploadcare/entity/uploader.rb +75 -0
  44. data/lib/uploadcare/entity/video_converter.rb +26 -0
  45. data/lib/uploadcare/entity/webhook.rb +14 -0
  46. data/lib/uploadcare/exception/conversion_error.rb +8 -0
  47. data/lib/uploadcare/exception/request_error.rb +9 -0
  48. data/lib/uploadcare/exception/throttle_error.rb +16 -0
  49. data/lib/uploadcare/param/authentication_header.rb +25 -0
  50. data/lib/uploadcare/param/conversion/document/processing_job_url_builder.rb +39 -0
  51. data/lib/uploadcare/param/conversion/video/processing_job_url_builder.rb +64 -0
  52. data/lib/uploadcare/param/param.rb +10 -0
  53. data/lib/uploadcare/param/secure_auth_header.rb +37 -0
  54. data/lib/uploadcare/param/simple_auth_header.rb +14 -0
  55. data/lib/uploadcare/param/upload/signature_generator.rb +24 -0
  56. data/lib/uploadcare/param/upload/upload_params_generator.rb +23 -0
  57. data/lib/uploadcare/param/user_agent.rb +21 -0
  58. data/lib/uploadcare/ruby/version.rb +5 -0
  59. data/uploadcare-ruby.gemspec +50 -37
  60. metadata +109 -115
  61. data/.travis.yml +0 -26
  62. data/UPGRADE_NOTES.md +0 -36
  63. data/lib/uploadcare/api.rb +0 -26
  64. data/lib/uploadcare/api/file_api.rb +0 -7
  65. data/lib/uploadcare/api/file_list_api.rb +0 -19
  66. data/lib/uploadcare/api/file_storage_api.rb +0 -34
  67. data/lib/uploadcare/api/group_api.rb +0 -38
  68. data/lib/uploadcare/api/group_list_api.rb +0 -17
  69. data/lib/uploadcare/api/project_api.rb +0 -9
  70. data/lib/uploadcare/api/raw_api.rb +0 -38
  71. data/lib/uploadcare/api/uploading_api.rb +0 -71
  72. data/lib/uploadcare/api/uploading_api/upload_params.rb +0 -72
  73. data/lib/uploadcare/api/validators/file_list_options_validator.rb +0 -73
  74. data/lib/uploadcare/api/validators/group_list_options_validator.rb +0 -49
  75. data/lib/uploadcare/errors/errors.rb +0 -64
  76. data/lib/uploadcare/resources/file.rb +0 -164
  77. data/lib/uploadcare/resources/file_list.rb +0 -14
  78. data/lib/uploadcare/resources/group.rb +0 -115
  79. data/lib/uploadcare/resources/group_list.rb +0 -14
  80. data/lib/uploadcare/resources/project.rb +0 -13
  81. data/lib/uploadcare/resources/resource_list.rb +0 -83
  82. data/lib/uploadcare/rest/auth/auth.rb +0 -31
  83. data/lib/uploadcare/rest/auth/secure.rb +0 -43
  84. data/lib/uploadcare/rest/auth/simple.rb +0 -16
  85. data/lib/uploadcare/rest/connections/api_connection.rb +0 -53
  86. data/lib/uploadcare/rest/connections/upload_connection.rb +0 -22
  87. data/lib/uploadcare/rest/middlewares/auth_middleware.rb +0 -24
  88. data/lib/uploadcare/rest/middlewares/parse_json_middleware.rb +0 -33
  89. data/lib/uploadcare/rest/middlewares/raise_error_middleware.rb +0 -21
  90. data/lib/uploadcare/utils/parser.rb +0 -71
  91. data/lib/uploadcare/utils/user_agent.rb +0 -44
  92. data/lib/uploadcare/version.rb +0 -3
  93. data/spec/api/file_list_api_spec.rb +0 -95
  94. data/spec/api/file_storage_api_spec.rb +0 -88
  95. data/spec/api/group_list_api_spec.rb +0 -59
  96. data/spec/api/raw_api_spec.rb +0 -25
  97. data/spec/api/uploading_api/upload_params_spec.rb +0 -99
  98. data/spec/api/uploading_api_spec.rb +0 -59
  99. data/spec/resources/file_list_spec.rb +0 -25
  100. data/spec/resources/file_spec.rb +0 -223
  101. data/spec/resources/group_list_spec.rb +0 -25
  102. data/spec/resources/group_spec.rb +0 -101
  103. data/spec/resources/operations_spec.rb +0 -59
  104. data/spec/resources/project_spec.rb +0 -21
  105. data/spec/rest/api_connection_spec.rb +0 -68
  106. data/spec/rest/auth/secure_spec.rb +0 -66
  107. data/spec/rest/auth/simple_spec.rb +0 -31
  108. data/spec/rest/errors_spec.rb +0 -75
  109. data/spec/rest/upload_connection_spec.rb +0 -19
  110. data/spec/shared/resource_list.rb +0 -188
  111. data/spec/spec_helper.rb +0 -54
  112. data/spec/uploadcare_spec.rb +0 -16
  113. data/spec/utils/parser_spec.rb +0 -85
  114. data/spec/utils/user_agent_spec.rb +0 -46
  115. data/spec/view.png +0 -0
  116. data/spec/view2.jpg +0 -0
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uploadcare
4
+ module Concerns
5
+ # Wrapper for responses
6
+ # raises errors instead of returning monads
7
+ module UploadErrorHandler
8
+ include Exception
9
+
10
+ # Extension of ApiStruct's failure method
11
+ #
12
+ # Raises errors instead of returning falsey objects
13
+ # @see https://github.com/rubygarage/api_struct/blob/master/lib/api_struct/client.rb#L55
14
+ def failure(response)
15
+ catch_throttling_error(response)
16
+ parsed_response = JSON.parse(response.body.to_s)
17
+ raise RequestError, parsed_response['detail']
18
+ rescue JSON::ParserError
19
+ raise RequestError, response.status
20
+ end
21
+
22
+ private
23
+
24
+ def catch_throttling_error(response)
25
+ return unless response.code == 429
26
+
27
+ retry_after = response.headers['Retry-After'].to_i + 1 || 11
28
+ raise ThrottleError.new(retry_after), "Response throttled, retry #{retry_after} seconds later"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uploadcare
4
+ module Entity
5
+ # @abstract
6
+ module Decorator
7
+ # provides pagination methods for things in Uploadcare that paginate,
8
+ # namely [FileList] and [Group]
9
+ #
10
+ # Requirements:
11
+ # - Should be Entity with Client
12
+ # - Associated Client should have `list` method that returns objects with pagination
13
+ # - Response should have :next, :previous, :total, :per_page params and :results fields
14
+ module Paginator
15
+ @entity ||= Hashie::Mash.new
16
+
17
+ # meta data of a pagination object
18
+ def meta
19
+ Hashie::Mash.new(next: @entity[:next], previous: @entity[:previous],
20
+ total: @entity[:total], per_page: @entity[:per_page])
21
+ end
22
+
23
+ # Returns new instance of current object on next page
24
+ def next_page
25
+ url = @entity[:next]
26
+ return unless url
27
+
28
+ query = URI.decode_www_form(URI(url).query).to_h
29
+ query = query.map { |k, v| [k.to_sym, v] }.to_h
30
+ self.class.list(**query)
31
+ end
32
+
33
+ # Returns new instance of current object on previous page
34
+ def previous_page
35
+ url = @entity[:previous]
36
+ return unless url
37
+
38
+ query = URI.decode_www_form(URI(url).query).to_h
39
+ query = query.map { |k, v| [k.to_sym, v] }.to_h
40
+ self.class.list(**query)
41
+ end
42
+
43
+ # Attempts to load the entire list after offset into results of current object
44
+ #
45
+ # It's possible to avoid loading objects on previous pages by offsetting them first
46
+ def load
47
+ return if @entity[:next].nil? || @entity[:results].length == @entity[:total]
48
+
49
+ np = self
50
+ until np.next.nil?
51
+ np = np.next_page
52
+ @entity[:results].concat(np.results.map(&:to_h))
53
+ end
54
+ @entity[:next] = nil
55
+ @entity[:per_page] = @entity[:total]
56
+ self
57
+ end
58
+
59
+ # iterate through pages, starting with current one
60
+ #
61
+ # @yield [Block]
62
+ def each(&block)
63
+ current_page = self
64
+ while current_page
65
+ current_page.results.each(&block)
66
+ current_page = current_page.next_page
67
+ end
68
+ end
69
+
70
+ # Load and return all objects in list
71
+ #
72
+ # @return [Array]
73
+ def all
74
+ load[:results]
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uploadcare
4
+ module Entity
5
+ # This serializer lets a user convert uploaded documents
6
+ # @see https://uploadcare.com/api-refs/rest-api/v0.6.0/#operation/documentConvert
7
+ class DocumentConverter < Entity
8
+ client_service Conversion::DocumentConversionClient
9
+ # Converts documents
10
+ #
11
+ # @param doc_params [Array] of hashes with params or [Hash]
12
+ # @option options [Boolean] :store (false) whether to store file on servers.
13
+ def self.convert(doc_params, **options)
14
+ params = doc_params.is_a?(Hash) ? [doc_params] : doc_params
15
+ Conversion::DocumentConversionClient.new.convert_many(params, **options)
16
+ end
17
+
18
+ # Returns a status of document conversion job
19
+ #
20
+ # @param token [Integer, String] token obtained from a server in convert method
21
+ def self.status(token)
22
+ Conversion::DocumentConversionClient.new.get_conversion_status(token)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem.find_files('client/**/*.rb').each { |path| require path }
4
+
5
+ module Uploadcare
6
+ # Entities represent objects existing in Uploadcare cloud
7
+ #
8
+ # Typically, Entities inherit class methods from {Client} instance methods
9
+ # @see Client
10
+ module Entity
11
+ # @abstract
12
+ class Entity < ApiStruct::Entity
13
+ include Client
14
+ end
15
+ end
16
+
17
+ include Entity
18
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uploadcare
4
+ module Entity
5
+ # This serializer returns a single file
6
+ #
7
+ # @see https://uploadcare.com/docs/api_reference/rest/handling_projects/
8
+ class File < Entity
9
+ client_service FileClient
10
+
11
+ attr_entity :datetime_removed, :datetime_stored, :datetime_uploaded, :image_info, :is_image, :is_ready,
12
+ :mime_type, :original_file_url, :original_filename, :size, :url, :uuid, :variations, :video_info,
13
+ :source, :rekognition_info
14
+
15
+ # gets file's uuid - even if it's only initialized with url
16
+ # @return [String]
17
+ def uuid
18
+ return @entity.uuid if @entity.uuid
19
+
20
+ uuid = @entity.url.gsub('https://ucarecdn.com/', '')
21
+ uuid.gsub(%r{/.*}, '')
22
+ end
23
+
24
+ # loads file metadata, if it's initialized with url or uuid
25
+ def load
26
+ initialize(File.info(uuid).entity)
27
+ end
28
+
29
+ # 'copy' method is used to copy original files or their modified versions to default storage.
30
+ #
31
+ # Source files MAY either be stored or just uploaded and MUST NOT be deleted.
32
+ #
33
+ # @param [String] source uuid or uploadcare link to file.
34
+ # @param [Hash] args
35
+ # @option args [Boolean] :store Whether to store the file
36
+ # @option args [Boolean] :strip_operations Copies file without transformations (if source has them)
37
+ # @option args [String] :target points to a target custom storage.
38
+ # @option args [Boolean] :make_public make files on custom storage available via public links.
39
+ # @option args [String] :pattern define file naming pattern for the custom storage scenario.
40
+ #
41
+ # @see https://uploadcare.com/api-refs/rest-api/v0.5.0/#operation/copyFile
42
+ def self.copy(source, **args)
43
+ response = FileClient.new.copy(source: source, **args).success[:result]
44
+ File.new(response)
45
+ end
46
+
47
+ # Copies file to current project
48
+ #
49
+ # source can be UID or full CDN link
50
+ #
51
+ # @see .copy
52
+ def self.local_copy(source, **args)
53
+ File.copy(source, **args)
54
+ end
55
+
56
+ # copy file to different project
57
+ #
58
+ # source can be UID or full CDN link
59
+ #
60
+ # @see .copy
61
+ def self.remote_copy(source, target, **args)
62
+ File.copy(source: source, target: target, **args)
63
+ end
64
+
65
+ # Instance version of #{copy}. Copies current file.
66
+ def copy(**args)
67
+ File.copy(uuid, **args)
68
+ end
69
+
70
+ # Instance version of {internal_copy}
71
+ def local_copy(**args)
72
+ File.local_copy(uuid, **args)
73
+ end
74
+
75
+ # Instance version of {external_copy}
76
+ def remote_copy(target, **args)
77
+ File.copy(uuid, target: target, **args)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uploadcare/entity/file'
4
+ require 'uploadcare/entity/decorator/paginator'
5
+ require 'api_struct'
6
+
7
+ module Uploadcare
8
+ module Entity
9
+ # This serializer returns lists of files
10
+ #
11
+ # This is a paginated list, so all pagination methods apply
12
+ # @see Uploadcare::Entity::Decorator::Paginator
13
+ class FileList < ApiStruct::Entity
14
+ include Uploadcare::Entity::Decorator::Paginator
15
+ client_service Client::FileListClient
16
+
17
+ attr_entity :next, :previous, :total, :per_page
18
+
19
+ has_entities :results, as: Uploadcare::Entity::File
20
+ has_entities :result, as: Uploadcare::Entity::File
21
+
22
+ # alias for result/results, depending on which API this FileList was initialized from
23
+ # @return [Array] of [Uploadcare::Entity::File]
24
+ def files
25
+ results
26
+ rescue ApiStruct::EntityError
27
+ result
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uploadcare/entity/file'
4
+
5
+ module Uploadcare
6
+ module Entity
7
+ # Groups serve a purpose of better organizing files in your Uploadcare projects.
8
+ #
9
+ # You can create one from a set of files by using their UUIDs.
10
+ #
11
+ # @see https://uploadcare.com/docs/api_reference/upload/groups/
12
+ class Group < Entity
13
+ client_service RestGroupClient, prefix: 'rest', only: :store
14
+ client_service GroupClient
15
+
16
+ attr_entity :id, :datetime_created, :datetime_stored, :files_count, :cdn_url, :url
17
+ has_entities :files, as: Uploadcare::Entity::File
18
+
19
+ # Remove these lines and bump api_struct version when this PR is accepted:
20
+ # @see https://github.com/rubygarage/api_struct/pull/15
21
+ def self.store(uuid)
22
+ rest_store(uuid)
23
+ end
24
+
25
+ # gets groups's id - even if it's only initialized with cdn_url
26
+ # @return [String]
27
+ def id
28
+ return @entity.id if @entity.id
29
+
30
+ id = @entity.cdn_url.gsub('https://ucarecdn.com/', '')
31
+ id.gsub(%r{/.*}, '')
32
+ end
33
+
34
+ # loads group metadata, if it's initialized with url or id
35
+ def load
36
+ initialize(Group.info(id).entity)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uploadcare/entity/group'
4
+ require 'uploadcare/entity/decorator/paginator'
5
+
6
+ module Uploadcare
7
+ module Entity
8
+ # List of groups
9
+ #
10
+ # @see https://uploadcare.com/docs/api_reference/upload/groups/
11
+ #
12
+ # This is a paginated list, so all pagination methods apply
13
+ # @see Uploadcare::Entity::Decorator::Paginator
14
+ class GroupList < Entity
15
+ include Uploadcare::Entity::Decorator::Paginator
16
+ client_service RestGroupClient, only: :list
17
+
18
+ attr_entity :next, :previous, :total, :per_page, :results
19
+ has_entities :results, as: Group
20
+
21
+ alias groups results
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uploadcare
4
+ module Entity
5
+ # This serializer returns info about a project and its data
6
+ # @see https://uploadcare.com/docs/api_reference/rest/handling_projects/
7
+ class Project < Entity
8
+ client_service ProjectClient
9
+
10
+ attr_entity :collaborators, :pub_key, :name, :autostore_enabled
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uploadcare
4
+ module Entity
5
+ # This serializer lets user upload files by various means, and usually returns an array of files
6
+ # @see https://uploadcare.com/api-refs/upload-api/#tag/Upload
7
+ class Uploader < Entity
8
+ client_service UploaderClient
9
+ client_service MultipartUploaderClient, only: :upload, prefix: :multipart
10
+
11
+ attr_entity :files
12
+ has_entities :files, as: Uploadcare::Entity::File
13
+
14
+ # Upload file or group of files from array, File, or url
15
+ #
16
+ # @param object [Array], [String] or [File]
17
+ # @param [Hash] options options for upload
18
+ # @option options [Boolean] :store (false) whether to store file on servers.
19
+ def self.upload(object, **options)
20
+ if big_file?(object)
21
+ upload_big_file(object, **options)
22
+ elsif file?(object)
23
+ upload_file(object, **options)
24
+ elsif object.is_a?(Array)
25
+ upload_files(object, **options)
26
+ elsif object.is_a?(String)
27
+ upload_from_url(object, **options)
28
+ else
29
+ raise ArgumentError, "Expected input to be a file/Array/URL, given: `#{object}`"
30
+ end
31
+ end
32
+
33
+ # upload single file
34
+ def self.upload_file(file, **options)
35
+ response = UploaderClient.new.upload_many([file], **options)
36
+ Uploadcare::Entity::File.info(response.success.to_a.flatten[-1])
37
+ end
38
+
39
+ # upload multiple files
40
+ def self.upload_files(arr, **options)
41
+ response = UploaderClient.new.upload_many(arr, **options)
42
+ response.success.map { |pair| Uploadcare::Entity::File.new(uuid: pair[1], original_filename: pair[0]) }
43
+ end
44
+
45
+ # upload file of size above 10mb (involves multipart upload)
46
+ def self.upload_big_file(file, **_options)
47
+ response = MultipartUploaderClient.new.upload(file)
48
+ Uploadcare::Entity::File.new(response.success)
49
+ end
50
+
51
+ # upload files from url
52
+ # @param url [String]
53
+ def self.upload_from_url(url, **options)
54
+ response = UploaderClient.new.upload_from_url(url, **options)
55
+ return response.success[:token] unless response.success[:files]
56
+
57
+ response.success[:files].map { |file_data| Uploadcare::Entity::File.new(file_data) }
58
+ end
59
+
60
+ class << self
61
+ private
62
+
63
+ # check if object is a file
64
+ def file?(object)
65
+ object.respond_to?(:path) && ::File.exist?(object.path)
66
+ end
67
+
68
+ # check if object needs to be uploaded using multipart upload
69
+ def big_file?(object)
70
+ file?(object) && object.size >= Uploadcare.config.multipart_size_threshold
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uploadcare
4
+ module Entity
5
+ # This serializer lets a user convert uploaded videos, and usually returns an array of results
6
+ # @see https://uploadcare.com/api-refs/rest-api/v0.6.0/#operation/videoConvert
7
+ class VideoConverter < Entity
8
+ client_service Conversion::VideoConversionClient
9
+ # Converts video files
10
+ #
11
+ # @param doc_params [Array] of hashes with params or [Hash]
12
+ # @option options [Boolean] :store (false) whether to store file on servers.
13
+ def self.convert(video_params, **options)
14
+ params = video_params.is_a?(Hash) ? [video_params] : video_params
15
+ Conversion::VideoConversionClient.new.convert_many(params, **options)
16
+ end
17
+
18
+ # Returns a status of video conversion job
19
+ #
20
+ # @param token [Integer, String] token obtained from a server in convert method
21
+ def self.status(token)
22
+ Conversion::VideoConversionClient.new.get_conversion_status(token)
23
+ end
24
+ end
25
+ end
26
+ end