uploadcare-ruby 1.2.1 → 3.0.3

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 (98) 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 -5
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +20 -0
  7. data/.yardopts +4 -0
  8. data/CHANGELOG.md +25 -24
  9. data/DEVELOPMENT.md +18 -0
  10. data/Gemfile +2 -0
  11. data/LICENSE +1 -1
  12. data/README.md +191 -519
  13. data/Rakefile +6 -4
  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/file_client.rb +44 -0
  19. data/lib/uploadcare/client/file_list_client.rb +46 -0
  20. data/lib/uploadcare/client/group_client.rb +45 -0
  21. data/lib/uploadcare/client/multipart_upload/chunks_client.rb +46 -0
  22. data/lib/uploadcare/client/multipart_upload_client.rb +62 -0
  23. data/lib/uploadcare/client/project_client.rb +18 -0
  24. data/lib/uploadcare/client/rest_client.rb +73 -0
  25. data/lib/uploadcare/client/rest_group_client.rb +23 -0
  26. data/lib/uploadcare/client/upload_client.rb +35 -0
  27. data/lib/uploadcare/client/uploader_client.rb +93 -0
  28. data/lib/uploadcare/client/webhook_client.rb +43 -0
  29. data/lib/uploadcare/concern/error_handler.rb +54 -0
  30. data/lib/uploadcare/concern/throttle_handler.rb +25 -0
  31. data/lib/uploadcare/concern/upload_error_handler.rb +32 -0
  32. data/lib/uploadcare/entity/decorator/paginator.rb +81 -0
  33. data/lib/uploadcare/entity/entity.rb +18 -0
  34. data/lib/uploadcare/entity/file.rb +81 -0
  35. data/lib/uploadcare/entity/file_list.rb +30 -0
  36. data/lib/uploadcare/entity/group.rb +41 -0
  37. data/lib/uploadcare/entity/group_list.rb +24 -0
  38. data/lib/uploadcare/entity/project.rb +13 -0
  39. data/lib/uploadcare/entity/uploader.rb +73 -0
  40. data/lib/uploadcare/entity/webhook.rb +14 -0
  41. data/lib/uploadcare/exception/request_error.rb +9 -0
  42. data/lib/uploadcare/exception/throttle_error.rb +14 -0
  43. data/lib/uploadcare/param/authentication_header.rb +25 -0
  44. data/lib/uploadcare/param/param.rb +10 -0
  45. data/lib/uploadcare/param/secure_auth_header.rb +37 -0
  46. data/lib/uploadcare/param/simple_auth_header.rb +14 -0
  47. data/lib/uploadcare/param/upload/signature_generator.rb +24 -0
  48. data/lib/uploadcare/param/upload/upload_params_generator.rb +23 -0
  49. data/lib/uploadcare/param/user_agent.rb +21 -0
  50. data/lib/uploadcare/ruby/version.rb +5 -0
  51. data/uploadcare-ruby.gemspec +50 -36
  52. metadata +112 -96
  53. data/.travis.yml +0 -12
  54. data/lib/uploadcare/api.rb +0 -24
  55. data/lib/uploadcare/api/file_api.rb +0 -7
  56. data/lib/uploadcare/api/file_list_api.rb +0 -8
  57. data/lib/uploadcare/api/group_api.rb +0 -38
  58. data/lib/uploadcare/api/group_list_api.rb +0 -8
  59. data/lib/uploadcare/api/project_api.rb +0 -9
  60. data/lib/uploadcare/api/raw_api.rb +0 -44
  61. data/lib/uploadcare/api/uploading_api.rb +0 -110
  62. data/lib/uploadcare/errors/errors.rb +0 -64
  63. data/lib/uploadcare/resources/file.rb +0 -164
  64. data/lib/uploadcare/resources/file_list.rb +0 -41
  65. data/lib/uploadcare/resources/group.rb +0 -115
  66. data/lib/uploadcare/resources/group_list.rb +0 -31
  67. data/lib/uploadcare/resources/project.rb +0 -13
  68. data/lib/uploadcare/rest/auth/auth.rb +0 -31
  69. data/lib/uploadcare/rest/auth/secure.rb +0 -43
  70. data/lib/uploadcare/rest/auth/simple.rb +0 -16
  71. data/lib/uploadcare/rest/connections/api_connection.rb +0 -32
  72. data/lib/uploadcare/rest/connections/upload_connection.rb +0 -21
  73. data/lib/uploadcare/rest/middlewares/auth_middleware.rb +0 -24
  74. data/lib/uploadcare/rest/middlewares/parse_json_middleware.rb +0 -33
  75. data/lib/uploadcare/rest/middlewares/raise_error_middleware.rb +0 -21
  76. data/lib/uploadcare/utils/parser.rb +0 -71
  77. data/lib/uploadcare/utils/user_agent.rb +0 -44
  78. data/lib/uploadcare/version.rb +0 -3
  79. data/spec/api/raw_api_spec.rb +0 -25
  80. data/spec/resources/file_list_spec.rb +0 -64
  81. data/spec/resources/file_spec.rb +0 -222
  82. data/spec/resources/group_list_spec.rb +0 -30
  83. data/spec/resources/group_spec.rb +0 -101
  84. data/spec/resources/operations_spec.rb +0 -59
  85. data/spec/resources/project_spec.rb +0 -21
  86. data/spec/rest/api_connection_spec.rb +0 -68
  87. data/spec/rest/auth/secure_spec.rb +0 -66
  88. data/spec/rest/auth/simple_spec.rb +0 -31
  89. data/spec/rest/errors_spec.rb +0 -75
  90. data/spec/rest/upload_connection_spec.rb +0 -19
  91. data/spec/spec_helper.rb +0 -41
  92. data/spec/uploadcare_spec.rb +0 -16
  93. data/spec/uploading/uploading_multiple_spec.rb +0 -43
  94. data/spec/uploading/uploading_spec.rb +0 -40
  95. data/spec/utils/parser_spec.rb +0 -87
  96. data/spec/utils/user_agent_spec.rb +0 -46
  97. data/spec/view.png +0 -0
  98. data/spec/view2.jpg +0 -0
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
- #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
3
4
  require 'rspec/core/rake_task'
4
5
 
5
- task :default => :spec
6
- RSpec::Core::RakeTask.new
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'uploadcare/ruby'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/uploadcare.rb CHANGED
@@ -1,32 +1,42 @@
1
- require 'faraday'
2
- require 'json'
3
- require 'ostruct'
1
+ # frozen_string_literal: true
4
2
 
5
- require 'uploadcare/api'
6
- require 'uploadcare/version'
3
+ # Gem version
4
+ require 'ruby/version'
7
5
 
8
- module Uploadcare
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
- }
19
-
20
- warn '[DEPRECATION] `Uploadcare::USER_AGENT` constant is deprecated and will be removed in version 3.0'
21
- USER_AGENT = "uploadcare-ruby/#{Gem.ruby_version}/#{Uploadcare::VERSION}"
6
+ # Exceptions
7
+ require 'exception/throttle_error'
8
+ require 'exception/request_error'
22
9
 
10
+ # Entities
11
+ require 'entity/entity'
12
+ require 'entity/file'
13
+ require 'entity/file_list'
14
+ require 'entity/group'
15
+ require 'entity/group_list'
16
+ require 'entity/project'
17
+ require 'entity/uploader'
18
+ require 'entity/webhook'
23
19
 
24
- def self.default_settings
25
- DEFAULT_SETTINGS
26
- end
20
+ # General api
21
+ require 'api/api'
27
22
 
28
- def self.user_agent(options={})
29
- warn '[DEPRECATION] `Uploadcare::user_agent` method is deprecated and will be removed in version 3.0'
30
- UserAgent.new.call(options)
31
- end
23
+ # Ruby wrapper for Uploadcare API
24
+ #
25
+ # @see https://uploadcare.com/docs/api_reference
26
+ module Uploadcare
27
+ extend Dry::Configurable
28
+ setting :public_key, ENV.fetch('UPLOADCARE_PUBLIC_KEY')
29
+ setting :secret_key, ENV.fetch('UPLOADCARE_SECRET_KEY')
30
+ setting :auth_type, 'Uploadcare'
31
+ setting :multipart_size_threshold, 100 * 1024 * 1024
32
+ setting :rest_api_root, 'https://api.uploadcare.com'
33
+ setting :upload_api_root, 'https://upload.uploadcare.com'
34
+ setting :max_request_tries, 100
35
+ setting :base_request_sleep, 1 # seconds
36
+ setting :max_request_sleep, 60.0 # seconds
37
+ setting :sign_uploads, false
38
+ setting :upload_signature_lifetime, 30 * 60 # seconds
39
+ setting :max_throttle_attempts, 5
40
+ setting :upload_threads, 2 # used for multiupload only ATM
41
+ setting :framework_data, ''
32
42
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem.find_files('client/**/*.rb').each { |path| require path }
4
+ Gem.find_files('entity/**/*.rb').each { |path| require path }
5
+
6
+ module Uploadcare
7
+ # End-user interface
8
+ #
9
+ # It delegates methods to other classes:
10
+ # * To class methods of Entity objects
11
+ # * To instance methods of Client objects
12
+ # @see Uploadcare::Entity
13
+ # @see Uploadcare::Client
14
+ class Api
15
+ extend Forwardable
16
+ include Entity
17
+
18
+ def_delegator File, :file
19
+ def_delegators FileList, :file_list, :store_files, :delete_files
20
+ def_delegators Group, :group
21
+ def_delegators Project, :project
22
+ def_delegators Uploader, :upload, :upload_files, :upload_url
23
+ def_delegators Webhook, :create_webhook, :list_webhooks, :delete_webhook, :update_webhook
24
+ end
25
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'rest_client'
4
+
5
+ module Uploadcare
6
+ module Client
7
+ # API client for handling single files
8
+ # @see https://uploadcare.com/docs/api_reference/rest/accessing_files/
9
+ # @see https://uploadcare.com/api-refs/rest-api/v0.5.0/#tag/File
10
+ class FileClient < RestClient
11
+ # Gets list of files without pagination fields
12
+ def index
13
+ response = get(uri: '/files/')
14
+ response.fmap { |i| i[:results] }
15
+ end
16
+
17
+ # Acquire file info
18
+ # @see https://uploadcare.com/api-refs/rest-api/v0.5.0/#operation/fileInfo
19
+ def info(uuid)
20
+ get(uri: "/files/#{uuid}/")
21
+ end
22
+ alias file info
23
+
24
+ # 'copy' method is used to copy original files or their modified versions to default storage.
25
+ # Source files MAY either be stored or just uploaded and MUST NOT be deleted.
26
+ # @see https://uploadcare.com/api-refs/rest-api/v0.5.0/#operation/copyFile
27
+ def copy(**options)
28
+ body = options.compact.to_json
29
+ post(uri: '/files/', content: body)
30
+ end
31
+
32
+ # @see https://uploadcare.com/api-refs/rest-api/v0.5.0/#operation/deleteFile
33
+ def delete(uuid)
34
+ request(method: 'DELETE', uri: "/files/#{uuid}/")
35
+ end
36
+
37
+ # Store a single file, preventing it from being deleted in 2 weeks
38
+ # @see https://uploadcare.com/api-refs/rest-api/v0.5.0/#operation/storeFile
39
+ def store(uuid)
40
+ put(uri: "/files/#{uuid}/storage/")
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'rest_client'
4
+
5
+ module Uploadcare
6
+ module Client
7
+ # API client for handling file lists
8
+ class FileListClient < RestClient
9
+ # Returns a pagination json of files stored in project
10
+ # @see https://uploadcare.com/api-refs/rest-api/v0.5.0/#operation/filesList
11
+ #
12
+ # valid options:
13
+ # removed: [true|false]
14
+ # stored: [true|false]
15
+ # limit: (1..1000)
16
+ # ordering: ["datetime_uploaded"|"-datetime_uploaded"|"size"|"-size"]
17
+ # from: number of files skipped
18
+ def file_list(**options)
19
+ query = options.empty? ? '' : '?' + URI.encode_www_form(options)
20
+ get(uri: "/files/#{query}")
21
+ end
22
+
23
+ # Make a set of files "stored". This will prevent them from being deleted automatically
24
+ # @see https://uploadcare.com/api-refs/rest-api/v0.5.0/#operation/filesStoring
25
+ # uuids: Array
26
+ def batch_store(uuids)
27
+ body = uuids.to_json
28
+ put(uri: '/files/storage/', body: body)
29
+ end
30
+
31
+ alias request_delete delete
32
+
33
+ # Delete several files by list of uids
34
+ # @see https://uploadcare.com/api-refs/rest-api/v0.5.0/#operation/filesDelete
35
+ # uuids: Array
36
+ def batch_delete(uuids)
37
+ body = uuids.to_json
38
+ request_delete(uri: '/files/storage/', body: body)
39
+ end
40
+
41
+ alias store_files batch_store
42
+ alias delete_files batch_delete
43
+ alias list file_list
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'upload_client'
4
+
5
+ module Uploadcare
6
+ module Client
7
+ # Groups serve a purpose of better organizing files in your Uploadcare projects.
8
+ # You can create one from a set of files by using their UUIDs.
9
+ # @see https://uploadcare.com/docs/api_reference/upload/groups/
10
+ class GroupClient < UploadClient
11
+ # Create files group from a set of files by using their UUIDs.
12
+ # @see https://uploadcare.com/api-refs/upload-api/#operation/createFilesGroup
13
+ def create(file_list, **options)
14
+ body_hash = group_body_hash(file_list, **options)
15
+ body = HTTP::FormData::Multipart.new(body_hash)
16
+ post(path: 'group/',
17
+ headers: { 'Content-type': body.content_type },
18
+ body: body)
19
+ end
20
+
21
+ # Get group info
22
+ # @see https://uploadcare.com/api-refs/upload-api/#operation/filesGroupInfo
23
+ def info(group_id)
24
+ get(path: 'group/info/', params: { 'pub_key': Uploadcare.config.public_key, 'group_id': group_id })
25
+ end
26
+
27
+ private
28
+
29
+ def file_params(file_ids)
30
+ ids = (0...file_ids.size).map { |i| "files[#{i}]" }
31
+ ids.zip(file_ids).to_h
32
+ end
33
+
34
+ def group_body_hash(file_list, **options)
35
+ { pub_key: Uploadcare.config.public_key }.merge(file_params(parse_file_list(file_list))).merge(**options)
36
+ end
37
+
38
+ # API accepts only list of ids, but some users may want to upload list of files
39
+ # @return [Array] of [String]
40
+ def parse_file_list(file_list)
41
+ file_list.map { |file| file.methods.include?(:uuid) ? file.uuid : file }
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parallel'
4
+
5
+ module Uploadcare
6
+ module Client
7
+ module MultipartUpload
8
+ # This class splits file into chunks of set chunk_size
9
+ # and uploads them into cloud storage.
10
+ # Used for multipart uploads
11
+ # @see https://uploadcare.com/api-refs/upload-api/#tag/Upload/paths/https:~1~1uploadcare.s3-accelerate.amazonaws.com~1%3C%3Cpresigned-url%3E/put
12
+ class ChunksClient < ApiStruct::Client
13
+ CHUNK_SIZE = 5_242_880
14
+
15
+ # In multiple threads, split file into chunks and upload those chunks into respective Amazon links
16
+ # @param object [File]
17
+ # @param links [Array] of strings; by default list of Amazon storage urls
18
+ def upload_chunks(object, links)
19
+ Parallel.each(0...links.count, in_threads: Uploadcare.config.upload_threads) do |link_id|
20
+ offset = link_id * CHUNK_SIZE
21
+ chunk = IO.read(object, CHUNK_SIZE, offset)
22
+ upload_chunk(chunk, links[link_id])
23
+ end
24
+ end
25
+
26
+ def api_root
27
+ ''
28
+ end
29
+
30
+ def headers
31
+ {}
32
+ end
33
+
34
+ private
35
+
36
+ def upload_chunk(chunk, link)
37
+ put(path: link, body: chunk, headers: { 'Content-type': 'application/octet-stream' })
38
+ end
39
+
40
+ def default_params
41
+ {}
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'client/multipart_upload/chunks_client'
4
+ require_relative 'upload_client'
5
+
6
+ module Uploadcare
7
+ module Client
8
+ # Client for multipart uploads
9
+ #
10
+ # @see https://uploadcare.com/api-refs/upload-api/#tag/Upload
11
+ class MultipartUploaderClient < UploadClient
12
+ include MultipartUpload
13
+
14
+ # Upload a big file by splitting it into parts and sending those parts into assigned buckets
15
+ # object should be File
16
+ def upload(object, store: false)
17
+ response = upload_start(object, store: store)
18
+ return response unless response.success[:parts] && response.success[:uuid]
19
+
20
+ links = response.success[:parts]
21
+ uuid = response.success[:uuid]
22
+ ChunksClient.new.upload_chunks(object, links)
23
+ upload_complete(uuid)
24
+ end
25
+
26
+ # Asks Uploadcare server to create a number of storage bin for uploads
27
+ def upload_start(object, store: false)
28
+ body = HTTP::FormData::Multipart.new(
29
+ Param::Upload::UploadParamsGenerator.call(store).merge(multiupload_metadata(object))
30
+ )
31
+ post(path: 'multipart/start/',
32
+ headers: { 'Content-type': body.content_type },
33
+ body: body)
34
+ end
35
+
36
+ # When every chunk is uploaded, ask Uploadcare server to finish the upload
37
+ def upload_complete(uuid)
38
+ body = HTTP::FormData::Multipart.new(
39
+ 'UPLOADCARE_PUB_KEY': Uploadcare.config.public_key,
40
+ 'uuid': uuid
41
+ )
42
+ post(path: 'multipart/complete/', body: body, headers: { 'Content-type': body.content_type })
43
+ end
44
+
45
+ private
46
+
47
+ def multiupload_metadata(file)
48
+ file = HTTP::FormData::File.new(file)
49
+ {
50
+ filename: file.filename,
51
+ size: file.size,
52
+ content_type: file.content_type
53
+ }
54
+ end
55
+
56
+ alias api_struct_post post
57
+ def post(**args)
58
+ handle_throttling { api_struct_post(**args) }
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Uploadcare
4
+ module Client
5
+ # API client for getting project info
6
+ # @see https://uploadcare.com/docs/api_reference/rest/handling_projects/
7
+ class ProjectClient < RestClient
8
+ # get information about current project
9
+ # current project is determined by public and private key combination
10
+ # @see https://uploadcare.com/api-refs/rest-api/v0.5.0/#tag/Project
11
+ def show
12
+ get(uri: '/project/')
13
+ end
14
+
15
+ alias project show
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'rest_client'
4
+ require 'uploadcare/concern/error_handler'
5
+ require 'uploadcare/concern/throttle_handler'
6
+ require 'param/authentication_header'
7
+
8
+ module Uploadcare
9
+ module Client
10
+ # @abstract
11
+ # General client for signed REST requests
12
+ class RestClient < ApiStruct::Client
13
+ include Uploadcare::Concerns::ErrorHandler
14
+ include Uploadcare::Concerns::ThrottleHandler
15
+ include Exception
16
+
17
+ alias api_struct_delete delete
18
+ alias api_struct_get get
19
+ alias api_struct_post post
20
+ alias api_struct_put put
21
+
22
+ # Send request with authentication header
23
+ #
24
+ # Handle throttling as well
25
+ def request(method: 'GET', uri:, **options)
26
+ request_headers = Param::AuthenticationHeader.call(method: method.upcase, uri: uri,
27
+ content_type: headers[:'Content-type'], **options)
28
+ handle_throttling do
29
+ send('api_struct_' + method.downcase, path: remove_trailing_slash(uri),
30
+ headers: request_headers, body: options[:content])
31
+ end
32
+ end
33
+
34
+ def get(**options)
35
+ request(method: 'GET', **options)
36
+ end
37
+
38
+ def post(**options)
39
+ request(method: 'POST', **options)
40
+ end
41
+
42
+ def put(**options)
43
+ request(method: 'PUT', **options)
44
+ end
45
+
46
+ def delete(**options)
47
+ request(method: 'DELETE', **options)
48
+ end
49
+
50
+ def api_root
51
+ Uploadcare.config.rest_api_root
52
+ end
53
+
54
+ def headers
55
+ {
56
+ 'Content-type': 'application/json',
57
+ 'Accept': 'application/vnd.uploadcare-v0.5+json',
58
+ 'User-Agent': Uploadcare::Param::UserAgent.call
59
+ }
60
+ end
61
+
62
+ private
63
+
64
+ def remove_trailing_slash(str)
65
+ str.gsub(%r{^\/}, '')
66
+ end
67
+
68
+ def default_params
69
+ {}
70
+ end
71
+ end
72
+ end
73
+ end